first commit
This commit is contained in:
commit
d46130d303
2
.gitattributes
vendored
Executable file
2
.gitattributes
vendored
Executable file
@ -0,0 +1,2 @@
|
||||
/mvnw text eol=lf
|
||||
*.cmd text eol=crlf
|
||||
140
.gitignore
vendored
Normal file
140
.gitignore
vendored
Normal file
@ -0,0 +1,140 @@
|
||||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### MAC ###
|
||||
.DS_Store
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
# ---> Java
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
replay_pid*
|
||||
|
||||
# ---> JetBrains
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
.idea/compiler.xml
|
||||
.idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
*.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
.env
|
||||
.idea/
|
||||
.run/
|
||||
**/static/images/uplaod
|
||||
19
.mvn/wrapper/maven-wrapper.properties
vendored
Executable file
19
.mvn/wrapper/maven-wrapper.properties
vendored
Executable file
@ -0,0 +1,19 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
wrapperVersion=3.3.2
|
||||
distributionType=only-script
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
|
||||
49
Dockerfile
Normal file
49
Dockerfile
Normal file
@ -0,0 +1,49 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
FROM maven:3-eclipse-temurin-23-alpine AS dependency
|
||||
WORKDIR /app
|
||||
COPY pom.xml ./
|
||||
COPY domain/pom.xml domain/
|
||||
COPY domain/spi/pom.xml domain/spi/
|
||||
COPY domain/api/pom.xml domain/api/
|
||||
COPY domain/service/pom.xml domain/service/
|
||||
COPY domain/data/pom.xml domain/data/
|
||||
COPY application/pom.xml application/
|
||||
COPY infrastructure/pom.xml infrastructure/
|
||||
COPY bootstrap/pom.xml bootstrap/
|
||||
COPY common/pom.xml common/
|
||||
ARG XPEDITIS_PROFILE
|
||||
RUN mvn -P${XPEDITIS_PROFILE} dependency:go-offline \
|
||||
&& mvn dependency:get -Dartifact=net.bytebuddy:byte-buddy-agent:1.15.11 -B \
|
||||
&& mvn dependency:get -Dartifact=org.mapstruct:mapstruct-processor:1.6.3 -B \
|
||||
&& mvn dependency:get -Dartifact=org.projectlombok:lombok-mapstruct-binding:0.2.0 -B \
|
||||
&& mvn dependency:get -Dartifact=com.mysql:mysql-connector-j:9.1.0 -B \
|
||||
&& mvn dependency:get -Dartifact=org.flywaydb:flyway-core:10.20.1 -B \
|
||||
&& mvn dependency:get -Dartifact=org.flywaydb:flyway-mysql:10.20.1 -B
|
||||
|
||||
FROM dependency AS builder
|
||||
COPY domain/spi/src domain/spi/src
|
||||
COPY domain/api/src domain/api/src
|
||||
COPY domain/service/src domain/service/src
|
||||
COPY domain/data/src domain/data/src
|
||||
COPY application/src application/src
|
||||
COPY infrastructure/src infrastructure/src
|
||||
COPY bootstrap/src bootstrap/src
|
||||
COPY common/src common/src
|
||||
ARG XPEDITIS_PROFILE
|
||||
RUN mvn -o clean package -P${XPEDITIS_PROFILE} -Dmaven.test.skip=true -DskipTests
|
||||
|
||||
#FROM builder AS test
|
||||
#RUN mvn -o clean test
|
||||
|
||||
FROM eclipse-temurin:23-jdk-alpine AS production
|
||||
WORKDIR /opt/app
|
||||
EXPOSE 8080
|
||||
COPY --from=builder /app/bootstrap/target/bootstrap*.jar xpeditis.jar
|
||||
COPY wait-for-it.sh ./
|
||||
RUN chmod +x wait-for-it.sh
|
||||
COPY entrypoint.sh ./
|
||||
RUN chmod +x entrypoint.sh
|
||||
ENTRYPOINT ["./entrypoint.sh"]
|
||||
#CMD ["java", "-jar", "-Dserver.port=8080", "leblr.jar"]
|
||||
#HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "curl", "--fail", "http://localhost:8080/actuator/health", "|| exit 1" ]
|
||||
36
Dockerfile-springboot
Normal file
36
Dockerfile-springboot
Normal file
@ -0,0 +1,36 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
FROM eclipse-temurin:23-jdk AS dependency
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY .mvn/ .mvn
|
||||
COPY mvnw ./
|
||||
|
||||
COPY pom.xml ./
|
||||
COPY domain/pom.xml domain/
|
||||
COPY domain/spi/pom.xml domain/spi/
|
||||
COPY domain/api/pom.xml domain/api/
|
||||
COPY domain/service/pom.xml domain/service/
|
||||
COPY domain/data/pom.xml domain/data/
|
||||
COPY application/pom.xml application/
|
||||
COPY infrastructure/pom.xml infrastructure/
|
||||
COPY bootstrap/pom.xml bootstrap/
|
||||
COPY common/pom.xml common/
|
||||
ARG XPEDITIS_PROFILE
|
||||
RUN ./mvnw -P${XPEDITIS_PROFILE} dependency:go-offline \
|
||||
&& ./mvnw dependency:get -Dartifact=net.bytebuddy:byte-buddy-agent:1.15.11 -B \
|
||||
&& ./mvnw dependency:get -Dartifact=org.mapstruct:mapstruct-processor:1.6.3 -B \
|
||||
&& ./mvnw dependency:get -Dartifact=org.projectlombok:lombok-mapstruct-binding:0.2.0 -B
|
||||
|
||||
FROM dependency AS production
|
||||
COPY domain/spi/src domain/spi/src
|
||||
COPY domain/api/src domain/api/src
|
||||
COPY domain/service/src domain/service/src
|
||||
COPY domain/data/src domain/data/src
|
||||
COPY application/src application/src
|
||||
COPY infrastructure/src infrastructure/src
|
||||
COPY bootstrap/src bootstrap/src
|
||||
COPY common/src common/src
|
||||
|
||||
CMD ["./mvnw", "spring-boot:run"]
|
||||
7
README.md
Normal file
7
README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# leblr-backend
|
||||
|
||||
Le BLR backend side<br>
|
||||
SWAGGER UI : http://localhost:8080/swagger-ui.html<br>
|
||||
<br>
|
||||
.\mvnw clean install flyway:migrate -Pprod<br>
|
||||
.\mvnw clean install flyway:migrate '-Dflyway.configFiles=flyway-h2.conf' -Pdev<br>
|
||||
68
application/pom.xml
Executable file
68
application/pom.xml
Executable file
@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>xpeditis</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>application</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- spring-boot dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<version>2.8.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${org.projectlombok.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@ -0,0 +1,83 @@
|
||||
package com.dh7789dev.xpeditis.advice;
|
||||
|
||||
import com.dh7789dev.xpeditis.NlsService;
|
||||
import com.dh7789dev.xpeditis.dto.CustomInternalExceptionResponse;
|
||||
import com.dh7789dev.xpeditis.exception.CustomInternalException;
|
||||
import com.dh7789dev.xpeditis.exception.GlobalNotFoundException;
|
||||
import com.dh7789dev.xpeditis.exception.StorageException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Slf4j
|
||||
//@Order(1)
|
||||
@RestControllerAdvice(basePackages = {"com.dh7789dev.xpeditis.controller"} )
|
||||
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
|
||||
private static final String INTERNAL_ERROR = "internal.error";
|
||||
|
||||
private final NlsService nlsService;
|
||||
|
||||
@Autowired
|
||||
public GlobalExceptionHandler(NlsService nlsService) {
|
||||
this.nlsService = nlsService;
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = {IllegalArgumentException.class})
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public String handleIllegalArgumentException(HttpServletRequest req, IllegalArgumentException ex) {
|
||||
return nlsService.getMessage("error.invalid.argument");
|
||||
}
|
||||
|
||||
@ExceptionHandler(StorageException.class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public CustomInternalExceptionResponse handleFileStorageException(HttpServletRequest req, StorageException ex) {
|
||||
return new CustomInternalExceptionResponse(
|
||||
(String) req.getAttribute("request_id"),
|
||||
"StorageError",
|
||||
ex.getMessage(),
|
||||
req.getRequestURL().toString());
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public CustomInternalExceptionResponse handleUnknownException(HttpServletRequest req, Exception ex) {
|
||||
CustomInternalExceptionResponse response = new CustomInternalExceptionResponse();
|
||||
response.setErrorCode(nlsService.getMessage(INTERNAL_ERROR));
|
||||
response.setErrorMessage(ex.getMessage());
|
||||
response.setRequestURL(req.getRequestURL().toString());
|
||||
response.setTimestamp(Instant.now());
|
||||
response.setId((String) req.getAttribute("request_id"));
|
||||
return response;
|
||||
}
|
||||
|
||||
@ExceptionHandler(CustomInternalException.class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public CustomInternalExceptionResponse handleCustomInternalException(HttpServletRequest req, CustomInternalException ex) {
|
||||
CustomInternalExceptionResponse response = new CustomInternalExceptionResponse();
|
||||
response.setErrorCode(nlsService.getMessage(ex.getNlsKey(), ex.getNlsParameters()));
|
||||
response.setErrorMessage(ex.getMessage());
|
||||
response.setRequestURL(req.getRequestURL().toString());
|
||||
response.setTimestamp(Instant.now());
|
||||
response.setId((String) req.getAttribute("request_id"));
|
||||
return response;
|
||||
}
|
||||
|
||||
@ExceptionHandler(GlobalNotFoundException.class)
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
//@ResponseBody
|
||||
public CustomInternalExceptionResponse globalNotFoundHandler(HttpServletRequest req, GlobalNotFoundException ex) {
|
||||
return new CustomInternalExceptionResponse(
|
||||
(String) req.getAttribute("request_id"),
|
||||
ex.getErrorCode(),
|
||||
ex.getMessage(),
|
||||
req.getRequestURL().toString());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.dh7789dev.xpeditis.controller;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(name = "/",
|
||||
produces = APPLICATION_JSON_VALUE)
|
||||
public class IndexRestController {
|
||||
|
||||
@Value("${spring.application.name}")
|
||||
String name;
|
||||
|
||||
@Value("${spring.application.version}")
|
||||
String version;
|
||||
|
||||
@Value("${spring.profiles.active}")
|
||||
String springProfile;
|
||||
|
||||
public record ServiceInformation(String name,
|
||||
String version,
|
||||
@JsonProperty("spring profile") String springProfile) {
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<ServiceInformation> index() {
|
||||
return ResponseEntity.ok(new ServiceInformation(name, version, springProfile));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
package com.dh7789dev.xpeditis.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
|
||||
|
||||
@Controller
|
||||
public class UploadController {
|
||||
|
||||
@Value("${file.upload-dir}")
|
||||
String uploadDir;
|
||||
|
||||
private final EventService eventService;
|
||||
|
||||
private final GalleryService galleryService;
|
||||
|
||||
public UploadController(EventService eventService, GalleryService galleryService) {
|
||||
this.eventService = eventService;
|
||||
this.galleryService = galleryService;
|
||||
}
|
||||
|
||||
@GetMapping("/uploadimage")
|
||||
public String displayUploadForm() {
|
||||
return "addImages";
|
||||
}
|
||||
|
||||
@PostMapping(value = "/upload/{eventId}", consumes = MULTIPART_FORM_DATA_VALUE)
|
||||
public String uploadImage(Model model,
|
||||
@PathVariable long eventId,
|
||||
@RequestParam("images") List<MultipartFile> images) {
|
||||
|
||||
eventService.addImages(eventId, images);
|
||||
StringBuilder fileNames = new StringBuilder();
|
||||
images.forEach(image -> fileNames.append(image.getOriginalFilename()).append(" "));
|
||||
model.addAttribute("msg", "Uploaded images: " + fileNames);
|
||||
return "addImages";
|
||||
}
|
||||
|
||||
@PostMapping(value = "/upload/gallery/{galleryId}", consumes = MULTIPART_FORM_DATA_VALUE)
|
||||
public String uploadImageToGallery(Model model,
|
||||
@PathVariable long galleryId,
|
||||
@RequestParam("images") List<MultipartFile> images) {
|
||||
|
||||
galleryService.addImages(galleryId, images);
|
||||
StringBuilder fileNames = new StringBuilder();
|
||||
images.forEach(image -> fileNames.append(image.getOriginalFilename()).append(" "));
|
||||
model.addAttribute("msg", "Uploaded images: " + fileNames);
|
||||
return "addImages";
|
||||
}
|
||||
|
||||
@GetMapping("/addevent")
|
||||
public String displayUploadFormToAddEvent() {
|
||||
return "addEvent";
|
||||
}
|
||||
|
||||
@PostMapping(value = "/upload", consumes = MULTIPART_FORM_DATA_VALUE)
|
||||
public String addEvent(Model model,
|
||||
@RequestPart("newEvent") Event newEvent,
|
||||
@RequestPart("images") List<MultipartFile> images) {
|
||||
eventService.addEvent(newEvent, images);
|
||||
StringBuilder fileNames = new StringBuilder();
|
||||
images.forEach(image -> fileNames.append(image.getOriginalFilename()).append(" "));
|
||||
model.addAttribute("msg", "Uploaded images: " + fileNames);
|
||||
return "addEvent";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.dh7789dev.xpeditis.controller.api.v1;
|
||||
|
||||
import com.dh7789dev.xpeditis.AuthenticationService;
|
||||
import com.dh7789dev.xpeditis.dto.AuthenticationRequest;
|
||||
import com.dh7789dev.xpeditis.dto.AuthenticationResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = "${apiPrefix}/api/v1/auth",
|
||||
produces = APPLICATION_JSON_VALUE)
|
||||
@RequiredArgsConstructor
|
||||
public class AuthenticationRestController {
|
||||
|
||||
private final AuthenticationService service;
|
||||
|
||||
@PostMapping("/authenticate")
|
||||
public ResponseEntity<AuthenticationResponse> authenticate(
|
||||
@RequestBody @Valid AuthenticationRequest request) {
|
||||
return ResponseEntity.ok(service.authenticate(request));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package com.dh7789dev.xpeditis.controller.api.v1;
|
||||
|
||||
import com.dh7789dev.xpeditis.UserService;
|
||||
import com.dh7789dev.xpeditis.dto.ChangePasswordRequest;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||
|
||||
@RestController
|
||||
@Validated
|
||||
@RequestMapping(value = "${apiPrefix}/api/v1/users",
|
||||
produces = APPLICATION_JSON_VALUE)
|
||||
public class UserRestController {
|
||||
|
||||
private final UserService service;
|
||||
|
||||
public UserRestController(UserService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@Operation(summary = "Change password of the connected user")
|
||||
@PatchMapping("/password")
|
||||
public ResponseEntity<Void> changePassword(
|
||||
@RequestBody ChangePasswordRequest request,
|
||||
Principal connectedUser) {
|
||||
service.changePassword(request, connectedUser);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
1
application/src/main/java/lombok.config
Executable file
1
application/src/main/java/lombok.config
Executable file
@ -0,0 +1 @@
|
||||
lombok.addLombokGeneratedAnnotation = true
|
||||
128
bootstrap/pom.xml
Executable file
128
bootstrap/pom.xml
Executable file
@ -0,0 +1,128 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>xpeditis</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>bootstrap</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<description>Xpeditis</description>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>23</maven.compiler.source>
|
||||
<maven.compiler.target>23</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>application</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>service</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>infrastructure</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>dev</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<properties>
|
||||
<spring.profiles.active>dev</spring.profiles.active>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>prod</id>
|
||||
<properties>
|
||||
<spring.profiles.active>prod</spring.profiles.active>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
<finalName>${project.name}</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>false</skip>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
27
bootstrap/src/main/java/com/dh7789dev/xpeditis/XpeditisApplication.java
Executable file
27
bootstrap/src/main/java/com/dh7789dev/xpeditis/XpeditisApplication.java
Executable file
@ -0,0 +1,27 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
|
||||
@ComponentScan(basePackages = {"com.dh7789dev.xpeditis"})
|
||||
@EnableJpaRepositories("com.dh7789dev.xpeditis.dao")
|
||||
@EntityScan("com.dh7789dev.xpeditis.entity")
|
||||
@EnableJpaAuditing(auditorAwareRef = "auditorProvider")
|
||||
@SpringBootApplication
|
||||
public class XpeditisApplication extends SpringBootServletInitializer {
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder applicationBuilder) {
|
||||
return applicationBuilder.sources(XpeditisApplication.class);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(XpeditisApplication.class, args);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
package com.dh7789dev.xpeditis.configuration;
|
||||
|
||||
import com.dh7789dev.xpeditis.dao.UserDao;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CommonsRequestLoggingFilter;
|
||||
import org.springframework.web.servlet.LocaleResolver;
|
||||
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
|
||||
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
@EnableAsync
|
||||
public class GlobalConfiguration {
|
||||
|
||||
private static final String USER_NOT_FOUND_MSG = "User %s not found";
|
||||
|
||||
private final UserDao userDao;
|
||||
|
||||
public GlobalConfiguration(UserDao userDao) {
|
||||
this.userDao = userDao;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CommonsRequestLoggingFilter loggingFilter() {
|
||||
CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();
|
||||
filter.setIncludeQueryString(true);
|
||||
filter.setIncludePayload(true);
|
||||
filter.setIncludeClientInfo(true);
|
||||
filter.setMaxPayloadLength(10000);
|
||||
filter.setIncludeHeaders(false);
|
||||
return filter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageSource messageSource() {
|
||||
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
|
||||
messageSource.setBasename("classpath:language/i18n");
|
||||
messageSource.setDefaultEncoding("UTF-8");
|
||||
messageSource.setDefaultLocale(Locale.FRANCE);
|
||||
messageSource.setUseCodeAsDefaultMessage(true);
|
||||
// Refresh cache once every hour
|
||||
messageSource.setCacheSeconds(3600);
|
||||
return messageSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LocaleResolver localeResolver() {
|
||||
// Can be Fixed, AcceptHeader, Session or Cookie
|
||||
CookieLocaleResolver localeResolver = new CookieLocaleResolver();
|
||||
localeResolver.setDefaultLocale(Locale.FRANCE);
|
||||
localeResolver.setDefaultTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
return localeResolver;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LocaleChangeInterceptor localeChangeInterceptor() {
|
||||
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
|
||||
// Example: ?lang=en
|
||||
localeChangeInterceptor.setParamName("lang");
|
||||
return localeChangeInterceptor;
|
||||
}
|
||||
|
||||
@Bean
|
||||
UrlBasedCorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
//configuration.setAllowCredentials(true);
|
||||
configuration.setAllowedOrigins(List.of("http://localhost:8080", "http://localhost:3000",
|
||||
"http://127.0.0.1:8080", "https://leblr.preprod.weworkstudio.fr","https://leblr.fr",
|
||||
"https://api.leblr.preprod.weworkstudio.fr/","https://api.leblr.fr/", "https://www.leblr.fr"));
|
||||
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH"));
|
||||
configuration.setAllowedHeaders(List.of("*"));
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", configuration);
|
||||
return source;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UserDetailsService userDetailsService() {
|
||||
return username -> userDao.findByUsername(username)
|
||||
.orElseThrow(() -> new UsernameNotFoundException(String.format(USER_NOT_FOUND_MSG, username)));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package com.dh7789dev.xpeditis.configuration;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
||||
|
||||
@Configuration
|
||||
public class InterceptorConfiguration implements WebMvcConfigurer {
|
||||
|
||||
private final LocaleChangeInterceptor localeChangeInterceptor;
|
||||
|
||||
private final RequestIdInterceptor requestIdInterceptor;
|
||||
|
||||
@Autowired
|
||||
public InterceptorConfiguration(LocaleChangeInterceptor localeChangeInterceptor,
|
||||
RequestIdInterceptor requestIdInterceptor) {
|
||||
this.localeChangeInterceptor = localeChangeInterceptor;
|
||||
this.requestIdInterceptor = requestIdInterceptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
final String[] excluded = {"/error"};
|
||||
registry.addInterceptor(localeChangeInterceptor)
|
||||
.excludePathPatterns(excluded);
|
||||
registry.addInterceptor(requestIdInterceptor)
|
||||
.excludePathPatterns(excluded);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
package com.dh7789dev.xpeditis.configuration;
|
||||
|
||||
import com.dh7789dev.xpeditis.dao.TokenDao;
|
||||
import com.dh7789dev.xpeditis.util.JwtUtil;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
private static final String AUTH_HEADER = "Authorization";
|
||||
private static final String AUTH_TYPE = "Bearer ";
|
||||
|
||||
private final UserDetailsService userDetailsService;
|
||||
private final JwtUtil jwtUtil;
|
||||
private final TokenDao tokenDao;
|
||||
|
||||
public JwtAuthenticationFilter(UserDetailsService userDetailsService, JwtUtil jwtUtil, TokenDao tokenDao) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
this.jwtUtil = jwtUtil;
|
||||
this.tokenDao = tokenDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(
|
||||
@NonNull HttpServletRequest request,
|
||||
@NonNull HttpServletResponse response,
|
||||
@NonNull FilterChain filterChain
|
||||
) throws ServletException, IOException {
|
||||
|
||||
final String jwt;
|
||||
final String username;
|
||||
|
||||
if (request.getServletPath().contains("/api/v1/auth")) {
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
final String authHeader = request.getHeader(AUTH_HEADER);
|
||||
if (authHeader == null || !authHeader.startsWith(AUTH_TYPE)) {
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
jwt = authHeader.substring(AUTH_TYPE.length()).trim();
|
||||
username = jwtUtil.extractUsername(jwt);
|
||||
|
||||
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
||||
|
||||
boolean isTokenValid = tokenDao.findByToken(jwt)
|
||||
.map(t -> !t.isExpired() && !t.isRevoked())
|
||||
.orElse(false);
|
||||
if (isTokenValid && jwtUtil.isTokenValid(jwt, userDetails)) {
|
||||
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
|
||||
userDetails,
|
||||
null,
|
||||
userDetails.getAuthorities()
|
||||
);
|
||||
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
SecurityContextHolder.getContext().setAuthentication(authToken);
|
||||
} else {
|
||||
throw new UsernameNotFoundException("Failed to authenticate with access token");
|
||||
}
|
||||
}
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package com.dh7789dev.xpeditis.configuration;
|
||||
|
||||
import com.dh7789dev.xpeditis.dao.TokenDao;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class LogoutService implements LogoutHandler {
|
||||
|
||||
private final TokenDao tokenDao;
|
||||
|
||||
@Override
|
||||
public void logout(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
Authentication authentication) {
|
||||
final String authHeader = request.getHeader("Authorization");
|
||||
final String jwt;
|
||||
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
||||
return;
|
||||
}
|
||||
jwt = authHeader.substring(7);
|
||||
var storedToken = tokenDao.findByToken(jwt)
|
||||
.orElse(null);
|
||||
if (storedToken != null) {
|
||||
storedToken.setExpired(true);
|
||||
storedToken.setRevoked(true);
|
||||
tokenDao.save(storedToken);
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.dh7789dev.xpeditis.configuration;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Component
|
||||
public class RequestIdInterceptor implements HandlerInterceptor {
|
||||
|
||||
private static final String REQUEST_ID = "request_id";
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
final String requestId = UUID.randomUUID().toString();
|
||||
MDC.put(REQUEST_ID, requestId);
|
||||
request.setAttribute(REQUEST_ID, requestId);
|
||||
return HandlerInterceptor.super.preHandle(request, response, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
MDC.clear();
|
||||
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,128 @@
|
||||
package com.dh7789dev.xpeditis.configuration;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||
|
||||
import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS;
|
||||
import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
//@EnableMethodSecurity
|
||||
public class SecurityConfiguration {
|
||||
|
||||
@Value("${application.csrf.enabled}")
|
||||
boolean csrfEnabled;
|
||||
|
||||
private static final String ADMIN_ROLE = "ADMIN";
|
||||
|
||||
private static final String API_V1_URI = "/api/v1/**";
|
||||
|
||||
private static final String[] WHITE_LIST_URL = {
|
||||
"/api/v1/auth/**",
|
||||
"/actuator/health/**"};
|
||||
|
||||
private static final String[] INTERNAL_WHITE_LIST_URL = {
|
||||
"/v2/api-docs",
|
||||
"/v3/api-docs",
|
||||
"/v3/api-docs/**",
|
||||
"/swagger-resources",
|
||||
"/swagger-resources/**",
|
||||
"/configuration/ui",
|
||||
"/configuration/security",
|
||||
"/swagger-ui/**",
|
||||
"/webjars/**",
|
||||
"/swagger-ui.html",
|
||||
"/uploadimage",
|
||||
"/upload/**",
|
||||
"/addevent"};
|
||||
|
||||
private static final WebExpressionAuthorizationManager INTERNAL_ACCESS =
|
||||
new WebExpressionAuthorizationManager("hasIpAddress('127.0.0.1') or hasIpAddress('0:0:0:0:0:0:0:1')");
|
||||
|
||||
private final UserDetailsService userDetailsService;
|
||||
|
||||
private final LogoutHandler logoutHandler;
|
||||
|
||||
@Autowired
|
||||
public SecurityConfiguration(UserDetailsService userDetailsService, LogoutHandler logoutHandler) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
this.logoutHandler = logoutHandler;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
|
||||
return configuration.getAuthenticationManager();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationProvider authenticationProvider() {
|
||||
final DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setPasswordEncoder(passwordEncoder());
|
||||
provider.setUserDetailsService(userDetailsService);
|
||||
return provider;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtAuthenticationFilter jwtAuthFilter) throws Exception {
|
||||
|
||||
if (csrfEnabled) {
|
||||
http.csrf(csrf -> csrf.ignoringRequestMatchers(antMatcher("/h2-console/**")));
|
||||
} else {
|
||||
// csrf is disabled for dev and test
|
||||
http.csrf(AbstractHttpConfigurer::disable);
|
||||
}
|
||||
http.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin));
|
||||
http.authorizeHttpRequests(auth ->
|
||||
auth.requestMatchers(WHITE_LIST_URL).permitAll()
|
||||
.requestMatchers(antMatcher(HttpMethod.GET, "/")).permitAll()
|
||||
.requestMatchers(antMatcher(HttpMethod.GET, API_V1_URI)).permitAll()
|
||||
.requestMatchers(antMatcher(HttpMethod.GET, "/images/**")).permitAll()
|
||||
.requestMatchers(antMatcher(HttpMethod.GET, "/api/v1/reservations")).hasRole(ADMIN_ROLE)
|
||||
.requestMatchers(antMatcher(HttpMethod.GET, "/api/v1/reservations/**")).hasRole(ADMIN_ROLE)
|
||||
.requestMatchers(antMatcher(HttpMethod.PUT, API_V1_URI)).hasRole(ADMIN_ROLE)
|
||||
.requestMatchers(antMatcher(HttpMethod.DELETE, API_V1_URI)).hasRole(ADMIN_ROLE)
|
||||
.requestMatchers(antMatcher(HttpMethod.POST, "/api/v1/reservations")).permitAll()
|
||||
.requestMatchers(antMatcher(HttpMethod.POST, API_V1_URI)).hasRole(ADMIN_ROLE)
|
||||
.requestMatchers(antMatcher("/h2-console/**")).access(INTERNAL_ACCESS)
|
||||
.requestMatchers(antMatcher("/actuator/**")).access(INTERNAL_ACCESS)
|
||||
.requestMatchers(INTERNAL_WHITE_LIST_URL).access(INTERNAL_ACCESS)
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.sessionManagement(session -> session.sessionCreationPolicy(STATELESS))
|
||||
.authenticationProvider(authenticationProvider())
|
||||
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
|
||||
.logout(logout -> logout
|
||||
.logoutUrl("/api/v1/auth/logout")
|
||||
.addLogoutHandler(logoutHandler)
|
||||
.logoutSuccessHandler((request,
|
||||
response,
|
||||
authentication) -> SecurityContextHolder.clearContext()));
|
||||
|
||||
return http.build();
|
||||
}
|
||||
}
|
||||
60
bootstrap/src/main/resources/application-dev.yml
Normal file
60
bootstrap/src/main/resources/application-dev.yml
Normal file
@ -0,0 +1,60 @@
|
||||
---
|
||||
spring:
|
||||
h2:
|
||||
console:
|
||||
enabled: 'true'
|
||||
|
||||
datasource:
|
||||
url: jdbc:h2:mem:xpeditis;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
|
||||
driverClassName: org.h2.Driver
|
||||
username: sa
|
||||
password: ''
|
||||
|
||||
sql:
|
||||
init:
|
||||
platform: h2
|
||||
mode: always
|
||||
|
||||
jpa:
|
||||
show-sql: true
|
||||
properties:
|
||||
hibernate:
|
||||
format_sql: true
|
||||
# show_sql: true
|
||||
database-platform: org.hibernate.dialect.H2Dialect
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
# Just to load initial data for the demo. DO NOT USE IT IN PRODUCTION
|
||||
defer-datasource-initialization: true
|
||||
|
||||
flyway: # flyway automatically uses the datasource from the application to connect to the DB
|
||||
enabled: false # enables flyway database migration
|
||||
|
||||
mail:
|
||||
host: sandbox.smtp.mailtrap.io
|
||||
port: 2525
|
||||
username: 2597bd31d265eb
|
||||
password: cd126234193c89
|
||||
properties:
|
||||
mail:
|
||||
smtp:
|
||||
ssl:
|
||||
trust:"*"
|
||||
auth: true
|
||||
starttls:
|
||||
enable: true
|
||||
connectiontimeout: 5000
|
||||
timeout: 3000
|
||||
writetimeout: 5000
|
||||
|
||||
application:
|
||||
email:
|
||||
from: randommailjf@gmail.com
|
||||
csrf:
|
||||
enabled: false
|
||||
security:
|
||||
jwt:
|
||||
secret-key: 404E635266556A586E3272357538782F413F4428472B4B6250645367566B5970
|
||||
expiration: 86400000 # a day
|
||||
refresh-token:
|
||||
expiration: 604800000 # 7 days
|
||||
66
bootstrap/src/main/resources/application-prod.yml
Normal file
66
bootstrap/src/main/resources/application-prod.yml
Normal file
@ -0,0 +1,66 @@
|
||||
---
|
||||
spring:
|
||||
datasource:
|
||||
url: ${SPRING_DATASOURCE_URL}
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
username: ${SPRING_DATASOURCE_USERNAME}
|
||||
password: ${SPRING_DATASOURCE_PASSWORD}
|
||||
#hikari:
|
||||
#schema: leblr
|
||||
|
||||
sql:
|
||||
init:
|
||||
platform: mysql
|
||||
mode: never
|
||||
#data-locations: import_users.sql
|
||||
|
||||
jpa:
|
||||
# show-sql: true
|
||||
properties:
|
||||
hibernate:
|
||||
format_sql: true
|
||||
#show_sql: true
|
||||
database: mysql
|
||||
database-platform: org.hibernate.dialect.MySQLDialect
|
||||
hibernate:
|
||||
ddl-auto: validate
|
||||
defer-datasource-initialization: false
|
||||
#open-in-view: false
|
||||
|
||||
flyway: # flyway automatically uses the datasource from the application to connect to the DB
|
||||
enabled: true # enables flyway database migration
|
||||
locations: classpath:db/migration/structure, classpath:db/migration/data # the location where flyway should look for migration scripts
|
||||
validate-on-migrate: true
|
||||
baseline-on-migrate: true
|
||||
baseline-version: 0
|
||||
default-schema: leblr
|
||||
|
||||
mail:
|
||||
protocol: smtp
|
||||
host: ssl0.ovh.net
|
||||
port: 587
|
||||
username: contact@xpeditis.fr
|
||||
password:
|
||||
properties:
|
||||
mail:
|
||||
smtp:
|
||||
auth: true
|
||||
starttls:
|
||||
enable: true
|
||||
connectiontimeout: 5000
|
||||
timeout: 3000
|
||||
writetimeout: 5000
|
||||
|
||||
application:
|
||||
email:
|
||||
from: contact@leblr.fr
|
||||
|
||||
csrf:
|
||||
enabled: false
|
||||
|
||||
security:
|
||||
jwt:
|
||||
secret-key: 404E635266556A586E3272357538782F413F4428472B4B6250645367566B5970
|
||||
expiration: 86400000 # a day
|
||||
refresh-token:
|
||||
expiration: 604800000 # 7 days
|
||||
52
bootstrap/src/main/resources/application.yml
Executable file
52
bootstrap/src/main/resources/application.yml
Executable file
@ -0,0 +1,52 @@
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
file:
|
||||
upload-dir: /upload
|
||||
|
||||
spring:
|
||||
http:
|
||||
encoding:
|
||||
charset: UTF-8
|
||||
enabled: true
|
||||
force: true
|
||||
|
||||
application:
|
||||
name: '@project.description@'
|
||||
version: '@project.version@'
|
||||
|
||||
profiles:
|
||||
active: '@spring.profiles.active@'
|
||||
|
||||
banner:
|
||||
location: 'classpath:banner.txt'
|
||||
|
||||
# jackson:
|
||||
# date-format: yyyy-MM-dd HH:mm:ss
|
||||
# time-zone: Europe/Paris
|
||||
|
||||
# messages:
|
||||
# basename: language/i18n
|
||||
|
||||
servlet:
|
||||
multipart:
|
||||
enabled: true
|
||||
max-file-size: 50MB
|
||||
max-request-size: 50MB
|
||||
#location: ${java.io.tmpdir}
|
||||
|
||||
logging:
|
||||
level:
|
||||
org:
|
||||
springframework:
|
||||
web:
|
||||
filter:
|
||||
CommonsRequestLoggingFilter: INFO
|
||||
security:
|
||||
config:
|
||||
annotation:
|
||||
authentication:
|
||||
configuration:
|
||||
InitializeUserDetailsBeanManagerConfigurer: ERROR
|
||||
|
||||
apiPrefix: ""
|
||||
17
bootstrap/src/main/resources/banner.txt
Normal file
17
bootstrap/src/main/resources/banner.txt
Normal file
@ -0,0 +1,17 @@
|
||||
██╗ ██╗██████╗ ███████╗██████╗ ██╗████████╗██╗███████╗
|
||||
╚██╗██╔╝██╔══██╗██╔════╝██╔══██╗██║╚══██╔══╝██║██╔════╝
|
||||
╚███╔╝ ██████╔╝█████╗ ██║ ██║██║ ██║ ██║███████╗
|
||||
██╔██╗ ██╔═══╝ ██╔══╝ ██║ ██║██║ ██║ ██║╚════██║
|
||||
██╔╝ ██╗██║ ███████╗██████╔╝██║ ██║ ██║███████║
|
||||
╚═╝ ╚═╝╚═╝ ╚══════╝╚═════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝
|
||||
|
||||
⚓ MARITIME LOGISTICS & SHIPPING SOLUTIONS ⚓
|
||||
🌊 Setting Sail for Excellence 🌊
|
||||
|
||||
═══════════════════════════════════════════════════════
|
||||
Port: ${server.port:8080} | Version: ${spring.application.version}
|
||||
═══════════════════════════════════════════════════════
|
||||
🚢 Navigating the Digital Ocean 🚢
|
||||
Ready to Ship Your Success!
|
||||
|
||||
Powered by Spring Boot ${spring-boot.version}
|
||||
28
bootstrap/src/main/resources/data-h2.sql
Normal file
28
bootstrap/src/main/resources/data-h2.sql
Normal file
@ -0,0 +1,28 @@
|
||||
INSERT INTO users (username, email, password, role)
|
||||
VALUES ('dbuser', 'dbuser@dev.ovh', '{bcrypt}$2y$10$.qkbukzzX21D.bqbI.B2R.tvWP90o/Y16QRWVLodw51BHft7ZWbc.', 'USER'),
|
||||
('dbadmin', 'dbadmin@dev.ovh', '{bcrypt}$2y$10$kp1V7UYDEWn17WSK16UcmOnFd1mPFVF6UkLrOOCGtf24HOYt8p1iC', 'ADMIN');
|
||||
|
||||
INSERT INTO event (name, description, date)
|
||||
VALUES ('toto', 'hello', '2025-01-01'),
|
||||
('tata', 'hola', '2025-01-10');
|
||||
|
||||
INSERT INTO gallery (name, description)
|
||||
VALUES ('gallery', '');
|
||||
|
||||
INSERT INTO menu_category (name)
|
||||
VALUES ('STARTERS'),
|
||||
('DISHES'),
|
||||
('DESSERTS'),
|
||||
('PIZZAS'),
|
||||
('RED_WINES'),
|
||||
('WHITE_WINES');
|
||||
|
||||
INSERT INTO product (name, description, price, category_id)
|
||||
VALUES ('Coconut Cake', 'Fresh Coconut', 4.90, 3),
|
||||
('Pasta', 'Fresh Pasta', 12.79, 2),
|
||||
('Foie Gras', 'Fresh Pasta', 12.79, 1);
|
||||
|
||||
INSERT INTO selected_day (date)
|
||||
VALUES ('2035-01-01'),
|
||||
('2035-03-02'),
|
||||
('2035-03-10');
|
||||
7
bootstrap/src/main/resources/language/i18n_en.properties
Normal file
7
bootstrap/src/main/resources/language/i18n_en.properties
Normal file
@ -0,0 +1,7 @@
|
||||
internal.error=Unable to perform action
|
||||
red.wines.name=RED WINES
|
||||
white.wines.name=WHITE WINES
|
||||
starters.name=STARTERS
|
||||
dishes.name=DISHES
|
||||
desserts.name=DESSERTS
|
||||
pizzas.name=PIZZAS
|
||||
7
bootstrap/src/main/resources/language/i18n_fr.properties
Normal file
7
bootstrap/src/main/resources/language/i18n_fr.properties
Normal file
@ -0,0 +1,7 @@
|
||||
internal.error=Impossible de réaliser l'action
|
||||
red.wines.name=VINS ROUGES
|
||||
white.wines.name=VINS BLANCS
|
||||
starters.name=ENTREES
|
||||
dishes.name=PLATS
|
||||
desserts.name=DESSERTS
|
||||
pizzas.name=PIZZAS
|
||||
57
bootstrap/src/main/resources/logback-spring.xml
Executable file
57
bootstrap/src/main/resources/logback-spring.xml
Executable file
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE configuration>
|
||||
<!--<configuration debug="true" scan="true" scanPeriod="30 seconds">-->
|
||||
<configuration scan="true" scanPeriod="30 seconds">
|
||||
|
||||
<property name="XPEDITIS" value="XPEDITIS_" />
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<pattern>
|
||||
%d{dd-MM-yyyy HH:mm:ss.SSS} [r:%X{request_id:--}] %magenta([%thread]) %contextName %highlight(%-5level) %yellow(%logger{36}.%M) - %msg%n
|
||||
<!--%black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable-->
|
||||
</pattern>
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<springProfile name="dev">
|
||||
<property name="XPEDITIS_LOGS_DEV" value="logs/dev" />
|
||||
<root>
|
||||
<level value="DEBUG"/>
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
</springProfile>
|
||||
|
||||
<springProfile name="prod">
|
||||
<property name="XPEDITIS_LOGS_PROD" value="logs/prod" />
|
||||
|
||||
<!-- everything.log -->
|
||||
<appender name="${XPEDITIS}prod" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${XPEDITIS_LOGS_PROD}/everything.log</file>
|
||||
<append>true</append>
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>
|
||||
%d{dd-MM-yyyy HH:mm:ss.SSS} [r:%X{request_id:--}] [%thread] %contextName %-5level %logger{36}.%M - %msg%n
|
||||
<!--%d %p %C{1.} [%t] %m%n-->
|
||||
</pattern>
|
||||
</encoder>
|
||||
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<!-- rollover daily and when the file reaches 10 MegaBytes -->
|
||||
<fileNamePattern>
|
||||
${XPEDITIS_LOGS_PROD}/archived/everything_%d{dd-MM-yyyy}_%i.log
|
||||
</fileNamePattern>
|
||||
<maxFileSize>1MB</maxFileSize>
|
||||
<maxHistory>10</maxHistory>
|
||||
<totalSizeCap>10MB</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
<root>
|
||||
<level value="INFO"/>
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="${LEBLR}prod"/>
|
||||
</root>
|
||||
</springProfile>
|
||||
|
||||
</configuration>
|
||||
74
bootstrap/src/main/resources/templates/addEvent.html
Normal file
74
bootstrap/src/main/resources/templates/addEvent.html
Normal file
@ -0,0 +1,74 @@
|
||||
<body>
|
||||
<section class="my-5">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 mx-auto">
|
||||
<h2>Upload Image Example</h2>
|
||||
<p th:text="${message}" th:if="${message ne null}" class="alert alert-primary"></p>
|
||||
<form id="uploadForm" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<label for="nameInput">Name:</label>
|
||||
<input type="text" id="nameInput" name="name" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="descriptionInput">Description:</label>
|
||||
<input type="text" id="descriptionInput" name="description" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="dateInput">Date:</label>
|
||||
<input type="date" id="dateInput" name="date" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="file" name="images" accept="image/*" class="form-control-file" multiple>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary" onclick="submitForm()">Upload images</button>
|
||||
</form>
|
||||
<span th:if="${msg != null}" th:text="${msg}"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
function submitForm() {
|
||||
var form = document.getElementById('uploadForm');
|
||||
var formData = new FormData();
|
||||
|
||||
// Ajouter les champs de formulaire à formData
|
||||
formData.append('name', document.getElementById('nameInput').value);
|
||||
formData.append('description', document.getElementById('descriptionInput').value);
|
||||
formData.append('date', document.getElementById('dateInput').value);
|
||||
|
||||
// Ajouter les images à formData
|
||||
var images = form.querySelector('input[type="file"]').files;
|
||||
for (var i = 0; i < images.length; i++) {
|
||||
formData.append('images', images[i]);
|
||||
}
|
||||
|
||||
// Créer un objet Blob pour newEvent
|
||||
var eventData = {
|
||||
name: formData.get('name'),
|
||||
description: formData.get('description'),
|
||||
date: formData.get('date')
|
||||
};
|
||||
|
||||
var newEventBlob = new Blob([JSON.stringify(eventData)], { type: 'application/json' });
|
||||
|
||||
// Ajouter newEvent en tant que RequestPart séparé
|
||||
formData.append('newEvent', newEventBlob);
|
||||
|
||||
// Envoyer la requête
|
||||
fetch('/upload', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(data => {
|
||||
alert(data);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
42
bootstrap/src/main/resources/templates/addImages.html
Normal file
42
bootstrap/src/main/resources/templates/addImages.html
Normal file
@ -0,0 +1,42 @@
|
||||
<body>
|
||||
<section class="my-5">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 mx-auto">
|
||||
<h2>Upload Image Example</h2>
|
||||
<p th:text="${message}" th:if="${message ne null}" class="alert alert-primary"></p>
|
||||
<form id="uploadForm" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<label for="numberInput">Enter a Number:</label>
|
||||
<input type="number" id="numberInput" name="number" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="file" name="images" accept="image/*" class="form-control-file" multiple>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary" onclick="submitForm1()">Upload images to event</button>
|
||||
<button type="button" class="btn btn-primary" onclick="submitForm2()">Upload images to gallery</button>
|
||||
</form>
|
||||
<span th:if="${msg != null}" th:text="${msg}"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
function submitForm2() {
|
||||
var number = document.getElementById('numberInput').value;
|
||||
var form = document.getElementById('uploadForm');
|
||||
form.action = '/upload/gallery/' + number;
|
||||
form.method = 'post';
|
||||
form.submit();
|
||||
}
|
||||
|
||||
function submitForm1() {
|
||||
var number = document.getElementById('numberInput').value;
|
||||
var form = document.getElementById('uploadForm');
|
||||
form.action = '/upload/' + number;
|
||||
form.method = 'post';
|
||||
form.submit();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
14
bootstrap/src/test/java/com/dh7789dev/xpeditis/LeBlrApplicationTests.java
Executable file
14
bootstrap/src/test/java/com/dh7789dev/xpeditis/LeBlrApplicationTests.java
Executable file
@ -0,0 +1,14 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
||||
@SpringBootTest
|
||||
@ActiveProfiles("dev")
|
||||
class LeBlrApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
}
|
||||
16
common/pom.xml
Executable file
16
common/pom.xml
Executable file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>xpeditis</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>common</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,8 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
public class CommonUtil {
|
||||
|
||||
public void sayHello() {
|
||||
System.out.println("Hello!");
|
||||
}
|
||||
}
|
||||
79
compose.yml
Normal file
79
compose.yml
Normal file
@ -0,0 +1,79 @@
|
||||
services:
|
||||
|
||||
db:
|
||||
image: mysql:latest
|
||||
restart: always
|
||||
ports:
|
||||
- "3306:3306"
|
||||
networks:
|
||||
- xpeditis
|
||||
environment:
|
||||
MYSQL_DATABASE_FILE: /run/secrets/mysql-database
|
||||
MYSQL_USER_FILE: /run/secrets/mysql-user
|
||||
MYSQL_PASSWORD_FILE: /run/secrets/mysql-password
|
||||
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql-root-password
|
||||
# MYSQL_RANDOM_ROOT_PASSWORD: '1'
|
||||
secrets:
|
||||
- mysql-database
|
||||
- mysql-user
|
||||
- mysql-password
|
||||
- mysql-root-password
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ../database/mysql
|
||||
target: /var/lib/mysql
|
||||
- type: bind
|
||||
source: ../database/config/docker-fixes.cnf
|
||||
target: /etc/mysql/conf.d/docker-fixes.cnf
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "10"
|
||||
container_name: db
|
||||
|
||||
back:
|
||||
image: leblr-backend
|
||||
restart: always
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
XPEDITIS_PROFILE: prod
|
||||
secrets:
|
||||
- mysql-user
|
||||
- mysql-password
|
||||
target: production
|
||||
ports:
|
||||
- "8081:8080"
|
||||
networks:
|
||||
- xpeditis
|
||||
depends_on:
|
||||
- db
|
||||
environment:
|
||||
SPRING_DATASOURCE_URL:
|
||||
SPRING_DATASOURCE_USERNAME:
|
||||
SPRING_DATASOURCE_PASSWORD:
|
||||
volumes:
|
||||
- ./logs/prod:/opt/app/logs/prod:rw
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "10"
|
||||
container_name: leblr_backend
|
||||
|
||||
secrets:
|
||||
mysql-user:
|
||||
file: ../database/secrets/mysql-user.txt
|
||||
mysql-database:
|
||||
file: ../database/secrets/mysql-database.txt
|
||||
mysql-password:
|
||||
file: ../database/secrets/mysql-password.txt
|
||||
mysql-root-password:
|
||||
file: ../database/secrets/mysql-root-password.txt
|
||||
|
||||
networks:
|
||||
leblr:
|
||||
name: leblr
|
||||
external: true
|
||||
32
domain/api/pom.xml
Executable file
32
domain/api/pom.xml
Executable file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>domain</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>api</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>23</maven.compiler.source>
|
||||
<maven.compiler.target>23</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>data</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@ -0,0 +1,9 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
import com.dh7789dev.xpeditis.dto.AuthenticationRequest;
|
||||
import com.dh7789dev.xpeditis.dto.AuthenticationResponse;
|
||||
|
||||
public interface AuthenticationService {
|
||||
|
||||
AuthenticationResponse authenticate(AuthenticationRequest request);
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
public interface EmailService {
|
||||
|
||||
void sendCustomerReservationEmail(Reservation reservation);
|
||||
|
||||
void sendAdminReservationEmail(Reservation reservation);
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
public interface NlsService {
|
||||
|
||||
/**
|
||||
* @param key nls message key
|
||||
* @return the message corresponding to the key translated into the desired language
|
||||
*/
|
||||
String getMessage(String key);
|
||||
|
||||
/**
|
||||
* @param key nls message key
|
||||
* @param parameters parameters to use in the message
|
||||
* @return the message corresponding to the key translated into the desired language
|
||||
*/
|
||||
String getMessage(String key, Object[] parameters);
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
public interface StorageService {
|
||||
|
||||
void init();
|
||||
|
||||
String upload(MultipartFile file, String newFileName);
|
||||
|
||||
Resource download(String fileName);
|
||||
|
||||
void delete(String fileName);
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
import com.dh7789dev.xpeditis.dto.ChangePasswordRequest;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
public interface UserService {
|
||||
|
||||
void changePassword(ChangePasswordRequest request, Principal connectedUser);
|
||||
}
|
||||
57
domain/data/pom.xml
Executable file
57
domain/data/pom.xml
Executable file
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>domain</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>data</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>23</maven.compiler.source>
|
||||
<maven.compiler.target>23</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.validation</groupId>
|
||||
<artifactId>jakarta.validation-api</artifactId>
|
||||
</dependency>
|
||||
<!-- @Json -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${org.projectlombok.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@ -0,0 +1,21 @@
|
||||
package com.dh7789dev.xpeditis.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Accessors(chain = true)
|
||||
public class AuthenticationRequest {
|
||||
|
||||
@NotBlank
|
||||
final String username;
|
||||
|
||||
@NotBlank
|
||||
final String password;
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package com.dh7789dev.xpeditis.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Accessors(chain = true)
|
||||
public class AuthenticationResponse {
|
||||
|
||||
@JsonProperty("access_token")
|
||||
String accessToken;
|
||||
|
||||
@JsonProperty("refresh_token")
|
||||
String refreshToken;
|
||||
|
||||
@JsonProperty("created_at")
|
||||
Date createdAt;
|
||||
|
||||
@JsonProperty("expires_at")
|
||||
Date expiresAt;
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.dh7789dev.xpeditis.dto;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Data
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Accessors(chain = true)
|
||||
public class ChangePasswordRequest {
|
||||
|
||||
String currentPassword;
|
||||
|
||||
String newPassword;
|
||||
|
||||
String confirmationPassword;
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.dh7789dev.xpeditis.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Accessors(chain = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class CustomInternalExceptionResponse {
|
||||
|
||||
String id;
|
||||
|
||||
Instant timestamp;
|
||||
|
||||
String errorCode;
|
||||
|
||||
String errorMessage;
|
||||
|
||||
String requestURL;
|
||||
|
||||
public CustomInternalExceptionResponse(String id, String errorCode, String errorMessage, String requestURL) {
|
||||
this.id = id;
|
||||
this.errorCode = errorCode;
|
||||
this.errorMessage = errorMessage;
|
||||
this.requestURL = requestURL;
|
||||
this.timestamp = Instant.now();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.dh7789dev.xpeditis.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Accessors(chain = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class Gallery {
|
||||
|
||||
Long id;
|
||||
|
||||
@NotBlank(message = "name cannot be empty")
|
||||
String name;
|
||||
|
||||
String description;
|
||||
|
||||
List<Image> images;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Gallery(" + String.format("name=%s, description=%s)", name, description);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package com.dh7789dev.xpeditis.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Data
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Accessors(chain = true)
|
||||
public class Image {
|
||||
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
@JsonIgnore
|
||||
String path;
|
||||
|
||||
String uri;
|
||||
|
||||
public Image(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.dh7789dev.xpeditis.exception;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Accessors(chain = true)
|
||||
public class CustomInternalException extends RuntimeException {
|
||||
|
||||
private static final String INTERNAL_ERROR = "internal.error";
|
||||
|
||||
final String errorCode;
|
||||
|
||||
final String nlsKey;
|
||||
|
||||
final String[] nlsParameters;
|
||||
|
||||
public CustomInternalException(String message) {
|
||||
super(message);
|
||||
errorCode = "InternalError";
|
||||
nlsKey = INTERNAL_ERROR;
|
||||
nlsParameters = new String[]{};
|
||||
}
|
||||
|
||||
public CustomInternalException(String errorCode, String message, String nlsKey) {
|
||||
super(message);
|
||||
this.errorCode = errorCode;
|
||||
this.nlsKey = nlsKey;
|
||||
this.nlsParameters= new String[]{};
|
||||
}
|
||||
|
||||
public CustomInternalException(String errorCode, String message, String nlsKey, String[] nlsParameters) {
|
||||
super(message);
|
||||
this.errorCode = errorCode;
|
||||
this.nlsKey = nlsKey;
|
||||
this.nlsParameters = nlsParameters;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.dh7789dev.xpeditis.exception;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Accessors(chain = true)
|
||||
public class GlobalNotFoundException extends RuntimeException {
|
||||
|
||||
final String errorCode;
|
||||
|
||||
public GlobalNotFoundException(String subject) {
|
||||
super((subject + " Not Found"));
|
||||
this.errorCode = subject + "NotFound";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
package com.dh7789dev.xpeditis.exception;
|
||||
|
||||
public class NlsNotFoundException extends RuntimeException {
|
||||
|
||||
public NlsNotFoundException(String nlsKey, String locale) {
|
||||
super("Nls message not found for nlsKey " + nlsKey + " and locale " + locale);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package com.dh7789dev.xpeditis.exception;
|
||||
|
||||
public class StorageException extends RuntimeException {
|
||||
|
||||
public StorageException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public StorageException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
27
domain/pom.xml
Executable file
27
domain/pom.xml
Executable file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>xpeditis</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>domain</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>23</maven.compiler.source>
|
||||
<maven.compiler.target>23</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>data</module>
|
||||
<module>api</module>
|
||||
<module>spi</module>
|
||||
<module>service</module>
|
||||
</modules>
|
||||
</project>
|
||||
82
domain/service/pom.xml
Executable file
82
domain/service/pom.xml
Executable file
@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>domain</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>service</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>23</maven.compiler.source>
|
||||
<maven.compiler.target>23</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<junit.version>5.9.2</junit.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- spring-boot dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>spi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-junit-jupiter</artifactId>
|
||||
<version>${mockito.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>${assertj.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${org.projectlombok.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@ -0,0 +1,20 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
import com.dh7789dev.xpeditis.dto.AuthenticationRequest;
|
||||
import com.dh7789dev.xpeditis.dto.AuthenticationResponse;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
|
||||
private final AuthenticationRepository authenticationRepository;
|
||||
|
||||
public AuthenticationServiceImpl(AuthenticationRepository authenticationRepository) {
|
||||
this.authenticationRepository = authenticationRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationResponse authenticate(AuthenticationRequest request) {
|
||||
return authenticationRepository.authenticate(request);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
@Service
|
||||
public class EmailServiceImpl implements EmailService {
|
||||
|
||||
@Value("${application.email.from}")
|
||||
String adminEmail;
|
||||
|
||||
private final EmailSenderRepository emailSenderRepository;
|
||||
|
||||
private final DateTimeFormatter outputFormatter;
|
||||
|
||||
@Autowired
|
||||
public EmailServiceImpl(EmailSenderRepository emailSenderRepository) {
|
||||
this.emailSenderRepository = emailSenderRepository;
|
||||
this.outputFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy 'à' HH:mm");
|
||||
}
|
||||
|
||||
protected String buildCustomerReservationEmail(String name, String date, int nbPerson) {
|
||||
return "<div dir=\"ltr\" style=\"font-family: Arial, sans-serif; background-color: #f6f6f6; padding: 20px;\">\n" +
|
||||
" <table width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"max-width: 600px; margin: auto; background-color: #ffffff; border-radius: 8px; overflow: hidden;\">\n" +
|
||||
" <tr>\n" +
|
||||
" <td style=\"padding: 20px; text-align: center;\">\n" +
|
||||
" <h1 style=\"color: #333;\">Bienvenue au Restaurant le BLR!</h1>\n" +
|
||||
" <img src=\"https://demo.stripocdn.email/content/guids/04fb15d2-fa4d-45a6-9edf-63e2a4d6d00a/images/group_3.png\" alt=\"Restaurant le BLR\" width=\"100%\" style=\"max-width: 600px; border-radius: 8px;\">\n" +
|
||||
" <hr style=\"border: none; border-bottom: 4px solid #ccad53; margin: 20px 0;\">\n" +
|
||||
" <h2 style=\"color: #333;\">Bonjour " + name + ",</h2>\n" +
|
||||
" <p style=\"color: #555; line-height: 1.6;\">\n" +
|
||||
" Merci beaucoup pour votre réservation chez <strong>Le BLR</strong>.<br>\n" +
|
||||
" Nous sommes ravis de vous avoir parmi nous !<br>\n" +
|
||||
" Vous avez effectué une réservation pour <strong>" + nbPerson + " " + (nbPerson > 1 ? "personnes" : "personne") + "</strong>.<br>\n" +
|
||||
" Nous avons hâte de vous accueillir dans notre restaurant le <strong>" + date + "</strong> et de vous offrir une expérience inoubliable !<br>\n" +
|
||||
" À très bientôt,<br>\n" +
|
||||
" L'équipe du <strong>Le BLR</strong>\n" +
|
||||
" </p>\n" +
|
||||
" </td>\n" +
|
||||
" </tr>\n" +
|
||||
" </table>\n" +
|
||||
"</div>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendCustomerReservationEmail(Reservation reservation) {
|
||||
emailSenderRepository.send(reservation.getEmail(),
|
||||
buildCustomerReservationEmail(reservation.getName(), reservation.getDate().format(outputFormatter), reservation.getNbPerson()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendAdminReservationEmail(Reservation reservation) {
|
||||
emailSenderRepository.send(adminEmail,
|
||||
buildCustomerReservationEmail(reservation.getName(), reservation.getDate().format(outputFormatter), reservation.getNbPerson()));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
import com.dh7789dev.xpeditis.exception.StorageException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.UrlResource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class FileSystemStorageService implements StorageService {
|
||||
|
||||
@Value("${file.upload-dir}")
|
||||
String uploadDir;
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
Path directory = Paths.get(uploadDir);
|
||||
if (!Files.exists(directory)) {
|
||||
try {
|
||||
log.info("Create directory {} to store images", directory);
|
||||
Files.createDirectories(directory);
|
||||
} catch (IOException e) {
|
||||
throw new StorageException("Failed to create directory " + uploadDir, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String upload(MultipartFile file, String newFileName) {
|
||||
|
||||
if (!file.isEmpty()) {
|
||||
|
||||
Path filePath = Paths.get(uploadDir, newFileName);
|
||||
log.info("File path: {}", filePath);
|
||||
try {
|
||||
Files.write(filePath, file.getBytes());
|
||||
} catch (IOException e) {
|
||||
throw new StorageException("Failed to store file", e);
|
||||
}
|
||||
log.info("save {} to {}", file.getOriginalFilename(), newFileName);
|
||||
return filePath.toString();
|
||||
} else {
|
||||
throw new StorageException("Failed to store file");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource download(String fileName) {
|
||||
|
||||
try {
|
||||
Path filePath = Paths.get(uploadDir).resolve(fileName).normalize();
|
||||
log.info("Download file path: {}", fileName);
|
||||
Resource resource = new UrlResource(filePath.toUri());
|
||||
if (!resource.exists() || !resource.isReadable()) {
|
||||
throw new StorageException("Could not read file: " + fileName);
|
||||
}
|
||||
return resource;
|
||||
} catch (IOException e) {
|
||||
throw new StorageException("Failed to download file " + fileName, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String fileName) {
|
||||
|
||||
try {
|
||||
Path filePath = Paths.get(uploadDir).resolve(fileName).normalize();
|
||||
log.info("Delete file path: {}", fileName);
|
||||
if (Files.exists(filePath)) {
|
||||
Files.delete(filePath);
|
||||
} else {
|
||||
throw new StorageException("File does not exist: " + fileName);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new StorageException("Failed to delete file " + fileName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
@Service
|
||||
public class NlsServiceImpl implements NlsService {
|
||||
|
||||
private final NlsRepository nlsRepository;
|
||||
|
||||
@Autowired
|
||||
public NlsServiceImpl(NlsRepository nlsRepository) {
|
||||
this.nlsRepository = nlsRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key nls message key
|
||||
* @return the message corresponding to the key translated into the desired language
|
||||
*/
|
||||
@Override
|
||||
public String getMessage(String key) {
|
||||
return nlsRepository.getMessage(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key nls message key
|
||||
* @param parameters parameters to use in the message
|
||||
* @return the message corresponding to the key translated into the desired language
|
||||
*/
|
||||
@Override
|
||||
public String getMessage(String key, Object[] parameters) {
|
||||
String message = nlsRepository.getMessage(key, parameters);
|
||||
// escape simple quotes: double them
|
||||
message = message.replace("'", "''").replace("{", "'{");
|
||||
// format message
|
||||
return MessageFormat.format(message, parameters);
|
||||
}
|
||||
|
||||
private Locale getLocale(final Locale locale) {
|
||||
Locale locale1;
|
||||
if (locale != null) {
|
||||
// hack for simplified chinese
|
||||
if (locale.getLanguage().equals("zh") && locale.getCountry().isEmpty()) {
|
||||
locale1 = Locale.SIMPLIFIED_CHINESE;
|
||||
} else {
|
||||
locale1 = locale;
|
||||
}
|
||||
} else {
|
||||
locale1 = Locale.getDefault();
|
||||
}
|
||||
return locale1;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
import com.dh7789dev.xpeditis.dto.ChangePasswordRequest;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
@Service
|
||||
public class UserServiceImpl implements UserService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
public UserServiceImpl(UserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changePassword(ChangePasswordRequest request, Principal connectedUser) {
|
||||
userRepository.changePassword(request, connectedUser);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class MenuServiceImplTest {
|
||||
|
||||
@Mock
|
||||
private MenuRepository menuRepository;
|
||||
|
||||
@InjectMocks
|
||||
private MenuServiceImpl menuService;
|
||||
|
||||
@Test
|
||||
void given_whenGetCategories_then() {
|
||||
|
||||
// given
|
||||
when(menuRepository.findAll()).thenReturn(List.of());
|
||||
|
||||
// when
|
||||
List<MenuCategory> categories = menuService.getCategories();
|
||||
|
||||
// then
|
||||
assertThat(categories).isEmpty();
|
||||
}
|
||||
}
|
||||
28
domain/spi/pom.xml
Executable file
28
domain/spi/pom.xml
Executable file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>domain</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>spi</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>23</maven.compiler.source>
|
||||
<maven.compiler.target>23</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>data</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@ -0,0 +1,9 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
import com.dh7789dev.xpeditis.dto.AuthenticationRequest;
|
||||
import com.dh7789dev.xpeditis.dto.AuthenticationResponse;
|
||||
|
||||
public interface AuthenticationRepository {
|
||||
|
||||
AuthenticationResponse authenticate(AuthenticationRequest request);
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
public interface EmailSenderRepository {
|
||||
|
||||
void send(String emailAddressTo, String emailContent);
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
public interface NlsRepository {
|
||||
|
||||
/**
|
||||
* @param key nls message key
|
||||
* @return the message corresponding to the key translated into the desired language
|
||||
*/
|
||||
String getMessage(String key);
|
||||
|
||||
/**
|
||||
* @param key nls message key
|
||||
* @param parameters parameters to use in the message
|
||||
* @return the message corresponding to the key translated into the desired language
|
||||
*/
|
||||
String getMessage(String key, Object[] parameters);
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
package com.dh7789dev.xpeditis;
|
||||
|
||||
import com.dh7789dev.xpeditis.dto.ChangePasswordRequest;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
public interface UserRepository {
|
||||
|
||||
void changePassword(ChangePasswordRequest request, Principal connectedUser);
|
||||
}
|
||||
4
entrypoint.sh
Normal file
4
entrypoint.sh
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
# ./wait-for-it.sh db:3306 --timeout=60 --strict --
|
||||
java -jar -Dserver.port=8080 xpeditis.jar
|
||||
5
infrastructure/flyway.conf
Normal file
5
infrastructure/flyway.conf
Normal file
@ -0,0 +1,5 @@
|
||||
flyway.user=user
|
||||
flyway.password=LEBLR_p4ssw0rd_971
|
||||
flyway.schemas=leblr
|
||||
flyway.url=jdbc:mysql://localhost:3306/leblr
|
||||
flyway.locations=classpath:db/migration/structure,classpath:db/migration/data
|
||||
151
infrastructure/pom.xml
Executable file
151
infrastructure/pom.xml
Executable file
@ -0,0 +1,151 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>xpeditis</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>infrastructure</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>23</maven.compiler.source>
|
||||
<maven.compiler.target>23</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<org.flywaydb.version>11.3.1</org.flywaydb.version>
|
||||
<io.jsonwebtoken.version>0.12.6</io.jsonwebtoken.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.dh7789dev</groupId>
|
||||
<artifactId>spi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- spring-boot dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-mail</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- JWT -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
<version>${io.jsonwebtoken.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-impl</artifactId>
|
||||
<version>${io.jsonwebtoken.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-jackson</artifactId>
|
||||
<version>${io.jsonwebtoken.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>dev</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>2.3.232</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>prod</id>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<version>9.2.0</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<!-- flyway dependency -->
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-core</artifactId>
|
||||
<version>${org.flywaydb.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-mysql</artifactId>
|
||||
<version>${org.flywaydb.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${org.projectlombok.version}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-processor</artifactId>
|
||||
<version>${org.mapstruct.version}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok-mapstruct-binding</artifactId>
|
||||
<version>0.2.0</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-maven-plugin</artifactId>
|
||||
<version>${org.flywaydb.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@ -0,0 +1,33 @@
|
||||
package com.dh7789dev.xpeditis.configuration;
|
||||
|
||||
import com.dh7789dev.xpeditis.entity.UserEntity;
|
||||
import org.springframework.data.domain.AuditorAware;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component(value = "auditorProvider")
|
||||
public class AuditorAwareImpl implements AuditorAware<String> {
|
||||
|
||||
private static final String DEFAULT_AUDITOR = "SYSTEM";
|
||||
|
||||
@Override
|
||||
public Optional<String> getCurrentAuditor() {
|
||||
|
||||
Authentication authentication = SecurityContextHolder
|
||||
.getContext()
|
||||
.getAuthentication();
|
||||
|
||||
if (authentication == null || !authentication.isAuthenticated()) {
|
||||
return Optional.empty();
|
||||
} else if (authentication instanceof AnonymousAuthenticationToken) {
|
||||
return Optional.of(DEFAULT_AUDITOR);
|
||||
}
|
||||
|
||||
UserEntity userPrincipal = (UserEntity) authentication.getPrincipal();
|
||||
return Optional.ofNullable(userPrincipal.getUsername());
|
||||
}
|
||||
}
|
||||
17
infrastructure/src/main/java/com/dh7789dev/xpeditis/dao/EventDao.java
Executable file
17
infrastructure/src/main/java/com/dh7789dev/xpeditis/dao/EventDao.java
Executable file
@ -0,0 +1,17 @@
|
||||
package com.dh7789dev.xpeditis.dao;
|
||||
|
||||
import com.dh7789dev.xpeditis.entity.EventEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface EventDao extends JpaRepository<EventEntity, Long> {
|
||||
|
||||
Optional<EventEntity> findByName(String name);
|
||||
|
||||
List<EventEntity> findAllByDate(Instant date);
|
||||
|
||||
List<EventEntity> findAllByOrderByDateDescNameAsc();
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package com.dh7789dev.xpeditis.dao;
|
||||
|
||||
import com.dh7789dev.xpeditis.entity.GalleryEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface GalleryDao extends JpaRepository<GalleryEntity, Long> {
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package com.dh7789dev.xpeditis.dao;
|
||||
|
||||
import com.dh7789dev.xpeditis.entity.ImageEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface ImageDao extends JpaRepository<ImageEntity, Long> {
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
package com.dh7789dev.xpeditis.dao;
|
||||
|
||||
import com.dh7789dev.xpeditis.entity.MenuCategoryEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface MenuDao extends JpaRepository<MenuCategoryEntity, Long> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
package com.dh7789dev.xpeditis.dao;
|
||||
|
||||
import com.dh7789dev.xpeditis.entity.ProductEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface ProductDao extends JpaRepository<ProductEntity, Long> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.dh7789dev.xpeditis.dao;
|
||||
|
||||
import com.dh7789dev.xpeditis.entity.ReservationEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
public interface ReservationDao extends JpaRepository<ReservationEntity, Long> {
|
||||
|
||||
List<ReservationEntity> findByName(String name);
|
||||
|
||||
@Query("SELECT r FROM ReservationEntity r WHERE r.date >= :startOfDay AND r.date < :endOfDay")
|
||||
List<ReservationEntity> findReservationsByDates(@Param("startOfDay") LocalDateTime startOfDay,
|
||||
@Param("endOfDay") LocalDateTime endOfDay);
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.dh7789dev.xpeditis.dao;
|
||||
|
||||
import com.dh7789dev.xpeditis.entity.SelectedDayEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
public interface SelectedDayDao extends JpaRepository<SelectedDayEntity, Long> {
|
||||
|
||||
@Query("SELECT day FROM SelectedDayEntity day WHERE day.date >= :date")
|
||||
List<SelectedDayEntity> findAllFromDate(LocalDate date);
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.dh7789dev.xpeditis.dao;
|
||||
|
||||
import com.dh7789dev.xpeditis.entity.TokenEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface TokenDao extends JpaRepository<TokenEntity, Integer> {
|
||||
|
||||
Optional<TokenEntity> findByToken(String token);
|
||||
|
||||
@Query(value = """
|
||||
select t from TokenEntity t inner join UserEntity u\s
|
||||
on t.user.id = u.id\s
|
||||
where u.id = :userId and (t.expired = false or t.revoked = false)\s
|
||||
""")
|
||||
List<TokenEntity> findAllValidTokenByUserId(Long userId);
|
||||
}
|
||||
11
infrastructure/src/main/java/com/dh7789dev/xpeditis/dao/UserDao.java
Executable file
11
infrastructure/src/main/java/com/dh7789dev/xpeditis/dao/UserDao.java
Executable file
@ -0,0 +1,11 @@
|
||||
package com.dh7789dev.xpeditis.dao;
|
||||
|
||||
import com.dh7789dev.xpeditis.entity.UserEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface UserDao extends JpaRepository<UserEntity, Long> {
|
||||
|
||||
Optional<UserEntity> findByUsername(String username);
|
||||
}
|
||||
48
infrastructure/src/main/java/com/dh7789dev/xpeditis/entity/BaseEntity.java
Executable file
48
infrastructure/src/main/java/com/dh7789dev/xpeditis/entity/BaseEntity.java
Executable file
@ -0,0 +1,48 @@
|
||||
package com.dh7789dev.xpeditis.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedBy;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
@Getter
|
||||
@Setter
|
||||
@MappedSuperclass
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
public abstract class BaseEntity implements Serializable {
|
||||
|
||||
@Id
|
||||
@Column(name = "id", updatable = false, nullable = false)
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
Long id;
|
||||
|
||||
// @Version
|
||||
// @Column(name = "version")
|
||||
// int version;
|
||||
|
||||
@CreatedDate
|
||||
@Column(name = "created_date", updatable = false, nullable = false, columnDefinition = "TIMESTAMP default CURRENT_TIMESTAMP")
|
||||
Instant createdDate;
|
||||
|
||||
@LastModifiedDate
|
||||
@Column(name = "modified_date", updatable = false, nullable = false, columnDefinition = "TIMESTAMP default CURRENT_TIMESTAMP")
|
||||
Instant modifiedDate;
|
||||
|
||||
@CreatedBy
|
||||
@Column(name = "created_by", updatable = false, nullable = false, columnDefinition = "varchar(255) default 'SYSTEM'")
|
||||
String createdBy;
|
||||
|
||||
@LastModifiedBy
|
||||
@Column(name = "modified_by")
|
||||
String modifiedBy;
|
||||
}
|
||||
34
infrastructure/src/main/java/com/dh7789dev/xpeditis/entity/EventEntity.java
Executable file
34
infrastructure/src/main/java/com/dh7789dev/xpeditis/entity/EventEntity.java
Executable file
@ -0,0 +1,34 @@
|
||||
package com.dh7789dev.xpeditis.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Accessors(chain = true)
|
||||
@Table(name = "event", uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = {"name"})
|
||||
})
|
||||
public class EventEntity extends BaseEntity {
|
||||
|
||||
@Column(nullable = false, unique = true)
|
||||
String name;
|
||||
|
||||
@Column
|
||||
String description;
|
||||
|
||||
@Column(nullable = false)
|
||||
LocalDate date;
|
||||
|
||||
@OneToMany(mappedBy = "event", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<ImageEntity> images;
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package com.dh7789dev.xpeditis.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Accessors(chain = true)
|
||||
@Table(name = "gallery", uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = {"name"})
|
||||
})
|
||||
public class GalleryEntity extends BaseEntity {
|
||||
|
||||
@Column(unique = true)
|
||||
String name;
|
||||
|
||||
@Column
|
||||
String description;
|
||||
|
||||
@OneToMany(mappedBy = "gallery", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<ImageEntity> images;
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package com.dh7789dev.xpeditis.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Accessors(chain = true)
|
||||
@Table(name = "image", uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = {"name", "path"})
|
||||
})
|
||||
public class ImageEntity extends BaseEntity {
|
||||
|
||||
@Column(unique = true)
|
||||
String name;
|
||||
|
||||
@Column(unique = true)
|
||||
String path;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "event_id")
|
||||
EventEntity event;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "gallery_id")
|
||||
GalleryEntity gallery;
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.dh7789dev.xpeditis.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
@Table(name = "menu_category", uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = {"name"})
|
||||
})
|
||||
public class MenuCategoryEntity extends BaseEntity {
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "name", nullable = false, unique = true)
|
||||
private MenuCategory.Name name;
|
||||
|
||||
@OneToMany(mappedBy = "category")
|
||||
private List<ProductEntity> products;
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.dh7789dev.xpeditis.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum Permission {
|
||||
|
||||
ADMIN_READ("admin:read"),
|
||||
ADMIN_UPDATE("admin:update"),
|
||||
ADMIN_CREATE("admin:create"),
|
||||
ADMIN_DELETE("admin:delete"),
|
||||
MANAGER_READ("management:read"),
|
||||
MANAGER_UPDATE("management:update"),
|
||||
MANAGER_CREATE("management:create"),
|
||||
MANAGER_DELETE("management:delete");
|
||||
|
||||
private final String permission;
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package com.dh7789dev.xpeditis.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Accessors(chain = true)
|
||||
@Table(name = "product", uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = {"name"})
|
||||
})
|
||||
public class ProductEntity extends BaseEntity {
|
||||
|
||||
@Column(nullable = false, unique = true)
|
||||
String name;
|
||||
|
||||
@Column
|
||||
String description;
|
||||
|
||||
@Column(nullable = false)
|
||||
BigDecimal price;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "category_id")
|
||||
private MenuCategoryEntity category;
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.dh7789dev.xpeditis.entity;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Table(name = "reservation")
|
||||
public class ReservationEntity extends BaseEntity {
|
||||
|
||||
@Column(nullable = false)
|
||||
String name;
|
||||
|
||||
@Column(nullable = false)
|
||||
String email;
|
||||
|
||||
@Column
|
||||
String phone;
|
||||
|
||||
@Column(nullable = false)
|
||||
int nbPerson;
|
||||
|
||||
@Column(nullable = false)
|
||||
LocalDateTime date;
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package com.dh7789dev.xpeditis.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.dh7789dev.xpeditis.entity.Permission.*;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum Role {
|
||||
|
||||
USER(Collections.emptySet()),
|
||||
ADMIN(Set.of(
|
||||
ADMIN_READ,
|
||||
ADMIN_UPDATE,
|
||||
ADMIN_DELETE,
|
||||
ADMIN_CREATE,
|
||||
MANAGER_READ,
|
||||
MANAGER_UPDATE,
|
||||
MANAGER_DELETE,
|
||||
MANAGER_CREATE)
|
||||
),
|
||||
MANAGER(Set.of(
|
||||
MANAGER_READ,
|
||||
MANAGER_UPDATE,
|
||||
MANAGER_DELETE,
|
||||
MANAGER_CREATE));
|
||||
|
||||
private final Set<Permission> permissions;
|
||||
|
||||
public List<SimpleGrantedAuthority> getAuthorities() {
|
||||
var authorities = getPermissions()
|
||||
.stream()
|
||||
.map(permission -> new SimpleGrantedAuthority(permission.getPermission()))
|
||||
.collect(Collectors.toList());
|
||||
authorities.add(new SimpleGrantedAuthority("ROLE_" + this.name()));
|
||||
return authorities;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.dh7789dev.xpeditis.entity;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.*;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Accessors(chain = true)
|
||||
@Table(name = "selected_day")
|
||||
public class SelectedDayEntity extends BaseEntity {
|
||||
|
||||
LocalDate date;
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package com.dh7789dev.xpeditis.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
@Table(name = "token", uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = {"token"})
|
||||
})
|
||||
public class TokenEntity extends BaseEntity {
|
||||
|
||||
public enum Type {
|
||||
BEARER
|
||||
}
|
||||
|
||||
@Column(unique = true)
|
||||
private String token;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private Type tokenType = Type.BEARER;
|
||||
|
||||
private boolean revoked;
|
||||
|
||||
private boolean expired;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "user_id")
|
||||
private UserEntity user;
|
||||
}
|
||||
87
infrastructure/src/main/java/com/dh7789dev/xpeditis/entity/UserEntity.java
Executable file
87
infrastructure/src/main/java/com/dh7789dev/xpeditis/entity/UserEntity.java
Executable file
@ -0,0 +1,87 @@
|
||||
package com.dh7789dev.xpeditis.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@Table(name = "users", uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = {"username", "email"})
|
||||
})
|
||||
public class UserEntity extends BaseEntity implements UserDetails {
|
||||
|
||||
@NaturalId
|
||||
@Column(nullable = false, unique = true, length = 50)
|
||||
private String username;
|
||||
|
||||
@Column(name = "first_name", length = 50)
|
||||
private String firstName;
|
||||
|
||||
@Column(name = "last_name", length = 50)
|
||||
private String lastName;
|
||||
|
||||
@Column(nullable = false, unique = true, length = 50)
|
||||
private String email;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String password;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(nullable = false)
|
||||
private Role role;
|
||||
|
||||
@Column(name = "enabled", nullable = false, columnDefinition = "BOOLEAN DEFAULT TRUE NOT NULL")
|
||||
private boolean enabled;
|
||||
|
||||
@OneToMany(mappedBy = "user")
|
||||
private List<TokenEntity> tokens;
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return role.getAuthorities();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UserEntity(" + super.toString() + String.format("username=%s, firstName=%s, lastName=%s, email=%s, role=%s)",
|
||||
username, firstName, lastName, email, role.name());
|
||||
}
|
||||
}
|
||||
25
infrastructure/src/main/java/com/dh7789dev/xpeditis/mapper/EventMapper.java
Executable file
25
infrastructure/src/main/java/com/dh7789dev/xpeditis/mapper/EventMapper.java
Executable file
@ -0,0 +1,25 @@
|
||||
package com.dh7789dev.xpeditis.mapper;
|
||||
|
||||
import com.dh7789dev.xpeditis.entity.EventEntity;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper(/*componentModel = MappingConstants.ComponentModel.SPRING,*/
|
||||
uses = {ImageMapper.class})
|
||||
public interface EventMapper {
|
||||
|
||||
EventMapper INSTANCE = Mappers.getMapper(EventMapper.class);
|
||||
|
||||
@Mapping(target = "createdDate", ignore = true)
|
||||
@Mapping(target = "modifiedDate", ignore = true)
|
||||
@Mapping(target = "createdBy", ignore = true)
|
||||
@Mapping(target = "modifiedBy", ignore = true)
|
||||
EventEntity eventToEventEntity(Event event);
|
||||
|
||||
Event eventEntityToEvent(EventEntity eventEntity);
|
||||
|
||||
List<Event> eventEntitiesToEvents(List<EventEntity> eventEntities);
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.dh7789dev.xpeditis.mapper;
|
||||
|
||||
import com.dh7789dev.xpeditis.dto.Gallery;
|
||||
import com.dh7789dev.xpeditis.entity.GalleryEntity;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper(/*componentModel = MappingConstants.ComponentModel.SPRING,*/
|
||||
uses = {ImageMapper.class})
|
||||
public interface GalleryMapper {
|
||||
|
||||
GalleryMapper INSTANCE = Mappers.getMapper(GalleryMapper.class);
|
||||
|
||||
@Mapping(target = "createdDate", ignore = true)
|
||||
@Mapping(target = "modifiedDate", ignore = true)
|
||||
@Mapping(target = "createdBy", ignore = true)
|
||||
@Mapping(target = "modifiedBy", ignore = true)
|
||||
GalleryEntity galleryToGalleryEntity(Gallery gallery);
|
||||
|
||||
Gallery galleryEntityToGallery(GalleryEntity galleryEntity);
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.dh7789dev.xpeditis.mapper;
|
||||
|
||||
import com.dh7789dev.xpeditis.dto.Image;
|
||||
import com.dh7789dev.xpeditis.entity.ImageEntity;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.MappingConstants;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
|
||||
public interface ImageMapper {
|
||||
|
||||
ImageMapper INSTANCE = Mappers.getMapper(ImageMapper.class);
|
||||
|
||||
@Mapping(target = "createdDate", ignore = true)
|
||||
@Mapping(target = "modifiedDate", ignore = true)
|
||||
@Mapping(target = "createdBy", ignore = true)
|
||||
@Mapping(target = "modifiedBy", ignore = true)
|
||||
@Mapping(target = "event", ignore = true)
|
||||
ImageEntity imageToImageEntity(Image image);
|
||||
|
||||
@Mapping(target = "path", ignore = true)
|
||||
@Mapping(target = "uri", expression = "java(\"/api/v1/images/\" + imageEntity.getId())")
|
||||
Image imageEntityToImage(ImageEntity imageEntity);
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package com.dh7789dev.xpeditis.mapper;
|
||||
|
||||
import com.dh7789dev.xpeditis.entity.MenuCategoryEntity;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper(/*componentModel = MappingConstants.ComponentModel.SPRING,*/
|
||||
uses = {ProductMapper.class})
|
||||
public interface MenuCategoryMapper {
|
||||
|
||||
MenuCategoryMapper INSTANCE = Mappers.getMapper(MenuCategoryMapper.class);
|
||||
|
||||
@Mapping(target = "createdDate", ignore = true)
|
||||
@Mapping(target = "modifiedDate", ignore = true)
|
||||
@Mapping(target = "createdBy", ignore = true)
|
||||
@Mapping(target = "modifiedBy", ignore = true)
|
||||
@Mapping(source = "menuItems", target = "products")
|
||||
MenuCategoryEntity menuCategoryToMenuCategoryEntity(MenuCategory menuCategory);
|
||||
|
||||
@Mapping(source = "products", target = "menuItems")
|
||||
MenuCategory menuCategoryEntityToMenuCategory(MenuCategoryEntity menuCategoryEntity);
|
||||
|
||||
List<MenuCategory> menuCategoryEntitiesToMenuCategories(List<MenuCategoryEntity> menuCategoryEntities);
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package com.dh7789dev.xpeditis.mapper;
|
||||
|
||||
import com.dh7789dev.xpeditis.entity.ProductEntity;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.MappingConstants;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
|
||||
public interface ProductMapper {
|
||||
|
||||
ProductMapper INSTANCE = Mappers.getMapper(ProductMapper.class);
|
||||
|
||||
@Mapping(target = "createdDate", ignore = true)
|
||||
@Mapping(target = "modifiedDate", ignore = true)
|
||||
@Mapping(target = "createdBy", ignore = true)
|
||||
@Mapping(target = "modifiedBy", ignore = true)
|
||||
@Mapping(target = "category", ignore = true)
|
||||
ProductEntity menuItemToProductEntity(MenuItem menuItem);
|
||||
|
||||
MenuItem productEntityToMenuItem(ProductEntity productEntity);
|
||||
|
||||
List<MenuItem> productEntitiesToMenuItems(List<ProductEntity> productEntities);
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.dh7789dev.xpeditis.mapper;
|
||||
|
||||
import com.dh7789dev.xpeditis.entity.ReservationEntity;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.MappingConstants;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
|
||||
public interface ReservationMapper {
|
||||
|
||||
ReservationMapper INSTANCE = Mappers.getMapper(ReservationMapper.class);
|
||||
|
||||
@Mapping(target = "createdDate", ignore = true)
|
||||
@Mapping(target = "modifiedDate", ignore = true)
|
||||
@Mapping(target = "createdBy", ignore = true)
|
||||
@Mapping(target = "modifiedBy", ignore = true)
|
||||
ReservationEntity reservationToReservationEntity(Reservation reservation);
|
||||
|
||||
Reservation reservationEntityToReservation(ReservationEntity reservationEntity);
|
||||
|
||||
List<Reservation> reservationEntitiesToReservation(List<ReservationEntity> reservationEntities);
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.dh7789dev.xpeditis.mapper;
|
||||
|
||||
import com.dh7789dev.xpeditis.entity.SelectedDayEntity;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.MappingConstants;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
|
||||
public interface SelectedDayMapper {
|
||||
|
||||
SelectedDayMapper INSTANCE = Mappers.getMapper(SelectedDayMapper.class);
|
||||
|
||||
@Mapping(target = "createdDate", ignore = true)
|
||||
@Mapping(target = "modifiedDate", ignore = true)
|
||||
@Mapping(target = "createdBy", ignore = true)
|
||||
@Mapping(target = "modifiedBy", ignore = true)
|
||||
SelectedDayEntity selectedDayToSelectedDayEntity(SelectedDay selectedDay);
|
||||
|
||||
SelectedDay selectedDayEntityToSelectedDay(SelectedDayEntity selectedDayEntity);
|
||||
|
||||
List<SelectedDay> selectedDayEntitiesToSelectedDays(List<SelectedDayEntity> selectedDayEntities);
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
package com.dh7789dev.xpeditis.repository;
|
||||
|
||||
import com.dh7789dev.xpeditis.AuthenticationRepository;
|
||||
import com.dh7789dev.xpeditis.dao.TokenDao;
|
||||
import com.dh7789dev.xpeditis.dao.UserDao;
|
||||
import com.dh7789dev.xpeditis.dto.AuthenticationRequest;
|
||||
import com.dh7789dev.xpeditis.dto.AuthenticationResponse;
|
||||
import com.dh7789dev.xpeditis.entity.TokenEntity;
|
||||
import com.dh7789dev.xpeditis.entity.UserEntity;
|
||||
import com.dh7789dev.xpeditis.util.JwtUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AuthenticationJwtRepository implements AuthenticationRepository {
|
||||
|
||||
private final AuthenticationManager authenticationManager;
|
||||
private final UserDao userDao;
|
||||
private final TokenDao tokenDao;
|
||||
private final JwtUtil jwtUtil;
|
||||
|
||||
@Override
|
||||
public AuthenticationResponse authenticate(AuthenticationRequest request) {
|
||||
|
||||
log.info("username: {}, password: {}", request.getUsername(), request.getPassword());
|
||||
UsernamePasswordAuthenticationToken authToken = UsernamePasswordAuthenticationToken
|
||||
.unauthenticated(request.getUsername(), request.getPassword());
|
||||
Authentication authentication = authenticationManager.authenticate(authToken);
|
||||
|
||||
if (!authentication.isAuthenticated()) {
|
||||
throw new UsernameNotFoundException("Failed to authenticate");
|
||||
}
|
||||
|
||||
var userEntity = userDao.findByUsername(request.getUsername()).orElseThrow();
|
||||
|
||||
var jwtToken = jwtUtil.generateToken(userEntity);
|
||||
var refreshToken = jwtUtil.generateRefreshToken(userEntity);
|
||||
|
||||
revokeAllUserTokens(userEntity);
|
||||
saveUserToken(userEntity, jwtToken);
|
||||
|
||||
return new AuthenticationResponse()
|
||||
.setAccessToken(jwtToken)
|
||||
.setRefreshToken(refreshToken)
|
||||
.setCreatedAt(jwtUtil.extractCreatedAt(jwtToken))
|
||||
.setExpiresAt(jwtUtil.extractExpiration(jwtToken));
|
||||
}
|
||||
|
||||
private void saveUserToken(UserEntity user, String jwtToken) {
|
||||
var tokenEntity = new TokenEntity()
|
||||
.setUser(user)
|
||||
.setToken(jwtToken)
|
||||
.setTokenType(TokenEntity.Type.BEARER)
|
||||
.setExpired(false)
|
||||
.setRevoked(false);
|
||||
tokenDao.save(tokenEntity);
|
||||
}
|
||||
|
||||
private void revokeAllUserTokens(UserEntity userEntity) {
|
||||
var validUserTokens = tokenDao.findAllValidTokenByUserId(userEntity.getId());
|
||||
if (validUserTokens.isEmpty()) return;
|
||||
validUserTokens.forEach(token -> {
|
||||
token.setExpired(true);
|
||||
token.setRevoked(true);
|
||||
});
|
||||
tokenDao.saveAll(validUserTokens);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package com.dh7789dev.xpeditis.repository;
|
||||
|
||||
import com.dh7789dev.xpeditis.EmailSenderRepository;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Slf4j
|
||||
@Repository
|
||||
public class JavaMailSenderRepository implements EmailSenderRepository {
|
||||
|
||||
@Value("${application.email.from}")
|
||||
String emailAddressFrom;
|
||||
|
||||
private final JavaMailSender emailSender;
|
||||
|
||||
@Autowired
|
||||
public JavaMailSenderRepository(JavaMailSender emailSender) {
|
||||
this.emailSender = emailSender;
|
||||
}
|
||||
|
||||
@Async
|
||||
@Override
|
||||
public void send(String emailAddressTo, String emailContent) {
|
||||
try {
|
||||
MimeMessage mimeMessage = emailSender.createMimeMessage();
|
||||
MimeMessageHelper helperMessage = new MimeMessageHelper(mimeMessage, "utf-8");
|
||||
helperMessage.setText(emailContent, true);
|
||||
helperMessage.setTo(emailAddressTo);
|
||||
helperMessage.setSubject("Reservation Confirmation");
|
||||
helperMessage.setFrom(emailAddressFrom);
|
||||
emailSender.send(mimeMessage);
|
||||
} catch (MessagingException e) {
|
||||
log.error("failed to send email", e);
|
||||
throw new IllegalStateException("failed to send email");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package com.dh7789dev.xpeditis.repository;
|
||||
|
||||
import com.dh7789dev.xpeditis.NlsRepository;
|
||||
import com.dh7789dev.xpeditis.exception.NlsNotFoundException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.NoSuchMessageException;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Slf4j
|
||||
@Repository
|
||||
public class NlsCatalogRepository implements NlsRepository {
|
||||
|
||||
private final MessageSource messageSource;
|
||||
|
||||
@Autowired
|
||||
public NlsCatalogRepository(MessageSource messageSource) {
|
||||
this.messageSource = messageSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key nls message key
|
||||
* @return the message corresponding to the key translated into the desired language
|
||||
*/
|
||||
@Override
|
||||
public String getMessage(String key) {
|
||||
return this.getMessage(key, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key nls message key
|
||||
* @param parameters parameters to use in the message
|
||||
* @return the message corresponding to the key translated into the desired language
|
||||
*/
|
||||
@Override
|
||||
public String getMessage(String key, Object[] parameters) {
|
||||
try {
|
||||
return messageSource.getMessage(key, parameters, LocaleContextHolder.getLocale());
|
||||
} catch (NoSuchMessageException e) {
|
||||
log.warn(e.getMessage());
|
||||
throw new NlsNotFoundException(key, LocaleContextHolder.getLocale().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user