diff --git a/core/src/main/java/cz/muni/fi/pa165/core/DataInitializer.java b/core/src/main/java/cz/muni/fi/pa165/core/DataInitializer.java index 7a0bdc5ec0c8bae4609372dab7cdc415d7bbb5a7..160775cf406e00d5e3961f13abe469d37a946674 100644 --- a/core/src/main/java/cz/muni/fi/pa165/core/DataInitializer.java +++ b/core/src/main/java/cz/muni/fi/pa165/core/DataInitializer.java @@ -65,7 +65,7 @@ public class DataInitializer implements ApplicationRunner { Device device = Device.builder().name("device02").build(); deviceService.create(device); - SmartMeter smartMeter = SmartMeter.builder().device(device).build(); + SmartMeter smartMeter = SmartMeter.builder().name("smart").device(device).build(); smartMeterService.create(smartMeter); } @@ -90,7 +90,7 @@ public class DataInitializer implements ApplicationRunner { Device device = Device.builder().name("device03").build(); deviceService.create(device); - SmartMeter smartMeter = SmartMeter.builder().device(device).build(); + SmartMeter smartMeter = SmartMeter.builder().name("smartMeter01").device(device).build(); smartMeterService.create(smartMeter); List<SmartMeter> smartMeterList = new ArrayList<SmartMeter>(); @@ -126,7 +126,7 @@ public class DataInitializer implements ApplicationRunner { .email("test@email.com") .firstName("John") .lastName("Doe") - .username("johnD") + .username("johnDCopy") .password("password") .userType(UserType.ADMIN) .build(); diff --git a/core/src/main/java/cz/muni/fi/pa165/core/common/DomainFacade.java b/core/src/main/java/cz/muni/fi/pa165/core/common/DomainFacade.java index 408ecd5f9add5267e0b2cf87cc737547ae874468..06830e0770daf4cbc0db6ebf20a64d7ef9b0c48b 100644 --- a/core/src/main/java/cz/muni/fi/pa165/core/common/DomainFacade.java +++ b/core/src/main/java/cz/muni/fi/pa165/core/common/DomainFacade.java @@ -2,7 +2,10 @@ package cz.muni.fi.pa165.core.common; import cz.muni.fi.pa165.model.dto.common.DomainObjectDto; import cz.muni.fi.pa165.model.dto.common.Result; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.web.server.ResponseStatusException; import java.util.List; @@ -88,7 +91,11 @@ public abstract class DomainFacade<E extends DomainObject, * @return the DTO representation of the created entity */ public T create(C createDto) { - return mapper.toDto(service.create(mapper.fromCreateDto(createDto))); + try { + return mapper.toDto(service.create(mapper.fromCreateDto(createDto))); + } catch (DataIntegrityViolationException e) { + throw new ResponseStatusException(HttpStatus.CONFLICT, "Entity with the same name already exists", e); + } } /** diff --git a/core/src/main/java/cz/muni/fi/pa165/core/company/Company.java b/core/src/main/java/cz/muni/fi/pa165/core/company/Company.java index 202eab6b38919b10ad27dd7da233a9b9c3052762..a05bef743ba4f2f576cfb7c2ecef3d2579a35b0e 100644 --- a/core/src/main/java/cz/muni/fi/pa165/core/company/Company.java +++ b/core/src/main/java/cz/muni/fi/pa165/core/company/Company.java @@ -2,9 +2,7 @@ package cz.muni.fi.pa165.core.company; import cz.muni.fi.pa165.core.common.DomainObject; import cz.muni.fi.pa165.core.user.roles.CompanyRole; -import jakarta.persistence.Entity; -import jakarta.persistence.OneToMany; -import jakarta.persistence.Table; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -21,7 +19,8 @@ import java.util.List; @AllArgsConstructor @Table(name = "domain_company") public class Company extends DomainObject { - private String name; - @OneToMany(mappedBy = "company") - private List<CompanyRole> employeeList; + @Column(unique = true, nullable = false) + private String name; + @OneToMany(mappedBy = "company") + private List<CompanyRole> employeeList; } diff --git a/core/src/main/java/cz/muni/fi/pa165/core/company/CompanyController.java b/core/src/main/java/cz/muni/fi/pa165/core/company/CompanyController.java index e134fa069e534f57ce44891c1db279145e4b0ab1..db8d142b314c62111801bb921df475f9f41f5a3e 100644 --- a/core/src/main/java/cz/muni/fi/pa165/core/company/CompanyController.java +++ b/core/src/main/java/cz/muni/fi/pa165/core/company/CompanyController.java @@ -13,7 +13,9 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -85,8 +87,10 @@ public class CompanyController { @ApiResponse(responseCode = "201", description = "The newly created company", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = CompanyDto.class))) - public CompanyDto create(@RequestBody @Valid CompanyCreateDto companyCreateDto) { - return companyFacade.create(companyCreateDto); + @ApiResponse(responseCode = "400", description = "Invalid input", content = @Content) + @ApiResponse(responseCode = "409", description = "Company with the same name already exists", content = @Content) + public ResponseEntity<CompanyDto> create(@RequestBody @Valid CompanyCreateDto companyCreateDto) { + return ResponseEntity.status(HttpStatus.CREATED).body(companyFacade.create(companyCreateDto)); } @PutMapping("/{id}") diff --git a/core/src/main/java/cz/muni/fi/pa165/core/device/Device.java b/core/src/main/java/cz/muni/fi/pa165/core/device/Device.java index f10e88d2c36700870dafde60616587c77bb34b5f..ad73d8472b76d2bd66fde0f8b78f6a4120923071 100644 --- a/core/src/main/java/cz/muni/fi/pa165/core/device/Device.java +++ b/core/src/main/java/cz/muni/fi/pa165/core/device/Device.java @@ -3,10 +3,7 @@ package cz.muni.fi.pa165.core.device; import cz.muni.fi.pa165.core.common.DomainObject; import cz.muni.fi.pa165.core.manufacturer.Manufacturer; import cz.muni.fi.pa165.core.smartmeter.SmartMeter; -import jakarta.persistence.Entity; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.OneToMany; -import jakarta.persistence.Table; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -24,6 +21,7 @@ import java.util.List; @Table(name = "domain_device") public class Device extends DomainObject { + @Column(unique = true, nullable = false) private String name; @OneToMany(mappedBy = "device") diff --git a/core/src/main/java/cz/muni/fi/pa165/core/manufacturer/Manufacturer.java b/core/src/main/java/cz/muni/fi/pa165/core/manufacturer/Manufacturer.java index 767dd0470305837000e0e8875386efc9015eb63a..30097056b3b1af81466870274e39824b35ad073f 100644 --- a/core/src/main/java/cz/muni/fi/pa165/core/manufacturer/Manufacturer.java +++ b/core/src/main/java/cz/muni/fi/pa165/core/manufacturer/Manufacturer.java @@ -2,6 +2,7 @@ package cz.muni.fi.pa165.core.manufacturer; import cz.muni.fi.pa165.core.common.DomainObject; import cz.muni.fi.pa165.core.device.Device; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; @@ -22,6 +23,7 @@ import java.util.List; @Table(name = "domain_manufacturer") public class Manufacturer extends DomainObject { + @Column(unique = true, nullable = false) private String name; @OneToMany(mappedBy = "manufacturer") diff --git a/core/src/main/java/cz/muni/fi/pa165/core/smartmeter/SmartMeter.java b/core/src/main/java/cz/muni/fi/pa165/core/smartmeter/SmartMeter.java index f99ffbc7e7acab094f2472a39957f63953107de9..fb352278c20c864defb859d6775a7c894780002a 100644 --- a/core/src/main/java/cz/muni/fi/pa165/core/smartmeter/SmartMeter.java +++ b/core/src/main/java/cz/muni/fi/pa165/core/smartmeter/SmartMeter.java @@ -4,10 +4,7 @@ import cz.muni.fi.pa165.core.common.DomainObject; import cz.muni.fi.pa165.core.device.Device; import cz.muni.fi.pa165.core.house.House; import cz.muni.fi.pa165.core.metrics.Metrics; -import jakarta.persistence.Entity; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.OneToMany; -import jakarta.persistence.Table; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -25,6 +22,7 @@ import java.util.List; @Table(name = "domain_smartMeter") public class SmartMeter extends DomainObject { + @Column(unique = true, nullable = false) private String name; @ManyToOne diff --git a/core/src/main/java/cz/muni/fi/pa165/core/user/User.java b/core/src/main/java/cz/muni/fi/pa165/core/user/User.java index fd12eee3a8e6b55028763cac921df4b60801b07d..ac0a4bcb96f6c8a18e38e1119031d202c88da333 100644 --- a/core/src/main/java/cz/muni/fi/pa165/core/user/User.java +++ b/core/src/main/java/cz/muni/fi/pa165/core/user/User.java @@ -3,11 +3,7 @@ package cz.muni.fi.pa165.core.user; import cz.muni.fi.pa165.core.common.DomainObject; import cz.muni.fi.pa165.core.house.House; import cz.muni.fi.pa165.core.user.roles.Role; -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.OneToMany; -import jakarta.persistence.Table; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -25,6 +21,7 @@ import java.util.List; @Table(name = "domain_user") public class User extends DomainObject { + @Column(unique = true, nullable = false) private String username; @Enumerated(EnumType.STRING) diff --git a/core/src/main/java/cz/muni/fi/pa165/core/user/UserController.java b/core/src/main/java/cz/muni/fi/pa165/core/user/UserController.java index ad867dbbbd7939a47d10167f63ef19758bab1e1a..1837b499d617e1bf8c6aec8868cb69f303f631dc 100644 --- a/core/src/main/java/cz/muni/fi/pa165/core/user/UserController.java +++ b/core/src/main/java/cz/muni/fi/pa165/core/user/UserController.java @@ -22,6 +22,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; import java.util.List; @@ -83,8 +84,15 @@ public class UserController { @PostMapping public ResponseEntity<UserDto> create( @Parameter(description = "User to be created") @RequestBody UserCreateDto userCreateDto) { - return ResponseEntity.status(HttpStatus.CREATED).body(userFacade.create(userCreateDto)); - + try { + ResponseEntity<UserDto> response = ResponseEntity.status(HttpStatus.CREATED).body(userFacade.create(userCreateDto)); + return response; + } catch (ResponseStatusException ex) { + if (ex.getStatusCode() == HttpStatus.CONFLICT) { + return ResponseEntity.status(HttpStatus.CONFLICT).build(); + } + throw new IllegalArgumentException("Possible error"); + } } @Operation( @@ -167,7 +175,6 @@ public class UserController { return userFacade.findAll(); } - @Operation(summary = "Log in a user", tags = {"user"}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successful login"), @@ -207,9 +214,8 @@ public class UserController { @Valid @RequestBody ChangePasswordDto request) { return userFacade.changePassword(request, userId); // userId from JWT token. } - /* - TODO: get user with roles - */ + // TODO: get user with roles + } diff --git a/core/src/test/java/cz/muni/fi/pa165/core/company/CompanyControllerTest.java b/core/src/test/java/cz/muni/fi/pa165/core/company/CompanyControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..87535c321b2d234f1217eaf4e9e1d4b5c2bcd6e7 --- /dev/null +++ b/core/src/test/java/cz/muni/fi/pa165/core/company/CompanyControllerTest.java @@ -0,0 +1,61 @@ +package cz.muni.fi.pa165.core.company; + +import com.fasterxml.jackson.databind.ObjectMapper; +import cz.muni.fi.pa165.core.user.UserController; +import cz.muni.fi.pa165.model.dto.company.CompanyCreateDto; +import cz.muni.fi.pa165.model.dto.company.CompanyDto; +import cz.muni.fi.pa165.model.dto.user.UserCreateDto; +import cz.muni.fi.pa165.model.dto.user.UserDto; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.web.servlet.MockMvc; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Integration tests for the {@link CompanyController} class. + */ +@SpringBootTest +@AutoConfigureMockMvc +public class CompanyControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + private final static String URL = "/api/company"; + private final static String CONTENT_TYPE = "application/json"; + + /** + * Tests the {@link CompanyController#create(CompanyCreateDto)} method with valid input. + * Expects the response status code to be 201 (Created). + */ + @Test + @DisplayName("Create company with valid input") + void createNonExistingCompanyTest() throws Exception { + // Prepare + CompanyCreateDto createDto = new CompanyCreateDto(); + createDto.setName("superDuperCompany"); + + // Execute + String response = mockMvc.perform(post(URL) + .contentType(CONTENT_TYPE) + .content(objectMapper.writeValueAsString(createDto))) + .andExpect(status().isCreated()) + .andReturn() + .getResponse() + .getContentAsString(); + + // Verify + CompanyDto companyDto = objectMapper.readValue(response, CompanyDto.class); + assertThat(companyDto.getId()).isNotNull(); + assertThat(companyDto.getName()).isEqualTo(createDto.getName()); + } +}