Some improvements:
* Switches to PostgreSQL * Added Minio storage * Added attachments to properties * Introduced DTOs for improved security
This commit is contained in:
10
README.md
Normal file
10
README.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# SKAMP Base API
|
||||||
|
|
||||||
|
## Environment
|
||||||
|
|
||||||
|
The default profile is `dev`.
|
||||||
|
In production, set it to `prod` via environment variables:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
java ...
|
||||||
|
```
|
||||||
@@ -5,7 +5,7 @@ meta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
post {
|
post {
|
||||||
url: {{KEYCLOAK_BASE_URL}}/realms/propify/protocol/openid-connect/token
|
url: {{KEYCLOAK_BASE_URL}}/realms/{{KEYCLOAK_REALM}}/protocol/openid-connect/token
|
||||||
body: formUrlEncoded
|
body: formUrlEncoded
|
||||||
auth: inherit
|
auth: inherit
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ auth:bearer {
|
|||||||
|
|
||||||
body:json {
|
body:json {
|
||||||
{
|
{
|
||||||
"name": "Mustername 1",
|
"name": "Bungalow",
|
||||||
"street": "Musterstraße",
|
"street": "Hebbelstraße",
|
||||||
"houseNumber": "1",
|
"houseNumber": "30",
|
||||||
"zipCode": "55123",
|
"zipCode": "55127",
|
||||||
"city": "Musterstadt",
|
"city": "Mainz",
|
||||||
"country": "de",
|
"country": "DE",
|
||||||
"notes": "Lorem ipsum"
|
"notes": "Lorem ipsum"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
bruno/propify/Properties/Upload files.bru
Normal file
39
bruno/propify/Properties/Upload files.bru
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
meta {
|
||||||
|
name: Upload files
|
||||||
|
type: http
|
||||||
|
seq: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
url: {{API_BASE_URL}}/api/{{API_VERSION}}/properties/f4eb0c54-7c8f-4e60-b71f-1d08b8b6e2d4/upload
|
||||||
|
body: multipartForm
|
||||||
|
auth: bearer
|
||||||
|
}
|
||||||
|
|
||||||
|
auth:bearer {
|
||||||
|
token: {{BEARER_TOKEN}}
|
||||||
|
}
|
||||||
|
|
||||||
|
body:json {
|
||||||
|
{
|
||||||
|
"name": "Bungalow",
|
||||||
|
"street": "Hebbelstraße",
|
||||||
|
"houseNumber": "30",
|
||||||
|
"zipCode": "55127",
|
||||||
|
"city": "Mainz",
|
||||||
|
"country": "DE",
|
||||||
|
"notes": "Lorem ipsum"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body:multipart-form {
|
||||||
|
attachments: @file(/Users/murat/Pictures/IMG_0229.jpeg|/Users/murat/Pictures/schnürsenkel technik.gif)
|
||||||
|
}
|
||||||
|
|
||||||
|
body:file {
|
||||||
|
file: @file(/Users/murat/Pictures/IMG_0229.jpeg) @contentType(image/jpeg)
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": "1",
|
"version": "1",
|
||||||
"name": "propify",
|
"name": "skamp-api",
|
||||||
"type": "collection",
|
"type": "collection",
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
vars {
|
vars {
|
||||||
API_BASE_URL: http://localhost:8080
|
API_BASE_URL: http://localhost:8080
|
||||||
API_VERSION: v1
|
API_VERSION: v1
|
||||||
BEARER_TOKEN: -
|
|
||||||
KEYCLOAK_BASE_URL: http://localhost:8280
|
KEYCLOAK_BASE_URL: http://localhost:8280
|
||||||
DEV_USERNAME: dev@example.com
|
DEV_USERNAME: dev@example.com
|
||||||
DEV_PASSWORD: dev
|
DEV_PASSWORD: dev
|
||||||
ADMIN_USERNAME: admin@example.com
|
ADMIN_USERNAME: admin@example.com
|
||||||
ADMIN_PASSWORD: admin
|
ADMIN_PASSWORD: admin
|
||||||
KEYCLOAK_CLIENT_ID: propify-app
|
KEYCLOAK_CLIENT_ID: skamp-app
|
||||||
|
KEYCLOAK_REALM: skamp
|
||||||
}
|
}
|
||||||
|
vars:secret [
|
||||||
|
BEARER_TOKEN
|
||||||
|
]
|
||||||
|
|||||||
20
pom.xml
20
pom.xml
@@ -9,10 +9,10 @@
|
|||||||
<relativePath/> <!-- lookup parent from repository -->
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
</parent>
|
</parent>
|
||||||
<groupId>de.iwomm</groupId>
|
<groupId>de.iwomm</groupId>
|
||||||
<artifactId>propify-api</artifactId>
|
<artifactId>skamp-api</artifactId>
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
<name>propify-api</name>
|
<name>skamp-api</name>
|
||||||
<description>Propify API</description>
|
<description>SKAMP API</description>
|
||||||
<url/>
|
<url/>
|
||||||
<licenses>
|
<licenses>
|
||||||
<license/>
|
<license/>
|
||||||
@@ -84,6 +84,20 @@
|
|||||||
<artifactId>spring-boot-starter-security</artifactId>
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<version>42.6.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/software.amazon.awssdk/s3 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>software.amazon.awssdk</groupId>
|
||||||
|
<artifactId>s3</artifactId>
|
||||||
|
<version>2.33.0</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import org.springframework.boot.SpringApplication;
|
|||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class PropifyApiApplication {
|
public class SkampApiApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
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;
|
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.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 de.iwomm.propify_api.service.PropertyService;
|
||||||
|
import jakarta.persistence.EntityNotFoundException;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.web.bind.annotation.*;
|
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.io.IOException;
|
||||||
import java.util.Optional;
|
import java.net.URI;
|
||||||
import java.util.UUID;
|
import java.util.*;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/properties")
|
@RequestMapping("/api/v1/properties")
|
||||||
public class PropertyController {
|
public class PropertyController {
|
||||||
private final PropertyService propertyService;
|
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;
|
this.propertyService = propertyService;
|
||||||
}
|
this.attachmentService = attachmentService;
|
||||||
|
this.s3service = s3Service;
|
||||||
@GetMapping("/info")
|
|
||||||
@PreAuthorize("isAuthenticated()")
|
|
||||||
public String infoEndpoint() {
|
|
||||||
return "Hello, you are authenticated!";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
@PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_USER')")
|
@PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_USER')")
|
||||||
public List<Property> getAllProperties() {
|
public ResponseEntity<?> getAllProperties() {
|
||||||
return propertyService.findAll();
|
List<PropertyDTO> propertiesDTO = propertyService.toDTOs(propertyService.findAll());
|
||||||
|
|
||||||
|
return ResponseEntity
|
||||||
|
.ok(propertiesDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
@GetMapping("/{id}")
|
||||||
@PreAuthorize("hasAnyRole('ADMIN', 'USER')")
|
@PreAuthorize("hasAnyRole('ADMIN', 'USER')")
|
||||||
public Property getPropertyById(@PathVariable UUID id) {
|
public ResponseEntity<?> getPropertyById(@PathVariable UUID id) {
|
||||||
return propertyService.findById(id).orElse(null);
|
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
|
@PostMapping
|
||||||
@ResponseStatus(HttpStatus.CREATED)
|
|
||||||
@PreAuthorize("hasRole('ADMIN')")
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
public Property createProperty(@RequestBody Property property) {
|
public ResponseEntity<?> createProperty(@RequestBody PropertyDTO propertyDTO) {
|
||||||
return propertyService.save(property);
|
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}")
|
@DeleteMapping("/{id}")
|
||||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
|
||||||
@PreAuthorize("hasRole('ADMIN')")
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
public void deleteProperty(@PathVariable UUID id) {
|
public ResponseEntity<?> deleteProperty(@PathVariable UUID id) {
|
||||||
Optional<Property> property = propertyService.findById(id);
|
try {
|
||||||
if (property.isEmpty()) {
|
propertyService.deleteById(id);
|
||||||
return;
|
|
||||||
|
return ResponseEntity
|
||||||
|
.noContent()
|
||||||
|
.build();
|
||||||
|
} catch (EntityNotFoundException e) {
|
||||||
|
return ResponseEntity
|
||||||
|
.notFound()
|
||||||
|
.build();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return ResponseEntity
|
||||||
|
.internalServerError()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
propertyService.delete(property.get());
|
@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;
|
package de.iwomm.propify_api.entity;
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.*;
|
||||||
import jakarta.persistence.GeneratedValue;
|
|
||||||
import jakarta.persistence.Id;
|
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@@ -12,16 +12,83 @@ public class Property {
|
|||||||
@GeneratedValue
|
@GeneratedValue
|
||||||
private UUID id;
|
private UUID id;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
private String street;
|
private String street;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
private String houseNumber;
|
private String houseNumber;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
private String zipCode;
|
private String zipCode;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
private String city;
|
private String city;
|
||||||
private String country;
|
|
||||||
private String notes;
|
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() {}
|
||||||
|
|
||||||
|
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) {
|
public void setId(UUID id) {
|
||||||
this.id = 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;
|
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.context.annotation.Configuration;
|
||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class CorsConfig implements WebMvcConfigurer {
|
public class CorsConfig implements WebMvcConfigurer {
|
||||||
private final CorsProperties corsProperties;
|
private final CorsProperties corsProperties;
|
||||||
@@ -21,7 +16,7 @@ public class CorsConfig implements WebMvcConfigurer {
|
|||||||
public void addCorsMappings(CorsRegistry registry) {
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
registry.addMapping("/**") // Apply rules to all endpoints
|
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"
|
.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())
|
.allowedHeaders(corsProperties.getAllowedHeaders())
|
||||||
.allowCredentials(true); // Allow cookies and authentication headers
|
.allowCredentials(true); // Allow cookies and authentication headers
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,17 +14,17 @@ public class KeycloakRoleConverter implements Converter<Jwt, Collection<GrantedA
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<GrantedAuthority> convert(Jwt jwt) {
|
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");
|
Map<String, Object> realmAccess = (Map<String, Object>) jwt.getClaims().get("realm_access");
|
||||||
|
|
||||||
if (realmAccess == null || realmAccess.isEmpty()) {
|
if (realmAccess == null || realmAccess.isEmpty()) {
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Holen Sie sich die Liste der Rollen
|
// Get list of roles
|
||||||
List<String> roles = (List<String>) realmAccess.get("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()
|
return roles.stream()
|
||||||
.map(roleName -> "ROLE_" + roleName.toUpperCase()) // Empfohlene Namenskonvention
|
.map(roleName -> "ROLE_" + roleName.toUpperCase()) // Empfohlene Namenskonvention
|
||||||
.map(SimpleGrantedAuthority::new)
|
.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.config.http.SessionCreationPolicy;
|
||||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@@ -36,7 +35,7 @@ public class SecurityConfig {
|
|||||||
return http.build();
|
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() {
|
private JwtAuthenticationConverter jwtAuthenticationConverter() {
|
||||||
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
|
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
|
||||||
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(new KeycloakRoleConverter());
|
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;
|
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.entity.Property;
|
||||||
import de.iwomm.propify_api.repository.PropertyRepository;
|
import de.iwomm.propify_api.repository.PropertyRepository;
|
||||||
|
import jakarta.persistence.EntityNotFoundException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -32,7 +38,65 @@ public class PropertyService {
|
|||||||
return propertyRepository.save(property);
|
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);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,60 @@
|
|||||||
spring:
|
spring:
|
||||||
|
|
||||||
|
servlet:
|
||||||
|
multipart:
|
||||||
|
max-file-size: 1000MB # Maximal zulässige Größe pro Datei (z.B. 10 MB)
|
||||||
|
max-request-size: 5000MB # Maximal zulässige Größe der gesamten Anfrage (z.B. 50 MB)
|
||||||
|
profiles:
|
||||||
|
active: dev
|
||||||
application:
|
application:
|
||||||
name: propify-api
|
name: skamp-api
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:h2:mem:demo;DB_CLOSE_DELAY=-1
|
url: jdbc:postgresql://localhost:5432/skamp
|
||||||
driver-class-name: org.h2.Driver
|
username: dev
|
||||||
username: sa
|
password: dev
|
||||||
password:
|
driver-class-name: org.postgresql.Driver
|
||||||
jpa:
|
jpa:
|
||||||
hibernate:
|
hibernate:
|
||||||
ddl-auto: update
|
ddl-auto: update # möglich: validate, update, create, create-drop
|
||||||
show-sql: true
|
show-sql: true
|
||||||
h2:
|
properties:
|
||||||
console:
|
hibernate:
|
||||||
enabled: true
|
format_sql: true
|
||||||
|
database-platform: org.hibernate.dialect.PostgreSQLDialect
|
||||||
|
# datasource:
|
||||||
|
# url: jdbc:h2:mem:demo;DB_CLOSE_DELAY=-1
|
||||||
|
# driver-class-name: org.h2.Driver
|
||||||
|
# username: sa
|
||||||
|
# password:
|
||||||
|
# jpa:
|
||||||
|
# hibernate:
|
||||||
|
# ddl-auto: update
|
||||||
|
# show-sql: true
|
||||||
|
# h2:
|
||||||
|
# console:
|
||||||
|
# enabled: true
|
||||||
|
|
||||||
security:
|
security:
|
||||||
oauth2:
|
oauth2:
|
||||||
resourceserver:
|
resourceserver:
|
||||||
jwt:
|
jwt:
|
||||||
issuer-uri: http://localhost:8280/realms/propify
|
issuer-uri: http://localhost:8280/realms/skamp
|
||||||
jwk-set-uri: ${spring.security.oauth2.resourceserver.jwt.issuer-uri}/protocol/openid-connect/certs
|
jwk-set-uri: ${spring.security.oauth2.resourceserver.jwt.issuer-uri}/protocol/openid-connect/certs
|
||||||
|
|
||||||
logging:
|
logging:
|
||||||
level:
|
level:
|
||||||
org:
|
org:
|
||||||
springframework:
|
springframework:
|
||||||
security: DEBUG
|
security: DEBUG
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cors:
|
cors:
|
||||||
allowed-origins:
|
allowed-origins:
|
||||||
- http://localhost:4200
|
- http://localhost:4200
|
||||||
- http://localhost:8080
|
|
||||||
allowed-headers: "*"
|
allowed-headers: "*"
|
||||||
|
|
||||||
|
s3:
|
||||||
|
access-key: dev
|
||||||
|
secret-key: dev123456
|
||||||
|
endpoint: http://localhost:9000
|
||||||
Reference in New Issue
Block a user