Put and post methods work with error handling 🔨
continuous-integration/drone/push Build is failing Details

Quarkus_Continue
Emre KARTAL 2 years ago
parent 2d23793eb0
commit 4011ff18c6

@ -57,7 +57,7 @@ public class GameDto {
public Long hostID;
@JsonProperty("winner")
public UserTinyDTO winner;
public UserTinyDto winner;
@JsonIgnore
@JsonProperty("rounds")
@ -72,7 +72,7 @@ public class GameDto {
Uni<List<ParticipeDto>> players,
LocalDate time,
Long ownerGame,
UserTinyDTO winner,
UserTinyDto winner,
Uni<List<RoundDto>> rounds) {
this.players = players;
this.date = time;

@ -15,9 +15,9 @@ public class ParticipeDto {
public int totalPoints;
@Schema(description = "The User entity that this Participe belongs to")
public UserDTO user;
public UserDto user;
public ParticipeDto(Long idUser, UserDTO user, Integer totalPoints, String guestName) {
public ParticipeDto(Long idUser, UserDto user, Integer totalPoints, String guestName) {
this.idUser = idUser;
this.guestName = guestName;

@ -5,7 +5,7 @@ import org.eclipse.microprofile.openapi.annotations.media.Schema;
@RegisterForReflection
@Schema(description = "A DTO for transferring user details")
public class UserDTO {
public class UserDto {
public Long id;
public String name;
@ -13,7 +13,7 @@ public class UserDTO {
public String mail;
//public UserStatsDTO stats;
public UserDTO(Long id, String name, String image, String mail) {
public UserDto(Long id, String name, String image, String mail) {
this.id = id;
this.name = name;
this.image = image;

@ -5,7 +5,7 @@ import org.eclipse.microprofile.openapi.annotations.media.Schema;
@RegisterForReflection
@Schema(description = "A DTO describing the stats of a User")
public class UserStatsDTO {
public class UserStatsDto {
public Long nbVictories;
public Long nbGames;
public Long highscore;
@ -14,8 +14,8 @@ public class UserStatsDTO {
public Double avgScore;
public Double avgPinsPerRound;
public UserStatsDTO(Long nbVictories, Long nbGames, Long highscore, Long nbStrikes, Long nbSpares, Double avgScore,
Double avgPinsPerRound) {
public UserStatsDto(Long nbVictories, Long nbGames, Long highscore, Long nbStrikes, Long nbSpares, Double avgScore,
Double avgPinsPerRound) {
this.nbVictories = nbVictories;
this.nbGames = nbGames;
this.highscore = highscore;

@ -1,16 +1,20 @@
package org.acme.api.dto;
import io.quarkus.hibernate.reactive.panache.common.ProjectedFieldName;
import io.quarkus.runtime.annotations.RegisterForReflection;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
@RegisterForReflection
@Schema(description = "A minimal DTO for transferring user information")
public class UserTinyDTO {
public Long id;
public class UserTinyDto {
public String name;
public UserTinyDTO(Long id, String name) {
this.id = id;
public String image;
public String mail;
public String password;
public UserTinyDto(String name, String image, String mail, String password) {
this.name = name;
this.image = image;
this.mail = mail;
this.password = password;
}
}

@ -6,7 +6,7 @@ import java.util.stream.Collectors;
import javax.ws.rs.NotFoundException;
import org.acme.api.dto.GameDto;
import org.acme.api.mappeur.GameMappeur;
import org.acme.api.mapper.GameMapper;
import io.smallrye.mutiny.Uni;
@ -19,20 +19,20 @@ public class GameManager {
}
public Uni<GameDto> saveGame(GameDto game) {
return dbManager.dbContext.gameRepository.persist(GameMappeur.toEntity(game, dbManager.dbContext))
.onItem().transform(gameEntity -> GameMappeur.toDto(gameEntity, dbManager.dbContext));
return dbManager.dbContext.gameRepository.persist(GameMapper.toEntity(game, dbManager.dbContext))
.onItem().transform(gameEntity -> GameMapper.toDto(gameEntity, dbManager.dbContext));
}
public Uni<GameDto> getDetailsGameById(Long gameId) {
return dbManager.dbContext.gameRepository.findById(gameId)
.onItem().ifNull().failWith(new NotFoundException("Game not found"))
.onItem().transform(gameEntity -> GameMappeur.toDto(gameEntity, dbManager.dbContext));
.onItem().transform(gameEntity -> GameMapper.toDto(gameEntity, dbManager.dbContext));
}
public Uni<List<GameDto>> getAllGames() {
return dbManager.dbContext.gameRepository.findAll().list()
.onItem().transform(games -> games.stream()
.map(gameEntity -> GameMappeur.toDto(gameEntity, dbManager.dbContext))
.map(gameEntity -> GameMapper.toDto(gameEntity, dbManager.dbContext))
.collect(Collectors.toList()))
.onFailure().invoke(throwable -> {
// Log the error or perform any other error handling here

@ -1,5 +0,0 @@
package org.acme.api.mappeur;
public class TrhowMappeur {
}

@ -1,18 +0,0 @@
package org.acme.api.mappeur;
import org.acme.api.dto.UserDTO;
import org.acme.api.dto.UserTinyDTO;
import org.acme.hibernates.entities.UserEntity;
public class UserMappeur {
public static UserDTO toUserDto(UserEntity entity) {
/*return new UserDTO(entity.id, entity.name, entity.stats.getNbVictories(), entity.stats.getNbGames(),
entity.stats.getHighscore(), entity.stats.getNbStrikes(), entity.stats.getNbSpares(),
entity.stats.getAvgScore(), entity.stats.getAvgPinsPerRound());*/
return new UserDTO((long)2, "f","fd","fd");
}
public static UserTinyDTO toUserTinyDTO(UserEntity entity) {
return new UserTinyDTO(entity.id, entity.getName());
}
}

@ -1,26 +1,19 @@
package org.acme.api.controllers;
import java.net.URI;
import java.util.List;
import java.util.stream.Collectors;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.acme.api.BowlDbContext;
import org.acme.api.dto.UserDTO;
import org.acme.hibernates.entities.UserEntity;
import org.acme.api.dto.UserDto;
import org.acme.api.dto.UserTinyDto;
import org.acme.api.mapper.UserMapper;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.jboss.logging.Logger;
@ -42,9 +35,10 @@ public class UserController {
@GET
@Operation(summary = "Get all users")
@Produces(MediaType.APPLICATION_JSON)
public Uni<List<UserDTO>> getUsers() {
public Uni<List<UserDto>> getUsers() {
LOGGER.info("Get all users");
return service.userRepository.findAll().project(UserDTO.class).list();
return service.userRepository.findAll().list()
.map(entities -> entities.stream().map(UserMapper::toDto).collect(Collectors.toList()));
}
@GET
@ -66,9 +60,17 @@ public class UserController {
@Path("/name/{name}")
public Uni<Response> getUserByName(@PathParam("name") String name) {
LOGGER.info("Get user with name : " + name);
return service.userRepository.findwithName(name)
.map(user -> user == null ? Response.status(Status.NOT_FOUND) : Response.ok(user).status(200))
.map(Response.ResponseBuilder::build);
return service.userRepository.verifiedName(name)
.flatMap(exist -> {
if (exist) {
return service.userRepository.findWithName(name)
.map(user -> Response.ok(user).build());
} else {
throw new NotFoundException("User not found");
}
});
}
@GET
@ -78,9 +80,16 @@ public class UserController {
@Path("/mail/{mail}")
public Uni<Response> getUserByMail(@PathParam("mail") String mail) {
LOGGER.info("Get user with mail : " + mail);
return service.userRepository.findwithMail(mail)
.map(user -> user == null ? Response.status(Status.NOT_FOUND) : Response.ok(user).status(200))
.map(Response.ResponseBuilder::build);
return service.userRepository.verifiedMail(mail)
.flatMap(exist -> {
if (exist) {
return service.userRepository.findWithMail(mail)
.map(user -> Response.ok(user).build());
} else {
throw new NotFoundException("User not found");
}
});
}
@POST
@ -88,35 +97,67 @@ public class UserController {
@APIResponse(responseCode = "201", description = "User successfully created")
@APIResponse(responseCode = "422", description = "User invalidly set on request")
@ReactiveTransactional
public Uni<Response> createUser(UserEntity user) {
public Uni<Response> createUser(UserTinyDto user) {
if (user == null) {
throw new WebApplicationException("user was invalidly set on request.", 422);
}
LOGGER.info("creating user: " + user.getName());
return service.userRepository.persist(user)
.map(persistedUser -> Response
.created(URI.create("/users/" + user.id))
.entity(persistedUser)
.build())
LOGGER.info("creating user: " + user);
return Uni.combine().all().unis(
service.userRepository.verifiedName(user.name),
service.userRepository.verifiedMail(user.mail))
.asTuple()
.flatMap(tuple -> {
boolean nameExists = tuple.getItem1();
boolean mailExists = tuple.getItem2();
if (nameExists) {
throw new WebApplicationException("Name already exists", Status.BAD_REQUEST);
}
if (mailExists) {
throw new WebApplicationException("Mail already exists", Status.BAD_REQUEST);
}
return service.userRepository.addUser(user)
.map(createdUser -> Response.status(Response.Status.CREATED).entity(createdUser).build());
})
.onFailure().recoverWithItem(Response.status(Status.BAD_REQUEST).build());
}
@PUT
@Operation(summary = "Update a user")
@APIResponse(responseCode = "200", description = "OK")
@APIResponse(responseCode = "400", description = "Bad Request")
@APIResponse(responseCode = "404", description = "User not found")
@Path("/{id}")
@ReactiveTransactional
public Uni<Response> updateUser(@PathParam("id") Long id, UserEntity newUser) {
public Uni<Response> updateUser(@PathParam("id") Long id, UserTinyDto newUser) {
LOGGER.info("Update user with id : " + id);
return service.userRepository.findById(id)
.onItem().ifNull().failWith(() -> new WebApplicationException("User not found", Status.NOT_FOUND))
.onItem().ifNotNull().invoke(oldUser -> {
oldUser.setName(newUser.getName());
})
.onItem().ifNotNull().transform(entity -> Response.ok(entity).build());
.onItem().ifNotNull().transformToUni(oldUser ->
Uni.combine().all().unis(
service.userRepository.verifiedName(newUser.name),
service.userRepository.verifiedMail(newUser.mail))
.asTuple()
.flatMap(tuple -> {
boolean nameExists = tuple.getItem1();
boolean mailExists = tuple.getItem2();
if (nameExists && !oldUser.getName().equalsIgnoreCase(newUser.name)) {
throw new WebApplicationException("Name already exists", Status.BAD_REQUEST);
}
if (mailExists && !oldUser.getMail().equalsIgnoreCase(newUser.mail)) {
throw new WebApplicationException("Mail already exists", Status.BAD_REQUEST);
}
oldUser.setName(newUser.name);
oldUser.setMail(newUser.mail);
oldUser.setImage(newUser.image);
return service.userRepository.persistAndFlush(oldUser)
.map(entity -> Response.ok(UserMapper.toDto(entity)).build());
})
);
}
@DELETE
@Operation(summary = "Delete a user")
@APIResponse(responseCode = "204")

@ -1,4 +1,4 @@
package org.acme.api.mappeur;
package org.acme.api.mapper;
import java.time.LocalDate;
import java.time.ZoneId;
@ -17,7 +17,7 @@ import io.smallrye.mutiny.Uni;
public class Extensions {
public static Uni<List<RoundDto>> toRoundDtoList(Uni<List<RoundEntity>> uni) {
return uni.map(roundEntities -> roundEntities.stream()
.map(RoundMappeur::toDto)
.map(RoundMapper::toDto)
.collect(Collectors.toList()));
}
@ -26,7 +26,7 @@ public class Extensions {
.onItem().transformToUni(participes -> {
List<ParticipeDto> dtos = new ArrayList<>();
for (ParticipeEntity entity : participes) {
dtos.add(ParticipeMappeur.toDto(entity));
dtos.add(ParticipeMapper.toDto(entity));
}
return Uni.createFrom().item(dtos);
})

@ -1,10 +1,10 @@
package org.acme.api.mappeur;
package org.acme.api.mapper;
import org.acme.api.BowlDbContext;
import org.acme.api.dto.GameDto;
import org.acme.hibernates.entities.GameEntity;
public class GameMappeur {
public class GameMapper {
public static GameDto toDto(GameEntity entity, BowlDbContext dbContext) {
GameDto dto = new GameDto();

@ -1,11 +1,11 @@
package org.acme.api.mappeur;
package org.acme.api.mapper;
import org.acme.api.dto.ParticipeDto;
import org.acme.hibernates.entities.ParticipeEntity;
public class ParticipeMappeur {
public class ParticipeMapper {
public static ParticipeDto toDto(ParticipeEntity entity) {
return new ParticipeDto(entity.user.id, UserMappeur.toUserDto(entity.user), entity.totalPoints,
return new ParticipeDto(entity.user.id, UserMapper.toDto(entity.user), entity.totalPoints,
entity.guestName);
}

@ -1,4 +1,4 @@
package org.acme.api.mappeur;
package org.acme.api.mapper;
import java.util.List;
@ -6,7 +6,7 @@ import org.acme.api.dto.RoundDto;
import org.acme.hibernates.entities.RoundEntity;
import org.acme.hibernates.entities.ThrowEntity;
public class RoundMappeur {
public class RoundMapper {
public static RoundDto toDto(RoundEntity entity) {
List<ThrowEntity> throwsGame = entity.throwsGame;

@ -0,0 +1,5 @@
package org.acme.api.mapper;
public class TrhowMapper {
}

@ -0,0 +1,38 @@
package org.acme.api.mapper;
import org.acme.api.dto.UserDto;
import org.acme.api.dto.UserTinyDto;
import org.acme.hibernates.entities.UserEntity;
import java.security.MessageDigest;
public class UserMapper {
private static final String HASH_ALGORITHM = "SHA-256";
public static UserDto toDto(UserEntity user) {
return new UserDto(user.id, user.getName(), user.getImage(), user.getMail());
}
public static UserEntity toEntity(UserTinyDto user) {
try {
MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
byte[] hashedBytes = digest.digest(user.password.getBytes("UTF-8"));
String hashedPassword = bytesToHex(hashedBytes);
return new UserEntity(user.name.toLowerCase(), user.image, user.mail.toLowerCase(), hashedPassword);
} catch (Exception ex) {
throw new RuntimeException("Error hashing password", ex);
}
}
private static String bytesToHex(byte[] bytes) {
StringBuilder hexString = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(0xFF & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
}

@ -2,29 +2,53 @@ package org.acme.api.service;
import javax.enterprise.context.ApplicationScoped;
import org.acme.api.dto.UserDTO;
import org.acme.api.dto.UserDto;
import org.acme.api.dto.UserTinyDto;
import org.acme.api.mapper.UserMapper;
import org.acme.hibernates.entities.UserEntity;
import io.quarkus.hibernate.reactive.panache.PanacheRepository;
import io.smallrye.mutiny.Uni;
import java.util.Objects;
@ApplicationScoped
public class UserRepository implements PanacheRepository<UserEntity> {
// public Uni<UserEntity> getUserByName(String name) {
// return UserEntity.find("name", name).firstResult();
// }
public Uni<UserDto> addUser(UserTinyDto user) {
UserEntity userEntity = UserMapper.toEntity(user);
return persistAndFlush(userEntity)
.map(ignore -> UserMapper.toDto(userEntity));
}
public Uni<UserDto> findWithName(String name) {
return find("name", name.toLowerCase())
.firstResult()
.map(UserMapper::toDto);
}
public Uni<Boolean> verifiedName(String name) {
return find("name", name.toLowerCase())
.firstResult()
.map(Objects::nonNull);
}
public Uni<UserDTO> findwithName(String name) {
return find("name", name.toLowerCase()).project(UserDTO.class).firstResult();
public Uni<Boolean> verifiedMail(String mail) {
return find("mail", mail.toLowerCase())
.firstResult()
.map(Objects::nonNull);
}
public Uni<UserDTO> findwithMail(String mail) {
return find("mail", mail.toLowerCase()).project(UserDTO.class).firstResult();
public Uni<UserDto> findWithMail(String mail) {
return find("mail", mail.toLowerCase())
.firstResult()
.map(UserMapper::toDto);
}
public Uni<UserDTO> getUserById(Long id) {
return find("id", id).project(UserDTO.class).firstResult();
public Uni<UserDto> getUserById(Long id) {
return find("id", id)
.firstResult()
.map(UserMapper::toDto);
}
}

@ -29,9 +29,17 @@ public class UserEntity {
//this.stats = new UserStatsEntity(this);
}
public UserEntity(String name, String image, String mail, String password) {
this.name = name;
this.image = image;
this.mail = mail;
this.password = password;
//this.stats = new UserStatsEntity(this);
}
// return name as uppercase in the model
public String getName() {
return name.toUpperCase();
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
// store all names in lowercase in the DB
@ -44,7 +52,23 @@ public class UserEntity {
}
public void setPassword(String password) {
this.password = password.toLowerCase();
this.password = password;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public String getMail() {
return mail;
}
public void setMail(String mail) {
this.mail = mail.toLowerCase();
}
}

@ -1,9 +1,9 @@
INSERT INTO
INSERT INTO
Users (name, password, image, mail)
VALUES
('david', 'password123','','david.d_almeida@etu.uca.fr'),
('emre', 'password2','','emre.kartal@etu.uca.fr'),
('arthur', 'password3','','arthur.valin@etu.uca.fr');
('david', '38762cf7f55934b34d179ae6a4c80cadccbb7f0a2c2a5b4c4a1cb595d8dadb31','','david.d_almeida@etu.uca.fr'),
('emre', 'af7c70f8789d9e0fde5b5f18b61c5e5dc5d5c5f5e7e5c4f4be7b2cb5d57ef52c','','emre.kartal@etu.uca.fr'),
('arthur', '0cc175b9c0f1b6a831c399e269772661','','arthur.valin@etu.uca.fr');
/*INSERT INTO games (isFinished, nbPoints, time, winner, host_id) VALUES (false, 0, CURRENT_TIMESTAMP, 0, 1);
INSERT INTO participe (idGame, position, guestname, totalpoints, iduser) VALUES (1, 1, 'Alice', 0, 1);

Loading…
Cancel
Save