From 58a366b2c733d9e94f7047501bd6bdf1e59fd76a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Svein=20K=C3=A5re?= Date: Thu, 28 Mar 2024 14:06:44 +0100 Subject: [PATCH 1/2] Removed category field from questions --- src/main/java/com/idatt2105/backend/dto/QuestionDTO.java | 1 - src/main/java/com/idatt2105/backend/model/Question.java | 7 +------ .../java/com/idatt2105/backend/model/QuestionAttempt.java | 2 -- .../idatt2105/backend/repository/QuestionRepository.java | 2 -- 4 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/main/java/com/idatt2105/backend/dto/QuestionDTO.java b/src/main/java/com/idatt2105/backend/dto/QuestionDTO.java index b9c6c80..ff028a6 100644 --- a/src/main/java/com/idatt2105/backend/dto/QuestionDTO.java +++ b/src/main/java/com/idatt2105/backend/dto/QuestionDTO.java @@ -14,7 +14,6 @@ public class QuestionDTO { private Long questionId; private String questionText; private String mediaUrl; - private String category; private int points; private Long quizId; private QuestionType type; diff --git a/src/main/java/com/idatt2105/backend/model/Question.java b/src/main/java/com/idatt2105/backend/model/Question.java index 48255a9..b2f86f9 100644 --- a/src/main/java/com/idatt2105/backend/model/Question.java +++ b/src/main/java/com/idatt2105/backend/model/Question.java @@ -35,9 +35,6 @@ public class Question { @Column(name = "media_url") private String mediaUrl; - @Column(name = "category") - private String category; - @Column(name = "points") private int points; @@ -49,7 +46,6 @@ public class Question { public void extractFromDTO(QuestionDTO dto) { this.questionText = dto.getQuestionText(); this.mediaUrl = dto.getMediaUrl(); - this.category = dto.getCategory(); this.points = dto.getPoints(); } @@ -72,13 +68,12 @@ public boolean equals(Object o) { && Objects.equals(id, question.id) && Objects.equals(questionText, question.questionText) && Objects.equals(mediaUrl, question.mediaUrl) - && Objects.equals(category, question.category) && Objects.equals(thisQuizId, thatQuizId); } @Override public int hashCode() { Long quizId = quiz == null ? null : quiz.getId(); - return Objects.hash(id, questionText, mediaUrl, category, points, quizId); + return Objects.hash(id, questionText, mediaUrl, points, quizId); } } diff --git a/src/main/java/com/idatt2105/backend/model/QuestionAttempt.java b/src/main/java/com/idatt2105/backend/model/QuestionAttempt.java index a0a234c..3e60c55 100644 --- a/src/main/java/com/idatt2105/backend/model/QuestionAttempt.java +++ b/src/main/java/com/idatt2105/backend/model/QuestionAttempt.java @@ -27,7 +27,6 @@ public class QuestionAttempt { private String questionText; private String mediaUrl; - private String category; private int points; @ManyToOne @@ -38,7 +37,6 @@ public class QuestionAttempt { public void extractFromDTO(QuestionAttemptDTO dto) { this.questionText = dto.getQuestionText(); this.mediaUrl = dto.getMediaUrl(); - this.category = dto.getCategory(); this.points = dto.getPoints(); } } diff --git a/src/main/java/com/idatt2105/backend/repository/QuestionRepository.java b/src/main/java/com/idatt2105/backend/repository/QuestionRepository.java index e420bd1..2ced25b 100644 --- a/src/main/java/com/idatt2105/backend/repository/QuestionRepository.java +++ b/src/main/java/com/idatt2105/backend/repository/QuestionRepository.java @@ -7,7 +7,5 @@ import com.idatt2105.backend.model.Question; public interface QuestionRepository extends JpaRepository { - List findQuestionsByCategory(String category); - List findQuestionsByQuizId(Long quizId); } From d335ea31ca5624f6d8b0907dff747eb77e068108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Svein=20K=C3=A5re?= Date: Thu, 28 Mar 2024 17:04:46 +0100 Subject: [PATCH 2/2] Added category to quizzes --- pom.xml | 2 +- .../backend/controller/QuizController.java | 36 ++++++++---- .../backend/dto/QuestionAttemptDTO.java | 1 - .../com/idatt2105/backend/dto/QuizDTO.java | 18 +++++- .../com/idatt2105/backend/model/Category.java | 33 +++++++++++ .../com/idatt2105/backend/model/Quiz.java | 3 + .../repository/CategoryRepository.java | 13 +++++ .../backend/repository/QuizRepository.java | 3 + .../backend/service/QuizService.java | 55 +++++++++++++++++-- .../backend/dto/QuestionAttemptDTOTests.java | 14 ----- .../backend/dto/QuestionDTOTests.java | 12 ---- .../backend/model/QuestionAttemptTests.java | 15 ----- .../backend/model/QuestionTests.java | 14 ----- 13 files changed, 144 insertions(+), 75 deletions(-) create mode 100644 src/main/java/com/idatt2105/backend/model/Category.java create mode 100644 src/main/java/com/idatt2105/backend/repository/CategoryRepository.java diff --git a/pom.xml b/pom.xml index 358aa06..c7d8c7c 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.idatt2105 backend - 0.0.1-SNAPSHOT + 1.1 backend Backend for IDATT2105 Project diff --git a/src/main/java/com/idatt2105/backend/controller/QuizController.java b/src/main/java/com/idatt2105/backend/controller/QuizController.java index e51e978..5502ad3 100644 --- a/src/main/java/com/idatt2105/backend/controller/QuizController.java +++ b/src/main/java/com/idatt2105/backend/controller/QuizController.java @@ -17,8 +17,8 @@ import org.springframework.web.bind.annotation.RestController; import com.idatt2105.backend.dto.QuizDTO; -import com.idatt2105.backend.dto.QuizUpdateRequestDTO; import com.idatt2105.backend.dto.UserDTO; +import com.idatt2105.backend.model.Category; import com.idatt2105.backend.model.Tag; import com.idatt2105.backend.service.QuizService; @@ -84,17 +84,8 @@ public ResponseEntity removeUserFromQuiz( @PutMapping("/{id}") @Operation(summary = "Update quiz") public ResponseEntity updateQuiz( - @PathVariable("id") Long id, @RequestBody QuizUpdateRequestDTO requestDTO) { - if (requestDTO.getQuizPictureUrl() == null) { - requestDTO.setQuizPictureUrl(quizService.getQuizById(id).getQuizPictureUrl()); - } - QuizDTO updatedQuiz = - new QuizDTO.Builder() - .setTitle(requestDTO.getTitle()) - .setDescription(requestDTO.getDescription()) - .setQuizPictureUrl(requestDTO.getQuizPictureUrl()) - .build(); - quizService.updateQuiz(id, updatedQuiz); + @PathVariable("id") Long id, @RequestBody QuizDTO requestDTO) { + quizService.updateQuiz(id, requestDTO); return new ResponseEntity<>(HttpStatus.OK); } @@ -139,4 +130,25 @@ public ResponseEntity> getAllTags() { List tags = quizService.getAllTags(); return new ResponseEntity<>(tags, HttpStatus.OK); } + + @PostMapping("/create/category") + @Operation(summary = "Create a new category") + public ResponseEntity createCategory(@RequestBody Category category) { + Category createdCategory = quizService.createCategory(category); + return new ResponseEntity<>(createdCategory, HttpStatus.CREATED); + } + + @PostMapping("/category") + @Operation(summary = "Get all quizzes with a specific category") + public ResponseEntity> getQuizzesByCategory(@RequestBody Category category) { + List quizzes = quizService.getQuizzesByCategory(category); + return new ResponseEntity<>(quizzes, HttpStatus.OK); + } + + @GetMapping("/categories") + @Operation(summary = "Get all categories") + public ResponseEntity> getAllCategories() { + List categories = quizService.getAllCategories(); + return new ResponseEntity<>(categories, HttpStatus.OK); + } } diff --git a/src/main/java/com/idatt2105/backend/dto/QuestionAttemptDTO.java b/src/main/java/com/idatt2105/backend/dto/QuestionAttemptDTO.java index 596cc1d..6bc13ac 100644 --- a/src/main/java/com/idatt2105/backend/dto/QuestionAttemptDTO.java +++ b/src/main/java/com/idatt2105/backend/dto/QuestionAttemptDTO.java @@ -16,7 +16,6 @@ public class QuestionAttemptDTO { private QuestionType type; private String questionText; private String mediaUrl; - private String category; private int points; private Set alternatives = new HashSet<>(); private Boolean userAnswer; diff --git a/src/main/java/com/idatt2105/backend/dto/QuizDTO.java b/src/main/java/com/idatt2105/backend/dto/QuizDTO.java index d37276c..3ad744c 100644 --- a/src/main/java/com/idatt2105/backend/dto/QuizDTO.java +++ b/src/main/java/com/idatt2105/backend/dto/QuizDTO.java @@ -29,6 +29,7 @@ public class QuizDTO { private String title; private String description; private String quizPictureUrl; + private String categoryName; private LocalDateTime creationDate; private LocalDateTime lastModifiedDate; private Set userDTOs; @@ -44,6 +45,7 @@ public QuizDTO(Quiz quiz) { this.title = quiz.getTitle(); this.description = quiz.getDescription(); this.quizPictureUrl = quiz.getQuizPictureUrl(); + this.categoryName = quiz.getCategory() == null ? null : quiz.getCategory().getName(); this.creationDate = quiz.getCreationDate(); this.lastModifiedDate = quiz.getLastModifiedDate(); this.userDTOs = new HashSet<>(); @@ -82,6 +84,7 @@ public static class Builder { private String title; private String description; private String quizPictureUrl; + private String categoryName; private LocalDateTime creationDate; private LocalDateTime lastModifiedDate; private Set userDTOs; @@ -107,6 +110,11 @@ public Builder setQuizPictureUrl(String quizPictureUrl) { return this; } + public Builder setCategoryName(String categoryName) { + this.categoryName = categoryName; + return this; + } + public Builder setCreationDate(LocalDateTime creationDate) { this.creationDate = creationDate; return this; @@ -129,7 +137,15 @@ public Builder setTags(Set tags) { public QuizDTO build() { return new QuizDTO( - id, title, description, quizPictureUrl, creationDate, lastModifiedDate, userDTOs, tags); + id, + title, + description, + quizPictureUrl, + categoryName, + creationDate, + lastModifiedDate, + userDTOs, + tags); } } } diff --git a/src/main/java/com/idatt2105/backend/model/Category.java b/src/main/java/com/idatt2105/backend/model/Category.java new file mode 100644 index 0000000..52bfeeb --- /dev/null +++ b/src/main/java/com/idatt2105/backend/model/Category.java @@ -0,0 +1,33 @@ +package com.idatt2105.backend.model; + +import java.util.Set; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import io.swagger.v3.oas.annotations.Hidden; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import lombok.Data; + +@Entity +@Data +public class Category { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "name") + private String name; + + @Column(name = "picture_url") + private String pictureUrl; + + @OneToMany(mappedBy = "category") + @Hidden + @JsonIgnore + private Set quizzes; +} diff --git a/src/main/java/com/idatt2105/backend/model/Quiz.java b/src/main/java/com/idatt2105/backend/model/Quiz.java index 96f01da..37c64c1 100644 --- a/src/main/java/com/idatt2105/backend/model/Quiz.java +++ b/src/main/java/com/idatt2105/backend/model/Quiz.java @@ -18,6 +18,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinTable; import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import jakarta.validation.constraints.NotEmpty; @@ -72,6 +73,8 @@ public class Quiz { inverseJoinColumns = @JoinColumn(name = "tag_id")) private Set tags = new HashSet<>(); + @ManyToOne private Category category; + public void addTags(Collection tags) { tags.stream().filter(Objects::nonNull).forEach(this.tags::add); } diff --git a/src/main/java/com/idatt2105/backend/repository/CategoryRepository.java b/src/main/java/com/idatt2105/backend/repository/CategoryRepository.java new file mode 100644 index 0000000..40b7ac0 --- /dev/null +++ b/src/main/java/com/idatt2105/backend/repository/CategoryRepository.java @@ -0,0 +1,13 @@ +package com.idatt2105.backend.repository; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.idatt2105.backend.model.Category; + +public interface CategoryRepository extends JpaRepository { + Optional findByName(String name); + + boolean existsByName(String name); +} diff --git a/src/main/java/com/idatt2105/backend/repository/QuizRepository.java b/src/main/java/com/idatt2105/backend/repository/QuizRepository.java index 749fef1..77362a4 100644 --- a/src/main/java/com/idatt2105/backend/repository/QuizRepository.java +++ b/src/main/java/com/idatt2105/backend/repository/QuizRepository.java @@ -6,6 +6,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import com.idatt2105.backend.model.Category; import com.idatt2105.backend.model.Quiz; import com.idatt2105.backend.model.Tag; @@ -14,4 +15,6 @@ public interface QuizRepository extends JpaRepository { Optional findByTitle(String title); List findByTagsContains(Tag tag); + + List findByCategory(Category category); } diff --git a/src/main/java/com/idatt2105/backend/service/QuizService.java b/src/main/java/com/idatt2105/backend/service/QuizService.java index f6e9488..0ddbaa8 100644 --- a/src/main/java/com/idatt2105/backend/service/QuizService.java +++ b/src/main/java/com/idatt2105/backend/service/QuizService.java @@ -13,9 +13,11 @@ import com.idatt2105.backend.dto.QuizDTO; import com.idatt2105.backend.dto.UserDTO; +import com.idatt2105.backend.model.Category; import com.idatt2105.backend.model.Quiz; import com.idatt2105.backend.model.Tag; import com.idatt2105.backend.model.User; +import com.idatt2105.backend.repository.CategoryRepository; import com.idatt2105.backend.repository.QuizRepository; import com.idatt2105.backend.repository.TagRepository; import com.idatt2105.backend.repository.UserRepository; @@ -27,13 +29,18 @@ public class QuizService { private final QuizRepository quizRepository; private final UserRepository userRepository; private final TagRepository tagRepository; + private final CategoryRepository categoryRepository; @Autowired public QuizService( - QuizRepository quizRepository, UserRepository userRepository, TagRepository tagRepository) { + QuizRepository quizRepository, + UserRepository userRepository, + TagRepository tagRepository, + CategoryRepository categoryRepository) { this.quizRepository = quizRepository; this.userRepository = userRepository; this.tagRepository = tagRepository; + this.categoryRepository = categoryRepository; } public List getAllQuizzes() { @@ -76,10 +83,16 @@ public void updateQuiz(Long id, QuizDTO updatedQuiz) { Quiz existingQuiz = findQuiz(id); - existingQuiz.setTitle(updatedQuiz.getTitle()); - existingQuiz.setDescription(updatedQuiz.getDescription()); - existingQuiz.setLastModifiedDate(LocalDateTime.now()); - existingQuiz.setQuizPictureUrl(updatedQuiz.getQuizPictureUrl()); + // Only update fields that are included in the request + Optional.ofNullable(updatedQuiz.getTitle()).ifPresent(existingQuiz::setTitle); + Optional.ofNullable(updatedQuiz.getDescription()).ifPresent(existingQuiz::setDescription); + Optional.ofNullable(updatedQuiz.getQuizPictureUrl()).ifPresent(existingQuiz::setQuizPictureUrl); + Optional.ofNullable(updatedQuiz.getCategoryName()) + .ifPresent( + categoryName -> { + Category category = findCategoryByName(categoryName); + existingQuiz.setCategory(category); + }); quizRepository.save(existingQuiz); } @@ -189,6 +202,32 @@ public List getAllTags() { return tagRepository.findAll(); } + public Category createCategory(Category category) { + if (category == null) { + throw new IllegalArgumentException("Category parameter cannot be null."); + } + if (categoryRepository.existsByName(category.getName())) { + throw new IllegalArgumentException( + "Category with name " + category.getName() + " already exists."); + } + category.setId(null); // Avoids conflicts with existing categories + + return categoryRepository.save(category); + } + + public List getQuizzesByCategory(Category category) { + if (category == null) { + throw new IllegalArgumentException("Category parameter cannot be null."); + } + Category foundCategory = findCategoryByName(category.getName()); + List quizzes = quizRepository.findByCategory(foundCategory); + return quizzes.stream().map(QuizDTO::new).toList(); + } + + public List getAllCategories() { + return categoryRepository.findAll(); + } + private Quiz findQuiz(Long id) { return quizRepository .findById(id) @@ -200,4 +239,10 @@ private User findUser(Long id) { .findById(id) .orElseThrow(() -> new InvalidIdException("User with id " + id + " not found")); } + + private Category findCategoryByName(String name) { + return categoryRepository + .findByName(name) + .orElseThrow(() -> new InvalidIdException("Category with name " + name + " not found")); + } } diff --git a/src/test/java/com/idatt2105/backend/dto/QuestionAttemptDTOTests.java b/src/test/java/com/idatt2105/backend/dto/QuestionAttemptDTOTests.java index 89fa984..f5d861d 100644 --- a/src/test/java/com/idatt2105/backend/dto/QuestionAttemptDTOTests.java +++ b/src/test/java/com/idatt2105/backend/dto/QuestionAttemptDTOTests.java @@ -47,13 +47,6 @@ void testGetMediaUrl() { assertEquals(mediaUrl, questionAttemptDTO.getMediaUrl()); } - @Test - void testGetCategory() { - String category = "Category"; - questionAttemptDTO.setCategory(category); - assertEquals(category, questionAttemptDTO.getCategory()); - } - @Test void testGetPoints() { int points = 10; @@ -109,13 +102,6 @@ void testSetMediaUrl() { assertEquals(mediaUrl, questionAttemptDTO.getMediaUrl()); } - @Test - void testSetCategory() { - String category = "Category"; - questionAttemptDTO.setCategory(category); - assertEquals(category, questionAttemptDTO.getCategory()); - } - @Test void testSetPoints() { int points = 10; diff --git a/src/test/java/com/idatt2105/backend/dto/QuestionDTOTests.java b/src/test/java/com/idatt2105/backend/dto/QuestionDTOTests.java index 655faf1..65fee20 100644 --- a/src/test/java/com/idatt2105/backend/dto/QuestionDTOTests.java +++ b/src/test/java/com/idatt2105/backend/dto/QuestionDTOTests.java @@ -43,7 +43,6 @@ void setUp() { question.setType(QuestionType.MULTIPLE_CHOICE); question.setQuestionId(2L); question.setMediaUrl("test.com"); - question.setCategory("Test category"); question.isCorrect(true); } @@ -72,11 +71,6 @@ void getMediaUrlReturnsMediaUrl() { assertEquals("test.com", question.getMediaUrl()); } - @Test - void getCategoryReturnsCategory() { - assertEquals("Test category", question.getCategory()); - } - @Test void isCorrectReturnsCorrect() { assertTrue(question.isCorrect()); @@ -136,12 +130,6 @@ void setMediaUrlSetsMediaUrl() { assertEquals("test.com", question.getMediaUrl()); } - @Test - void setCategorySetsCategory() { - question.setCategory("Test category"); - assertEquals("Test category", question.getCategory()); - } - @Test void setCorrectSetsCorrect() { question.isCorrect(true); diff --git a/src/test/java/com/idatt2105/backend/model/QuestionAttemptTests.java b/src/test/java/com/idatt2105/backend/model/QuestionAttemptTests.java index 6f62c59..cff0ef6 100644 --- a/src/test/java/com/idatt2105/backend/model/QuestionAttemptTests.java +++ b/src/test/java/com/idatt2105/backend/model/QuestionAttemptTests.java @@ -39,13 +39,6 @@ void getMediaUrlReturnsCorrectMediaUrl() { assertEquals(expectedMediaUrl, questionAttempt.getMediaUrl()); } - @Test - void getCategoryReturnsCorrectCategory() { - String expectedCategory = "Geography"; - questionAttempt.setCategory(expectedCategory); - assertEquals(expectedCategory, questionAttempt.getCategory()); - } - @Test void getPointsReturnsCorrectPoints() { int expectedPoints = 5; @@ -84,13 +77,6 @@ void setMediaUrlSetsMediaUrlCorrectly() { assertEquals(expectedMediaUrl, questionAttempt.getMediaUrl()); } - @Test - void setCategorySetsCategoryCorrectly() { - String expectedCategory = "Geography"; - questionAttempt.setCategory(expectedCategory); - assertEquals(expectedCategory, questionAttempt.getCategory()); - } - @Test void setPointsSetsPointsCorrectly() { int expectedPoints = 5; @@ -115,7 +101,6 @@ void equalObjectsHashToSameValue() { q.setId(1L); q.setQuestionText("Test question"); q.setMediaUrl("Test media url"); - q.setCategory("Test category"); q.setPoints(1); QuizAttempt quiz = new QuizAttempt(); quiz.setId(1L); diff --git a/src/test/java/com/idatt2105/backend/model/QuestionTests.java b/src/test/java/com/idatt2105/backend/model/QuestionTests.java index 2d41de3..7be517d 100644 --- a/src/test/java/com/idatt2105/backend/model/QuestionTests.java +++ b/src/test/java/com/idatt2105/backend/model/QuestionTests.java @@ -30,13 +30,6 @@ void getMediaUrlReturnsCorrectUrl() { assertEquals("image.jpg", question.getMediaUrl()); } - @Test - void getCategoryReturnsCorrectCategory() { - Question question = new Question(); - question.setCategory("Geography"); - assertEquals("Geography", question.getCategory()); - } - @Test void getPointsReturnsCorrectPoints() { Question question = new Question(); @@ -76,13 +69,6 @@ void setMediaUrlSetsCorrectUrl() { assertEquals("image.jpg", question.getMediaUrl()); } - @Test - void setCategorySetsCorrectCategory() { - Question question = new Question(); - question.setCategory("Geography"); - assertEquals("Geography", question.getCategory()); - } - @Test void setPointsSetsCorrectPoints() { Question question = new Question();