Add fields to user entity.
This commit is contained in:
@@ -5,6 +5,9 @@ import java.util.List;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.codiki.domain.user.model.UserRole.STANDARD;
|
||||||
|
import static org.codiki.domain.user.model.builder.UserBuilder.anUser;
|
||||||
|
import static org.springframework.util.ObjectUtils.isEmpty;
|
||||||
import org.codiki.application.security.AuthenticationFacade;
|
import org.codiki.application.security.AuthenticationFacade;
|
||||||
import org.codiki.application.security.JwtService;
|
import org.codiki.application.security.JwtService;
|
||||||
import org.codiki.application.security.annotation.AllowedToAdmins;
|
import org.codiki.application.security.annotation.AllowedToAdmins;
|
||||||
@@ -12,6 +15,8 @@ import org.codiki.application.security.model.CustomUserDetails;
|
|||||||
import org.codiki.domain.exception.LoginFailureException;
|
import org.codiki.domain.exception.LoginFailureException;
|
||||||
import org.codiki.domain.exception.RefreshTokenDoesNotExistException;
|
import org.codiki.domain.exception.RefreshTokenDoesNotExistException;
|
||||||
import org.codiki.domain.exception.UserDoesNotExistException;
|
import org.codiki.domain.exception.UserDoesNotExistException;
|
||||||
|
import org.codiki.domain.user.exception.UserAlreadyExistsException;
|
||||||
|
import org.codiki.domain.user.exception.UserCreationException;
|
||||||
import org.codiki.domain.user.model.RefreshToken;
|
import org.codiki.domain.user.model.RefreshToken;
|
||||||
import org.codiki.domain.user.model.User;
|
import org.codiki.domain.user.model.User;
|
||||||
import org.codiki.domain.user.model.UserAuthenticationData;
|
import org.codiki.domain.user.model.UserAuthenticationData;
|
||||||
@@ -107,4 +112,26 @@ public class UserUseCases {
|
|||||||
userPort.save(refreshToken);
|
userPort.save(refreshToken);
|
||||||
return refreshToken;
|
return refreshToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public User createUser(String pseudo, String email, String password) {
|
||||||
|
if (isEmpty(pseudo) || isEmpty(email) || isEmpty(password)) {
|
||||||
|
throw new UserCreationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userPort.existsByEmail(email)) {
|
||||||
|
throw new UserAlreadyExistsException();
|
||||||
|
}
|
||||||
|
|
||||||
|
User newUser = anUser()
|
||||||
|
.withId(UUID.randomUUID())
|
||||||
|
.withPseudo(pseudo)
|
||||||
|
.withEmail(email)
|
||||||
|
.withPassword(passwordEncoder.encode(password))
|
||||||
|
.withRole(STANDARD)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
userPort.save(newUser);
|
||||||
|
|
||||||
|
return newUser;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.codiki.domain.user.exception;
|
||||||
|
|
||||||
|
import org.codiki.domain.exception.FunctionnalException;
|
||||||
|
|
||||||
|
public class UserAlreadyExistsException extends FunctionnalException {
|
||||||
|
public UserAlreadyExistsException() {
|
||||||
|
super("An user already exists with this email address.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.codiki.domain.user.exception;
|
||||||
|
|
||||||
|
import org.codiki.domain.exception.FunctionnalException;
|
||||||
|
|
||||||
|
public class UserCreationException extends FunctionnalException {
|
||||||
|
public UserCreationException() {
|
||||||
|
super("Pseudo, email address and password can not be empty.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,9 @@ import java.util.UUID;
|
|||||||
|
|
||||||
public record User(
|
public record User(
|
||||||
UUID id,
|
UUID id,
|
||||||
|
String pseudo,
|
||||||
|
String email,
|
||||||
String password,
|
String password,
|
||||||
|
UUID photoId,
|
||||||
List<UserRole> roles
|
List<UserRole> roles
|
||||||
) {}
|
) {}
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package org.codiki.domain.user.model.builder;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.codiki.domain.user.model.User;
|
||||||
|
import org.codiki.domain.user.model.UserRole;
|
||||||
|
|
||||||
|
public class UserBuilder {
|
||||||
|
private UUID id;
|
||||||
|
private String pseudo;
|
||||||
|
private String email;
|
||||||
|
private String password;
|
||||||
|
private UUID photoId;
|
||||||
|
private Set<UserRole> roles = new HashSet<>();
|
||||||
|
|
||||||
|
private UserBuilder() {}
|
||||||
|
|
||||||
|
public static UserBuilder anUser() {
|
||||||
|
return new UserBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserBuilder withId(UUID id) {
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserBuilder withPseudo(String pseudo) {
|
||||||
|
this.pseudo = pseudo;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserBuilder withEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserBuilder withPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserBuilder withPhotoId(UUID photoId) {
|
||||||
|
this.photoId = photoId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserBuilder withRole(UserRole role) {
|
||||||
|
this.roles.add(role);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserBuilder withRoles(List<UserRole> roles) {
|
||||||
|
this.roles = new HashSet<>(roles);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User build() {
|
||||||
|
return new User(id, pseudo,email, password, photoId, new LinkedList<>(roles));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,4 +21,6 @@ public interface UserPort {
|
|||||||
Optional<RefreshToken> findRefreshTokenById(UUID refreshTokenId);
|
Optional<RefreshToken> findRefreshTokenById(UUID refreshTokenId);
|
||||||
|
|
||||||
void save(RefreshToken refreshToken);
|
void save(RefreshToken refreshToken);
|
||||||
|
|
||||||
|
boolean existsByEmail(String email);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import org.codiki.domain.picture.exception.PictureUploadException;
|
|||||||
import org.codiki.domain.publication.exception.PublicationEditionException;
|
import org.codiki.domain.publication.exception.PublicationEditionException;
|
||||||
import org.codiki.domain.publication.exception.PublicationNotFoundException;
|
import org.codiki.domain.publication.exception.PublicationNotFoundException;
|
||||||
import org.codiki.domain.publication.exception.PublicationUpdateForbiddenException;
|
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.HttpStatus;
|
||||||
import org.springframework.http.ProblemDetail;
|
import org.springframework.http.ProblemDetail;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
@@ -30,7 +32,9 @@ public class GlobalControllerExceptionHandler extends ResponseEntityExceptionHan
|
|||||||
CategoryNotFoundException.class,
|
CategoryNotFoundException.class,
|
||||||
LoginFailureException.class,
|
LoginFailureException.class,
|
||||||
PublicationEditionException.class,
|
PublicationEditionException.class,
|
||||||
PictureUploadException.class
|
PictureUploadException.class,
|
||||||
|
UserAlreadyExistsException.class,
|
||||||
|
UserCreationException.class
|
||||||
})
|
})
|
||||||
public ProblemDetail handleBadRequestExceptions(Exception exception) {
|
public ProblemDetail handleBadRequestExceptions(Exception exception) {
|
||||||
return buildProblemDetail(BAD_REQUEST, exception);
|
return buildProblemDetail(BAD_REQUEST, exception);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.codiki.exposition.user;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.springframework.http.HttpStatus.CREATED;
|
||||||
import org.codiki.application.security.annotation.AllowedToAdmins;
|
import org.codiki.application.security.annotation.AllowedToAdmins;
|
||||||
import org.codiki.application.security.annotation.AllowedToAnonymous;
|
import org.codiki.application.security.annotation.AllowedToAnonymous;
|
||||||
import org.codiki.application.user.UserUseCases;
|
import org.codiki.application.user.UserUseCases;
|
||||||
@@ -10,10 +11,13 @@ import org.codiki.domain.user.model.UserAuthenticationData;
|
|||||||
import org.codiki.exposition.user.model.LoginRequest;
|
import org.codiki.exposition.user.model.LoginRequest;
|
||||||
import org.codiki.exposition.user.model.LoginResponse;
|
import org.codiki.exposition.user.model.LoginResponse;
|
||||||
import org.codiki.exposition.user.model.RefreshTokenRequest;
|
import org.codiki.exposition.user.model.RefreshTokenRequest;
|
||||||
|
import org.codiki.exposition.user.model.SignInRequestDto;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@@ -43,4 +47,10 @@ public class UserController {
|
|||||||
UserAuthenticationData userAuthenticationData = userUseCases.authenticate(request.refreshTokenValue());
|
UserAuthenticationData userAuthenticationData = userUseCases.authenticate(request.refreshTokenValue());
|
||||||
return new LoginResponse(userAuthenticationData);
|
return new LoginResponse(userAuthenticationData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
@ResponseStatus(CREATED)
|
||||||
|
public void signIn(@RequestBody SignInRequestDto request) {
|
||||||
|
userUseCases.createUser(request.pseudo(), request.email(), request.password());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package org.codiki.exposition.user.model;
|
||||||
|
|
||||||
|
public record SignInRequestDto(
|
||||||
|
String pseudo,
|
||||||
|
String email,
|
||||||
|
String password
|
||||||
|
) {
|
||||||
|
}
|
||||||
@@ -51,6 +51,11 @@ public class UserJpaAdapter implements UserPort {
|
|||||||
return userJpaRepository.existsById(userId);
|
return userJpaRepository.existsById(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean existsByEmail(String email) {
|
||||||
|
return userJpaRepository.existsByEmail(email);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<RefreshToken> findRefreshTokenByUserId(UUID userId) {
|
public Optional<RefreshToken> findRefreshTokenByUserId(UUID userId) {
|
||||||
return refreshTokenJpaRepository.findByUserId(userId)
|
return refreshTokenJpaRepository.findByUserId(userId)
|
||||||
|
|||||||
@@ -27,10 +27,14 @@ import lombok.Setter;
|
|||||||
public class UserEntity {
|
public class UserEntity {
|
||||||
@Id
|
@Id
|
||||||
private UUID id;
|
private UUID id;
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String pseudo;
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String email;
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private String password;
|
private String password;
|
||||||
|
@Column
|
||||||
|
private UUID photoId;
|
||||||
@ElementCollection(targetClass = UserRole.class)
|
@ElementCollection(targetClass = UserRole.class)
|
||||||
@CollectionTable(
|
@CollectionTable(
|
||||||
name = "user_role",
|
name = "user_role",
|
||||||
@@ -41,14 +45,20 @@ public class UserEntity {
|
|||||||
|
|
||||||
public UserEntity(User user) {
|
public UserEntity(User user) {
|
||||||
id = user.id();
|
id = user.id();
|
||||||
|
pseudo = user.pseudo();
|
||||||
|
email = user.email();
|
||||||
password = user.password();
|
password = user.password();
|
||||||
|
photoId = user.photoId();
|
||||||
roles = user.roles();
|
roles = user.roles();
|
||||||
}
|
}
|
||||||
|
|
||||||
public User toUser() {
|
public User toUser() {
|
||||||
return new User(
|
return new User(
|
||||||
id,
|
id,
|
||||||
|
pseudo,
|
||||||
|
email,
|
||||||
password,
|
password,
|
||||||
|
photoId,
|
||||||
roles
|
roles
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,4 +17,6 @@ public interface UserJpaRepository extends JpaRepository<UserEntity, UUID> {
|
|||||||
|
|
||||||
@Query("SELECT u FROM UserEntity u JOIN FETCH u.roles")
|
@Query("SELECT u FROM UserEntity u JOIN FETCH u.roles")
|
||||||
List<UserEntity> findAll();
|
List<UserEntity> findAll();
|
||||||
|
|
||||||
|
boolean existsByEmail(String email);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
insert into "user" values
|
||||||
|
('5ad462b8-8f9e-4a26-bb86-c74fef5d11b6', 'Standard user', 'standard.user@codiki.org', '$2a$10$FVhrYRXw.Zw2V5jGUkvX/.1U.IdWlwd8J.Y/5pb5etAzyoBhJ3FHG', null),
|
||||||
|
('15a13dc7-029d-4eab-a63d-c1e96f90241d', 'Admin user', 'admin.user@codiki.org', '$2a$10$FVhrYRXw.Zw2V5jGUkvX/.1U.IdWlwd8J.Y/5pb5etAzyoBhJ3FHG', null);
|
||||||
|
|
||||||
|
insert into user_role values
|
||||||
|
('5ad462b8-8f9e-4a26-bb86-c74fef5d11b6', 0),
|
||||||
|
('15a13dc7-029d-4eab-a63d-c1e96f90241d', 0),
|
||||||
|
('15a13dc7-029d-4eab-a63d-c1e96f90241d', 1);
|
||||||
|
|
||||||
|
insert into category values
|
||||||
|
('172fa901-3f4b-4540-92f3-1c15820e8ec9', 'Main category', null),
|
||||||
|
('3f4b4540-a901-92f3-1c15-8ec9172f820e', 'Sub category', '172fa901-3f4b-4540-92f3-1c15820e8ec9');
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
CREATE TABLE IF NOT EXISTS "user" (
|
CREATE TABLE IF NOT EXISTS "user" (
|
||||||
id UUID NOT NULL,
|
id UUID NOT NULL,
|
||||||
name VARCHAR NOT NULL,
|
pseudo VARCHAR NOT NULL,
|
||||||
|
email VARCHAR NOT NULL,
|
||||||
password VARCHAR NOT NULL,
|
password VARCHAR NOT NULL,
|
||||||
|
photo_id UUID,
|
||||||
CONSTRAINT user_pk PRIMARY KEY (id)
|
CONSTRAINT user_pk PRIMARY KEY (id)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -39,6 +41,9 @@ CREATE TABLE IF NOT EXISTS picture (
|
|||||||
);
|
);
|
||||||
CREATE INDEX picture_publisher_id_idx ON picture (publisher_id);
|
CREATE INDEX picture_publisher_id_idx ON picture (publisher_id);
|
||||||
|
|
||||||
|
ALTER TABLE "user" ADD CONSTRAINT user_photo_id_fk FOREIGN KEY (photo_id) REFERENCES picture (id);
|
||||||
|
CREATE INDEX user_photo_id_idx ON "user" (photo_id);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS publication (
|
CREATE TABLE IF NOT EXISTS publication (
|
||||||
id UUID NOT NULL,
|
id UUID NOT NULL,
|
||||||
key VARCHAR(10) NOT NULL,
|
key VARCHAR(10) NOT NULL,
|
||||||
|
|||||||
Reference in New Issue
Block a user