diff --git a/backend/pom.xml b/backend/pom.xml
index a1fe9a5..2de204e 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -72,6 +72,11 @@
org.springframework.boot
spring-boot-starter-validation
+
+ org.apache.commons
+ commons-text
+ 1.10.0
+
diff --git a/backend/src/main/java/com/ninjaws/quiz/components/StartupRunner.java b/backend/src/main/java/com/ninjaws/quiz/components/StartupRunner.java
new file mode 100644
index 0000000..1885a81
--- /dev/null
+++ b/backend/src/main/java/com/ninjaws/quiz/components/StartupRunner.java
@@ -0,0 +1,27 @@
+package com.ninjaws.quiz.components;
+
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+/**
+ * Sets up the database, and adds the categories
+ *
+ * Fills up the primary database
+ *
+ * Then, at night, creates a new database, adds categories, and then starts filling it up
+ * When full, swaps the databases, and wipes the old one
+ */
+public class StartupRunner implements CommandLineRunner {
+ private final JdbcTemplate primaryJdbcTemplate;
+
+ public StartupRunner(JdbcTemplate primaryJdbcTemplate) {
+ this.primaryJdbcTemplate = primaryJdbcTemplate;
+ }
+
+ @Override
+ public void run(String... args) {
+ // Initialization logic here
+ primaryJdbcTemplate.execute("CREATE TABLE IF NOT EXISTS test_table (id INT PRIMARY KEY, name VARCHAR(255))");
+ primaryJdbcTemplate.update("INSERT INTO test_table (id, name) VALUES (?, ?)", 1, "Sample Data");
+ }
+}
diff --git a/backend/src/main/java/com/ninjaws/quiz/config/DataSourceConfig.java b/backend/src/main/java/com/ninjaws/quiz/config/DataSourceConfig.java
new file mode 100644
index 0000000..8645af9
--- /dev/null
+++ b/backend/src/main/java/com/ninjaws/quiz/config/DataSourceConfig.java
@@ -0,0 +1,46 @@
+package com.ninjaws.quiz.config;
+
+import javax.sql.DataSource;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Primary;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+public class DataSourceConfig {
+ @Primary
+ @Bean(name = "primaryDataSourceProperties")
+ @ConfigurationProperties("spring.datasource.primary")
+ public DataSourceProperties primaryDataSourceProperties() {
+ return new DataSourceProperties();
+ }
+
+ @Primary
+ @Bean(name = "primaryDataSource")
+ public DataSource primaryDataSource() {
+ return primaryDataSourceProperties().initializeDataSourceBuilder().build();
+ }
+
+ @Bean(name = "secondaryDataSourceProperties")
+ @ConfigurationProperties("spring.datasource.secondary")
+ public DataSourceProperties secondaryDataSourceProperties() {
+ return new DataSourceProperties();
+ }
+
+ @Bean(name = "secondaryDataSource")
+ public DataSource secondaryDataSource() {
+ return secondaryDataSourceProperties().initializeDataSourceBuilder().build();
+ }
+
+ @Bean
+ public JdbcTemplate primaryJdbcTemplate(@Qualifier("primaryDataSource") DataSource ds) {
+ return new JdbcTemplate(ds);
+ }
+
+ @Bean
+ public JdbcTemplate secondaryJdbcTemplate(@Qualifier("secondaryDataSource") DataSource ds) {
+ return new JdbcTemplate(ds);
+ }
+}
diff --git a/backend/src/main/java/com/ninjaws/quiz/entities/Category.java b/backend/src/main/java/com/ninjaws/quiz/entities/Category.java
new file mode 100644
index 0000000..3e20685
--- /dev/null
+++ b/backend/src/main/java/com/ninjaws/quiz/entities/Category.java
@@ -0,0 +1,25 @@
+package com.ninjaws.quiz.entities;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import lombok.Getter;
+import lombok.Setter;
+
+@Entity
+@Table(name = "category")
+@Getter
+@Setter
+public class Category {
+ @Id
+ private Integer id;
+ private String name;
+
+ public Category() {}
+
+ public Category(int id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+}
diff --git a/backend/src/main/java/com/ninjaws/quiz/entities/QuestionEntity.java b/backend/src/main/java/com/ninjaws/quiz/entities/QuestionEntity.java
new file mode 100644
index 0000000..753254d
--- /dev/null
+++ b/backend/src/main/java/com/ninjaws/quiz/entities/QuestionEntity.java
@@ -0,0 +1,36 @@
+package com.ninjaws.quiz.entities;
+
+import java.util.List;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
+import lombok.Getter;
+import lombok.Setter;
+
+@Entity
+@Table(name = "question")
+@Getter
+@Setter
+public class QuestionEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @ManyToOne
+ @JoinColumn(name = "category", nullable = false)
+ private Category category;
+
+ private String difficulty;
+ private String type;
+ private String question;
+
+ //* Hidden from the user */
+ private String correctAnswer;
+ private List incorrectAnswers;
+}
diff --git a/backend/src/main/java/com/ninjaws/quiz/models/ApiResponse.java b/backend/src/main/java/com/ninjaws/quiz/models/ApiResponse.java
index 776d0e0..9715b25 100644
--- a/backend/src/main/java/com/ninjaws/quiz/models/ApiResponse.java
+++ b/backend/src/main/java/com/ninjaws/quiz/models/ApiResponse.java
@@ -17,5 +17,5 @@ public class ApiResponse {
@JsonProperty("response_code")
private int responseCode;
@JsonProperty("results")
- private List results;
+ private List results;
}
diff --git a/backend/src/main/java/com/ninjaws/quiz/models/CategoryResponse.java b/backend/src/main/java/com/ninjaws/quiz/models/CategoryResponse.java
new file mode 100644
index 0000000..2644a4b
--- /dev/null
+++ b/backend/src/main/java/com/ninjaws/quiz/models/CategoryResponse.java
@@ -0,0 +1,14 @@
+package com.ninjaws.quiz.models;
+
+import java.util.List;
+
+import com.ninjaws.quiz.entities.Category;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class CategoryResponse {
+ List trivia_categories;
+}
diff --git a/backend/src/main/java/com/ninjaws/quiz/models/Question.java b/backend/src/main/java/com/ninjaws/quiz/models/QuestionDTO.java
similarity index 88%
rename from backend/src/main/java/com/ninjaws/quiz/models/Question.java
rename to backend/src/main/java/com/ninjaws/quiz/models/QuestionDTO.java
index 6c0a32d..4127152 100644
--- a/backend/src/main/java/com/ninjaws/quiz/models/Question.java
+++ b/backend/src/main/java/com/ninjaws/quiz/models/QuestionDTO.java
@@ -7,25 +7,17 @@ import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
-import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
-@Entity
-@Table(name = "question")
@Getter
@Setter
-public class Question {
+public class QuestionDTO {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private Long id;
-
- private String type;
- private String difficulty;
private String category;
+ private String difficulty;
+ private String type;
private String question;
-
//* Hidden from the user */
private String correctAnswer;
diff --git a/backend/src/main/java/com/ninjaws/quiz/models/QuizSettings.java b/backend/src/main/java/com/ninjaws/quiz/models/QuizSettings.java
index 9ed2ff4..cb82d5e 100644
--- a/backend/src/main/java/com/ninjaws/quiz/models/QuizSettings.java
+++ b/backend/src/main/java/com/ninjaws/quiz/models/QuizSettings.java
@@ -48,21 +48,25 @@ public class QuizSettings {
@Max(50)
private int amount = 10;
- private Type type = Type.ANY;
+ // private Type type = Type.ANY;
- private Difficulty difficulty = Difficulty.ANY;
-
- private Category category = Category.ANY;
+ // private Difficulty difficulty = Difficulty.ANY;
+ private Integer category;
+ private String difficulty;
+ private String type;
public QuizSettings(){}
/** Inverse of toApiQuery */
- public QuizSettings(int amount, Integer category, String difficulty, String type) {
+ public QuizSettings(int amount, Integer category, String difficulty, String type) {
this.amount = amount;
- this.category = category == null ? Category.ANY : Category.values()[category];
- this.difficulty = difficulty == null ? Difficulty.ANY : Difficulty.valueOf(difficulty.toUpperCase());
- this.type = type == null ? Type.ANY : type.equals("boolean") ? Type.BOOLEAN : Type.MULTIPLE;
+ this.category = category;
+ this.difficulty = difficulty;
+ this.type = type;
+ // this.category = category == null ? Category.ANY : Category.values()[category];
+ // this.difficulty = difficulty == null ? Difficulty.ANY : Difficulty.valueOf(difficulty.toUpperCase());
+ // this.type = type == null ? Type.ANY : type.equals("boolean") ? Type.BOOLEAN : Type.MULTIPLE;
}
/**
@@ -77,19 +81,37 @@ public class QuizSettings {
* Converts the class to a format that can be provided as arguments for the api request
* @return The resulting request arguments as String
*/
+ // public String toApiQuery() {
+ // StringBuilder query = new StringBuilder("?amount=" + amount);
+
+ // if (category != null && category != Category.ANY) {
+ // query.append("&category=").append(category.getApiValue());
+ // }
+
+ // if (difficulty != null && difficulty != Difficulty.ANY) {
+ // query.append("&difficulty=").append(difficulty.getApiValue());
+ // }
+
+ // if (type != null && type != Type.ANY) {
+ // query.append("&type=").append(type.getApiValue());
+ // }
+
+ // return query.toString();
+ // }
+
public String toApiQuery() {
StringBuilder query = new StringBuilder("?amount=" + amount);
- if (category != null && category != Category.ANY) {
- query.append("&category=").append(category.getApiValue());
+ if (category != null) {
+ query.append("&category=").append(category);
}
- if (difficulty != null && difficulty != Difficulty.ANY) {
- query.append("&difficulty=").append(difficulty.getApiValue());
+ if (difficulty != null ) {
+ query.append("&difficulty=").append(difficulty);
}
- if (type != null && type != Type.ANY) {
- query.append("&type=").append(type.getApiValue());
+ if (type != null ) {
+ query.append("&type=").append(type);
}
return query.toString();
diff --git a/backend/src/main/java/com/ninjaws/quiz/models/Session.java b/backend/src/main/java/com/ninjaws/quiz/models/Session.java
index 757467d..2916d6c 100644
--- a/backend/src/main/java/com/ninjaws/quiz/models/Session.java
+++ b/backend/src/main/java/com/ninjaws/quiz/models/Session.java
@@ -11,7 +11,7 @@ import lombok.Setter;
public class Session {
private final String id;
private int statusCode = 0;
- private List questions;
+ private List questions;
public Session() {
this.id = UUID.randomUUID().toString();
diff --git a/backend/src/main/java/com/ninjaws/quiz/repositories/CategoryRepository.java b/backend/src/main/java/com/ninjaws/quiz/repositories/CategoryRepository.java
new file mode 100644
index 0000000..e9bf67d
--- /dev/null
+++ b/backend/src/main/java/com/ninjaws/quiz/repositories/CategoryRepository.java
@@ -0,0 +1,11 @@
+package com.ninjaws.quiz.repositories;
+
+import java.util.Optional;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import com.ninjaws.quiz.entities.Category;
+
+public interface CategoryRepository extends JpaRepository{
+ Optional findByName(String name);
+}
diff --git a/backend/src/main/java/com/ninjaws/quiz/repositories/QuestionRepository.java b/backend/src/main/java/com/ninjaws/quiz/repositories/QuestionRepository.java
index 31e331a..4ec9de2 100644
--- a/backend/src/main/java/com/ninjaws/quiz/repositories/QuestionRepository.java
+++ b/backend/src/main/java/com/ninjaws/quiz/repositories/QuestionRepository.java
@@ -1,8 +1,26 @@
package com.ninjaws.quiz.repositories;
+import java.util.List;
+
import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
-import com.ninjaws.quiz.models.Question;
+import com.ninjaws.quiz.entities.QuestionEntity;
-public interface QuestionRepository extends JpaRepository {
+public interface QuestionRepository extends JpaRepository{//, JpaSpecificationExecutor {
+
+ @Query(value = "SELECT * FROM question AS q " +
+ "WHERE (?1 IS NULL OR q.category = ?1) " +
+ "AND (?2 IS NULL OR q.difficulty = ?2) " +
+ "AND (?3 IS NULL OR q.type = ?3) " +
+ "ORDER BY RAND() LIMIT ?4", nativeQuery = true)
+ List lookupQuestions(Integer categoryId, String difficulty, String type, int limit);
+
+ // public List getQuestionsBy(String type, String category, String difficulty, int limit) {
+ // Specification spec = Specification.where(QuestionSpecification.hasType(type))
+ // .and(QuestionSpecification.hasCategory(category))
+ // .and(QuestionSpecification.hasDifficulty(difficulty));
+
+ // return productRepository.findAll(spec);
+ // }
}
diff --git a/backend/src/main/java/com/ninjaws/quiz/services/ApiService.java b/backend/src/main/java/com/ninjaws/quiz/services/ApiService.java
index 7918f4f..219e6fb 100644
--- a/backend/src/main/java/com/ninjaws/quiz/services/ApiService.java
+++ b/backend/src/main/java/com/ninjaws/quiz/services/ApiService.java
@@ -9,6 +9,7 @@ import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import com.ninjaws.quiz.models.ApiResponse;
+import com.ninjaws.quiz.models.CategoryResponse;
import com.ninjaws.quiz.models.QuizSettings;
import com.ninjaws.quiz.models.Request;
@@ -26,13 +27,13 @@ public class ApiService {
private static final System.Logger logger = System.getLogger(ApiService.class.getName());
- private final String apiUrl = "https://opentdb.com/api.php";
+ private final String apiUrl = "https://opentdb.com";
public ApiService() {
}
private String buildRequestString(QuizSettings quizSettings) {
- return apiUrl + quizSettings.toApiQuery();
+ return apiUrl + "/api.php" + quizSettings.toApiQuery();
}
public void handleRequest(@Valid Request request) {
@@ -54,7 +55,9 @@ public class ApiService {
* Store them in the DataService
*/
public void collectBulk() {
- String url = apiUrl + "?amount=50";
+ // TODO: Make this happen only once, when a new database is generated
+ getCategories();
+ String url = apiUrl + "/api.php?amount=50";
try {
ResponseEntity response = restTemplate.getForEntity(url, String.class);
String json = response.getBody();
@@ -64,5 +67,21 @@ public class ApiService {
} catch (RestClientException | IOException e) {
logger.log(System.Logger.Level.ERROR, "Critical failure", e);
}
+
+ }
+
+
+ public void getCategories() {
+ String url = apiUrl + "/api_category.php";
+ try {
+ ResponseEntity response = restTemplate.getForEntity(url, String.class);
+ String json = response.getBody();
+ CategoryResponse categoryResponse = cleanerService.extractCategoryResponse(json);
+ responseHandler.handleCategoryResponse(categoryResponse);
+
+ } catch (RestClientException | IOException e) {
+ logger.log(System.Logger.Level.ERROR, "Critical failure", e);
+ }
+
}
}
diff --git a/backend/src/main/java/com/ninjaws/quiz/services/CleanerService.java b/backend/src/main/java/com/ninjaws/quiz/services/CleanerService.java
index 5385f67..9c08359 100644
--- a/backend/src/main/java/com/ninjaws/quiz/services/CleanerService.java
+++ b/backend/src/main/java/com/ninjaws/quiz/services/CleanerService.java
@@ -1,22 +1,87 @@
package com.ninjaws.quiz.services;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.StringEscapeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ninjaws.quiz.entities.Category;
+import com.ninjaws.quiz.entities.QuestionEntity;
import com.ninjaws.quiz.models.ApiResponse;
+import com.ninjaws.quiz.models.CategoryResponse;
+import com.ninjaws.quiz.models.QuestionDTO;
+import com.ninjaws.quiz.repositories.CategoryRepository;
@Service
public class CleanerService {
@Autowired
private ObjectMapper objectMapper;
+ @Autowired
+ private CategoryRepository categoryRepository;
- public CleanerService() {}
+ public CleanerService() {
+ }
public ApiResponse extractApiResponse(String json) throws IOException {
return objectMapper.readValue(json, ApiResponse.class);
}
+
+ public CategoryResponse extractCategoryResponse(String json) throws IOException {
+ return objectMapper.readValue(json, CategoryResponse.class);
+ }
+
+ public List questionListEntitytoDTO(List entities) {
+ List dtos = new ArrayList<>();
+ for (int i = 0; i < entities.size(); i++) {
+ QuestionEntity entity = entities.get(i);
+ dtos.add(questionEntityToDTO(entity));
+ }
+ return dtos;
+ }
+
+ public QuestionDTO questionEntityToDTO(QuestionEntity entity) {
+ QuestionDTO dto = new QuestionDTO();
+ dto.setQuestion(entity.getQuestion());
+ dto.setCorrectAnswer(entity.getCorrectAnswer());
+ dto.setIncorrectAnswer(entity.getIncorrectAnswers());
+ dto.setCategory(entity.getCategory().getName());
+ dto.setType(entity.getType());
+ dto.setDifficulty(entity.getDifficulty());
+ return dto;
+ }
+
+ public List questionListDTOtoEntity(List dtos) {
+ List entities = new ArrayList<>();
+ for (int i = 0; i < dtos.size(); i++) {
+ QuestionDTO dto = dtos.get(i);
+ entities.add(questionDTOtoEntity(dto));
+ }
+ return entities;
+ }
+
+ public QuestionEntity questionDTOtoEntity(QuestionDTO dto) {
+ QuestionEntity entity = new QuestionEntity();
+ Category category = categoryRepository.findByName(decodeString(dto.getCategory())).orElseThrow(() -> new IllegalStateException("Category not in DB!"));
+ entity.setCategory(category);
+ entity.setDifficulty(dto.getDifficulty());
+ entity.setType(dto.getType());
+ entity.setQuestion(dto.getQuestion());
+ entity.setCorrectAnswer(dto.getCorrectAnswer());
+ entity.setIncorrectAnswers(dto.getIncorrectAnswers());
+ return entity;
+ }
+
+ /**
+ * For some reason, the categories come with special characters,
+ * But the categories from the questions dont
+ * So this has to be manually fixed if they are to be stored in the db (otherwise namematching doesnt work)
+ */
+ private String decodeString(String text){
+ return StringEscapeUtils.unescapeHtml4(text);
+ }
}
diff --git a/backend/src/main/java/com/ninjaws/quiz/services/DataService.java b/backend/src/main/java/com/ninjaws/quiz/services/DataService.java
index ceefcd0..adb2469 100644
--- a/backend/src/main/java/com/ninjaws/quiz/services/DataService.java
+++ b/backend/src/main/java/com/ninjaws/quiz/services/DataService.java
@@ -5,23 +5,61 @@ import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-import com.ninjaws.quiz.models.Question;
+import com.ninjaws.quiz.entities.Category;
+import com.ninjaws.quiz.entities.QuestionEntity;
+import com.ninjaws.quiz.models.QuizSettings;
+import com.ninjaws.quiz.repositories.CategoryRepository;
import com.ninjaws.quiz.repositories.QuestionRepository;
@Service
public class DataService {
+
@Autowired
private QuestionRepository questionRepository;
- public List getAllQuestions() {
+ @Autowired
+ private CategoryRepository categoryRepository;
+
+ public List getAllQuestions() {
return questionRepository.findAll();
}
- public Question saveQuestion(Question question) {
+ public QuestionEntity saveQuestion(QuestionEntity question) {
return questionRepository.save(question);
}
- public List saveQuestions(List questions) {
+ public List saveQuestions(List questions) {
return questionRepository.saveAll(questions);
}
+
+ // public List getRandomQuestions(String type, String category, String difficulty, int limit) {
+ // return questionRepository.findRandomQuestions(type, limit);
+ // }
+
+ public List lookupQuestions(QuizSettings quizSettings) {
+ // Long category = Long.valueOf(quizSettings.getCategory().getApiValue() == 1 ? null : quizSettings.getCategory().getApiValue());
+ // String difficulty = quizSettings.getDifficulty() == QuizSettings.Difficulty.ANY ? null : quizSettings.getDifficulty().getApiValue();
+ // String type = quizSettings.getType() == QuizSettings.Type.ANY ? null : quizSettings.getType().getApiValue();
+ // System.out.println(category);
+ // System.out.println(difficulty);
+ // System.out.println(type);
+
+ return questionRepository.lookupQuestions(quizSettings.getCategory(), quizSettings.getDifficulty(), quizSettings.getType(), quizSettings.getAmount());
+ }
+
+ /**
+ * Tries to get questions that match the specified QuizSettings
+ * @return The questions if the query was possible, and an empty array if not
+ */
+ // public List getByQuizSettings(QuizSettings quizSettings) {
+ // Specification spec = Specification.where(QuestionSpecification.hasType(type))
+ // .and(QuestionSpecification.hasCategory(category))
+ // .and(QuestionSpecification.hasDifficulty(difficulty));
+
+ // return productRepository.findAll(spec);
+ // }
+
+ public List saveCategories(List categories) {
+ return categoryRepository.saveAll(categories);
+ }
}
diff --git a/backend/src/main/java/com/ninjaws/quiz/services/DatabaseScheduler.java b/backend/src/main/java/com/ninjaws/quiz/services/DatabaseScheduler.java
new file mode 100644
index 0000000..83686c1
--- /dev/null
+++ b/backend/src/main/java/com/ninjaws/quiz/services/DatabaseScheduler.java
@@ -0,0 +1,20 @@
+package com.ninjaws.quiz.services;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+@Service
+public class DatabaseScheduler {
+ @Autowired
+ private JdbcTemplate secondaryJdbcTemplate;
+
+ @Scheduled(fixedRate = 60000) // Runs every 60 seconds
+ public void createAndFillSecondaryDatabase() {
+ // Create tables and insert data into the secondary database
+ secondaryJdbcTemplate.
+ .execute("CREATE TABLE IF NOT EXISTS sample_table (id INT PRIMARY KEY, name VARCHAR(255))");
+ secondaryJdbcTemplate.update("INSERT INTO sample_table (id, name) VALUES (?, ?)", 1, "Sample Data");
+ }
+}
diff --git a/backend/src/main/java/com/ninjaws/quiz/services/QuizService.java b/backend/src/main/java/com/ninjaws/quiz/services/QuizService.java
index 0b22c30..d511850 100644
--- a/backend/src/main/java/com/ninjaws/quiz/services/QuizService.java
+++ b/backend/src/main/java/com/ninjaws/quiz/services/QuizService.java
@@ -1,10 +1,12 @@
package com.ninjaws.quiz.services;
+import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import com.ninjaws.quiz.entities.QuestionEntity;
import com.ninjaws.quiz.models.Answers;
import com.ninjaws.quiz.models.QuizSettings;
import com.ninjaws.quiz.models.Request;
@@ -18,6 +20,10 @@ public class QuizService {
private CacheService cacheService;
@Autowired
private QueueService queueService;
+ @Autowired
+ private DataService dataService;
+ @Autowired
+ private CleanerService cleanerService;
/**
* Actions:
@@ -29,7 +35,22 @@ public class QuizService {
*/
public Optional createSession(QuizSettings quizSettings) {
Session session = new Session();
+
+ /** First, we check if there are already enough items in our db */
+ List questionsRetrieved = dataService.lookupQuestions(quizSettings);
+ if(!questionsRetrieved.isEmpty()) {
+ session.setQuestions(cleanerService.questionListEntitytoDTO(questionsRetrieved));
+ }
+
cacheService.addToCache(session.getId(), session);
+
+ /**
+ * If the questions were retrieved from the DB, then it doesn't need to be added to the queue
+ */
+ if(!questionsRetrieved.isEmpty()) {
+ return Optional.of(session.getId());
+ }
+
boolean addedToQueue = queueService.addToQueue(new Request(session.getId(), quizSettings));
/** In this order, because doing the queue before the cache could lead to race conditions (request completion immediately calls cache, but then the item doesn't exist) */
if(!addedToQueue) {
diff --git a/backend/src/main/java/com/ninjaws/quiz/services/ResponseHandlingService.java b/backend/src/main/java/com/ninjaws/quiz/services/ResponseHandlingService.java
index 07abae9..96b2dd0 100644
--- a/backend/src/main/java/com/ninjaws/quiz/services/ResponseHandlingService.java
+++ b/backend/src/main/java/com/ninjaws/quiz/services/ResponseHandlingService.java
@@ -4,6 +4,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ninjaws.quiz.models.ApiResponse;
+import com.ninjaws.quiz.models.CategoryResponse;
import com.ninjaws.quiz.models.Session;
@Service
@@ -13,6 +14,8 @@ public class ResponseHandlingService {
private CacheService cacheService;
@Autowired
private DataService dataService;
+ @Autowired
+ private CleanerService cleanerService;
/**
* If there is no sessionId, then this is a request from the scheduler
@@ -30,6 +33,7 @@ public class ResponseHandlingService {
case 0:
// Success
updateSessionInCache(session, response);
+ dataService.saveQuestions(cleanerService.questionListDTOtoEntity(response.getResults()));
break;
case 1:
// Not enough questions to satisfy the request.
@@ -63,8 +67,7 @@ public class ResponseHandlingService {
public void handleResponse(ApiResponse response) {
switch (response.getResponseCode()) {
case 0:
- // TODO: Store in DB
- dataService.saveQuestions(response.getResults());
+ dataService.saveQuestions(cleanerService.questionListDTOtoEntity(response.getResults()));
break;
case 4:
// Signal DataService that we have extracted all the data. Stop gathering, switch to caching-mode
@@ -83,4 +86,7 @@ public class ResponseHandlingService {
cacheService.addToCache(session.getId(), session);
}
+ public void handleCategoryResponse(CategoryResponse categoryResponse) {
+ dataService.saveCategories(categoryResponse.getTrivia_categories());
+ }
}
diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties
index 5fa94c6..f7d952d 100644
--- a/backend/src/main/resources/application.properties
+++ b/backend/src/main/resources/application.properties
@@ -3,10 +3,32 @@ server.port=9090
# H2 Database configuration
spring.h2.console.enabled=true
-spring.datasource.url=jdbc:h2:mem:testdb
-spring.datasource.driverClassName=org.h2.Driver
-spring.datasource.username=sa
-spring.datasource.password=
+# spring.h2.console.path=/console
-spring.jpa.hibernate.ddl-auto=create-drop
-spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
\ No newline at end of file
+
+# spring.datasource.url=jdbc:h2:mem:testdb
+# spring.datasource.driverClassName=org.h2.Driver
+# spring.datasource.username=sa
+# spring.datasource.password=
+
+# spring.jpa.hibernate.ddl-auto=create-drop
+# spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
+
+
+# Primary database configuration
+spring.datasource.primary.url=jdbc:h2:mem:testdb
+# ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+spring.datasource.primary.driver-class-name=org.h2.Driver
+spring.datasource.primary.username=sa
+spring.datasource.primary.password=
+spring.jpa.primary.hibernate.ddl-auto=create-drop
+spring.jpa.primary.database-platform=org.hibernate.dialect.H2Dialect
+
+# Secondary database configuration
+spring.datasource.secondary.url=jdbc:h2:mem:secondarydb
+# ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+spring.datasource.secondary.driver-class-name=org.h2.Driver
+spring.datasource.secondary.username=sa
+spring.datasource.secondary.password=
+spring.jpa.secondary.hibernate.ddl-auto=create-drop
+spring.jpa.secondary.database-platform=org.hibernate.dialect.H2Dialect
\ No newline at end of file
diff --git a/backend/src/test/java/com/ninjaws/quiz/repositories/QuestRepositoryTest.java b/backend/src/test/java/com/ninjaws/quiz/repositories/QuestRepositoryTest.java
deleted file mode 100644
index a11b441..0000000
--- a/backend/src/test/java/com/ninjaws/quiz/repositories/QuestRepositoryTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.ninjaws.quiz.repositories;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
-import org.springframework.test.annotation.Rollback;
-
-import com.ninjaws.quiz.models.Question;
-
-@DataJpaTest
-public class QuestRepositoryTest {
- @Autowired
- private QuestionRepository questionRepository;
-
- private Question question;
-
- @BeforeEach
- public void setUp() {
- question = new Question();
- question.setType("multiple choice");
- question.setDifficulty("easy");
- question.setCategory("general knowledge");
- question.setQuestion("What is the capital of France?");
- question.setCorrectAnswer("Paris");
- question.setIncorrectAnswers(Arrays.asList("Berlin", "Madrid", "Rome"));
- }
-
- @Test
- @Rollback(false)
- public void testSaveQuestion() {
- Question savedQuestion = questionRepository.save(question);
- assertThat(savedQuestion).isNotNull();
- assertThat(savedQuestion.getId()).isGreaterThan(1);
- }
-
- @Test
- public void testFindQuestionById() {
- questionRepository.save(question);
- Optional foundQuestion = questionRepository.findById(question.getId());
- assertThat(foundQuestion).isPresent();
- assertThat(foundQuestion.get().getQuestion()).isEqualTo(question.getQuestion());
- }
-
- @Test
- public void testFindAllQuestions() {
- questionRepository.save(question);
- List questions = questionRepository.findAll();
- assertThat(questions).isNotEmpty();
- }
-
- @Test
- public void testDeleteQuestion() {
- questionRepository.save(question);
- Long id = question.getId();
- questionRepository.deleteById(id);
- Optional deletedQuestion = questionRepository.findById(id);
- assertThat(deletedQuestion).isNotPresent();
- }
-
- @Test
- @Rollback(false)
- public void testSaveQuestions() {
- Question question1 = new Question();
- question1.setType("multiple choice");
- question1.setDifficulty("easy");
- question1.setCategory("general knowledge");
- question1.setQuestion("What is the capital of France?");
- question1.setCorrectAnswer("Paris");
- question1.setIncorrectAnswers(Arrays.asList("Berlin", "Madrid", "Rome"));
-
- Question question2 = new Question();
- question2.setType("multiple choice");
- question2.setDifficulty("medium");
- question2.setCategory("science");
- question2.setQuestion("What is the chemical symbol for water?");
- question2.setCorrectAnswer("H2O");
- question2.setIncorrectAnswers(Arrays.asList("CO2", "O2", "NaCl"));
-
- List savedQuestions = questionRepository.saveAll(Arrays.asList(question1, question2));
-
- assertThat(savedQuestions).hasSize(2);
- assertThat(savedQuestions.get(0).getQuestion()).isEqualTo("What is the capital of France?");
- assertThat(savedQuestions.get(1).getQuestion()).isEqualTo("What is the chemical symbol for water?");
- }
-}
diff --git a/backend/src/test/java/com/ninjaws/quiz/services/CleanerServiceTest.java b/backend/src/test/java/com/ninjaws/quiz/services/CleanerServiceTest.java
deleted file mode 100644
index 8c0f904..0000000
--- a/backend/src/test/java/com/ninjaws/quiz/services/CleanerServiceTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.ninjaws.quiz.services;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.*;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.ninjaws.quiz.models.ApiResponse;
-import com.ninjaws.quiz.models.Question;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-
-public class CleanerServiceTest {
-
- @InjectMocks
- private CleanerService cleanerService;
-
- @Mock
- private ObjectMapper objectMapper;
-
- @BeforeEach
- public void setUp() {
- MockitoAnnotations.openMocks(this);
- }
-
- @Test
- public void testExtractApiResponse() throws IOException {
- String json = "{\"response_code\":200,\"results\":[{\"type\":\"multiple choice\",\"difficulty\":\"easy\",\"category\":\"general knowledge\",\"question\":\"What is the capital of France?\",\"correct_answer\":\"Paris\",\"incorrect_answers\":[\"Berlin\",\"Madrid\",\"Rome\"]}]}"; // Example JSON input
-
- Question question = new Question();
- question.setType("multiple choice");
- question.setDifficulty("easy");
- question.setCategory("general knowledge");
- question.setQuestion("What is the capital of France?");
- question.setCorrectAnswer("Paris");
- question.setIncorrectAnswers(Arrays.asList("Berlin", "Madrid", "Rome"));
-
- ApiResponse expectedResponse = new ApiResponse();
- expectedResponse.setResponseCode(200);
- expectedResponse.setResults(Arrays.asList(question));
- when(objectMapper.readValue(json, ApiResponse.class)).thenReturn(expectedResponse);
-
- ApiResponse actualResponse = cleanerService.extractApiResponse(json);
- assertThat(actualResponse).isNotNull();
- assertThat(actualResponse.getResponseCode()).isEqualTo(expectedResponse.getResponseCode());
- assertThat(actualResponse.getResults()).isNotEmpty();
- assertThat(actualResponse.getResults().get(0).getQuestion()).isEqualTo(question.getQuestion());
- verify(objectMapper, times(1)).readValue(json, ApiResponse.class);
- }
-}
\ No newline at end of file
diff --git a/backend/src/test/java/com/ninjaws/quiz/services/CleanerServiceTest.txt b/backend/src/test/java/com/ninjaws/quiz/services/CleanerServiceTest.txt
new file mode 100644
index 0000000..bdb7919
--- /dev/null
+++ b/backend/src/test/java/com/ninjaws/quiz/services/CleanerServiceTest.txt
@@ -0,0 +1,107 @@
+package com.ninjaws.quiz.services;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ninjaws.quiz.entities.Category;
+import com.ninjaws.quiz.models.ApiResponse;
+import com.ninjaws.quiz.models.QuestionDTO;
+
+// public class CleanerServiceTest {
+
+// @InjectMocks
+// private CleanerService cleanerService;
+
+// @Mock
+// private ObjectMapper objectMapper;
+
+// @BeforeEach
+// public void setUp() {
+// MockitoAnnotations.openMocks(this);
+// }
+
+// @Test
+// public void testExtractApiResponse() throws IOException {
+// String json = "{\"response_code\":200,\"results\":[{\"type\":\"multiple choice\",\"difficulty\":\"easy\",\"category\":\"general knowledge\",\"question\":\"What is the capital of France?\",\"correct_answer\":\"Paris\",\"incorrect_answers\":[\"Berlin\",\"Madrid\",\"Rome\"]}]}"; // Example JSON input
+
+// Question question = new Question();
+// question.setType("multiple choice");
+// question.setDifficulty("easy");
+// question.setCategory("general knowledge");
+// question.setQuestion("What is the capital of France?");
+// question.setCorrectAnswer("Paris");
+// question.setIncorrectAnswers(Arrays.asList("Berlin", "Madrid", "Rome"));
+
+// ApiResponse expectedResponse = new ApiResponse();
+// expectedResponse.setResponseCode(200);
+// expectedResponse.setResults(Arrays.asList(question));
+// when(objectMapper.readValue(json, ApiResponse.class)).thenReturn(expectedResponse);
+
+// ApiResponse actualResponse = cleanerService.extractApiResponse(json);
+// assertThat(actualResponse).isNotNull();
+// assertThat(actualResponse.getResponseCode()).isEqualTo(expectedResponse.getResponseCode());
+// assertThat(actualResponse.getResults()).isNotEmpty();
+// assertThat(actualResponse.getResults().get(0).getQuestion()).isEqualTo(question.getQuestion());
+// verify(objectMapper, times(1)).readValue(json, ApiResponse.class);
+// }
+// }
+
+@ExtendWith(MockitoExtension.class)
+public class CleanerServiceTest {
+
+ @InjectMocks
+ private CleanerService cleanerService;
+
+ @Mock
+ private ObjectMapper objectMapper;
+
+ @BeforeEach
+ public void setUp() {
+ MockitoAnnotations.openMocks(this);
+ }
+
+ @Test
+ public void testExtractApiResponse() throws IOException {
+ String json = "{\"response_code\":200,\"results\":[{\"type\":\"multiple choice\",\"difficulty\":\"easy\",\"category\":\"general knowledge\",\"question\":\"What is the capital of France?\",\"correct_answer\":\"Paris\",\"incorrect_answers\":[\"Berlin\",\"Madrid\",\"Rome\"]}]}"; // Example JSON input
+
+ // Create a Category object for the question
+ Category category = new Category();
+ category.setId(1L);
+ category.setName("General Knowledge");
+
+ // Create the Question object with the category
+ QuestionDTO question = new QuestionDTO();
+ question.setType("multiple choice");
+ question.setDifficulty("easy");
+ question.setCategory(category); // Set the Category object here
+ question.setQuestion("What is the capital of France?");
+ question.setCorrectAnswer("Paris");
+ question.setIncorrectAnswers(Arrays.asList("Berlin", "Madrid", "Rome"));
+
+ ApiResponse expectedResponse = new ApiResponse();
+ expectedResponse.setResponseCode(200);
+ expectedResponse.setResults(Arrays.asList(question));
+ when(objectMapper.readValue(json, ApiResponse.class)).thenReturn(expectedResponse);
+
+ ApiResponse actualResponse = cleanerService.extractApiResponse(json);
+ assertThat(actualResponse).isNotNull();
+ assertThat(actualResponse.getResponseCode()).isEqualTo(expectedResponse.getResponseCode());
+ assertThat(actualResponse.getResults()).isNotEmpty();
+ assertThat(actualResponse.getResults().get(0).getQuestion()).isEqualTo(question.getQuestion());
+ assertThat(actualResponse.getResults().get(0).getCategory().getName()).isEqualTo(category.getName()); // Check category name
+ verify(objectMapper, times(1)).readValue(json, ApiResponse.class);
+ }
+}
\ No newline at end of file
diff --git a/backend/src/test/java/com/ninjaws/quiz/services/DataServiceTest.java b/backend/src/test/java/com/ninjaws/quiz/services/DataServiceTest.java
deleted file mode 100644
index 2fe0683..0000000
--- a/backend/src/test/java/com/ninjaws/quiz/services/DataServiceTest.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package com.ninjaws.quiz.services;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyList;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import com.ninjaws.quiz.models.Question;
-import com.ninjaws.quiz.repositories.QuestionRepository;
-
-public class DataServiceTest {
-
- @InjectMocks
- private DataService dataService;
-
- @Mock
- private QuestionRepository questionRepository;
-
- private Question question;
-
-
- @BeforeEach
- public void setUp() {
- MockitoAnnotations.openMocks(this);
-
- question = new Question();
- question.setType("multiple choice");
- question.setDifficulty("easy");
- question.setCategory("general knowledge");
- question.setQuestion("What is the capital of France?");
- question.setCorrectAnswer("Paris");
- question.setIncorrectAnswers(Arrays.asList("Berlin", "Madrid", "Rome"));
- }
-
- @Test
- public void testSaveQuestion() {
- when(questionRepository.save(any(Question.class))).thenReturn(question);
-
- Question savedQuestion = dataService.saveQuestion(question);
- assertThat(savedQuestion).isNotNull();
- assertThat(savedQuestion.getQuestion()).isEqualTo("What is the capital of France?");
- verify(questionRepository, times(1)).save(question);
- }
-
- @Test
- public void testGetAllQuestions() {
- when(questionRepository.findAll()).thenReturn(Arrays.asList(question));
-
- List questions = dataService.getAllQuestions();
- assertThat(questions).isNotEmpty();
- assertThat(questions.size()).isEqualTo(1);
- assertThat(questions.get(0).getQuestion()).isEqualTo("What is the capital of France?");
- verify(questionRepository, times(1)).findAll();
- }
-
- @Test
- public void testFindQuestionById() {
- when(questionRepository.findById(any(Long.class))).thenReturn(Optional.of(question));
-
- Optional foundQuestion = questionRepository.findById(1L);
- assertThat(foundQuestion).isPresent();
- assertThat(foundQuestion.get().getQuestion()).isEqualTo("What is the capital of France?");
- verify(questionRepository, times(1)).findById(1L);
- }
-
- @Test
- public void testSaveQuestions() {
- Question question1 = new Question();
- question1.setType("multiple choice");
- question1.setDifficulty("easy");
- question1.setCategory("general knowledge");
- question1.setQuestion("What is the capital of France?");
- question1.setCorrectAnswer("Paris");
- question1.setIncorrectAnswers(Arrays.asList("Berlin", "Madrid", "Rome"));
-
- Question question2 = new Question();
- question2.setType("multiple choice");
- question2.setDifficulty("medium");
- question2.setCategory("science");
- question2.setQuestion("What is the chemical symbol for water?");
- question2.setCorrectAnswer("H2O");
- question2.setIncorrectAnswers(Arrays.asList("CO2", "O2", "NaCl"));
-
- when(questionRepository.saveAll(anyList())).thenReturn(Arrays.asList(question1, question2));
-
- List questions = dataService.saveQuestions(Arrays.asList(question1, question2));
-
- assertThat(questions).hasSize(2);
- assertThat(questions.get(0).getQuestion()).isEqualTo("What is the capital of France?");
- assertThat(questions.get(1).getQuestion()).isEqualTo("What is the chemical symbol for water?");
- verify(questionRepository, times(1)).saveAll(anyList());
- }
-}
diff --git a/backend/src/test/java/com/ninjaws/quiz/services/DataServiceTest.txt b/backend/src/test/java/com/ninjaws/quiz/services/DataServiceTest.txt
new file mode 100644
index 0000000..faa94e2
--- /dev/null
+++ b/backend/src/test/java/com/ninjaws/quiz/services/DataServiceTest.txt
@@ -0,0 +1,202 @@
+package com.ninjaws.quiz.services;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import com.ninjaws.quiz.entities.Category;
+import com.ninjaws.quiz.models.QuestionDTO;
+import com.ninjaws.quiz.repositories.QuestionRepository;
+
+// public class DataServiceTest {
+
+// @InjectMocks
+// private DataService dataService;
+
+// @Mock
+// private QuestionRepository questionRepository;
+
+// private Question question;
+
+
+// @BeforeEach
+// public void setUp() {
+// MockitoAnnotations.openMocks(this);
+
+// question = new Question();
+// question.setType("multiple choice");
+// question.setDifficulty("easy");
+// question.setCategory("general knowledge");
+// question.setQuestion("What is the capital of France?");
+// question.setCorrectAnswer("Paris");
+// question.setIncorrectAnswers(Arrays.asList("Berlin", "Madrid", "Rome"));
+// }
+
+// @Test
+// public void testSaveQuestion() {
+// when(questionRepository.save(any(Question.class))).thenReturn(question);
+
+// Question savedQuestion = dataService.saveQuestion(question);
+// assertThat(savedQuestion).isNotNull();
+// assertThat(savedQuestion.getQuestion()).isEqualTo("What is the capital of France?");
+// verify(questionRepository, times(1)).save(question);
+// }
+
+// @Test
+// public void testGetAllQuestions() {
+// when(questionRepository.findAll()).thenReturn(Arrays.asList(question));
+
+// List questions = dataService.getAllQuestions();
+// assertThat(questions).isNotEmpty();
+// assertThat(questions.size()).isEqualTo(1);
+// assertThat(questions.get(0).getQuestion()).isEqualTo("What is the capital of France?");
+// verify(questionRepository, times(1)).findAll();
+// }
+
+// @Test
+// public void testFindQuestionById() {
+// when(questionRepository.findById(any(Long.class))).thenReturn(Optional.of(question));
+
+// Optional foundQuestion = questionRepository.findById(1L);
+// assertThat(foundQuestion).isPresent();
+// assertThat(foundQuestion.get().getQuestion()).isEqualTo("What is the capital of France?");
+// verify(questionRepository, times(1)).findById(1L);
+// }
+
+// @Test
+// public void testSaveQuestions() {
+// Question question1 = new Question();
+// question1.setType("multiple choice");
+// question1.setDifficulty("easy");
+// question1.setCategory("general knowledge");
+// question1.setQuestion("What is the capital of France?");
+// question1.setCorrectAnswer("Paris");
+// question1.setIncorrectAnswers(Arrays.asList("Berlin", "Madrid", "Rome"));
+
+// Question question2 = new Question();
+// question2.setType("multiple choice");
+// question2.setDifficulty("medium");
+// question2.setCategory("science");
+// question2.setQuestion("What is the chemical symbol for water?");
+// question2.setCorrectAnswer("H2O");
+// question2.setIncorrectAnswers(Arrays.asList("CO2", "O2", "NaCl"));
+
+// when(questionRepository.saveAll(anyList())).thenReturn(Arrays.asList(question1, question2));
+
+// List questions = dataService.saveQuestions(Arrays.asList(question1, question2));
+
+// assertThat(questions).hasSize(2);
+// assertThat(questions.get(0).getQuestion()).isEqualTo("What is the capital of France?");
+// assertThat(questions.get(1).getQuestion()).isEqualTo("What is the chemical symbol for water?");
+// verify(questionRepository, times(1)).saveAll(anyList());
+// }
+// }
+
+@ExtendWith(MockitoExtension.class)
+public class DataServiceTest {
+
+ @InjectMocks
+ private DataService dataService;
+
+ @Mock
+ private QuestionRepository questionRepository;
+
+ private QuestionDTO question;
+ private Category category;
+
+ @BeforeEach
+ public void setUp() {
+ MockitoAnnotations.openMocks(this);
+
+ category = new Category();
+ category.setId(1L);
+ category.setName("General Knowledge");
+
+ question = new QuestionDTO();
+ question.setType("multiple choice");
+ question.setDifficulty("easy");
+ question.setCategory(category); // Set the Category object here
+ question.setQuestion("What is the capital of France?");
+ question.setCorrectAnswer("Paris");
+ question.setIncorrectAnswers(Arrays.asList("Berlin", "Madrid", "Rome"));
+ }
+
+ @Test
+ public void testSaveQuestion() {
+ when(questionRepository.save(any(QuestionDTO.class))).thenReturn(question);
+
+ QuestionDTO savedQuestion = dataService.saveQuestion(question);
+ assertThat(savedQuestion).isNotNull();
+ assertThat(savedQuestion.getQuestion()).isEqualTo("What is the capital of France?");
+ assertThat(savedQuestion.getCategory().getName()).isEqualTo("General Knowledge"); // Check category name
+ verify(questionRepository, times(1)).save(question);
+ }
+
+ @Test
+ public void testGetAllQuestions() {
+ when(questionRepository.findAll()).thenReturn(Arrays.asList(question));
+
+ List questions = dataService.getAllQuestions();
+ assertThat(questions).isNotEmpty();
+ assertThat(questions.size()).isEqualTo(1);
+ assertThat(questions.get(0).getQuestion()).isEqualTo("What is the capital of France?");
+ assertThat(questions.get(0).getCategory().getName()).isEqualTo("General Knowledge"); // Check category name
+ verify(questionRepository, times(1)).findAll();
+ }
+
+ @Test
+ public void testFindQuestionById() {
+ when(questionRepository.findById(any(Long.class))).thenReturn(Optional.of(question));
+
+ Optional foundQuestion = questionRepository.findById(1L);
+ assertThat(foundQuestion).isPresent();
+ assertThat(foundQuestion.get().getQuestion()).isEqualTo("What is the capital of France?");
+ assertThat(foundQuestion.get().getCategory().getName()).isEqualTo("General Knowledge"); // Check category name
+ verify(questionRepository, times(1)).findById(1L);
+ }
+
+ @Test
+ public void testSaveQuestions() {
+ QuestionDTO question1 = new QuestionDTO();
+ question1.setType("multiple choice");
+ question1.setDifficulty("easy");
+ question1.setCategory(category); // Set the Category object here
+ question1.setQuestion("What is the capital of France?");
+ question1.setCorrectAnswer("Paris");
+ question1.setIncorrectAnswers(Arrays.asList("Berlin", "Madrid", "Rome"));
+
+ QuestionDTO question2 = new QuestionDTO();
+ Category category2 = new Category();
+ category2.setId(2L);
+ category2.setName("Science");
+ question2.setType("multiple choice");
+ question2.setDifficulty("medium");
+ question2.setCategory(category2); // Set the Category object here
+ question2.setQuestion("What is the chemical symbol for water?");
+ question2.setCorrectAnswer("H2O");
+ question2.setIncorrectAnswers(Arrays.asList("CO2", "O2", "NaCl"));
+
+ when(questionRepository.saveAll(anyList())).thenReturn(Arrays.asList(question1, question2));
+
+ List questions = dataService.saveQuestions(Arrays.asList(question1, question2));
+
+ assertThat(questions).hasSize(2);
+ assertThat(questions.get(0).getQuestion()).isEqualTo("What is the capital of France?");
+ assertThat(questions.get(1).getQuestion()).isEqualTo("What is the chemical symbol for water?");
+ verify(questionRepository, times(1)).saveAll(anyList());
+ }
+}
diff --git a/frontend/src/app/Quiz/services/quiz.service.ts b/frontend/src/app/Quiz/services/quiz.service.ts
index 5be7448..184570f 100644
--- a/frontend/src/app/Quiz/services/quiz.service.ts
+++ b/frontend/src/app/Quiz/services/quiz.service.ts
@@ -71,7 +71,7 @@ export class QuizService {
url += catIndex !== 0 ? `&category=${catIndex}` : '';
const diff = quizParams.difficulty.toLowerCase();
- url += diff !== 'any difficulty' ? `&category=${diff}` : '';
+ url += diff !== 'any difficulty' ? `&difficulty=${diff}` : '';
const typeIndex = this.getTypes().indexOf(quizParams.type);
url +=
diff --git a/scripts/LoadTestMultiple.sh b/scripts/LoadTestMultiple.sh
index 9122900..352f191 100755
--- a/scripts/LoadTestMultiple.sh
+++ b/scripts/LoadTestMultiple.sh
@@ -3,7 +3,7 @@
start_time=$(date +%s)
for i in {1..6}; do
- ./LoadTestOne.sh &
+ ./LoadTestOne-WithParams.sh &
sleep 0.1
done
diff --git a/scripts/LoadTestOne-WithParams.sh b/scripts/LoadTestOne-WithParams.sh
new file mode 100755
index 0000000..f23ce00
--- /dev/null
+++ b/scripts/LoadTestOne-WithParams.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+# Step 1: Get the sessionId from the questions endpoint
+sessionIdJson=$(curl -s "http://localhost:9090/quiz/questions?amount=25&category=27&difficulty=medium&type=boolean")
+
+statusCode=$(echo "$sessionIdJson" | grep -o '"statusCode":[0-9]*' | sed 's/"statusCode"://')
+
+if [ "$statusCode" -ne 0 ]; then
+ echo "Exiting: statusCode is not 0."
+ exit 1
+fi
+
+sessionId=$(echo "$sessionIdJson" | grep -o '"sessionId":"[^"]*"' | sed 's/"sessionId":"//;s/"//')
+
+if [ -z "$sessionId" ]; then
+ echo "Failed to get sessionId"
+ exit 1
+fi
+
+echo "Received sessionId: $sessionId"
+
+# Step 2: Poll the status endpoint every 2 seconds
+while true; do
+ status_response=$(curl -s http://localhost:9090/quiz/status/"$sessionId")
+
+ if [ $? -eq 0 ]; then
+
+ statusCode=$(echo "$status_response" | grep -o '"statusCode":[0-9]*' | sed 's/"statusCode"://')
+
+ if [ "$statusCode" -ne 0 ]; then
+ echo "Exiting: statusCode is $statusCode"
+ exit 1
+ fi
+
+ # Check if the response is JSON (starts with '{')
+ if [[ $status_response == \{* ]]; then
+# echo "$statusCode"
+ echo "$sessionId: done! status: $statusCode"
+ break
+ fi
+ else
+ echo "Status check failed, retrying..."
+ fi
+
+ sleep 2
+done
diff --git a/scripts/LoadTestOne.sh b/scripts/LoadTestOne.sh
index 1137ee1..feb32eb 100755
--- a/scripts/LoadTestOne.sh
+++ b/scripts/LoadTestOne.sh
@@ -30,7 +30,8 @@ while true; do
break
fi
else
- echo "Status check failed, retrying..."
+ echo "Status check failed, exiting..."
+ exit 1
fi
sleep 2
diff --git a/scripts/benchmarks/basic.png b/scripts/benchmarks/1. Queue.png
similarity index 100%
rename from scripts/benchmarks/basic.png
rename to scripts/benchmarks/1. Queue.png
diff --git a/scripts/benchmarks/2. DB and Queue - No Params.png b/scripts/benchmarks/2. DB and Queue - No Params.png
new file mode 100644
index 0000000..d2a3811
Binary files /dev/null and b/scripts/benchmarks/2. DB and Queue - No Params.png differ