-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #51 from nora-kauczor/move-check-answer-to-backend
Move check answer to backend
- Loading branch information
Showing
16 changed files
with
556 additions
and
165 deletions.
There are no files selected for viewing
20 changes: 20 additions & 0 deletions
20
backend/src/main/java/org/example/backend/check/CheckController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package org.example.backend.check; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
|
||
@RestController | ||
@RequestMapping("/api/check") | ||
@RequiredArgsConstructor | ||
public class CheckController { | ||
|
||
private final CheckService checkService; | ||
|
||
|
||
@GetMapping("/{vocabId}") | ||
public boolean isUserAnswerCorrect(@PathVariable String vocabId, @RequestParam String answer) { | ||
return checkService.isUserAnswerCorrect(vocabId, answer); | ||
} | ||
|
||
} |
55 changes: 55 additions & 0 deletions
55
backend/src/main/java/org/example/backend/check/CheckService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package org.example.backend.check; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.example.backend.vocab.Language; | ||
import org.example.backend.vocab.Vocab; | ||
import org.example.backend.vocab.VocabRepo; | ||
import org.springframework.stereotype.Service; | ||
|
||
|
||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
import static org.example.backend.check.CorrectAnswers.getCorrectAnswers; | ||
|
||
@RequiredArgsConstructor | ||
@Service | ||
public class CheckService { | ||
|
||
private final VocabRepo vocabRepo; | ||
|
||
public boolean isUserAnswerCorrect(String vocabId, String userAnswer) { | ||
Optional<Vocab> vocabOptional = vocabRepo.findById(vocabId); | ||
Vocab vocab = vocabOptional.orElseThrow(); | ||
String word = vocab.getWord(); | ||
Language language = vocab.getLanguage(); | ||
List<String> correctAnswers = getCorrectAnswers(word, language); | ||
List<String> correctAnswersLowerCase = correctAnswers.stream() | ||
.map(String::toLowerCase) | ||
.toList(); | ||
String inputWithoutExtraSpaces = getInputWithoutExtraSpaces(userAnswer); | ||
return correctAnswersLowerCase.stream() | ||
.anyMatch(answer -> answer.equals(inputWithoutExtraSpaces.toLowerCase())); | ||
} | ||
|
||
|
||
public String getInputWithoutExtraSpaces(String userAnswer) { | ||
String trimmedInput = userAnswer.trim(); | ||
StringBuilder result = new StringBuilder(); | ||
boolean previousWasSpace = false; | ||
for (int i = 0; i < trimmedInput.length(); i++) { | ||
char currentChar = trimmedInput.charAt(i); | ||
if (currentChar == ' ') { | ||
if (previousWasSpace) { | ||
continue; | ||
} | ||
previousWasSpace = true; | ||
} else { | ||
previousWasSpace = false; | ||
} | ||
|
||
result.append(currentChar); | ||
} | ||
return result.toString(); | ||
} | ||
} |
137 changes: 137 additions & 0 deletions
137
backend/src/main/java/org/example/backend/check/CorrectAnswers.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package org.example.backend.check; | ||
|
||
import org.example.backend.vocab.Language; | ||
|
||
import java.util.List; | ||
|
||
|
||
public class CorrectAnswers { | ||
|
||
public static List<String> getCorrectAnswers(String word, Language language) { | ||
String leftSideOfSlash = getLeftSideOfSlash(word); | ||
String leftSideOfSlashWithoutArticle = getWordWithoutArticle(leftSideOfSlash, language); | ||
String rightSideOfSlash = getRightSideOfSlash(word); | ||
String rightSideOfSlashWithoutArticle = getWordWithoutArticle(word, language); | ||
String leftSideOfSlashWithEndingOfRightSide = getLeftSideOfSlashWithEndingOfRightSide(word); | ||
String wordWithoutArticle = getWordWithoutArticle(word, language); | ||
String wordWithoutBrackets = getWordWithoutBrackets(word); | ||
String wordWithoutBracketsRunTwice = getWordWithoutBrackets(wordWithoutBrackets); | ||
String wordWithoutBracketsRunTwiceWithoutArticle = getWordWithoutArticle(wordWithoutBracketsRunTwice, language); | ||
String wordWithoutBracketsAndWithoutContent = getWordWithoutBracketsAndWithoutBracketsContent(word); | ||
String wordWithoutBracketsAndWithoutContentRunTwice = getWordWithoutBracketsAndWithoutBracketsContent(wordWithoutBracketsAndWithoutContent); | ||
String wordWithoutBracketsAndWithoutContentRunTwiceWithoutArticle = getWordWithoutArticle(wordWithoutBracketsAndWithoutContentRunTwice, language); | ||
return List.of( | ||
word, | ||
leftSideOfSlash, | ||
leftSideOfSlashWithoutArticle, | ||
rightSideOfSlash, | ||
rightSideOfSlashWithoutArticle, | ||
leftSideOfSlashWithEndingOfRightSide, | ||
wordWithoutArticle, | ||
wordWithoutBracketsRunTwiceWithoutArticle, | ||
wordWithoutBracketsRunTwice, | ||
wordWithoutBracketsAndWithoutContentRunTwiceWithoutArticle, | ||
wordWithoutBracketsAndWithoutContentRunTwice | ||
); | ||
} | ||
|
||
public static String getLeftSideOfSlash(String word) { | ||
char slash = '/'; | ||
boolean wordHasSlash = word.indexOf(slash) != -1; | ||
if (!wordHasSlash) { | ||
return word; | ||
} | ||
int indexOfSlash = word.indexOf(slash); | ||
return word.substring(0, indexOfSlash); | ||
} | ||
|
||
public static String getRightSideOfSlash(String word) { | ||
char slash = '/'; | ||
boolean wordHasSlash = word.indexOf(slash) != -1; | ||
if (!wordHasSlash) { | ||
return word; | ||
} | ||
int indexOfSlash = word.indexOf(slash); | ||
return word.substring(indexOfSlash + 1); | ||
} | ||
|
||
public static String getLeftSideOfSlashWithEndingOfRightSide(String word) { | ||
char slash = '/'; | ||
boolean wordHasSlash = word.indexOf(slash) != -1; | ||
if (!wordHasSlash) { | ||
return word; | ||
} | ||
int indexOfSlash = word.indexOf(slash); | ||
char minus = '-'; | ||
boolean wordHasMinus = word.indexOf(minus) != -1; | ||
if (!wordHasMinus) { | ||
return word; | ||
} | ||
String ending = word.substring(indexOfSlash + 2); | ||
String leftSideWithoutLastLetter = word.substring(0, indexOfSlash - 1); | ||
return leftSideWithoutLastLetter + ending; | ||
} | ||
|
||
public static String getWordWithoutArticle(String word, Language language) { | ||
List<String> articles = List.of("el", "la", "los", "las", "un", | ||
"una", "unos", "unas"); | ||
if (language.equals(Language.ITALIAN)) { | ||
articles = List.of("il", "lo", "la", "i", "gli", "le", | ||
"un", "uno", "una", "un'"); | ||
} | ||
if (language.equals(Language.FRENCH)) { | ||
articles = List.of("le", "la", "les", "un", "une", "des", | ||
"l'"); | ||
} | ||
boolean wordStartsWithArticlesLetters = articles.stream().anyMatch(word::contains); | ||
if (!wordStartsWithArticlesLetters) { | ||
return word; | ||
} | ||
String wordWithoutArticle = word; | ||
for (String article : articles) { | ||
boolean articleIsAtBeginning = word.indexOf(article) == 0; | ||
int articleLength = article.length(); | ||
String substringBehindArticle = word.substring(articleLength, articleLength + 1); | ||
boolean spaceBehindArticle = substringBehindArticle.equals(" "); | ||
if (articleIsAtBeginning && spaceBehindArticle) { | ||
wordWithoutArticle = word.substring(articleLength + 1); | ||
} | ||
boolean bracketBehindArticle = substringBehindArticle.equals("("); | ||
if (articleIsAtBeginning && bracketBehindArticle) { | ||
wordWithoutArticle = word.substring(articleLength + 4); | ||
} | ||
} | ||
return wordWithoutArticle; | ||
} | ||
|
||
public static String getWordWithoutBrackets(String word) { | ||
char openingBracket = '('; | ||
char closingBracket = ')'; | ||
boolean wordHasBrackets = word.indexOf(openingBracket) != -1; | ||
if (!wordHasBrackets) { | ||
return word; | ||
} | ||
int indexOfOpeningBracket = word.indexOf(openingBracket); | ||
int indexOfClosingBracket = word.indexOf(closingBracket); | ||
String substringBeforeBrackets = word.substring(0, indexOfOpeningBracket); | ||
String substringBetweenBrackets = word.substring(indexOfOpeningBracket + 1, indexOfClosingBracket); | ||
String subStringAfterBrackets = word.substring(indexOfClosingBracket + 1); | ||
return substringBeforeBrackets + substringBetweenBrackets + subStringAfterBrackets; | ||
} | ||
|
||
public static String getWordWithoutBracketsAndWithoutBracketsContent(String word) { | ||
char openingBracket = '('; | ||
char closingBracket = ')'; | ||
boolean wordHasBrackets = word.indexOf(openingBracket) != -1; | ||
if (!wordHasBrackets) { | ||
return word; | ||
} | ||
int indexOfOpeningBracket = word.indexOf(openingBracket); | ||
int indexOfClosingBracket = word.indexOf(closingBracket); | ||
String substringBeforeBrackets = word.substring(0, indexOfOpeningBracket); | ||
String subStringAfterBrackets = word.substring(indexOfClosingBracket + 1); | ||
return substringBeforeBrackets + subStringAfterBrackets; | ||
} | ||
|
||
|
||
} |
12 changes: 2 additions & 10 deletions
12
backend/src/main/java/org/example/backend/vocab/VocabRepo.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,14 @@ | ||
package org.example.backend.vocab; | ||
|
||
import org.example.backend.exception.LanguageNotFoundException; | ||
|
||
import org.springframework.data.mongodb.repository.MongoRepository; | ||
import org.springframework.stereotype.Repository; | ||
|
||
import java.util.List; | ||
|
||
import static org.example.backend.vocab.Language.getEnumByString; | ||
|
||
@Repository | ||
public interface VocabRepo extends MongoRepository<Vocab, String> { | ||
List<Vocab> getByLanguage(Language language); | ||
|
||
// public static List<Vocab> getAllNEWTEST(String languageString, String userId) throws LanguageNotFoundException { | ||
// Language language = getEnumByString(languageString); | ||
// return vocabRepo.findAll().stream() | ||
// .filter(vocab -> vocab.getCreatedBy().equals("Wordio") || vocab.getCreatedBy().equals(userId)) | ||
// .filter(vocab -> vocab.getLanguage().equals(language)) | ||
// .toList(); | ||
// } | ||
|
||
} |
111 changes: 111 additions & 0 deletions
111
backend/src/test/java/org/example/backend/check/CheckControllerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package org.example.backend.check; | ||
|
||
import org.example.backend.vocab.Language; | ||
import org.example.backend.vocab.Vocab; | ||
import org.example.backend.vocab.VocabRepo; | ||
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.web.servlet.AutoConfigureMockMvc; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.test.annotation.DirtiesContext; | ||
import org.springframework.test.web.servlet.MockMvc; | ||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; | ||
|
||
import java.util.HashMap; | ||
|
||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.oauth2Login; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
|
||
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) | ||
@SpringBootTest | ||
@AutoConfigureMockMvc | ||
class CheckControllerTest { | ||
|
||
@Autowired | ||
private MockMvc mvc; | ||
|
||
@Autowired | ||
private VocabRepo vocabRepo; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
Vocab testVocab = new Vocab("vocab-id", "beau/belle", "beautiful", | ||
"", Language.FRENCH, new HashMap<>(), "Wordio"); | ||
Vocab testVocab2 = new Vocab("vocab-id2", "la liberté", "liberty", | ||
"", Language.FRENCH, new HashMap<>(), "Wordio"); | ||
Vocab testVocab3 = new Vocab("vocab-id3", "rojo/-a", "red", | ||
"", Language.FRENCH, new HashMap<>(), "Wordio"); | ||
vocabRepo.save(testVocab); | ||
vocabRepo.save(testVocab2); | ||
vocabRepo.save(testVocab3); | ||
} | ||
|
||
@Test | ||
void isUserAnswerCorrect_ShouldReturnTrue_whenCalledWithIdOfBeauBelleAndUserAnswerBeau() throws Exception { | ||
mvc.perform(MockMvcRequestBuilders.get("/api/check/vocab-id") | ||
.param("answer", "beau") | ||
.with(oauth2Login().attributes(attributes -> { | ||
attributes.put("sub", "jane-doe"); | ||
}))) | ||
.andExpect(status().isOk()) | ||
.andExpect(content().string("true")); | ||
} | ||
|
||
@Test | ||
void isUserAnswerCorrect_ShouldReturnFalse_whenCalledWithIdOfBeauBelleAndUserAnswerBaeu()throws Exception { | ||
mvc.perform(MockMvcRequestBuilders.get("/api/check/vocab-id") | ||
.param("answer", "baeu") | ||
.with(oauth2Login().attributes(attributes -> { | ||
attributes.put("sub", "jane-doe"); | ||
}))) | ||
.andExpect(status().isOk()) | ||
.andExpect(content().string("false")); | ||
} | ||
|
||
@Test | ||
void isUserAnswerCorrect_ShouldReturnTrue_whenCalledWithIdOfLaLiberteAndUserAnswerLaliberte() throws Exception { | ||
mvc.perform(MockMvcRequestBuilders.get("/api/check/vocab-id2") | ||
.param("answer", "la liberté") | ||
.with(oauth2Login().attributes(attributes -> { | ||
attributes.put("sub", "jane-doe"); | ||
}))) | ||
.andExpect(status().isOk()) | ||
.andExpect(content().string("true")); | ||
} | ||
|
||
@Test | ||
void isUserAnswerCorrect_ShouldReturnTrue_whenCalledWithIdOfLaLiberteAndUserAnswerliberte() throws Exception { | ||
mvc.perform(MockMvcRequestBuilders.get("/api/check/vocab-id2") | ||
.param("answer", "liberté") | ||
.with(oauth2Login().attributes(attributes -> { | ||
attributes.put("sub", "jane-doe"); | ||
}))) | ||
.andExpect(status().isOk()) | ||
.andExpect(content().string("true")); | ||
} | ||
|
||
@Test | ||
void isUserAnswerCorrect_ShouldReturnTrue_whenCalledWithIdOfRojoAAndUserAnswerRojo() throws Exception { | ||
mvc.perform(MockMvcRequestBuilders.get("/api/check/vocab-id3") | ||
.param("answer", "rojo") | ||
.with(oauth2Login().attributes(attributes -> { | ||
attributes.put("sub", "jane-doe"); | ||
}))) | ||
.andExpect(status().isOk()) | ||
.andExpect(content().string("true")); | ||
} | ||
|
||
|
||
@Test | ||
void isUserAnswerCorrect_ShouldReturnTrue_whenCalledWithIdOfRojoAAndUserAnswerRoja() throws Exception { | ||
mvc.perform(MockMvcRequestBuilders.get("/api/check/vocab-id3") | ||
.param("answer", "roja") | ||
.with(oauth2Login().attributes(attributes -> { | ||
attributes.put("sub", "jane-doe"); | ||
}))) | ||
.andExpect(status().isOk()) | ||
.andExpect(content().string("true")); | ||
} | ||
} |
Oops, something went wrong.