feat: Implement Update Project Route (SCRUM-11) (!28)
Co-authored-by: Phan Huy Tran <p.tran@neusta.de> Reviewed-on: #28 Reviewed-by: Jan Gleytenhoover <krisellp9@gmail.com> Co-authored-by: Phan Huy Tran <ptran@noreply.localhost> Co-committed-by: Phan Huy Tran <ptran@noreply.localhost>
This commit is contained in:
		
					parent
					
						
							
								cbb77cc1ca
							
						
					
				
			
			
				commit
				
					
						4eb7626c10
					
				
			
		
					 23 changed files with 1065 additions and 786 deletions
				
			
		
							
								
								
									
										168
									
								
								build.gradle.kts
									
										
									
									
									
								
							
							
						
						
									
										168
									
								
								build.gradle.kts
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,85 +1,85 @@
 | 
			
		|||
plugins {
 | 
			
		||||
    java
 | 
			
		||||
    id("org.springframework.boot") version "3.3.4"
 | 
			
		||||
    id("io.spring.dependency-management") version "1.1.6"
 | 
			
		||||
    id("checkstyle")
 | 
			
		||||
    id("org.sonarqube") version "5.1.0.4882"
 | 
			
		||||
    id("jacoco")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tasks.jacocoTestReport {
 | 
			
		||||
    dependsOn(tasks.test) // Ensure tests are run before generating the report
 | 
			
		||||
    reports {
 | 
			
		||||
        xml.required = true
 | 
			
		||||
        csv.required = true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sonar {
 | 
			
		||||
  properties {
 | 
			
		||||
    property("sonar.projectKey", "LF8")
 | 
			
		||||
    property("sonar.projectName", "LF8")
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tasks.withType<Checkstyle> {
 | 
			
		||||
    reports {
 | 
			
		||||
        // Disable HTML report
 | 
			
		||||
        html.required.set(false)
 | 
			
		||||
 | 
			
		||||
        // Disable XML report
 | 
			
		||||
        xml.required.set(false)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
group = "de.szut"
 | 
			
		||||
version = "0.0.1-SNAPSHOT"
 | 
			
		||||
 | 
			
		||||
tasks.test {
 | 
			
		||||
    useJUnitPlatform()
 | 
			
		||||
 | 
			
		||||
    // Activate the 'test' profile for Spring during tests
 | 
			
		||||
    systemProperty("spring.profiles.active", "test")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
java {
 | 
			
		||||
    toolchain {
 | 
			
		||||
        languageVersion = JavaLanguageVersion.of(21)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
configurations {
 | 
			
		||||
    compileOnly {
 | 
			
		||||
        extendsFrom(configurations.annotationProcessor.get())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
repositories {
 | 
			
		||||
    mavenCentral()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
val springDocVersion = "2.6.0"
 | 
			
		||||
val oauth2Version = "3.3.4"
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
 | 
			
		||||
    implementation("org.springframework.boot:spring-boot-starter-web")
 | 
			
		||||
    implementation("org.springframework.boot:spring-boot-starter-validation")
 | 
			
		||||
    implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:$springDocVersion")
 | 
			
		||||
    implementation("org.springframework.boot:spring-boot-starter-security")
 | 
			
		||||
    implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server:$oauth2Version")
 | 
			
		||||
    implementation("org.springframework.boot:spring-boot-starter-oauth2-client:$oauth2Version")
 | 
			
		||||
 | 
			
		||||
    testImplementation("com.h2database:h2")
 | 
			
		||||
    testImplementation("org.springframework.boot:spring-boot-starter-test")
 | 
			
		||||
 | 
			
		||||
    compileOnly("org.projectlombok:lombok")
 | 
			
		||||
    annotationProcessor("org.projectlombok:lombok")
 | 
			
		||||
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
 | 
			
		||||
    runtimeOnly("org.postgresql:postgresql")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tasks.withType<Test> {
 | 
			
		||||
    useJUnitPlatform()
 | 
			
		||||
    finalizedBy(tasks.jacocoTestReport) // Run JaCoCo report after tests
 | 
			
		||||
plugins {
 | 
			
		||||
    java
 | 
			
		||||
    id("org.springframework.boot") version "3.3.4"
 | 
			
		||||
    id("io.spring.dependency-management") version "1.1.6"
 | 
			
		||||
    id("checkstyle")
 | 
			
		||||
    id("org.sonarqube") version "5.1.0.4882"
 | 
			
		||||
    id("jacoco")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tasks.jacocoTestReport {
 | 
			
		||||
    dependsOn(tasks.test) // Ensure tests are run before generating the report
 | 
			
		||||
    reports {
 | 
			
		||||
        xml.required = true
 | 
			
		||||
        csv.required = true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sonar {
 | 
			
		||||
  properties {
 | 
			
		||||
    property("sonar.projectKey", "LF8")
 | 
			
		||||
    property("sonar.projectName", "LF8")
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tasks.withType<Checkstyle> {
 | 
			
		||||
    reports {
 | 
			
		||||
        // Disable HTML report
 | 
			
		||||
        html.required.set(false)
 | 
			
		||||
 | 
			
		||||
        // Disable XML report
 | 
			
		||||
        xml.required.set(false)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
group = "de.szut"
 | 
			
		||||
version = "0.0.1-SNAPSHOT"
 | 
			
		||||
 | 
			
		||||
tasks.test {
 | 
			
		||||
    useJUnitPlatform()
 | 
			
		||||
 | 
			
		||||
    // Activate the 'test' profile for Spring during tests
 | 
			
		||||
    systemProperty("spring.profiles.active", "test")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
java {
 | 
			
		||||
    toolchain {
 | 
			
		||||
        languageVersion = JavaLanguageVersion.of(21)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
configurations {
 | 
			
		||||
    compileOnly {
 | 
			
		||||
        extendsFrom(configurations.annotationProcessor.get())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
repositories {
 | 
			
		||||
    mavenCentral()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
val springDocVersion = "2.6.0"
 | 
			
		||||
val oauth2Version = "3.3.4"
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
 | 
			
		||||
    implementation("org.springframework.boot:spring-boot-starter-web")
 | 
			
		||||
    implementation("org.springframework.boot:spring-boot-starter-validation")
 | 
			
		||||
    implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:$springDocVersion")
 | 
			
		||||
    implementation("org.springframework.boot:spring-boot-starter-security")
 | 
			
		||||
    implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server:$oauth2Version")
 | 
			
		||||
    implementation("org.springframework.boot:spring-boot-starter-oauth2-client:$oauth2Version")
 | 
			
		||||
 | 
			
		||||
    testImplementation("com.h2database:h2")
 | 
			
		||||
    testImplementation("org.springframework.boot:spring-boot-starter-test")
 | 
			
		||||
 | 
			
		||||
    compileOnly("org.projectlombok:lombok")
 | 
			
		||||
    annotationProcessor("org.projectlombok:lombok")
 | 
			
		||||
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
 | 
			
		||||
    runtimeOnly("org.postgresql:postgresql")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tasks.withType<Test> {
 | 
			
		||||
    useJUnitPlatform()
 | 
			
		||||
    finalizedBy(tasks.jacocoTestReport) // Run JaCoCo report after tests
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,3 +1,3 @@
 | 
			
		|||
### GET request to example server
 | 
			
		||||
GET http://localhost:8080/projects/2
 | 
			
		||||
Authorization: Bearer {{auth_token}}
 | 
			
		||||
### GET request to example server
 | 
			
		||||
GET http://localhost:8080/projects/1
 | 
			
		||||
Authorization: Bearer {{auth_token}}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										15
									
								
								requests/updateProject.http
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								requests/updateProject.http
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
### GET request to example server
 | 
			
		||||
PUT http://localhost:8080/projects/1
 | 
			
		||||
Authorization: Bearer {{auth_token}}
 | 
			
		||||
Content-Type: application/json
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
  "name": "newName",
 | 
			
		||||
  "leading_employee": 2,
 | 
			
		||||
  "employees": [],
 | 
			
		||||
  "contractor": 9,
 | 
			
		||||
  "contractor_name": "New Contractor name",
 | 
			
		||||
  "comment": "new goal of project",
 | 
			
		||||
  "start_date": "01.01.2010",
 | 
			
		||||
  "planned_end_date": "01.01.2021"
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,77 +1,77 @@
 | 
			
		|||
package de.szut.lf8_starter.config;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import io.swagger.v3.oas.models.Components;
 | 
			
		||||
import io.swagger.v3.oas.models.OpenAPI;
 | 
			
		||||
import io.swagger.v3.oas.models.info.Info;
 | 
			
		||||
import io.swagger.v3.oas.models.security.SecurityRequirement;
 | 
			
		||||
import io.swagger.v3.oas.models.security.SecurityScheme;
 | 
			
		||||
import io.swagger.v3.oas.models.servers.Server;
 | 
			
		||||
import jakarta.servlet.ServletContext;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@Configuration
 | 
			
		||||
public class OpenAPIConfiguration {
 | 
			
		||||
 | 
			
		||||
    private ServletContext context;
 | 
			
		||||
 | 
			
		||||
    public OpenAPIConfiguration(ServletContext context) {
 | 
			
		||||
        this.context = context;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public OpenAPI springShopOpenAPI(
 | 
			
		||||
            //  @Value("${info.app.version}") String appVersion,
 | 
			
		||||
    ) {
 | 
			
		||||
        final String securitySchemeName = "bearerAuth";
 | 
			
		||||
 | 
			
		||||
        return new OpenAPI()
 | 
			
		||||
                .addServersItem(new Server().url(this.context.getContextPath()))
 | 
			
		||||
                .info(new Info()
 | 
			
		||||
                        .title("LF8 project starter")
 | 
			
		||||
                        .description("""
 | 
			
		||||
                                ## Auth
 | 
			
		||||
                                
 | 
			
		||||
                                ## Authentication
 | 
			
		||||
                                
 | 
			
		||||
                                This Hello service uses JWTs to authenticate requests. You will receive a bearer token by making a POST-Request in IntelliJ on:
 | 
			
		||||
                                
 | 
			
		||||
                                ```
 | 
			
		||||
                                POST http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token
 | 
			
		||||
                                Content-Type: application/x-www-form-urlencoded
 | 
			
		||||
                                grant_type=password&client_id=employee-management-service&username=user&password=test
 | 
			
		||||
                                ```
 | 
			
		||||
                                
 | 
			
		||||
                                or by CURL:
 | 
			
		||||
                                
 | 
			
		||||
                                ```
 | 
			
		||||
                                curl -X POST 'http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token' 
 | 
			
		||||
                                --header 'Content-Type: application/x-www-form-urlencoded' 
 | 
			
		||||
                                --data-urlencode 'grant_type=password' 
 | 
			
		||||
                                --data-urlencode 'client_id=employee-management-service' 
 | 
			
		||||
                                --data-urlencode 'username=user' 
 | 
			
		||||
                                --data-urlencode 'password=test'
 | 
			
		||||
                                ```
 | 
			
		||||
                                
 | 
			
		||||
                                To get a bearer-token in Postman, you have to follow the instructions in 
 | 
			
		||||
                                [Postman-Documentation](https://documenter.getpostman.com/view/7294517/SzmfZHnd).
 | 
			
		||||
                                """)
 | 
			
		||||
                        .version("0.1"))
 | 
			
		||||
                .addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
 | 
			
		||||
                .components(
 | 
			
		||||
                        new Components()
 | 
			
		||||
                                .addSecuritySchemes(securitySchemeName,
 | 
			
		||||
                                        new SecurityScheme()
 | 
			
		||||
                                                .name(securitySchemeName)
 | 
			
		||||
                                                .type(SecurityScheme.Type.HTTP)
 | 
			
		||||
                                                .scheme("bearer")
 | 
			
		||||
                                                .bearerFormat("JWT")
 | 
			
		||||
                                )
 | 
			
		||||
                );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
package de.szut.lf8_starter.config;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import io.swagger.v3.oas.models.Components;
 | 
			
		||||
import io.swagger.v3.oas.models.OpenAPI;
 | 
			
		||||
import io.swagger.v3.oas.models.info.Info;
 | 
			
		||||
import io.swagger.v3.oas.models.security.SecurityRequirement;
 | 
			
		||||
import io.swagger.v3.oas.models.security.SecurityScheme;
 | 
			
		||||
import io.swagger.v3.oas.models.servers.Server;
 | 
			
		||||
import jakarta.servlet.ServletContext;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@Configuration
 | 
			
		||||
public class OpenAPIConfiguration {
 | 
			
		||||
 | 
			
		||||
    private ServletContext context;
 | 
			
		||||
 | 
			
		||||
    public OpenAPIConfiguration(ServletContext context) {
 | 
			
		||||
        this.context = context;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public OpenAPI springShopOpenAPI(
 | 
			
		||||
            //  @Value("${info.app.version}") String appVersion,
 | 
			
		||||
    ) {
 | 
			
		||||
        final String securitySchemeName = "bearerAuth";
 | 
			
		||||
 | 
			
		||||
        return new OpenAPI()
 | 
			
		||||
                .addServersItem(new Server().url(this.context.getContextPath()))
 | 
			
		||||
                .info(new Info()
 | 
			
		||||
                        .title("LF8 project starter")
 | 
			
		||||
                        .description("""
 | 
			
		||||
                                ## Auth
 | 
			
		||||
                                
 | 
			
		||||
                                ## Authentication
 | 
			
		||||
                                
 | 
			
		||||
                                This Hello service uses JWTs to authenticate requests. You will receive a bearer token by making a POST-Request in IntelliJ on:
 | 
			
		||||
                                
 | 
			
		||||
                                ```
 | 
			
		||||
                                POST http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token
 | 
			
		||||
                                Content-Type: application/x-www-form-urlencoded
 | 
			
		||||
                                grant_type=password&client_id=employee-management-service&username=user&password=test
 | 
			
		||||
                                ```
 | 
			
		||||
                                
 | 
			
		||||
                                or by CURL:
 | 
			
		||||
                                
 | 
			
		||||
                                ```
 | 
			
		||||
                                curl -X POST 'http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token' 
 | 
			
		||||
                                --header 'Content-Type: application/x-www-form-urlencoded' 
 | 
			
		||||
                                --data-urlencode 'grant_type=password' 
 | 
			
		||||
                                --data-urlencode 'client_id=employee-management-service' 
 | 
			
		||||
                                --data-urlencode 'username=user' 
 | 
			
		||||
                                --data-urlencode 'password=test'
 | 
			
		||||
                                ```
 | 
			
		||||
                                
 | 
			
		||||
                                To get a bearer-token in Postman, you have to follow the instructions in 
 | 
			
		||||
                                [Postman-Documentation](https://documenter.getpostman.com/view/7294517/SzmfZHnd).
 | 
			
		||||
                                """)
 | 
			
		||||
                        .version("0.1"))
 | 
			
		||||
                .addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
 | 
			
		||||
                .components(
 | 
			
		||||
                        new Components()
 | 
			
		||||
                                .addSecuritySchemes(securitySchemeName,
 | 
			
		||||
                                        new SecurityScheme()
 | 
			
		||||
                                                .name(securitySchemeName)
 | 
			
		||||
                                                .type(SecurityScheme.Type.HTTP)
 | 
			
		||||
                                                .scheme("bearer")
 | 
			
		||||
                                                .bearerFormat("JWT")
 | 
			
		||||
                                )
 | 
			
		||||
                );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,33 +1,33 @@
 | 
			
		|||
package de.szut.lf8_starter.config;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import de.szut.lf8_starter.hello.HelloEntity;
 | 
			
		||||
import de.szut.lf8_starter.hello.HelloRepository;
 | 
			
		||||
import org.springframework.boot.ApplicationArguments;
 | 
			
		||||
import org.springframework.boot.ApplicationRunner;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import org.springframework.web.client.RestTemplate;
 | 
			
		||||
 | 
			
		||||
@Component
 | 
			
		||||
public class SampleDataCreator implements ApplicationRunner {
 | 
			
		||||
 | 
			
		||||
    private HelloRepository repository;
 | 
			
		||||
 | 
			
		||||
    public SampleDataCreator(HelloRepository repository) {
 | 
			
		||||
        this.repository = repository;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void run(ApplicationArguments args) {
 | 
			
		||||
        repository.save(new HelloEntity("Hallo Welt!"));
 | 
			
		||||
        repository.save(new HelloEntity("Schöner Tag heute"));
 | 
			
		||||
        repository.save(new HelloEntity("FooBar"));
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public RestTemplate restTemplate() {
 | 
			
		||||
        return new RestTemplate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
package de.szut.lf8_starter.config;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import de.szut.lf8_starter.hello.HelloEntity;
 | 
			
		||||
import de.szut.lf8_starter.hello.HelloRepository;
 | 
			
		||||
import org.springframework.boot.ApplicationArguments;
 | 
			
		||||
import org.springframework.boot.ApplicationRunner;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import org.springframework.web.client.RestTemplate;
 | 
			
		||||
 | 
			
		||||
@Component
 | 
			
		||||
public class SampleDataCreator implements ApplicationRunner {
 | 
			
		||||
 | 
			
		||||
    private HelloRepository repository;
 | 
			
		||||
 | 
			
		||||
    public SampleDataCreator(HelloRepository repository) {
 | 
			
		||||
        this.repository = repository;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void run(ApplicationArguments args) {
 | 
			
		||||
        repository.save(new HelloEntity("Hallo Welt!"));
 | 
			
		||||
        repository.save(new HelloEntity("Schöner Tag heute"));
 | 
			
		||||
        repository.save(new HelloEntity("FooBar"));
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public RestTemplate restTemplate() {
 | 
			
		||||
        return new RestTemplate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,51 +1,59 @@
 | 
			
		|||
package de.szut.lf8_starter.exceptionHandling;
 | 
			
		||||
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Content;
 | 
			
		||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
 | 
			
		||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
 | 
			
		||||
import jakarta.validation.ConstraintViolationException;
 | 
			
		||||
import org.springframework.http.HttpStatus;
 | 
			
		||||
import org.springframework.http.ResponseEntity;
 | 
			
		||||
import org.springframework.web.bind.MethodArgumentNotValidException;
 | 
			
		||||
import org.springframework.web.bind.annotation.ControllerAdvice;
 | 
			
		||||
import org.springframework.web.bind.annotation.ExceptionHandler;
 | 
			
		||||
import org.springframework.web.context.request.WebRequest;
 | 
			
		||||
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
 | 
			
		||||
@ControllerAdvice
 | 
			
		||||
@ApiResponses(value = {
 | 
			
		||||
        @ApiResponse(responseCode = "500", description = "invalid JSON posted",
 | 
			
		||||
                content = @Content)
 | 
			
		||||
})
 | 
			
		||||
public class GlobalExceptionHandler {
 | 
			
		||||
 | 
			
		||||
    @ExceptionHandler(ResourceNotFoundException.class)
 | 
			
		||||
    public ResponseEntity<ErrorDetails> handleHelloEntityNotFoundException(ResourceNotFoundException ex, WebRequest request) {
 | 
			
		||||
        ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
 | 
			
		||||
        return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ExceptionHandler(Exception.class)
 | 
			
		||||
    public ResponseEntity<ErrorDetails> handleAllOtherExceptions(Exception ex, WebRequest request) {
 | 
			
		||||
        ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getClass() + " " + ex.getMessage(), request.getDescription(false));
 | 
			
		||||
 | 
			
		||||
        return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ExceptionHandler(MethodArgumentNotValidException.class)
 | 
			
		||||
    public ResponseEntity<ErrorDetails> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, WebRequest request) {
 | 
			
		||||
        ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
 | 
			
		||||
 | 
			
		||||
        return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ExceptionHandler(ConstraintViolationException.class)
 | 
			
		||||
    public ResponseEntity<ErrorDetails> handleConstraintViolationException(ConstraintViolationException ex, WebRequest request) {
 | 
			
		||||
        String errorMessage = ex.getConstraintViolations().stream().findFirst().get().getMessage();
 | 
			
		||||
 | 
			
		||||
        ErrorDetails errorDetails = new ErrorDetails(new Date(), errorMessage, request.getDescription(false));
 | 
			
		||||
 | 
			
		||||
        return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
package de.szut.lf8_starter.exceptionHandling;
 | 
			
		||||
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Content;
 | 
			
		||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
 | 
			
		||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
 | 
			
		||||
import jakarta.validation.ConstraintViolationException;
 | 
			
		||||
import org.springframework.http.HttpStatus;
 | 
			
		||||
import org.springframework.http.ResponseEntity;
 | 
			
		||||
import org.springframework.http.converter.HttpMessageNotReadableException;
 | 
			
		||||
import org.springframework.web.bind.MethodArgumentNotValidException;
 | 
			
		||||
import org.springframework.web.bind.annotation.ControllerAdvice;
 | 
			
		||||
import org.springframework.web.bind.annotation.ExceptionHandler;
 | 
			
		||||
import org.springframework.web.context.request.WebRequest;
 | 
			
		||||
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
 | 
			
		||||
@ControllerAdvice
 | 
			
		||||
@ApiResponses(value = {
 | 
			
		||||
        @ApiResponse(responseCode = "500", description = "invalid JSON posted",
 | 
			
		||||
                content = @Content)
 | 
			
		||||
})
 | 
			
		||||
public class GlobalExceptionHandler {
 | 
			
		||||
 | 
			
		||||
    @ExceptionHandler(ResourceNotFoundException.class)
 | 
			
		||||
    public ResponseEntity<ErrorDetails> handleHelloEntityNotFoundException(ResourceNotFoundException ex, WebRequest request) {
 | 
			
		||||
        ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
 | 
			
		||||
        return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ExceptionHandler(Exception.class)
 | 
			
		||||
    public ResponseEntity<ErrorDetails> handleAllOtherExceptions(Exception ex, WebRequest request) {
 | 
			
		||||
        ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getClass() + " " + ex.getMessage(), request.getDescription(false));
 | 
			
		||||
 | 
			
		||||
        return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ExceptionHandler(MethodArgumentNotValidException.class)
 | 
			
		||||
    public ResponseEntity<ErrorDetails> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, WebRequest request) {
 | 
			
		||||
        ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
 | 
			
		||||
 | 
			
		||||
        return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ExceptionHandler(HttpMessageNotReadableException.class)
 | 
			
		||||
    public ResponseEntity<ErrorDetails> handleHttpMessageNotReadableException(HttpMessageNotReadableException ex, WebRequest request) {
 | 
			
		||||
        ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
 | 
			
		||||
 | 
			
		||||
        return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ExceptionHandler(ConstraintViolationException.class)
 | 
			
		||||
    public ResponseEntity<ErrorDetails> handleConstraintViolationException(ConstraintViolationException ex, WebRequest request) {
 | 
			
		||||
        String errorMessage = ex.getConstraintViolations().stream().findFirst().get().getMessage();
 | 
			
		||||
 | 
			
		||||
        ErrorDetails errorDetails = new ErrorDetails(new Date(), errorMessage, request.getDescription(false));
 | 
			
		||||
 | 
			
		||||
        return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,65 +1,65 @@
 | 
			
		|||
package de.szut.lf8_starter.hello;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import de.szut.lf8_starter.exceptionHandling.ResourceNotFoundException;
 | 
			
		||||
import de.szut.lf8_starter.hello.dto.HelloCreateDto;
 | 
			
		||||
import de.szut.lf8_starter.hello.dto.HelloGetDto;
 | 
			
		||||
import io.swagger.v3.oas.annotations.Operation;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Content;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
 | 
			
		||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
 | 
			
		||||
import jakarta.validation.Valid;
 | 
			
		||||
import org.springframework.http.HttpStatus;
 | 
			
		||||
import org.springframework.security.access.prepost.PreAuthorize;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping(value = "hello")
 | 
			
		||||
@PreAuthorize("hasAnyAuthority('user')")
 | 
			
		||||
public class HelloController {
 | 
			
		||||
    private final HelloService service;
 | 
			
		||||
    private final HelloMapper helloMapper;
 | 
			
		||||
 | 
			
		||||
    public HelloController(HelloService service, HelloMapper mappingService) {
 | 
			
		||||
        this.service = service;
 | 
			
		||||
        this.helloMapper = mappingService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Operation(summary = "creates a new hello with its id and message")
 | 
			
		||||
    @ApiResponses(value = {
 | 
			
		||||
            @ApiResponse(responseCode = "201", description = "created hello",
 | 
			
		||||
                    content = {@Content(mediaType = "application/json",
 | 
			
		||||
                            schema = @Schema(implementation = HelloGetDto.class))}),
 | 
			
		||||
            @ApiResponse(responseCode = "400", description = "invalid JSON posted",
 | 
			
		||||
                    content = @Content),
 | 
			
		||||
            @ApiResponse(responseCode = "401", description = "not authorized",
 | 
			
		||||
                    content = @Content)})
 | 
			
		||||
    @PostMapping
 | 
			
		||||
    public HelloGetDto create(@RequestBody @Valid HelloCreateDto helloCreateDto) {
 | 
			
		||||
        HelloEntity helloEntity = this.helloMapper.mapCreateDtoToEntity(helloCreateDto);
 | 
			
		||||
        helloEntity = this.service.create(helloEntity);
 | 
			
		||||
        return this.helloMapper.mapToGetDto(helloEntity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Operation(summary = "deletes a Hello by id")
 | 
			
		||||
    @ApiResponses(value = {
 | 
			
		||||
            @ApiResponse(responseCode = "204", description = "delete successful"),
 | 
			
		||||
            @ApiResponse(responseCode = "401", description = "not authorized",
 | 
			
		||||
                    content = @Content),
 | 
			
		||||
            @ApiResponse(responseCode = "404", description = "resource not found",
 | 
			
		||||
                    content = @Content)})
 | 
			
		||||
    @DeleteMapping("/{id}")
 | 
			
		||||
    @ResponseStatus(code = HttpStatus.NO_CONTENT)
 | 
			
		||||
    public void deleteHelloById(@PathVariable long id) {
 | 
			
		||||
        var entity = this.service.readById(id);
 | 
			
		||||
        if (entity == null) {
 | 
			
		||||
            throw new ResourceNotFoundException("HelloEntity not found on id = " + id);
 | 
			
		||||
        } else {
 | 
			
		||||
            this.service.delete(entity);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
package de.szut.lf8_starter.hello;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import de.szut.lf8_starter.exceptionHandling.ResourceNotFoundException;
 | 
			
		||||
import de.szut.lf8_starter.hello.dto.HelloCreateDto;
 | 
			
		||||
import de.szut.lf8_starter.hello.dto.HelloGetDto;
 | 
			
		||||
import io.swagger.v3.oas.annotations.Operation;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Content;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
 | 
			
		||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
 | 
			
		||||
import jakarta.validation.Valid;
 | 
			
		||||
import org.springframework.http.HttpStatus;
 | 
			
		||||
import org.springframework.security.access.prepost.PreAuthorize;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping(value = "hello")
 | 
			
		||||
@PreAuthorize("hasAnyAuthority('user')")
 | 
			
		||||
public class HelloController {
 | 
			
		||||
    private final HelloService service;
 | 
			
		||||
    private final HelloMapper helloMapper;
 | 
			
		||||
 | 
			
		||||
    public HelloController(HelloService service, HelloMapper mappingService) {
 | 
			
		||||
        this.service = service;
 | 
			
		||||
        this.helloMapper = mappingService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Operation(summary = "creates a new hello with its id and message")
 | 
			
		||||
    @ApiResponses(value = {
 | 
			
		||||
            @ApiResponse(responseCode = "201", description = "created hello",
 | 
			
		||||
                    content = {@Content(mediaType = "application/json",
 | 
			
		||||
                            schema = @Schema(implementation = HelloGetDto.class))}),
 | 
			
		||||
            @ApiResponse(responseCode = "400", description = "invalid JSON posted",
 | 
			
		||||
                    content = @Content),
 | 
			
		||||
            @ApiResponse(responseCode = "401", description = "not authorized",
 | 
			
		||||
                    content = @Content)})
 | 
			
		||||
    @PostMapping
 | 
			
		||||
    public HelloGetDto create(@RequestBody @Valid HelloCreateDto helloCreateDto) {
 | 
			
		||||
        HelloEntity helloEntity = this.helloMapper.mapCreateDtoToEntity(helloCreateDto);
 | 
			
		||||
        helloEntity = this.service.create(helloEntity);
 | 
			
		||||
        return this.helloMapper.mapToGetDto(helloEntity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Operation(summary = "deletes a Hello by id")
 | 
			
		||||
    @ApiResponses(value = {
 | 
			
		||||
            @ApiResponse(responseCode = "204", description = "delete successful"),
 | 
			
		||||
            @ApiResponse(responseCode = "401", description = "not authorized",
 | 
			
		||||
                    content = @Content),
 | 
			
		||||
            @ApiResponse(responseCode = "404", description = "resource not found",
 | 
			
		||||
                    content = @Content)})
 | 
			
		||||
    @DeleteMapping("/{id}")
 | 
			
		||||
    @ResponseStatus(code = HttpStatus.NO_CONTENT)
 | 
			
		||||
    public void deleteHelloById(@PathVariable long id) {
 | 
			
		||||
        var entity = this.service.readById(id);
 | 
			
		||||
        if (entity == null) {
 | 
			
		||||
            throw new ResourceNotFoundException("HelloEntity not found on id = " + id);
 | 
			
		||||
        } else {
 | 
			
		||||
            this.service.delete(entity);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,27 +1,27 @@
 | 
			
		|||
package de.szut.lf8_starter.hello;
 | 
			
		||||
 | 
			
		||||
import jakarta.persistence.*;
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import lombok.Setter;
 | 
			
		||||
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
@Getter
 | 
			
		||||
@Setter
 | 
			
		||||
@Entity
 | 
			
		||||
@Table(name = "hello")
 | 
			
		||||
public class HelloEntity {
 | 
			
		||||
 | 
			
		||||
    @Id
 | 
			
		||||
    @GeneratedValue(strategy = GenerationType.IDENTITY)
 | 
			
		||||
    private long id;
 | 
			
		||||
 | 
			
		||||
    private String message;
 | 
			
		||||
 | 
			
		||||
    public HelloEntity(String message) {
 | 
			
		||||
        this.message = message;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
package de.szut.lf8_starter.hello;
 | 
			
		||||
 | 
			
		||||
import jakarta.persistence.*;
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import lombok.Setter;
 | 
			
		||||
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
@Getter
 | 
			
		||||
@Setter
 | 
			
		||||
@Entity
 | 
			
		||||
@Table(name = "hello")
 | 
			
		||||
public class HelloEntity {
 | 
			
		||||
 | 
			
		||||
    @Id
 | 
			
		||||
    @GeneratedValue(strategy = GenerationType.IDENTITY)
 | 
			
		||||
    private long id;
 | 
			
		||||
 | 
			
		||||
    private String message;
 | 
			
		||||
 | 
			
		||||
    public HelloEntity(String message) {
 | 
			
		||||
        this.message = message;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,20 +1,20 @@
 | 
			
		|||
package de.szut.lf8_starter.hello;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import de.szut.lf8_starter.hello.dto.HelloCreateDto;
 | 
			
		||||
import de.szut.lf8_starter.hello.dto.HelloGetDto;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
@Service
 | 
			
		||||
public class HelloMapper {
 | 
			
		||||
 | 
			
		||||
    public HelloGetDto mapToGetDto(HelloEntity entity) {
 | 
			
		||||
        return new HelloGetDto(entity.getId(), entity.getMessage());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public HelloEntity mapCreateDtoToEntity(HelloCreateDto dto) {
 | 
			
		||||
        var entity = new HelloEntity();
 | 
			
		||||
        entity.setMessage(dto.getMessage());
 | 
			
		||||
        return entity;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
package de.szut.lf8_starter.hello;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import de.szut.lf8_starter.hello.dto.HelloCreateDto;
 | 
			
		||||
import de.szut.lf8_starter.hello.dto.HelloGetDto;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
@Service
 | 
			
		||||
public class HelloMapper {
 | 
			
		||||
 | 
			
		||||
    public HelloGetDto mapToGetDto(HelloEntity entity) {
 | 
			
		||||
        return new HelloGetDto(entity.getId(), entity.getMessage());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public HelloEntity mapCreateDtoToEntity(HelloCreateDto dto) {
 | 
			
		||||
        var entity = new HelloEntity();
 | 
			
		||||
        entity.setMessage(dto.getMessage());
 | 
			
		||||
        return entity;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,12 @@
 | 
			
		|||
package de.szut.lf8_starter.hello;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaRepository;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public interface HelloRepository extends JpaRepository<HelloEntity, Long> {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    List<HelloEntity> findByMessage(String message);
 | 
			
		||||
}
 | 
			
		||||
package de.szut.lf8_starter.hello;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaRepository;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public interface HelloRepository extends JpaRepository<HelloEntity, Long> {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    List<HelloEntity> findByMessage(String message);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,40 +1,40 @@
 | 
			
		|||
package de.szut.lf8_starter.hello;
 | 
			
		||||
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@Service
 | 
			
		||||
public class HelloService {
 | 
			
		||||
    private final HelloRepository repository;
 | 
			
		||||
 | 
			
		||||
    public HelloService(HelloRepository repository) {
 | 
			
		||||
        this.repository = repository;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public HelloEntity create(HelloEntity entity) {
 | 
			
		||||
        return this.repository.save(entity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<HelloEntity> readAll() {
 | 
			
		||||
        return this.repository.findAll();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public HelloEntity readById(long id) {
 | 
			
		||||
        Optional<HelloEntity> optionalQualification = this.repository.findById(id);
 | 
			
		||||
        if (optionalQualification.isEmpty()) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return optionalQualification.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public void delete(HelloEntity entity) {
 | 
			
		||||
        this.repository.delete(entity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<HelloEntity> findByMessage(String message) {
 | 
			
		||||
        return this.repository.findByMessage(message);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
package de.szut.lf8_starter.hello;
 | 
			
		||||
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@Service
 | 
			
		||||
public class HelloService {
 | 
			
		||||
    private final HelloRepository repository;
 | 
			
		||||
 | 
			
		||||
    public HelloService(HelloRepository repository) {
 | 
			
		||||
        this.repository = repository;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public HelloEntity create(HelloEntity entity) {
 | 
			
		||||
        return this.repository.save(entity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<HelloEntity> readAll() {
 | 
			
		||||
        return this.repository.findAll();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public HelloEntity readById(long id) {
 | 
			
		||||
        Optional<HelloEntity> optionalQualification = this.repository.findById(id);
 | 
			
		||||
        if (optionalQualification.isEmpty()) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return optionalQualification.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public void delete(HelloEntity entity) {
 | 
			
		||||
        this.repository.delete(entity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<HelloEntity> findByMessage(String message) {
 | 
			
		||||
        return this.repository.findByMessage(message);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,20 +1,20 @@
 | 
			
		|||
package de.szut.lf8_starter.hello.dto;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonCreator;
 | 
			
		||||
import jakarta.validation.constraints.Size;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import lombok.Setter;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@Getter
 | 
			
		||||
@Setter
 | 
			
		||||
public class HelloCreateDto {
 | 
			
		||||
 | 
			
		||||
    @Size(min = 3, message = "at least length of 3")
 | 
			
		||||
    private String message;
 | 
			
		||||
 | 
			
		||||
    @JsonCreator
 | 
			
		||||
    public HelloCreateDto(String message) {
 | 
			
		||||
        this.message = message;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
package de.szut.lf8_starter.hello.dto;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonCreator;
 | 
			
		||||
import jakarta.validation.constraints.Size;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import lombok.Setter;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@Getter
 | 
			
		||||
@Setter
 | 
			
		||||
public class HelloCreateDto {
 | 
			
		||||
 | 
			
		||||
    @Size(min = 3, message = "at least length of 3")
 | 
			
		||||
    private String message;
 | 
			
		||||
 | 
			
		||||
    @JsonCreator
 | 
			
		||||
    public HelloCreateDto(String message) {
 | 
			
		||||
        this.message = message;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,17 +1,17 @@
 | 
			
		|||
package de.szut.lf8_starter.hello.dto;
 | 
			
		||||
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import lombok.Setter;
 | 
			
		||||
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
@Getter
 | 
			
		||||
@Setter
 | 
			
		||||
public class HelloGetDto {
 | 
			
		||||
 | 
			
		||||
    private long id;
 | 
			
		||||
 | 
			
		||||
    private String message;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
package de.szut.lf8_starter.hello.dto;
 | 
			
		||||
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import lombok.Setter;
 | 
			
		||||
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
@Getter
 | 
			
		||||
@Setter
 | 
			
		||||
public class HelloGetDto {
 | 
			
		||||
 | 
			
		||||
    private long id;
 | 
			
		||||
 | 
			
		||||
    private String message;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,41 +1,61 @@
 | 
			
		|||
package de.szut.lf8_starter.project;
 | 
			
		||||
 | 
			
		||||
import de.szut.lf8_starter.project.dto.CreateProjectDto;
 | 
			
		||||
import de.szut.lf8_starter.project.dto.GetProjectDto;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
@Service
 | 
			
		||||
public class ProjectMapper {
 | 
			
		||||
    public ProjectEntity mapCreateDtoToEntity(CreateProjectDto createProjectDto) {
 | 
			
		||||
        ProjectEntity projectEntity = new ProjectEntity();
 | 
			
		||||
 | 
			
		||||
        projectEntity.setName(createProjectDto.getName());
 | 
			
		||||
        projectEntity.setComment(createProjectDto.getComment());
 | 
			
		||||
        projectEntity.setLeadingEmployee(createProjectDto.getLeadingEmployee());
 | 
			
		||||
        projectEntity.setEmployees(createProjectDto.getEmployees());
 | 
			
		||||
        projectEntity.setContractor(createProjectDto.getContractor());
 | 
			
		||||
        projectEntity.setContractorName(createProjectDto.getContractorName());
 | 
			
		||||
        projectEntity.setStartDate(createProjectDto.getStartDate());
 | 
			
		||||
        projectEntity.setPlannedEndDate(createProjectDto.getPlannedEndDate());
 | 
			
		||||
        projectEntity.setEndDate(createProjectDto.getEndDate());
 | 
			
		||||
 | 
			
		||||
        return projectEntity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public GetProjectDto mapToGetDto(ProjectEntity projectEntity) {
 | 
			
		||||
        GetProjectDto getProjectDto = new GetProjectDto();
 | 
			
		||||
 | 
			
		||||
        getProjectDto.setId(projectEntity.getId());
 | 
			
		||||
        getProjectDto.setName(projectEntity.getName());
 | 
			
		||||
        getProjectDto.setComment(projectEntity.getComment());
 | 
			
		||||
        getProjectDto.setLeadingEmployee(projectEntity.getLeadingEmployee());
 | 
			
		||||
        getProjectDto.setEmployees(projectEntity.getEmployees());
 | 
			
		||||
        getProjectDto.setContractor(projectEntity.getContractor());
 | 
			
		||||
        getProjectDto.setContractorName(projectEntity.getContractorName());
 | 
			
		||||
        getProjectDto.setStartDate(projectEntity.getStartDate());
 | 
			
		||||
        getProjectDto.setPlannedEndDate(projectEntity.getPlannedEndDate());
 | 
			
		||||
        getProjectDto.setEndDate(projectEntity.getEndDate());
 | 
			
		||||
 | 
			
		||||
        return getProjectDto;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
package de.szut.lf8_starter.project;
 | 
			
		||||
 | 
			
		||||
import de.szut.lf8_starter.project.dto.CreateProjectDto;
 | 
			
		||||
import de.szut.lf8_starter.project.dto.GetProjectDto;
 | 
			
		||||
import de.szut.lf8_starter.project.dto.UpdateProjectDto;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
@Service
 | 
			
		||||
public class ProjectMapper {
 | 
			
		||||
    public ProjectEntity mapCreateDtoToEntity(CreateProjectDto createProjectDto) {
 | 
			
		||||
        ProjectEntity projectEntity = new ProjectEntity();
 | 
			
		||||
 | 
			
		||||
        projectEntity.setName(createProjectDto.getName());
 | 
			
		||||
        projectEntity.setComment(createProjectDto.getComment());
 | 
			
		||||
        projectEntity.setLeadingEmployee(createProjectDto.getLeadingEmployee());
 | 
			
		||||
        projectEntity.setEmployees(createProjectDto.getEmployees());
 | 
			
		||||
        projectEntity.setContractor(createProjectDto.getContractor());
 | 
			
		||||
        projectEntity.setContractorName(createProjectDto.getContractorName());
 | 
			
		||||
        projectEntity.setStartDate(createProjectDto.getStartDate());
 | 
			
		||||
        projectEntity.setPlannedEndDate(createProjectDto.getPlannedEndDate());
 | 
			
		||||
        projectEntity.setEndDate(createProjectDto.getEndDate());
 | 
			
		||||
 | 
			
		||||
        return projectEntity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public GetProjectDto mapToGetDto(ProjectEntity projectEntity) {
 | 
			
		||||
        GetProjectDto getProjectDto = new GetProjectDto();
 | 
			
		||||
 | 
			
		||||
        getProjectDto.setId(projectEntity.getId());
 | 
			
		||||
        getProjectDto.setName(projectEntity.getName());
 | 
			
		||||
        getProjectDto.setComment(projectEntity.getComment());
 | 
			
		||||
        getProjectDto.setLeadingEmployee(projectEntity.getLeadingEmployee());
 | 
			
		||||
        getProjectDto.setEmployees(projectEntity.getEmployees());
 | 
			
		||||
        getProjectDto.setContractor(projectEntity.getContractor());
 | 
			
		||||
        getProjectDto.setContractorName(projectEntity.getContractorName());
 | 
			
		||||
        getProjectDto.setStartDate(projectEntity.getStartDate());
 | 
			
		||||
        getProjectDto.setPlannedEndDate(projectEntity.getPlannedEndDate());
 | 
			
		||||
        getProjectDto.setEndDate(projectEntity.getEndDate());
 | 
			
		||||
 | 
			
		||||
        return getProjectDto;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ProjectEntity mapUpdateDtoToEntity(UpdateProjectDto updateProjectDto, ProjectEntity projectEntity) {
 | 
			
		||||
        projectEntity.setName(updateProjectDto.getName() != null ? updateProjectDto.getName() : projectEntity.getName());
 | 
			
		||||
        projectEntity.setLeadingEmployee(updateProjectDto.getLeadingEmployee() != null ? updateProjectDto.getLeadingEmployee() : projectEntity.getLeadingEmployee());
 | 
			
		||||
        projectEntity.setContractor(updateProjectDto.getContractor() != null ? updateProjectDto.getContractor() : projectEntity.getContractor());
 | 
			
		||||
        projectEntity.setContractorName(updateProjectDto.getContractorName() != null ? updateProjectDto.getContractorName() : projectEntity.getContractorName());
 | 
			
		||||
        projectEntity.setComment(updateProjectDto.getComment() != null ? updateProjectDto.getComment() : projectEntity.getComment());
 | 
			
		||||
        projectEntity.setStartDate(updateProjectDto.getStartDate() != null ? updateProjectDto.getStartDate() : projectEntity.getStartDate());
 | 
			
		||||
        projectEntity.setPlannedEndDate(updateProjectDto.getPlannedEndDate() != null ? updateProjectDto.getPlannedEndDate() : projectEntity.getPlannedEndDate());
 | 
			
		||||
        projectEntity.setEndDate(updateProjectDto.getEndDate() != null ? updateProjectDto.getEndDate() : projectEntity.getEndDate());
 | 
			
		||||
 | 
			
		||||
        if (updateProjectDto.getEmployees() != null) {
 | 
			
		||||
            projectEntity.getEmployees().clear();
 | 
			
		||||
 | 
			
		||||
            projectEntity.setEmployees(updateProjectDto.getEmployees());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return projectEntity;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,34 +1,33 @@
 | 
			
		|||
package de.szut.lf8_starter.project;
 | 
			
		||||
 | 
			
		||||
import de.szut.lf8_starter.exceptionHandling.ResourceNotFoundException;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@Service
 | 
			
		||||
public class ProjectService {
 | 
			
		||||
    private final ProjectRepository projectRepository;
 | 
			
		||||
 | 
			
		||||
    public ProjectService(ProjectRepository projectRepository) {
 | 
			
		||||
        this.projectRepository = projectRepository;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ProjectEntity create(ProjectEntity projectEntity) {
 | 
			
		||||
        return this.projectRepository.save(projectEntity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<ProjectEntity> readAll() {
 | 
			
		||||
        return this.projectRepository.findAll();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ProjectEntity findById(Long id) {
 | 
			
		||||
        Optional<ProjectEntity> articleEntity = projectRepository.findById(id);
 | 
			
		||||
 | 
			
		||||
        if (articleEntity.isEmpty()) {
 | 
			
		||||
            throw new ResourceNotFoundException("Project with id " + id + " not found");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return articleEntity.get();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
package de.szut.lf8_starter.project;
 | 
			
		||||
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@Service
 | 
			
		||||
public class ProjectService {
 | 
			
		||||
    private final ProjectRepository projectRepository;
 | 
			
		||||
 | 
			
		||||
    public ProjectService(ProjectRepository projectRepository) {
 | 
			
		||||
        this.projectRepository = projectRepository;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ProjectEntity create(ProjectEntity projectEntity) {
 | 
			
		||||
        return this.projectRepository.save(projectEntity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<ProjectEntity> readAll() {
 | 
			
		||||
        return this.projectRepository.findAll();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Optional<ProjectEntity> findById(Long id) {
 | 
			
		||||
        return projectRepository.findById(id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ProjectEntity update(ProjectEntity project) {
 | 
			
		||||
        this.projectRepository.save(project);
 | 
			
		||||
 | 
			
		||||
        return project;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,40 +1,46 @@
 | 
			
		|||
package de.szut.lf8_starter.project.action;
 | 
			
		||||
 | 
			
		||||
import de.szut.lf8_starter.project.ProjectEntity;
 | 
			
		||||
import de.szut.lf8_starter.project.ProjectMapper;
 | 
			
		||||
import de.szut.lf8_starter.project.ProjectService;
 | 
			
		||||
import de.szut.lf8_starter.project.dto.GetProjectDto;
 | 
			
		||||
import io.swagger.v3.oas.annotations.Operation;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Content;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
 | 
			
		||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
 | 
			
		||||
import org.springframework.http.HttpStatus;
 | 
			
		||||
import org.springframework.http.ResponseEntity;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping(value = "projects")
 | 
			
		||||
public class GetProjectAction {
 | 
			
		||||
    private final ProjectService projectService;
 | 
			
		||||
    private final ProjectMapper projectMapper;
 | 
			
		||||
 | 
			
		||||
    public GetProjectAction(ProjectService projectService, ProjectMapper projectMapper) {
 | 
			
		||||
        this.projectService = projectService;
 | 
			
		||||
        this.projectMapper = projectMapper;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Operation(summary = "Find project by ID")
 | 
			
		||||
    @ApiResponses(value = {
 | 
			
		||||
            @ApiResponse(responseCode = "200", description = "Project found", content = {
 | 
			
		||||
                    @Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))
 | 
			
		||||
            }),
 | 
			
		||||
            @ApiResponse(responseCode = "404", description = "Project not found", content = @Content)
 | 
			
		||||
    })
 | 
			
		||||
    @GetMapping("/{id}")
 | 
			
		||||
    public ResponseEntity<GetProjectDto> findArticleById(@PathVariable Long id) {
 | 
			
		||||
        ProjectEntity project = this.projectService.findById(id);
 | 
			
		||||
 | 
			
		||||
        return new ResponseEntity<>(this.projectMapper.mapToGetDto(project), HttpStatus.OK);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
package de.szut.lf8_starter.project.action;
 | 
			
		||||
 | 
			
		||||
import de.szut.lf8_starter.project.ProjectEntity;
 | 
			
		||||
import de.szut.lf8_starter.project.ProjectMapper;
 | 
			
		||||
import de.szut.lf8_starter.project.ProjectService;
 | 
			
		||||
import de.szut.lf8_starter.project.dto.GetProjectDto;
 | 
			
		||||
import io.swagger.v3.oas.annotations.Operation;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Content;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
 | 
			
		||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
 | 
			
		||||
import org.springframework.http.HttpStatus;
 | 
			
		||||
import org.springframework.http.ResponseEntity;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping(value = "projects")
 | 
			
		||||
public class GetProjectAction {
 | 
			
		||||
    private final ProjectService projectService;
 | 
			
		||||
    private final ProjectMapper projectMapper;
 | 
			
		||||
 | 
			
		||||
    public GetProjectAction(ProjectService projectService, ProjectMapper projectMapper) {
 | 
			
		||||
        this.projectService = projectService;
 | 
			
		||||
        this.projectMapper = projectMapper;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Operation(summary = "Find project by ID")
 | 
			
		||||
    @ApiResponses(value = {
 | 
			
		||||
            @ApiResponse(responseCode = "200", description = "Project found", content = {
 | 
			
		||||
                    @Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))
 | 
			
		||||
            }),
 | 
			
		||||
            @ApiResponse(responseCode = "404", description = "Project not found", content = @Content)
 | 
			
		||||
    })
 | 
			
		||||
    @GetMapping("/{id}")
 | 
			
		||||
    public ResponseEntity<GetProjectDto> findArticleById(@PathVariable Long id) {
 | 
			
		||||
        Optional<ProjectEntity> project = this.projectService.findById(id);
 | 
			
		||||
 | 
			
		||||
        if (project.isEmpty()) {
 | 
			
		||||
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return new ResponseEntity<>(this.projectMapper.mapToGetDto(project.get()), HttpStatus.OK);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
package de.szut.lf8_starter.project.action;
 | 
			
		||||
 | 
			
		||||
import de.szut.lf8_starter.project.ProjectEntity;
 | 
			
		||||
import de.szut.lf8_starter.project.ProjectMapper;
 | 
			
		||||
import de.szut.lf8_starter.project.ProjectService;
 | 
			
		||||
import de.szut.lf8_starter.project.dto.GetProjectDto;
 | 
			
		||||
import de.szut.lf8_starter.project.dto.UpdateProjectDto;
 | 
			
		||||
import io.swagger.v3.oas.annotations.Operation;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Content;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
 | 
			
		||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
 | 
			
		||||
import jakarta.validation.Valid;
 | 
			
		||||
import org.springframework.http.HttpStatus;
 | 
			
		||||
import org.springframework.http.ResponseEntity;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping(value = "/projects")
 | 
			
		||||
public class UpdateProjectAction {
 | 
			
		||||
    private final ProjectService projectService;
 | 
			
		||||
    private final ProjectMapper projectMapper;
 | 
			
		||||
 | 
			
		||||
    public UpdateProjectAction(ProjectService projectService, ProjectMapper mappingService) {
 | 
			
		||||
        this.projectService = projectService;
 | 
			
		||||
        this.projectMapper = mappingService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Operation(summary = "Update a project by ID")
 | 
			
		||||
    @ApiResponses(value = {
 | 
			
		||||
            @ApiResponse(responseCode = "200", description = "Project updated successfully",
 | 
			
		||||
                    content = @Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))),
 | 
			
		||||
            @ApiResponse(responseCode = "404", description = "Project not found", content = @Content)
 | 
			
		||||
    })
 | 
			
		||||
    @PutMapping("/{id}")
 | 
			
		||||
    public ResponseEntity<GetProjectDto> updateSupplier(@PathVariable Long id, @Valid @RequestBody UpdateProjectDto updateProjectDto) {
 | 
			
		||||
        Optional<ProjectEntity> project = this.projectService.findById(id);
 | 
			
		||||
 | 
			
		||||
        if (project.isEmpty()) {
 | 
			
		||||
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ProjectEntity updatedProject = this.projectMapper.mapUpdateDtoToEntity(updateProjectDto, project.get());
 | 
			
		||||
        this.projectService.update(updatedProject);
 | 
			
		||||
 | 
			
		||||
        return new ResponseEntity<>(this.projectMapper.mapToGetDto(updatedProject), HttpStatus.OK);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,36 @@
 | 
			
		|||
package de.szut.lf8_starter.project.dto;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonFormat;
 | 
			
		||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
 | 
			
		||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import lombok.Setter;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDate;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Getter
 | 
			
		||||
@Setter
 | 
			
		||||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
 | 
			
		||||
public class UpdateProjectDto {
 | 
			
		||||
    private String name;
 | 
			
		||||
 | 
			
		||||
    private Long leadingEmployee;
 | 
			
		||||
 | 
			
		||||
    private List<Long> employees;
 | 
			
		||||
 | 
			
		||||
    private Long contractor;
 | 
			
		||||
 | 
			
		||||
    private String contractorName;
 | 
			
		||||
 | 
			
		||||
    private String comment;
 | 
			
		||||
 | 
			
		||||
    @JsonFormat(pattern = "dd.MM.yyyy")
 | 
			
		||||
    private LocalDate startDate;
 | 
			
		||||
 | 
			
		||||
    @JsonFormat(pattern = "dd.MM.yyyy")
 | 
			
		||||
    private LocalDate plannedEndDate;
 | 
			
		||||
 | 
			
		||||
    @JsonFormat(pattern = "dd.MM.yyyy")
 | 
			
		||||
    private LocalDate endDate;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,49 +1,49 @@
 | 
			
		|||
package de.szut.lf8_starter.security;
 | 
			
		||||
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.springframework.http.ResponseEntity;
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
 | 
			
		||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import org.springframework.web.client.RestTemplate;
 | 
			
		||||
import org.springframework.web.util.UriComponentsBuilder;
 | 
			
		||||
 | 
			
		||||
import jakarta.servlet.http.HttpServletRequest;
 | 
			
		||||
import jakarta.servlet.http.HttpServletResponse;
 | 
			
		||||
 | 
			
		||||
@Slf4j
 | 
			
		||||
@Component
 | 
			
		||||
public class KeycloakLogoutHandler implements LogoutHandler {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private final RestTemplate restTemplate;
 | 
			
		||||
 | 
			
		||||
    public KeycloakLogoutHandler(RestTemplate restTemplate) {
 | 
			
		||||
        this.restTemplate = restTemplate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication auth) {
 | 
			
		||||
        logout(auth);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void logout(Authentication auth) {
 | 
			
		||||
        logoutFromKeycloak((OidcUser) auth.getPrincipal());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void logoutFromKeycloak(OidcUser user) {
 | 
			
		||||
        String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
 | 
			
		||||
        UriComponentsBuilder builder = UriComponentsBuilder
 | 
			
		||||
                .fromUriString(endSessionEndpoint)
 | 
			
		||||
                .queryParam("id_token_hint", user.getIdToken().getTokenValue());
 | 
			
		||||
 | 
			
		||||
        ResponseEntity<String> logoutResponse = restTemplate.getForEntity(builder.toUriString(), String.class);
 | 
			
		||||
        if (logoutResponse.getStatusCode().is2xxSuccessful()) {
 | 
			
		||||
            log.info("Successfulley logged out from Keycloak");
 | 
			
		||||
        } else {
 | 
			
		||||
            log.error("Could not propagate logout to Keycloak");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
package de.szut.lf8_starter.security;
 | 
			
		||||
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.springframework.http.ResponseEntity;
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
 | 
			
		||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import org.springframework.web.client.RestTemplate;
 | 
			
		||||
import org.springframework.web.util.UriComponentsBuilder;
 | 
			
		||||
 | 
			
		||||
import jakarta.servlet.http.HttpServletRequest;
 | 
			
		||||
import jakarta.servlet.http.HttpServletResponse;
 | 
			
		||||
 | 
			
		||||
@Slf4j
 | 
			
		||||
@Component
 | 
			
		||||
public class KeycloakLogoutHandler implements LogoutHandler {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private final RestTemplate restTemplate;
 | 
			
		||||
 | 
			
		||||
    public KeycloakLogoutHandler(RestTemplate restTemplate) {
 | 
			
		||||
        this.restTemplate = restTemplate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication auth) {
 | 
			
		||||
        logout(auth);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void logout(Authentication auth) {
 | 
			
		||||
        logoutFromKeycloak((OidcUser) auth.getPrincipal());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void logoutFromKeycloak(OidcUser user) {
 | 
			
		||||
        String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
 | 
			
		||||
        UriComponentsBuilder builder = UriComponentsBuilder
 | 
			
		||||
                .fromUriString(endSessionEndpoint)
 | 
			
		||||
                .queryParam("id_token_hint", user.getIdToken().getTokenValue());
 | 
			
		||||
 | 
			
		||||
        ResponseEntity<String> logoutResponse = restTemplate.getForEntity(builder.toUriString(), String.class);
 | 
			
		||||
        if (logoutResponse.getStatusCode().is2xxSuccessful()) {
 | 
			
		||||
            log.info("Successfulley logged out from Keycloak");
 | 
			
		||||
        } else {
 | 
			
		||||
            log.error("Could not propagate logout to Keycloak");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,94 +1,94 @@
 | 
			
		|||
package de.szut.lf8_starter.security;
 | 
			
		||||
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.context.annotation.Profile;
 | 
			
		||||
import org.springframework.http.HttpMethod;
 | 
			
		||||
import org.springframework.security.config.Customizer;
 | 
			
		||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 | 
			
		||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 | 
			
		||||
import org.springframework.security.core.GrantedAuthority;
 | 
			
		||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
 | 
			
		||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
 | 
			
		||||
import org.springframework.security.core.session.SessionRegistry;
 | 
			
		||||
import org.springframework.security.core.session.SessionRegistryImpl;
 | 
			
		||||
import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
 | 
			
		||||
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
 | 
			
		||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
 | 
			
		||||
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
 | 
			
		||||
import org.springframework.security.web.SecurityFilterChain;
 | 
			
		||||
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
 | 
			
		||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
 | 
			
		||||
import org.springframework.security.web.session.HttpSessionEventPublisher;
 | 
			
		||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
 | 
			
		||||
 | 
			
		||||
@Configuration
 | 
			
		||||
@EnableWebSecurity
 | 
			
		||||
class KeycloakSecurityConfig {
 | 
			
		||||
 | 
			
		||||
    private static final String REALM_ACCESS_CLAIM = "realm_access";
 | 
			
		||||
    private static final String ROLES_CLAIM = "roles";
 | 
			
		||||
 | 
			
		||||
    KeycloakSecurityConfig() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public SessionRegistry sessionRegistry() {
 | 
			
		||||
        return new SessionRegistryImpl();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
 | 
			
		||||
        return new RegisterSessionAuthenticationStrategy(sessionRegistry());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public HttpSessionEventPublisher httpSessionEventPublisher() {
 | 
			
		||||
        return new HttpSessionEventPublisher();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public SecurityFilterChain resourceServerFilterChain(HttpSecurity http) throws Exception {
 | 
			
		||||
 | 
			
		||||
        http.authorizeHttpRequests(auth -> auth
 | 
			
		||||
                .requestMatchers(new AntPathRequestMatcher("/welcome"))
 | 
			
		||||
                .permitAll()
 | 
			
		||||
                .requestMatchers(
 | 
			
		||||
                        new AntPathRequestMatcher("/swagger"),
 | 
			
		||||
                        new AntPathRequestMatcher("/swagger-ui/**"),
 | 
			
		||||
                        new AntPathRequestMatcher("/v3/api-docs/**"))
 | 
			
		||||
                .permitAll()
 | 
			
		||||
                .requestMatchers(new AntPathRequestMatcher("/hello/**"))
 | 
			
		||||
                .hasRole("user")
 | 
			
		||||
                .requestMatchers(new AntPathRequestMatcher("/roles"))
 | 
			
		||||
                .authenticated()
 | 
			
		||||
                .requestMatchers(new AntPathRequestMatcher("/"))
 | 
			
		||||
                .permitAll()
 | 
			
		||||
                .anyRequest()
 | 
			
		||||
                .authenticated()).oauth2ResourceServer(spec -> spec.jwt(Customizer.withDefaults()));
 | 
			
		||||
        return http.build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public JwtAuthenticationConverter jwtAuthenticationConverter() {
 | 
			
		||||
        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
 | 
			
		||||
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwt -> {
 | 
			
		||||
            List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
            Map<String, Object> realmAccess = jwt.getClaim(REALM_ACCESS_CLAIM);
 | 
			
		||||
            if (realmAccess != null && realmAccess.containsKey(ROLES_CLAIM)) {
 | 
			
		||||
                List<String> roles = (List<String>) realmAccess.get(ROLES_CLAIM);
 | 
			
		||||
                for (String role : roles) {
 | 
			
		||||
                    grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_" + role));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return grantedAuthorities;
 | 
			
		||||
        });
 | 
			
		||||
        return jwtAuthenticationConverter;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
package de.szut.lf8_starter.security;
 | 
			
		||||
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.context.annotation.Profile;
 | 
			
		||||
import org.springframework.http.HttpMethod;
 | 
			
		||||
import org.springframework.security.config.Customizer;
 | 
			
		||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 | 
			
		||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 | 
			
		||||
import org.springframework.security.core.GrantedAuthority;
 | 
			
		||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
 | 
			
		||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
 | 
			
		||||
import org.springframework.security.core.session.SessionRegistry;
 | 
			
		||||
import org.springframework.security.core.session.SessionRegistryImpl;
 | 
			
		||||
import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
 | 
			
		||||
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
 | 
			
		||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
 | 
			
		||||
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
 | 
			
		||||
import org.springframework.security.web.SecurityFilterChain;
 | 
			
		||||
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
 | 
			
		||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
 | 
			
		||||
import org.springframework.security.web.session.HttpSessionEventPublisher;
 | 
			
		||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
 | 
			
		||||
 | 
			
		||||
@Configuration
 | 
			
		||||
@EnableWebSecurity
 | 
			
		||||
class KeycloakSecurityConfig {
 | 
			
		||||
 | 
			
		||||
    private static final String REALM_ACCESS_CLAIM = "realm_access";
 | 
			
		||||
    private static final String ROLES_CLAIM = "roles";
 | 
			
		||||
 | 
			
		||||
    KeycloakSecurityConfig() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public SessionRegistry sessionRegistry() {
 | 
			
		||||
        return new SessionRegistryImpl();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
 | 
			
		||||
        return new RegisterSessionAuthenticationStrategy(sessionRegistry());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public HttpSessionEventPublisher httpSessionEventPublisher() {
 | 
			
		||||
        return new HttpSessionEventPublisher();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public SecurityFilterChain resourceServerFilterChain(HttpSecurity http) throws Exception {
 | 
			
		||||
 | 
			
		||||
        http.authorizeHttpRequests(auth -> auth
 | 
			
		||||
                .requestMatchers(new AntPathRequestMatcher("/welcome"))
 | 
			
		||||
                .permitAll()
 | 
			
		||||
                .requestMatchers(
 | 
			
		||||
                        new AntPathRequestMatcher("/swagger"),
 | 
			
		||||
                        new AntPathRequestMatcher("/swagger-ui/**"),
 | 
			
		||||
                        new AntPathRequestMatcher("/v3/api-docs/**"))
 | 
			
		||||
                .permitAll()
 | 
			
		||||
                .requestMatchers(new AntPathRequestMatcher("/hello/**"))
 | 
			
		||||
                .hasRole("user")
 | 
			
		||||
                .requestMatchers(new AntPathRequestMatcher("/roles"))
 | 
			
		||||
                .authenticated()
 | 
			
		||||
                .requestMatchers(new AntPathRequestMatcher("/"))
 | 
			
		||||
                .permitAll()
 | 
			
		||||
                .anyRequest()
 | 
			
		||||
                .authenticated()).oauth2ResourceServer(spec -> spec.jwt(Customizer.withDefaults()));
 | 
			
		||||
        return http.build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public JwtAuthenticationConverter jwtAuthenticationConverter() {
 | 
			
		||||
        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
 | 
			
		||||
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwt -> {
 | 
			
		||||
            List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
            Map<String, Object> realmAccess = jwt.getClaim(REALM_ACCESS_CLAIM);
 | 
			
		||||
            if (realmAccess != null && realmAccess.containsKey(ROLES_CLAIM)) {
 | 
			
		||||
                List<String> roles = (List<String>) realmAccess.get(ROLES_CLAIM);
 | 
			
		||||
                for (String role : roles) {
 | 
			
		||||
                    grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_" + role));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return grantedAuthorities;
 | 
			
		||||
        });
 | 
			
		||||
        return jwtAuthenticationConverter;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,25 +1,25 @@
 | 
			
		|||
package de.szut.lf8_starter.welcome;
 | 
			
		||||
 | 
			
		||||
import org.springframework.http.ResponseEntity;
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
import org.springframework.security.core.GrantedAuthority;
 | 
			
		||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RestController;
 | 
			
		||||
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
 | 
			
		||||
@RestController
 | 
			
		||||
public class WelcomeController {
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/welcome")
 | 
			
		||||
    public String welcome() {
 | 
			
		||||
        return "welcome to lf8_starter";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/roles")
 | 
			
		||||
    public ResponseEntity<Collection<GrantedAuthority>> getRoles(Authentication authentication) {
 | 
			
		||||
        return ResponseEntity.ok((Collection<GrantedAuthority>) authentication.getAuthorities());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
package de.szut.lf8_starter.welcome;
 | 
			
		||||
 | 
			
		||||
import org.springframework.http.ResponseEntity;
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
import org.springframework.security.core.GrantedAuthority;
 | 
			
		||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RestController;
 | 
			
		||||
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
 | 
			
		||||
@RestController
 | 
			
		||||
public class WelcomeController {
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/welcome")
 | 
			
		||||
    public String welcome() {
 | 
			
		||||
        return "welcome to lf8_starter";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/roles")
 | 
			
		||||
    public ResponseEntity<Collection<GrantedAuthority>> getRoles(Authentication authentication) {
 | 
			
		||||
        return ResponseEntity.ok((Collection<GrantedAuthority>) authentication.getAuthorities());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,54 +1,59 @@
 | 
			
		|||
package de.szut.lf8_starter.integration.project;
 | 
			
		||||
 | 
			
		||||
import de.szut.lf8_starter.project.ProjectEntity;
 | 
			
		||||
import de.szut.lf8_starter.project.ProjectRepository;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
 | 
			
		||||
import org.springframework.boot.test.context.SpringBootTest;
 | 
			
		||||
import org.springframework.test.web.servlet.MockMvc;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDate;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
 | 
			
		||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 | 
			
		||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
 | 
			
		||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 | 
			
		||||
 | 
			
		||||
@SpringBootTest
 | 
			
		||||
@AutoConfigureMockMvc(addFilters = false)
 | 
			
		||||
class FindProjectActionTest {
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private MockMvc mockMvc;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private ProjectRepository projectRepository;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void createProjectTest() throws Exception {
 | 
			
		||||
        var project = new ProjectEntity();
 | 
			
		||||
        project.setId(1);
 | 
			
		||||
        project.setComment("comment");
 | 
			
		||||
        project.setContractor(1);
 | 
			
		||||
        project.setContractorName("contractorName");
 | 
			
		||||
        project.setEndDate(LocalDate.of(2024, 1, 1));
 | 
			
		||||
        project.setLeadingEmployee(1);
 | 
			
		||||
        project.setName("name");
 | 
			
		||||
        project.setStartDate(LocalDate.of(2021, 1, 1));
 | 
			
		||||
        project.setEmployees(List.of(1L, 2L, 3L));
 | 
			
		||||
        this.projectRepository.save(project);
 | 
			
		||||
 | 
			
		||||
        this.mockMvc.perform(get("/projects/1"))
 | 
			
		||||
                .andExpect(status().isOk())
 | 
			
		||||
                .andExpect(jsonPath("id").value(1))
 | 
			
		||||
                .andExpect(jsonPath("comment").value("comment"))
 | 
			
		||||
                .andExpect(jsonPath("contractor").value(1))
 | 
			
		||||
                .andExpect(jsonPath("contractor_name").value("contractorName"))
 | 
			
		||||
                .andExpect(jsonPath("end_date").value("01.01.2024"))
 | 
			
		||||
                .andExpect(jsonPath("leading_employee").value(1))
 | 
			
		||||
                .andExpect(jsonPath("name").value("name"))
 | 
			
		||||
                .andExpect(jsonPath("start_date").value("01.01.2021"))
 | 
			
		||||
                .andExpect(jsonPath("employees").isArray())
 | 
			
		||||
                .andExpect(jsonPath("employees", hasSize(3)));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
package de.szut.lf8_starter.integration.project;
 | 
			
		||||
 | 
			
		||||
import de.szut.lf8_starter.project.ProjectEntity;
 | 
			
		||||
import de.szut.lf8_starter.project.ProjectRepository;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
 | 
			
		||||
import org.springframework.boot.test.context.SpringBootTest;
 | 
			
		||||
import org.springframework.test.web.servlet.MockMvc;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDate;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
 | 
			
		||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 | 
			
		||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
 | 
			
		||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 | 
			
		||||
 | 
			
		||||
@SpringBootTest
 | 
			
		||||
@AutoConfigureMockMvc(addFilters = false)
 | 
			
		||||
class GetProjectActionTest {
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private MockMvc mockMvc;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private ProjectRepository projectRepository;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void getProjectTest() throws Exception {
 | 
			
		||||
        var project = new ProjectEntity();
 | 
			
		||||
        project.setId(1);
 | 
			
		||||
        project.setComment("comment");
 | 
			
		||||
        project.setContractor(1);
 | 
			
		||||
        project.setContractorName("contractorName");
 | 
			
		||||
        project.setEndDate(LocalDate.of(2024, 1, 1));
 | 
			
		||||
        project.setLeadingEmployee(1);
 | 
			
		||||
        project.setName("name");
 | 
			
		||||
        project.setStartDate(LocalDate.of(2021, 1, 1));
 | 
			
		||||
        project.setEmployees(List.of(1L, 2L, 3L));
 | 
			
		||||
        this.projectRepository.save(project);
 | 
			
		||||
 | 
			
		||||
        this.mockMvc.perform(get("/projects/1"))
 | 
			
		||||
                .andExpect(status().isOk())
 | 
			
		||||
                .andExpect(jsonPath("id").value(1))
 | 
			
		||||
                .andExpect(jsonPath("comment").value("comment"))
 | 
			
		||||
                .andExpect(jsonPath("contractor").value(1))
 | 
			
		||||
                .andExpect(jsonPath("contractor_name").value("contractorName"))
 | 
			
		||||
                .andExpect(jsonPath("end_date").value("01.01.2024"))
 | 
			
		||||
                .andExpect(jsonPath("leading_employee").value(1))
 | 
			
		||||
                .andExpect(jsonPath("name").value("name"))
 | 
			
		||||
                .andExpect(jsonPath("start_date").value("01.01.2021"))
 | 
			
		||||
                .andExpect(jsonPath("employees").isArray())
 | 
			
		||||
                .andExpect(jsonPath("employees", hasSize(3)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void getProjectShouldReturnNotFoundResponseWhenProjectIsNotFound() throws Exception {
 | 
			
		||||
        this.mockMvc.perform(get("/projects/2")).andExpect(status().isNotFound());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,140 @@
 | 
			
		|||
package de.szut.lf8_starter.integration.project;
 | 
			
		||||
 | 
			
		||||
import de.szut.lf8_starter.project.ProjectEntity;
 | 
			
		||||
import de.szut.lf8_starter.project.ProjectRepository;
 | 
			
		||||
import org.json.JSONObject;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
 | 
			
		||||
import org.springframework.boot.test.context.SpringBootTest;
 | 
			
		||||
import org.springframework.http.MediaType;
 | 
			
		||||
import org.springframework.test.web.servlet.MockMvc;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDate;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThat;
 | 
			
		||||
import static org.hamcrest.Matchers.is;
 | 
			
		||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
 | 
			
		||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
 | 
			
		||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 | 
			
		||||
 | 
			
		||||
@SpringBootTest
 | 
			
		||||
@AutoConfigureMockMvc(addFilters = false)
 | 
			
		||||
class UpdateProjectActionTest {
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private MockMvc mockMvc;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private ProjectRepository projectRepository;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void updateProjectShouldUpdateProject() throws Exception {
 | 
			
		||||
        ProjectEntity project = new ProjectEntity();
 | 
			
		||||
        project.setId(1);
 | 
			
		||||
        project.setComment("comment");
 | 
			
		||||
        project.setContractor(1);
 | 
			
		||||
        project.setContractorName("contractorName");
 | 
			
		||||
        project.setEndDate(LocalDate.of(2024, 1, 1));
 | 
			
		||||
        project.setLeadingEmployee(1);
 | 
			
		||||
        project.setName("name");
 | 
			
		||||
        project.setStartDate(LocalDate.of(2021, 1, 1));
 | 
			
		||||
        project.setEmployees(List.of(1L, 2L, 3L));
 | 
			
		||||
        this.projectRepository.save(project);
 | 
			
		||||
 | 
			
		||||
        String content = """
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "updatedName",
 | 
			
		||||
                    "leading_employee": 2,
 | 
			
		||||
                    "employees": [3, 4, 5],
 | 
			
		||||
                    "contractor": 6,
 | 
			
		||||
                    "contractor_name": "Updated Contractor name",
 | 
			
		||||
                    "comment": "new goal of project",
 | 
			
		||||
                    "start_date": "01.01.2021",
 | 
			
		||||
                    "planned_end_date": "01.01.2022"
 | 
			
		||||
                  }
 | 
			
		||||
                """;
 | 
			
		||||
 | 
			
		||||
        final var contentAsString = this.mockMvc.perform(
 | 
			
		||||
                        put("/projects/1").content(content).contentType(MediaType.APPLICATION_JSON)
 | 
			
		||||
                )
 | 
			
		||||
                .andExpect(status().isOk())
 | 
			
		||||
                .andExpect(jsonPath("name", is("updatedName")))
 | 
			
		||||
                .andExpect(jsonPath("leading_employee", is(2)))
 | 
			
		||||
                .andExpect(jsonPath("employees", is(Arrays.asList(3, 4, 5))))
 | 
			
		||||
                .andExpect(jsonPath("contractor", is(6)))
 | 
			
		||||
                .andExpect(jsonPath("contractor_name", is("Updated Contractor name")))
 | 
			
		||||
                .andExpect(jsonPath("comment", is("new goal of project")))
 | 
			
		||||
                .andExpect(jsonPath("start_date", is("01.01.2021")))
 | 
			
		||||
                .andExpect(jsonPath("planned_end_date", is("01.01.2022")))
 | 
			
		||||
                .andReturn()
 | 
			
		||||
                .getResponse()
 | 
			
		||||
                .getContentAsString();
 | 
			
		||||
 | 
			
		||||
        final var id = Long.parseLong(new JSONObject(contentAsString).get("id").toString());
 | 
			
		||||
 | 
			
		||||
        final var existingProject = this.projectRepository.findById(id);
 | 
			
		||||
        assertThat(existingProject.get().getName()).isEqualTo("updatedName");
 | 
			
		||||
        assertThat(existingProject.get().getLeadingEmployee()).isEqualTo(2);
 | 
			
		||||
        assertThat(existingProject.get().getContractor()).isEqualTo(6);
 | 
			
		||||
        assertThat(existingProject.get().getContractorName()).isEqualTo("Updated Contractor name");
 | 
			
		||||
        assertThat(existingProject.get().getComment()).isEqualTo("new goal of project");
 | 
			
		||||
        assertThat(existingProject.get().getStartDate()).isEqualTo(LocalDate.of(2021, 1, 1));
 | 
			
		||||
        assertThat(existingProject.get().getPlannedEndDate()).isEqualTo(LocalDate.of(2022, 1, 1));
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void updateProjectShouldUpdateProjectPartially() throws Exception {
 | 
			
		||||
        ProjectEntity project = new ProjectEntity();
 | 
			
		||||
        project.setId(1);
 | 
			
		||||
        project.setName("name");
 | 
			
		||||
        project.setLeadingEmployee(1);
 | 
			
		||||
        project.setContractor(1);
 | 
			
		||||
        project.setComment("comment");
 | 
			
		||||
        project.setEmployees(List.of(1L, 2L, 3L));
 | 
			
		||||
        project.setContractorName("contractorName");
 | 
			
		||||
        project.setStartDate(LocalDate.of(2021, 1, 1));
 | 
			
		||||
        project.setPlannedEndDate(LocalDate.of(2023, 1, 1));
 | 
			
		||||
        project.setEndDate(LocalDate.of(2024, 1, 1));
 | 
			
		||||
        this.projectRepository.save(project);
 | 
			
		||||
 | 
			
		||||
        String content = """
 | 
			
		||||
                {}
 | 
			
		||||
                """;
 | 
			
		||||
 | 
			
		||||
        final var contentAsString = this.mockMvc.perform(
 | 
			
		||||
                        put("/projects/1").content(content).contentType(MediaType.APPLICATION_JSON)
 | 
			
		||||
                )
 | 
			
		||||
                .andExpect(status().isOk())
 | 
			
		||||
                .andExpect(jsonPath("name", is("name")))
 | 
			
		||||
                .andExpect(jsonPath("leading_employee", is(1)))
 | 
			
		||||
                .andExpect(jsonPath("employees", is(List.of(1,2,3))))
 | 
			
		||||
                .andExpect(jsonPath("contractor", is(1)))
 | 
			
		||||
                .andExpect(jsonPath("contractor_name", is("contractorName")))
 | 
			
		||||
                .andExpect(jsonPath("comment", is("comment")))
 | 
			
		||||
                .andExpect(jsonPath("start_date", is("01.01.2021")))
 | 
			
		||||
                .andExpect(jsonPath("planned_end_date", is("01.01.2023")))
 | 
			
		||||
                .andExpect(jsonPath("end_date", is("01.01.2024")))
 | 
			
		||||
                .andReturn()
 | 
			
		||||
                .getResponse()
 | 
			
		||||
                .getContentAsString();
 | 
			
		||||
 | 
			
		||||
        final var id = Long.parseLong(new JSONObject(contentAsString).get("id").toString());
 | 
			
		||||
 | 
			
		||||
        final var existingProject = this.projectRepository.findById(id);
 | 
			
		||||
        assertThat(existingProject.get().getName()).isEqualTo("name");
 | 
			
		||||
        assertThat(existingProject.get().getLeadingEmployee()).isEqualTo(1);
 | 
			
		||||
        assertThat(existingProject.get().getContractor()).isEqualTo(1);
 | 
			
		||||
        assertThat(existingProject.get().getContractorName()).isEqualTo("contractorName");
 | 
			
		||||
        assertThat(existingProject.get().getComment()).isEqualTo("comment");
 | 
			
		||||
        assertThat(existingProject.get().getStartDate()).isEqualTo(LocalDate.of(2021, 1, 1));
 | 
			
		||||
        assertThat(existingProject.get().getPlannedEndDate()).isEqualTo(LocalDate.of(2023, 1, 1));
 | 
			
		||||
        assertThat(existingProject.get().getEndDate()).isEqualTo(LocalDate.of(2024, 1, 1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    void updateProjectShouldReturnNotFoundResponseWhenProjectIsNotFound() throws Exception {
 | 
			
		||||
        this.mockMvc.perform(put("/projects/2").content("{}").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isNotFound());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in a new issue