From 26c4e15cd9e78d4fee94ab5b2c8e787d2115386e Mon Sep 17 00:00:00 2001
From: Filip Bugos <xbugos@fi.muni.cz>
Date: Sat, 8 Apr 2023 18:57:18 +0200
Subject: [PATCH] fix: unique seeder 08/04/23

---
 .../muni/fi/pa165/core/DataInitializer.java   |  6 +-
 .../fi/pa165/core/common/DomainFacade.java    |  9 ++-
 .../muni/fi/pa165/core/company/Company.java   | 11 ++--
 .../pa165/core/company/CompanyController.java |  8 ++-
 .../cz/muni/fi/pa165/core/device/Device.java  |  6 +-
 .../pa165/core/manufacturer/Manufacturer.java |  2 +
 .../fi/pa165/core/smartmeter/SmartMeter.java  |  6 +-
 .../java/cz/muni/fi/pa165/core/user/User.java |  7 +--
 .../fi/pa165/core/user/UserController.java    | 18 ++++--
 .../core/company/CompanyControllerTest.java   | 61 +++++++++++++++++++
 10 files changed, 103 insertions(+), 31 deletions(-)
 create mode 100644 core/src/test/java/cz/muni/fi/pa165/core/company/CompanyControllerTest.java

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 7a0bdc5..160775c 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 408ecd5..06830e0 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 202eab6..a05bef7 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 e134fa0..db8d142 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 f10e88d..ad73d84 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 767dd04..3009705 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 f99ffbc..fb35227 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 fd12eee..ac0a4bc 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 317a298..b6cae31 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(
@@ -166,7 +174,6 @@ public class UserController {
 		return userFacade.findAll();
 	}
 
-
 	@Operation(summary = "Log in a user", tags = {"user"})
 	@ApiResponses(value = {
 			@ApiResponse(responseCode = "200", description = "Successful login"),
@@ -206,9 +213,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 0000000..87535c3
--- /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());
+	}
+}
-- 
GitLab