Some improvements:
* Switches to PostgreSQL * Added Minio storage * Added attachments to properties * Introduced DTOs for improved security
This commit is contained in:
@@ -4,10 +4,10 @@ import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class PropifyApiApplication {
|
||||
public class SkampApiApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(PropifyApiApplication.class, args);
|
||||
SpringApplication.run(SkampApiApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.iwomm.propify_api.controller;
|
||||
|
||||
import de.iwomm.propify_api.service.AttachmentService;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/attachments")
|
||||
public class AttachmentController {
|
||||
private final AttachmentService attachmentService;
|
||||
|
||||
public AttachmentController(AttachmentService attachmentService) {
|
||||
this.attachmentService = attachmentService;
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseEntity<?> delete(@PathVariable UUID id) {
|
||||
try {
|
||||
this.attachmentService.deleteById(id);
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity
|
||||
.internalServerError()
|
||||
.build();
|
||||
}
|
||||
return ResponseEntity
|
||||
.noContent()
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -1,58 +1,185 @@
|
||||
package de.iwomm.propify_api.controller;
|
||||
|
||||
import de.iwomm.propify_api.dto.BulkDeletePropertyIdsDTO;
|
||||
import de.iwomm.propify_api.dto.PropertyDTO;
|
||||
import de.iwomm.propify_api.entity.Attachment;
|
||||
import de.iwomm.propify_api.entity.Property;
|
||||
import de.iwomm.propify_api.s3.S3Service;
|
||||
import de.iwomm.propify_api.s3.UploadResponse;
|
||||
import de.iwomm.propify_api.service.AttachmentService;
|
||||
import de.iwomm.propify_api.service.PropertyService;
|
||||
import jakarta.persistence.EntityNotFoundException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/properties")
|
||||
public class PropertyController {
|
||||
private final PropertyService propertyService;
|
||||
private final AttachmentService attachmentService;
|
||||
private final S3Service s3service;
|
||||
|
||||
public PropertyController(PropertyService propertyService) {
|
||||
public PropertyController(PropertyService propertyService, AttachmentService attachmentService, S3Service s3Service) {
|
||||
this.propertyService = propertyService;
|
||||
}
|
||||
|
||||
@GetMapping("/info")
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
public String infoEndpoint() {
|
||||
return "Hello, you are authenticated!";
|
||||
this.attachmentService = attachmentService;
|
||||
this.s3service = s3Service;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_USER')")
|
||||
public List<Property> getAllProperties() {
|
||||
return propertyService.findAll();
|
||||
public ResponseEntity<?> getAllProperties() {
|
||||
List<PropertyDTO> propertiesDTO = propertyService.toDTOs(propertyService.findAll());
|
||||
|
||||
return ResponseEntity
|
||||
.ok(propertiesDTO);
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@PreAuthorize("hasAnyRole('ADMIN', 'USER')")
|
||||
public Property getPropertyById(@PathVariable UUID id) {
|
||||
return propertyService.findById(id).orElse(null);
|
||||
public ResponseEntity<?> getPropertyById(@PathVariable UUID id) {
|
||||
try {
|
||||
return ResponseEntity
|
||||
.ok(propertyService.findById(id).orElseThrow(EntityNotFoundException::new));
|
||||
} catch (EntityNotFoundException e) {
|
||||
return ResponseEntity
|
||||
.notFound()
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity
|
||||
.internalServerError()
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/{id}/upload")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseEntity<?> upload(@RequestParam("attachments") List<MultipartFile> files, @PathVariable UUID id) {
|
||||
List<String> messages = new ArrayList<>();
|
||||
|
||||
if (files.isEmpty()) {
|
||||
return ResponseEntity
|
||||
.ok()
|
||||
.body(new UploadResponse(HttpStatus.BAD_REQUEST, "No attachments provided."));
|
||||
}
|
||||
|
||||
Property property;
|
||||
|
||||
try {
|
||||
property = propertyService.findById(id).orElseThrow(EntityNotFoundException::new);
|
||||
} catch (EntityNotFoundException e) {
|
||||
return ResponseEntity
|
||||
.unprocessableEntity()
|
||||
.build();
|
||||
}
|
||||
|
||||
files.forEach(file -> {
|
||||
String originalFileName = file.getOriginalFilename();
|
||||
String uniqueFileName = id + "/" + UUID.randomUUID() + "_" + originalFileName;
|
||||
try {
|
||||
s3service.putObject("skamp", uniqueFileName, file);
|
||||
|
||||
Attachment newAttachment = new Attachment();
|
||||
newAttachment.setProperty(property);
|
||||
newAttachment.setStoragePath(uniqueFileName);
|
||||
newAttachment.setFileName(originalFileName);
|
||||
this.attachmentService.save(newAttachment);
|
||||
|
||||
property.getAttachments().add(newAttachment);
|
||||
|
||||
messages.add("Successfully uploaded " + originalFileName + " to " + uniqueFileName);
|
||||
} catch (IOException e) {
|
||||
messages.add("Failed uploading " + originalFileName);
|
||||
}
|
||||
});
|
||||
|
||||
propertyService.save(property);
|
||||
|
||||
return ResponseEntity.ok(new UploadResponse(HttpStatus.OK, messages));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public Property createProperty(@RequestBody Property property) {
|
||||
return propertyService.save(property);
|
||||
public ResponseEntity<?> createProperty(@RequestBody PropertyDTO propertyDTO) {
|
||||
try {
|
||||
Property newItem = propertyService.saveDTO(propertyDTO);
|
||||
|
||||
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
|
||||
.path("/{id}")
|
||||
.buildAndExpand(newItem.getId())
|
||||
.toUri();
|
||||
|
||||
return ResponseEntity
|
||||
.created(location)
|
||||
.body(newItem);
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity
|
||||
.internalServerError()
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@PatchMapping("/{id}")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseEntity<?> updateProperty(@PathVariable UUID id, @RequestBody PropertyDTO propertyDTO) {
|
||||
try {
|
||||
return ResponseEntity
|
||||
.ok(propertyService.update(id, propertyDTO));
|
||||
} catch (EntityNotFoundException e) {
|
||||
return ResponseEntity
|
||||
.notFound()
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity
|
||||
.internalServerError()
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public void deleteProperty(@PathVariable UUID id) {
|
||||
Optional<Property> property = propertyService.findById(id);
|
||||
if (property.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
public ResponseEntity<?> deleteProperty(@PathVariable UUID id) {
|
||||
try {
|
||||
propertyService.deleteById(id);
|
||||
|
||||
propertyService.delete(property.get());
|
||||
return ResponseEntity
|
||||
.noContent()
|
||||
.build();
|
||||
} catch (EntityNotFoundException e) {
|
||||
return ResponseEntity
|
||||
.notFound()
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity
|
||||
.internalServerError()
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/bulk-delete")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseEntity<?> deleteProperties(@RequestBody BulkDeletePropertyIdsDTO propertiesDTO) {
|
||||
try {
|
||||
propertyService.deleteByIds(propertiesDTO);
|
||||
|
||||
return ResponseEntity
|
||||
.noContent()
|
||||
.build();
|
||||
} catch (EntityNotFoundException e) {
|
||||
return ResponseEntity
|
||||
.notFound()
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity
|
||||
.internalServerError()
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package de.iwomm.propify_api.database;
|
||||
|
||||
import de.iwomm.propify_api.entity.Property;
|
||||
import de.iwomm.propify_api.repository.PropertyRepository;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Profile("dev") // Runs only in "dev" environments
|
||||
public class DatabaseSeeder implements CommandLineRunner {
|
||||
private final PropertyRepository propertyRepository;
|
||||
|
||||
public DatabaseSeeder(PropertyRepository propertyRepository) {
|
||||
this.propertyRepository = propertyRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
if (propertyRepository.count() == 0) {
|
||||
propertyRepository.save(new Property("Mustergebäude 1", "Musterstraße", "1", "12345", "Musterstadt", "DE", "Musterbemerkung 1"));
|
||||
propertyRepository.save(new Property("Mustergebäude 2", "Dagobertstraße", "2", "22345", "Entenhausen", "AT", "Musterbemerkung 2"));
|
||||
propertyRepository.save(new Property("Mustergebäude 3", "Mustersteet", "3", "32345", "New York", "CH", "Musterbemerkung 3"));
|
||||
System.out.println("Countries seeded.");
|
||||
} else {
|
||||
System.out.println("Countries already seeded.");
|
||||
}
|
||||
}
|
||||
}
|
||||
39
src/main/java/de/iwomm/propify_api/dto/AttachmentDTO.java
Normal file
39
src/main/java/de/iwomm/propify_api/dto/AttachmentDTO.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package de.iwomm.propify_api.dto;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class AttachmentDTO {
|
||||
private UUID id;
|
||||
private String storagePath;
|
||||
private String fileName;
|
||||
|
||||
public AttachmentDTO(UUID id, String storagePath, String fileName) {
|
||||
this.id = id;
|
||||
this.storagePath = storagePath;
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getStoragePath() {
|
||||
return storagePath;
|
||||
}
|
||||
|
||||
public void setStoragePath(String storagePath) {
|
||||
this.storagePath = storagePath;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.iwomm.propify_api.dto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BulkDeletePropertyIdsDTO {
|
||||
List<UUID> ids = new ArrayList<>();
|
||||
|
||||
public List<UUID> getIds() {
|
||||
return ids;
|
||||
}
|
||||
|
||||
public void setIds(List<UUID> ids) {
|
||||
this.ids = ids;
|
||||
}
|
||||
}
|
||||
101
src/main/java/de/iwomm/propify_api/dto/PropertyDTO.java
Normal file
101
src/main/java/de/iwomm/propify_api/dto/PropertyDTO.java
Normal file
@@ -0,0 +1,101 @@
|
||||
package de.iwomm.propify_api.dto;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PropertyDTO {
|
||||
private UUID id;
|
||||
private String name;
|
||||
private String street;
|
||||
private String houseNumber;
|
||||
private String zipCode;
|
||||
private String city;
|
||||
private String country;
|
||||
private String notes;
|
||||
private List<AttachmentDTO> attachments;
|
||||
|
||||
|
||||
public PropertyDTO(UUID id, String name, String street, String houseNumber, String zipCode, String city, String country, String notes, List<AttachmentDTO> attachments) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.street = street;
|
||||
this.houseNumber = houseNumber;
|
||||
this.zipCode = zipCode;
|
||||
this.city = city;
|
||||
this.country = country;
|
||||
this.notes = notes;
|
||||
this.attachments = attachments;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public void setStreet(String street) {
|
||||
this.street = street;
|
||||
}
|
||||
|
||||
public String getHouseNumber() {
|
||||
return houseNumber;
|
||||
}
|
||||
|
||||
public void setHouseNumber(String houseNumber) {
|
||||
this.houseNumber = houseNumber;
|
||||
}
|
||||
|
||||
public String getZipCode() {
|
||||
return zipCode;
|
||||
}
|
||||
|
||||
public void setZipCode(String zipCode) {
|
||||
this.zipCode = zipCode;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String getNotes() {
|
||||
return notes;
|
||||
}
|
||||
|
||||
public void setNotes(String notes) {
|
||||
this.notes = notes;
|
||||
}
|
||||
|
||||
public String getCountry() {
|
||||
return country;
|
||||
}
|
||||
|
||||
public void setCountry(String country) {
|
||||
this.country = country;
|
||||
}
|
||||
|
||||
public List<AttachmentDTO> getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
public void setAttachments(List<AttachmentDTO> attachments) {
|
||||
this.attachments = attachments;
|
||||
}
|
||||
}
|
||||
72
src/main/java/de/iwomm/propify_api/entity/Attachment.java
Normal file
72
src/main/java/de/iwomm/propify_api/entity/Attachment.java
Normal file
@@ -0,0 +1,72 @@
|
||||
package de.iwomm.propify_api.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
public class Attachment {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.UUID)
|
||||
@Column(nullable = false)
|
||||
private UUID id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String storagePath;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String fileName;
|
||||
|
||||
@ManyToOne()
|
||||
@JoinColumn(name = "property_id")
|
||||
private Property property;
|
||||
|
||||
@Column(nullable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
this.createdAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(LocalDateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public void setProperty(Property property) {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
public Property getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public String getStoragePath() {
|
||||
return storagePath;
|
||||
}
|
||||
|
||||
public void setStoragePath(String storagePath) {
|
||||
this.storagePath = storagePath;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package de.iwomm.propify_api.entity;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@@ -12,16 +12,83 @@ public class Property {
|
||||
@GeneratedValue
|
||||
private UUID id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String street;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String houseNumber;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String zipCode;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String city;
|
||||
private String country;
|
||||
|
||||
private String notes;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String country;
|
||||
|
||||
@OneToMany(mappedBy = "property", orphanRemoval = true)
|
||||
@OrderBy("fileName")
|
||||
private List<Attachment> attachments;
|
||||
|
||||
@Column(nullable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
public List<Attachment> getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
public void setAttachments(List<Attachment> attachment) {
|
||||
this.attachments = attachment;
|
||||
}
|
||||
|
||||
|
||||
public Property() {}
|
||||
|
||||
public Property(String name, String street, String houseNumber, String zipCode, String city, String country, String notes) {
|
||||
this.name = name;
|
||||
this.street = street;
|
||||
this.houseNumber = houseNumber;
|
||||
this.zipCode = zipCode;
|
||||
this.city = city;
|
||||
this.country = country;
|
||||
this.notes = notes;
|
||||
}
|
||||
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
this.createdAt = LocalDateTime.now();
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
@PreUpdate
|
||||
protected void onUpdate() {
|
||||
this.updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(LocalDateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) {
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package de.iwomm.propify_api.repository;
|
||||
|
||||
import de.iwomm.propify_api.entity.Attachment;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface AttachmentRepository extends JpaRepository<Attachment, UUID> {
|
||||
}
|
||||
37
src/main/java/de/iwomm/propify_api/s3/S3ClientConfig.java
Normal file
37
src/main/java/de/iwomm/propify_api/s3/S3ClientConfig.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package de.iwomm.propify_api.s3;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "s3")
|
||||
public class S3ClientConfig {
|
||||
|
||||
private String accessKey;
|
||||
private String secretKey;
|
||||
private String endpoint;
|
||||
|
||||
public String getAccessKey() {
|
||||
return accessKey;
|
||||
}
|
||||
|
||||
public void setAccessKey(String accessKey) {
|
||||
this.accessKey = accessKey;
|
||||
}
|
||||
|
||||
public String getSecretKey() {
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
public void setSecretKey(String secretKey) {
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
public String getEndpoint() {
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
public void setEndpoint(String endpoint) {
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
}
|
||||
46
src/main/java/de/iwomm/propify_api/s3/S3Service.java
Normal file
46
src/main/java/de/iwomm/propify_api/s3/S3Service.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package de.iwomm.propify_api.s3;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
|
||||
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
|
||||
import software.amazon.awssdk.core.sync.RequestBody;
|
||||
import software.amazon.awssdk.regions.Region;
|
||||
import software.amazon.awssdk.services.s3.S3Client;
|
||||
import software.amazon.awssdk.services.s3.S3Configuration;
|
||||
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
@Service
|
||||
public class S3Service {
|
||||
|
||||
private final S3Client s3Client;
|
||||
|
||||
public S3Service(S3ClientConfig s3ClientConfig) {
|
||||
AwsBasicCredentials credentials = AwsBasicCredentials.create(s3ClientConfig.getAccessKey(), s3ClientConfig.getSecretKey());
|
||||
|
||||
this.s3Client = S3Client.builder()
|
||||
.endpointOverride(URI.create(s3ClientConfig.getEndpoint()))
|
||||
.credentialsProvider(StaticCredentialsProvider.create(credentials))
|
||||
.region(Region.US_EAST_1)
|
||||
.serviceConfiguration(S3Configuration.builder()
|
||||
.pathStyleAccessEnabled(true)
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
public void putObject(String bucket, String key, MultipartFile file) throws IOException {
|
||||
PutObjectRequest request = PutObjectRequest.builder()
|
||||
.bucket(bucket)
|
||||
.key(key)
|
||||
.contentType(file.getContentType())
|
||||
.build();
|
||||
|
||||
s3Client.putObject(request, RequestBody.fromBytes(file.getBytes()));
|
||||
}
|
||||
}
|
||||
33
src/main/java/de/iwomm/propify_api/s3/UploadResponse.java
Normal file
33
src/main/java/de/iwomm/propify_api/s3/UploadResponse.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package de.iwomm.propify_api.s3;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class UploadResponse {
|
||||
private final HttpStatus status;
|
||||
private List<String> messages;
|
||||
|
||||
public UploadResponse(HttpStatus status, List<String> messages) {
|
||||
this.status = status;
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
public UploadResponse(HttpStatus status, String message) {
|
||||
this.status = status;
|
||||
this.messages = new ArrayList<>();
|
||||
this.messages.add(message);
|
||||
}
|
||||
|
||||
public List<String> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
public void setMessages(List<String> messages) {
|
||||
this.messages = messages;
|
||||
}
|
||||
public void addMessage(String message) {
|
||||
this.messages.add(message);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,9 @@
|
||||
package de.iwomm.propify_api.security;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
public class CorsConfig implements WebMvcConfigurer {
|
||||
private final CorsProperties corsProperties;
|
||||
@@ -21,7 +16,7 @@ public class CorsConfig implements WebMvcConfigurer {
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**") // Apply rules to all endpoints
|
||||
.allowedOrigins(corsProperties.getAllowedOrigins().toArray(new String[0])) // This targets the frontend app's URLs (you can allow multiple URLs, e.g. "http://localhost:4200,http://example.com"
|
||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
.allowedMethods("GET", "POST", "PATCH", "PUT", "DELETE", "OPTIONS")
|
||||
.allowedHeaders(corsProperties.getAllowedHeaders())
|
||||
.allowCredentials(true); // Allow cookies and authentication headers
|
||||
}
|
||||
|
||||
@@ -14,17 +14,17 @@ public class KeycloakRoleConverter implements Converter<Jwt, Collection<GrantedA
|
||||
|
||||
@Override
|
||||
public Collection<GrantedAuthority> convert(Jwt jwt) {
|
||||
// Holen Sie sich das "realm_access" Feld aus dem Token
|
||||
// Get the "realm_access" field from token
|
||||
Map<String, Object> realmAccess = (Map<String, Object>) jwt.getClaims().get("realm_access");
|
||||
|
||||
if (realmAccess == null || realmAccess.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
// Holen Sie sich die Liste der Rollen
|
||||
// Get list of roles
|
||||
List<String> roles = (List<String>) realmAccess.get("roles");
|
||||
|
||||
// Konvertieren Sie die Rollen in Spring Security GrantedAuthority-Objekte
|
||||
// KConvert roles to Spring Security GrantedAuthority-Objects
|
||||
return roles.stream()
|
||||
.map(roleName -> "ROLE_" + roleName.toUpperCase()) // Empfohlene Namenskonvention
|
||||
.map(SimpleGrantedAuthority::new)
|
||||
|
||||
@@ -9,7 +9,6 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@@ -36,7 +35,7 @@ public class SecurityConfig {
|
||||
return http.build();
|
||||
}
|
||||
|
||||
// Konvertiert die Keycloak-Rollen (im JWT) in Spring Security Authorities
|
||||
// Convert Keycloak-Roles (in JWT) in Spring Security Authorities
|
||||
private JwtAuthenticationConverter jwtAuthenticationConverter() {
|
||||
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
|
||||
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(new KeycloakRoleConverter());
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package de.iwomm.propify_api.service;
|
||||
|
||||
import de.iwomm.propify_api.dto.AttachmentDTO;
|
||||
import de.iwomm.propify_api.dto.PropertyDTO;
|
||||
import de.iwomm.propify_api.entity.Attachment;
|
||||
import de.iwomm.propify_api.repository.AttachmentRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
public class AttachmentService {
|
||||
private final AttachmentRepository attachmentRepository;
|
||||
|
||||
public AttachmentService(AttachmentRepository attachmentRepository) {
|
||||
this.attachmentRepository = attachmentRepository;
|
||||
}
|
||||
|
||||
public void save(Attachment attachment) {
|
||||
attachmentRepository.save(attachment);
|
||||
}
|
||||
|
||||
public void delete(Attachment attachment) {
|
||||
attachmentRepository.delete(attachment);
|
||||
}
|
||||
|
||||
public void deleteById(UUID id) {
|
||||
attachmentRepository.deleteById(id);
|
||||
}
|
||||
|
||||
public List<AttachmentDTO> toDTOs(List<Attachment> attachments) {
|
||||
List<AttachmentDTO> dtos = new ArrayList<>();
|
||||
|
||||
attachments.forEach(attachment -> {
|
||||
dtos.add(new AttachmentDTO(
|
||||
attachment.getId(),
|
||||
attachment.getStoragePath(),
|
||||
attachment.getFileName()
|
||||
));
|
||||
});
|
||||
|
||||
return dtos;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,15 @@
|
||||
package de.iwomm.propify_api.service;
|
||||
|
||||
import de.iwomm.propify_api.dto.AttachmentDTO;
|
||||
import de.iwomm.propify_api.dto.BulkDeletePropertyIdsDTO;
|
||||
import de.iwomm.propify_api.dto.PropertyDTO;
|
||||
import de.iwomm.propify_api.entity.Attachment;
|
||||
import de.iwomm.propify_api.entity.Property;
|
||||
import de.iwomm.propify_api.repository.PropertyRepository;
|
||||
import jakarta.persistence.EntityNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
@@ -32,7 +38,65 @@ public class PropertyService {
|
||||
return propertyRepository.save(property);
|
||||
}
|
||||
|
||||
public void delete(Property property) {
|
||||
public void deleteById(UUID id) {
|
||||
Property property = propertyRepository.findById(id).orElseThrow(EntityNotFoundException::new);
|
||||
propertyRepository.delete(property);
|
||||
}
|
||||
|
||||
public void deleteByIds(BulkDeletePropertyIdsDTO propertyIdsDTO) {
|
||||
propertyRepository.deleteAllById(propertyIdsDTO.getIds());
|
||||
}
|
||||
|
||||
public Property update(UUID id, PropertyDTO propertyDto) {
|
||||
Property updated = propertyRepository.findById(id).orElseThrow(EntityNotFoundException::new);
|
||||
|
||||
updated.setName(propertyDto.getName());
|
||||
updated.setStreet(propertyDto.getStreet());
|
||||
updated.setHouseNumber(propertyDto.getHouseNumber());
|
||||
updated.setZipCode(propertyDto.getZipCode());
|
||||
updated.setCity(propertyDto.getCity());
|
||||
updated.setCountry(propertyDto.getCountry());
|
||||
updated.setNotes(propertyDto.getNotes());
|
||||
|
||||
propertyRepository.save(updated);
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
public Property saveDTO(PropertyDTO dto) {
|
||||
return this.save(new Property(
|
||||
dto.getName(),
|
||||
dto.getStreet(),
|
||||
dto.getHouseNumber(),
|
||||
dto.getZipCode(),
|
||||
dto.getCity(),
|
||||
dto.getCountry(),
|
||||
dto.getNotes()
|
||||
));
|
||||
}
|
||||
|
||||
public List<PropertyDTO> toDTOs(List<Property> properties) {
|
||||
List<PropertyDTO> dtos = new ArrayList<>();
|
||||
|
||||
properties.forEach(property -> {
|
||||
List<AttachmentDTO> attachments = new ArrayList<>();
|
||||
property.getAttachments().forEach(attachment -> {
|
||||
attachments.add(new AttachmentDTO(attachment.getId(), attachment.getStoragePath(), attachment.getFileName()));
|
||||
});
|
||||
|
||||
dtos.add(new PropertyDTO(
|
||||
property.getId(),
|
||||
property.getName(),
|
||||
property.getStreet(),
|
||||
property.getHouseNumber(),
|
||||
property.getZipCode(),
|
||||
property.getCity(),
|
||||
property.getCountry(),
|
||||
property.getNotes(),
|
||||
attachments
|
||||
));
|
||||
});
|
||||
|
||||
return dtos;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user