diff --git a/src/main/java/id/ac/ui/cs/advprog/turorial0/controller/CourseController.java b/src/main/java/id/ac/ui/cs/advprog/turorial0/controller/CourseController.java new file mode 100644 index 0000000000000000000000000000000000000000..fb5cca447bc9c0182b3a4defd9c4e6c45ed5a32e --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/turorial0/controller/CourseController.java @@ -0,0 +1,46 @@ +package id.ac.ui.cs.advprog.turorial0.controller; + +import id.ac.ui.cs.advprog.turorial0.exception.DuplicateCourseNameException; +import id.ac.ui.cs.advprog.turorial0.model.Course; +import id.ac.ui.cs.advprog.turorial0.service.CourseService; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Controller +@RequestMapping("/course") +public class CourseController { + @Autowired + private CourseService service; + + @GetMapping("/list") + public String courseListPage(Model model) { + List<Course> allCourses = service.findAll(); + model.addAttribute("courses", allCourses); + return "coursesList"; + } + + @GetMapping("/create") + public String createCoursePage(Model model) { + Course course = new Course(); + model.addAttribute("course", course); + return "createCourse"; + } + + @PostMapping("/create") + public String createCoursePost(@ModelAttribute Course course, Model model) { + try { + service.create(course); + } catch (DuplicateCourseNameException e) { + model.addAttribute("error", e); + model.addAttribute("course", course); + return "createCourse"; + } + return "redirect:list"; + } +} + diff --git a/src/main/java/id/ac/ui/cs/advprog/turorial0/exception/DuplicateCourseNameException.java b/src/main/java/id/ac/ui/cs/advprog/turorial0/exception/DuplicateCourseNameException.java new file mode 100644 index 0000000000000000000000000000000000000000..5898d132c25dc5d94e657ec6c2170155f08c897d --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/turorial0/exception/DuplicateCourseNameException.java @@ -0,0 +1,7 @@ +package id.ac.ui.cs.advprog.turorial0.exception; + +public class DuplicateCourseNameException extends RuntimeException { + public DuplicateCourseNameException(String courseName) { + super(String.format("The course name %s is a duplicate!", courseName)); + } +} \ No newline at end of file diff --git a/src/main/java/id/ac/ui/cs/advprog/turorial0/model/Course.java b/src/main/java/id/ac/ui/cs/advprog/turorial0/model/Course.java new file mode 100644 index 0000000000000000000000000000000000000000..6a1dd2a0579fe65d8fe0c9921b5c85c3320d442c --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/turorial0/model/Course.java @@ -0,0 +1,12 @@ +package id.ac.ui.cs.advprog.turorial0.model; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class Course { + private String courseName; + private String courseId; + private boolean vacancyStatus = true; +} \ No newline at end of file diff --git a/src/main/java/id/ac/ui/cs/advprog/turorial0/repository/CourseRepository.java b/src/main/java/id/ac/ui/cs/advprog/turorial0/repository/CourseRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..0da0b7abb1602aafdf464de12bf6d6b845c46715 --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/turorial0/repository/CourseRepository.java @@ -0,0 +1,30 @@ +package id.ac.ui.cs.advprog.turorial0.repository; + +import id.ac.ui.cs.advprog.turorial0.model.Course; +import id.ac.ui.cs.advprog.turorial0.exception.DuplicateCourseNameException; +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.*; + +@Repository +public class CourseRepository { + private List<Course> courseList = new ArrayList<>(); + private Map<String, Course> courseMap = new HashMap<>(); + + public Course create(Course course) { + if (courseMap.get(course.getCourseName()) == null) { + courseMap.put(course.getCourseName(), course); + courseList.add(course); + return course; + } + + throw new DuplicateCourseNameException(course.getCourseName()); + } + + public Iterator<Course> findAll() { + return courseList.iterator(); + } +} diff --git a/src/main/java/id/ac/ui/cs/advprog/turorial0/service/CourseService.java b/src/main/java/id/ac/ui/cs/advprog/turorial0/service/CourseService.java new file mode 100644 index 0000000000000000000000000000000000000000..f6eeb25ceb13e393e030754966a381a822cde7be --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/turorial0/service/CourseService.java @@ -0,0 +1,11 @@ +package id.ac.ui.cs.advprog.turorial0.service; + +import id.ac.ui.cs.advprog.turorial0.model.Course; + +import java.util.List; + +public interface CourseService { + public Course create(Course course); + + public List<Course> findAll(); +} diff --git a/src/main/java/id/ac/ui/cs/advprog/turorial0/service/CourseServiceImpl.java b/src/main/java/id/ac/ui/cs/advprog/turorial0/service/CourseServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..432ce0ea6d97b2583d0d7124e0267bdd1e602f48 --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/turorial0/service/CourseServiceImpl.java @@ -0,0 +1,40 @@ +package id.ac.ui.cs.advprog.turorial0.service; + +import id.ac.ui.cs.advprog.turorial0.model.Course; +import id.ac.ui.cs.advprog.turorial0.repository.CourseRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +@Service +public class CourseServiceImpl implements CourseService { + @Autowired + private CourseRepository courseRepo; + + @Override + public Course create(Course course) { + courseRepo.create(course); + generateCourseId(course); + return course; + } + + private void generateCourseId(Course course) { + StringBuilder stringBuilder = new StringBuilder(); + for (char letter : course.getCourseName().toCharArray()) { + if (stringBuilder.toString().length() <= 30) { + stringBuilder.append(String.valueOf((int) letter)); + } + } + + course.setCourseId(stringBuilder.toString()); + } + + @Override + public List<Course> findAll() { + Iterator<Course> courseIterator = courseRepo.findAll(); + List<Course> courseList = new ArrayList<>(); + courseIterator.forEachRemaining(courseList::add); + return courseList; + } +} diff --git a/src/main/resources/templates/courseList.html b/src/main/resources/templates/courseList.html new file mode 100644 index 0000000000000000000000000000000000000000..a5f68a3b3fa3cdd42c09f3f5cbf9dbd508f35d88 --- /dev/null +++ b/src/main/resources/templates/courseList.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<html lang="en" xmlns:th="http://www.thymeleaf.org"> +<head> + <meta charset="UTF-8"> + <title>Course List</title> + <link + href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" + rel="stylesheet" + integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" + crossorigin="anonymous" + > +</head> +<body class="p-2"> + +<div class="w-50 mx-auto"> + <h2>Course' List</h2> + <a th:href="@{/course/create}" class="btn btn-primary btn-sm mb-3">Create course</a> + + <table class="table"> + <thead> + <tr> + <th scope="col">Course ID</th> + <th scope="col">Course Name</th> + <th scope="col">Vacancy Status</th> + </tr> + </thead> + <tbody th:each="course: ${courses}"> + <tr> + <td th:text="${course.courseId}"></td> + <td th:text="${course.courseName}"></td> + <td th:text="${course.vacancyStatus}"></td> + </tr> + + </tbody> + </table> +</div> + +<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" + integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" + crossorigin="anonymous"> +</script> +</body> +</html> \ No newline at end of file diff --git a/src/main/resources/templates/createCourse.html b/src/main/resources/templates/createCourse.html new file mode 100644 index 0000000000000000000000000000000000000000..4d21e90478c845ed9d845010284b1c7aeba9493e --- /dev/null +++ b/src/main/resources/templates/createCourse.html @@ -0,0 +1,44 @@ +<!DOCTYPE html> +<html lang="en" xmlns:th="http://www.thymeleaf.org"> +<head> + <meta charset="UTF-8"> + <title>Create new Course</title> + <link + href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" + rel="stylesheet" + integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" + crossorigin="anonymous" + > +</head> +<body class="p-2"> +<div class="w-25 mx-auto"> + <h3>Create new Course</h3> + <form th:action="@{/course/create}" th:object="${course}" method="post"> + <div class="form-group"> + <label for="nameInput">Course Name</label> + <input + th:field="*{courseName}" + type="text" + class="form-control" + id="nameInput" + aria-describedby="nameHelp" + placeholder="Enter course' name" + required + /> + <!-- bagian input field tersebut dipasangkan dengan field `name` pada `Student`.--> + <small id="nameHelp" class="form-text text-muted">Please enter unique course.</small> + </div> + <div class="form-group"> + <label for="addressTextarea">Vacancy Status</label> + <textarea th:field="*{vacancyStatus}" class="form-control" id="addressTextarea" rows="3"></textarea> + </div> + <button type="submit" class="btn btn-primary my-2">Submit</button> + </form> +</div> +<script + src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" + integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" + crossorigin="anonymous"> +</script> +</body> +</html> \ No newline at end of file