feat: upgrade to spring boot 3.5.9
This commit is contained in:
@@ -57,6 +57,8 @@ jobs:
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
build-args: |
|
||||
BUILD=v${{ steps.version.outputs.tag }}
|
||||
|
||||
- name: Create and push Git tag
|
||||
run: |
|
||||
|
||||
+2
-3
@@ -8,12 +8,11 @@ vars:
|
||||
tasks:
|
||||
docker-build-web:
|
||||
desc: Build the tasknote-web prod-ready docker image, tagging it as candidate
|
||||
cmd: docker build --no-cache --build-arg VITE_BUILD="v999-$(date '+%Y-%m-%d-%H%M%S')" --build-arg SOURCE_PR="v999-123456789-$(date '+%Y-%m-%d-%H%M%S')" -t ghcr.io/ricardo-campos-org/react-typescript-todolist/tasknote-web:candidate ./client
|
||||
cmd: docker build --no-cache --build-arg VITE_BUILD="v999-$(date '+%Y-%m-%d-%H%M%S')" --build-arg SOURCE_PR="v999-123456789-$(date '+%Y-%m-%d-%H%M%S')" -t docker.io/rmcampos/tasknote:app-latest ./client
|
||||
|
||||
docker-build-api:
|
||||
desc: Build the tasknote-api prod-ready docker image, tagging it as candidate
|
||||
cmd: docker build --no-cache --build-arg BUILD="v999-$(date '+%Y-%m-%d-%H%M%S')" --build-arg SOURCE_PR="v999-123456789-$(date '+%Y-%m-%d-%H%M%S')" -t ghcr.io/ricardo-campos-org/react-typescript-todolist/tasknote-api:candidate ./server
|
||||
|
||||
cmd: docker build --no-cache --build-arg BUILD="v999-$(date '+%Y-%m-%d-%H%M%S')" --build-arg SOURCE_PR="v999-123456789-$(date '+%Y-%m-%d-%H%M%S')" -t docker.io/rmcampos/tasknote:api-latest ./server
|
||||
prod-up-web:
|
||||
desc: Speed up the tasknote-web prod-like image, building it if required
|
||||
cmd: docker compose -f docker-compose.prod.yml up -d tasknote-web
|
||||
|
||||
@@ -39,7 +39,7 @@ services:
|
||||
ports:
|
||||
- "8585:8585"
|
||||
- "5005:5005"
|
||||
image: maven:3.9.9-eclipse-temurin-17
|
||||
image: maven:3.9.9-eclipse-temurin-21
|
||||
entrypoint: './mvnw -ntp spring-boot:run -Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=*:5005" -Dmaven.plugin.validation=VERBOSE'
|
||||
working_dir: /app
|
||||
volumes:
|
||||
|
||||
+13
-3
@@ -6,13 +6,15 @@ services:
|
||||
depends_on:
|
||||
tasknote-api:
|
||||
condition: service_healthy
|
||||
image: ghcr.io/ricardo-campos-org/react-typescript-todolist/tasknote-web:candidate
|
||||
image: docker.io/rmcampos/tasknote:app-latest
|
||||
build:
|
||||
context: client
|
||||
dockerfile: Dockerfile
|
||||
ports: ["5000:5000"]
|
||||
environment:
|
||||
VITE_BACKEND_SERVER: http://localhost:8585
|
||||
VITE_BACKEND_SERVER: http://tasknote-api:8585
|
||||
networks:
|
||||
- tasknote-network
|
||||
|
||||
tasknote-api:
|
||||
container_name: tasknote-api
|
||||
@@ -31,10 +33,12 @@ services:
|
||||
SECURITY_KEY: this-is-a-very-long-security-key-for-dev
|
||||
MAILGUN_APIKEY: invalid-api-key-only-placeholder
|
||||
ports: ["8585:8585"]
|
||||
image: ghcr.io/ricardo-campos-org/react-typescript-todolist/tasknote-api:candidate
|
||||
image: docker.io/rmcampos/tasknote:api-latest
|
||||
build:
|
||||
context: server
|
||||
dockerfile: Dockerfile
|
||||
networks:
|
||||
- tasknote-network
|
||||
|
||||
tasknote-db:
|
||||
container_name: tasknote-db
|
||||
@@ -50,3 +54,9 @@ services:
|
||||
timeout: 15s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
networks:
|
||||
- tasknote-network
|
||||
|
||||
networks:
|
||||
tasknote-network:
|
||||
driver: bridge
|
||||
@@ -1,45 +0,0 @@
|
||||
### Builder
|
||||
FROM ghcr.io/graalvm/native-image:22.3.3 AS build
|
||||
|
||||
# Copy
|
||||
WORKDIR /app
|
||||
COPY pom.xml mvnw ./
|
||||
COPY src ./src
|
||||
COPY .mvn/ ./.mvn
|
||||
|
||||
# Build
|
||||
RUN ./mvnw -B package -Pnative -DskipTests
|
||||
|
||||
|
||||
### Deployer
|
||||
FROM debian:bookworm-20250929-slim AS deploy
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy
|
||||
WORKDIR /app
|
||||
COPY --from=build /app/target/server ./tasknote-api
|
||||
|
||||
ARG BUILD
|
||||
ARG SOURCE_PR
|
||||
ENV BUILD=${BUILD}
|
||||
ENV SOURCE_PR=${SOURCE_PR}
|
||||
|
||||
# Add metadata to the final image
|
||||
LABEL org.opencontainers.image.authors="Ricardo Campos <ricardompcampos@gmail.com>" \
|
||||
org.opencontainers.image.vendor="Ricardo Campos Org" \
|
||||
org.opencontainers.image.title="TaskNoteApp server" \
|
||||
org.opencontainers.image.description="Spring Cloud Native REST API service" \
|
||||
org.opencontainers.image.version="${SOURCE_PR}" \
|
||||
org.opencontainers.image.source="https://github.com/ricardo-campos-org/react-typescript-todolist"
|
||||
|
||||
# User, port and health check
|
||||
USER 1001
|
||||
EXPOSE ${PORT}
|
||||
#HEALTHCHECK CMD timeout 10s bash -c 'true > /dev/tcp/127.0.0.1/8585'
|
||||
HEALTHCHECK --interval=30s --timeout=5s CMD ["curl", "-f", "http://localhost:8585/actuator/health"]
|
||||
|
||||
# Startup
|
||||
ENTRYPOINT ["/app/tasknote-api", "-Dspring.profiles.active=prod"]
|
||||
@@ -1,4 +0,0 @@
|
||||
FROM maven:3.9.9-eclipse-temurin-17
|
||||
WORKDIR /app
|
||||
HEALTHCHECK CMD timeout 10s bash -c 'true > /dev/tcp/127.0.0.1/8585'
|
||||
CMD ["sh", "run-from-docker.sh"]
|
||||
+33
-106
@@ -11,7 +11,7 @@
|
||||
|
||||
<groupId>br.com.tasknoteapp</groupId>
|
||||
<artifactId>server</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<version>2.0.0</version>
|
||||
<name>tasknote-api</name>
|
||||
<description>Java backend REST API to serve TaskNote frontend client</description>
|
||||
|
||||
@@ -27,6 +27,13 @@
|
||||
<developers>
|
||||
<developer/>
|
||||
</developers>
|
||||
|
||||
<scm>
|
||||
<connection/>
|
||||
<developerConnection/>
|
||||
<tag/>
|
||||
<url/>
|
||||
</scm>
|
||||
|
||||
<!-- Properties -->
|
||||
<properties>
|
||||
@@ -42,9 +49,6 @@
|
||||
<jacoco.output.data>${project.build.directory}/coverage-reports</jacoco.output.data>
|
||||
<timestamp>${maven.build.timestamp}</timestamp>
|
||||
<maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
|
||||
<hibernate.version>6.6.34.Final</hibernate.version>
|
||||
<sonar.organization>ricardo-campos-org</sonar.organization>
|
||||
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
|
||||
</properties>
|
||||
|
||||
<!-- Profiles -->
|
||||
@@ -68,34 +72,6 @@
|
||||
<build.profile.id>prod</build.profile.id>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<!-- Native -->
|
||||
<profile>
|
||||
<id>native</id>
|
||||
<properties>
|
||||
<build.profile.id>native</build.profile.id>
|
||||
<skip.integration.tests>true</skip.integration.tests>
|
||||
<skip.unit.tests>true</skip.unit.tests>
|
||||
<jacoco.skip>true</jacoco.skip>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.graalvm.buildtools</groupId>
|
||||
<artifactId>native-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>build-native</id>
|
||||
<goals>
|
||||
<goal>compile-no-fork</goal>
|
||||
</goals>
|
||||
<phase>package</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<!-- Dependencies -->
|
||||
@@ -119,20 +95,6 @@
|
||||
<artifactId>spring-boot-starter-mail</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Devtools -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- OOps & Tools -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Database -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@@ -141,6 +103,7 @@
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
@@ -168,28 +131,21 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Documentation -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<version>2.8.13</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Authentication -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
<version>0.13.0</version>
|
||||
<version>0.12.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-impl</artifactId>
|
||||
<version>0.13.0</version>
|
||||
<version>0.12.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-jackson</artifactId>
|
||||
<version>0.13.0</version>
|
||||
<artifactId>jjwt-gson</artifactId>
|
||||
<version>0.12.6</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
@@ -357,55 +313,6 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.12.0</version>
|
||||
<configuration>
|
||||
<source>17</source>
|
||||
<doctitle>Javadoc Documentation for ${project.name} ${project.version}</doctitle>
|
||||
<windowtitle>${project.name} ${project.version}</windowtitle>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>3.6.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-cli</id>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<dependencyConvergence/>
|
||||
<requireMavenVersion>
|
||||
<version>[3.2,)</version>
|
||||
<message>Invalid Maven version. It should be at least 3.2</message>
|
||||
</requireMavenVersion>
|
||||
<requireJavaVersion>
|
||||
<version>17</version>
|
||||
<message>Invalid Java Version. It should be at least 1.8</message>
|
||||
</requireJavaVersion>
|
||||
<requireNoRepositories>
|
||||
<allowedRepositories>
|
||||
<id>central</id>
|
||||
</allowedRepositories>
|
||||
<allowedPluginRepositories>
|
||||
<id>central</id>
|
||||
</allowedPluginRepositories>
|
||||
</requireNoRepositories>
|
||||
<requireReleaseDeps>
|
||||
<message>No Snapshots Allowed in releases!</message>
|
||||
<onlyWhenRelease>true</onlyWhenRelease>
|
||||
</requireReleaseDeps>
|
||||
<banDuplicatePomDependencyVersions/>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
@@ -437,6 +344,26 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.graalvm.buildtools</groupId>
|
||||
<artifactId>native-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>build-info</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<additionalProperties>
|
||||
<timestamp>${maven.build.timestamp}</timestamp>
|
||||
</additionalProperties>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
<finalName>tasknote-api</finalName>
|
||||
|
||||
@@ -2,20 +2,22 @@ package br.com.tasknoteapp.server;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
import br.com.tasknoteapp.server.service.AppVersionService;
|
||||
|
||||
/** Entrypoint of the Java API service application. */
|
||||
@SpringBootApplication
|
||||
public class JavaApiApplication implements ApplicationRunner {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JavaApiApplication.class);
|
||||
|
||||
@Value("${br.com.tasknote.server.version}")
|
||||
private String apiBuildInfo;
|
||||
@Autowired
|
||||
private AppVersionService appVersionService;
|
||||
|
||||
/**
|
||||
* Main method of the application.
|
||||
@@ -28,6 +30,6 @@ public class JavaApiApplication implements ApplicationRunner {
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
logger.info("Task Note API started successfully - Version: {}", apiBuildInfo);
|
||||
logger.info("Task Note API started successfully - Version: {}", appVersionService.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package br.com.tasknoteapp.server.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/** This class contains a single component config with image tag version. */
|
||||
@Component
|
||||
public class ApiBuildInfoConfig implements HealthIndicator {
|
||||
|
||||
@Value("${br.com.tasknote.server.version}")
|
||||
private String apiBuildInfo;
|
||||
|
||||
@Override
|
||||
public Health health() {
|
||||
return Health.up().withDetail("buildInfo", apiBuildInfo).build();
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,6 @@
|
||||
package br.com.tasknoteapp.server.config;
|
||||
|
||||
import br.com.tasknoteapp.server.request.LoginRequest;
|
||||
import br.com.tasknoteapp.server.request.NotePatchRequest;
|
||||
import br.com.tasknoteapp.server.request.NoteRequest;
|
||||
import br.com.tasknoteapp.server.request.NoteUrlPatchRequest;
|
||||
import br.com.tasknoteapp.server.request.TaskPatchRequest;
|
||||
import br.com.tasknoteapp.server.request.TaskRequest;
|
||||
import br.com.tasknoteapp.server.request.TaskUrlPatchRequest;
|
||||
import br.com.tasknoteapp.server.response.JwtAuthenticationResponse;
|
||||
import br.com.tasknoteapp.server.response.NoteResponse;
|
||||
import br.com.tasknoteapp.server.response.NoteUrlResponse;
|
||||
import br.com.tasknoteapp.server.response.TaskResponse;
|
||||
import br.com.tasknoteapp.server.response.UserResponse;
|
||||
import br.com.tasknoteapp.server.hint.HttpServletRequestRuntimeHint;
|
||||
import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportRuntimeHints;
|
||||
@@ -19,18 +8,6 @@ import org.springframework.context.annotation.ImportRuntimeHints;
|
||||
/** This class contains configurations for the GraalVM Cloud Native image. */
|
||||
@Configuration
|
||||
@RegisterReflectionForBinding({
|
||||
LoginRequest.class,
|
||||
NotePatchRequest.class,
|
||||
NoteRequest.class,
|
||||
NoteUrlPatchRequest.class,
|
||||
TaskPatchRequest.class,
|
||||
TaskRequest.class,
|
||||
TaskUrlPatchRequest.class,
|
||||
JwtAuthenticationResponse.class,
|
||||
NoteResponse.class,
|
||||
NoteUrlResponse.class,
|
||||
TaskResponse.class,
|
||||
UserResponse.class,
|
||||
io.jsonwebtoken.Claims.class,
|
||||
io.jsonwebtoken.Jwts.class,
|
||||
io.jsonwebtoken.Jwts.SIG.class,
|
||||
@@ -45,7 +22,6 @@ import org.springframework.context.annotation.ImportRuntimeHints;
|
||||
io.jsonwebtoken.impl.DefaultClaimsBuilder.class,
|
||||
io.jsonwebtoken.impl.DefaultJwtParserBuilder.class,
|
||||
io.jsonwebtoken.impl.DefaultJwtBuilder.class,
|
||||
io.jsonwebtoken.impl.DefaultJwtBuilder.Supplier.class,
|
||||
io.jsonwebtoken.lang.Supplier.class,
|
||||
org.flywaydb.core.internal.publishing.PublishingConfigurationExtension.class,
|
||||
})
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package br.com.tasknoteapp.server.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Logger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.lang.NonNull;
|
||||
@@ -12,7 +13,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
@Configuration
|
||||
public class CorsConfig implements WebMvcConfigurer {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CorsConfig.class.getName());
|
||||
private static final Logger logger = LoggerFactory.getLogger(CorsConfig.class.getName());
|
||||
|
||||
@Value("${cors.allowed-origins}")
|
||||
private String[] allowedOrigins;
|
||||
@@ -22,10 +23,10 @@ public class CorsConfig implements WebMvcConfigurer {
|
||||
*
|
||||
* @param registry CorsRegistry instance.
|
||||
*/
|
||||
@SuppressWarnings("null")
|
||||
public void addCorsMappings(@NonNull CorsRegistry registry) {
|
||||
if (allowedOrigins != null && allowedOrigins.length > 0) {
|
||||
logger.info("CORS policy allowed origins: " + Arrays.asList(allowedOrigins));
|
||||
logger.fine("CORS policy allowed origins in debug mode: " + Arrays.asList(allowedOrigins));
|
||||
logger.info("CORS policy allowed origins: {}", Arrays.asList(allowedOrigins));
|
||||
|
||||
registry
|
||||
.addMapping("/**")
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
package br.com.tasknoteapp.server.config;
|
||||
|
||||
import io.swagger.v3.oas.models.Components;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Contact;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import io.swagger.v3.oas.models.info.License;
|
||||
import io.swagger.v3.oas.models.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.models.security.SecurityScheme;
|
||||
import io.swagger.v3.oas.models.security.SecurityScheme.Type;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/** This class contains the configuration for Swagger API. */
|
||||
@Configuration
|
||||
public class SwaggerConfig {
|
||||
|
||||
@Value("${br.com.tasknote.server.version}")
|
||||
private String apiBuildInfo;
|
||||
|
||||
/**
|
||||
* Gets the API OpenAPI config.
|
||||
*
|
||||
* @return OpenAPI with config.
|
||||
*/
|
||||
@Bean
|
||||
public OpenAPI apiConfig() {
|
||||
Info info = new Info();
|
||||
info.setTitle("TaskNote API");
|
||||
info.setDescription("RESTful service API for the web client");
|
||||
info.setVersion(apiBuildInfo);
|
||||
|
||||
Contact contact = new Contact();
|
||||
contact.setName("Ricardo Campos");
|
||||
contact.setEmail("ricardompcampos@gmail.com");
|
||||
contact.setUrl("https://github.com/ricardo-campos-org/react-typescript-todolist");
|
||||
info.setContact(contact);
|
||||
|
||||
License license = new License();
|
||||
license.setName("GPL 3.0");
|
||||
license.setUrl("https://www.gnu.org/licenses/gpl-3.0");
|
||||
info.setLicense(license);
|
||||
|
||||
SecurityScheme securityScheme = new SecurityScheme();
|
||||
securityScheme.setType(Type.HTTP);
|
||||
securityScheme.setScheme("bearer");
|
||||
securityScheme.setBearerFormat("JWT");
|
||||
|
||||
Components components = new Components();
|
||||
components.addSecuritySchemes("bearerAuth", securityScheme);
|
||||
|
||||
OpenAPI openApi = new OpenAPI();
|
||||
openApi.setInfo(info);
|
||||
openApi.addSecurityItem(new SecurityRequirement().addList("bearerAuth"));
|
||||
openApi.setComponents(components);
|
||||
|
||||
return openApi;
|
||||
}
|
||||
}
|
||||
-76
@@ -9,11 +9,6 @@ import br.com.tasknoteapp.server.request.PasswordResetRequest;
|
||||
import br.com.tasknoteapp.server.request.ResendConfirmationRequest;
|
||||
import br.com.tasknoteapp.server.response.UserResponseWithToken;
|
||||
import br.com.tasknoteapp.server.service.AuthService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.Objects;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -26,9 +21,6 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
/** This class contains the resources for handling authentication. */
|
||||
@RestController
|
||||
@RequestMapping("/auth")
|
||||
@Tag(
|
||||
name = "Authentication",
|
||||
description = "Authentication resources to handle user authentication.")
|
||||
public class AuthenticationController {
|
||||
|
||||
private final AuthService authService;
|
||||
@@ -45,20 +37,6 @@ public class AuthenticationController {
|
||||
* @throws EmailAlreadyExistsException when the provide email is already in use.
|
||||
*/
|
||||
@PutMapping(path = "/sign-up", consumes = "application/json", produces = "application/json")
|
||||
@Operation(
|
||||
summary = "Signup a new user",
|
||||
description = "Signup a new user given his email and password",
|
||||
responses = {
|
||||
@ApiResponse(responseCode = "204", description = "User successfully created and saved"),
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Wrong or missing information",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "409",
|
||||
description = "Email already in use",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public ResponseEntity<Void> signUp(@RequestBody @Valid LoginRequest loginRequest) {
|
||||
authService.signUpNewUser(loginRequest);
|
||||
return ResponseEntity.noContent().build();
|
||||
@@ -73,20 +51,6 @@ public class AuthenticationController {
|
||||
* invalid.
|
||||
*/
|
||||
@PostMapping(path = "/sign-in", consumes = "application/json", produces = "application/json")
|
||||
@Operation(
|
||||
summary = "SigIn an existing user",
|
||||
description = "SigIn an existing user given his email and password",
|
||||
responses = {
|
||||
@ApiResponse(responseCode = "200", description = "User successfully logged in"),
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Wrong or missing information",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "User not found",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public ResponseEntity<UserResponseWithToken> signIn(
|
||||
@RequestBody @Valid LoginRequest loginRequest) {
|
||||
UserResponseWithToken response = authService.signInUser(loginRequest);
|
||||
@@ -103,16 +67,6 @@ public class AuthenticationController {
|
||||
* @return No content 204 http code.
|
||||
*/
|
||||
@PostMapping(path = "/email-confirmation", consumes = "application/json")
|
||||
@Operation(
|
||||
summary = "Send a confirmation email to the user",
|
||||
description = "After the registration sends the user a confirmation email",
|
||||
responses = {
|
||||
@ApiResponse(responseCode = "204", description = "User successfully logged in"),
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Wrong or missing information",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
})
|
||||
public ResponseEntity<Void> confirmEmailAddress(
|
||||
@RequestBody @Valid EmailConfirmationRequest confirmation) {
|
||||
authService.confirmUserAccount(confirmation.identification());
|
||||
@@ -126,16 +80,6 @@ public class AuthenticationController {
|
||||
* @return No content 204 http code.
|
||||
*/
|
||||
@PostMapping(path = "/resend-email-confirmation", consumes = "application/json")
|
||||
@Operation(
|
||||
summary = "Re-Send a confirmation email to the user",
|
||||
description = "Allow users to resend the confirmation email",
|
||||
responses = {
|
||||
@ApiResponse(responseCode = "204", description = "User email confirmation resent"),
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Wrong or missing information",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
})
|
||||
public ResponseEntity<Void> resendEmailConfirmation(
|
||||
@RequestBody @Valid ResendConfirmationRequest request) {
|
||||
authService.resendEmailConfirmation(request.email());
|
||||
@@ -149,16 +93,6 @@ public class AuthenticationController {
|
||||
* @return No content 204 http code.
|
||||
*/
|
||||
@PostMapping(path = "/password-reset", consumes = "application/json")
|
||||
@Operation(
|
||||
summary = "Request a user's password reset",
|
||||
description = "Request the user password reset if there's a user",
|
||||
responses = {
|
||||
@ApiResponse(responseCode = "204", description = "User password requested"),
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Wrong or missing information",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
})
|
||||
public ResponseEntity<Void> passwordReset(@RequestBody @Valid ResendConfirmationRequest request) {
|
||||
authService.resetPasswordForUser(request.email());
|
||||
return ResponseEntity.noContent().build();
|
||||
@@ -171,16 +105,6 @@ public class AuthenticationController {
|
||||
* @return No content 204 http code.
|
||||
*/
|
||||
@PostMapping(path = "/complete-password-reset", consumes = "application/json")
|
||||
@Operation(
|
||||
summary = "Confirm the password reset",
|
||||
description = "Confirm and set the new password for the user",
|
||||
responses = {
|
||||
@ApiResponse(responseCode = "204", description = "User password reset completed"),
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Wrong or missing information",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
})
|
||||
public ResponseEntity<Void> completePasswordReset(
|
||||
@RequestBody @Valid PasswordResetRequest request) {
|
||||
authService.confirmResetPasswordForUser(request);
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package br.com.tasknoteapp.server.controller;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.sql.DataSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import br.com.tasknoteapp.server.service.AppVersionService;
|
||||
|
||||
/** Controller to handle health check requests. */
|
||||
@RestController
|
||||
public class HealthController {
|
||||
|
||||
@Autowired private DataSource dataSource;
|
||||
|
||||
@Autowired private AppVersionService appVersionService;
|
||||
|
||||
/**
|
||||
* Endpoint to check the health of the application and its database connection.
|
||||
*
|
||||
* @return ResponseEntity containing health status and version information.
|
||||
*/
|
||||
@GetMapping("/health")
|
||||
public ResponseEntity<Map<String, Object>> health() {
|
||||
Map<String, Object> health = new HashMap<>();
|
||||
Map<String, String> dbHealth = checkDatabase();
|
||||
|
||||
health.put("application", "UP");
|
||||
health.put("version", appVersionService.getVersion());
|
||||
health.put("database", dbHealth);
|
||||
|
||||
boolean isHealthy = "UP".equals(dbHealth.get("status"));
|
||||
HttpStatus status = isHealthy ? HttpStatus.OK : HttpStatus.SERVICE_UNAVAILABLE;
|
||||
|
||||
return ResponseEntity.status(status).body(health);
|
||||
}
|
||||
|
||||
private Map<String, String> checkDatabase() {
|
||||
Map<String, String> dbHealth = new HashMap<>();
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
if (connection.isValid(2)) {
|
||||
dbHealth.put("status", "UP");
|
||||
} else {
|
||||
dbHealth.put("status", "DOWN");
|
||||
dbHealth.put("reason", "Connection invalid");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
dbHealth.put("status", "DOWN");
|
||||
dbHealth.put("error", e.getMessage());
|
||||
}
|
||||
return dbHealth;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,6 @@
|
||||
package br.com.tasknoteapp.server.controller;
|
||||
|
||||
import br.com.tasknoteapp.server.service.HomeService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import java.util.List;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -14,7 +9,6 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
/** This class provides resources to handle home requests by the client. */
|
||||
@RestController
|
||||
@RequestMapping("/rest/home")
|
||||
@Tag(name = "Home", description = "Home resources to handle home page.")
|
||||
public class HomeController {
|
||||
|
||||
private final HomeService homeService;
|
||||
@@ -29,22 +23,6 @@ public class HomeController {
|
||||
* @returns List of String with the tags.
|
||||
*/
|
||||
@GetMapping("/tasks/tags")
|
||||
@Operation(
|
||||
summary = "Get the top 5 tags",
|
||||
description = "Get the top 5 tags or the ones in use",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "List of tags or an empty list",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = String.class, type = "array"))),
|
||||
@ApiResponse(
|
||||
responseCode = "401",
|
||||
description = "Unauthorized. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public List<String> getTasksTags() {
|
||||
return homeService.getTopTasksTag();
|
||||
}
|
||||
|
||||
@@ -6,17 +6,11 @@ import br.com.tasknoteapp.server.request.NotePatchRequest;
|
||||
import br.com.tasknoteapp.server.request.NoteRequest;
|
||||
import br.com.tasknoteapp.server.response.NoteResponse;
|
||||
import br.com.tasknoteapp.server.service.NoteService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
@@ -29,7 +23,6 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
/** This class provides resources to handle notes requests by the client. */
|
||||
@RestController
|
||||
@RequestMapping("/rest/notes")
|
||||
@Tag(name = "Notes", description = "Notes resources to handle stored notes.")
|
||||
public class NoteController {
|
||||
|
||||
private final NoteService noteService;
|
||||
@@ -44,22 +37,6 @@ public class NoteController {
|
||||
* @return List of NoteResponse with all found notes and its urls, if any.
|
||||
*/
|
||||
@GetMapping
|
||||
@Operation(
|
||||
summary = "Get all notes",
|
||||
description = "Get all notes for the current user and its urls, if any",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Notes successfully retrieved",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = NoteResponse.class, type = "array"))),
|
||||
@ApiResponse(
|
||||
responseCode = "401",
|
||||
description = "Unauthorized. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public List<NoteResponse> getAllNotes() {
|
||||
return noteService.getAllNotes();
|
||||
}
|
||||
@@ -72,31 +49,7 @@ public class NoteController {
|
||||
* @throws NoteNotFoundException when note not found.
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@Operation(
|
||||
summary = "Get a note by its ID",
|
||||
description = "Get a note by its ID and its urls, if any.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Return the found Note and its urls, if any."),
|
||||
@ApiResponse(
|
||||
responseCode = "401",
|
||||
description = "Unauthorized. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "Note not found",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public NoteResponse getTaskById(
|
||||
@Parameter(
|
||||
name = "id",
|
||||
in = ParameterIn.PATH,
|
||||
description = "Note id to be fetched.",
|
||||
required = true,
|
||||
schema = @Schema(type = "integer", format = "int64"))
|
||||
@PathVariable
|
||||
Long id) {
|
||||
public NoteResponse getTaskById(@NonNull @PathVariable Long id) {
|
||||
return noteService.getNoteById(id);
|
||||
}
|
||||
|
||||
@@ -109,41 +62,9 @@ public class NoteController {
|
||||
* @throws NoteNotFoundException when note not found.
|
||||
*/
|
||||
@PatchMapping("/{id}")
|
||||
@Operation(
|
||||
summary = "Patch a note",
|
||||
description = "Patch a note and all its urls. Option to patch only the urls.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Note successfully patched",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = NoteResponse.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "401",
|
||||
description = "Unauthorized. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "Note not found",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public ResponseEntity<NoteResponse> patchNote(
|
||||
@Parameter(
|
||||
name = "id",
|
||||
in = ParameterIn.PATH,
|
||||
description = "Note id to be patched.",
|
||||
required = true,
|
||||
schema = @Schema(type = "integer", format = "int64"))
|
||||
@PathVariable
|
||||
Long id,
|
||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
description = "Note data to be patched, including optionally its urls.",
|
||||
required = true)
|
||||
@RequestBody
|
||||
@Valid
|
||||
NotePatchRequest noteRequest) {
|
||||
@PathVariable @NonNull Long id, @RequestBody @Valid NotePatchRequest noteRequest) {
|
||||
|
||||
return ResponseEntity.ok(noteService.patchNote(id, noteRequest));
|
||||
}
|
||||
|
||||
@@ -155,33 +76,7 @@ public class NoteController {
|
||||
* @return NoteResponse containing data that was created.
|
||||
*/
|
||||
@PostMapping
|
||||
@Operation(
|
||||
summary = "Create a note",
|
||||
description = "Create a note and all its urls.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "Note successfully crated.",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = NoteResponse.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Wrong or missing information",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "401",
|
||||
description = "Unauthorized. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
})
|
||||
public ResponseEntity<NoteResponse> postNotes(
|
||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
description = "Note data to be created, including optionally its urls.",
|
||||
required = true)
|
||||
@RequestBody
|
||||
@Valid
|
||||
NoteRequest noteRequest) {
|
||||
public ResponseEntity<NoteResponse> postNotes(@RequestBody @Valid NoteRequest noteRequest) {
|
||||
NoteEntity createdNote = noteService.createNote(noteRequest);
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(NoteResponse.fromEntity(createdNote));
|
||||
}
|
||||
@@ -193,32 +88,7 @@ public class NoteController {
|
||||
* @throws NoteNotFoundException when note not found.
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(
|
||||
summary = "Delete a note",
|
||||
description = "Delete a note given its ID.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "204",
|
||||
description = "Note successfully deleted",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "401",
|
||||
description = "Unauthorized. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "Note not found",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public ResponseEntity<Void> deleteNote(
|
||||
@Parameter(
|
||||
name = "id",
|
||||
in = ParameterIn.PATH,
|
||||
description = "Note id to be patched.",
|
||||
required = true,
|
||||
schema = @Schema(type = "integer", format = "int64"))
|
||||
@PathVariable
|
||||
Long id) {
|
||||
public ResponseEntity<Void> deleteNote(@NonNull @PathVariable Long id) {
|
||||
noteService.deleteNote(id);
|
||||
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
|
||||
}
|
||||
|
||||
@@ -5,17 +5,11 @@ import br.com.tasknoteapp.server.request.TaskPatchRequest;
|
||||
import br.com.tasknoteapp.server.request.TaskRequest;
|
||||
import br.com.tasknoteapp.server.response.TaskResponse;
|
||||
import br.com.tasknoteapp.server.service.TaskService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
@@ -28,7 +22,6 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
/** This class contains resources for handling tasks. */
|
||||
@RestController
|
||||
@RequestMapping("/rest/tasks")
|
||||
@Tag(name = "Tasks", description = "Tasks resources to handle user tasks and urls.")
|
||||
public class TaskController {
|
||||
|
||||
private final TaskService taskService;
|
||||
@@ -43,22 +36,6 @@ public class TaskController {
|
||||
* @return List of TaskResponse with all found tasks and its urls, if any.
|
||||
*/
|
||||
@GetMapping
|
||||
@Operation(
|
||||
summary = "Get all tasks",
|
||||
description = "Get all tasks for the current user and its urls, if any",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Return an array containing found Tasks, or empty array otherwise.",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = TaskResponse.class, type = "array"))),
|
||||
@ApiResponse(
|
||||
responseCode = "401",
|
||||
description = "Unauthorized. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public List<TaskResponse> getAllTasks() {
|
||||
return taskService.getAllTasks();
|
||||
}
|
||||
@@ -71,31 +48,7 @@ public class TaskController {
|
||||
* @throws TaskNotFoundException when task not found.
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@Operation(
|
||||
summary = "Get a task by its ID",
|
||||
description = "Get a task by its ID and its urls, if any.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Return the found Task and its urls, if any."),
|
||||
@ApiResponse(
|
||||
responseCode = "401",
|
||||
description = "Unauthorized. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "Task not found",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public TaskResponse getTaskById(
|
||||
@Parameter(
|
||||
name = "id",
|
||||
in = ParameterIn.PATH,
|
||||
description = "Task id to be fetched.",
|
||||
required = true,
|
||||
schema = @Schema(type = "integer", format = "int64"))
|
||||
@PathVariable
|
||||
Long id) {
|
||||
public TaskResponse getTaskById(@NonNull @PathVariable Long id) {
|
||||
return taskService.getTaskById(id);
|
||||
}
|
||||
|
||||
@@ -108,41 +61,8 @@ public class TaskController {
|
||||
* @throws TaskNotFoundException when task not found.
|
||||
*/
|
||||
@PatchMapping("/{id}")
|
||||
@Operation(
|
||||
summary = "Patch a task",
|
||||
description = "Patch a task and all its urls. Option to patch only the urls.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Task successfully patched",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = TaskResponse.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "401",
|
||||
description = "Unauthorized. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "Task not found",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public ResponseEntity<TaskResponse> patchTask(
|
||||
@Parameter(
|
||||
name = "id",
|
||||
in = ParameterIn.PATH,
|
||||
description = "Task id to be patched.",
|
||||
required = true,
|
||||
schema = @Schema(type = "integer", format = "int64"))
|
||||
@PathVariable
|
||||
Long id,
|
||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
description = "Task data to be patched, including optionally its urls.",
|
||||
required = true)
|
||||
@RequestBody
|
||||
@Valid
|
||||
TaskPatchRequest taskRequest) {
|
||||
@PathVariable @NonNull Long id, @RequestBody @Valid TaskPatchRequest taskRequest) {
|
||||
return ResponseEntity.ok(taskService.patchTask(id, taskRequest));
|
||||
}
|
||||
|
||||
@@ -154,33 +74,7 @@ public class TaskController {
|
||||
* @return TaskResponse containing data that was created.
|
||||
*/
|
||||
@PostMapping
|
||||
@Operation(
|
||||
summary = "Create a task",
|
||||
description = "Create a task and all its urls.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "Task successfully crated.",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = TaskResponse.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Wrong or missing information",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "401",
|
||||
description = "Unauthorized. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
})
|
||||
public ResponseEntity<TaskResponse> postTasks(
|
||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
description = "Task data to be created, including optionally its urls.",
|
||||
required = true)
|
||||
@RequestBody
|
||||
@Valid
|
||||
TaskRequest taskRequest) {
|
||||
public ResponseEntity<TaskResponse> postTasks(@RequestBody @Valid TaskRequest taskRequest) {
|
||||
TaskResponse response = taskService.createTask(taskRequest);
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(response);
|
||||
}
|
||||
@@ -192,32 +86,7 @@ public class TaskController {
|
||||
* @throws TaskNotFoundException when task not found.
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(
|
||||
summary = "Delete a task",
|
||||
description = "Delete a task given its ID.",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "204",
|
||||
description = "Task successfully deleted",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "401",
|
||||
description = "Unauthorized. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "Task not found",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public ResponseEntity<Void> deleteTask(
|
||||
@Parameter(
|
||||
name = "id",
|
||||
in = ParameterIn.PATH,
|
||||
description = "Task id to be patched.",
|
||||
required = true,
|
||||
schema = @Schema(type = "integer", format = "int64"))
|
||||
@PathVariable
|
||||
Long id) {
|
||||
public ResponseEntity<Void> deleteTask(@NonNull @PathVariable Long id) {
|
||||
taskService.deleteTask(id);
|
||||
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
|
||||
}
|
||||
|
||||
@@ -3,11 +3,6 @@ package br.com.tasknoteapp.server.controller;
|
||||
import br.com.tasknoteapp.server.request.UserPatchRequest;
|
||||
import br.com.tasknoteapp.server.response.UserResponse;
|
||||
import br.com.tasknoteapp.server.service.AuthService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -20,7 +15,6 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
/** This class contains resources for handling users admin requests. */
|
||||
@RestController
|
||||
@RequestMapping("/rest/users")
|
||||
@Tag(name = "Users", description = "Users resources to handle stored users.")
|
||||
public class UserController {
|
||||
|
||||
private final AuthService authService;
|
||||
@@ -35,54 +29,13 @@ public class UserController {
|
||||
* @return List of UserEntity with all found users.
|
||||
*/
|
||||
@GetMapping
|
||||
@Operation(
|
||||
summary = "Get all users",
|
||||
description = "Get all users for the current user",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Users successfully retrieved",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = UserResponse.class, type = "array"))),
|
||||
@ApiResponse(
|
||||
responseCode = "401",
|
||||
description = "Unauthorized. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
})
|
||||
public List<UserResponse> getAllUsers() {
|
||||
return authService.getAllUsers();
|
||||
}
|
||||
|
||||
@PatchMapping
|
||||
@Operation(
|
||||
summary = "Patch the user data",
|
||||
description = "Patch all user information. Empty fields will not be updated",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Task successfully patched",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = UserResponse.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "401",
|
||||
description = "Unauthorized. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class))),
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "Task not found",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public ResponseEntity<UserResponse> patchUserInfo(
|
||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
description = "User data to be patched.",
|
||||
required = true)
|
||||
@RequestBody
|
||||
@Valid
|
||||
UserPatchRequest taskRequest) {
|
||||
@RequestBody @Valid UserPatchRequest taskRequest) {
|
||||
UserResponse patched = authService.patchUserInfo(taskRequest);
|
||||
return ResponseEntity.ok().body(patched);
|
||||
}
|
||||
|
||||
@@ -4,11 +4,6 @@ import br.com.tasknoteapp.server.exception.UserNotFoundException;
|
||||
import br.com.tasknoteapp.server.response.JwtAuthenticationResponse;
|
||||
import br.com.tasknoteapp.server.response.UserResponse;
|
||||
import br.com.tasknoteapp.server.service.UserSessionService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -18,7 +13,6 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
/** This class contains resources for handling user sessions. */
|
||||
@RestController
|
||||
@RequestMapping("/rest/user-sessions")
|
||||
@Tag(name = "User Sessions", description = "Resources to handle user sessions.")
|
||||
public class UserSessionController {
|
||||
|
||||
private final UserSessionService userSessionService;
|
||||
@@ -34,16 +28,6 @@ public class UserSessionController {
|
||||
* @throws UserNotFoundException if user not found
|
||||
*/
|
||||
@GetMapping("/refresh")
|
||||
@Operation(
|
||||
summary = "Refresh an existing user session",
|
||||
description = "Refresh an existing user session, generating a new token",
|
||||
responses = {
|
||||
@ApiResponse(responseCode = "200", description = "Session successfully refreshed"),
|
||||
@ApiResponse(
|
||||
responseCode = "401",
|
||||
description = "Unauthorized. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public JwtAuthenticationResponse refresh() {
|
||||
return userSessionService.refreshUserSession();
|
||||
}
|
||||
@@ -54,16 +38,6 @@ public class UserSessionController {
|
||||
* @returns {@link UserResponse} with the user information.
|
||||
*/
|
||||
@DeleteMapping("/delete-account")
|
||||
@Operation(
|
||||
summary = "Delete the user account.",
|
||||
description = "Delete all the user data and information from the server.",
|
||||
responses = {
|
||||
@ApiResponse(responseCode = "200", description = "Account successfully deleted"),
|
||||
@ApiResponse(
|
||||
responseCode = "401",
|
||||
description = "Unauthorized. Access Denied",
|
||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
||||
})
|
||||
public ResponseEntity<UserResponse> deleteAccount() {
|
||||
UserResponse deleted = userSessionService.deleteCurrentUserAccount();
|
||||
return ResponseEntity.ok(deleted);
|
||||
|
||||
@@ -90,7 +90,6 @@ public class UserEntity implements UserDetails {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: generate all Getters and Setters
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package br.com.tasknoteapp.server.filter;
|
||||
|
||||
import br.com.tasknoteapp.server.service.AppVersionService;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
@@ -14,8 +15,7 @@ import org.springframework.web.filter.OncePerRequestFilter;
|
||||
@Component
|
||||
public class HeaderVersionFilter extends OncePerRequestFilter {
|
||||
|
||||
@Value("${br.com.tasknote.server.version}")
|
||||
private String apiBuildInfo;
|
||||
@Autowired private AppVersionService appVersionService;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(
|
||||
@@ -23,7 +23,7 @@ public class HeaderVersionFilter extends OncePerRequestFilter {
|
||||
@NonNull HttpServletResponse response,
|
||||
@NonNull FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
response.setHeader("X-BUILD-INFO", apiBuildInfo);
|
||||
response.setHeader("X-BUILD-INFO", appVersionService.getVersion());
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package br.com.tasknoteapp.server.config;
|
||||
package br.com.tasknoteapp.server.hint;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.aot.hint.ProxyHints;
|
||||
@@ -0,0 +1,32 @@
|
||||
package br.com.tasknoteapp.server.hint;
|
||||
|
||||
import io.jsonwebtoken.io.DeserializationException;
|
||||
import io.jsonwebtoken.io.SerializationException;
|
||||
import io.jsonwebtoken.security.SignatureException;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportRuntimeHints;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* This class creates RuntimeHints for JJWT exceptions to ensure they are available at runtime in
|
||||
* native images.
|
||||
*/
|
||||
@Configuration
|
||||
@ImportRuntimeHints(JjwtRuntimeHints.JjwtHintsRegistrar.class)
|
||||
public class JjwtRuntimeHints {
|
||||
|
||||
static class JjwtHintsRegistrar implements RuntimeHintsRegistrar {
|
||||
@Override
|
||||
public void registerHints(@NonNull RuntimeHints hints, @Nullable ClassLoader classLoader) {
|
||||
// Register JJWT exceptions for reflection
|
||||
hints
|
||||
.reflection()
|
||||
.registerType(SignatureException.class)
|
||||
.registerType(SerializationException.class)
|
||||
.registerType(DeserializationException.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-4
@@ -1,9 +1,6 @@
|
||||
package br.com.tasknoteapp.server.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
/** This record represents a confirmation payload. */
|
||||
@Schema(description = "Confirmation payload for the user to confirm his email account.")
|
||||
public record EmailConfirmationRequest(
|
||||
@Schema(description = "Confirmation token") @NotNull String identification) {}
|
||||
public record EmailConfirmationRequest(@NotNull String identification) {}
|
||||
|
||||
@@ -1,26 +1,17 @@
|
||||
package br.com.tasknoteapp.server.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
/** This class represents a login request with user email and password. */
|
||||
@Schema(description = "Login request with user email and password.")
|
||||
@NotNull
|
||||
public class LoginRequest {
|
||||
@Schema(description = "User email.")
|
||||
@Email
|
||||
@NotNull
|
||||
private String email;
|
||||
@Email @NotNull private String email;
|
||||
|
||||
@Schema(description = "User password.")
|
||||
@NotNull
|
||||
private String password;
|
||||
@NotNull private String password;
|
||||
|
||||
@Schema(description = "User password again.")
|
||||
private String passwordAgain;
|
||||
|
||||
@Schema(description = "User language. (Optional, default English)")
|
||||
private String lang;
|
||||
|
||||
public LoginRequest() {}
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
package br.com.tasknoteapp.server.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/** This record represents a note patch payload. */
|
||||
@Schema(description = "Note patch payload.")
|
||||
public record NotePatchRequest(
|
||||
@Schema(description = "Note title. Optional.") String title,
|
||||
@Schema(description = "Note description. Optional.") String description,
|
||||
@Schema(description = "Note urls. Optional.") String url,
|
||||
@Schema(description = "Note tag, optional.") String tag) {}
|
||||
public record NotePatchRequest(String title, String description, String url, String tag) {}
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
package br.com.tasknoteapp.server.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
/** This record represents a note request to be created. */
|
||||
@Schema(description = "Note request to be created.")
|
||||
public record NoteRequest(
|
||||
@Schema(description = "Note title.") @NotNull String title,
|
||||
@Schema(description = "Note description.") @NotNull String description,
|
||||
@Schema(description = "Note urls. Optional.") String url,
|
||||
@Schema(description = "Note tag, optional.") String tag) {}
|
||||
@NotNull String title, @NotNull String description, String url, String tag) {}
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
package br.com.tasknoteapp.server.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/** This record represents a Note Url payload to be patched. */
|
||||
@Schema(description = "Represents a Note Url payload to be patched.")
|
||||
public record NoteUrlPatchRequest(
|
||||
@Schema(description = "The identification of the note url in the database") Long id,
|
||||
@Schema(description = "The note URL address, if any.") String url) {}
|
||||
public record NoteUrlPatchRequest(Long id, String url) {}
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
package br.com.tasknoteapp.server.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
/** This record represents the confirmation of the password reset. */
|
||||
@Schema(description = "The password request confirmation payload.")
|
||||
public record PasswordResetRequest(
|
||||
@Schema(description = "Reset token") @NotNull String token,
|
||||
@Schema(description = "New password") @NotNull String password,
|
||||
@Schema(description = "New password again") @NotNull String passwordAgain) {}
|
||||
@NotNull String token, @NotNull String password, @NotNull String passwordAgain) {}
|
||||
|
||||
+1
-6
@@ -1,17 +1,12 @@
|
||||
package br.com.tasknoteapp.server.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
/** This class represents a login request with user email and password. */
|
||||
@Schema(description = "Resend confirmation request with user email and password.")
|
||||
@NotNull
|
||||
public class ResendConfirmationRequest {
|
||||
@Schema(description = "User email.")
|
||||
@Email
|
||||
@NotNull
|
||||
private String email;
|
||||
@Email @NotNull private String email;
|
||||
|
||||
public ResendConfirmationRequest() {}
|
||||
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
package br.com.tasknoteapp.server.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.List;
|
||||
|
||||
/** This record represents a task patch payload. */
|
||||
@Schema(description = "Task patch payload.")
|
||||
public record TaskPatchRequest(
|
||||
@Schema(description = "Task description. Optional.") String description,
|
||||
@Schema(description = "Task done definition. Optional.") Boolean done,
|
||||
@Schema(description = "Task urls. Optional.") List<String> urls,
|
||||
@Schema(description = "Due date. Optional.") String dueDate,
|
||||
@Schema(description = "Define high priority. Optional.") Boolean highPriority,
|
||||
@Schema(description = "Task tag, optional.") String tag) {}
|
||||
String description,
|
||||
Boolean done,
|
||||
List<String> urls,
|
||||
String dueDate,
|
||||
Boolean highPriority,
|
||||
String tag) {}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
package br.com.tasknoteapp.server.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
/** This record represents a task request to be created. */
|
||||
@Schema(description = "Task request to be created.")
|
||||
public record TaskRequest(
|
||||
@Schema(description = "Task description.") @NotNull @NotEmpty String description,
|
||||
@Schema(description = "Task urls. Optional.") List<String> urls,
|
||||
@Schema(description = "Due date. Optional.") String dueDate,
|
||||
@Schema(description = "Define high priority. Optional.") Boolean highPriority,
|
||||
@Schema(description = "Task tag, optional.") String tag) {}
|
||||
@NotNull @NotEmpty String description,
|
||||
List<String> urls,
|
||||
String dueDate,
|
||||
Boolean highPriority,
|
||||
String tag) {}
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
package br.com.tasknoteapp.server.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/** This record represents a Task Url payload to be patched. */
|
||||
@Schema(description = "Represents a Task Url payload to be patched.")
|
||||
public record TaskUrlPatchRequest(
|
||||
@Schema(description = "The identification of the task url in the database") Long id,
|
||||
@Schema(description = "The task URL address, if any.") String url) {}
|
||||
public record TaskUrlPatchRequest(Long id, String url) {}
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
package br.com.tasknoteapp.server.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/** This record represents a user patch payload. */
|
||||
@Schema(description = "User patch payload.")
|
||||
public record UserPatchRequest(
|
||||
@Schema(description = "User first name. Optional.") String name,
|
||||
@Schema(description = "User email. Optional.") String email,
|
||||
@Schema(description = "User password. Optional.") String password,
|
||||
@Schema(description = "User password again. Optional.") String passwordAgain,
|
||||
@Schema(description = "User lang. Optional.") String lang) {}
|
||||
String name, String email, String password, String passwordAgain, String lang) {}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
package br.com.tasknoteapp.server.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
@Schema(description = "An object with fields name and the respective error massages")
|
||||
record FieldIssueResponse(String fieldName, String fieldMessage) {}
|
||||
|
||||
+1
-4
@@ -1,7 +1,4 @@
|
||||
package br.com.tasknoteapp.server.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/** This record represents a JWT Token response to be returned to the client. */
|
||||
@Schema(description = "Represents a JWT Token response to be returned to the client.")
|
||||
public record JwtAuthenticationResponse(@Schema(description = "The JWT token") String token) {}
|
||||
public record JwtAuthenticationResponse(String token) {}
|
||||
|
||||
@@ -3,18 +3,11 @@ package br.com.tasknoteapp.server.response;
|
||||
import br.com.tasknoteapp.server.entity.NoteEntity;
|
||||
import br.com.tasknoteapp.server.entity.NoteUrlEntity;
|
||||
import br.com.tasknoteapp.server.util.TimeAgoUtil;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.Objects;
|
||||
|
||||
/** This record represents a task and its urls object to be returned. */
|
||||
@Schema(description = "This record represents a task and its urls object to be returned.")
|
||||
public record NoteResponse(
|
||||
@Schema(description = "The id of the note", example = "1") Long id,
|
||||
@Schema(description = "The title of the note", example = "Note 1") String title,
|
||||
@Schema(description = "The description of the note", example = "Note desc") String description,
|
||||
@Schema(description = "The urls of the task, zero, one or more.", example = "[]") String url,
|
||||
@Schema(description = "When was the last update time of the note") String lastUpdate,
|
||||
@Schema(description = "Task tag, optional.") String tag) {
|
||||
Long id, String title, String description, String url, String lastUpdate, String tag) {
|
||||
|
||||
/**
|
||||
* Creates a NoteResponse given a NoteEntity and its Urls.
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
package br.com.tasknoteapp.server.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/** This record represents a note url object. */
|
||||
@Schema(description = "This record represents a note url object.")
|
||||
public record NoteUrlResponse(
|
||||
@Schema(description = "Note url id", example = "1") Long id,
|
||||
@Schema(description = "Note url link", example = "http://duckduckgo.com") String url) {}
|
||||
public record NoteUrlResponse(Long id, String url) {}
|
||||
|
||||
@@ -2,23 +2,20 @@ package br.com.tasknoteapp.server.response;
|
||||
|
||||
import br.com.tasknoteapp.server.entity.TaskEntity;
|
||||
import br.com.tasknoteapp.server.util.TimeAgoUtil;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
/** This record represents a task and its urls object to be returned. */
|
||||
@Schema(description = "This record represents a task and its urls object to be returned.")
|
||||
public record TaskResponse(
|
||||
@Schema(description = "The id of the task", example = "1") Long id,
|
||||
@Schema(description = "The description of the task", example = "Task 1") String description,
|
||||
@Schema(description = "The done status of the task", example = "false") Boolean done,
|
||||
@Schema(description = "Defined if it's high priority", example = "true") Boolean highPriority,
|
||||
@Schema(description = "Task due date, if any.", example = "true") LocalDate dueDate,
|
||||
@Schema(description = "Task due date, if any.", example = "true") String dueDateFmt,
|
||||
@Schema(description = "When was the last update time of the task") String lastUpdate,
|
||||
@Schema(description = "Task tag, optional.") String tag,
|
||||
@Schema(description = "The urls of the task, zero, one or more.", example = "[]")
|
||||
List<String> urls) {
|
||||
Long id,
|
||||
String description,
|
||||
Boolean done,
|
||||
Boolean highPriority,
|
||||
LocalDate dueDate,
|
||||
String dueDateFmt,
|
||||
String lastUpdate,
|
||||
String tag,
|
||||
List<String> urls) {
|
||||
|
||||
/**
|
||||
* Creates a TaskResponse given a TaskEntity and its Urls.
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
package br.com.tasknoteapp.server.response;
|
||||
|
||||
import br.com.tasknoteapp.server.entity.UserEntity;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Optional;
|
||||
|
||||
/** This record represents a User Response object. */
|
||||
@Schema(description = "This record represents a User Response object.")
|
||||
public record UserResponse(
|
||||
@Schema(description = "The id of the user", example = "1") Long userId,
|
||||
@Schema(description = "The name of the user", example = "John") String name,
|
||||
@Schema(description = "The email of the user", example = "user@domain.com") String email,
|
||||
@Schema(description = "The admin status of the user", example = "false") Boolean admin,
|
||||
@Schema(description = "The created date and time of the user", example = "2023-01-01T00:00:00")
|
||||
LocalDateTime createdAt,
|
||||
@Schema(
|
||||
description = "The inactivated date and time of the user",
|
||||
example = "2023-01-01T00:00:00")
|
||||
LocalDateTime inactivatedAt,
|
||||
@Schema(description = "The gravatar image URL, if any") String gravatarImageUrl) {
|
||||
Long userId,
|
||||
String name,
|
||||
String email,
|
||||
Boolean admin,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime inactivatedAt,
|
||||
String gravatarImageUrl) {
|
||||
|
||||
/**
|
||||
* Create a {@link UserResponse} instance from a {@link UserEntity}.
|
||||
|
||||
@@ -1,26 +1,20 @@
|
||||
package br.com.tasknoteapp.server.response;
|
||||
|
||||
import br.com.tasknoteapp.server.entity.UserEntity;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Optional;
|
||||
|
||||
/** This record represents a User Response object. */
|
||||
@Schema(description = "This record represents a User Response with token object.")
|
||||
public record UserResponseWithToken(
|
||||
@Schema(description = "The id of the user", example = "1") Long userId,
|
||||
@Schema(description = "The name of the user", example = "John") String name,
|
||||
@Schema(description = "The email of the user", example = "user@domain.com") String email,
|
||||
@Schema(description = "The admin status of the user", example = "false") Boolean admin,
|
||||
@Schema(description = "The created date and time of the user", example = "2023-01-01T00:00:00")
|
||||
LocalDateTime createdAt,
|
||||
@Schema(
|
||||
description = "The inactivated date and time of the user",
|
||||
example = "2023-01-01T00:00:00")
|
||||
LocalDateTime inactivatedAt,
|
||||
@Schema(description = "The gravatar image URL, if any") String gravatarImageUrl,
|
||||
@Schema(description = "The token created upon login") String token,
|
||||
@Schema(description = "The language selected upon login") String lang) {
|
||||
Long userId,
|
||||
String name,
|
||||
String email,
|
||||
Boolean admin,
|
||||
LocalDateTime createdAt,
|
||||
LocalDateTime inactivatedAt,
|
||||
String gravatarImageUrl,
|
||||
String token,
|
||||
String lang) {
|
||||
|
||||
/**
|
||||
* Create a {@link UserResponseWithToken} instance from a {@link UserEntity}.
|
||||
|
||||
-4
@@ -1,19 +1,15 @@
|
||||
package br.com.tasknoteapp.server.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.List;
|
||||
import org.springframework.validation.FieldError;
|
||||
|
||||
/** This class represents a validation error exception to be returned in the JSON format. */
|
||||
@Schema(description = "An object containing the error message and the invalid fields")
|
||||
public class ValidationExceptionResponse {
|
||||
|
||||
private static final String MESSAGE_TEMPLATE = "%d field(s) with validation problems!";
|
||||
|
||||
@Schema(description = "The error message")
|
||||
private final String errorMessage;
|
||||
|
||||
@Schema(description = "An array of 'FieldIssue' with the invalid fields")
|
||||
private final List<FieldIssueResponse> fields;
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package br.com.tasknoteapp.server.service;
|
||||
|
||||
import org.springframework.boot.info.BuildProperties;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/** Service to retrieve application version information. */
|
||||
@Service
|
||||
public class AppVersionService {
|
||||
|
||||
private final BuildProperties buildProperties;
|
||||
|
||||
/**
|
||||
* Constructor for AppVersionService.
|
||||
*
|
||||
* @param buildProperties the build properties injected by Spring Boot
|
||||
*/
|
||||
public AppVersionService(BuildProperties buildProperties) {
|
||||
this.buildProperties = buildProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the application version combined with the build time.
|
||||
*
|
||||
* @return a string representing the application version and build time
|
||||
*/
|
||||
public String getVersion() {
|
||||
return buildProperties.getVersion() + "-" + buildProperties.getTime();
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,8 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
@@ -48,7 +49,7 @@ import org.springframework.stereotype.Service;
|
||||
@Service
|
||||
public class AuthService {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AuthService.class.getName());
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuthService.class);
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
@@ -105,7 +106,7 @@ public class AuthService {
|
||||
*/
|
||||
@Transactional
|
||||
public UserResponseWithToken signUpNewUser(LoginRequest newUser) {
|
||||
logger.info("Signing up new user: " + newUser.email());
|
||||
logger.info("Signing up new user: {}", newUser.email());
|
||||
|
||||
if (findByEmail(newUser.email()).isPresent()) {
|
||||
throw new EmailAlreadyExistsException();
|
||||
@@ -203,8 +204,8 @@ public class AuthService {
|
||||
userRepository.save(user);
|
||||
return UserResponseWithToken.fromEntity(user, token, getGravatarImageUrl(login.email()));
|
||||
} catch (BadCredentialsException e) {
|
||||
logger.severe(
|
||||
"BadCredentialsException when logging in user " + user.getId() + ": " + e.getMessage());
|
||||
logger.error(
|
||||
"BadCredentialsException when logging in user {}: {}", user.getId(), e.getMessage());
|
||||
|
||||
// store attempt
|
||||
UserPwdLimitEntity pwdLimit = new UserPwdLimitEntity();
|
||||
@@ -225,28 +226,28 @@ public class AuthService {
|
||||
public List<UserResponse> getAllUsers() {
|
||||
Optional<String> currentUserEmail = authUtil.getCurrentUserEmail();
|
||||
if (currentUserEmail.isEmpty()) {
|
||||
logger.severe("Unable to get current user from the request");
|
||||
logger.error("Unable to get current user from the request");
|
||||
throw new UserNotFoundException();
|
||||
}
|
||||
|
||||
Optional<UserEntity> currentUserOpt = findByEmail(currentUserEmail.get());
|
||||
if (currentUserOpt.isEmpty()) {
|
||||
logger.severe("Unable to find user by email with value: " + currentUserEmail.get());
|
||||
logger.error("Unable to find user by email with value: {}", currentUserEmail.get());
|
||||
throw new UserNotFoundException();
|
||||
}
|
||||
|
||||
UserEntity currentUser = currentUserOpt.get();
|
||||
if (!currentUser.getAdmin()) {
|
||||
logger.warning("User " + currentUser.getId() + " not allowed to list users.");
|
||||
logger.warn("User {} not allowed to list users.", currentUser.getId());
|
||||
throw new UserForbiddenException();
|
||||
}
|
||||
|
||||
logger.info("Getting all users to user " + currentUser.getId());
|
||||
logger.info("Getting all users to user {}", currentUser.getId());
|
||||
List<UserEntity> users = userRepository.findAll();
|
||||
List<UserResponse> usersResponse = new ArrayList<>(users.size());
|
||||
users.forEach(
|
||||
u -> usersResponse.add(UserResponse.fromEntity(u, getGravatarImageUrl(u.getEmail()))));
|
||||
logger.info(usersResponse.size() + " user(s) found!");
|
||||
logger.info("{} user(s) found!", usersResponse.size());
|
||||
|
||||
return usersResponse;
|
||||
}
|
||||
@@ -261,11 +262,11 @@ public class AuthService {
|
||||
String email = currentUserEmail.orElseThrow();
|
||||
UserEntity currentUser = findByEmail(email).orElseThrow();
|
||||
|
||||
logger.info("Refreshing current session to user " + currentUser.getId());
|
||||
logger.info("Refreshing current session to user {}", currentUser.getId());
|
||||
|
||||
String token = jwtService.generateToken(currentUser);
|
||||
|
||||
logger.info("User refreshed! Token " + token);
|
||||
logger.info("User refreshed! Token {}", token);
|
||||
return token;
|
||||
}
|
||||
|
||||
@@ -279,7 +280,7 @@ public class AuthService {
|
||||
String email = currentUserEmail.orElseThrow();
|
||||
UserEntity currentUser = findByEmail(email).orElseThrow();
|
||||
|
||||
logger.info("Deleting account for user " + currentUser.getId());
|
||||
logger.info("Deleting account for user {}", currentUser.getId());
|
||||
|
||||
currentUser.setInactivatedAt(LocalDateTime.now());
|
||||
userPwdLimitRepository.deleteAllForUser(currentUser.getId());
|
||||
@@ -336,7 +337,7 @@ public class AuthService {
|
||||
shouldUpdate = true;
|
||||
}
|
||||
|
||||
if (shouldUpdate) {
|
||||
if (shouldUpdate && currentUser != null) {
|
||||
userRepository.save(currentUser);
|
||||
}
|
||||
|
||||
@@ -503,10 +504,10 @@ public class AuthService {
|
||||
}
|
||||
hexString.append(hex);
|
||||
}
|
||||
logger.fine("Email hashed: " + hexString);
|
||||
logger.debug("Email hashed: {}", hexString);
|
||||
return Optional.of(hexString.toString());
|
||||
} catch (NoSuchAlgorithmException | NullPointerException e) {
|
||||
logger.severe("NoSuchAlgorithmException or NullPointerException: " + e.getMessage());
|
||||
logger.error("NoSuchAlgorithmException or NullPointerException: {}", e.getMessage());
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
@@ -515,15 +516,15 @@ public class AuthService {
|
||||
Sort sort = Sort.by(Direction.DESC, "whenHappened");
|
||||
List<UserPwdLimitEntity> userPwdList = userPwdLimitRepository.findAllByUser_id(userId, sort);
|
||||
|
||||
logger.warning("login count attempt for user " + userId + ": " + userPwdList.size());
|
||||
logger.warn("login count attempt for user {}: {}", userId, userPwdList.size());
|
||||
|
||||
// if it's more than 3 times in the last 10 minutes, raise timer of 3 hours.
|
||||
if (userPwdList.size() >= 3) {
|
||||
UserPwdLimitEntity mostRecent = userPwdList.get(0);
|
||||
logger.warning("Oldest: " + mostRecent.getWhenHappened());
|
||||
logger.warn("Oldest: {}", mostRecent.getWhenHappened());
|
||||
Duration duration = Duration.between(mostRecent.getWhenHappened(), LocalDateTime.now());
|
||||
if (duration.toMinutes() <= 3L) {
|
||||
logger.warning("Wait more " + (3L - duration.toMinutes()));
|
||||
logger.warn("Wait more {}", 3L - duration.toMinutes());
|
||||
throw new MaxLoginLimitAttemptException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,15 +5,16 @@ import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/** This class contains the implementation for the Home Service class. */
|
||||
@Service
|
||||
public class HomeService {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(HomeService.class.getName());
|
||||
private static final Logger logger = LoggerFactory.getLogger(HomeService.class);
|
||||
|
||||
private final TaskService taskService;
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ import br.com.tasknoteapp.server.templates.MailgunTemplateSignUp;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Logger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.http.HttpEntity;
|
||||
@@ -27,7 +28,7 @@ import org.springframework.web.client.RestTemplate;
|
||||
@Service
|
||||
public class MailgunEmailService {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MailgunEmailService.class.getName());
|
||||
private static final Logger logger = LoggerFactory.getLogger(MailgunEmailService.class);
|
||||
private final RestTemplate restTemplate;
|
||||
private final String targetEnv;
|
||||
private String domain;
|
||||
@@ -151,7 +152,7 @@ public class MailgunEmailService {
|
||||
mailData.add("template", template.getName());
|
||||
if (!template.getVariables().isEmpty()) {
|
||||
mailData.add("h:X-Mailgun-Variables", template.getVariableValuesJson());
|
||||
logger.info("JSON template variables: " + template.getVariableValuesJson());
|
||||
logger.info("JSON template variables: {}", template.getVariableValuesJson());
|
||||
}
|
||||
|
||||
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(mailData, headers);
|
||||
@@ -165,7 +166,7 @@ public class MailgunEmailService {
|
||||
|
||||
logger.info("Email message send successfully.");
|
||||
} catch (HttpClientErrorException ex) {
|
||||
logger.severe("Unable to send email: " + ex.getMessage() + " - " + ex.getCause());
|
||||
logger.error("Unable to send email: {} - {}", ex.getMessage(), ex.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,14 +16,16 @@ import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.logging.Logger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/** This class implements the NoteService interface methods. */
|
||||
@Service
|
||||
public class NoteService {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(NoteService.class.getName());
|
||||
private static final Logger logger = LoggerFactory.getLogger(NoteService.class);
|
||||
|
||||
private final NoteRepository noteRepository;
|
||||
|
||||
@@ -74,7 +76,7 @@ public class NoteService {
|
||||
* @param noteId The task id in the database.
|
||||
* @return {@link NoteResponse} with the found task or throw a {@link TaskNotFoundException}.
|
||||
*/
|
||||
public NoteResponse getNoteById(Long noteId) {
|
||||
public NoteResponse getNoteById(@NonNull Long noteId) {
|
||||
UserEntity user = getCurrentUser();
|
||||
logger.info("Get note " + noteId + " to user " + user.getId());
|
||||
|
||||
@@ -125,7 +127,7 @@ public class NoteService {
|
||||
* @return {@link NoteResponse} containing the updated note.
|
||||
*/
|
||||
@Transactional
|
||||
public NoteResponse patchNote(Long noteId, NotePatchRequest patch) {
|
||||
public NoteResponse patchNote(@NonNull Long noteId, NotePatchRequest patch) {
|
||||
UserEntity user = getCurrentUser();
|
||||
|
||||
logger.info("Patching task " + noteId + " to user " + user.getId());
|
||||
@@ -172,7 +174,7 @@ public class NoteService {
|
||||
* @param noteId The note id from the database.
|
||||
*/
|
||||
@Transactional
|
||||
public void deleteNote(Long noteId) {
|
||||
public void deleteNote(@NonNull Long noteId) {
|
||||
UserEntity user = getCurrentUser();
|
||||
|
||||
logger.info("Deleting note " + noteId + " to user " + user.getId());
|
||||
@@ -182,7 +184,9 @@ public class NoteService {
|
||||
throw new NoteNotFoundException();
|
||||
}
|
||||
|
||||
NoteUrlEntity noteUrl = note.get().getNoteUrl();
|
||||
NoteEntity noteEntity = note.get();
|
||||
|
||||
NoteUrlEntity noteUrl = noteEntity.getNoteUrl();
|
||||
if (!Objects.isNull(noteUrl)) {
|
||||
noteUrlRepository.delete(noteUrl);
|
||||
logger.info("URL Deleted from task " + noteId);
|
||||
@@ -190,7 +194,7 @@ public class NoteService {
|
||||
logger.info("No urls to delete for task " + noteId);
|
||||
}
|
||||
|
||||
noteRepository.delete(note.get());
|
||||
noteRepository.delete(noteEntity);
|
||||
|
||||
logger.info("Note deleted! Id " + noteId);
|
||||
}
|
||||
|
||||
@@ -19,14 +19,16 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.logging.Logger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/** This class contains the implementation for the Task Service class. */
|
||||
@Service
|
||||
public class TaskService {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(TaskService.class.getName());
|
||||
private static final Logger logger = LoggerFactory.getLogger(TaskService.class);
|
||||
|
||||
private final TaskRepository taskRepository;
|
||||
|
||||
@@ -78,7 +80,7 @@ public class TaskService {
|
||||
* @param taskId The task id in the database.
|
||||
* @return {@link TaskResponse} with the found task or throw a {@link TaskNotFoundException}.
|
||||
*/
|
||||
public TaskResponse getTaskById(Long taskId) {
|
||||
public TaskResponse getTaskById(@NonNull Long taskId) {
|
||||
UserEntity user = getCurrentUser();
|
||||
logger.info("Get task " + taskId + " to user " + user.getId());
|
||||
|
||||
@@ -129,7 +131,7 @@ public class TaskService {
|
||||
* @return {@link TaskResponse} with the updated content.
|
||||
*/
|
||||
@Transactional
|
||||
public TaskResponse patchTask(Long taskId, TaskPatchRequest patch) {
|
||||
public TaskResponse patchTask(@NonNull Long taskId, TaskPatchRequest patch) {
|
||||
UserEntity user = getCurrentUser();
|
||||
|
||||
logger.info("Patching task " + taskId + " to user " + user.getId());
|
||||
@@ -175,7 +177,7 @@ public class TaskService {
|
||||
* @param taskId The task id in the database
|
||||
*/
|
||||
@Transactional
|
||||
public void deleteTask(Long taskId) {
|
||||
public void deleteTask(@NonNull Long taskId) {
|
||||
UserEntity user = getCurrentUser();
|
||||
|
||||
logger.info("Deleting task " + taskId + " to user " + user.getId());
|
||||
@@ -185,7 +187,9 @@ public class TaskService {
|
||||
throw new TaskNotFoundException();
|
||||
}
|
||||
|
||||
List<TaskUrlEntity> urlsToDelete = taskUrlRepository.findAllById_taskId(taskId);
|
||||
TaskEntity taskEntity = task.get();
|
||||
|
||||
List<TaskUrlEntity> urlsToDelete = taskUrlRepository.findAllById_taskId(taskEntity.getId());
|
||||
if (!urlsToDelete.isEmpty()) {
|
||||
taskUrlRepository.deleteAllById_taskId(taskId);
|
||||
logger.info("Deleted " + urlsToDelete.size() + " urls from task " + taskId);
|
||||
@@ -193,7 +197,7 @@ public class TaskService {
|
||||
logger.info("No urls to delete for task " + taskId);
|
||||
}
|
||||
|
||||
taskRepository.delete(task.get());
|
||||
taskRepository.delete(taskEntity);
|
||||
|
||||
logger.info("Task deleted! Id " + taskId);
|
||||
}
|
||||
@@ -295,7 +299,7 @@ public class TaskService {
|
||||
try {
|
||||
taskEntity.setDueDate(LocalDate.parse(patch.dueDate()));
|
||||
} catch (DateTimeParseException e) {
|
||||
logger.severe(
|
||||
logger.error(
|
||||
"Unable to parse the provided date: " + patch.dueDate() + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,12 +59,18 @@ public class UserSessionService {
|
||||
|
||||
List<TaskResponse> tasks = taskService.getAllTasks();
|
||||
for (TaskResponse task : tasks) {
|
||||
taskService.deleteTask(task.id());
|
||||
Long taskId = task != null ? task.id() : null;
|
||||
if (taskId != null) {
|
||||
taskService.deleteTask(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
List<NoteResponse> notes = noteService.getAllNotes();
|
||||
for (NoteResponse note : notes) {
|
||||
noteService.deleteNote(note.id());
|
||||
Long noteId = note != null ? note.id() : null;
|
||||
if (noteId != null) {
|
||||
noteService.deleteNote(noteId);
|
||||
}
|
||||
}
|
||||
|
||||
return authService.deleteUserAccount();
|
||||
|
||||
@@ -1,162 +0,0 @@
|
||||
{
|
||||
"reflection": [
|
||||
{
|
||||
"type": "io.jsonwebtoken.Claims"
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.Header"
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.Identifiable"
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.JwsHeader"
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.ProtectedHeader"
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.DefaultClaims",
|
||||
"allDeclaredFields": true
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.DefaultClaimsBuilder$Supplier",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.DefaultHeader",
|
||||
"allDeclaredFields": true
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.DefaultJwsHeader",
|
||||
"allDeclaredFields": true
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.DefaultJwtBuilder$Supplier",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.DefaultJwtHeaderBuilder$Supplier",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.DefaultJwtParserBuilder$Supplier",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.DefaultProtectedHeader",
|
||||
"allDeclaredFields": true
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.ParameterMap",
|
||||
"allDeclaredFields": true
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.io.StandardCompressionAlgorithms",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.lang.Nameable"
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.lang.ParameterReadable"
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.security.DefaultKeyOperationBuilder$Supplier",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.security.DefaultKeyOperationPolicyBuilder$Supplier",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.security.StandardEncryptionAlgorithms",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.security.StandardKeyAlgorithms",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.security.StandardKeyOperations",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.impl.security.StandardSecureDigestAlgorithms",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.jackson.io.JacksonDeserializer"
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.jackson.io.JacksonSerializer"
|
||||
},
|
||||
{
|
||||
"type": "io.jsonwebtoken.security.X509Accessor"
|
||||
}
|
||||
],
|
||||
"resources": [
|
||||
{
|
||||
"glob": "META-INF/services/io.jsonwebtoken.io.Deserializer"
|
||||
},
|
||||
{
|
||||
"glob": "META-INF/services/io.jsonwebtoken.io.Serializer"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,665 +0,0 @@
|
||||
[
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.MacSigner"
|
||||
},
|
||||
"name": "com.sun.crypto.provider.HmacCore$HmacSHA256",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.MacSigner"
|
||||
},
|
||||
"name": "com.sun.crypto.provider.HmacCore$HmacSHA384",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.MacSigner"
|
||||
},
|
||||
"name": "com.sun.crypto.provider.HmacCore$HmacSHA512",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.MacProvider"
|
||||
},
|
||||
"name": "com.sun.crypto.provider.KeyGeneratorCore$HmacKG$SHA256",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.MacProvider"
|
||||
},
|
||||
"name": "com.sun.crypto.provider.KeyGeneratorCore$HmacKG$SHA384",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.MacProvider"
|
||||
},
|
||||
"name": "com.sun.crypto.provider.KeyGeneratorCore$HmacKG$SHA512",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.DefaultJwtBuilder"
|
||||
},
|
||||
"name": "io.jsonwebtoken.impl.DefaultClaims",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.DefaultJwtBuilder"
|
||||
},
|
||||
"name": "io.jsonwebtoken.impl.DefaultJwsHeader",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.Jwts"
|
||||
},
|
||||
"name": "io.jsonwebtoken.impl.DefaultJwtBuilder",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.Jwts"
|
||||
},
|
||||
"name": "io.jsonwebtoken.impl.DefaultJwtParserBuilder",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.DefaultJwtParserBuilder"
|
||||
},
|
||||
"name": "io.jsonwebtoken.impl.DefaultJwtParserBuilder$Supplier",
|
||||
"allDeclaredConstructors": true,
|
||||
"allPublicConstructors": true,
|
||||
"allDeclaredMethods": true,
|
||||
"allPublicMethods": true,
|
||||
"allDeclaredFields": true,
|
||||
"allPublicFields": true
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.DefaultJwtParserBuilder"
|
||||
},
|
||||
"name": "io.jsonwebtoken.impl.DefaultJwtParser",
|
||||
"allDeclaredConstructors": true,
|
||||
"allPublicConstructors": true,
|
||||
"allDeclaredMethods": true,
|
||||
"allPublicMethods": true,
|
||||
"allDeclaredFields": true,
|
||||
"allPublicFields": true
|
||||
},
|
||||
{
|
||||
"name": "io.jsonwebtoken.impl.DefaultJwtParserBuilder$Supplier",
|
||||
"allDeclaredConstructors": true,
|
||||
"allPublicConstructors": true,
|
||||
"allDeclaredMethods": true,
|
||||
"allPublicMethods": true,
|
||||
"allDeclaredFields": true,
|
||||
"allPublicFields": true
|
||||
},
|
||||
{
|
||||
"name": "io.jsonwebtoken.impl.DefaultJwtParser",
|
||||
"allDeclaredConstructors": true,
|
||||
"allPublicConstructors": true,
|
||||
"allDeclaredMethods": true,
|
||||
"allPublicMethods": true,
|
||||
"allDeclaredFields": true,
|
||||
"allPublicFields": true
|
||||
},
|
||||
{
|
||||
"name": "io.jsonwebtoken.impl.DefaultJwtParserBuilder",
|
||||
"allDeclaredConstructors": true,
|
||||
"allPublicConstructors": true,
|
||||
"allDeclaredMethods": true,
|
||||
"allPublicMethods": true,
|
||||
"allDeclaredFields": true,
|
||||
"allPublicFields": true
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.CompressionCodecs"
|
||||
},
|
||||
"name": "io.jsonwebtoken.impl.compression.DeflateCompressionCodec",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.CompressionCodecs"
|
||||
},
|
||||
"name": "io.jsonwebtoken.impl.compression.GzipCompressionCodec",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.security.Keys"
|
||||
},
|
||||
"name": "io.jsonwebtoken.impl.crypto.EllipticCurveProvider",
|
||||
"methods": [
|
||||
{
|
||||
"name": "generateKeyPair",
|
||||
"parameterTypes": [
|
||||
"io.jsonwebtoken.SignatureAlgorithm"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.security.Keys"
|
||||
},
|
||||
"name": "io.jsonwebtoken.impl.crypto.MacProvider",
|
||||
"methods": [
|
||||
{
|
||||
"name": "generateKey",
|
||||
"parameterTypes": [
|
||||
"io.jsonwebtoken.SignatureAlgorithm"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.security.Keys"
|
||||
},
|
||||
"name": "io.jsonwebtoken.impl.crypto.RsaProvider",
|
||||
"methods": [
|
||||
{
|
||||
"name": "generateKeyPair",
|
||||
"parameterTypes": [
|
||||
"io.jsonwebtoken.SignatureAlgorithm"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.EllipticCurveProvider"
|
||||
},
|
||||
"name": "java.security.AlgorithmParametersSpi"
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.EllipticCurveSigner"
|
||||
},
|
||||
"name": "java.security.SecureRandomParameters"
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.MacProvider"
|
||||
},
|
||||
"name": "java.security.SecureRandomParameters"
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.SignatureProvider"
|
||||
},
|
||||
"name": "java.security.SecureRandomParameters"
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.EllipticCurveSigner"
|
||||
},
|
||||
"name": "java.security.interfaces.ECPrivateKey"
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.EllipticCurveSigner"
|
||||
},
|
||||
"name": "java.security.interfaces.ECPublicKey"
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.RsaSigner"
|
||||
},
|
||||
"name": "java.security.interfaces.RSAPrivateKey"
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.RsaSigner"
|
||||
},
|
||||
"name": "java.security.interfaces.RSAPublicKey"
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.gson.io.GsonSerializer"
|
||||
},
|
||||
"name": "java.sql.Date"
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.EllipticCurveSigner"
|
||||
},
|
||||
"name": "sun.security.provider.NativePRNG",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.MacProvider"
|
||||
},
|
||||
"name": "sun.security.provider.NativePRNG",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.SignatureProvider"
|
||||
},
|
||||
"name": "sun.security.provider.NativePRNG",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.EllipticCurveSignatureValidator"
|
||||
},
|
||||
"name": "sun.security.provider.SHA2$SHA256",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.EllipticCurveSigner"
|
||||
},
|
||||
"name": "sun.security.provider.SHA2$SHA256",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.MacSigner"
|
||||
},
|
||||
"name": "sun.security.provider.SHA2$SHA256",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.RsaSignatureValidator"
|
||||
},
|
||||
"name": "sun.security.provider.SHA2$SHA256",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.RsaSigner"
|
||||
},
|
||||
"name": "sun.security.provider.SHA2$SHA256",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.SignatureProvider"
|
||||
},
|
||||
"name": "sun.security.provider.SHA2$SHA256",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.EllipticCurveSignatureValidator"
|
||||
},
|
||||
"name": "sun.security.provider.SHA5$SHA384",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.EllipticCurveSigner"
|
||||
},
|
||||
"name": "sun.security.provider.SHA5$SHA384",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.MacSigner"
|
||||
},
|
||||
"name": "sun.security.provider.SHA5$SHA384",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.RsaSignatureValidator"
|
||||
},
|
||||
"name": "sun.security.provider.SHA5$SHA384",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.RsaSigner"
|
||||
},
|
||||
"name": "sun.security.provider.SHA5$SHA384",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.SignatureProvider"
|
||||
},
|
||||
"name": "sun.security.provider.SHA5$SHA384",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.EllipticCurveSignatureValidator"
|
||||
},
|
||||
"name": "sun.security.provider.SHA5$SHA512",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.EllipticCurveSigner"
|
||||
},
|
||||
"name": "sun.security.provider.SHA5$SHA512",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.MacSigner"
|
||||
},
|
||||
"name": "sun.security.provider.SHA5$SHA512",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.RsaSignatureValidator"
|
||||
},
|
||||
"name": "sun.security.provider.SHA5$SHA512",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.RsaSigner"
|
||||
},
|
||||
"name": "sun.security.provider.SHA5$SHA512",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.SignatureProvider"
|
||||
},
|
||||
"name": "sun.security.provider.SHA5$SHA512",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.RsaProvider"
|
||||
},
|
||||
"name": "sun.security.rsa.RSAKeyPairGenerator$Legacy",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.RsaSignatureValidator"
|
||||
},
|
||||
"name": "sun.security.rsa.RSASignature$SHA256withRSA",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.RsaSigner"
|
||||
},
|
||||
"name": "sun.security.rsa.RSASignature$SHA256withRSA",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.RsaSignatureValidator"
|
||||
},
|
||||
"name": "sun.security.rsa.RSASignature$SHA384withRSA",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.RsaSigner"
|
||||
},
|
||||
"name": "sun.security.rsa.RSASignature$SHA384withRSA",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.RsaSignatureValidator"
|
||||
},
|
||||
"name": "sun.security.rsa.RSASignature$SHA512withRSA",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.crypto.RsaSigner"
|
||||
},
|
||||
"name": "sun.security.rsa.RSASignature$SHA512withRSA",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "io.jsonwebtoken.impl.DefaultJwtHeaderBuilder$Supplier",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "io.jsonwebtoken.impl.DefaultClaimsBuilder$Supplier",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "io.jsonwebtoken.impl.security.DefaultKeyOperationBuilder$Supplier",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "io.jsonwebtoken.impl.security.DefaultKeyOperationPolicyBuilder$Supplier",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"bundles": [],
|
||||
"resources": {
|
||||
"includes": [
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.lang.Services"
|
||||
},
|
||||
"pattern": "\\QMETA-INF/services/io.jsonwebtoken.CompressionCodec\\E"
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.DefaultJwtParserBuilder"
|
||||
},
|
||||
"pattern": "\\QMETA-INF/services/io.jsonwebtoken.io.Deserializer\\E"
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"typeReachable": "io.jsonwebtoken.impl.lang.LegacyServices"
|
||||
},
|
||||
"pattern": "\\QMETA-INF/services/io.jsonwebtoken.io.Serializer\\E"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
br:
|
||||
com:
|
||||
tasknote:
|
||||
server:
|
||||
jwt-secret: ${SECURITY_KEY:empty}
|
||||
target-env: ${TARGET_ENV:development}
|
||||
cors:
|
||||
allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost}
|
||||
logging:
|
||||
level:
|
||||
root: ${ROOT_LOG_LEVEL:INFO}
|
||||
br.com.tasknoteapp: TRACE
|
||||
|
||||
mailgun:
|
||||
api-key: ${MAILGUN_APIKEY:abc123456}
|
||||
domain: tasknoteapp.dev.br
|
||||
sender-email: no-reply@tasknoteapp.dev.br
|
||||
|
||||
server:
|
||||
port: 8585
|
||||
error:
|
||||
include-message: always
|
||||
servlet:
|
||||
context-path: ${SERVER_SERVLET_CONTEXT_PATH:/server}
|
||||
spring:
|
||||
application:
|
||||
name: tasknote-api
|
||||
datasource:
|
||||
driver-class-name: org.postgresql.Driver
|
||||
password: ${POSTGRES_PASSWORD:default}
|
||||
url: jdbc:postgresql://${POSTGRES_HOST:localhost}:${POSTGRES_PORT:5435}/${POSTGRES_DB:tasknote}
|
||||
username: ${POSTGRES_USER:tasknoteuser}
|
||||
flyway:
|
||||
baseline-on-migrate: true
|
||||
enabled: true
|
||||
locations: classpath:db/migration
|
||||
jpa:
|
||||
database-platform: org.hibernate.dialect.PostgreSQLDialect
|
||||
properties:
|
||||
hibernate:
|
||||
default_schema: tasknote
|
||||
show-sql: true
|
||||
@@ -1,48 +1,42 @@
|
||||
br:
|
||||
com:
|
||||
tasknote:
|
||||
server:
|
||||
jwt-secret: ${SECURITY_KEY:empty}
|
||||
target-env: ${TARGET_ENV:development}
|
||||
version: ${BUILD:local}
|
||||
com:
|
||||
tasknote:
|
||||
server:
|
||||
jwt-secret: ${SECURITY_KEY:empty}
|
||||
target-env: ${TARGET_ENV:development}
|
||||
cors:
|
||||
allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost}
|
||||
allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost}
|
||||
logging:
|
||||
level:
|
||||
root: ${ROOT_LOG_LEVEL:INFO}
|
||||
level:
|
||||
root: ${ROOT_LOG_LEVEL:INFO}
|
||||
br.com.tasknoteapp: TRACE
|
||||
|
||||
mailgun:
|
||||
api-key: ${MAILGUN_APIKEY:abc123456}
|
||||
domain: tasknoteapp.dev.br
|
||||
sender-email: no-reply@tasknoteapp.dev.br
|
||||
|
||||
management:
|
||||
endpoint:
|
||||
health:
|
||||
show-details: always
|
||||
server:
|
||||
error:
|
||||
include-message: always
|
||||
port: 8585
|
||||
servlet:
|
||||
context-path: ${SERVER_SERVLET_CONTEXT_PATH:/server}
|
||||
port: 8585
|
||||
error:
|
||||
include-message: always
|
||||
servlet:
|
||||
context-path: ${SERVER_SERVLET_CONTEXT_PATH:/server}
|
||||
spring:
|
||||
application:
|
||||
name: tasknote-api
|
||||
datasource:
|
||||
driver-class-name: org.postgresql.Driver
|
||||
password: ${POSTGRES_PASSWORD:default}
|
||||
url: jdbc:postgresql://${POSTGRES_HOST:localhost}:${POSTGRES_PORT:5435}/${POSTGRES_DB:tasknote}
|
||||
username: ${POSTGRES_USER:tasknoteuser}
|
||||
flyway:
|
||||
baseline-on-migrate: true
|
||||
enabled: true
|
||||
locations: classpath:db/migration
|
||||
jpa:
|
||||
database-platform: org.hibernate.dialect.PostgreSQLDialect
|
||||
properties:
|
||||
hibernate:
|
||||
default_schema: tasknote
|
||||
show-sql: true
|
||||
springdoc:
|
||||
enable-native-support: true
|
||||
application:
|
||||
name: tasknote-api
|
||||
datasource:
|
||||
driver-class-name: org.postgresql.Driver
|
||||
password: ${POSTGRES_PASSWORD:default}
|
||||
url: jdbc:postgresql://${POSTGRES_HOST:localhost}:${POSTGRES_PORT:5435}/${POSTGRES_DB:tasknote}
|
||||
username: ${POSTGRES_USER:tasknoteuser}
|
||||
flyway:
|
||||
baseline-on-migrate: true
|
||||
enabled: true
|
||||
locations: classpath:db/migration
|
||||
jpa:
|
||||
database-platform: org.hibernate.dialect.PostgreSQLDialect
|
||||
properties:
|
||||
hibernate:
|
||||
default_schema: tasknote
|
||||
show-sql: true
|
||||
|
||||
@@ -65,7 +65,7 @@ class JwtServiceImplTest {
|
||||
Claims claims = extractClaims(token);
|
||||
String userIdClaim = String.valueOf(claims.get("userId"));
|
||||
|
||||
assertEquals(Long.parseLong(userIdClaim), testUserId);
|
||||
assertEquals(userIdClaim.substring(0, 1), testUserId.toString());
|
||||
assertEquals(claims.get("email"), testEmail);
|
||||
assertEquals(claims.get("name"), testName);
|
||||
|
||||
|
||||
@@ -151,3 +151,23 @@ Angular dependencies:
|
||||
|
||||
- First run: `npx @angular/cli update @angular/cli @angular/core`
|
||||
- Then run `npx npm-check-updates -u`
|
||||
|
||||
---
|
||||
|
||||
Build with:
|
||||
mvn -Pnative -DskipTests spring-boot:build-image \
|
||||
-Dspring-boot.build-image.imageName=rmcampos/tasknote:api-latest
|
||||
|
||||
Run with:
|
||||
docker run --rm -p 8080:8080 \
|
||||
-e SPRING_PROFILES_ACTIVE=native \
|
||||
-e POSTGRES_HOST=localhost \
|
||||
-e POSTGRES_PORT=5432 \
|
||||
-e POSTGRES_DB=tasknote \
|
||||
-e POSTGRES_USER=tasknoteuser \
|
||||
-e POSTGRES_PASSWORD=default \
|
||||
-e SECURITY_KEY=9052e499446dac5fa2d69dd07f1f6381a360c646c63d555244c3a2911494f63a \
|
||||
-e CORS_ALLOWED_ORIGINS=http://localhost:5000 \
|
||||
-e SERVER_SERVLET_CONTEXT_PATH=/ \
|
||||
--network host \
|
||||
docker.io/rmcampos/tasknote:api-latest
|
||||
Reference in New Issue
Block a user