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

View File

@@ -1,8 +1,11 @@
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.services.ConfigurationFileService;
import org.cerberus.services.SecurityService;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import java.security.Principal;
@@ -14,28 +17,48 @@ import static org.cerberus.core.constant.RoleSecurity.MAINTAINER;
@RestController
@RequestMapping("/api/applications/{applicationId}/configurationFile")
public class ConfigurationFileController {
private ConfigurationFileService configurationFileService;
private ConfigurationFileService service;
private SecurityService securityService;
ConfigurationFileController(ConfigurationFileService configurationFileService,
ConfigurationFileController(ConfigurationFileService service,
SecurityService securityService) {
this.configurationFileService = configurationFileService;
this.service = service;
this.securityService = securityService;
}
@GetMapping("/{id}")
@JsonView({View.ConfigurationFileDTO.class})
public ConfigurationFile findById(@PathVariable("applicationId") UUID applicationId,
@PathVariable("id") UUID configurationFileId,
Principal connectedUser) {
securityService.checkHasAnyRole(connectedUser, applicationId, ADMIN, MAINTAINER);
return configurationFileService.findByApplicationIdAndId(applicationId, configurationFileId);
return service.findByApplicationIdAndId(applicationId, configurationFileId);
}
@PostMapping
public void create(@PathVariable("applicationId") UUID applicationId,
@JsonView({View.ConfigurationFileDTO.class})
public ConfigurationFile create(@PathVariable("applicationId") UUID applicationId,
@RequestBody ConfigurationFile configurationFile,
Principal connectedUser) {
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
@RequestMapping("/api/users")
public class UserController {
private UserService userService;
private UserService service;
public UserController(UserService userService) {
this.userService = userService;
public UserController(UserService service) {
this.service = service;
}
@PostMapping("/login")
@ResponseStatus(NO_CONTENT)
public void login(@RequestBody User user) {
userService.authenticate(user);
service.authenticate(user);
}
@GetMapping("/disconnection")
@@ -40,6 +40,6 @@ public class UserController {
@PostMapping("/signup")
@ResponseStatus(NO_CONTENT)
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;
import com.fasterxml.jackson.annotation.JsonView;
import org.cerberus.entities.dto.View;
import org.hibernate.annotations.Proxy;
import javax.persistence.*;
@@ -14,12 +16,15 @@ import static javax.persistence.CascadeType.REMOVE;
@Proxy(lazy = false)
public class Application {
@Id
@JsonView({View.ApplicationDTO.class, View.ConfigurationFileDTO.class})
private UUID id;
@Column(nullable = false)
@Column(nullable = false, unique = true)
@JsonView({View.ApplicationDTO.class})
private String name;
@Column(nullable = false)
@Column(nullable = false, unique = true)
@JsonView({View.ApplicationDTO.class})
private String serviceName;
@OneToMany(mappedBy = "application", cascade = { REMOVE })

View File

@@ -1,5 +1,7 @@
package org.cerberus.entities.persistence;
import com.fasterxml.jackson.annotation.JsonView;
import org.cerberus.entities.dto.View;
import org.hibernate.annotations.Proxy;
import javax.persistence.*;
@@ -10,13 +12,16 @@ import java.util.UUID;
@Proxy(lazy = false)
public class ConfigurationFile {
@Id
@JsonView({View.ConfigurationFileDTO.class})
private UUID id;
@Column(nullable = false)
@JsonView({View.ConfigurationFileDTO.class})
private String path;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "application_id")
@JsonView({ConfigurationFile.class})
private Application application;
@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.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.UUID;
@Repository
public interface ApplicationRepository extends JpaRepository<Application, UUID> {
@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.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 java.util.UUID;
@Repository
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.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@Repository
public interface UserRepository extends JpaRepository<User, UUID> {
@Query("SELECT u FROM User u WHERE u.email = :email")
Optional<User> findByEmail(@Param("email") String email);

View File

@@ -13,28 +13,32 @@ import static org.cerberus.core.utils.StringUtils.concat;
@Service
public class ApplicationService extends AbstractService<Application> {
private ApplicationRepository applicationRepository;
private ApplicationRepository repository;
private ApplicationRoleService applicationRoleService;
private ApplicationValidator applicationValidator;
private ApplicationValidator validator;
ApplicationService(ApplicationRepository applicationRepository,
ApplicationService(ApplicationRepository repository,
ApplicationRoleService applicationRoleService,
ApplicationValidator applicationValidator) {
super(applicationRepository);
this.applicationRepository = applicationRepository;
ApplicationValidator validator) {
super(repository);
this.repository = repository;
this.applicationRoleService = applicationRoleService;
this.applicationValidator = applicationValidator;
this.validator = validator;
}
@Transactional
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."));
}
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
applicationRoleService.create(application, user, MAINTAINER);
@@ -42,9 +46,21 @@ public class ApplicationService extends AbstractService<Application> {
}
public Application update(Application application) {
applicationValidator.validate(application);
applicationValidator.sanitize(application);
applicationRepository.save(application);
return application;
validator.validate(application);
validator.sanitize(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
public class ConfigurationFileService extends AbstractService<ConfigurationFile> {
private ApplicationService applicationService;
private ConfigurationFileRepository configurationFileRepository;
private ConfigurationFileValidator configurationFileValidator;
private ConfigurationFileRepository repository;
private ConfigurationFileValidator validator;
ConfigurationFileService(ApplicationService applicationService,
ConfigurationFileRepository configurationFileRepository,
ConfigurationFileValidator configurationFileValidator) {
super(configurationFileRepository);
ConfigurationFileRepository repository,
ConfigurationFileValidator validator) {
super(repository);
this.applicationService = applicationService;
this.configurationFileRepository = configurationFileRepository;
this.configurationFileValidator = configurationFileValidator;
this.repository = repository;
this.validator = validator;
}
public ConfigurationFile findByApplicationIdAndId(UUID applicationId, UUID configurationFileId) {
@@ -31,15 +31,36 @@ public class ConfigurationFileService extends AbstractService<ConfigurationFile>
return findByIdOrElseThrow(configurationFileId);
}
public void create(UUID applicationId, ConfigurationFile configurationFile) {
if(applicationId == null || StringUtils.isNull(applicationId.toString())) {
throw new BadRequestException("Application id is required.");
}
configurationFileValidator.validate(configurationFile);
public ConfigurationFile create(UUID applicationId, ConfigurationFile configurationFile) {
return save(applicationId, configurationFile, false);
}
configurationFile.setApplication(applicationService.findById(applicationId)
.orElseThrow(() -> new BadRequestException("The application doesn't exist."))
);
configurationFileRepository.save(configurationFile);
public ConfigurationFile update(UUID applicationId, ConfigurationFile configurationFile) {
return save(applicationId, configurationFile, true);
}
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 SignUpMapper signUpMapper;
private SignUpValidator signUpValidator;
private UserRepository userRepository;
private UserRepository repository;
public UserService(CustomAuthenticationProvider authenticationProvider,
SignUpMapper signUpMapper,
SignUpValidator signUpValidator,
UserRepository userRepository) {
UserRepository repository) {
this.authenticationProvider = authenticationProvider;
this.signUpMapper = signUpMapper;
this.signUpValidator = signUpValidator;
this.userRepository = userRepository;
this.repository = repository;
}
public void authenticate(User user) {
@@ -48,7 +48,7 @@ public class UserService {
}
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)) {
throw new BadRequestException("Credentials are incorrect.");
@@ -73,24 +73,24 @@ public class UserService {
}
public List<ApplicationRole> getApplicationRolesByEmail(String email) {
return userRepository.getApplicationRolesByEmail(email);
return repository.getApplicationRolesByEmail(email);
}
public void signUp(SignUpDTO inputData) {
signUpValidator.validate(inputData);
if(userRepository.isEmailAlreadyExists(inputData.getEmail())) {
if(repository.isEmailAlreadyExists(inputData.getEmail())) {
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) {
return userRepository.isAdmin(user.getId());
return repository.isAdmin(user.getId());
}
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 (
id uuid DEFAULT uuid_generate_v4(),
name VARCHAR NOT NULL UNIQUE,
service_name VARCHAR NOT NULL,
service_name VARCHAR NOT NULL UNIQUE,
CONSTRAINT application_pk PRIMARY KEY (id)
);
@@ -20,7 +20,8 @@ CREATE TABLE configuration_file (
path VARCHAR NOT NULL,
application_id uuid NOT NULL,
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);