Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
# **`Documentation`**

## **`API`**
### Swagger
The swagger is available at this address after launching the application : http://localhost:18080/swagger

## **`Front`**
### Install
```npm install --legacy-peer-deps```
### Launch
```npm run serve```

Available at : http://localhost:8080/

# **`Technical test`**

Salut et bienvenue ici. Auchan te propose de consacrer un peu de temps pour nous exposer tes talents.
Expand Down
17 changes: 17 additions & 0 deletions technical-test-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,23 @@
</properties>

<dependencies>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package technical.test.api.DTO;

import lombok.Getter;

@Getter
public class Author {

private final String id;
private final String firstName;
private final String lastName;
private final int birthDate;

public Author(String firstName, String lastName, int birthDate) {
this.id = String.format("%s_%s", firstName, lastName).toLowerCase();
this.firstName = firstName;
this.lastName = lastName;
this.birthDate = birthDate;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package technical.test.api.DTO;

public record Book(String isbn, String title, Integer releaseDateYear, String authorId) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package technical.test.api.DTO;

public record BookAuthorInformation(String title, int releaseDateYear, String lastNameAuthor) {}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.reactive.config.EnableWebFlux;

@SpringBootApplication
@EnableWebFlux
public class TechnicalTestApiApplication {

public static void main(String[] args) {
SpringApplication.run(TechnicalTestApiApplication.class, args);
}

}
public static void main(String[] args) {
SpringApplication.run(TechnicalTestApiApplication.class, args);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package technical.test.api.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import org.springframework.web.reactive.config.CorsRegistry;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.config.WebFluxConfigurer;

@Configuration
@EnableWebFlux
public class WebFluxConfig implements WebFluxConfigurer {
@Override
public void addCorsMappings(CorsRegistry corsRegistry) {
corsRegistry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*");
}

@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package technical.test.api.controllers;

import jakarta.validation.Valid;
import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import lombok.AllArgsConstructor;
import org.springframework.validation.annotation.Validated;
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 reactor.core.publisher.Mono;
import technical.test.api.DTO.Author;
import technical.test.api.usecases.author.RegisterAuthor;

@RestController
@RequestMapping(value = "/library/authors")
@AllArgsConstructor
@Validated
public class AuthorController {

private final RegisterAuthor registerAuthor;

@PostMapping
public Mono<Author> registerAuthor(
@RequestParam(value = "firstname", required = false)
@NotNull(message = "firstName can't be null")
@NotBlank(message = "firstName can't be empty")
String firstName,
@RequestParam(value = "lastname", required = false)
@NotNull(message = "lastName can't be null")
@NotBlank(message = "lastName can't be empty")
String lastName,
@RequestParam(value = "birthdate", required = false)
@Positive(message = "birthDate must be positive")
@NotNull(message = "birthDate can't be null")
@Digits(integer = Integer.MAX_VALUE, fraction = 0, message = "birthDate must be an integer")
Integer birthDate) {
return registerAuthor.register(firstName, lastName, birthDate);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package technical.test.api.controllers;

import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import lombok.AllArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
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 reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import technical.test.api.DTO.Book;
import technical.test.api.DTO.BookAuthorInformation;
import technical.test.api.usecases.book.FindBook;
import technical.test.api.usecases.book.RegisterBook;

@RestController
@RequestMapping(value = "/library/books")
@AllArgsConstructor
@Validated
public class BookController {

private final FindBook findBook;

private final RegisterBook registerBook;

@GetMapping
public Flux<BookAuthorInformation> findAllBooks(
@RequestParam(value = "authorRefId", required = false)
String authorId,
@RequestParam(required = false)
@Digits(integer = Integer.MAX_VALUE, fraction = 0, message = "yearFrom must be an integer")
Integer yearFrom,
@RequestParam(required = false)
@Digits(integer = Integer.MAX_VALUE, fraction = 0, message = "yearTo must be an integer")
Integer yearTo) {
return findBook.findBookByAuthorAndDateBetween(authorId, yearFrom, yearTo);
}

@PostMapping
public Mono<Book> registerBook(
@RequestParam(required = false)
@NotNull(message = "isbn can't be null")
@NotBlank(message = "isbn can't be empty")
String isbn,
@RequestParam(required = false)
@NotNull(message = "title can't be null")
@NotBlank(message = "title can't be empty")
String title,
@RequestParam(required = false)
@NotNull(message = "releaseDateYear can't be null")
@Digits(integer = Integer.MAX_VALUE, fraction = 0, message = "releaseDateYear must be an integer")
int releaseDateYear,
@RequestParam(value = "authorRefId", required = false)
@NotNull(message = "authorRefId can't be null")
@NotBlank(message = "authorRefId can't be empty")
String authorId) {
return registerBook.register(isbn, title, releaseDateYear, authorId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package technical.test.api.entities;

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document
@Getter
@AllArgsConstructor
public class AuthorEntity {

private final String firstName;
private final String lastName;
private final int birthDate;
@Id
private String id;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package technical.test.api.entities;

import lombok.Getter;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document
@Getter
public class BookEntity {

private final String isbn;
private final String title;
private final Integer releaseDateYear;
private final String authorId;
@Id
private String id;

public BookEntity(String isbn, String title, Integer releaseDateYear, String authorId) {
this.isbn = isbn;
this.title = title;
this.releaseDateYear = releaseDateYear;
this.authorId = authorId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package technical.test.api.handlers;

import java.util.List;

public record ErrorResponse(int statusCode, String statusMessage, List<String> errorsDescription) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package technical.test.api.handlers;

import jakarta.validation.ConstraintViolationException;
import java.util.Arrays;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@ControllerAdvice
@RestController
public class GlobalExceptionHandler {

@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Mono<ErrorResponse> handleBadValidationRequestException(ConstraintViolationException ex) {
return Mono.just(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.name(),
Arrays.stream(ex.getMessage().split(",")).map(String::trim).toList()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package technical.test.api.mappers;

import org.mapstruct.Mapper;
import technical.test.api.DTO.Author;
import technical.test.api.entities.AuthorEntity;

@Mapper(componentModel = "spring")
public interface IAuthorMapper {

Author toAuthor(AuthorEntity authorEntity);

AuthorEntity toAuthor(Author author);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package technical.test.api.mappers;

import org.mapstruct.Mapper;
import technical.test.api.DTO.Book;
import technical.test.api.entities.BookEntity;

@Mapper(componentModel = "spring")
public interface IBookMapper {
Book toBook(BookEntity bookEntity);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package technical.test.api.repositories.author;

import lombok.AllArgsConstructor;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Mono;
import technical.test.api.entities.AuthorEntity;

@Repository
@AllArgsConstructor
public class AuthorRepositoryImpl implements IAuthorRepositoryImpl {

private final IAuthorRepository authorRepository;

@Override
public Mono<AuthorEntity> findById(String id) {
return this.authorRepository.findById(id);
}

@Override
public Mono<AuthorEntity> save(AuthorEntity authorEntity) {
return this.authorRepository.save(authorEntity);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package technical.test.api.repositories.author;

import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.stereotype.Repository;
import technical.test.api.entities.AuthorEntity;

@Repository
public interface IAuthorRepository extends ReactiveMongoRepository<AuthorEntity, String> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package technical.test.api.repositories.author;

import reactor.core.publisher.Mono;
import technical.test.api.entities.AuthorEntity;

public interface IAuthorRepositoryImpl {

Mono<AuthorEntity> findById(String id);

Mono<AuthorEntity> save(AuthorEntity authorEntity);
}
Loading