Merge branch 'main' into dependabot/maven/java-api/org.springframework.boot-spring-boot-starter-parent-3.3.4

This commit is contained in:
2024-09-29 12:02:13 -03:00
95 changed files with 1342 additions and 782 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ updates:
schedule:
interval: "weekly"
- package-ecosystem: "maven"
directory: "/java-api"
directory: "/server"
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
+3 -3
View File
@@ -71,10 +71,10 @@ jobs:
restore-keys: ${{ runner.os }}-m2
- name: Build with Maven
run: cd java-api && ./mvnw --no-transfer-progress clean compile -DskipTests
run: cd server && ./mvnw --no-transfer-progress clean compile -DskipTests
- name: Google Checkstyle
run: cd java-api && ./mvnw --no-transfer-progress checkstyle:checkstyle -Dskip.checkstyle=false
run: cd server && ./mvnw --no-transfer-progress checkstyle:checkstyle -Dskip.checkstyle=false
#- name: All Tests
# run: cd java-api && ./mvnw --no-transfer-progress clean verify -P tests --file pom.xml
# run: cd server && ./mvnw --no-transfer-progress clean verify -P tests --file pom.xml
+5 -5
View File
@@ -94,13 +94,13 @@ jobs:
restore-keys: ${{ runner.os }}-m2
- name: Build with Maven
run: cd java-api && ./mvnw --no-transfer-progress clean compile -DskipTests
run: cd server && ./mvnw --no-transfer-progress clean compile -DskipTests
- name: Google Check-Style
run: cd java-api && ./mvnw --no-transfer-progress checkstyle:checkstyle -Dskip.checkstyle=false
run: cd server && ./mvnw --no-transfer-progress checkstyle:checkstyle -Dskip.checkstyle=false
#- name: All Tests
# run: cd java-api && ./mvnw --no-transfer-progress clean verify -P tests --file pom.xml
# run: cd server && ./mvnw --no-transfer-progress clean verify -P tests --file pom.xml
java-docker-build:
name: Build Java Docker image
@@ -123,8 +123,8 @@ jobs:
uses: docker/build-push-action@v6
with:
push: true
context: ./java-api
tags: ghcr.io/ricardo-campos-org/react-typescript-todolist/java-api:${{ github.event.number }}
context: ./server
tags: ghcr.io/ricardo-campos-org/react-typescript-todolist/server:${{ github.event.number }}
build-args: BUILD=${{ github.event.number }}
cache-from: type=gha
cache-to: type=gha,mode=max
+2 -2
View File
@@ -63,9 +63,9 @@ TODO: add GIF or screenshot of the app
npm start
```
**Java API:**
**Server - Java API:**
```sh
cd java-api
cd server
./mvnw spring-boot:run \
-Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"
```
+2 -2
View File
@@ -25,7 +25,7 @@
Strict-Transport-Security "max-age=31536000"
Content-Security-Policy "
base-uri 'self';
connect-src 'self';
connect-src 'self' {$VITE_BACKEND_SERVER};
default-src 'self';
font-src https://cdn.jsdelivr.net/npm/ 'self';
frame-src 'self';
@@ -42,7 +42,7 @@
handle /env.js {
header Content-Type "text/javascript"
respond `window.config = {"BUILD":"{$BUILD}"};`
respond `window.config = {"VITE_BUILD":"{$VITE_BUILD}","VITE_BACKEND_SERVER":"{$VITE_BACKEND_SERVER}"};`
}
file_server
+342 -497
View File
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -17,7 +17,7 @@
"@testing-library/react": "^16.0.0",
"@testing-library/user-event": "^14.5.2",
"@types/jest": "^29.5.12",
"@types/node": "^22.5.2",
"@types/node": "^22.7.0",
"@types/react-dom": "^18.3.0",
"@types/react-router-bootstrap": "^0.26.6",
"@vitejs/plugin-react": "^4.3.1",
@@ -26,8 +26,8 @@
"react-bootstrap": "^2.10.4",
"react-dom": "^18.3.1",
"react-router-bootstrap": "^0.26.3",
"react-router-dom": "^6.26.1",
"typescript": "^5.5.4",
"react-router-dom": "^6.26.2",
"typescript": "^5.6.2",
"vite": "^5.4.6"
},
"scripts": {
@@ -60,13 +60,13 @@
"devDependencies": {
"@types/react": "^18.3.5",
"@typescript-eslint/eslint-plugin": "^8.4.0",
"@vitest/coverage-v8": "^2.0.5",
"@vitest/coverage-v8": "^2.1.1",
"eslint": "^8.57.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsdoc": "^50.2.2",
"eslint-plugin-promise": "^7.1.0",
"eslint-plugin-react": "^7.35.0",
"eslint-plugin-react": "^7.36.1",
"eslint-plugin-react-hooks": "^4.6.2",
"jsdom": "^25.0.0",
"sass": "^1.77.8",
+24 -12
View File
@@ -11,7 +11,24 @@ function getToken(): string {
}
/**
* Retrieves all the headers for the app.
*
* @returns {Headers} the headers.
*/
function getHeaders(): Headers {
const csrfToken = document.cookie.split('; ').find((row: string) => row.startsWith('XSRF-TOKEN='))?.split('=')[1];
return new Headers({
'Content-Type': 'application/json',
Authorization: `Bearer ${getToken()}`,
'X-XSRF-TOKEN': csrfToken || ''
});
}
/**
* Handle errors for the AJAX HTTPS requests.
*
* @param {number} httpStatusCode The HTTP response status code.
*/
function handleError(httpStatusCode: number) {
if (httpStatusCode === 400) {
@@ -31,6 +48,7 @@ const api = {
const response = await fetch(url, {
method: 'GET',
mode: 'cors',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${getToken()}`
@@ -48,10 +66,8 @@ const api = {
const response = await fetch(url, {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${getToken()}`
},
credentials: 'include',
headers: getHeaders(),
body: JSON.stringify(payload)
});
if (response.ok) {
@@ -66,10 +82,8 @@ const api = {
const response = await fetch(url, {
method: 'PATCH',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${getToken()}`
},
credentials: 'include',
headers: getHeaders(),
body: JSON.stringify(payload)
});
if (response.ok) {
@@ -84,10 +98,8 @@ const api = {
const response = await fetch(url, {
method: 'DELETE',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${getToken()}`
}
credentials: 'include',
headers: getHeaders()
});
if (response.status === 204) {
return true;
+4 -2
View File
@@ -4,12 +4,14 @@ const server = env.VITE_BACKEND_SERVER;
const ApiConfig = {
signInUrl: `${server}/auth/signin`,
signInUrl: `${server}/auth/sign-in`,
registerUrl: `${server}/auth/signup`,
registerUrl: `${server}/auth/sign-up`,
refreshTokenUrl: `${server}/rest/user-sessions/refresh`,
csrfTokenUrl: `${server}/rest/user-sessions/csrf`,
tasksUrl: `${server}/rest/tasks`,
homeUrl: `${server}/rest/home`,
+6
View File
@@ -16,6 +16,7 @@ async function registerUser(email: string, password: string): Promise<SigninResp
const response = await fetch(ApiConfig.registerUrl, {
method: 'PUT',
mode: 'cors',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
},
@@ -35,6 +36,8 @@ async function registerUser(email: string, password: string): Promise<SigninResp
} catch (error) {
if (typeof error === 'string') {
throw new Error(error as string);
} else if (error instanceof Error) {
throw error;
}
}
throw new Error('Unknown error');
@@ -54,6 +57,7 @@ async function authenticateUser(email: string, password: string): Promise<Signin
const response = await fetch(ApiConfig.signInUrl, {
method: 'POST',
mode: 'cors',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
},
@@ -76,6 +80,8 @@ async function authenticateUser(email: string, password: string): Promise<Signin
} catch (error) {
if (typeof error === 'string') {
throw new Error(error as string);
} else if (error instanceof Error) {
throw error;
}
}
throw new Error('Unknown error');
+8 -1
View File
@@ -2,6 +2,7 @@ import React, { useContext } from 'react';
import {
Button, Col, Container, Row
} from 'react-bootstrap';
import { useNavigate } from 'react-router-dom';
import { env } from '../../env';
import AuthContext from '../../context/AuthContext';
import './style.css';
@@ -17,9 +18,15 @@ import './style.css';
*/
function Footer(): JSX.Element {
const { signOut, user } = useContext(AuthContext);
const navigate = useNavigate();
const build = env.VITE_BUILD;
const currentYear = new Date().getFullYear();
const goOut = () => {
signOut();
navigate('/');
};
return (
<footer className="footer">
<Container>
@@ -38,7 +45,7 @@ function Footer(): JSX.Element {
{user?.email}
</Col>
<Col xs={12} sm={4} className="text-center text-sm-end">
<Button type="button" variant="link" onClick={signOut} className="logout-button">
<Button type="button" variant="link" onClick={() => goOut()} className="logout-button">
Logout
</Button>
</Col>
+10 -3
View File
@@ -23,13 +23,17 @@ const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }: Pro
const [intervalInstance, setIntervalInstance] = useState<NodeJS.Timeout | null>(null);
const fetchCurrentSession = async (pathname: string): Promise<SigninResponse | undefined> => {
const token = localStorage.getItem(API_TOKEN);
if (!token) {
return undefined;
}
try {
const bearerToken: SigninResponse = await api.getJSON(ApiConfig.refreshTokenUrl);
setSigned(true);
return bearerToken;
} catch (e) {
if (e instanceof Error) {
if (e.message !== 'No saved token!') {
if (e.message !== 'No saved token!' && e.message !== 'Forbidden! Access denied') {
console.warn(e.message);
}
} else if (e) {
@@ -82,7 +86,10 @@ const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }: Pro
updateUserSession(currentUser, registerResponse.token);
return Promise.resolve('OK');
} catch (e) {
return Promise.reject(e);
if (e instanceof Error) {
return Promise.reject(new Error(e.message));
}
return Promise.reject(new Error('Unknown error!'));
}
};
@@ -102,7 +109,7 @@ const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }: Pro
}
};
const signOut = async (): Promise<void> => {
const signOut = (): void => {
logoutUser();
setSigned(false);
setUser(undefined);
+6 -4
View File
@@ -28,11 +28,11 @@ function Task(): JSX.Element {
};
const loadTasks = async () => {
const tasksFetched: TaskResponse[] | Error = await api.getJSON(ApiConfig.tasksUrl);
if (tasksFetched instanceof Error) {
handleError(tasksFetched);
} else {
try {
const tasksFetched: TaskResponse[] = await api.getJSON(ApiConfig.tasksUrl);
setTasks(tasksFetched);
} catch (e) {
handleError(e);
}
};
@@ -41,6 +41,7 @@ function Task(): JSX.Element {
description: desc,
urls: url ? [url] : []
};
try {
await api.postJSON(ApiConfig.tasksUrl, payload);
loadTasks();
@@ -94,6 +95,7 @@ function Task(): JSX.Element {
useEffect(() => {
loadTasks();
// getCsrfToken();
}, []);
return (
+1 -1
View File
@@ -38,7 +38,7 @@ services:
entrypoint: sh -c './encora-cert.sh'
working_dir: /app
volumes:
- "./java-api:/app"
- "./server:/app"
- $HOME/zscaler-certs:/certs
healthcheck:
test: curl -f http://localhost:8585/actuator/health | grep '"status":"UP"'
@@ -1,44 +0,0 @@
package br.com.tasknoteapp.java_api.config;
import br.com.tasknoteapp.java_api.request.LoginRequest;
import br.com.tasknoteapp.java_api.request.NotePatchRequest;
import br.com.tasknoteapp.java_api.request.NoteRequest;
import br.com.tasknoteapp.java_api.request.NoteUrlPatchRequest;
import br.com.tasknoteapp.java_api.request.TaskPatchRequest;
import br.com.tasknoteapp.java_api.request.TaskRequest;
import br.com.tasknoteapp.java_api.request.TaskUrlPatchRequest;
import br.com.tasknoteapp.java_api.response.JwtAuthenticationResponse;
import br.com.tasknoteapp.java_api.response.NoteResponse;
import br.com.tasknoteapp.java_api.response.NoteUrlResponse;
import br.com.tasknoteapp.java_api.response.SearchResponse;
import br.com.tasknoteapp.java_api.response.SummaryResponse;
import br.com.tasknoteapp.java_api.response.TaskResponse;
import br.com.tasknoteapp.java_api.response.TaskUrlResponse;
import br.com.tasknoteapp.java_api.response.UserResponse;
import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportRuntimeHints;
@Configuration
@RegisterReflectionForBinding({
LoginRequest.class,
NotePatchRequest.class,
NoteRequest.class,
NoteUrlPatchRequest.class,
TaskPatchRequest.class,
TaskRequest.class,
TaskUrlPatchRequest.class,
JwtAuthenticationResponse.class,
NoteResponse.class,
NoteUrlResponse.class,
SearchResponse.class,
SummaryResponse.class,
TaskResponse.class,
TaskUrlResponse.class,
UserResponse.class,
io.jsonwebtoken.Claims.class,
io.jsonwebtoken.Jwts.class,
io.jsonwebtoken.impl.security.StandardSecureDigestAlgorithms.class,
})
@ImportRuntimeHints(value = {HttpServletRequestRuntimeHint.class})
public class CloudNativeConfig {}
+2 -2
View File
@@ -21,7 +21,7 @@ ENV BUILD_NUMBER=${BUILD_NUMBER}
# Copy
WORKDIR /app
COPY --from=build /app/target/java-api ./java-api
COPY --from=build /app/target/server ./tasknote-api
# User, port and health check
USER 1001
@@ -29,4 +29,4 @@ EXPOSE ${PORT}
HEALTHCHECK CMD timeout 10s bash -c 'true > /dev/tcp/127.0.0.1/8585'
# Startup
ENTRYPOINT ["/app/java-api", "-Dspring.profiles.active=prod"]
ENTRYPOINT ["/app/tasknote-api", "-Dspring.profiles.active=prod"]
View File
View File
+5 -8
View File
@@ -10,9 +10,9 @@
</parent>
<groupId>br.com.tasknoteapp</groupId>
<artifactId>java-api</artifactId>
<artifactId>server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>java-api</name>
<name>tasknote-api</name>
<description>Java backend REST API to serve TaskNote frontend client</description>
<!-- URL -->
@@ -42,6 +42,7 @@
<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.5.2.Final</hibernate.version>
</properties>
<!-- Profiles -->
@@ -184,8 +185,6 @@
</dependencies>
<build>
<finalName>java-api</finalName>
<plugins>
<plugin>
<groupId>org.hibernate.orm.tooling</groupId>
@@ -205,10 +204,6 @@
</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>
@@ -443,6 +438,8 @@
</executions>
</plugin>
</plugins>
<finalName>tasknote-api</finalName>
</build>
</project>
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api;
package br.com.tasknoteapp.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -0,0 +1,53 @@
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.SearchResponse;
import br.com.tasknoteapp.server.response.SummaryResponse;
import br.com.tasknoteapp.server.response.TaskResponse;
import br.com.tasknoteapp.server.response.TaskUrlResponse;
import br.com.tasknoteapp.server.response.UserResponse;
import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportRuntimeHints;
@Configuration
@RegisterReflectionForBinding({
LoginRequest.class,
NotePatchRequest.class,
NoteRequest.class,
NoteUrlPatchRequest.class,
TaskPatchRequest.class,
TaskRequest.class,
TaskUrlPatchRequest.class,
JwtAuthenticationResponse.class,
NoteResponse.class,
NoteUrlResponse.class,
SearchResponse.class,
SummaryResponse.class,
TaskResponse.class,
TaskUrlResponse.class,
UserResponse.class,
io.jsonwebtoken.Claims.class,
io.jsonwebtoken.Jwts.class,
io.jsonwebtoken.Jwts.SIG.class,
io.jsonwebtoken.Jwts.ENC.class,
io.jsonwebtoken.Jwts.KEY.class,
io.jsonwebtoken.impl.security.StandardSecureDigestAlgorithms.class,
io.jsonwebtoken.impl.security.StandardKeyOperations.class,
io.jsonwebtoken.impl.security.StandardEncryptionAlgorithms.class,
io.jsonwebtoken.impl.security.StandardKeyAlgorithms.class,
io.jsonwebtoken.impl.io.StandardCompressionAlgorithms.class,
io.jsonwebtoken.impl.DefaultClaimsBuilder.class,
io.jsonwebtoken.impl.DefaultJwtParserBuilder.class,
})
@ImportRuntimeHints(value = {HttpServletRequestRuntimeHint.class})
public class CloudNativeConfig {}
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.config;
package br.com.tasknoteapp.server.config;
import java.util.Arrays;
import lombok.extern.slf4j.Slf4j;
@@ -28,6 +28,8 @@ public class CorsConfig implements WebMvcConfigurer {
registry
.addMapping("/**")
.allowedOrigins(allowedOrigins)
.allowCredentials(true)
.allowedHeaders("X-XSRF-TOKEN", "Content-Type", "Accept", "Authorization", "X-Frame-Options", "X-XSS-Protection", "Content-Security-Policy")
.allowedMethods("GET", "PUT", "POST", "DELETE", "OPTIONS", "HEAD", "PATCH");
}
}
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.config;
package br.com.tasknoteapp.server.config;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.aot.hint.ProxyHints;
@@ -1,7 +1,7 @@
package br.com.tasknoteapp.java_api.config;
package br.com.tasknoteapp.server.config;
import br.com.tasknoteapp.java_api.filter.JwtAuthenticationFilter;
import br.com.tasknoteapp.java_api.service.UserService;
import br.com.tasknoteapp.server.filter.JwtAuthenticationFilter;
import br.com.tasknoteapp.server.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -14,11 +14,12 @@ import org.springframework.security.config.annotation.authentication.configurati
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
/** This class contains security configurations. */
@Configuration
@@ -40,25 +41,29 @@ public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors(Customizer.withDefaults())
.csrf(Customizer.withDefaults())
.csrf(
custom ->
custom
.ignoringRequestMatchers("/auth/**")
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler()))
.authorizeHttpRequests(
request ->
request
.requestMatchers(HttpMethod.OPTIONS, "/**")
.permitAll()
.requestMatchers("/auth/**")
.permitAll()
.requestMatchers("/rest/**")
.authenticated()
.requestMatchers(HttpMethod.OPTIONS, "/**")
.permitAll()
.anyRequest()
.permitAll())
.sessionManagement(
manager -> manager.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.httpBasic(AbstractHttpConfigurer::disable)
.formLogin(AbstractHttpConfigurer::disable)
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.authenticationProvider(authenticationProvider());
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.config;
package br.com.tasknoteapp.server.config;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
@@ -16,7 +16,7 @@ import org.springframework.context.annotation.Configuration;
@Configuration
public class SwaggerConfig {
@Value("${br.com.tasknote.java-api.version}")
@Value("${br.com.tasknote.server.version}")
private String nrSparBackendVersion;
/**
@@ -1,10 +1,10 @@
package br.com.tasknoteapp.java_api.controller;
package br.com.tasknoteapp.server.controller;
import br.com.tasknoteapp.java_api.exception.UserAlreadyExistsException;
import br.com.tasknoteapp.java_api.exception.UserNotFoundException;
import br.com.tasknoteapp.java_api.request.LoginRequest;
import br.com.tasknoteapp.java_api.response.JwtAuthenticationResponse;
import br.com.tasknoteapp.java_api.service.AuthService;
import br.com.tasknoteapp.server.exception.UserAlreadyExistsException;
import br.com.tasknoteapp.server.exception.UserNotFoundException;
import br.com.tasknoteapp.server.request.LoginRequest;
import br.com.tasknoteapp.server.response.JwtAuthenticationResponse;
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;
@@ -1,8 +1,8 @@
package br.com.tasknoteapp.java_api.controller;
package br.com.tasknoteapp.server.controller;
import br.com.tasknoteapp.java_api.response.SearchResponse;
import br.com.tasknoteapp.java_api.response.SummaryResponse;
import br.com.tasknoteapp.java_api.service.HomeService;
import br.com.tasknoteapp.server.response.SearchResponse;
import br.com.tasknoteapp.server.response.SummaryResponse;
import br.com.tasknoteapp.server.service.HomeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
@@ -1,10 +1,10 @@
package br.com.tasknoteapp.java_api.controller;
package br.com.tasknoteapp.server.controller;
import br.com.tasknoteapp.java_api.entity.NoteEntity;
import br.com.tasknoteapp.java_api.request.NotePatchRequest;
import br.com.tasknoteapp.java_api.request.NoteRequest;
import br.com.tasknoteapp.java_api.response.NoteResponse;
import br.com.tasknoteapp.java_api.service.NoteService;
import br.com.tasknoteapp.server.entity.NoteEntity;
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;
@@ -1,6 +1,6 @@
package br.com.tasknoteapp.java_api.controller;
package br.com.tasknoteapp.server.controller;
import br.com.tasknoteapp.java_api.response.ValidationExceptionResponse;
import br.com.tasknoteapp.server.response.ValidationExceptionResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
@@ -1,11 +1,11 @@
package br.com.tasknoteapp.java_api.controller;
package br.com.tasknoteapp.server.controller;
import br.com.tasknoteapp.java_api.entity.TaskEntity;
import br.com.tasknoteapp.java_api.exception.TaskNotFoundException;
import br.com.tasknoteapp.java_api.request.TaskPatchRequest;
import br.com.tasknoteapp.java_api.request.TaskRequest;
import br.com.tasknoteapp.java_api.response.TaskResponse;
import br.com.tasknoteapp.java_api.service.TaskService;
import br.com.tasknoteapp.server.entity.TaskEntity;
import br.com.tasknoteapp.server.exception.TaskNotFoundException;
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;
@@ -1,7 +1,7 @@
package br.com.tasknoteapp.java_api.controller;
package br.com.tasknoteapp.server.controller;
import br.com.tasknoteapp.java_api.response.UserResponse;
import br.com.tasknoteapp.java_api.service.AuthService;
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;
@@ -1,19 +1,22 @@
package br.com.tasknoteapp.java_api.controller;
package br.com.tasknoteapp.server.controller;
import br.com.tasknoteapp.java_api.exception.UserNotFoundException;
import br.com.tasknoteapp.java_api.response.JwtAuthenticationResponse;
import br.com.tasknoteapp.java_api.service.AuthService;
import br.com.tasknoteapp.server.exception.UserNotFoundException;
import br.com.tasknoteapp.server.response.JwtAuthenticationResponse;
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 lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/** This class contains resources for handling user sessions. */
@Slf4j
@RestController
@RequestMapping("/rest/user-sessions")
@AllArgsConstructor
@@ -28,7 +31,7 @@ public class UserSessionController {
* @return JwtAuthenticationResponse with token created.
* @throws UserNotFoundException if user not found
*/
@GetMapping(path = "/refresh")
@GetMapping("/refresh")
@Operation(
summary = "Refresh an existing user session",
description = "Refresh an existing user session, generating a new token",
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.entity;
package br.com.tasknoteapp.server.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.entity;
package br.com.tasknoteapp.server.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.entity;
package br.com.tasknoteapp.server.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.entity;
package br.com.tasknoteapp.server.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.entity;
package br.com.tasknoteapp.server.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.exception;
package br.com.tasknoteapp.server.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.exception;
package br.com.tasknoteapp.server.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.exception;
package br.com.tasknoteapp.server.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.exception;
package br.com.tasknoteapp.server.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.exception;
package br.com.tasknoteapp.server.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.exception;
package br.com.tasknoteapp.server.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@@ -1,7 +1,7 @@
package br.com.tasknoteapp.java_api.filter;
package br.com.tasknoteapp.server.filter;
import br.com.tasknoteapp.java_api.service.JwtService;
import br.com.tasknoteapp.java_api.service.UserService;
import br.com.tasknoteapp.server.service.JwtService;
import br.com.tasknoteapp.server.service.UserService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
@@ -1,6 +1,6 @@
package br.com.tasknoteapp.java_api.repository;
package br.com.tasknoteapp.server.repository;
import br.com.tasknoteapp.java_api.entity.NoteEntity;
import br.com.tasknoteapp.server.entity.NoteEntity;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
@@ -1,6 +1,6 @@
package br.com.tasknoteapp.java_api.repository;
package br.com.tasknoteapp.server.repository;
import br.com.tasknoteapp.java_api.entity.NoteUrlEntity;
import br.com.tasknoteapp.server.entity.NoteUrlEntity;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
@@ -1,6 +1,6 @@
package br.com.tasknoteapp.java_api.repository;
package br.com.tasknoteapp.server.repository;
import br.com.tasknoteapp.java_api.entity.TaskEntity;
import br.com.tasknoteapp.server.entity.TaskEntity;
import java.util.List;
@@ -1,6 +1,6 @@
package br.com.tasknoteapp.java_api.repository;
package br.com.tasknoteapp.server.repository;
import br.com.tasknoteapp.java_api.entity.TaskUrlEntity;
import br.com.tasknoteapp.server.entity.TaskUrlEntity;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
@@ -1,6 +1,6 @@
package br.com.tasknoteapp.java_api.repository;
package br.com.tasknoteapp.server.repository;
import br.com.tasknoteapp.java_api.entity.UserEntity;
import br.com.tasknoteapp.server.entity.UserEntity;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.request;
package br.com.tasknoteapp.server.request;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.request;
package br.com.tasknoteapp.server.request;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.request;
package br.com.tasknoteapp.server.request;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
@@ -1,3 +1,3 @@
package br.com.tasknoteapp.java_api.request;
package br.com.tasknoteapp.server.request;
public record NoteUrlPatchRequest(Long id, String url) {}
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.request;
package br.com.tasknoteapp.server.request;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.request;
package br.com.tasknoteapp.server.request;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
@@ -1,3 +1,3 @@
package br.com.tasknoteapp.java_api.request;
package br.com.tasknoteapp.server.request;
public record TaskUrlPatchRequest(Long id, String url) {}
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.response;
package br.com.tasknoteapp.server.response;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -1,3 +1,3 @@
package br.com.tasknoteapp.java_api.response;
package br.com.tasknoteapp.server.response;
public record JwtAuthenticationResponse(String token) {}
@@ -1,7 +1,7 @@
package br.com.tasknoteapp.java_api.response;
package br.com.tasknoteapp.server.response;
import br.com.tasknoteapp.java_api.entity.NoteEntity;
import br.com.tasknoteapp.java_api.entity.NoteUrlEntity;
import br.com.tasknoteapp.server.entity.NoteEntity;
import br.com.tasknoteapp.server.entity.NoteUrlEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.ArrayList;
import java.util.List;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.response;
package br.com.tasknoteapp.server.response;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.response;
package br.com.tasknoteapp.server.response;
import java.util.List;
@@ -1,3 +1,3 @@
package br.com.tasknoteapp.java_api.response;
package br.com.tasknoteapp.server.response;
public record SummaryResponse(Integer pendingTaskCount, Integer doneTaskCount) {}
@@ -1,7 +1,7 @@
package br.com.tasknoteapp.java_api.response;
package br.com.tasknoteapp.server.response;
import br.com.tasknoteapp.java_api.entity.TaskEntity;
import br.com.tasknoteapp.java_api.entity.TaskUrlEntity;
import br.com.tasknoteapp.server.entity.TaskEntity;
import br.com.tasknoteapp.server.entity.TaskUrlEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.ArrayList;
import java.util.List;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.response;
package br.com.tasknoteapp.server.response;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.response;
package br.com.tasknoteapp.server.response;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDateTime;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.response;
package br.com.tasknoteapp.server.response;
import java.util.List;
@@ -1,8 +1,8 @@
package br.com.tasknoteapp.java_api.service;
package br.com.tasknoteapp.server.service;
import br.com.tasknoteapp.java_api.entity.UserEntity;
import br.com.tasknoteapp.java_api.request.LoginRequest;
import br.com.tasknoteapp.java_api.response.UserResponse;
import br.com.tasknoteapp.server.entity.UserEntity;
import br.com.tasknoteapp.server.request.LoginRequest;
import br.com.tasknoteapp.server.response.UserResponse;
import java.util.List;
import java.util.Optional;
import org.springframework.security.core.userdetails.User;
@@ -1,7 +1,7 @@
package br.com.tasknoteapp.java_api.service;
package br.com.tasknoteapp.server.service;
import br.com.tasknoteapp.java_api.response.SearchResponse;
import br.com.tasknoteapp.java_api.response.SummaryResponse;
import br.com.tasknoteapp.server.response.SearchResponse;
import br.com.tasknoteapp.server.response.SummaryResponse;
/** This interface contains methods for handling user Home requests. */
public interface HomeService {
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.service;
package br.com.tasknoteapp.server.service;
import java.time.LocalDateTime;
import java.util.Map;
@@ -1,9 +1,9 @@
package br.com.tasknoteapp.java_api.service;
package br.com.tasknoteapp.server.service;
import br.com.tasknoteapp.java_api.entity.NoteEntity;
import br.com.tasknoteapp.java_api.request.NotePatchRequest;
import br.com.tasknoteapp.java_api.request.NoteRequest;
import br.com.tasknoteapp.java_api.response.NoteResponse;
import br.com.tasknoteapp.server.entity.NoteEntity;
import br.com.tasknoteapp.server.request.NotePatchRequest;
import br.com.tasknoteapp.server.request.NoteRequest;
import br.com.tasknoteapp.server.response.NoteResponse;
import java.util.List;
public interface NoteService {
@@ -1,9 +1,9 @@
package br.com.tasknoteapp.java_api.service;
package br.com.tasknoteapp.server.service;
import br.com.tasknoteapp.java_api.entity.TaskEntity;
import br.com.tasknoteapp.java_api.request.TaskPatchRequest;
import br.com.tasknoteapp.java_api.request.TaskRequest;
import br.com.tasknoteapp.java_api.response.TaskResponse;
import br.com.tasknoteapp.server.entity.TaskEntity;
import br.com.tasknoteapp.server.request.TaskPatchRequest;
import br.com.tasknoteapp.server.request.TaskRequest;
import br.com.tasknoteapp.server.response.TaskResponse;
import java.util.List;
/** This interface contains methods for handling user user Tasks. */
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.service;
package br.com.tasknoteapp.server.service;
import org.springframework.security.core.userdetails.UserDetailsService;
@@ -1,16 +1,16 @@
package br.com.tasknoteapp.java_api.service.impl;
package br.com.tasknoteapp.server.service.impl;
import br.com.tasknoteapp.java_api.entity.UserEntity;
import br.com.tasknoteapp.java_api.exception.BadPasswordException;
import br.com.tasknoteapp.java_api.exception.UserAlreadyExistsException;
import br.com.tasknoteapp.java_api.exception.UserForbiddenException;
import br.com.tasknoteapp.java_api.exception.UserNotFoundException;
import br.com.tasknoteapp.java_api.repository.UserRepository;
import br.com.tasknoteapp.java_api.request.LoginRequest;
import br.com.tasknoteapp.java_api.response.UserResponse;
import br.com.tasknoteapp.java_api.service.AuthService;
import br.com.tasknoteapp.java_api.service.JwtService;
import br.com.tasknoteapp.java_api.util.AuthUtil;
import br.com.tasknoteapp.server.entity.UserEntity;
import br.com.tasknoteapp.server.exception.BadPasswordException;
import br.com.tasknoteapp.server.exception.UserAlreadyExistsException;
import br.com.tasknoteapp.server.exception.UserForbiddenException;
import br.com.tasknoteapp.server.exception.UserNotFoundException;
import br.com.tasknoteapp.server.repository.UserRepository;
import br.com.tasknoteapp.server.request.LoginRequest;
import br.com.tasknoteapp.server.response.UserResponse;
import br.com.tasknoteapp.server.service.AuthService;
import br.com.tasknoteapp.server.service.JwtService;
import br.com.tasknoteapp.server.util.AuthUtil;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@@ -1,12 +1,12 @@
package br.com.tasknoteapp.java_api.service.impl;
package br.com.tasknoteapp.server.service.impl;
import br.com.tasknoteapp.java_api.response.NoteResponse;
import br.com.tasknoteapp.java_api.response.SearchResponse;
import br.com.tasknoteapp.java_api.response.SummaryResponse;
import br.com.tasknoteapp.java_api.response.TaskResponse;
import br.com.tasknoteapp.java_api.service.HomeService;
import br.com.tasknoteapp.java_api.service.NoteService;
import br.com.tasknoteapp.java_api.service.TaskService;
import br.com.tasknoteapp.server.response.NoteResponse;
import br.com.tasknoteapp.server.response.SearchResponse;
import br.com.tasknoteapp.server.response.SummaryResponse;
import br.com.tasknoteapp.server.response.TaskResponse;
import br.com.tasknoteapp.server.service.HomeService;
import br.com.tasknoteapp.server.service.NoteService;
import br.com.tasknoteapp.server.service.TaskService;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -1,12 +1,15 @@
package br.com.tasknoteapp.java_api.service.impl;
package br.com.tasknoteapp.server.service.impl;
import br.com.tasknoteapp.java_api.service.JwtService;
import br.com.tasknoteapp.server.service.JwtService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import javax.crypto.SecretKey;
import org.springframework.security.core.userdetails.UserDetails;
@@ -29,7 +32,10 @@ class JwtServiceImpl implements JwtService {
@Override
public LocalDateTime extractExpiration(String token) {
Date date = extractClaim(token, Claims::getExpiration);
return date.toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDateTime();
if (!Objects.isNull(date)) {
return date.toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDateTime();
}
return null;
}
@Override
@@ -51,21 +57,33 @@ class JwtServiceImpl implements JwtService {
@Override
public boolean isTokenExpired(String token) {
return extractExpiration(token).isBefore(LocalDateTime.now());
LocalDateTime expiration = extractExpiration(token);
if (expiration != null) {
return expiration.isBefore(LocalDateTime.now());
}
return true;
}
@Override
public boolean validateTokenAndUser(String token, UserDetails user) {
final String email = user.getUsername();
return !isTokenExpired(token) && getEmailFromToken(token).equals(email);
return !isTokenExpired(token) && email.equals(getEmailFromToken(token));
}
private <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
final Optional<Claims> claims = extractAllClaims(token);
if (claims.isPresent()) {
return claimsResolver.apply(claims.get());
}
return null;
}
private Claims extractAllClaims(String token) {
return Jwts.parser().verifyWith(KEY).build().parseSignedClaims(token).getPayload();
private Optional<Claims> extractAllClaims(String token) {
try {
return Optional.of(
Jwts.parser().verifyWith(KEY).build().parseSignedClaims(token).getPayload());
} catch (MalformedJwtException me) {
return Optional.empty();
}
}
}
@@ -1,18 +1,18 @@
package br.com.tasknoteapp.java_api.service.impl;
package br.com.tasknoteapp.server.service.impl;
import br.com.tasknoteapp.java_api.entity.NoteEntity;
import br.com.tasknoteapp.java_api.entity.NoteUrlEntity;
import br.com.tasknoteapp.java_api.entity.UserEntity;
import br.com.tasknoteapp.java_api.exception.NoteNotFoundException;
import br.com.tasknoteapp.java_api.repository.NoteRepository;
import br.com.tasknoteapp.java_api.repository.NoteUrlRepository;
import br.com.tasknoteapp.java_api.request.NotePatchRequest;
import br.com.tasknoteapp.java_api.request.NoteRequest;
import br.com.tasknoteapp.java_api.request.NoteUrlPatchRequest;
import br.com.tasknoteapp.java_api.response.NoteResponse;
import br.com.tasknoteapp.java_api.service.AuthService;
import br.com.tasknoteapp.java_api.service.NoteService;
import br.com.tasknoteapp.java_api.util.AuthUtil;
import br.com.tasknoteapp.server.entity.NoteEntity;
import br.com.tasknoteapp.server.entity.NoteUrlEntity;
import br.com.tasknoteapp.server.entity.UserEntity;
import br.com.tasknoteapp.server.exception.NoteNotFoundException;
import br.com.tasknoteapp.server.repository.NoteRepository;
import br.com.tasknoteapp.server.repository.NoteUrlRepository;
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.response.NoteResponse;
import br.com.tasknoteapp.server.service.AuthService;
import br.com.tasknoteapp.server.service.NoteService;
import br.com.tasknoteapp.server.util.AuthUtil;
import jakarta.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;
@@ -1,18 +1,18 @@
package br.com.tasknoteapp.java_api.service.impl;
package br.com.tasknoteapp.server.service.impl;
import br.com.tasknoteapp.java_api.entity.TaskEntity;
import br.com.tasknoteapp.java_api.entity.TaskUrlEntity;
import br.com.tasknoteapp.java_api.entity.UserEntity;
import br.com.tasknoteapp.java_api.exception.TaskNotFoundException;
import br.com.tasknoteapp.java_api.repository.TaskRepository;
import br.com.tasknoteapp.java_api.repository.TaskUrlRepository;
import br.com.tasknoteapp.java_api.request.TaskPatchRequest;
import br.com.tasknoteapp.java_api.request.TaskRequest;
import br.com.tasknoteapp.java_api.request.TaskUrlPatchRequest;
import br.com.tasknoteapp.java_api.response.TaskResponse;
import br.com.tasknoteapp.java_api.service.AuthService;
import br.com.tasknoteapp.java_api.service.TaskService;
import br.com.tasknoteapp.java_api.util.AuthUtil;
import br.com.tasknoteapp.server.entity.TaskEntity;
import br.com.tasknoteapp.server.entity.TaskUrlEntity;
import br.com.tasknoteapp.server.entity.UserEntity;
import br.com.tasknoteapp.server.exception.TaskNotFoundException;
import br.com.tasknoteapp.server.repository.TaskRepository;
import br.com.tasknoteapp.server.repository.TaskUrlRepository;
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.TaskResponse;
import br.com.tasknoteapp.server.service.AuthService;
import br.com.tasknoteapp.server.service.TaskService;
import br.com.tasknoteapp.server.util.AuthUtil;
import jakarta.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;
@@ -1,8 +1,8 @@
package br.com.tasknoteapp.java_api.service.impl;
package br.com.tasknoteapp.server.service.impl;
import br.com.tasknoteapp.java_api.entity.UserEntity;
import br.com.tasknoteapp.java_api.repository.UserRepository;
import br.com.tasknoteapp.java_api.service.UserService;
import br.com.tasknoteapp.server.entity.UserEntity;
import br.com.tasknoteapp.server.repository.UserRepository;
import br.com.tasknoteapp.server.service.UserService;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.util;
package br.com.tasknoteapp.server.util;
import java.util.Objects;
import java.util.Optional;
@@ -0,0 +1,578 @@
[
{
"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.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": []
}
]
}
]
@@ -0,0 +1,25 @@
{
"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"
}
]
}
}
@@ -1,6 +1,8 @@
spring.application.name=java-api
spring.application.name=tasknote-api
server.port = 8585
server.error.include-message=always
logging.level.br.com.tasknoteapp.server = DEBUG
logging.level.org.springframework.security = DEBUG
# Actuator and ops
management.endpoint.health.show-details=always
@@ -21,7 +23,7 @@ spring.flyway.locations=classpath:db/migration
springdoc.enable-native-support=true
# Version (build)
br.com.tasknote.java-api.version=${BUILD:local}
br.com.tasknote.server.version=${BUILD:local}
# CORS
cors.allowed-origins=${CORS_ALLOWED_ORIGINS:http://localhost}
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api;
package br.com.tasknoteapp.server;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.controller;
package br.com.tasknoteapp.server.controller;
import static org.mockito.Mockito.when;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
@@ -7,9 +7,9 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import br.com.tasknoteapp.java_api.exception.UserAlreadyExistsException;
import br.com.tasknoteapp.java_api.request.LoginRequest;
import br.com.tasknoteapp.java_api.service.AuthService;
import br.com.tasknoteapp.server.exception.UserAlreadyExistsException;
import br.com.tasknoteapp.server.request.LoginRequest;
import br.com.tasknoteapp.server.service.AuthService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@@ -1,4 +1,4 @@
package br.com.tasknoteapp.java_api.controller;
package br.com.tasknoteapp.server.controller;
import static org.mockito.Mockito.when;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
@@ -6,11 +6,11 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import br.com.tasknoteapp.java_api.response.NoteResponse;
import br.com.tasknoteapp.java_api.response.SearchResponse;
import br.com.tasknoteapp.java_api.response.SummaryResponse;
import br.com.tasknoteapp.java_api.response.TaskResponse;
import br.com.tasknoteapp.java_api.service.HomeService;
import br.com.tasknoteapp.server.response.NoteResponse;
import br.com.tasknoteapp.server.response.SearchResponse;
import br.com.tasknoteapp.server.response.SummaryResponse;
import br.com.tasknoteapp.server.response.TaskResponse;
import br.com.tasknoteapp.server.service.HomeService;
import java.util.List;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.DisplayName;
@@ -1,4 +1,4 @@
spring.application.name=java-api
spring.application.name=tasknote-api
server.port = 8585
server.error.include-message=always
@@ -18,7 +18,7 @@ spring.jpa.hibernate.ddl-auto=create-drop
spring.flyway.enabled=false
# Version (build)
br.com.tasknote.java-api.version=${BUILD:local}
br.com.tasknote.server.version=${BUILD:local}
# CORS
cors.allowed-origins=${CORS_ALLOWED_ORIGINS:http://localhost}
+40
View File
@@ -40,6 +40,7 @@ docker pull ghcr.io/ricardo-campos-org/react-typescript-todolist/client:50
Run it:
- Client
```sh
docker run -d --rm \
-p 80:5000 \
@@ -48,3 +49,42 @@ docker run -d --rm \
--name tasknote \
ghcr.io/ricardo-campos-org/react-typescript-todolist/client:50
```
- Java API
```sh
docker run -d --rm \
-p 8585:8585 \
-e CORS_ALLOWED_ORIGINS="http://localhost:5000" \
-e POSTGRES_DB=tasknote \
-e POSTGRES_HOST=localhost \
-e POSTGRES_USER=tasknoteuser \
-e POSTGRES_PASSWORD=default \
-e POSTGRES_PORT=5435 \
--name server \
ghcr.io/ricardo-campos-org/react-typescript-todolist/server:50
```
or
```sh
docker compose --file docker-compose.prod.yml up -d server
```
- DB
```sh
docker run -d --rm \
-p 5435:5432 \
-e POSTGRES_DB="tasknote" \
-e POSTGRES_USER="tasknoteuser" \
-e POSTGRES_PASSWORD="default" \
-e POSTGRES_PORT=5435 \
-e PGDATA=/tmp \
-v "./data:/tmp" \
--name db \
postgres:15.8-bookworm
```
or
```sh
docker compose --file docker-compose.prod.yml up -d db
```
- Get container IP
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' db
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash
cd java-api
cd server
./mvnw --no-transfer-progress clean compile -DskipTests && \
./mvnw --no-transfer-progress checkstyle:checkstyle -Dskip.checkstyle=false && \
./mvnw --no-transfer-progress clean verify -P tests --file pom.xml