diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/controller/NoticeController.java b/src/main/java/_11/asktpk/artisanconnectbackend/controller/NoticeController.java index 8003b28..d05a339 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/controller/NoticeController.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/controller/NoticeController.java @@ -7,7 +7,11 @@ import jakarta.persistence.EntityNotFoundException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; @@ -44,6 +48,8 @@ public class NoticeController { .body("Nie znaleziono klienta o ID: " + dto.getClientId()); } + dto.setPublishDate(java.time.LocalDateTime.now()); + noticeService.addNotice(dto); return ResponseEntity.status(HttpStatus.CREATED).body("Dodano ogłoszenie."); @@ -66,42 +72,81 @@ public class NoticeController { isError = true; errors.add(dto.getClientId().toString()); } else { - if(!isError){ + if (!isError) { noticeService.addNotice(dto); } } } - if(isError) { + if (isError) { return response.status(HttpStatus.BAD_REQUEST).body("Nie znaleziono klientów: " + errors); } return response; } -@PutMapping("/edit/{id}") -public ResponseEntity editNotice(@PathVariable("id") long id, @RequestBody NoticeDTO dto) { - if (noticeService.noticeExists(id)) { - try { - return new ResponseEntity<>(noticeService.updateNotice(id, dto), HttpStatus.OK); - } catch (EntityNotFoundException e) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage()); + @PutMapping("/edit/{id}") + public ResponseEntity editNotice(@PathVariable("id") long id, @RequestBody NoticeDTO dto) { + if (noticeService.noticeExists(id)) { + try { + return new ResponseEntity<>(noticeService.updateNotice(id, dto), HttpStatus.OK); + } catch (EntityNotFoundException e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage()); + } + } else { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Nie znaleziono ogłoszenia o ID: " + id); } - } else { - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Nie znaleziono ogłoszenia o ID: " + id); } -} -@DeleteMapping("/delete/{id}") -public ResponseEntity deleteNotice(@PathVariable("id") long id) { - if(noticeService.noticeExists(id)) { - noticeService.deleteNotice(id); - return new ResponseEntity<>(HttpStatus.OK); - } else { - return new ResponseEntity<>(HttpStatus.NOT_FOUND); + @DeleteMapping("/delete/{id}") + public ResponseEntity deleteNotice(@PathVariable("id") long id) { + if (noticeService.noticeExists(id)) { + noticeService.deleteNotice(id); + return new ResponseEntity<>(HttpStatus.OK); + } else { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } } -} + @PostMapping("/upload/{id}") + public ResponseEntity uploadImage(@PathVariable("id") Long id, @RequestParam("file") MultipartFile file) { + if (!noticeService.noticeExists(id)) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Nie znaleziono ogłoszenia o ID: " + id); + } + + try { + String filePath = noticeService.saveImage(id, file); + return ResponseEntity.ok("Zdjęcie zapisane pod ścieżką: " + filePath); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Błąd podczas zapisywania zdjęcia: " + e.getMessage()); + } + } + + + @GetMapping("/images/{id}") + public ResponseEntity> getAllImages(@PathVariable("id") Long id) { + try { + Path directoryPath = Paths.get("src/main/resources/static/images/notices/" + id); + if (!Files.exists(directoryPath) || !Files.isDirectory(directoryPath)) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); + } + + List imagePaths = new ArrayList<>(); + Files.list(directoryPath).forEach(file -> { + if (Files.isRegularFile(file) && Files.isReadable(file)) { + imagePaths.add(file.toString()); + } + }); + + if (imagePaths.isEmpty()) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); + } + + return ResponseEntity.ok(imagePaths); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); + } + } // @GetMapping("/check/{id}") // public ResponseEntity checkNotice(@PathVariable("id") long id) { diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/dto/NoticeDTO.java b/src/main/java/_11/asktpk/artisanconnectbackend/dto/NoticeDTO.java index e64eec9..63cb0d3 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/dto/NoticeDTO.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/dto/NoticeDTO.java @@ -5,7 +5,7 @@ import _11.asktpk.artisanconnectbackend.utils.Enums; import lombok.Getter; import lombok.Setter; -import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.List; @Getter @Setter @@ -26,7 +26,7 @@ public class NoticeDTO { private Enums.Status status; - private LocalDate publishDate; + private LocalDateTime publishDate; private List attributesNotices; @@ -36,7 +36,7 @@ public class NoticeDTO { public NoticeDTO(Long noticeId, String title, Long clientId, String description, Double price, Enums.Category category, List images, Enums.Status status, - LocalDate publishDate, List attributesNotices) { + LocalDateTime publishDate, List attributesNotices) { this.noticeId = noticeId; this.title = title; this.clientId = clientId; diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/entities/Notice.java b/src/main/java/_11/asktpk/artisanconnectbackend/entities/Notice.java index 6919f6e..881a5ed 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/entities/Notice.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/entities/Notice.java @@ -2,7 +2,7 @@ package _11.asktpk.artisanconnectbackend.entities; import jakarta.persistence.*; -import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.List; import _11.asktpk.artisanconnectbackend.utils.Enums.*; @@ -36,7 +36,7 @@ public class Notice { @Enumerated(EnumType.STRING) private Status status; - private LocalDate publishDate; + private LocalDateTime publishDate; @OneToMany(mappedBy = "notice", cascade = CascadeType.ALL) private List attributesNotices; diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/service/NoticeService.java b/src/main/java/_11/asktpk/artisanconnectbackend/service/NoticeService.java index d9eccbd..7f2b9ff 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/service/NoticeService.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/service/NoticeService.java @@ -7,7 +7,13 @@ import _11.asktpk.artisanconnectbackend.repository.NoticeRepository; import _11.asktpk.artisanconnectbackend.dto.NoticeDTO; import jakarta.persistence.EntityNotFoundException; import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.List; @@ -106,4 +112,51 @@ public class NoticeService { throw new EntityNotFoundException("Nie znaleziono ogłoszenia o ID: " + id); } } + + public String saveImage(Long noticeId, MultipartFile file) throws IOException { + String uploadDir = "src/main/resources/static/images/notices/" + noticeId; + Path uploadPath = Paths.get(uploadDir); + + if (!Files.exists(uploadPath)) { + Files.createDirectories(uploadPath); + } + + // szukanie nazwy pliku + String fileName = file.getOriginalFilename(); + if (fileName != null) { + String extension = fileName.substring(fileName.lastIndexOf('.')); + String baseName = fileName.substring(0, fileName.lastIndexOf('.')); + + List filesInDirectory = Files.list(uploadPath) + .filter(Files::isRegularFile) + .toList(); + + int maxNumber = filesInDirectory.stream() + .map(path -> path.getFileName().toString()) + .filter(name -> name.startsWith(baseName) && name.endsWith(extension)) + .map(name -> name.substring(baseName.length(), name.length() - extension.length())) + .filter(number -> number.matches("\\d+")) + .mapToInt(Integer::parseInt) + .max() + .orElse(0); + + fileName = baseName + (maxNumber + 1) + extension; + } + //koniec szukania nazwy pliku + + if(fileName == null) { + throw new IOException("Nie można znaleźć nazwy pliku"); + } + Path filePath = uploadPath.resolve(fileName); + Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING); + + Notice notice = noticeRepository.findById(noticeId) + .orElseThrow(() -> new EntityNotFoundException("Nie znaleziono ogłoszenia o ID: " + noticeId)); + List images = notice.getImages(); + images.add(filePath.toString()); + notice.setImages(images); + noticeRepository.save(notice); + + return filePath.toString(); + } } diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/utils/Enums.java b/src/main/java/_11/asktpk/artisanconnectbackend/utils/Enums.java index 78da471..1e1456b 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/utils/Enums.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/utils/Enums.java @@ -6,10 +6,14 @@ public class Enums { } public enum Category { - Electronics, Artwork, Kitchen, Buildings, Home, Fashion // Replace with actual categories + Handmade, Woodworking, Metalworking, Ceramics, + Textiles, Jewelry, Leatherwork, Painting, Sculpture, + Glasswork, Furniture, Restoration, Tailoring, Weaving, + Calligraphy, Pottery, Blacksmithing, Basketry, Embroidery, + Knitting, Carpentry, Other } public enum Status { - ACTIVE, INACTIVE // Replace with actual statuses + ACTIVE, INACTIVE } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 6e262f9..49cae4d 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -10,4 +10,6 @@ spring.sql.init.mode=always spring.jpa.defer-datasource-initialization=true # create and drop table, good for testing, production set to none or comment it -spring.jpa.hibernate.ddl-auto=create-drop \ No newline at end of file +spring.jpa.hibernate.ddl-auto=update + +spring.web.resources.static-locations=classpath:/static/,file:images/ \ No newline at end of file diff --git a/src/main/resources/sql/data.sql b/src/main/resources/sql/data.sql index 2ab1ead..3a9c65e 100644 --- a/src/main/resources/sql/data.sql +++ b/src/main/resources/sql/data.sql @@ -5,3 +5,11 @@ VALUES ('jane.smith@example.com', 'Jane', 'null', 'Smith', 'securepass', 'USER'), ('michael.brown@example.com', 'Michael', 'null', 'Brown', 'mypassword', 'USER'), ('emily.jones@example.com', 'Emily', 'null', 'Jones', 'passw0rd', 'USER'); + + +INSERT INTO notice (title, description, client_id, price, category, status, publish_date) VALUES + ('Ręcznie robiona biżuteria', 'Unikalna biżuteria wykonana ręcznie z najwyższej jakości materiałów.', 5, 150.00, 'Jewelry', 'ACTIVE', '2023-10-01'), + ('Drewniany stół', 'Solidny stół wykonany z litego drewna dębowego.', 3, 1200.00, 'Furniture', 'ACTIVE', '2023-09-15'), + ('Ceramiczna waza', 'Piękna waza ceramiczna, idealna na prezent.', 2, 300.00, 'Ceramics', 'INACTIVE', '2023-08-20'), + ('Obraz olejny', 'Obraz olejny przedstawiający krajobraz górski.', 4, 800.00, 'Painting', 'ACTIVE', '2023-07-10'), + ('Skórzany portfel', 'Ręcznie wykonany portfel ze skóry naturalnej.', 1, 250.00, 'Leatherwork', 'ACTIVE', '2023-06-05'); \ No newline at end of file