Add JsonView, update and delete routes for confFile entity and rename beans.

This commit is contained in:
2019-09-03 22:41:42 +02:00
parent 083b5116e6
commit e34ff82084
13 changed files with 162 additions and 63 deletions

View File

@@ -1,5 +1,7 @@
package org.cerberus.controllers; package org.cerberus.controllers;
import com.fasterxml.jackson.annotation.JsonView;
import org.cerberus.entities.dto.View;
import org.cerberus.entities.persistence.Application; import org.cerberus.entities.persistence.Application;
import org.cerberus.entities.persistence.User; import org.cerberus.entities.persistence.User;
import org.cerberus.services.ApplicationService; import org.cerberus.services.ApplicationService;
@@ -16,36 +18,39 @@ import static org.cerberus.core.constant.RoleSecurity.MAINTAINER;
@RestController @RestController
@RequestMapping("/api/applications") @RequestMapping("/api/applications")
public class ApplicationController { public class ApplicationController {
private ApplicationService applicationService; private ApplicationService service;
private SecurityService securityService; private SecurityService securityService;
public ApplicationController(ApplicationService applicationService, ApplicationController(ApplicationService service,
SecurityService securityService) { SecurityService securityService) {
this.applicationService = applicationService; this.service = service;
this.securityService = securityService; this.securityService = securityService;
} }
@GetMapping("/{id}") @GetMapping("/{id}")
@JsonView({View.ApplicationDTO.class})
public Application findById(@PathVariable("id") UUID id) { public Application findById(@PathVariable("id") UUID id) {
return applicationService.findByIdOrElseThrow(id); return service.findByIdOrElseThrow(id);
} }
@PostMapping @PostMapping
@JsonView({View.ApplicationDTO.class})
public Application create(@RequestBody Application application, Principal connectedUser) { public Application create(@RequestBody Application application, Principal connectedUser) {
User user = securityService.getAdminUser(connectedUser); User user = securityService.getAdminUser(connectedUser);
return applicationService.create(application, user); return service.create(application, user);
} }
@PutMapping @PutMapping
@JsonView({View.ApplicationDTO.class})
public Application update(@RequestBody Application application, Principal connectedUser) { public Application update(@RequestBody Application application, Principal connectedUser) {
securityService.checkHasAnyRole(connectedUser, application, ADMIN, MAINTAINER); securityService.checkHasAnyRole(connectedUser, application, ADMIN, MAINTAINER);
return applicationService.update(application); return service.update(application);
} }
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT) @ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(@PathVariable("id") UUID id, Principal connectedUser) { public void delete(@PathVariable("id") UUID id, Principal connectedUser) {
securityService.checkHasAnyRole(connectedUser, id, ADMIN, MAINTAINER); securityService.checkHasAnyRole(connectedUser, id, ADMIN, MAINTAINER);
applicationService.delete(id); service.delete(id);
} }
} }

View File

@@ -1,8 +1,11 @@
package org.cerberus.controllers; package org.cerberus.controllers;
import com.fasterxml.jackson.annotation.JsonView;
import org.cerberus.entities.dto.View;
import org.cerberus.entities.persistence.ConfigurationFile; import org.cerberus.entities.persistence.ConfigurationFile;
import org.cerberus.services.ConfigurationFileService; import org.cerberus.services.ConfigurationFileService;
import org.cerberus.services.SecurityService; import org.cerberus.services.SecurityService;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.security.Principal; import java.security.Principal;
@@ -14,28 +17,48 @@ import static org.cerberus.core.constant.RoleSecurity.MAINTAINER;
@RestController @RestController
@RequestMapping("/api/applications/{applicationId}/configurationFile") @RequestMapping("/api/applications/{applicationId}/configurationFile")
public class ConfigurationFileController { public class ConfigurationFileController {
private ConfigurationFileService configurationFileService; private ConfigurationFileService service;
private SecurityService securityService; private SecurityService securityService;
ConfigurationFileController(ConfigurationFileService configurationFileService, ConfigurationFileController(ConfigurationFileService service,
SecurityService securityService) { SecurityService securityService) {
this.configurationFileService = configurationFileService; this.service = service;
this.securityService = securityService; this.securityService = securityService;
} }
@GetMapping("/{id}") @GetMapping("/{id}")
@JsonView({View.ConfigurationFileDTO.class})
public ConfigurationFile findById(@PathVariable("applicationId") UUID applicationId, public ConfigurationFile findById(@PathVariable("applicationId") UUID applicationId,
@PathVariable("id") UUID configurationFileId, @PathVariable("id") UUID configurationFileId,
Principal connectedUser) { Principal connectedUser) {
securityService.checkHasAnyRole(connectedUser, applicationId, ADMIN, MAINTAINER); securityService.checkHasAnyRole(connectedUser, applicationId, ADMIN, MAINTAINER);
return configurationFileService.findByApplicationIdAndId(applicationId, configurationFileId); return service.findByApplicationIdAndId(applicationId, configurationFileId);
} }
@PostMapping @PostMapping
public void create(@PathVariable("applicationId") UUID applicationId, @JsonView({View.ConfigurationFileDTO.class})
public ConfigurationFile create(@PathVariable("applicationId") UUID applicationId,
@RequestBody ConfigurationFile configurationFile, @RequestBody ConfigurationFile configurationFile,
Principal connectedUser) { Principal connectedUser) {
securityService.checkHasAnyRole(connectedUser, applicationId, ADMIN, MAINTAINER); securityService.checkHasAnyRole(connectedUser, applicationId, ADMIN, MAINTAINER);
configurationFileService.create(applicationId, configurationFile); return service.create(applicationId, configurationFile);
}
@PutMapping
@JsonView({View.ConfigurationFileDTO.class})
public ConfigurationFile update(@PathVariable("applicationId") UUID applicationId,
@RequestBody ConfigurationFile configurationFile,
Principal connectedUser) {
securityService.checkHasAnyRole(connectedUser, applicationId, ADMIN, MAINTAINER);
return service.update(applicationId, configurationFile);
}
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(@PathVariable("applicationId") UUID applicationId,
@PathVariable("id") UUID configurationFileId,
Principal connectedUser) {
securityService.checkHasAnyRole(connectedUser, applicationId, ADMIN, MAINTAINER);
service.delete(applicationId, configurationFileId);
} }
} }

View File

@@ -16,16 +16,16 @@ import static org.springframework.http.HttpStatus.NO_CONTENT;
@RestController @RestController
@RequestMapping("/api/users") @RequestMapping("/api/users")
public class UserController { public class UserController {
private UserService userService; private UserService service;
public UserController(UserService userService) { public UserController(UserService service) {
this.userService = userService; this.service = service;
} }
@PostMapping("/login") @PostMapping("/login")
@ResponseStatus(NO_CONTENT) @ResponseStatus(NO_CONTENT)
public void login(@RequestBody User user) { public void login(@RequestBody User user) {
userService.authenticate(user); service.authenticate(user);
} }
@GetMapping("/disconnection") @GetMapping("/disconnection")
@@ -40,6 +40,6 @@ public class UserController {
@PostMapping("/signup") @PostMapping("/signup")
@ResponseStatus(NO_CONTENT) @ResponseStatus(NO_CONTENT)
public void signUp(@RequestBody SignUpDTO inputData) { public void signUp(@RequestBody SignUpDTO inputData) {
userService.signUp(inputData); service.signUp(inputData);
} }
} }

View File

@@ -0,0 +1,7 @@
package org.cerberus.entities.dto;
public final class View {
private View() {}
public interface ApplicationDTO {}
public interface ConfigurationFileDTO {}
}

View File

@@ -1,5 +1,7 @@
package org.cerberus.entities.persistence; package org.cerberus.entities.persistence;
import com.fasterxml.jackson.annotation.JsonView;
import org.cerberus.entities.dto.View;
import org.hibernate.annotations.Proxy; import org.hibernate.annotations.Proxy;
import javax.persistence.*; import javax.persistence.*;
@@ -14,12 +16,15 @@ import static javax.persistence.CascadeType.REMOVE;
@Proxy(lazy = false) @Proxy(lazy = false)
public class Application { public class Application {
@Id @Id
@JsonView({View.ApplicationDTO.class, View.ConfigurationFileDTO.class})
private UUID id; private UUID id;
@Column(nullable = false) @Column(nullable = false, unique = true)
@JsonView({View.ApplicationDTO.class})
private String name; private String name;
@Column(nullable = false) @Column(nullable = false, unique = true)
@JsonView({View.ApplicationDTO.class})
private String serviceName; private String serviceName;
@OneToMany(mappedBy = "application", cascade = { REMOVE }) @OneToMany(mappedBy = "application", cascade = { REMOVE })

View File

@@ -1,5 +1,7 @@
package org.cerberus.entities.persistence; package org.cerberus.entities.persistence;
import com.fasterxml.jackson.annotation.JsonView;
import org.cerberus.entities.dto.View;
import org.hibernate.annotations.Proxy; import org.hibernate.annotations.Proxy;
import javax.persistence.*; import javax.persistence.*;
@@ -10,13 +12,16 @@ import java.util.UUID;
@Proxy(lazy = false) @Proxy(lazy = false)
public class ConfigurationFile { public class ConfigurationFile {
@Id @Id
@JsonView({View.ConfigurationFileDTO.class})
private UUID id; private UUID id;
@Column(nullable = false) @Column(nullable = false)
@JsonView({View.ConfigurationFileDTO.class})
private String path; private String path;
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "application_id") @JoinColumn(name = "application_id")
@JsonView({ConfigurationFile.class})
private Application application; private Application application;
@PrePersist @PrePersist

View File

@@ -4,10 +4,15 @@ import org.cerberus.entities.persistence.Application;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.UUID; import java.util.UUID;
@Repository
public interface ApplicationRepository extends JpaRepository<Application, UUID> { public interface ApplicationRepository extends JpaRepository<Application, UUID> {
@Query(value = "SELECT EXISTS(SELECT id FROM application WHERE name = :name)", nativeQuery = true) @Query(value = "SELECT EXISTS(SELECT id FROM application WHERE name = :name)", nativeQuery = true)
Boolean existsByName(@Param("name") String name); boolean existsByName(@Param("name") String name);
@Query(value = "SELECT EXISTS(SELECT id FROM application WHERE service_name = :serviceName)", nativeQuery = true)
boolean existsByServiceName(@Param("serviceName") String serviceName);
} }

View File

@@ -2,11 +2,20 @@ package org.cerberus.repositories;
import org.cerberus.entities.persistence.ConfigurationFile; import org.cerberus.entities.persistence.ConfigurationFile;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.UUID; import java.util.UUID;
@Repository @Repository
public interface ConfigurationFileRepository extends JpaRepository<ConfigurationFile, UUID> { public interface ConfigurationFileRepository extends JpaRepository<ConfigurationFile, UUID> {
@Query(value = "SELECT EXISTS(SELECT id FROM configuration_file WHERE path = :path AND application_id = :applicationId)", nativeQuery = true)
boolean existsByPathAndApplicationId(@Param("path") String path,
@Param("applicationId") UUID applicationId);
@Query(value = "SELECT EXISTS(SELECT id FROM configuration_file WHERE id = :configurationFileId " +
"AND application_id = :applicationId)", nativeQuery = true)
boolean doesBelongToApplication(@Param("configurationFileId") UUID configurationFileId,
@Param("applicationId") UUID applicationId);
} }

View File

@@ -5,11 +5,13 @@ import org.cerberus.entities.persistence.User;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
@Repository
public interface UserRepository extends JpaRepository<User, UUID> { public interface UserRepository extends JpaRepository<User, UUID> {
@Query("SELECT u FROM User u WHERE u.email = :email") @Query("SELECT u FROM User u WHERE u.email = :email")
Optional<User> findByEmail(@Param("email") String email); Optional<User> findByEmail(@Param("email") String email);

View File

@@ -13,28 +13,32 @@ import static org.cerberus.core.utils.StringUtils.concat;
@Service @Service
public class ApplicationService extends AbstractService<Application> { public class ApplicationService extends AbstractService<Application> {
private ApplicationRepository applicationRepository; private ApplicationRepository repository;
private ApplicationRoleService applicationRoleService; private ApplicationRoleService applicationRoleService;
private ApplicationValidator applicationValidator; private ApplicationValidator validator;
ApplicationService(ApplicationRepository applicationRepository, ApplicationService(ApplicationRepository repository,
ApplicationRoleService applicationRoleService, ApplicationRoleService applicationRoleService,
ApplicationValidator applicationValidator) { ApplicationValidator validator) {
super(applicationRepository); super(repository);
this.applicationRepository = applicationRepository; this.repository = repository;
this.applicationRoleService = applicationRoleService; this.applicationRoleService = applicationRoleService;
this.applicationValidator = applicationValidator; this.validator = validator;
} }
@Transactional @Transactional
public Application create(Application application, User user) { public Application create(Application application, User user) {
applicationValidator.validate(application); validator.validate(application);
if(applicationRepository.existsByName(application.getName())) { if(repository.existsByName(application.getName())) {
throw new BadRequestException(concat("The application ", application.getName(), " already exists.")); throw new BadRequestException(concat("The application ", application.getName(), " already exists."));
} }
if(repository.existsByServiceName(application.getServiceName())) {
throw new BadRequestException(concat("The service name ", application.getServiceName(),
" already exists for another application."));
}
applicationRepository.save(application); repository.save(application);
// Application creator is by default a maintainer // Application creator is by default a maintainer
applicationRoleService.create(application, user, MAINTAINER); applicationRoleService.create(application, user, MAINTAINER);
@@ -42,9 +46,21 @@ public class ApplicationService extends AbstractService<Application> {
} }
public Application update(Application application) { public Application update(Application application) {
applicationValidator.validate(application); validator.validate(application);
applicationValidator.sanitize(application); validator.sanitize(application);
applicationRepository.save(application);
return application; Application appFromDb = findByIdOrElseThrow(application.getId());
// If the app name changed
if(!appFromDb.getName().equals(application.getName()) && repository.existsByName(application.getName())) {
throw new BadRequestException(concat("The application ", application.getName(), " already exists."));
}
// If the app service name changed
if(!appFromDb.getServiceName().equals(application.getServiceName())
&& repository.existsByServiceName(application.getServiceName())) {
throw new BadRequestException(concat("The service name ", application.getServiceName(),
" already exists for another application."));
}
return repository.save(application);
} }
} }

View File

@@ -12,16 +12,16 @@ import java.util.UUID;
@Service @Service
public class ConfigurationFileService extends AbstractService<ConfigurationFile> { public class ConfigurationFileService extends AbstractService<ConfigurationFile> {
private ApplicationService applicationService; private ApplicationService applicationService;
private ConfigurationFileRepository configurationFileRepository; private ConfigurationFileRepository repository;
private ConfigurationFileValidator configurationFileValidator; private ConfigurationFileValidator validator;
ConfigurationFileService(ApplicationService applicationService, ConfigurationFileService(ApplicationService applicationService,
ConfigurationFileRepository configurationFileRepository, ConfigurationFileRepository repository,
ConfigurationFileValidator configurationFileValidator) { ConfigurationFileValidator validator) {
super(configurationFileRepository); super(repository);
this.applicationService = applicationService; this.applicationService = applicationService;
this.configurationFileRepository = configurationFileRepository; this.repository = repository;
this.configurationFileValidator = configurationFileValidator; this.validator = validator;
} }
public ConfigurationFile findByApplicationIdAndId(UUID applicationId, UUID configurationFileId) { public ConfigurationFile findByApplicationIdAndId(UUID applicationId, UUID configurationFileId) {
@@ -31,15 +31,36 @@ public class ConfigurationFileService extends AbstractService<ConfigurationFile>
return findByIdOrElseThrow(configurationFileId); return findByIdOrElseThrow(configurationFileId);
} }
public void create(UUID applicationId, ConfigurationFile configurationFile) { public ConfigurationFile create(UUID applicationId, ConfigurationFile configurationFile) {
if(applicationId == null || StringUtils.isNull(applicationId.toString())) { return save(applicationId, configurationFile, false);
throw new BadRequestException("Application id is required.");
} }
configurationFileValidator.validate(configurationFile);
configurationFile.setApplication(applicationService.findById(applicationId) public ConfigurationFile update(UUID applicationId, ConfigurationFile configurationFile) {
.orElseThrow(() -> new BadRequestException("The application doesn't exist.")) return save(applicationId, configurationFile, true);
); }
configurationFileRepository.save(configurationFile);
private ConfigurationFile save(UUID applicationId, ConfigurationFile configurationFile, boolean isUpdate) {
if(applicationId == null || StringUtils.isNull(applicationId.toString()) ||
(isUpdate && !repository.doesBelongToApplication(configurationFile.getId(), applicationId))) {
throwNotFoundException();
}
validator.validate(configurationFile);
if(repository.existsByPathAndApplicationId(configurationFile.getPath(), applicationId)) {
throw new BadRequestException("Configuration file already exists.");
}
configurationFile.setApplication(applicationService.findByIdOrElseThrow(applicationId));
return repository.save(configurationFile);
}
public void delete(UUID applicationId, UUID configurationFileId) {
if(applicationId == null || StringUtils.isNull(applicationId.toString())
|| configurationFileId == null || StringUtils.isNull(configurationFileId.toString())
|| !repository.doesBelongToApplication(configurationFileId, applicationId)) {
throwNotFoundException();
}
repository.deleteById(configurationFileId);
} }
} }

View File

@@ -25,16 +25,16 @@ public class UserService {
private CustomAuthenticationProvider authenticationProvider; private CustomAuthenticationProvider authenticationProvider;
private SignUpMapper signUpMapper; private SignUpMapper signUpMapper;
private SignUpValidator signUpValidator; private SignUpValidator signUpValidator;
private UserRepository userRepository; private UserRepository repository;
public UserService(CustomAuthenticationProvider authenticationProvider, public UserService(CustomAuthenticationProvider authenticationProvider,
SignUpMapper signUpMapper, SignUpMapper signUpMapper,
SignUpValidator signUpValidator, SignUpValidator signUpValidator,
UserRepository userRepository) { UserRepository repository) {
this.authenticationProvider = authenticationProvider; this.authenticationProvider = authenticationProvider;
this.signUpMapper = signUpMapper; this.signUpMapper = signUpMapper;
this.signUpValidator = signUpValidator; this.signUpValidator = signUpValidator;
this.userRepository = userRepository; this.repository = repository;
} }
public void authenticate(User user) { public void authenticate(User user) {
@@ -48,7 +48,7 @@ public class UserService {
} }
User checkCredentials(String email, String password) { User checkCredentials(String email, String password) {
Optional<User> optUser = userRepository.findByEmail(email); Optional<User> optUser = repository.findByEmail(email);
if(optUser.isEmpty() || !optUser.get().getPassword().equals(password)) { if(optUser.isEmpty() || !optUser.get().getPassword().equals(password)) {
throw new BadRequestException("Credentials are incorrect."); throw new BadRequestException("Credentials are incorrect.");
@@ -73,24 +73,24 @@ public class UserService {
} }
public List<ApplicationRole> getApplicationRolesByEmail(String email) { public List<ApplicationRole> getApplicationRolesByEmail(String email) {
return userRepository.getApplicationRolesByEmail(email); return repository.getApplicationRolesByEmail(email);
} }
public void signUp(SignUpDTO inputData) { public void signUp(SignUpDTO inputData) {
signUpValidator.validate(inputData); signUpValidator.validate(inputData);
if(userRepository.isEmailAlreadyExists(inputData.getEmail())) { if(repository.isEmailAlreadyExists(inputData.getEmail())) {
throw new BadRequestException("Email is already assigned to another user."); throw new BadRequestException("Email is already assigned to another user.");
} }
userRepository.save(signUpMapper.toUser(inputData)); repository.save(signUpMapper.toUser(inputData));
} }
public boolean isAdmin(User user) { public boolean isAdmin(User user) {
return userRepository.isAdmin(user.getId()); return repository.isAdmin(user.getId());
} }
public Optional<User> findByEmail(String email) { public Optional<User> findByEmail(String email) {
return userRepository.findByEmail(email); return repository.findByEmail(email);
} }
} }

View File

@@ -11,7 +11,7 @@ CREATE TABLE "user" (
CREATE TABLE application ( CREATE TABLE application (
id uuid DEFAULT uuid_generate_v4(), id uuid DEFAULT uuid_generate_v4(),
name VARCHAR NOT NULL UNIQUE, name VARCHAR NOT NULL UNIQUE,
service_name VARCHAR NOT NULL, service_name VARCHAR NOT NULL UNIQUE,
CONSTRAINT application_pk PRIMARY KEY (id) CONSTRAINT application_pk PRIMARY KEY (id)
); );
@@ -20,7 +20,8 @@ CREATE TABLE configuration_file (
path VARCHAR NOT NULL, path VARCHAR NOT NULL,
application_id uuid NOT NULL, application_id uuid NOT NULL,
CONSTRAINT configuration_file_pk PRIMARY KEY (id), CONSTRAINT configuration_file_pk PRIMARY KEY (id),
CONSTRAINT configuration_file_application_id_fk FOREIGN KEY (application_id) REFERENCES application (id) CONSTRAINT configuration_file_application_id_fk FOREIGN KEY (application_id) REFERENCES application (id),
CONSTRAINT configuration_file_path_application_id_unique UNIQUE (path, application_id)
); );
CREATE INDEX configuration_file_application_id_idx ON configuration_file(application_id); CREATE INDEX configuration_file_application_id_idx ON configuration_file(application_id);