Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/questions #71

Merged
merged 12 commits into from
Mar 3, 2024
28 changes: 28 additions & 0 deletions api/src/main/java/lab/en2b/quizapi/questions/answer/Answer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package lab.en2b.quizapi.questions.answer;

import jakarta.persistence.*;
import lab.en2b.quizapi.questions.question.Question;
import lombok.*;

import java.util.List;

@Entity
@Table(name = "answers")
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class Answer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Setter(AccessLevel.NONE)
private Long id;
private String text;
private AnswerCategory category;
@OneToMany(mappedBy = "correctAnswer", fetch = FetchType.EAGER)
private List<Question> questions;

@ManyToMany(mappedBy = "answers", fetch = FetchType.EAGER)
private List<Question> questionsWithThisAnswer;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package lab.en2b.quizapi.questions.answer;

public enum AnswerCategory {
CITY, COUNTRY, PERSON, EVENT, DATE, OTHER
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package lab.en2b.quizapi.questions.answer.dtos;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor
public class AnswerDto {
@JsonProperty("answer_id")
private Long answerId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package lab.en2b.quizapi.questions.answer.dtos;

import lab.en2b.quizapi.questions.answer.AnswerCategory;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@Getter
public class AnswerResponseDto {
private Long id;
private String text;
private AnswerCategory category;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package lab.en2b.quizapi.questions.answer.mappers;

import lab.en2b.quizapi.questions.answer.Answer;
import lab.en2b.quizapi.questions.answer.dtos.AnswerResponseDto;
import org.springframework.stereotype.Service;

import java.util.function.Function;

@Service
public class AnswerResponseDtoMapper implements Function<Answer, AnswerResponseDto> {
@Override
public AnswerResponseDto apply(Answer answer) {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package lab.en2b.quizapi.questions.question;

import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import lab.en2b.quizapi.questions.answer.Answer;
import lab.en2b.quizapi.questions.answer.AnswerCategory;
import lombok.*;

import java.util.List;

@Entity
@Table(name = "questions")
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class Question {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Setter(AccessLevel.NONE)
private Long id;
private String content;
@NotNull
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name="questions_answers",
joinColumns=
@JoinColumn(name="question_id", referencedColumnName="id"),
inverseJoinColumns=
@JoinColumn(name="answer_id", referencedColumnName="id")
)
private List<Answer> answers;
@ManyToOne
@JoinColumn(name = "correct_answer_id")
private Answer correctAnswer;
private QuestionCategory questionCategory;
private AnswerCategory answerCategory;
private String language;
private QuestionType type;


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package lab.en2b.quizapi.questions.question;

public enum QuestionCategory {
HISTORY, GEOGRAPHY, SCIENCE, MATH, LITERATURE, ART, SPORTS, MUSIC, MOVIES, TV, POLITICS, OTHER
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,38 @@
package lab.en2b.quizapi.questions.question;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import lab.en2b.quizapi.questions.answer.dtos.AnswerDto;
import lab.en2b.quizapi.questions.question.dtos.AnswerCheckResponseDto;
import lab.en2b.quizapi.questions.question.dtos.QuestionResponseDto;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/questions")
@RequiredArgsConstructor
public class QuestionController {
@GetMapping("/dummy")
private String getDummyQuestion(){
return "Who the hell is Steve Jobs?";
private final QuestionService questionService;

// TODO: REMOVE WHEN NOT USED FOR TESTING
@GetMapping
private ResponseEntity<List<QuestionResponseDto>> getQuestions() {
return ResponseEntity.ok(questionService.getQuestions());
}

@PostMapping("/{questionId}/answer")
private ResponseEntity<AnswerCheckResponseDto> answerQuestion(@PathVariable Long questionId, @RequestBody AnswerDto answerDto){
return ResponseEntity.ok(questionService.answerQuestion(questionId,answerDto));
}

@GetMapping("/new")
private ResponseEntity<QuestionResponseDto> generateQuestion(){
return ResponseEntity.ok(questionService.getQuestion());
}

@GetMapping("/{id}")
private ResponseEntity<QuestionResponseDto> getQuestionById(@PathVariable Long id){
return ResponseEntity.ok(questionService.getQuestionById(id));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package lab.en2b.quizapi.questions.question;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

public interface QuestionRepository extends JpaRepository<Question,Long> {
@Query(value = "SELECT * FROM questions ORDER BY RAND() LIMIT 1", nativeQuery = true)
Question findRandomQuestion();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package lab.en2b.quizapi.questions.question;

import lab.en2b.quizapi.questions.answer.dtos.AnswerDto;
import lab.en2b.quizapi.questions.question.dtos.AnswerCheckResponseDto;
import lab.en2b.quizapi.questions.question.dtos.QuestionResponseDto;
import lab.en2b.quizapi.questions.question.mappers.QuestionResponseDtoMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
public class QuestionService {

private final QuestionRepository questionRepository;
private final QuestionResponseDtoMapper questionResponseDtoMapper;
public List<QuestionResponseDto> getQuestions() {
return questionRepository.findAll().stream().map(questionResponseDtoMapper).toList();
}

public AnswerCheckResponseDto answerQuestion(Long id, AnswerDto answerDto) {
Question question = questionRepository.findById(id).orElseThrow();
if(question.getCorrectAnswer().getId().equals(answerDto.getAnswerId())){
return new AnswerCheckResponseDto(true);
}
else if(question.getAnswers().stream().noneMatch(i -> i.getId().equals(answerDto.getAnswerId()))){
throw new IllegalArgumentException("The answer you provided is not one of the options");
}
else {
return new AnswerCheckResponseDto(false);
}
}

public QuestionResponseDto getQuestion() {
return questionResponseDtoMapper.apply(questionRepository.findRandomQuestion());
}

public QuestionResponseDto getQuestionById(Long id) {
return questionResponseDtoMapper.apply(questionRepository.findById(id).orElseThrow());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package lab.en2b.quizapi.questions.question;

public enum QuestionType {
TEXT, VIDEO, IMAGE, AUDIO

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package lab.en2b.quizapi.questions.question.dtos;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@AllArgsConstructor
@Getter
public class AnswerCheckResponseDto {
private boolean wasCorrect;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package lab.en2b.quizapi.questions.question.dtos;

import lab.en2b.quizapi.questions.answer.AnswerCategory;
import lab.en2b.quizapi.questions.answer.dtos.AnswerResponseDto;
import lab.en2b.quizapi.questions.question.QuestionCategory;
import lab.en2b.quizapi.questions.question.QuestionType;
import lombok.Builder;

import java.util.List;

@Builder
public class QuestionResponseDto {
private Long id;
private String content;
private List<AnswerResponseDto> answers;
private QuestionCategory questionCategory;
private AnswerCategory answerCategory;
private String language;
private QuestionType type;



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package lab.en2b.quizapi.questions.question.mappers;

import lab.en2b.quizapi.questions.answer.mappers.AnswerResponseDtoMapper;
import lab.en2b.quizapi.questions.question.Question;
import lab.en2b.quizapi.questions.question.dtos.QuestionResponseDto;
import org.springframework.stereotype.Service;

import java.util.function.Function;

@Service
public class QuestionResponseDtoMapper implements Function<Question, QuestionResponseDto> {

@Override
public QuestionResponseDto apply(Question question) {
return QuestionResponseDto.builder()
.id(question.getId())
.content(question.getContent())
.type(question.getType())
.answerCategory(question.getAnswerCategory())
.answers(question.getAnswers().stream().map(new AnswerResponseDtoMapper()).toList())
.language(question.getLanguage())
.questionCategory(question.getQuestionCategory())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package lab.en2b.quizapi;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package lab.en2b.quizapi.questions;

import lab.en2b.quizapi.auth.config.SecurityConfig;
import lab.en2b.quizapi.auth.jwt.JwtUtils;
import lab.en2b.quizapi.questions.question.QuestionController;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(QuestionController.class)
@AutoConfigureMockMvc
@Import(SecurityConfig.class)
public class QuestionControllerTest {
@Autowired
MockMvc mockMvc;
@Mock
JwtUtils jwtUtils;
@Test
void getQuestionShouldReturn200() throws Exception {
mockMvc.perform(get("/questions")
.contentType("application/json")
.with(csrf()))
.andExpect(status().isOk());
}
}