diff --git a/backend/build.gradle b/backend/build.gradle index c8afe77dc250e2f1fa04a212cf1da0b0aff512a4..8670fbf4921f606b60ff0f2bff800b28c0c78d53 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -25,6 +25,9 @@ dependencies { implementation "org.zwobble.mammoth:mammoth:1.5.0" + implementation group: 'org.apache.poi', name: 'poi-ooxml', version: '5.2.2' + implementation 'org.jsoup:jsoup:1.15.4' + testImplementation 'org.springframework.boot:spring-boot-starter-test' // testImplementation 'org.springframework.security:spring-security-test' diff --git a/backend/src/main/java/ut/ee/hades/app/dao/entity/ExerciseEntity.java b/backend/src/main/java/ut/ee/hades/app/dao/entity/ExerciseEntity.java index 1773ddb91ed2ed143c4a7af3083de26d3bc8e81a..01b5d46147e8e93b54e2467febf2f5c63b4f73cb 100644 --- a/backend/src/main/java/ut/ee/hades/app/dao/entity/ExerciseEntity.java +++ b/backend/src/main/java/ut/ee/hades/app/dao/entity/ExerciseEntity.java @@ -14,7 +14,7 @@ public class ExerciseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne(fetch = FetchType.LAZY) + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE) @JoinColumn(name = "document_id") private FileEntity file; } diff --git a/backend/src/main/java/ut/ee/hades/app/dao/repository/DocumentRepository.java b/backend/src/main/java/ut/ee/hades/app/dao/repository/FileRepository.java similarity index 73% rename from backend/src/main/java/ut/ee/hades/app/dao/repository/DocumentRepository.java rename to backend/src/main/java/ut/ee/hades/app/dao/repository/FileRepository.java index a1ebaaf4058a6af1c019b3cd509221e286fdc8db..eaf6370bf16a6cffea627b0e9590c1341879207f 100644 --- a/backend/src/main/java/ut/ee/hades/app/dao/repository/DocumentRepository.java +++ b/backend/src/main/java/ut/ee/hades/app/dao/repository/FileRepository.java @@ -5,5 +5,5 @@ import org.springframework.stereotype.Repository; import ut.ee.hades.app.dao.entity.FileEntity; @Repository -public interface DocumentRepository extends JpaRepository<FileEntity, Long> { +public interface FileRepository extends JpaRepository<FileEntity, Long> { } diff --git a/backend/src/main/java/ut/ee/hades/app/enums/ExceptionCodeEnum.java b/backend/src/main/java/ut/ee/hades/app/enums/ExceptionCodeEnum.java index 3c8de9635eaa54f04fcf0ce904f80f7eba32a792..cc8887bdd5cab49db1c387a0c7b22622e732cb97 100644 --- a/backend/src/main/java/ut/ee/hades/app/enums/ExceptionCodeEnum.java +++ b/backend/src/main/java/ut/ee/hades/app/enums/ExceptionCodeEnum.java @@ -1,7 +1,19 @@ package ut.ee.hades.app.enums; public enum ExceptionCodeEnum { - NOT_ALLOWED_FILE_TYPE, - TEST_ERROR, + NOT_ALLOWED_FILE_TYPE("Ebasobiv faili tأ¼أ¼p!"), + FILE_DOWNLOAD_ERROR("Dokumendi alla laadimine ebaأµnnestus!"), + FILE_SAVE_ERROR("Dokumendi salvestamine ebaأµnnestus!"), + CONTENT_CONVERT_ERROR("Sisu teisendamine ebaأµnnestus!"); + + private final String name; + + ExceptionCodeEnum(String name) { + this.name = name; + } + + public String getName() { + return name; + } } diff --git a/backend/src/main/java/ut/ee/hades/app/exceptions/system/HADESConvertException.java b/backend/src/main/java/ut/ee/hades/app/exceptions/system/HADESConvertException.java new file mode 100644 index 0000000000000000000000000000000000000000..ee16e18e622c5d628605f119d4135954135e9e28 --- /dev/null +++ b/backend/src/main/java/ut/ee/hades/app/exceptions/system/HADESConvertException.java @@ -0,0 +1,9 @@ +package ut.ee.hades.app.exceptions.system; + + +public class HADESConvertException extends RuntimeException { + + public HADESConvertException(String message) { + super(message); + } +} diff --git a/backend/src/main/java/ut/ee/hades/app/exceptions/system/HADESFileDownloadException.java b/backend/src/main/java/ut/ee/hades/app/exceptions/system/HADESFileDownloadException.java new file mode 100644 index 0000000000000000000000000000000000000000..8dcad04aba7ba1c53cf9bcd8358e7e4c26dc7aae --- /dev/null +++ b/backend/src/main/java/ut/ee/hades/app/exceptions/system/HADESFileDownloadException.java @@ -0,0 +1,8 @@ +package ut.ee.hades.app.exceptions.system; + +public class HADESFileDownloadException extends Exception{ + + public HADESFileDownloadException(String message) { + super(message); + } +} diff --git a/backend/src/main/java/ut/ee/hades/app/exceptions/system/HADESFileSaveException.java b/backend/src/main/java/ut/ee/hades/app/exceptions/system/HADESFileSaveException.java new file mode 100644 index 0000000000000000000000000000000000000000..39d2af4cf43d579078159b30c56febbc6bfe0edd --- /dev/null +++ b/backend/src/main/java/ut/ee/hades/app/exceptions/system/HADESFileSaveException.java @@ -0,0 +1,8 @@ +package ut.ee.hades.app.exceptions.system; + +public class HADESFileSaveException extends Exception { + + public HADESFileSaveException(String message) { + super(message); + } +} diff --git a/backend/src/main/java/ut/ee/hades/app/exceptions/UiAlertDangerException.java b/backend/src/main/java/ut/ee/hades/app/exceptions/ui/UiAlertDangerException.java similarity index 87% rename from backend/src/main/java/ut/ee/hades/app/exceptions/UiAlertDangerException.java rename to backend/src/main/java/ut/ee/hades/app/exceptions/ui/UiAlertDangerException.java index b02e6fad573c904334eb57828405a3d7891f84c6..11c8478ca2d6a193cb87b46187bb1b48d6d80335 100644 --- a/backend/src/main/java/ut/ee/hades/app/exceptions/UiAlertDangerException.java +++ b/backend/src/main/java/ut/ee/hades/app/exceptions/ui/UiAlertDangerException.java @@ -1,4 +1,4 @@ -package ut.ee.hades.app.exceptions; +package ut.ee.hades.app.exceptions.ui; import lombok.Getter; import ut.ee.hades.app.web.model.UiAlert; diff --git a/backend/src/main/java/ut/ee/hades/app/exceptions/UiAlertException.java b/backend/src/main/java/ut/ee/hades/app/exceptions/ui/UiAlertException.java similarity index 56% rename from backend/src/main/java/ut/ee/hades/app/exceptions/UiAlertException.java rename to backend/src/main/java/ut/ee/hades/app/exceptions/ui/UiAlertException.java index 12e37ff2b3f1a52bf7fc1b62392d8456f2985040..1b24402959672d96ca991151c2d7ece771800bb4 100644 --- a/backend/src/main/java/ut/ee/hades/app/exceptions/UiAlertException.java +++ b/backend/src/main/java/ut/ee/hades/app/exceptions/ui/UiAlertException.java @@ -1,15 +1,13 @@ -package ut.ee.hades.app.exceptions; +package ut.ee.hades.app.exceptions.ui; -import lombok.AllArgsConstructor; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import ut.ee.hades.app.web.model.UiAlert; @Getter @Setter public class UiAlertException extends RuntimeException { - private UiAlert alert; + private transient UiAlert alert; } diff --git a/backend/src/main/java/ut/ee/hades/app/exceptions/UiAlertWarningException.java b/backend/src/main/java/ut/ee/hades/app/exceptions/ui/UiAlertWarningException.java similarity index 66% rename from backend/src/main/java/ut/ee/hades/app/exceptions/UiAlertWarningException.java rename to backend/src/main/java/ut/ee/hades/app/exceptions/ui/UiAlertWarningException.java index d369a92b1a62ce4df3cd4ff1cfbe92283863773c..cb94465c95a8411677800eaeae050cba7b415e3b 100644 --- a/backend/src/main/java/ut/ee/hades/app/exceptions/UiAlertWarningException.java +++ b/backend/src/main/java/ut/ee/hades/app/exceptions/ui/UiAlertWarningException.java @@ -1,8 +1,6 @@ -package ut.ee.hades.app.exceptions; +package ut.ee.hades.app.exceptions.ui; import lombok.Getter; -import ut.ee.hades.app.enums.ExceptionCodeEnum; -import ut.ee.hades.app.exceptions.UiAlertException; import ut.ee.hades.app.web.model.UiAlert; @Getter diff --git a/backend/src/main/java/ut/ee/hades/app/util/DocumentUtils.java b/backend/src/main/java/ut/ee/hades/app/util/DocumentUtils.java index 9f1203865a447edc2a2948765d390347dc29e11c..f9cb9601df6f0b139652c9c4517c4aeed7e48305 100644 --- a/backend/src/main/java/ut/ee/hades/app/util/DocumentUtils.java +++ b/backend/src/main/java/ut/ee/hades/app/util/DocumentUtils.java @@ -1,13 +1,39 @@ package ut.ee.hades.app.util; +import org.apache.poi.xwpf.usermodel.*; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; +import org.springframework.web.multipart.MultipartFile; import org.zwobble.mammoth.DocumentConverter; +import ut.ee.hades.app.dao.entity.FileEntity; +import ut.ee.hades.app.exceptions.ui.UiAlertWarningException; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; public class DocumentUtils { + private DocumentUtils() { + + } + + public static FileEntity prepareFileSave(MultipartFile file) throws IOException { + FileEntity fileEntity = new FileEntity(); + fileEntity.setContent(file.getBytes()); + fileEntity.setSize(file.getSize()); + fileEntity.setMimeType(file.getContentType()); + fileEntity.setName(file.getOriginalFilename()); + + return fileEntity; + } + + public static void validateFileType(MultipartFile file) { + if (AllowedMimeUtils.mimeMap.get(file.getContentType()) == null) { + throw new UiAlertWarningException("ExceptionCodeEnum.NOT_ALLOWED_FILE_TYPE"); + } + } + public static String convertToHtml(InputStream stream) throws IOException { DocumentConverter converter = new DocumentConverter(); return converter.convertToHtml(stream).getValue(); @@ -16,4 +42,41 @@ public class DocumentUtils { public static InputStream getInputStream(byte[] content) { return new ByteArrayInputStream(content); } + + + public static byte[] convertHtmlToDocx(String contentHtml) throws IOException { + + try(XWPFDocument document = new XWPFDocument()) { + Document parsedHtml = Jsoup.parse(contentHtml); + + Elements children = parsedHtml.body().children(); + + for (Element element : children) { + if (element.tagName().equals("h1")) { + XWPFParagraph heading = document.createParagraph(); + heading.setStyle("Heading1"); + XWPFRun run = heading.createRun(); + run.setText(element.text()); + } else if (element.tagName().equals("p")) { + XWPFParagraph paragraph = document.createParagraph(); + XWPFRun run = paragraph.createRun(); + run.setText(element.text()); + } else if (element.tagName().equals("table")) { + XWPFTable table = document.createTable(); + Elements rows = element.select("tr"); + for (Element row : rows) { + XWPFTableRow tableRow = table.createRow(); + Elements cells = row.select("td"); + for (Element cell : cells) { + tableRow.createCell().setText(cell.text()); + } + } + } + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + document.write(outputStream); + return outputStream.toByteArray(); + } + + } } diff --git a/backend/src/main/java/ut/ee/hades/app/web/controllers/RestExceptionHandler.java b/backend/src/main/java/ut/ee/hades/app/web/controllers/RestExceptionHandler.java index 2ee4ae48f7ab596325e4f07b8769645aba3fc9c9..01000d0a8e482e067f4f47a9b380edfcb340b925 100644 --- a/backend/src/main/java/ut/ee/hades/app/web/controllers/RestExceptionHandler.java +++ b/backend/src/main/java/ut/ee/hades/app/web/controllers/RestExceptionHandler.java @@ -7,7 +7,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; -import ut.ee.hades.app.exceptions.UiAlertException; +import ut.ee.hades.app.exceptions.ui.UiAlertException; import ut.ee.hades.app.web.model.UiAlert; @Slf4j diff --git a/backend/src/main/java/ut/ee/hades/app/web/controllers/secure/DocumentController.java b/backend/src/main/java/ut/ee/hades/app/web/controllers/secure/DocumentController.java index 23bcde496c9521b88bd6681bac58d23599e6919a..da7f9f8821344d7844e7f09c8532eebfaaea6dac 100644 --- a/backend/src/main/java/ut/ee/hades/app/web/controllers/secure/DocumentController.java +++ b/backend/src/main/java/ut/ee/hades/app/web/controllers/secure/DocumentController.java @@ -6,12 +6,11 @@ import org.springframework.core.io.Resource; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import ut.ee.hades.app.web.model.dto.ExerciseDTO; -import ut.ee.hades.app.web.model.dto.ManualDTO; +import ut.ee.hades.app.exceptions.system.HADESFileDownloadException; +import ut.ee.hades.app.exceptions.system.HADESFileSaveException; import ut.ee.hades.app.web.services.DocumentService; import java.io.IOException; -import java.util.List; @RestController @@ -21,44 +20,18 @@ import java.util.List; public class DocumentController { private final DocumentService documentService; - - @GetMapping(value = "/getAllManuals") - public @ResponseBody List<ManualDTO> getManualsList() { - return documentService.getAllManuals(); - } - - @PostMapping(value = "/createManual", consumes = "multipart/form-data") - public @ResponseBody ManualDTO saveManual(@RequestParam("file") MultipartFile multipartFile) throws IOException { - return documentService.createManual(multipartFile); - } - - @DeleteMapping(value = "/deleteManual/{manualId}") - public @ResponseBody void deleteManual(@PathVariable long manualId) throws IOException { - documentService.deleteManualById(manualId); - } - - @GetMapping(value = "/getAllExercises") - public @ResponseBody List<ExerciseDTO> getExercisesList() { - return documentService.getAllExercises(); - } - - @PostMapping(value = "/createExercise", consumes = "multipart/form-data") - public @ResponseBody ExerciseDTO createExercise(@RequestParam("file") MultipartFile multipartFile) throws IOException { - return documentService.createExercise(multipartFile); - } - - @DeleteMapping(value = "/deleteExercise/{exerciseId}") - public @ResponseBody void deleteExercise(@PathVariable long exerciseId) throws IOException { - documentService.deleteExerciseById(exerciseId); - } - @GetMapping(path = "/download/{docId}") - public ResponseEntity<Resource> downloadDocumentById(@PathVariable long docId) { + public ResponseEntity<Resource> downloadDocumentById(@PathVariable long docId) throws HADESFileDownloadException { return documentService.downloadDocumentById(docId); } - @PutMapping(path = "/saveExercise/{fileId}", consumes = "multipart/form-data") - public @ResponseBody void saveExercise(@PathVariable long fileId, @RequestParam("file") MultipartFile multipartFile) throws IOException { - documentService.saveExercise(fileId, multipartFile); + @PostMapping(path = "/getNewDocx") + public @ResponseBody byte[] getNewDocx(@RequestBody String modifiedContent) throws IOException { + return documentService.getNewDocx(modifiedContent); + } + + @PutMapping(path = "/saveEditedFile/{fileId}", consumes = "multipart/form-data") + public @ResponseBody void saveEditedFile(@PathVariable long fileId, @RequestParam("file") MultipartFile multipartFile) throws IOException, HADESFileSaveException { + documentService.saveEditedFile(fileId, multipartFile); } } diff --git a/backend/src/main/java/ut/ee/hades/app/web/controllers/secure/ExerciseController.java b/backend/src/main/java/ut/ee/hades/app/web/controllers/secure/ExerciseController.java new file mode 100644 index 0000000000000000000000000000000000000000..7a714abd2e386179c72b7140da7906a2eee98add --- /dev/null +++ b/backend/src/main/java/ut/ee/hades/app/web/controllers/secure/ExerciseController.java @@ -0,0 +1,38 @@ +package ut.ee.hades.app.web.controllers.secure; + + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import ut.ee.hades.app.web.model.dto.ExerciseDTO; +import ut.ee.hades.app.web.services.ExerciseService; + +import java.io.IOException; +import java.util.List; + +@RestController +@RequestMapping("api/exercise") +@RequiredArgsConstructor +@Slf4j +public class ExerciseController { + + private final ExerciseService exerciseService; + + + @GetMapping(value = "/getAllExercises") + public @ResponseBody List<ExerciseDTO> getExercisesList() { + return exerciseService.getAllExercises(); + } + + @PostMapping(value = "/createExercise", consumes = "multipart/form-data") + public @ResponseBody ExerciseDTO createExercise(@RequestParam("file") MultipartFile multipartFile) throws IOException { + return exerciseService.createExercise(multipartFile); + } + + @DeleteMapping(value = "/deleteExercise/{exerciseId}") + public @ResponseBody void deleteExercise(@PathVariable long exerciseId) throws IOException { + exerciseService.deleteExerciseById(exerciseId); + } + +} diff --git a/backend/src/main/java/ut/ee/hades/app/web/controllers/secure/LabelController.java b/backend/src/main/java/ut/ee/hades/app/web/controllers/secure/LabelController.java index 1299da86837e67f36a99a0de24a19076e842f9c6..119d2385a1b2c1a4ec0f2100896e22ae327b8bef 100644 --- a/backend/src/main/java/ut/ee/hades/app/web/controllers/secure/LabelController.java +++ b/backend/src/main/java/ut/ee/hades/app/web/controllers/secure/LabelController.java @@ -1,39 +1,26 @@ package ut.ee.hades.app.web.controllers.secure; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import ut.ee.hades.app.enums.ExceptionCodeEnum; -import ut.ee.hades.app.exceptions.UiAlertWarningException; import ut.ee.hades.app.web.model.dto.LabelDTO; import ut.ee.hades.app.web.services.LabelService; import java.util.List; -import static ut.ee.hades.app.enums.ExceptionCodeEnum.*; - @RestController @RequestMapping("api") public class LabelController { - private static final Logger log = LoggerFactory.getLogger(LabelController.class); - private final LabelService labelService; public LabelController(LabelService labelService) { this.labelService = labelService; } - @RequestMapping(value = "/getAllLabels", method = RequestMethod.GET) + @GetMapping(value = "/getAllLabels") public @ResponseBody List<LabelDTO> getAllLabels() { - try { - return labelService.getAllLabels(); - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new UiAlertWarningException("TEST_ERROR"); - } + return labelService.getAllLabels(); } } diff --git a/backend/src/main/java/ut/ee/hades/app/web/controllers/secure/ManualController.java b/backend/src/main/java/ut/ee/hades/app/web/controllers/secure/ManualController.java new file mode 100644 index 0000000000000000000000000000000000000000..e7365e95e99d9c921de1ae2817d75290fd22cfde --- /dev/null +++ b/backend/src/main/java/ut/ee/hades/app/web/controllers/secure/ManualController.java @@ -0,0 +1,41 @@ +package ut.ee.hades.app.web.controllers.secure; + + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import ut.ee.hades.app.web.model.dto.ManualDTO; +import ut.ee.hades.app.web.services.ManualService; + +import java.io.IOException; +import java.util.List; + +@RestController +@RequestMapping("api/manual") +@RequiredArgsConstructor +@Slf4j +public class ManualController { + + private final ManualService manualService; + + + + @GetMapping(value = "/getAllManuals") + public @ResponseBody List<ManualDTO> getManualsList() { + return manualService.getAllManuals(); + } + + + @PostMapping(value = "/createManual", consumes = "multipart/form-data") + public @ResponseBody ManualDTO saveManual(@RequestParam("file") MultipartFile multipartFile) throws IOException { + return manualService.createManual(multipartFile); + } + + @DeleteMapping(value = "/deleteManual/{manualId}") + public @ResponseBody void deleteManual(@PathVariable long manualId) throws IOException { + manualService.deleteManualById(manualId); + } + + +} diff --git a/backend/src/main/java/ut/ee/hades/app/web/model/dto/ManualDTO.java b/backend/src/main/java/ut/ee/hades/app/web/model/dto/ManualDTO.java index 5eb81bed45520e2dbfb56a52892b88b4b750d8c2..7c2edd29262cc74c0b80549eb17c4fd778db2583 100644 --- a/backend/src/main/java/ut/ee/hades/app/web/model/dto/ManualDTO.java +++ b/backend/src/main/java/ut/ee/hades/app/web/model/dto/ManualDTO.java @@ -5,10 +5,14 @@ import lombok.Data; import lombok.NoArgsConstructor; import ut.ee.hades.app.dao.entity.ManualEntity; import ut.ee.hades.app.enums.DocumentTypeEnum; +import ut.ee.hades.app.enums.ExceptionCodeEnum; +import ut.ee.hades.app.exceptions.system.HADESConvertException; import ut.ee.hades.app.util.DocumentUtils; import java.io.IOException; import java.io.InputStream; +import java.util.LinkedList; +import java.util.List; @Data @AllArgsConstructor @@ -21,6 +25,22 @@ public class ManualDTO { private final String docType = DocumentTypeEnum.MANUAL.getValue(); + public static List<ManualDTO> mapList (List<ManualEntity> manualEntities) { + List<ManualDTO> manualDTOs = new LinkedList<>(); + + manualEntities.forEach(manual -> { + try { + manualDTOs.add(ManualDTO.map(manual, DocumentUtils.getInputStream(manual.getFile().getContent()))); + } catch (IOException e) { + throw new HADESConvertException(ExceptionCodeEnum.CONTENT_CONVERT_ERROR.getName()); + } + }); + + return manualDTOs; + } + + + public static ManualDTO map(ManualEntity manualDoc, InputStream stream) throws IOException { ManualDTO manualDTO = new ManualDTO(); manualDTO.setManualId(manualDoc.getId()); diff --git a/backend/src/main/java/ut/ee/hades/app/web/services/DocumentService.java b/backend/src/main/java/ut/ee/hades/app/web/services/DocumentService.java index e59f00c737d3f68af4f028c585fb55f238c875dd..4da3ef17b20bb449be74384fbe9927fd17e2c3e1 100644 --- a/backend/src/main/java/ut/ee/hades/app/web/services/DocumentService.java +++ b/backend/src/main/java/ut/ee/hades/app/web/services/DocumentService.java @@ -3,26 +3,17 @@ package ut.ee.hades.app.web.services; import org.springframework.core.io.Resource; import org.springframework.http.ResponseEntity; import org.springframework.web.multipart.MultipartFile; -import ut.ee.hades.app.web.model.dto.ExerciseDTO; -import ut.ee.hades.app.web.model.dto.ManualDTO; +import ut.ee.hades.app.exceptions.system.HADESFileDownloadException; +import ut.ee.hades.app.exceptions.system.HADESFileSaveException; import java.io.IOException; -import java.util.List; public interface DocumentService { - List<ManualDTO> getAllManuals(); - ManualDTO createManual(MultipartFile uploadedFile) throws IOException; + void saveEditedFile(Long fileId, MultipartFile modifiedFile) throws IOException, HADESFileSaveException; - void deleteManualById(Long manualId) throws IOException; + ResponseEntity<Resource> downloadDocumentById(Long docId) throws HADESFileDownloadException; - List<ExerciseDTO> getAllExercises(); + byte[] getNewDocx(String modifiedContent) throws IOException; - void saveExercise(Long fileId, MultipartFile modifiedFile) throws IOException; - - ExerciseDTO createExercise(MultipartFile uploadedFile) throws IOException; - - void deleteExerciseById(Long exerciseId) throws IOException; - - ResponseEntity<Resource> downloadDocumentById(Long docId); } diff --git a/backend/src/main/java/ut/ee/hades/app/web/services/ExerciseService.java b/backend/src/main/java/ut/ee/hades/app/web/services/ExerciseService.java new file mode 100644 index 0000000000000000000000000000000000000000..b956a9cbe99a118dac17a7213e45e4e197de6e1a --- /dev/null +++ b/backend/src/main/java/ut/ee/hades/app/web/services/ExerciseService.java @@ -0,0 +1,17 @@ +package ut.ee.hades.app.web.services; + +import org.springframework.web.multipart.MultipartFile; +import ut.ee.hades.app.web.model.dto.ExerciseDTO; + +import java.io.IOException; +import java.util.List; + +public interface ExerciseService { + + List<ExerciseDTO> getAllExercises(); + + ExerciseDTO createExercise(MultipartFile uploadedFile) throws IOException; + + void deleteExerciseById(Long exerciseId) throws IOException; + +} diff --git a/backend/src/main/java/ut/ee/hades/app/web/services/ManualService.java b/backend/src/main/java/ut/ee/hades/app/web/services/ManualService.java new file mode 100644 index 0000000000000000000000000000000000000000..96957a7d78d20eabb4efb5e35bd524d7a6315835 --- /dev/null +++ b/backend/src/main/java/ut/ee/hades/app/web/services/ManualService.java @@ -0,0 +1,16 @@ +package ut.ee.hades.app.web.services; + +import org.springframework.web.multipart.MultipartFile; +import ut.ee.hades.app.web.model.dto.ManualDTO; + +import java.io.IOException; +import java.util.List; + +public interface ManualService { + + List<ManualDTO> getAllManuals(); + + ManualDTO createManual(MultipartFile uploadedFile) throws IOException; + + void deleteManualById(Long manualId) throws IOException; +} diff --git a/backend/src/main/java/ut/ee/hades/app/web/services/impl/DocumentServiceImpl.java b/backend/src/main/java/ut/ee/hades/app/web/services/impl/DocumentServiceImpl.java index e3d69ef310c5639c83d1965cfa1fe27bfe314958..e032405fbc8a2cc6b4a63496cfc0c6baa7b4541e 100644 --- a/backend/src/main/java/ut/ee/hades/app/web/services/impl/DocumentServiceImpl.java +++ b/backend/src/main/java/ut/ee/hades/app/web/services/impl/DocumentServiceImpl.java @@ -8,24 +8,17 @@ import org.springframework.core.io.Resource; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; -import ut.ee.hades.app.dao.entity.ExerciseEntity; import ut.ee.hades.app.dao.entity.FileEntity; -import ut.ee.hades.app.dao.entity.ManualEntity; -import ut.ee.hades.app.dao.repository.DocumentRepository; -import ut.ee.hades.app.dao.repository.ExerciseRepository; -import ut.ee.hades.app.dao.repository.LabelRepository; -import ut.ee.hades.app.dao.repository.ManualRepository; -import ut.ee.hades.app.exceptions.UiAlertWarningException; -import ut.ee.hades.app.util.AllowedMimeUtils; +import ut.ee.hades.app.dao.repository.FileRepository; +import ut.ee.hades.app.enums.ExceptionCodeEnum; +import ut.ee.hades.app.exceptions.system.HADESFileDownloadException; +import ut.ee.hades.app.exceptions.system.HADESFileSaveException; import ut.ee.hades.app.util.DocumentUtils; -import ut.ee.hades.app.web.model.dto.ExerciseDTO; -import ut.ee.hades.app.web.model.dto.ManualDTO; import ut.ee.hades.app.web.services.DocumentService; import ut.ee.hades.app.web.services.DownloadService; import java.io.IOException; -import java.util.LinkedList; -import java.util.List; +import java.util.Optional; @Service @Transactional @@ -33,110 +26,41 @@ import java.util.List; @Slf4j public class DocumentServiceImpl implements DocumentService { - private final LabelRepository labelRepository; - private final DocumentRepository documentRepository; - private final ManualRepository manualRepository; - private final ExerciseRepository exerciseRepository; + private final FileRepository fileRepository; private final DownloadService downloadService; @Override - public List<ManualDTO> getAllManuals() { - List<ManualDTO> manualDTOList = new LinkedList<>(); - List<ManualEntity> manualEntityList = manualRepository.findAll(); - - - manualEntityList.forEach(manual -> { - try { - manualDTOList.add(ManualDTO.map(manual, DocumentUtils.getInputStream(manual.getFile().getContent()))); - } catch (IOException e) { - throw new UiAlertWarningException("ExceptionCodeEnum.TEST_ERROR"); - } - }); - return manualDTOList; - } - - @Override - public ManualDTO createManual(MultipartFile uploadedFile) throws IOException { - validateFileType(uploadedFile); - - ManualEntity manualEntity = new ManualEntity(); - FileEntity fileEntity = prepareFileSave(uploadedFile); - manualEntity.setFile(fileEntity); - - documentRepository.save(fileEntity); - manualRepository.save(manualEntity); - log.info("File {} created", fileEntity); - log.info("Manual {} created", manualEntity); - - return ManualDTO.map(manualEntity, uploadedFile.getInputStream()); - } - - @Override - public void deleteManualById(Long manualId) { - manualRepository.deleteById(manualId); //TODO Delete file aswell + public void saveEditedFile(Long fileId, MultipartFile modifiedFile) throws IOException, HADESFileSaveException { + Optional<FileEntity> fileById = fileRepository.findById(fileId); + if (fileById.isPresent()) { + FileEntity fileEntity = fileById.get(); + fileEntity.setContent(modifiedFile.getBytes()); + fileEntity.setSize(modifiedFile.getSize()); + fileRepository.save(fileEntity); + } else { + throw new HADESFileSaveException(ExceptionCodeEnum.FILE_SAVE_ERROR.getName()); + } } - @Override - public List<ExerciseDTO> getAllExercises() { - List<ExerciseEntity> exerciseEntities = exerciseRepository.findAll(); - return ExerciseDTO.mapList(exerciseEntities); - } @Override - public void saveExercise(Long fileId, MultipartFile modifiedFile) throws IOException { - FileEntity byId = documentRepository.getById(fileId); - - - byId.setContent(modifiedFile.getBytes()); - byId.setSize(modifiedFile.getSize()); - documentRepository.save(byId); - } - - @Override - public ExerciseDTO createExercise(MultipartFile uploadedFile) throws IOException { - validateFileType(uploadedFile); - - ExerciseEntity exerciseEntity = new ExerciseEntity(); - FileEntity fileEntity = prepareFileSave(uploadedFile); - exerciseEntity.setFile(fileEntity); - - documentRepository.save(fileEntity); - exerciseRepository.save(exerciseEntity); - log.info("File {} created", fileEntity); - log.info("Exercise {} created", exerciseEntity); - - return ExerciseDTO.map(exerciseEntity, uploadedFile.getInputStream()); + public ResponseEntity<Resource> downloadDocumentById(Long docId) throws HADESFileDownloadException { + Optional<FileEntity> fileById = fileRepository.findById(docId); + if (fileById.isPresent()) { + FileEntity fileEntity = fileById.get(); + ByteArrayResource resource = new ByteArrayResource(fileEntity.getContent()); + return downloadService.downloadDoc(resource, fileEntity); + } else { + throw new HADESFileDownloadException(ExceptionCodeEnum.FILE_DOWNLOAD_ERROR.getName()); + } } - @Override - public void deleteExerciseById(Long exerciseId) { - exerciseRepository.deleteById(exerciseId); + public byte[] getNewDocx(String content) throws IOException { + return DocumentUtils.convertHtmlToDocx(content); } - @Override - public ResponseEntity<Resource> downloadDocumentById(Long docId) { - FileEntity document = documentRepository.getById(docId); - ByteArrayResource resource = new ByteArrayResource(document.getContent()); - return downloadService.downloadDoc(resource, document); - } - private FileEntity prepareFileSave(MultipartFile file) throws IOException { - FileEntity fileEntity = new FileEntity(); - fileEntity.setContent(file.getBytes()); - fileEntity.setSize(file.getSize()); - fileEntity.setMimeType(file.getContentType()); - fileEntity.setName(file.getOriginalFilename()); - - return fileEntity; - } - - private void validateFileType(MultipartFile file) { - if (AllowedMimeUtils.mimeMap.get(file.getContentType()) == null) { - log.error("Not allowed file {} type save", file); - throw new UiAlertWarningException("ExceptionCodeEnum.NOT_ALLOWED_FILE_TYPE"); - } - } } diff --git a/backend/src/main/java/ut/ee/hades/app/web/services/impl/ExerciseServiceImpl.java b/backend/src/main/java/ut/ee/hades/app/web/services/impl/ExerciseServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..7d238a9757ce3d3206650ed75508bc3f4d34613e --- /dev/null +++ b/backend/src/main/java/ut/ee/hades/app/web/services/impl/ExerciseServiceImpl.java @@ -0,0 +1,62 @@ +package ut.ee.hades.app.web.services.impl; + +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import ut.ee.hades.app.dao.entity.ExerciseEntity; +import ut.ee.hades.app.dao.entity.FileEntity; +import ut.ee.hades.app.dao.repository.FileRepository; +import ut.ee.hades.app.dao.repository.ExerciseRepository; +import ut.ee.hades.app.dao.repository.LabelRepository; +import ut.ee.hades.app.util.DocumentUtils; +import ut.ee.hades.app.web.model.dto.ExerciseDTO; +import ut.ee.hades.app.web.services.ExerciseService; + +import java.io.IOException; +import java.util.List; + + +@Service +@Transactional +@RequiredArgsConstructor +@Slf4j +public class ExerciseServiceImpl implements ExerciseService { + + private final FileRepository fileRepository; + + private final LabelRepository labelRepository; + + private final ExerciseRepository exerciseRepository; + + + @Override + public List<ExerciseDTO> getAllExercises() { + List<ExerciseEntity> exerciseEntities = exerciseRepository.findAll(); + return ExerciseDTO.mapList(exerciseEntities); + } + + @Override + public ExerciseDTO createExercise(MultipartFile uploadedFile) throws IOException { + DocumentUtils.validateFileType(uploadedFile); + + ExerciseEntity exerciseEntity = new ExerciseEntity(); + FileEntity fileEntity = DocumentUtils.prepareFileSave(uploadedFile); + exerciseEntity.setFile(fileEntity); + + fileRepository.save(fileEntity); + exerciseRepository.save(exerciseEntity); + log.info("File {} created", fileEntity); + log.info("Exercise {} created", exerciseEntity); + + return ExerciseDTO.map(exerciseEntity, uploadedFile.getInputStream()); + } + + @Override + public void deleteExerciseById(Long exerciseId) { + exerciseRepository.deleteById(exerciseId); + } + + +} diff --git a/backend/src/main/java/ut/ee/hades/app/web/services/impl/ManualServiceImpl.java b/backend/src/main/java/ut/ee/hades/app/web/services/impl/ManualServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..63034cbe2993a3d23aa21ecee654e7849ebf84d9 --- /dev/null +++ b/backend/src/main/java/ut/ee/hades/app/web/services/impl/ManualServiceImpl.java @@ -0,0 +1,61 @@ +package ut.ee.hades.app.web.services.impl; + + +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import ut.ee.hades.app.dao.entity.FileEntity; +import ut.ee.hades.app.dao.entity.ManualEntity; +import ut.ee.hades.app.dao.repository.FileRepository; +import ut.ee.hades.app.dao.repository.ManualRepository; +import ut.ee.hades.app.util.DocumentUtils; +import ut.ee.hades.app.web.model.dto.ManualDTO; +import ut.ee.hades.app.web.services.ManualService; + +import java.io.IOException; +import java.util.List; + +@Service +@Transactional +@RequiredArgsConstructor +@Slf4j +public class ManualServiceImpl implements ManualService { + + private final FileRepository fileRepository; + private final ManualRepository manualRepository; + + + + @Override + public List<ManualDTO> getAllManuals() { + List<ManualEntity> manualEntityList = manualRepository.findAll(); + return ManualDTO.mapList(manualEntityList); + } + + + @Override + public ManualDTO createManual(MultipartFile uploadedFile) throws IOException { + DocumentUtils.validateFileType(uploadedFile); + + ManualEntity manualEntity = new ManualEntity(); + FileEntity fileEntity = DocumentUtils.prepareFileSave(uploadedFile); + manualEntity.setFile(fileEntity); + + fileRepository.save(fileEntity); + manualRepository.save(manualEntity); + log.info("File {} created", fileEntity); + log.info("Manual {} created", manualEntity); + + return ManualDTO.map(manualEntity, uploadedFile.getInputStream()); + } + + + @Override + public void deleteManualById(Long manualId) { + manualRepository.deleteById(manualId); + } + + +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index e11ef7c4cefca886e04ac52222d8eed9c51d2c29..e61e69d417dd8b052fae5faba856480c2946a835 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -25,7 +25,6 @@ "@fortawesome/free-solid-svg-icons": "^6.2.1", "@tinymce/tinymce-angular": "^7.0.0", "bootstrap": "^5.2.3", - "docx": "^8.0.1", "jquery": "^3.6.4", "ng-multiselect-dropdown": "^0.3.9", "ngx-bootstrap": "^10.2.0", @@ -5562,7 +5561,8 @@ "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true }, "node_modules/cors": { "version": "2.8.5", @@ -5919,21 +5919,6 @@ "node": ">=6" } }, - "node_modules/docx": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/docx/-/docx-8.0.1.tgz", - "integrity": "sha512-C1gUzdTw7D+0NA5T6JZeV4xM8pqaaKezrNg6PZ5pPmjUh/qV9PWuoV0k5ZdpTpCOaPJIMzBoMx9cHQgLJRPDEA==", - "dependencies": { - "@types/node": "^18.0.0", - "jszip": "^3.1.5", - "nanoid": "^3.3.4", - "xml": "^1.0.1", - "xml-js": "^1.6.8" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/dom-serialize": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", @@ -7313,11 +7298,6 @@ "node": ">=0.10.0" } }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" - }, "node_modules/immutable": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", @@ -7762,7 +7742,8 @@ "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true }, "node_modules/isbinaryfile": { "version": "4.0.10", @@ -8020,44 +8001,6 @@ "node >= 0.2.0" ] }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/karma": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.1.tgz", @@ -8408,14 +8351,6 @@ } } }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dependencies": { - "immediate": "~3.0.5" - } - }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -9179,6 +9114,7 @@ "version": "3.3.4", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -9930,7 +9866,8 @@ "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true }, "node_modules/parent-module": { "version": "1.0.1", @@ -10346,7 +10283,8 @@ "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true }, "node_modules/promise-inflight": { "version": "1.0.1", @@ -11004,7 +10942,9 @@ "node_modules/sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true, + "optional": true }, "node_modules/schema-utils": { "version": "4.0.0", @@ -11240,11 +11180,6 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" - }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -12294,7 +12229,8 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true }, "node_modules/utils-merge": { "version": "1.0.1", @@ -12818,22 +12754,6 @@ } } }, - "node_modules/xml": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", - "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==" - }, - "node_modules/xml-js": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", - "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", - "dependencies": { - "sax": "^1.2.4" - }, - "bin": { - "xml-js": "bin/cli.js" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -17032,7 +16952,8 @@ "core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true }, "cors": { "version": "2.8.5", @@ -17296,18 +17217,6 @@ "@leichtgewicht/ip-codec": "^2.0.1" } }, - "docx": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/docx/-/docx-8.0.1.tgz", - "integrity": "sha512-C1gUzdTw7D+0NA5T6JZeV4xM8pqaaKezrNg6PZ5pPmjUh/qV9PWuoV0k5ZdpTpCOaPJIMzBoMx9cHQgLJRPDEA==", - "requires": { - "@types/node": "^18.0.0", - "jszip": "^3.1.5", - "nanoid": "^3.3.4", - "xml": "^1.0.1", - "xml-js": "^1.6.8" - } - }, "dom-serialize": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", @@ -18369,11 +18278,6 @@ "dev": true, "optional": true }, - "immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" - }, "immutable": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", @@ -18687,7 +18591,8 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true }, "isbinaryfile": { "version": "4.0.10", @@ -18887,46 +18792,6 @@ "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", "dev": true }, - "jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "requires": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, "karma": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.1.tgz", @@ -19192,14 +19057,6 @@ "webpack-sources": "^3.0.0" } }, - "lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "requires": { - "immediate": "~3.0.5" - } - }, "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -19802,7 +19659,8 @@ "nanoid": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true }, "needle": { "version": "3.2.0", @@ -20364,7 +20222,8 @@ "pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true }, "parent-module": { "version": "1.0.1", @@ -20653,7 +20512,8 @@ "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true }, "promise-inflight": { "version": "1.0.1", @@ -21120,7 +20980,9 @@ "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true, + "optional": true }, "schema-utils": { "version": "4.0.0", @@ -21321,11 +21183,6 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" - }, "setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -22110,7 +21967,8 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true }, "utils-merge": { "version": "1.0.1", @@ -22469,19 +22327,6 @@ "dev": true, "requires": {} }, - "xml": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", - "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==" - }, - "xml-js": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", - "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", - "requires": { - "sax": "^1.2.4" - } - }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/frontend/package.json b/frontend/package.json index 3f75cd354226cdbc027901c346f0aa916411fd78..7fb0cff555397391e99b80294ed5fd673df68d76 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -27,7 +27,6 @@ "@fortawesome/free-solid-svg-icons": "^6.2.1", "@tinymce/tinymce-angular": "^7.0.0", "bootstrap": "^5.2.3", - "docx": "^8.0.1", "jquery": "^3.6.4", "ng-multiselect-dropdown": "^0.3.9", "ngx-bootstrap": "^10.2.0", diff --git a/frontend/src/app/classes/BaseDocument.ts b/frontend/src/app/classes/BaseDocument.ts index 395f0c355a5c6988f7a8a2ec1c73adbc20edf425..60444c5cfd03f75dacdcc5b9f0bfbb5d2820c92a 100644 --- a/frontend/src/app/classes/BaseDocument.ts +++ b/frontend/src/app/classes/BaseDocument.ts @@ -1,13 +1,13 @@ import {DocumentType} from "./enums/DocumentType"; export class BaseDocument { - fileId?: number; - contentHtml?: string; - name?: string; - docType?: DocumentType; + fileId: number; + contentHtml: string; + name: string; + docType: DocumentType; - constructor(fileId?: number, contentHtml?: string, name?: string, docType?: DocumentType) { + constructor(fileId: number, contentHtml: string, name: string, docType: DocumentType) { this.fileId = fileId; this.contentHtml = contentHtml; this.name = name; diff --git a/frontend/src/app/classes/enums/MimeType.ts b/frontend/src/app/classes/enums/MimeType.ts new file mode 100644 index 0000000000000000000000000000000000000000..bbdd9ae357689135734c53d791729123b0942937 --- /dev/null +++ b/frontend/src/app/classes/enums/MimeType.ts @@ -0,0 +1,5 @@ + + +export class MimeType { + static readonly DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; +} diff --git a/frontend/src/app/classes/enums/SuccessResponse.ts b/frontend/src/app/classes/enums/SuccessResponse.ts index d3db2f72604c7c50f87d21d483f511bdf11c2b5e..f92640e67e921d1905453d84a05d08c60d6621ca 100644 --- a/frontend/src/app/classes/enums/SuccessResponse.ts +++ b/frontend/src/app/classes/enums/SuccessResponse.ts @@ -1,7 +1,8 @@ export class SuccessResponse { - static readonly MANUAL_DELETE_SUCCESS = "Juhend kustutatud"; - static readonly EXERCISE_DELETE_SUCCESS = "أœlesanne kustutatud"; - static readonly MANUAL_SAVE_SUCCESS = "Juhend salvestatud"; - static readonly EXERCISE_SAVE_SUCCESS = "أœlesanne salvestatud"; - + static readonly MANUAL_DELETE_SUCCESS = "Juhend kustutatud!"; + static readonly EXERCISE_DELETE_SUCCESS = "أœlesanne kustutatud!"; + static readonly MANUAL_SAVE_SUCCESS = "Juhend salvestatud!"; + static readonly EXERCISE_SAVE_SUCCESS = "أœlesanne salvestatud!"; + static readonly EXERCISE_EDIT_SUCCESS = "أœlesande muudatused salvestatud!" + static readonly MANUAL_EDIT_SUCCESS = "Juhendi muudatused salvestatud!" } diff --git a/frontend/src/app/components/doc-editor/doc-editor.component.html b/frontend/src/app/components/doc-editor/doc-editor.component.html index bea729a6a364cab7d7370f00f9bb7a11cb834722..7879fcf8ed7b38ad27dc78a5e5b635e08b427a28 100644 --- a/frontend/src/app/components/doc-editor/doc-editor.component.html +++ b/frontend/src/app/components/doc-editor/doc-editor.component.html @@ -19,7 +19,7 @@ <editor - [(ngModel)]="documentContent" + [(ngModel)]="editorContent" [init]="editorConfig" apiKey="{{getEditorAPIKey()}}" ></editor> diff --git a/frontend/src/app/components/doc-editor/doc-editor.component.ts b/frontend/src/app/components/doc-editor/doc-editor.component.ts index ad780f22fa7f57808b0a4b248cf82164e11e602f..7184166ec7369ddb2298b2bdc9b356ec277c18f6 100644 --- a/frontend/src/app/components/doc-editor/doc-editor.component.ts +++ b/frontend/src/app/components/doc-editor/doc-editor.component.ts @@ -15,8 +15,8 @@ export class DocEditorComponent implements OnInit { @Output() modifiedDocument = new EventEmitter<BaseDocument>(); @Input() - document: BaseDocument = new BaseDocument(); - documentContent: string = ''; + document: BaseDocument = new BaseDocument(-1, "", "", ""); + editorContent: string = ''; readonly editorConfig = { plugins: 'code link image table codesample autoresize', @@ -28,25 +28,12 @@ export class DocEditorComponent implements OnInit { items: 'print' } }, - content_style: 'html, body {' + - ' height: 100%;' + - ' }' + - '' + - ' html {' + - ' display: table;' + - ' margin: auto;' + - ' }' + - '' + - ' body {' + - ' display: table-cell;' + - ' vertical-align: middle;' + - ' }', code_dialog: true, codesample_languages: [ {text: 'Python', value: 'python'}, {text: 'Java', value: 'java'}, ], - autoresize_bottom_margin: 0, + autoresize_bottom_margin: 40, }; constructor(private documentService: DocumentService, @@ -55,11 +42,11 @@ export class DocEditorComponent implements OnInit { ngOnInit() { - this.documentContent = this.document.contentHtml!; + this.editorContent = this.document.contentHtml!; } saveDocument(document: BaseDocument) { - document.contentHtml = this.documentContent; + document.contentHtml = this.editorContent; this.modifiedDocument.emit(document); } diff --git a/frontend/src/app/components/exercises/exercises.component.ts b/frontend/src/app/components/exercises/exercises.component.ts index 411083e0472aae7d42aa5001ce454569b8c9698f..4320a8b0cd30f9d3bbe18cf7ee2d5adc2f595411 100644 --- a/frontend/src/app/components/exercises/exercises.component.ts +++ b/frontend/src/app/components/exercises/exercises.component.ts @@ -6,7 +6,8 @@ import {AlertType} from "../../alert/alert.model"; import {Exercise} from "../../classes/Exercise"; import {SuccessResponse} from "../../classes/enums/SuccessResponse"; import {DocumentToolbarComponent} from "../document-toolbar/document-toolbar.component"; -import {Document, Packer, Paragraph} from "docx"; +import {MimeType} from "../../classes/enums/MimeType"; +import {ExerciseService} from "../../services/exercise.service"; @Component({ selector: 'hades-exercises', @@ -24,6 +25,7 @@ export class ExercisesComponent implements OnInit { constructor( private sharedDataService: SharedDataService, private documentService: DocumentService, + private exerciseService: ExerciseService, private alertBroker: AlertBroker,) { } @@ -42,7 +44,7 @@ export class ExercisesComponent implements OnInit { getAllExercises() { - this.documentService.getAllExercises().subscribe(res => { + this.exerciseService.getAllExercises().subscribe(res => { for (const exercise of res) { this.allExercisesList.push(exercise); } @@ -54,12 +56,12 @@ export class ExercisesComponent implements OnInit { private addUploadedExerciseToList(addedExercise: Exercise) { this.allExercisesList.push(addedExercise); - this.updateDisplayList(true); + this.updateDisplayList(); this.sharedDataService.setUploadedExercise(null); } onDocumentDelete(deletedExercise: Exercise) { - this.documentService.deleteExerciseById(deletedExercise.exerciseId).subscribe(() => { + this.exerciseService.deleteExerciseById(deletedExercise.exerciseId).subscribe(() => { this.alertBroker.add(SuccessResponse.EXERCISE_DELETE_SUCCESS, AlertType.SUCCESS); this.allExercisesList = this.allExercisesList.filter((doc: Exercise) => doc.exerciseId !== deletedExercise.exerciseId); this.updateDisplayList(); @@ -67,34 +69,20 @@ export class ExercisesComponent implements OnInit { } onDocumentSave(modifiedExercise: Exercise) { - let asDocx = this.prepareDocx(modifiedExercise); - Packer.toBlob(asDocx).then(result => { - if (modifiedExercise.name && modifiedExercise.fileId) { - const file = new File([result], modifiedExercise.name, {type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}); + this.documentService.getNewDocx(modifiedExercise.contentHtml).subscribe(res => { + if (res.body) { + let file = new File([res.body], modifiedExercise.name, {type: MimeType.DOCX}); let formData = new FormData(); formData.append("file", file); - this.documentService.saveExercise(modifiedExercise.fileId, formData).subscribe(res => { - console.log("saved") + this.documentService.saveEditedFile(modifiedExercise.fileId, formData).subscribe(() => { + this.alertBroker.add(SuccessResponse.EXERCISE_EDIT_SUCCESS, AlertType.SUCCESS); }) } }); } - private prepareDocx(modifiedDoc: Exercise) { - return new Document({ - sections: [{ - properties: {}, - children: [ - new Paragraph({ - text: modifiedDoc.contentHtml, - }) - ], - }], - }); - } - - private updateDisplayList(emptyFilter?: boolean) { + private updateDisplayList() { this.displayExerciseList = this.allExercisesList; this.sharedDataService.updateDocumentDisplayListForToolbar(this.displayExerciseList); diff --git a/frontend/src/app/components/manuals/manuals.component.ts b/frontend/src/app/components/manuals/manuals.component.ts index db712cec0b7fa479320eb9998e82a280e81d20d6..590f435af69658094378aa812cadc60f775a9995 100644 --- a/frontend/src/app/components/manuals/manuals.component.ts +++ b/frontend/src/app/components/manuals/manuals.component.ts @@ -6,6 +6,8 @@ import {AlertType} from "../../alert/alert.model"; import {AlertBroker} from "../../alert/alert-broker"; import {SuccessResponse} from "../../classes/enums/SuccessResponse"; import {DocumentToolbarComponent} from "../document-toolbar/document-toolbar.component"; +import {ManualService} from "../../services/manual.service"; +import {MimeType} from "../../classes/enums/MimeType"; @Component({ @@ -23,6 +25,7 @@ export class ManualsComponent implements OnInit { constructor( private sharedDataService: SharedDataService, + private manualService: ManualService, private documentService: DocumentService, private alertBroker: AlertBroker) { } @@ -42,7 +45,7 @@ export class ManualsComponent implements OnInit { private getAllManuals() { - this.documentService.getAllManuals().subscribe(res => { + this.manualService.getAllManuals().subscribe(res => { for (const manual of res) { this.allManualsList.push(manual); } @@ -53,12 +56,12 @@ export class ManualsComponent implements OnInit { private addUploadedManualToList(addedManual: Manual) { this.allManualsList.push(addedManual); - this.updateDisplayList(true); + this.updateDisplayList(); this.sharedDataService.setUploadedManual(null); } onDocumentDelete(deletedManual: Manual) { - this.documentService.deleteManualById(deletedManual.manualId).subscribe(() => { + this.manualService.deleteManualById(deletedManual.manualId).subscribe(() => { this.alertBroker.add(SuccessResponse.MANUAL_DELETE_SUCCESS, AlertType.SUCCESS); this.allManualsList = this.allManualsList.filter((doc: Manual) => doc.manualId !== deletedManual.manualId); this.updateDisplayList(); @@ -66,10 +69,19 @@ export class ManualsComponent implements OnInit { } onDocumentSave(modifiedManual: Manual) { - console.log(modifiedManual); + this.documentService.getNewDocx(modifiedManual.contentHtml).subscribe(res => { + if (res.body) { + let file = new File([res.body], modifiedManual.name, {type: MimeType.DOCX}); + let formData = new FormData(); + formData.append("file", file); + this.documentService.saveEditedFile(modifiedManual.fileId, formData).subscribe(() => { + this.alertBroker.add(SuccessResponse.MANUAL_EDIT_SUCCESS, AlertType.SUCCESS); + }) + } + }); } - private updateDisplayList(emptyFilter?: boolean) { + private updateDisplayList() { this.displayManualList = this.allManualsList; this.sharedDataService.updateDocumentDisplayListForToolbar(this.displayManualList); diff --git a/frontend/src/app/modals/file-upload-modal/file-upload-modal.component.ts b/frontend/src/app/modals/file-upload-modal/file-upload-modal.component.ts index 14ae294f8b6fc0dc30b01cd1c142e46234f5752b..5f28b4a4a37f34f128afd26e563a793c5d5f9539 100644 --- a/frontend/src/app/modals/file-upload-modal/file-upload-modal.component.ts +++ b/frontend/src/app/modals/file-upload-modal/file-upload-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, OnInit} from '@angular/core'; +import {Component} from '@angular/core'; import {BsModalRef} from "ngx-bootstrap/modal"; import {DocumentService} from "../../services/document.service"; import {SharedDataService} from "../../services/shared-data.service"; @@ -7,13 +7,15 @@ import {DocumentType} from "../../classes/enums/DocumentType"; import {AlertBroker} from "../../alert/alert-broker"; import {SuccessResponse} from "../../classes/enums/SuccessResponse"; import {AlertType} from "../../alert/alert.model"; +import {ExerciseService} from "../../services/exercise.service"; +import {ManualService} from "../../services/manual.service"; @Component({ selector: 'hades-file-upload-modal', templateUrl: './file-upload-modal.component.html', styleUrls: ['./file-upload-modal.component.scss'] }) -export class FileUploadModalComponent implements OnInit { +export class FileUploadModalComponent { title = 'Faili أ¼leslaadimine'; uploadedFile?: FormData; @@ -56,14 +58,13 @@ export class FileUploadModalComponent implements OnInit { constructor(public bsModalRef: BsModalRef, private documentService: DocumentService, + private exerciseService: ExerciseService, + private manualService: ManualService, private sharedDataService: SharedDataService, private alertBroker: AlertBroker) { } - ngOnInit(): void { - - } initForm(): FormGroup { return new FormGroup({ @@ -101,10 +102,10 @@ export class FileUploadModalComponent implements OnInit { submitFile() { if (this.uploadedFile && this.getSelectedFileType) { if (this.getSelectedFileType() === DocumentType.MANUAL) { - this.documentService.createManual(this.uploadedFile).subscribe(res => this.sharedDataService.setUploadedManual(res)); + this.manualService.createManual(this.uploadedFile).subscribe(res => this.sharedDataService.setUploadedManual(res)); this.alertBroker.add(SuccessResponse.MANUAL_SAVE_SUCCESS, AlertType.SUCCESS); } else if (this.getSelectedFileType() === DocumentType.EXERCISE) { - this.documentService.createExercise(this.uploadedFile).subscribe(res => this.sharedDataService.setUploadedExercise(res)); + this.exerciseService.createExercise(this.uploadedFile).subscribe(res => this.sharedDataService.setUploadedExercise(res)); this.alertBroker.add(SuccessResponse.EXERCISE_SAVE_SUCCESS, AlertType.SUCCESS); } } diff --git a/frontend/src/app/services/document.service.ts b/frontend/src/app/services/document.service.ts index 0338e4c958bedb1c3bcb7054e9d6e77668d7a92a..83c31e34b868b6fffecb7bc07ef7bc33f5f782bf 100644 --- a/frontend/src/app/services/document.service.ts +++ b/frontend/src/app/services/document.service.ts @@ -1,8 +1,6 @@ import {Injectable} from '@angular/core'; import {Observable} from 'rxjs'; -import {Manual} from "../classes/Manual"; -import {HttpClient} from "@angular/common/http"; -import {Exercise} from "../classes/Exercise"; +import {HttpClient, HttpResponse} from "@angular/common/http"; @Injectable({ providedIn: 'root' @@ -12,32 +10,15 @@ export class DocumentService { } - getAllManuals(): Observable<Manual[]> { - return this.http.get<Manual[]>("api/getAllManuals"); + saveEditedFile(fileId: number, file: FormData) { + return this.http.put(`api/saveEditedFile/${fileId}`, file); } - createManual(file: FormData): Observable<Manual> { - return this.http.post<Manual>("api/createManual", file); - } - - deleteManualById(manualId: number) { - return this.http.delete(`api/deleteManual/${manualId}`); - } - - getAllExercises(): Observable<Exercise[]> { - return this.http.get<Exercise[]>("api/getAllExercises"); - } - - saveExercise(fileId: number, file: FormData) { - return this.http.put(`api/saveExercise/${fileId}`, file); - } - - createExercise(file: FormData): Observable<Exercise> { - return this.http.post<Exercise>("api/createExercise", file); - } - - deleteExerciseById(exerciseId: number) { - return this.http.delete(`api/deleteExercise/${exerciseId}`); + getNewDocx(newContent: string): Observable<HttpResponse<Blob>> { + return this.http.post<Blob>(`api/getNewDocx`, newContent, { + observe: 'response', + responseType: 'blob' as 'json' + }) } } diff --git a/frontend/src/app/services/exercise.service.ts b/frontend/src/app/services/exercise.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..55cba97f0e572803229259bf558801bf00a82c68 --- /dev/null +++ b/frontend/src/app/services/exercise.service.ts @@ -0,0 +1,27 @@ +import { Injectable } from '@angular/core'; +import {HttpClient} from "@angular/common/http"; +import {Observable} from "rxjs"; +import {Exercise} from "../classes/Exercise"; + +@Injectable({ + providedIn: 'root' +}) +export class ExerciseService { + + constructor(private http: HttpClient) { + + } + + getAllExercises(): Observable<Exercise[]> { + return this.http.get<Exercise[]>("api/exercise/getAllExercises"); + } + + createExercise(file: FormData): Observable<Exercise> { + return this.http.post<Exercise>("api/exercise/createExercise", file); + } + + deleteExerciseById(exerciseId: number) { + return this.http.delete(`api/exercise/deleteExercise/${exerciseId}`); + } + +} diff --git a/frontend/src/app/services/manual.service.ts b/frontend/src/app/services/manual.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..385a5b5fcc9a16881f6149119899cefbd013fbfe --- /dev/null +++ b/frontend/src/app/services/manual.service.ts @@ -0,0 +1,26 @@ +import { Injectable } from '@angular/core'; +import {HttpClient} from "@angular/common/http"; +import {Observable} from "rxjs"; +import {Manual} from "../classes/Manual"; + +@Injectable({ + providedIn: 'root' +}) +export class ManualService { + + constructor(private http: HttpClient) { } + + + getAllManuals(): Observable<Manual[]> { + return this.http.get<Manual[]>("api/manual/getAllManuals"); + } + + createManual(file: FormData): Observable<Manual> { + return this.http.post<Manual>("api/manual/createManual", file); + } + + deleteManualById(manualId: number) { + return this.http.delete(`api/manual/deleteManual/${manualId}`); + } + +} diff --git a/frontend/src/app/services/tests/exercise.service.spec.ts b/frontend/src/app/services/tests/exercise.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..abd9f14f2b490df4883023d516b6f46bce25b2c3 --- /dev/null +++ b/frontend/src/app/services/tests/exercise.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ExerciseService } from '../exercise.service'; + +describe('ExerciseService', () => { + let service: ExerciseService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ExerciseService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/services/tests/manual.service.spec.ts b/frontend/src/app/services/tests/manual.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..f795ef06562b30ca43bb029cffb499c01a51ccf2 --- /dev/null +++ b/frontend/src/app/services/tests/manual.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ManualService } from '../manual.service'; + +describe('ManualService', () => { + let service: ManualService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ManualService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/frontend/src/core/http-middleware.ts b/frontend/src/core/http-middleware.ts index 85e5320295bd5ae0b542832f3e7fe112ea48ace9..737e23d68da2fbfb592c0c8404cbfa5f8d4d1c6c 100644 --- a/frontend/src/core/http-middleware.ts +++ b/frontend/src/core/http-middleware.ts @@ -14,6 +14,7 @@ export class HttpMiddleware implements HttpInterceptor { intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { return next.handle(req) .pipe(catchError((error) => { + console.log(error) this.alertBroker.add("Oops!", AlertType.DANGER); return throwError(() => error); }))