Move backend files into a sub folder.

This commit is contained in:
Florian THIERRY
2024-03-27 10:28:22 +01:00
parent 39663e914d
commit 431d365d20
131 changed files with 3633 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.codiki</groupId>
<artifactId>codiki-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<artifactId>codiki-exposition</artifactId>
<name>codiki-exposition</name>
<description>Demo project for Spring Boot</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.codiki</groupId>
<artifactId>codiki-application</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-data-jpa</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-security</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.postgresql</groupId>-->
<!-- <artifactId>postgresql</artifactId>-->
<!-- <scope>runtime</scope>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-test</artifactId>-->
<!-- <scope>test</scope>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.security</groupId>-->
<!-- <artifactId>spring-security-test</artifactId>-->
<!-- <scope>test</scope>-->
<!-- </dependency>-->
</dependencies>
</project>

View File

@@ -0,0 +1,64 @@
package org.codiki.exposition.category;
import java.util.List;
import java.util.UUID;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.NO_CONTENT;
import org.codiki.application.category.CategoryUseCases;
import org.codiki.domain.category.model.Category;
import org.codiki.exposition.category.model.CategoryDto;
import org.codiki.exposition.category.model.CategoryEditionRequest;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/categories")
public class CategoryController {
private final CategoryUseCases categoryUseCases;
public CategoryController(CategoryUseCases categoryUseCases) {
this.categoryUseCases = categoryUseCases;
}
@PostMapping
@ResponseStatus(CREATED)
public CategoryDto createCategory(@RequestBody CategoryEditionRequest request) {
Category createdCategory = categoryUseCases.createCategory(request.name(), request.subCategoryIds());
return new CategoryDto(createdCategory);
}
@PutMapping("/{categoryId}")
public CategoryDto updateCategory(
@PathVariable("categoryId") UUID categoryId,
@RequestBody CategoryEditionRequest request
) {
Category createdCategory = categoryUseCases.updateCategory(
categoryId,
request.name(),
request.subCategoryIds()
);
return new CategoryDto(createdCategory);
}
@DeleteMapping("/{categoryId}")
@ResponseStatus(NO_CONTENT)
public void deleteCategory(@PathVariable("categoryId") UUID categoryId) {
categoryUseCases.deleteCategory(categoryId);
}
@GetMapping
public List<CategoryDto> getAllCategories() {
return categoryUseCases.getAll()
.stream()
.map(CategoryDto::new)
.toList();
}
}

View File

@@ -0,0 +1,23 @@
package org.codiki.exposition.category.model;
import java.util.List;
import java.util.UUID;
import org.codiki.domain.category.model.Category;
public record CategoryDto(
UUID id,
String name,
List<CategoryDto> subCategories
) {
public CategoryDto(Category category) {
this(
category.id(),
category.name(),
category.subCategories()
.stream()
.map(CategoryDto::new)
.toList()
);
}
}

View File

@@ -0,0 +1,9 @@
package org.codiki.exposition.category.model;
import java.util.List;
import java.util.UUID;
public record CategoryEditionRequest(
String name,
List<UUID> subCategoryIds
) {}

View File

@@ -0,0 +1,73 @@
package org.codiki.exposition.configuration;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.UNAUTHORIZED;
import org.codiki.domain.category.exception.CategoryDeletionException;
import org.codiki.domain.category.exception.CategoryEditionException;
import org.codiki.domain.category.exception.CategoryNotFoundException;
import org.codiki.domain.exception.LoginFailureException;
import org.codiki.domain.exception.RefreshTokenDoesNotExistException;
import org.codiki.domain.exception.RefreshTokenExpiredException;
import org.codiki.domain.exception.UserDoesNotExistException;
import org.codiki.domain.picture.exception.PictureNotFoundException;
import org.codiki.domain.picture.exception.PictureUploadException;
import org.codiki.domain.publication.exception.NoPublicationSearchResultException;
import org.codiki.domain.publication.exception.PublicationEditionException;
import org.codiki.domain.publication.exception.PublicationNotFoundException;
import org.codiki.domain.publication.exception.PublicationUpdateForbiddenException;
import org.codiki.domain.user.exception.UserAlreadyExistsException;
import org.codiki.domain.user.exception.UserCreationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@RestControllerAdvice
public class GlobalControllerExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler({
CategoryDeletionException.class,
CategoryEditionException.class,
CategoryNotFoundException.class,
LoginFailureException.class,
PublicationEditionException.class,
PictureUploadException.class,
UserAlreadyExistsException.class,
UserCreationException.class
})
public ProblemDetail handleBadRequestExceptions(Exception exception) {
return buildProblemDetail(BAD_REQUEST, exception);
}
@ExceptionHandler({
UserDoesNotExistException.class,
RefreshTokenDoesNotExistException.class,
PublicationNotFoundException.class,
PictureNotFoundException.class,
NoPublicationSearchResultException.class
})
public ProblemDetail handleNotFoundExceptions(Exception exception) {
return buildProblemDetail(NOT_FOUND, exception);
}
@ExceptionHandler({
RefreshTokenExpiredException.class
})
public ProblemDetail handleUnauthorizedExceptions(Exception exception) {
return buildProblemDetail(UNAUTHORIZED, exception);
}
@ExceptionHandler({
PublicationUpdateForbiddenException.class
})
public ProblemDetail handleForbiddenExceptions(Exception exception) {
return buildProblemDetail(FORBIDDEN, exception);
}
private static ProblemDetail buildProblemDetail(HttpStatus forbidden, Exception exception) {
return ProblemDetail.forStatusAndDetail(forbidden, exception.getMessage());
}
}

View File

@@ -0,0 +1,60 @@
package org.codiki.exposition.configuration.security;
import java.io.IOException;
import java.util.Optional;
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
import static org.springframework.util.ObjectUtils.isEmpty;
import org.codiki.application.security.JwtService;
import org.codiki.application.security.model.CustomUserDetails;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private static final String BEARER_PREFIX = "Bearer ";
private final JwtService jwtService;
public JwtAuthenticationFilter(JwtService jwtService) {
this.jwtService = jwtService;
}
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain
) throws ServletException, IOException {
Optional.ofNullable(request.getHeader(AUTHORIZATION))
.filter(authorizationHeader -> !isEmpty(authorizationHeader))
.filter(authorizationHeader -> authorizationHeader.startsWith(BEARER_PREFIX))
.map(authorizationHeader -> authorizationHeader.substring(BEARER_PREFIX.length()))
.filter(token -> {
String authorizationHeader = request.getHeader(AUTHORIZATION);
return !isEmpty(authorizationHeader) && authorizationHeader.startsWith(BEARER_PREFIX);
})
.filter(jwtService::isValid)
.flatMap(jwtService::extractUser)
.map(CustomUserDetails::new)
.map(userDetails -> new UsernamePasswordAuthenticationToken(
userDetails,
null,
userDetails.getAuthorities()
))
.ifPresent(authenticationToken -> {
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
});
filterChain.doFilter(request, response);
}
}

View File

@@ -0,0 +1,76 @@
package org.codiki.exposition.configuration.security;
import static org.springframework.http.HttpMethod.DELETE;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.HttpMethod.OPTIONS;
import static org.springframework.http.HttpMethod.POST;
import static org.springframework.http.HttpMethod.PUT;
import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS;
import org.codiki.domain.user.model.UserRole;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
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.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import static jakarta.servlet.DispatcherType.FORWARD;
import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static jakarta.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(securedEnabled = true)
public class SecurityConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(
HttpSecurity httpSecurity,
JwtAuthenticationFilter jwtAuthenticationFilter
) throws Exception {
httpSecurity
.csrf(AbstractHttpConfigurer::disable)
.httpBasic(Customizer.withDefaults())
.exceptionHandling(configurer -> configurer
.authenticationEntryPoint((request, response, authException) -> response.sendError(SC_UNAUTHORIZED))
.accessDeniedHandler((request, response, accessDeniedException) -> response.sendError(SC_FORBIDDEN))
)
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.sessionManagement(customizer -> customizer.sessionCreationPolicy(STATELESS))
.authorizeHttpRequests(requests -> requests
.dispatcherTypeMatchers(FORWARD).permitAll()
.requestMatchers(
GET,
"/api/health/check",
"/api/categories",
"/api/pictures/{pictureId}",
"/api/publications/{publicationId}",
"/api/publications",
"/error"
).permitAll()
.requestMatchers(
POST,
"/api/users/login",
"/api/users/refresh-token"
).permitAll()
.requestMatchers(
POST,
"/api/categories"
).hasRole(UserRole.ADMIN.name())
.requestMatchers(
PUT,
"/api/categories/{categoryId}"
).hasRole(UserRole.ADMIN.name())
.requestMatchers(
DELETE,
"/api/categories/{categoryId}"
).hasRole(UserRole.ADMIN.name())
.requestMatchers(OPTIONS).permitAll()
.anyRequest().authenticated()
);
return httpSecurity.build();
}
}

View File

@@ -0,0 +1,14 @@
package org.codiki.exposition.healthcheck;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/health")
public class HealthCheckController {
@GetMapping("/check")
public String healthCheck() {
return "Ok";
}
}

View File

@@ -0,0 +1,77 @@
package org.codiki.exposition.picture;
import static java.util.Objects.isNull;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
import org.apache.tika.mime.MimeType;
import org.apache.tika.mime.MimeTypeException;
import org.apache.tika.mime.MimeTypes;
import org.codiki.domain.picture.exception.PictureUploadException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
@Component
public class MultipartFileConverter {
private static final List<MimeType> ALLOWED_MIME_TYPES;
static {
MimeTypes mimeTypes = MimeTypes.getDefaultMimeTypes();
try {
ALLOWED_MIME_TYPES = List.of(
mimeTypes.forName("image/png"),
mimeTypes.forName("image/jpeg"),
mimeTypes.forName("image/svg+xml")
);
} catch (MimeTypeException exception) {
throw new RuntimeException("An error occurred while loading allowed mime types.", exception);
}
}
private final String tempPicturesFolderPath;
public MultipartFileConverter(@Value("${application.pictures.temp-path}") String tempPicturesFolderPath) {
this.tempPicturesFolderPath = tempPicturesFolderPath;
}
public File transformToFile(MultipartFile fileContent) {
File pictureFile = new File(buildPicturePath(fileContent));
try {
fileContent.transferTo(pictureFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
return pictureFile;
}
private String buildPicturePath(MultipartFile fileContent) {
checkMimeTypeIsAllowed(fileContent);
return String.format(
"%s/%s",
tempPicturesFolderPath,
UUID.randomUUID()
);
}
private void checkMimeTypeIsAllowed(MultipartFile fileContent) {
MimeType result = null;
try {
result = MimeTypes.getDefaultMimeTypes()
.forName(fileContent.getContentType());
} catch (MimeTypeException exception) {
// Do nothing
}
if (isNull(result) || !isAllowedMimeType(result)) {
throw new PictureUploadException("Unable to upload the picture because its format is incorrect.");
}
}
private boolean isAllowedMimeType(MimeType mimeType) {
return ALLOWED_MIME_TYPES.contains(mimeType);
}
}

View File

@@ -0,0 +1,47 @@
package org.codiki.exposition.picture;
import java.io.File;
import java.util.UUID;
import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE;
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
import org.codiki.application.picture.PictureUseCases;
import org.codiki.domain.picture.exception.PictureNotFoundException;
import org.codiki.domain.picture.model.Picture;
import org.springframework.core.io.FileSystemResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/api/pictures")
public class PictureController {
private final MultipartFileConverter multipartFileConverter;
private final PictureUseCases pictureUseCases;
public PictureController(
MultipartFileConverter multipartFileConverter,
PictureUseCases pictureUseCases
) {
this.multipartFileConverter = multipartFileConverter;
this.pictureUseCases = pictureUseCases;
}
@PostMapping(consumes = MULTIPART_FORM_DATA_VALUE)
public UUID uploadPicture(@RequestParam("file") MultipartFile fileContent) {
File pictureFile = multipartFileConverter.transformToFile(fileContent);
Picture newPicture = pictureUseCases.createPicture(pictureFile);
return newPicture.id();
}
@GetMapping(value = "/{pictureId}", produces = APPLICATION_OCTET_STREAM_VALUE)
public FileSystemResource loadPicture(@PathVariable("pictureId") UUID pictureId) {
Picture picture = pictureUseCases.findById(pictureId)
.orElseThrow(() -> new PictureNotFoundException(pictureId));
return new FileSystemResource(picture.contentFile());
}
}

View File

@@ -0,0 +1,80 @@
package org.codiki.exposition.publication;
import java.util.List;
import java.util.UUID;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.NO_CONTENT;
import static org.springframework.util.ObjectUtils.isEmpty;
import org.codiki.application.publication.PublicationUseCases;
import org.codiki.domain.publication.exception.NoPublicationSearchResultException;
import org.codiki.domain.publication.exception.PublicationNotFoundException;
import org.codiki.domain.publication.model.Publication;
import org.codiki.domain.publication.model.PublicationEditionRequest;
import org.codiki.exposition.publication.model.PublicationDto;
import org.codiki.exposition.publication.model.PublicationEditionRequestDto;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/publications")
public class PublicationController {
private final PublicationUseCases publicationUseCases;
public PublicationController(PublicationUseCases publicationUseCases) {
this.publicationUseCases = publicationUseCases;
}
@GetMapping("/{publicationId}")
public PublicationDto getById(@PathVariable("publicationId") UUID publicationId) {
return publicationUseCases.findById(publicationId)
.map(PublicationDto::new)
.orElseThrow(() -> new PublicationNotFoundException(publicationId));
}
@PostMapping
@ResponseStatus(CREATED)
public PublicationDto createPublication(@RequestBody PublicationEditionRequestDto requestDto) {
PublicationEditionRequest request = requestDto.toDomain();
Publication newPublication = publicationUseCases.createPublication(request);
return new PublicationDto(newPublication);
}
@PutMapping("/{publicationId}")
public PublicationDto updatePublication(
@PathVariable("publicationId") UUID publicationId,
@RequestBody PublicationEditionRequestDto requestDto
) {
PublicationEditionRequest request = requestDto.toDomain();
Publication updatedPublication = publicationUseCases.updatePublication(publicationId, request);
return new PublicationDto(updatedPublication);
}
@DeleteMapping("/{publicationId}")
@ResponseStatus(NO_CONTENT)
public void deletePublication(@PathVariable("publicationId") UUID publicationId) {
publicationUseCases.deletePublication(publicationId);
}
@GetMapping
public List<PublicationDto> searchPublications(@RequestParam("query") String searchQuery) {
final List<PublicationDto> publications = publicationUseCases.searchPublications(searchQuery)
.stream()
.map(PublicationDto::new)
.toList();
if (isEmpty(publications)) {
throw new NoPublicationSearchResultException();
}
return publications;
}
}

View File

@@ -0,0 +1,19 @@
package org.codiki.exposition.publication.model;
import java.util.UUID;
import org.codiki.domain.publication.model.Author;
public record AuthorDto(
UUID id,
String name,
String image
) {
public AuthorDto(Author author) {
this(
author.id(),
author.name(),
author.image()
);
}
}

View File

@@ -0,0 +1,33 @@
package org.codiki.exposition.publication.model;
import java.time.ZonedDateTime;
import java.util.UUID;
import org.codiki.domain.publication.model.Publication;
import org.codiki.exposition.category.model.CategoryDto;
public record PublicationDto(
UUID id,
String key,
String title,
String text,
String description,
ZonedDateTime creationDate,
UUID illustrationId,
UUID categoryId,
AuthorDto author
) {
public PublicationDto(Publication publication) {
this(
publication.id(),
publication.key(),
publication.title(),
publication.text(),
publication.description(),
publication.creationDate(),
publication.illustrationId(),
publication.categoryId(),
new AuthorDto(publication.author())
);
}
}

View File

@@ -0,0 +1,17 @@
package org.codiki.exposition.publication.model;
import java.util.UUID;
import org.codiki.domain.publication.model.PublicationEditionRequest;
public record PublicationEditionRequestDto(
String title,
String text,
String description,
UUID illustrationId,
UUID categoryId
) {
public PublicationEditionRequest toDomain() {
return new PublicationEditionRequest(title, text, description, illustrationId, categoryId);
}
}

View File

@@ -0,0 +1,55 @@
package org.codiki.exposition.user;
import java.util.List;
import static org.springframework.http.HttpStatus.CREATED;
import org.codiki.application.security.annotation.AllowedToAdmins;
import org.codiki.application.security.annotation.AllowedToAnonymous;
import org.codiki.application.user.UserUseCases;
import org.codiki.domain.user.model.User;
import org.codiki.domain.user.model.UserAuthenticationData;
import org.codiki.exposition.user.model.LoginRequest;
import org.codiki.exposition.user.model.LoginResponse;
import org.codiki.exposition.user.model.RefreshTokenRequest;
import org.codiki.exposition.user.model.SignInRequestDto;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserUseCases userUseCases;
public UserController(UserUseCases userUseCases) {
this.userUseCases = userUseCases;
}
@PostMapping("/login")
@AllowedToAnonymous
public LoginResponse login(@RequestBody LoginRequest request) {
UserAuthenticationData userAuthenticationData = userUseCases.authenticate(request.email(), request.password());
return new LoginResponse(userAuthenticationData);
}
@GetMapping
@AllowedToAdmins
public List<User> findAll() {
return userUseCases.findAll();
}
@PostMapping("/refresh-token")
public LoginResponse refreshToken(@RequestBody RefreshTokenRequest request) {
UserAuthenticationData userAuthenticationData = userUseCases.authenticate(request.refreshTokenValue());
return new LoginResponse(userAuthenticationData);
}
@PostMapping
@ResponseStatus(CREATED)
public void signIn(@RequestBody SignInRequestDto request) {
userUseCases.createUser(request.pseudo(), request.email(), request.password());
}
}

View File

@@ -0,0 +1,6 @@
package org.codiki.exposition.user.model;
public record LoginRequest(
String email,
String password
) {}

View File

@@ -0,0 +1,17 @@
package org.codiki.exposition.user.model;
import org.codiki.domain.user.model.UserAuthenticationData;
public record LoginResponse(
String tokenType,
String accessToken,
String refreshToken
) {
public LoginResponse(UserAuthenticationData userAuthenticationData) {
this(
userAuthenticationData.tokenType(),
userAuthenticationData.accessToken(),
userAuthenticationData.refreshToken().value().toString()
);
}
}

View File

@@ -0,0 +1,8 @@
package org.codiki.exposition.user.model;
import java.util.UUID;
public record RefreshTokenRequest(
UUID refreshTokenValue
) {
}

View File

@@ -0,0 +1,8 @@
package org.codiki.exposition.user.model;
public record SignInRequestDto(
String pseudo,
String email,
String password
) {
}