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