diff --git a/src/main/java/de/unistuttgart/bugfinder/code/CodeRepository.java b/src/main/java/de/unistuttgart/bugfinder/code/CodeRepository.java new file mode 100644 index 0000000..6324a16 --- /dev/null +++ b/src/main/java/de/unistuttgart/bugfinder/code/CodeRepository.java @@ -0,0 +1,8 @@ +package de.unistuttgart.bugfinder.code; + +import java.util.UUID; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface CodeRepository extends JpaRepository {} diff --git a/src/main/java/de/unistuttgart/bugfinder/configuration/ConfigurationController.java b/src/main/java/de/unistuttgart/bugfinder/configuration/ConfigurationController.java index 33c63ae..501f3f3 100644 --- a/src/main/java/de/unistuttgart/bugfinder/configuration/ConfigurationController.java +++ b/src/main/java/de/unistuttgart/bugfinder/configuration/ConfigurationController.java @@ -1,7 +1,7 @@ package de.unistuttgart.bugfinder.configuration; +import de.unistuttgart.bugfinder.configuration.vm.ConfigurationVM; import java.util.List; -import java.util.Optional; import java.util.UUID; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -27,6 +27,12 @@ public ConfigurationDTO get(@PathVariable final UUID id) { return configurationService.find(id); } + @GetMapping("/configurations/vm/{id}") + public ConfigurationVM getVM(@PathVariable final UUID id) { + log.debug("GET /configurations/{}", id); + return configurationService.getViewModel(id); + } + @ResponseStatus(HttpStatus.CREATED) @PostMapping("/configurations") public ConfigurationDTO createConfiguration(@RequestBody final ConfigurationDTO configurationDTO) { @@ -34,6 +40,19 @@ public ConfigurationDTO createConfiguration(@RequestBody final ConfigurationDTO return configurationService.save(configurationDTO); } + /** + * used by the lecture interface to build a configuration by the view model + * + * @param configurationBuilderCodeDTO + * @return + */ + @ResponseStatus(HttpStatus.CREATED) + @PostMapping("/configurations/build") + public ConfigurationDTO buildConfiguration(@RequestBody final ConfigurationVM configurationBuilderCodeDTO) { + log.debug("POST /configurations/builder with body {}", configurationBuilderCodeDTO); + return configurationService.build(configurationBuilderCodeDTO); + } + @PutMapping("/configurations/{id}") public ConfigurationDTO updateConfiguration( @PathVariable final UUID id, diff --git a/src/main/java/de/unistuttgart/bugfinder/configuration/ConfigurationDTO.java b/src/main/java/de/unistuttgart/bugfinder/configuration/ConfigurationDTO.java index 72d00f8..bcbbfdf 100644 --- a/src/main/java/de/unistuttgart/bugfinder/configuration/ConfigurationDTO.java +++ b/src/main/java/de/unistuttgart/bugfinder/configuration/ConfigurationDTO.java @@ -1,6 +1,5 @@ package de.unistuttgart.bugfinder.configuration; -import de.unistuttgart.bugfinder.code.Code; import de.unistuttgart.bugfinder.code.CodeDTO; import java.util.List; import java.util.UUID; diff --git a/src/main/java/de/unistuttgart/bugfinder/configuration/ConfigurationService.java b/src/main/java/de/unistuttgart/bugfinder/configuration/ConfigurationService.java index d851f8c..adf4b4f 100644 --- a/src/main/java/de/unistuttgart/bugfinder/configuration/ConfigurationService.java +++ b/src/main/java/de/unistuttgart/bugfinder/configuration/ConfigurationService.java @@ -1,13 +1,19 @@ package de.unistuttgart.bugfinder.configuration; -import static org.springframework.http.HttpStatus.NOT_FOUND; - +import de.unistuttgart.bugfinder.code.Code; import de.unistuttgart.bugfinder.code.CodeDTO; import de.unistuttgart.bugfinder.code.CodeMapper; -import de.unistuttgart.bugfinder.code.CodeService; -import java.util.List; -import java.util.Optional; -import java.util.UUID; +import de.unistuttgart.bugfinder.code.CodeRepository; +import de.unistuttgart.bugfinder.code.word.Word; +import de.unistuttgart.bugfinder.code.word.WordRepository; +import de.unistuttgart.bugfinder.configuration.vm.CodeVM; +import de.unistuttgart.bugfinder.configuration.vm.ConfigurationVM; +import de.unistuttgart.bugfinder.configuration.vm.WordVM; +import de.unistuttgart.bugfinder.solution.Solution; +import de.unistuttgart.bugfinder.solution.SolutionRepository; +import de.unistuttgart.bugfinder.solution.bug.Bug; +import de.unistuttgart.bugfinder.solution.bug.BugRepository; +import java.util.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -27,11 +33,24 @@ public class ConfigurationService { @Autowired private CodeMapper codeMapper; + @Autowired + private CodeRepository codeRepository; + + @Autowired + private SolutionRepository solutionRepository; + + @Autowired + private WordRepository wordRepository; + + @Autowired + private BugRepository bugRepository; + /** * Get a configuration by its id. + * * @param id the id of the configuration - * @throws ResponseStatusException (404) when configuration with its id does not exist * @return the found configuration + * @throws ResponseStatusException (404) when configuration with its id does not exist */ public Configuration getConfiguration(final UUID id) { return configurationRepository @@ -51,9 +70,10 @@ public List findAll() { /** * Get the configuration by its id as DTO. + * * @param id the id of the configuration - * @throws ResponseStatusException (404) when configuration with its id does not exist * @return the found configuration as DTO + * @throws ResponseStatusException (404) when configuration with its id does not exist */ public ConfigurationDTO find(final UUID id) { log.debug("get configuration {}", id); @@ -72,6 +92,53 @@ public ConfigurationDTO save(final ConfigurationDTO configurationDTO) { return configurationMapper.toDTO(configurationRepository.save(configurationMapper.fromDTO(configurationDTO))); } + public ConfigurationDTO build(final ConfigurationVM configurationVM) { + Set codesToPersist = new HashSet<>(configurationVM.getCodes().size()); + for (CodeVM codeVM : configurationVM.getCodes()) { + List wordsToPersistToCode = new ArrayList<>(codeVM.getWords().size()); + Set bugsToPersistToSolution = new HashSet<>(); + bugsToPersistToSolution = new HashSet<>(); + for (List row : codeVM.getWords()) { + // check if the row only contains blank strings + // the first row will never contain only blank strings since it comes from the lecture interface + if (row.stream().allMatch(wordVM -> wordVM.getCorrectValue().isBlank())) { + continue; + } + // if it is not the first row in the code we add a new line + if (codeVM.getWords().indexOf(row) != 0) { + wordsToPersistToCode.add(wordRepository.save(new Word(null, "\n"))); + } + for (WordVM wordVM : row) { + // check if the word is blank + // the first word will never be blank since it comes from the lecture interface + if (wordVM.getCorrectValue().isBlank()) { + continue; + } + // if it is not the first word in the row we add a space + if (row.indexOf(wordVM) != 0) { + wordsToPersistToCode.add(wordRepository.save(new Word(null, " "))); + } + String displayValue = wordVM.getDisplayValue() != null ? wordVM.getDisplayValue() : wordVM.getCorrectValue(); + Word word = new Word(null, displayValue); + word = wordRepository.save(word); + wordsToPersistToCode.add(word); + if (wordVM.getErrorType() != null) { + Bug bug = new Bug(word, wordVM.getErrorType(), wordVM.getCorrectValue()); + bugsToPersistToSolution.add(bug); + bug = bugRepository.save(bug); + } + } + } + Code code = new Code(null, wordsToPersistToCode); + codesToPersist.add(code); + Solution solution = new Solution(null, bugsToPersistToSolution, code); + code = codeRepository.save(code); + solution = solutionRepository.save(solution); + } + Configuration configuration = new Configuration(null, codesToPersist); + return configurationMapper.toDTO(configurationRepository.save(configuration)); + } + /** * Deletes the configuration with the given ID, if present. * @@ -99,4 +166,51 @@ public List getCodes(final UUID id) { final Configuration configuration = getConfiguration(id); return codeMapper.toDTO(configuration.getCodes()); } + + public ConfigurationVM getViewModel(UUID id) { + log.debug("get configuration view model {}", id); + final Configuration configuration = getConfiguration(id); + final ConfigurationVM configurationVM = new ConfigurationVM(new ArrayList<>()); + for (Code code : configuration.getCodes()) { + final CodeVM codeVM = new CodeVM(new ArrayList<>()); + final Solution solution = solutionRepository + .findByCodeId(code.getId()) + .orElseThrow(() -> + new ResponseStatusException( + HttpStatus.NOT_FOUND, + String.format("Solution with code id %s not found.", code.getId()) + ) + ); + + List row = new ArrayList<>(); + for (Word word : code.getWords()) { + if (word.getWord().equals(" ")) { + continue; + } + if (word.getWord().equals("\n")) { + codeVM.getWords().add(row); + row = new ArrayList<>(); + continue; + } + Optional bug = solution + .getBugs() + .stream() + .filter(b -> b.getWord().getId().equals(word.getId())) + .findFirst(); + final WordVM wordVM = new WordVM(); + if (bug.isPresent()) { + wordVM.setErrorType(bug.get().getErrorType()); + wordVM.setCorrectValue(bug.get().getCorrectValue()); + wordVM.setDisplayValue(word.getWord()); + } else { + wordVM.setCorrectValue(word.getWord()); + } + row.add(wordVM); + } + codeVM.getWords().add(row); + configurationVM.getCodes().add(codeVM); + } + + return configurationVM; + } } diff --git a/src/main/java/de/unistuttgart/bugfinder/configuration/vm/CodeVM.java b/src/main/java/de/unistuttgart/bugfinder/configuration/vm/CodeVM.java new file mode 100644 index 0000000..6179e9b --- /dev/null +++ b/src/main/java/de/unistuttgart/bugfinder/configuration/vm/CodeVM.java @@ -0,0 +1,17 @@ +package de.unistuttgart.bugfinder.configuration.vm; + +import java.util.List; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.FieldDefaults; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE) +public class CodeVM { + + List> words; +} diff --git a/src/main/java/de/unistuttgart/bugfinder/configuration/vm/ConfigurationVM.java b/src/main/java/de/unistuttgart/bugfinder/configuration/vm/ConfigurationVM.java new file mode 100644 index 0000000..2d71b3b --- /dev/null +++ b/src/main/java/de/unistuttgart/bugfinder/configuration/vm/ConfigurationVM.java @@ -0,0 +1,20 @@ +package de.unistuttgart.bugfinder.configuration.vm; + +import java.util.List; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.FieldDefaults; + +/** + * describes the view model of the lecture interface and is used to build configurations + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE) +public class ConfigurationVM { + + List codes; +} diff --git a/src/main/java/de/unistuttgart/bugfinder/configuration/vm/WordVM.java b/src/main/java/de/unistuttgart/bugfinder/configuration/vm/WordVM.java new file mode 100644 index 0000000..b089f17 --- /dev/null +++ b/src/main/java/de/unistuttgart/bugfinder/configuration/vm/WordVM.java @@ -0,0 +1,24 @@ +package de.unistuttgart.bugfinder.configuration.vm; + +import de.unistuttgart.bugfinder.solution.bug.ErrorType; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.FieldDefaults; +import org.springframework.lang.Nullable; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE) +public class WordVM { + + String correctValue; + + @Nullable + String displayValue; + + @Nullable + ErrorType errorType; +} diff --git a/src/test/java/de/unistuttgart/bugfinder/ConfigurationControllerTest.java b/src/test/java/de/unistuttgart/bugfinder/ConfigurationControllerTest.java index 7ac4b8a..26292a2 100644 --- a/src/test/java/de/unistuttgart/bugfinder/ConfigurationControllerTest.java +++ b/src/test/java/de/unistuttgart/bugfinder/ConfigurationControllerTest.java @@ -30,6 +30,8 @@ @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ConfigurationControllerTest { + private final String API_URL = "/configurations"; + @Autowired private MockMvc mvc; @@ -39,7 +41,6 @@ public class ConfigurationControllerTest { @Autowired private ConfigurationRepository configurationRepository; - private final String API_URL = "/configurations"; private ObjectMapper objectMapper; private Configuration initialConfig; private ConfigurationDTO initialConfigDTO;