Added a lot of support for new visual framework. Still WIP

This commit is contained in:
Andrew Lalis 2019-05-16 19:30:00 +02:00 committed by andrewlalis
parent 1aa6895aec
commit 13dd59aa8f
21 changed files with 505 additions and 346 deletions

View File

@ -37,7 +37,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
.and()
.authorizeRequests()
.antMatchers("/css/**", "/images/**")
.antMatchers("/css/**", "/images/**", "/javascript/**")
.permitAll()
.and()

View File

@ -0,0 +1,48 @@
package nl.andrewlalis.teaching_assistant_assistant.controllers;
import nl.andrewlalis.teaching_assistant_assistant.model.dto.NewUserRegistrationDTO;
import nl.andrewlalis.teaching_assistant_assistant.model.repositories.CourseRepository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
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 java.util.Arrays;
/**
* Controller for the registration page which is used for the creation of new accounts.
*/
@Controller
public class RegisterController {
private final Logger logger = LogManager.getLogger(RegisterController.class);
private CourseRepository courseRepository;
private static final String[] personTypes = {
"Student",
"Teaching Assistant",
"Professor",
"Administrator"
};
protected RegisterController(CourseRepository courseRepository) {
this.courseRepository = courseRepository;
}
@GetMapping("/register")
public String get(Model model) {
model.addAttribute("newUserRegistration", new NewUserRegistrationDTO(Arrays.asList(personTypes), this.courseRepository.findAll()));
return "register";
}
@PostMapping("/register")
public String post(@ModelAttribute NewUserRegistrationDTO newUserRegistration) {
logger.info("Received new registration: " + newUserRegistration);
return "redirect:/login";
}
}

View File

@ -18,7 +18,7 @@ public class CreateCourse extends UserPageController {
@GetMapping("/courses/create")
public String get(Model model) {
Course course = new Course("no name", "no code");
Course course = new Course(null, null);
model.addAttribute("course", course);
return "courses/create";
}

View File

@ -36,7 +36,7 @@ public class StudentCreateController extends UserPageController {
@GetMapping("/students/create")
public String getCreate(Model model) {
model.addAttribute("student", new Student("First Name", "Last Name", "Email Address", "Github Username", 1234567));
model.addAttribute("student", new Student(null, null, null, null, 1234567));
model.addAttribute("courses", this.courseRepository.findAll());
return "students/create";

View File

@ -0,0 +1,95 @@
package nl.andrewlalis.teaching_assistant_assistant.model.dto;
import nl.andrewlalis.teaching_assistant_assistant.model.Course;
import java.util.List;
/**
* A data transfer object to aid in the registration of a new authenticated user. This object therefore contains all the
* data that potential users enter prior to the actual creation of a new user.
*/
public class NewUserRegistrationDTO {
private String firstName;
private String lastName;
private String emailAddress;
private String username;
private String password;
private String passwordConfirm;
private String selectedPersonType;
private List<String> availablePersonTypes;
private Iterable<Course> availableCourses;
public NewUserRegistrationDTO(List<String> availablePersonTypes, Iterable<Course> availableCourses) {
this.availablePersonTypes = availablePersonTypes;
this.availableCourses = availableCourses;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPasswordConfirm() {
return passwordConfirm;
}
public void setPasswordConfirm(String passwordConfirm) {
this.passwordConfirm = passwordConfirm;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public List<String> getAvailablePersonTypes() {
return availablePersonTypes;
}
public Iterable<Course> getAvailableCourses() {
return availableCourses;
}
public String getSelectedPersonType() {
return this.selectedPersonType;
}
}

View File

@ -0,0 +1,18 @@
package nl.andrewlalis.teaching_assistant_assistant.model.repositories;
import nl.andrewlalis.teaching_assistant_assistant.model.security.Role;
import org.springframework.data.repository.CrudRepository;
import java.util.Optional;
/**
* The repository for all roles to which users may be assigned.
*/
public interface RoleRepository extends CrudRepository<Role, Long> {
/**
* Try to find a role by the given name.
* @return An optional Role that has the given name.
*/
public Optional<Role> findByName(String name);
}

View File

@ -1,59 +1,7 @@
/* Set the font for the whole website here. */
body {
font-family: sans-serif;
background-color: white;
padding-bottom: 70px;
}
/*.btn-primary {*/
/* background-color: green;*/
/*}*/
.content_container {
width: 50%;
margin-left: auto;
margin-right: auto;
text-align: left;
font-size: 16px;
color: black;
}
.sidebar_container {
width: 20%;
height: 100%;
position: fixed;
top: 70px;
right: 0;
}
.sidebar_block {
margin: 20px 0 20px 0;
padding: 20px;
background-color: green;
color: whitesmoke;
}
.sidebar_block a {
text-decoration: underline;
color: inherit;
}
.white_link {
text-decoration: underline;
color: white;
}
.sidebar_block a:hover {
color: lightgreen;
}
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
.page_row {
width: 100%;
margin-top: 10px;
margin-bottom: 10px;
}
label {
font-weight: bold;
}
/*.btn-primary:hover {*/
/* background-color: darkgreen;*/
/*}*/

File diff suppressed because one or more lines are too long

View File

@ -1,39 +1,27 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (~{::title}, ~{::#content}, ~{::#sidebar})}">
<head>
<title>Courses</title>
</head>
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (title='Courses', content=~{::#content}, actions=~{::#actions})}" lang="en">
<body>
<div id="content">
<h1>Courses</h1>
<hr>
<ul>
<li th:each="course: ${courses}">
<h2><a th:href="@{/courses/{code}(code=${course.getCode()})}" th:text="${course.getName()}"></a></h2>
<ul>
<li>Code: <span th:text="${course.getCode()}"></span></li>
<li>Created on: <span th:text="${course.getCreatedOn()}"></span></li>
<li>Students: <span th:text="${course.getStudents().size()}"></span></li>
<li>Teaching Assistants: <span th:text="${course.getTeachingAssistants().size()}"></span></li>
<li>Student Teams: <span th:text="${course.getStudentTeams().size()}"></span></li>
<li>Teaching Assistant Teams: <span th:text="${course.getTeachingAssistantTeams().size()}"></span></li>
<li>Number of Active Students (in a team): <span th:text="${course.getNumberOfStudentsInTeams()}"></span></li>
</ul>
</li>
</ul>
<div id="actions">
<a class="btn btn-primary m-1" th:href="@{/courses/create}">Create New Course</a>
</div>
<div id="sidebar">
<div class="sidebar_block">
<a href="/courses/create">Create new course</a>
</div>
<div class="sidebar_block">
Do something else
</div>
<div class="sidebar_block">
Click this link!
<div id="content" class="container-fluid">
<div class="col-sm-12 col-md-6 offset-3">
<div class="list-group">
<a th:each="course: ${courses}" class="list-group-item list-group-item-action flex-column align-items-start" th:href="@{/courses/{code}(code=${course.getCode()})}">
<div class="d-flex w-100 justify-content-between">
<h4 class="mb-1" th:text="${course.getName()}"></h4>
<small th:text="${course.getCode()}"></small>
</div>
<ul>
<li><span class="badge badge-primary" th:text="${course.getStudentTeams().size()}"></span> Student Teams</li>
<li><span class="badge badge-primary" th:text="${course.getNumberOfStudentsInTeams()}"></span> Active Students</li>
<li><span class="badge badge-primary" th:text="${course.getTeachingAssistants().size()}"></span> Teaching Assistants</li>
</ul>
<small>Created on <span th:text="${course.getCreatedOn()}"></span></small>
</a>
</div>
</div>
</div>

View File

@ -1,43 +1,35 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (~{::title}, ~{::#content}, ~{::#sidebar})}">
<head>
<title>Create a Course</title>
</head>
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (title='Create New Course', content=~{::#content})}" lang="en">
<body>
<div id="content">
<h1>Create New Course</h1>
<form action="#" th:action="@{/courses}" th:object="${course}" method="post">
<div class="page_row">
<label for="course_name_input">Name:</label>
<input id="course_name_input" type="text" th:field="*{name}" required/>
<div id="content" class="row justify-content-center">
<form th:action="@{/courses}" th:object="${course}" method="post">
<div class="form-group">
<label for="course_name_input">Name</label>
<input id="course_name_input" type="text" class="form-control" th:field="*{name}" required/>
</div>
<div class="page_row">
<label for="course_code_input">Code:</label>
<input id="course_code_input" type="text" th:field="*{code}" required/>
<div class="form-group">
<label for="course_code_input">Code</label>
<input id="course_code_input" type="text" class="form-control" th:field="*{code}" required/>
<small class="form-text text-muted">Unique identifying code for this course.</small>
</div>
<div class="page_row">
<label for="course_github_organization_name_input">Github Organization:</label>
<input id="course_github_organization_name_input" type="text" th:field="*{githubOrganizationName}" required/>
<div class="form-group">
<label for="course_github_organization_name_input">Github Organization</label>
<input id="course_github_organization_name_input" type="text" class="form-control" th:field="*{githubOrganizationName}" required/>
</div>
<div class="page_row">
<label for="course_github_api_key_input">Github API Key:</label>
<input id="course_github_api_key_input" type="text" th:field="*{apiKey}" required/>
<div class="form-group">
<label for="course_github_api_key_input">Github API Key</label>
<input id="course_github_api_key_input" type="text" class="form-control" th:field="*{apiKey}" required/>
<small class="form-text text-muted">Needed to manage student repositories.</small>
</div>
<div class="page_row">
<button type="submit">Submit</button>
</div>
<input class="btn btn-primary" type="submit" value="Create"/>
</form>
</div>
<div id="sidebar">
</div>
</body>
</html>

View File

@ -1,40 +1,35 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (~{::title}, ~{::#content}, ~{::#sidebar})}">
<head>
<meta charset="UTF-8">
<title th:text="${course.getName()}"></title>
</head>
<html lang="en" xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (title=${course.getName()}, content=~{::#content}, actions=~{::#actions})}">
<body>
<div id="content">
<h1><span th:text="${course.getName()}"></span> (Code: <span th:text="${course.getCode()}"></span>)</h1>
<hr>
<ul>
<li>
Github Organization: <a th:href="@{${'https://www.github.com/' + course.getGithubOrganizationName()}}" th:text="${course.getGithubOrganizationName()}"></a>
</li>
<li>
<a th:href="@{/courses/{code}/teaching_assistant_teams(code=${course.getCode()})}">Teaching Assistant Teams</a>
</li>
<li>
<a th:href="@{/courses/{code}/student_teams(code=${course.getCode()})}">Student Teams</a>
</li>
<li>
<a th:href="@{/courses/{code}/students(code=${course.getCode()})}">All Students</a>
</li>
<li>
<a th:href="@{/courses/{code}/teaching_assistants(code=${course.getCode()})}">All Teaching Assistants</a>
</li>
</ul>
<div id="actions">
<a class="btn btn-primary m-1" th:href="@{/courses/{code}/import_students(code=${course.getCode()})}">Import Students From CSV</a>
<a class="btn btn-primary m-1" th:href="@{/courses/{code}/import_teaching_assistants(code=${course.getCode()})}">Import Teaching Assistants From CSV</a>
</div>
<div id="sidebar">
<div class="sidebar_block">
<a th:href="@{/courses/{code}/import_students(code=${course.getCode()})}">Import students from CSV</a>
</div>
<div class="sidebar_block">
<a th:disabled="true" th:href="@{/courses/{code}/import_teaching_assistants(code=${course.getCode()})}">Import teaching assistants from CSV</a>
<div id="content" class="row justify-content-center">
<div class="col-sm-12 col-md-6">
<div class="list-group">
<a class="list-group-item list-group-item-action" th:href="@{${'https://www.github.com/' + course.getGithubOrganizationName()}}">
Github Organization: <span th:text="${course.getGithubOrganizationName()}"></span>
</a>
<a class="list-group-item list-group-item-action d-flex justify-content-between align-items-center" th:href="@{/courses/{code}/teaching_assistant_teams(code=${course.getCode()})}">
Teaching Assistant Teams
<span class="badge badge-primary" th:text="${course.getTeachingAssistantTeams().size()}"></span>
</a>
<a class="list-group-item list-group-item-action d-flex justify-content-between align-items-center" th:href="@{/courses/{code}/student_teams(code=${course.getCode()})}">
Student Teams
<span class="badge badge-primary" th:text="${course.getStudentTeams().size()}"></span>
</a>
<a class="list-group-item list-group-item-action d-flex justify-content-between align-items-center" th:href="@{/courses/{code}/students(code=${course.getCode()})}">
Students
<span class="badge badge-primary" th:text="${course.getStudents().size()}"></span>
</a>
<a class="list-group-item list-group-item-action d-flex justify-content-between align-items-center" th:href="@{/courses/{code}/teaching_assistants(code=${course.getCode()})}">
Teaching Assistants
<span class="badge badge-primary" th:text="${course.getTeachingAssistants().size()}"></span>
</a>
</div>
</div>
</div>

View File

@ -1,34 +1,77 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (~{::title}, ~{::#content}, ~{::#sidebar})}" lang="en">
<head>
<title>Homepage</title>
</head>
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (title='Home', content=~{::#content})}" lang="en">
<body>
<div id="content">
<h1>Teaching Assistant Assistant</h1>
<hr>
<div id="content" class="container-fluid">
<div class="row justify-content-center">
<div class="col-6">
<h3>Welcome to the Teaching Assistant Assistant, <span th:text="${user.getPerson().getFullName()}"></span>.</h3>
<p>
Welcome to the Teaching Assistant Assistant, <span th:text="${user.getPerson().getFullName()}"></span>. To find the courses in this application please follow the link to <a th:href="@{/courses}">courses</a>.
</p>
<p>
To find the courses in this application please follow the link to <a th:href="@{/courses}">courses</a>.
</p>
<p>
This application makes it easy to sift through lots of student groups that are usually handled manually in some
spreadsheet. By integrating all data into one web application it is possible to access the information you need
faster, and make coordinated changes without fear of introducing inconsistencies or errors.
</p>
</div>
<div id="sidebar">
<div class="sidebar_block">
This is an example sidebar block.
<p>
This application makes it easy to sift through lots of student groups that are usually handled manually in some
spreadsheet. By integrating all data into one web application it is possible to access the information you need
faster, and make coordinated changes without fear of introducing inconsistencies or errors.
</p>
</div>
</div>
<div id="generate_courses_block" class="sidebar_block">
<a href="/courses/generate">Click here to generate test data.</a>
</div>
<div class="sidebar_block">
Another sidebar block with a lot more text in it, so that the text should properly wrap to the next lines if needed.
<div class="row justify-content-center">
<div class="col-4">
<h5>Lights, Camera, Action!</h5>
<p>
Throughout the application, you'll find many of these action buttons, which you can use to interact with various objects or pages. Each action will have some accompanying text that describes the results of the action, and anything else you might need to be aware of.
</p>
<p>
Sometimes you'll need special permission to perform an action, so if you don't have permission to do so, the action button will appear grayed out, like one of the actions on the right is.
</p>
</div>
<div class="col-6">
<div class="card-columns">
<div class="card" style="width: 18rem;">
<div class="card-body">
<a class="btn btn-primary" href="#">
Do Action
</a>
<p class="card-text">
This text will tell you a little bit about what this action does, so that you think twice before you do some irreparable harm.
</p>
</div>
</div>
<div class="card" style="width: 18rem;">
<div class="card-body">
<a class="btn btn-primary" href="#">
Another Action
</a>
<p class="card-text">
Once again, please read these instructions before pressing that button, no matter how appealing it looks.
</p>
</div>
</div>
<div class="card" style="width: 18rem;">
<div class="card-body">
<a class="btn btn-primary disabled" href="#">
Do Action
</a>
<p class="card-text">
As you can see, the action button above is <em>disabled</em>, meaning that one of two things happened:
</p>
<ol>
<li>You don't have permission to perform the action.</li>
<li>This action is still a work-in-progress.</li>
</ol>
<p>
If you believe this to be an error, please contact the site administrator and make sure to mention your username and which action you need to perform.
</p>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,34 +1,45 @@
<!DOCTYPE html>
<html lang="en" th:fragment="layout (title, content, sidebar_content)" xmlns:th="http://www.thymeleaf.org">
<html lang="en" th:fragment="layout (title, content)" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title th:replace="${title}">basic_page</title>
<link rel="stylesheet" href="../../../resources/static/css/style.css" th:href="@{/css/style.css}" />
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"/>
<title th:text="${title}">basic_page</title>
<link rel="icon" th:href="@{/images/favicon.ico}"/>
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"/>
<script th:src="@{/javascript/bootstrap.bundle.min.js}"></script>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<link rel="stylesheet" href="../../../resources/static/css/style.css" th:href="@{/css/style.css}" />
</head>
<body>
<!-- Only show the header if the user is authenticated. -->
<header th:if="${user != null}">
<div th:replace="~{fragments/header :: header}"></div>
</header>
<div class="content_container">
<div th:replace="${content}">
<div class="content_container container-fluid">
<div class="row">
<div class="col">
<h1 class="text-center" th:text="${title}"></h1>
<hr>
</div>
</div>
<!-- If the page controller specifies some actions, add them here as cards. -->
<th:block th:if="${actions != null}">
<div th:include="${actions}" class="row justify-content-center mb-2">
</div>
</th:block>
<div th:replace="${content}" class="row">
<p>
Basic page content block.
</p>
</div>
</div>
<div class="sidebar_container">
<div th:replace="${sidebar_content}">
<p>
Basic page sidebar block.
</p>
</div>
</div>
<div th:replace="~{fragments/footer :: footer}"></div>
</body>

View File

@ -1,33 +0,0 @@
<!DOCTYPE html>
<html lang="en" th:fragment="layout (title, content, sidebar_content)" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title th:replace="${title}">basic_page</title>
<link rel="stylesheet" href="../../../resources/static/css/style.css" th:href="@{/css/style.css}" />
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"/>
<link rel="icon" th:href="@{/images/favicon.ico}"/>
</head>
<body>
<header th:replace="~{fragments/header :: header}"></header>
<div class="content_container">
<div th:replace="${content}">
<p>
Basic page content block.
</p>
</div>
</div>
<div class="sidebar_container">
<div th:replace="${sidebar_content}">
<p>
Basic page sidebar block.
</p>
</div>
</div>
<div th:replace="~{fragments/footer :: footer}"></div>
</body>
</html>

View File

@ -1,16 +1,9 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (~{::title}, ~{::#content}, ~{::#sidebar})}" lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}" type="text/css"/>
</head>
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (title='Login', content=~{::#content})}" lang="en">
<body>
<section id="content" class="container">
<div class="row justify-content-center">
<h1>Teaching Assistant <em>Assistant</em></h1>
</div>
<div class="row justify-content-center">
<div class="alert alert-danger" th:if="${param.error}">
@ -40,16 +33,12 @@
<input id="password_input" class="form-control" type="password" name="password"/>
</div>
<input type="submit" value="Login"/>
<input class="btn btn-primary" type="submit" value="Login"/>
<a class="white_link" th:href="@{/register}">Don't have an account? Sign up here!</a>
<a class="btn btn-secondary btn-sm" th:href="@{/register}">Don't have an account? Sign up here!</a>
</form>
</div>
</section>
<div id="sidebar">
</div>
</body>
</html>

View File

@ -0,0 +1,71 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (title='Register', content=~{::#content})}" lang="en">
<body>
<section id="content" class="container">
<div class="row">
<div class="col">
<p>
Here you can register to create a new account to access the information provided by this application, whether you are a professor, teaching assistant, or student. After filling out this submission form, you'll receive an email with a link to verify that you are who you say you are, after which your account will be activated.
</p>
</div>
</div>
<div class="row justify-content-center">
<form th:action="@{/register}" method="post" th:object="${newUserRegistration}">
<div class="form-row">
<div class="col">
<label for="first_name_input">First Name</label>
<input id="first_name_input" class="form-control" type="text" th:field="*{firstName}" required/>
</div>
<div class="col">
<label for="last_name_input">Last Name</label>
<input id="last_name_input" class="form-control" type="text" th:field="*{lastName}" required/>
</div>
</div>
<div class="form-row">
<div class="col">
<label for="email_input">Email</label>
<input id="email_input" class="form-control" type="text" th:field="*{emailAddress}" required/>
</div>
</div>
<div class="form-row">
<div class="col">
<label for="username_input">Username</label>
<input id="username_input" class="form-control" type="text" th:field="*{username}" required/>
</div>
</div>
<div class="form-row">
<div class="col">
<label for="role_select">I am a</label>
<select id="role_select" class="form-control" th:field="*{selectedPersonType}">
<option th:each="personType: ${newUserRegistration.getAvailablePersonTypes()}" th:text="${personType}" th:value="${personType}"></option>
</select>
</div>
</div>
<div class="form-row">
<div class="col">
<label for="password_input">Password</label>
<input id="password_input" class="form-control" type="password" th:field="*{password}" required/>
</div>
<div class="col">
<label for="password_confirm_input">Confirm Password</label>
<input id="password_confirm_input" class="form-control" type="password" th:field="*{passwordConfirm}" required/>
</div>
</div>
<div class="form-row mt-1">
<div class="col">
<input class="btn btn-primary" type="submit" value="Submit"/>
</div>
</div>
</form>
</div>
</section>
</body>
</html>

View File

@ -1,15 +1,17 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (~{::title}, ~{::#content}, ~{::#sidebar})}">
<html lang="en" xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (title='Students', content=~{::#content}, actions=~{::#actions})}">
<head>
<meta charset="UTF-8">
<title>Students</title>
</head>
<body>
<div id="content">
<h1>All Students</h1>
<div id="actions">
<a class="btn btn-primary m-1" th:href="@{/students/create}">Create Student</a>
</div>
<table>
<div id="content" class="row">
<table class="table">
<tr>
<th>Student</th>
<th>Student Number</th>
@ -44,11 +46,5 @@
</table>
</div>
<div id="sidebar">
<div class="sidebar_block">
<a th:href="@{/students/create}">Create Student</a>
</div>
</div>
</body>
</html>

View File

@ -1,59 +1,66 @@
<!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>
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (title='Create New Student', content=~{::#content})}">
<body>
<div id="content">
<h1>Create New Student</h1>
<div id="content" class="row justify-content-center">
<div class="col-sm-12 col-md-6">
<form th:action="@{/students/create}" th:object="${student}" method="post" enctype="application/x-www-form-urlencoded">
<div class="form-row">
<div class="col">
<label for="student_first_name_input">First Name</label>
<input id="student_first_name_input" class="form-control" type="text" th:field="*{firstName}" placeholder="Elon" required />
</div>
<div class="col">
<label for="student_last_name_input">Last Name</label>
<input id="student_last_name_input" class="form-control" type="text" th:field="*{lastName}" placeholder="Musk" required />
</div>
</div>
<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="form-row">
<div class="col">
<label for="student_email_input">Email Address</label>
<input id="student_email_input" class="form-control" type="email" th:field="*{emailAddress}" placeholder="me@example.com" required />
</div>
</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="form-row">
<div class="col">
<label for="student_github_username_input">Github Username</label>
<input id="student_github_username_input" class="form-control" type="text" th:field="*{githubUsername}" placeholder="username" required />
</div>
</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="form-row">
<div class="col">
<label for="student_number_input">Student Number</label>
<input id="student_number_input" class="form-control" type="number" th:field="*{studentNumber}" value="" placeholder="1234567" required />
</div>
</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="form-row">
<div class="col">
<label for="student_course_select">Add this student to a course?</label>
<select id="student_course_select" class="form-control" 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>
<small class="form-text text-muted">This can also be done later at this student's page.</small>
</div>
</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="form-row mt-1">
<div class="col">
<input class="btn btn-primary" type="submit" value="Submit" />
</div>
</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">
</form>
</div>
</div>
</body>

View File

@ -1,13 +1,13 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (~{::title}, ~{::#content}, ~{::#sidebar})}">
<head>
<title>Student</title>
</head>
<html lang="en" xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (title=${student.getFullName()}, content=~{::#content}, actions=~{::#actions})}">
<body>
<div id="content">
<h1>Student: <span th:text="${student.getFullName()}"></span></h1>
<div id="actions">
<a class="btn btn-primary m-1" th:href="@{/students/{id}/edit(id=${student.getId()})}">Edit</a>
</div>
<div id="content" class="row">
<ul>
<li>
Student Number: <code th:text="${student.getStudentNumber()}"></code>
@ -29,11 +29,5 @@
</ul>
</div>
<div id="sidebar">
<div class="sidebar_block">
<a th:href="@{/students/{id}/edit(id=${student.getId()})}">Edit</a>
</div>
</div>
</body>
</html>

View File

@ -1,22 +1,28 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (~{::title}, ~{::#content}, ~{::#sidebar})}">
<head>
<meta charset="UTF-8">
<title>Teaching Assistants</title>
</head>
<html lang="en" xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (title='Teaching Assistants', content=~{::#content})}">
<body>
<div id="content">
<h1>All Teaching Assistants</h1>
<table>
<table class="table">
<tr>
<th>Teaching Assistant</th>
<th>Github Username</th>
<th>Email</th>
<th>Courses</th>
<th>Delete</th>
</tr>
<tr th:each="teachingAssistant: ${teaching_assistants}">
<td>
<a th:href="@{/teaching_assistants/{id}(id=${teachingAssistant.getId()})}"><span th:text="${teachingAssistant.getFullName()}"></span></a>
</td>
<td th:text="${teachingAssistant.getGithubUsername()}"></td>
<td th:text="${teachingAssistant.getEmailAddress()}"></td>
<td th:text="${teachingAssistant.getId()}"></td>
<td>
<div th:each="course: ${teachingAssistant.getCourses()}">
<a th:href="@{/courses/{code}(code=${course.getCode()})}" th:text="${course.getName()}"></a><br>
</div>
</td>
<td>
<a th:href="@{/teaching_assistants/{id}/delete(id=${teachingAssistant.getId()})}">Delete</a>
</td>
@ -24,9 +30,5 @@
</table>
</div>
<div id="sidebar">
</div>
</body>
</html>

View File

@ -1,33 +1,21 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (~{::title}, ~{::#content}, ~{::#sidebar})}">
<head>
<title>Teaching Assistant</title>
</head>
<html lang="en" xmlns:th="http://www.thymeleaf.org" th:replace="~{layouts/basic_page :: layout (title=${teachingAssistant.getFullName()}, content=~{::#content})}">
<body>
<div id="content">
<h1>Teaching Assistant: <span th:text="${teachingAssistant.getFullName()}"></span></h1>
<ul>
<li>
Email: <code th:text="${teachingAssistant.getEmailAddress()}"></code>
</li>
<li>
Github Username: <code th:text="${teachingAssistant.getGithubUsername()}"></code>
</li>
<li>
Courses:
<ul>
<li th:each="course: ${teachingAssistant.getCourses()}">
<a th:href="@{/courses/{code}(code=${course.getCode()})}"><span th:text="${course.getName()}"></span></a>
</li>
</ul>
</li>
</ul>
</div>
<div id="sidebar">
<div id="content" class="row justify-content-center">
<div class="col-sm-12 col-md-6">
<div class="list-group">
<a class="list-group-item list-group-item-action" th:text="'Email: ' + ${teachingAssistant.getEmailAddress()}" th:href="'mailto: ' + ${teachingAssistant.getEmailAddress()}"></a>
<a class="list-group-item list-group-item-action" th:text="'Github Username: ' + ${teachingAssistant.getGithubUsername()}" th:href="'https://www.github.com/' + ${teachingAssistant.getGithubUsername()}" target="_blank"></a>
<div class="list-group-item">
<h5>Courses</h5>
<div th:each="course: ${teachingAssistant.getCourses()}">
<a class="list-group-item-action" th:text="${course.getName()}" th:href="@{/courses/{code}(code=${course.getCode()})}"></a><br>
</div>
</div>
</div>
</div>
</div>
</body>