diff --git a/pom.xml b/pom.xml
index 290fa836..86487ac8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -46,9 +46,9 @@
runtime
- org.wikidata.wdtk
- wdtk-dumpfiles
- 0.14.4
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.16.1
org.springframework.boot
diff --git a/src/main/java/com/uniovi/components/QuestionGeneratorTestController.java b/src/main/java/com/uniovi/components/QuestionGeneratorTestController.java
new file mode 100644
index 00000000..82ba147e
--- /dev/null
+++ b/src/main/java/com/uniovi/components/QuestionGeneratorTestController.java
@@ -0,0 +1,24 @@
+package com.uniovi.components;
+
+import com.uniovi.components.generators.geography.CapitalQuestionGenerator;
+import com.uniovi.entities.Question;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+public class QuestionGeneratorTestController {
+
+ @Autowired
+ CapitalQuestionGenerator qgen;
+
+ @RequestMapping("/test")
+ public void test() {
+ List q = qgen.getQuestions();
+ for(Question question : q){
+ System.out.println(question);
+ }
+ }
+}
diff --git a/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java
new file mode 100644
index 00000000..cb4d46ab
--- /dev/null
+++ b/src/main/java/com/uniovi/components/generators/AbstractQuestionGenerator.java
@@ -0,0 +1,88 @@
+package com.uniovi.components.generators;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.uniovi.entities.Answer;
+import com.uniovi.entities.Category;
+import com.uniovi.entities.Question;
+import com.uniovi.services.CategoryService;
+
+import java.net.URI;
+import java.net.URLEncoder;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class AbstractQuestionGenerator implements QuestionGenerator{
+
+ private List questions = new ArrayList<>();
+ protected final CategoryService categoryService;
+ private String query;
+ protected String statement;
+
+ protected AbstractQuestionGenerator(CategoryService categoryService) {
+ this.categoryService = categoryService;
+ }
+
+ public void questionGenerator(String statement, List options, String correctAnswer, Category category){
+ List answers = new ArrayList<>();
+ //Generamos las respuestas y las aƱadimos a la lista
+ for(String s: options){
+ Answer answer = new Answer(s, false);
+ answers.add(answer);
+ }
+ //Generamos la respuesta correcta y la aƱadimos a la lista
+ Answer correct = new Answer(correctAnswer, true);
+ answers.add(correct);
+
+ Question question = new Question(statement, answers, correct, category);
+ question.scrambleOptions();
+ questions.add(question);
+ }
+
+ public List getQuestions() {
+ HttpClient client = HttpClient.newHttpClient();
+ try {
+
+ String endpointUrl = "https://query.wikidata.org/sparql?query=" +
+ URLEncoder.encode(this.getQuery(), StandardCharsets.UTF_8.toString()) +
+ "&format=json";
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(endpointUrl))
+ .header("Accept", "application/json")
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ // Process the JSON response using Jackson ObjectMapper
+ ObjectMapper objectMapper = new ObjectMapper();
+ JsonNode jsonResponse = objectMapper.readTree(response.body());
+
+ // Access the data from the JSON response
+ JsonNode resultsNode = jsonResponse.path("results").path("bindings");
+
+ for (JsonNode result : resultsNode) {
+
+ List options = this.generateOptions(resultsNode, result);
+ String correctAnswer = this.generateCorrectAnswer(result);
+ String statement = this.getQuestionSubject(result);
+ questionGenerator(statement, options, correctAnswer, this.getCategory());
+
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ return questions;
+ }
+
+ protected abstract List generateOptions(JsonNode results, JsonNode result);
+ protected abstract String generateCorrectAnswer(JsonNode result);
+
+ protected abstract String getQuestionSubject(JsonNode result);
+
+}
diff --git a/src/main/java/com/uniovi/components/generators/QuestionGenerator.java b/src/main/java/com/uniovi/components/generators/QuestionGenerator.java
new file mode 100644
index 00000000..ccaa4dab
--- /dev/null
+++ b/src/main/java/com/uniovi/components/generators/QuestionGenerator.java
@@ -0,0 +1,18 @@
+package com.uniovi.components.generators;
+
+import com.uniovi.entities.Category;
+import com.uniovi.entities.Question;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Component
+public interface QuestionGenerator {
+
+ String getQuery();
+ List getQuestions();
+
+ Category getCategory();
+
+
+}
diff --git a/src/main/java/com/uniovi/components/generators/geography/AbstractGeographyGenerator.java b/src/main/java/com/uniovi/components/generators/geography/AbstractGeographyGenerator.java
new file mode 100644
index 00000000..d01919e9
--- /dev/null
+++ b/src/main/java/com/uniovi/components/generators/geography/AbstractGeographyGenerator.java
@@ -0,0 +1,17 @@
+package com.uniovi.components.generators.geography;
+
+import com.uniovi.components.generators.AbstractQuestionGenerator;
+import com.uniovi.entities.Category;
+import com.uniovi.services.CategoryService;
+
+public abstract class AbstractGeographyGenerator extends AbstractQuestionGenerator {
+
+ protected AbstractGeographyGenerator(CategoryService categoryService) {
+ super(categoryService);
+ }
+
+ @Override
+ public Category getCategory() {
+ return categoryService.getCategoryByName("Geography");
+ }
+}
diff --git a/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java
new file mode 100644
index 00000000..1bbd4475
--- /dev/null
+++ b/src/main/java/com/uniovi/components/generators/geography/BorderQuestionGenerator.java
@@ -0,0 +1,70 @@
+package com.uniovi.components.generators.geography;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.uniovi.services.CategoryService;
+
+import java.util.*;
+
+public class BorderQuestionGenerator extends AbstractGeographyGenerator{
+
+ private Set usedCountries = new HashSet<>();
+
+ public BorderQuestionGenerator(CategoryService categoryService) {
+ super(categoryService);
+ this.statement = "Which countries share a border with ";
+ }
+
+ private List getAllBorderingCountries(JsonNode resultsNode, String correctCountry) {
+ List allBorderingCountries = new ArrayList<>();
+ for (JsonNode result : resultsNode) {
+ String borderingCountry = result.path("borderingCountryLabel").path("value").asText();
+ if (!borderingCountry.equals(correctCountry)) {
+ allBorderingCountries.add(borderingCountry);
+ }
+ }
+ return allBorderingCountries;
+ }
+
+ private List selectRandomIncorrectBorderingCountries(List allBorderingCountries, String correctCountry, int count) {
+ List incorrectBorderingCountries = new ArrayList<>();
+ Random random = new Random();
+ while (incorrectBorderingCountries.size() < count && allBorderingCountries.size() > 0) {
+ int randomIndex = random.nextInt(allBorderingCountries.size());
+ String selectedBorderingCountry = allBorderingCountries.remove(randomIndex);
+ if (!selectedBorderingCountry.equals(correctCountry) && !incorrectBorderingCountries.contains(selectedBorderingCountry)) {
+ incorrectBorderingCountries.add(selectedBorderingCountry);
+ }
+ }
+ return incorrectBorderingCountries;
+ }
+
+ @Override
+ protected List generateOptions(JsonNode results, JsonNode result) {
+ String borderingCountryLabel = result.path("borderingCountryLabel").path("value").asText();
+ return selectRandomIncorrectBorderingCountries(
+ getAllBorderingCountries(results, borderingCountryLabel),
+ borderingCountryLabel, 3);
+ }
+
+ @Override
+ protected String generateCorrectAnswer(JsonNode result) {
+ return result.path("borderingCountryLabel").path("value").asText();
+ }
+
+ @Override
+ protected String getQuestionSubject(JsonNode result) {
+ return this.statement + result.path("countryLabel").path("value").asText() + "?";
+ }
+
+ @Override
+ public String getQuery() {
+ return "SELECT DISTINCT ?country ?countryLabel ?borderingCountry ?borderingCountryLabel\n" +
+ "WHERE {" +
+ " ?country wdt:P31 wd:Q3624078 ." +
+ " FILTER NOT EXISTS {?country wdt:P31 wd:Q3024240}" +
+ " FILTER NOT EXISTS {?country wdt:P31 wd:Q28171280}" +
+ " ?country wdt:P47 ?borderingCountry ." +
+ " SERVICE wikibase:label { bd:serviceParam wikibase:language \"[AUTO_LANGUAGE],en\" }" +
+ "}";
+ }
+}
diff --git a/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java b/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java
new file mode 100644
index 00000000..951292fc
--- /dev/null
+++ b/src/main/java/com/uniovi/components/generators/geography/CapitalQuestionGenerator.java
@@ -0,0 +1,72 @@
+package com.uniovi.components.generators.geography;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.uniovi.services.CategoryService;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+@Component
+public class CapitalQuestionGenerator extends AbstractGeographyGenerator{
+
+ public CapitalQuestionGenerator(CategoryService categoryService) {
+ super(categoryService);
+ this.statement = "What is the capital of ";
+ }
+
+ @Override
+ public String getQuery() {
+ return "SELECT DISTINCT ?country ?countryLabel ?capital ?capitalLabel\n" +
+ "WHERE {" +
+ " ?country wdt:P31 wd:Q3624078 ." +
+ " FILTER NOT EXISTS {?country wdt:P31 wd:Q3024240}" +
+ " FILTER NOT EXISTS {?country wdt:P31 wd:Q28171280}" +
+ " OPTIONAL { ?country wdt:P36 ?capital } ." +
+ " SERVICE wikibase:label { bd:serviceParam wikibase:language \"[AUTO_LANGUAGE],en\" }" +
+ "}" +
+ "ORDER BY ?countryLabel";
+ }
+
+ private List getAllCapitals(JsonNode resultsNode, String correctCapital) {
+ // Obtener todas las capitales del JSON (distintas a la capital correcta)
+ List allCapitals = new ArrayList<>();
+ for (JsonNode result : resultsNode) {
+ String capital = result.path("capitalLabel").path("value").asText();
+ if (!capital.equals(correctCapital)) {
+ allCapitals.add(capital);
+ }
+ }
+ return allCapitals;
+ }
+
+ private List selectRandomIncorrectCapitals(List allCapitals, String correctCapital, int count) {
+ List incorrectCapitals = new ArrayList<>();
+ Random random = new Random();
+ while (incorrectCapitals.size() < count && allCapitals.size() > 0) {
+ int randomIndex = random.nextInt(allCapitals.size());
+ String selectedCapital = allCapitals.remove(randomIndex);
+ if (!selectedCapital.equals(correctCapital) && !incorrectCapitals.contains(selectedCapital)) {
+ incorrectCapitals.add(selectedCapital);
+ }
+ }
+ return incorrectCapitals;
+ }
+
+ @Override
+ protected List generateOptions(JsonNode results, JsonNode result) {
+ String capitalLabel = result.path("capitalLabel").path("value").asText();
+ return selectRandomIncorrectCapitals(getAllCapitals(results, capitalLabel), capitalLabel, 3);
+ }
+
+ @Override
+ protected String generateCorrectAnswer(JsonNode result) {
+ return result.path("capitalLabel").path("value").asText();
+ }
+
+ @Override
+ protected String getQuestionSubject(JsonNode result) {
+ return this.statement + result.path("countryLabel").path("value").asText() + "?";
+ }
+}
diff --git a/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java b/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java
new file mode 100644
index 00000000..6e89b66c
--- /dev/null
+++ b/src/main/java/com/uniovi/components/generators/geography/ContinentQuestionGeneration.java
@@ -0,0 +1,69 @@
+package com.uniovi.components.generators.geography;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.uniovi.services.CategoryService;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class ContinentQuestionGeneration extends AbstractGeographyGenerator{
+ public ContinentQuestionGeneration(CategoryService categoryService) {
+ super(categoryService);
+ this.statement = "In which continent is ";
+ }
+
+ private List getAllContinents(JsonNode resultsNode, String correctContinent) {
+ // Obtener todas las capitales del JSON (distintas a la capital correcta)
+ List allContinents = new ArrayList<>();
+ for (JsonNode result : resultsNode) {
+ String continent = result.path("continentLabel").path("value").asText();
+ if (!continent.equals(correctContinent)) {
+ allContinents.add(continent);
+ }
+ }
+ return allContinents;
+ }
+
+ private List selectRandomIncorrectContinents(List allContinents, String correctContinent, int count) {
+ List incorrectContinents = new ArrayList<>();
+ Random random = new Random();
+ while (incorrectContinents.size() < count && allContinents.size() > 0) {
+ int randomIndex = random.nextInt(allContinents.size());
+ String selectedCapital = allContinents.remove(randomIndex);
+ if (!selectedCapital.equals(correctContinent) && !incorrectContinents.contains(selectedCapital)) {
+ incorrectContinents.add(selectedCapital);
+ }
+ }
+ return incorrectContinents;
+ }
+
+ @Override
+ protected List generateOptions(JsonNode results, JsonNode result) {
+ String continentLabel = result.path("continentLabel").path("value").asText();
+ return selectRandomIncorrectContinents(getAllContinents(results, continentLabel), continentLabel, 3);
+ }
+
+ @Override
+ protected String generateCorrectAnswer(JsonNode result) {
+ return result.path("continentLabel").path("value").asText();
+ }
+
+ @Override
+ protected String getQuestionSubject(JsonNode result) {
+ return this.statement + result.path("countryLabel").path("value").asText() + "?";
+ }
+
+ @Override
+ public String getQuery() {
+ return "SELECT DISTINCT ?country ?countryLabel ?continent ?continentLabel\n" +
+ "WHERE {" +
+ " ?country wdt:P31 wd:Q3624078 " +
+ " FILTER NOT EXISTS {?country wdt:P31 wd:Q3024240}" +
+ " FILTER NOT EXISTS {?country wdt:P31 wd:Q28171280}" +
+ " OPTIONAL { ?country wdt:P30 ?continent } ." +
+ " SERVICE wikibase:label { bd:serviceParam wikibase:language \"[AUTO_LANGUAGE],en\" }" +
+ "}" +
+ "ORDER BY ?countryLabel";
+ }
+}
diff --git a/src/main/java/com/uniovi/dto/AnswerDto.java b/src/main/java/com/uniovi/dto/AnswerDto.java
new file mode 100644
index 00000000..20ad1e37
--- /dev/null
+++ b/src/main/java/com/uniovi/dto/AnswerDto.java
@@ -0,0 +1,17 @@
+package com.uniovi.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class AnswerDto {
+ private Long id;
+ private String text;
+ private boolean correct;
+
+}
diff --git a/src/main/java/com/uniovi/dto/CategoryDto.java b/src/main/java/com/uniovi/dto/CategoryDto.java
new file mode 100644
index 00000000..6b34b07e
--- /dev/null
+++ b/src/main/java/com/uniovi/dto/CategoryDto.java
@@ -0,0 +1,20 @@
+package com.uniovi.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class CategoryDto {
+
+ private Long id;
+ private String name;
+ private String description;
+ private List questions;
+}
diff --git a/src/main/java/com/uniovi/dto/QuestionDto.java b/src/main/java/com/uniovi/dto/QuestionDto.java
new file mode 100644
index 00000000..dac83779
--- /dev/null
+++ b/src/main/java/com/uniovi/dto/QuestionDto.java
@@ -0,0 +1,22 @@
+package com.uniovi.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class QuestionDto {
+
+ private Long id;
+ private String statement;
+ private List options;
+ private AnswerDto correctAnswer;
+ private CategoryDto category;
+
+}
diff --git a/src/main/java/com/uniovi/entities/Answer.java b/src/main/java/com/uniovi/entities/Answer.java
new file mode 100644
index 00000000..61401b4a
--- /dev/null
+++ b/src/main/java/com/uniovi/entities/Answer.java
@@ -0,0 +1,33 @@
+package com.uniovi.entities;
+
+import jakarta.persistence.*;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@Entity
+@NoArgsConstructor
+public class Answer {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ private String text;
+ private boolean correct;
+
+ @ManyToOne
+ private Question question;
+
+ public Answer(String text, boolean correct) {
+ this.text = text;
+ this.correct = correct;
+ }
+
+ public String toString() {
+ return text;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/uniovi/entities/Category.java b/src/main/java/com/uniovi/entities/Category.java
new file mode 100644
index 00000000..cf5d8771
--- /dev/null
+++ b/src/main/java/com/uniovi/entities/Category.java
@@ -0,0 +1,32 @@
+package com.uniovi.entities;
+
+import jakarta.persistence.*;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@Getter
+@Setter
+@Entity
+@NoArgsConstructor
+public class Category {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ @Column(unique = true)
+ private String name;
+ private String description;
+
+ @OneToMany(mappedBy = "category")
+ private Set questions = new HashSet<>();
+
+ public Category(String name, String description) {
+ this.name = name;
+ this.description = description;
+ }
+}
diff --git a/src/main/java/com/uniovi/entities/Question.java b/src/main/java/com/uniovi/entities/Question.java
new file mode 100644
index 00000000..5046a2b0
--- /dev/null
+++ b/src/main/java/com/uniovi/entities/Question.java
@@ -0,0 +1,94 @@
+package com.uniovi.entities;
+
+import jakarta.persistence.*;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.springframework.util.Assert;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+@Getter
+@Setter
+@Entity
+@NoArgsConstructor
+public class Question {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ @Column(unique = true)
+ private String statement;
+
+ @OneToMany(mappedBy = "question")
+ private List options;
+
+ @OneToOne
+ private Answer correctAnswer;
+
+ @ManyToOne
+ private Category category;
+
+ public Question(String statement, List options, Answer correctAnswer, Category category) {
+ Assert.isTrue(options.contains(correctAnswer), "Correct answer must be one of the options");
+ this.statement = statement;
+ this.options = options;
+ this.correctAnswer = correctAnswer;
+ this.category = category;
+ }
+
+ public void addOption(Answer option) {
+ options.add(option);
+ }
+
+ public void removeOption(Answer option){
+ options.remove(option);
+ }
+
+ public Answer getOption(int index){
+ return options.get(index);
+ }
+
+ public Answer getOptions(String answer){
+ for (Answer option : options) {
+ if (option.getText().equals(answer)) {
+ return option;
+ }
+ }
+ return null;
+ }
+
+ public boolean isCorrectAnswer(Answer answer){
+ return answer.isCorrect();
+ }
+
+ public void scrambleOptions(){
+ Collections.shuffle(options);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Question question = (Question) o;
+ return Objects.equals(id, question.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id);
+ }
+
+ @Override
+ public String toString() {
+ return "Question{" +
+ "statement='" + statement + '\'' +
+ ", options=" + options.toString() +
+ ", correctAnswer=" + correctAnswer.toString() +
+ ", category=" + category +
+ '}';
+ }
+}
diff --git a/src/main/java/com/uniovi/repositories/AnswerRepository.java b/src/main/java/com/uniovi/repositories/AnswerRepository.java
new file mode 100644
index 00000000..b0beb5f8
--- /dev/null
+++ b/src/main/java/com/uniovi/repositories/AnswerRepository.java
@@ -0,0 +1,12 @@
+package com.uniovi.repositories;
+
+import com.uniovi.entities.Answer;
+import com.uniovi.entities.Question;
+import org.springframework.data.repository.CrudRepository;
+
+import java.util.List;
+
+public interface AnswerRepository extends CrudRepository {
+
+ List findByQuestion(Question question);
+}
diff --git a/src/main/java/com/uniovi/repositories/CategoryRepository.java b/src/main/java/com/uniovi/repositories/CategoryRepository.java
new file mode 100644
index 00000000..2771d22f
--- /dev/null
+++ b/src/main/java/com/uniovi/repositories/CategoryRepository.java
@@ -0,0 +1,10 @@
+package com.uniovi.repositories;
+
+import com.uniovi.entities.Category;
+import org.springframework.data.repository.CrudRepository;
+
+public interface CategoryRepository extends CrudRepository {
+
+ Category findByName(String name);
+
+}
diff --git a/src/main/java/com/uniovi/repositories/QuestionRepository.java b/src/main/java/com/uniovi/repositories/QuestionRepository.java
new file mode 100644
index 00000000..d940deac
--- /dev/null
+++ b/src/main/java/com/uniovi/repositories/QuestionRepository.java
@@ -0,0 +1,9 @@
+package com.uniovi.repositories;
+
+import com.uniovi.entities.Question;
+import org.springframework.data.repository.CrudRepository;
+
+import java.util.Optional;
+
+public interface QuestionRepository extends CrudRepository {
+}
diff --git a/src/main/java/com/uniovi/services/AnswerService.java b/src/main/java/com/uniovi/services/AnswerService.java
new file mode 100644
index 00000000..ff2ddd44
--- /dev/null
+++ b/src/main/java/com/uniovi/services/AnswerService.java
@@ -0,0 +1,35 @@
+package com.uniovi.services;
+
+import com.uniovi.entities.Answer;
+import com.uniovi.entities.Category;
+import com.uniovi.entities.Question;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+
+@Service
+public interface AnswerService {
+
+ /**
+ * Add a new answer to the database
+ *
+ * @param answer Question to be added
+ */
+ void addNewAnswer(Answer answer);
+
+ /**
+ * Get all the answers for a question
+ *
+ * @return A list with all the answers for a question
+ */
+ List getAnswersPerQuestion(Question question);
+
+ /**
+ * Get an answer by its id
+ *
+ * @param id The id of the answer
+ * @return The answer with the given id
+ */
+ Optional getAnswer(Long id);
+}
diff --git a/src/main/java/com/uniovi/services/CategoryService.java b/src/main/java/com/uniovi/services/CategoryService.java
new file mode 100644
index 00000000..52f29eb7
--- /dev/null
+++ b/src/main/java/com/uniovi/services/CategoryService.java
@@ -0,0 +1,36 @@
+package com.uniovi.services;
+
+import com.uniovi.entities.Category;
+import com.uniovi.entities.Question;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+
+@Service
+public interface CategoryService {
+
+ /**
+ * Add a new category to the database
+ *
+ * @param category Question to be added
+ */
+ void addNewCategory(Category category);
+
+ /**
+ * Get all the categories in the database
+ *
+ * @return A list with all the categories
+ */
+ List getAllCategories();
+
+ /**
+ * Get a category by its id
+ *
+ * @param id The id of the category
+ * @return The category with the given id
+ */
+ Optional getCategory(Long id);
+
+ Category getCategoryByName(String geography);
+}
diff --git a/src/main/java/com/uniovi/services/QuestionService.java b/src/main/java/com/uniovi/services/QuestionService.java
new file mode 100644
index 00000000..9bc96b7d
--- /dev/null
+++ b/src/main/java/com/uniovi/services/QuestionService.java
@@ -0,0 +1,34 @@
+package com.uniovi.services;
+
+import com.uniovi.dto.QuestionDto;
+import com.uniovi.entities.Question;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+
+@Service
+public interface QuestionService {
+
+ /**
+ * Add a new question to the database
+ *
+ * @param question Question to be added
+ */
+ void addNewQuestion(Question question);
+
+ /**
+ * Get all the questions in the database
+ *
+ * @return A list with all the questions
+ */
+ List getAllQuestions();
+
+ /**
+ * Get a question by its id
+ *
+ * @param id The id of the question
+ * @return The question with the given id
+ */
+ Optional getQuestion(Long id);
+}
diff --git a/src/main/java/com/uniovi/services/impl/AnswerServiceImpl.java b/src/main/java/com/uniovi/services/impl/AnswerServiceImpl.java
new file mode 100644
index 00000000..2bfdaa1d
--- /dev/null
+++ b/src/main/java/com/uniovi/services/impl/AnswerServiceImpl.java
@@ -0,0 +1,35 @@
+package com.uniovi.services.impl;
+
+import com.uniovi.entities.Answer;
+import com.uniovi.entities.Question;
+import com.uniovi.repositories.AnswerRepository;
+import com.uniovi.services.AnswerService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+
+@Service
+public class AnswerServiceImpl implements AnswerService {
+
+ private final AnswerRepository answerRepository;
+
+ public AnswerServiceImpl(AnswerRepository answerRepository) {
+ this.answerRepository = answerRepository;
+ }
+
+ @Override
+ public void addNewAnswer(Answer answer) {
+ answerRepository.save(answer);
+ }
+
+ @Override
+ public List getAnswersPerQuestion(Question question) {
+ return answerRepository.findByQuestion(question);
+ }
+
+ @Override
+ public Optional getAnswer(Long id) {
+ return answerRepository.findById(id);
+ }
+}
diff --git a/src/main/java/com/uniovi/services/impl/CategoryServiceImpl.java b/src/main/java/com/uniovi/services/impl/CategoryServiceImpl.java
new file mode 100644
index 00000000..636bffe5
--- /dev/null
+++ b/src/main/java/com/uniovi/services/impl/CategoryServiceImpl.java
@@ -0,0 +1,55 @@
+package com.uniovi.services.impl;
+
+import com.uniovi.entities.Category;
+import com.uniovi.repositories.CategoryRepository;
+import com.uniovi.services.CategoryService;
+import jakarta.annotation.PostConstruct;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+@Service
+public class CategoryServiceImpl implements CategoryService {
+
+ private final CategoryRepository categoryRepository;
+
+ public CategoryServiceImpl(CategoryRepository categoryRepository) {
+ this.categoryRepository = categoryRepository;
+ }
+
+ @Override
+ public void addNewCategory(Category category) {
+ categoryRepository.save(category);
+ }
+
+ @Override
+ public List getAllCategories() {
+ List l = new ArrayList<>();
+ categoryRepository.findAll().forEach(l::add);
+ return l;
+ }
+
+ @Override
+ public Optional getCategory(Long id) {
+ return categoryRepository.findById(id);
+ }
+
+ @Override
+ public Category getCategoryByName(String name) {
+ return categoryRepository.findByName(name);
+ }
+
+ private static final Map.Entry[] CATEGORIES = new AbstractMap.SimpleEntry[] {
+ new AbstractMap.SimpleEntry<>("Geography", "Questions about geography")
+ };
+
+ @PostConstruct
+ public void init() {
+ // Add categories, ensuring there's only 1 of them always
+ for (Map.Entry category : CATEGORIES) {
+ if (categoryRepository.findByName(category.getKey())==null) {
+ addNewCategory(new Category(category.getKey(), category.getValue()));
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java b/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java
new file mode 100644
index 00000000..0a3aa771
--- /dev/null
+++ b/src/main/java/com/uniovi/services/impl/QuestionServiceImpl.java
@@ -0,0 +1,38 @@
+package com.uniovi.services.impl;
+
+import com.uniovi.entities.Question;
+import com.uniovi.repositories.QuestionRepository;
+import com.uniovi.services.QuestionService;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+@Service
+public class QuestionServiceImpl implements QuestionService {
+
+ private final QuestionRepository questionRepository;
+
+ public QuestionServiceImpl(QuestionRepository questionRepository) {
+ this.questionRepository = questionRepository;
+ }
+
+ @Override
+ public void addNewQuestion(Question question) {
+ questionRepository.save(question);
+ }
+
+ @Override
+ public List getAllQuestions() {
+ List l = new ArrayList<>();
+ questionRepository.findAll().forEach(l::add);
+ return l;
+ }
+
+ @Override
+ public Optional getQuestion(Long id) {
+ return questionRepository.findById(id);
+ }
+
+}