diff --git a/build.gradle.kts b/build.gradle.kts index 5bf9652..2fbbcfc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,6 +6,10 @@ plugins { id("com.gradle.build-scan") version "2.0.2" id("org.springframework.boot") version "2.1.1.RELEASE" kotlin("jvm") version "1.3.11" + // https://kotlinlang.org/docs/reference/compiler-plugins.html#spring-support + id("org.jetbrains.kotlin.plugin.spring") version "1.3.11" + // https://kotlinlang.org/docs/reference/compiler-plugins.html#jpa-support + id("org.jetbrains.kotlin.plugin.jpa") version "1.3.11" } repositories { @@ -38,6 +42,10 @@ sourceSets { } } +tasks.test { + useJUnitPlatform() +} + val integrationTestImplementation by configurations.getting { extendsFrom(configurations.testImplementation.get()) } @@ -54,40 +62,44 @@ val integrationTest = task("integrationTest") { } dependencies { + // Kotlin + compile(kotlin("stdlib-jdk8")) + // Spring Boot - implementation(enforcedPlatform("org.springframework.boot:spring-boot-dependencies:2.1.1.RELEASE")) + compile(enforcedPlatform("org.springframework.boot:spring-boot-dependencies:2.1.1.RELEASE")) // web - implementation("org.springframework.boot:spring-boot-starter-web") + compile("org.springframework.boot:spring-boot-starter-web") // database - implementation("org.springframework.boot:spring-boot-starter-data-jpa") - implementation("org.hibernate:hibernate-java8") + compile("org.springframework.boot:spring-boot-starter-data-jpa") + compile("org.hibernate:hibernate-java8") runtime("org.postgresql:postgresql:42.2.2") - implementation("org.flywaydb:flyway-core:5.0.7") + compile("org.flywaydb:flyway-core:5.0.7") - implementation("org.bitbucket.cowwoc:requirements-core:4.0.4-RC") + compile("org.bitbucket.cowwoc:requirements-core:4.0.4-RC") // Jackson - implementation("com.fasterxml.jackson.core:jackson-databind:2.9.7") - implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.9.7") + compile("com.fasterxml.jackson.core:jackson-databind:2.9.7") + compile("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.9.7") + compile("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.7") // because of Java 9+ // https://stackoverflow.com/questions/43574426/how-to-resolve-java-lang-noclassdeffounderror-javax-xml-bind-jaxbexception-in-j#43574427 // https://blog.sourced-bvba.be/article/2017/12/17/java9-spring/ - implementation("javax.xml.bind:jaxb-api:2.3.0") - implementation("com.sun.xml.bind:jaxb-impl:2.3.0") - implementation("org.glassfish.jaxb:jaxb-runtime:2.3.0") - implementation("javax.activation:activation:1.1.1") + compile("javax.xml.bind:jaxb-api:2.3.0") + compile("com.sun.xml.bind:jaxb-impl:2.3.0") + compile("org.glassfish.jaxb:jaxb-runtime:2.3.0") + compile("javax.activation:activation:1.1.1") // dev tools - implementation("org.springframework.boot:spring-boot-devtools") + compile("org.springframework.boot:spring-boot-devtools") - testImplementation("org.springframework.boot:spring-boot-starter-test") - testImplementation("org.springframework.boot:spring-boot-test-autoconfigure") + testCompile("org.springframework.boot:spring-boot-starter-test") + testCompile("org.springframework.boot:spring-boot-test-autoconfigure") // JUnit 5 - testImplementation("org.junit.jupiter:junit-jupiter-api:5.3.2") + testCompile("org.junit.jupiter:junit-jupiter-api:5.3.2") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.3.2") // Support running JUnit 4 tests using JUnit 5 @@ -95,9 +107,8 @@ dependencies { testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.3.2") // H2 in-memory database - testImplementation("com.h2database:h2:1.4.197") + testCompile("com.h2database:h2:1.4.197") // integrationTestCompile("org.seleniumhq.selenium:selenium-java:3.13.0") // integrationTestCompile("org.seleniumhq.selenium:selenium-remote-driver:3.13.0") - compile(kotlin("stdlib-jdk8")) } \ No newline at end of file diff --git a/src/integrationTest/java/cloud/cosmin/checklister/BaseIT.java b/src/integrationTest/java/cloud/cosmin/checklister/BaseIT.java deleted file mode 100644 index 7e8a111..0000000 --- a/src/integrationTest/java/cloud/cosmin/checklister/BaseIT.java +++ /dev/null @@ -1,73 +0,0 @@ -package cloud.cosmin.checklister; - -import cloud.cosmin.checklister.discovery.Service; -import cloud.cosmin.checklister.discovery.ServiceDiscovery; -import cloud.cosmin.checklister.dto.ItemGetDto; -import cloud.cosmin.checklister.dto.ItemPostDto; -import cloud.cosmin.checklister.dto.ListGetDto; -import cloud.cosmin.checklister.dto.ListPostDto; -import org.junit.Before; -import org.springframework.web.client.RestTemplate; - -import java.io.IOException; -import java.net.URI; -import java.util.UUID; - -import static org.junit.Assert.assertNotNull; - -public class BaseIT { - protected Service service; - protected RestTemplate template = new RestTemplate(); - - protected String getListUrl(Service service) { - return service.http + "/api/v1/list"; - } - - - private String getItemPostUrl(UUID listId) { - return getListUrl(service) + "/" + listId.toString() + "/item"; - } - - private String getItemUrl(UUID itemId) { - return service.http + "/api/v1/item/" + itemId.toString(); - } - - @Before - public void setUp() throws IOException { - this.service = ServiceDiscovery.getService("checklister"); - } - - protected ListGetDto createList(String title) { - ListPostDto post = new ListPostDto(null, title); - URI newListUri = template.postForLocation(getListUrl(service), post, ListGetDto.class); - assertNotNull(newListUri); - - return template.getForObject(service.http + newListUri.toString(), ListGetDto.class); - } - - protected ListGetDto createList(UUID uuid, String title) { - ListPostDto post = new ListPostDto(uuid, title); - URI newListUri = template.postForLocation(getListUrl(service), post, ListGetDto.class); - assertNotNull(newListUri); - - return template.getForObject(service.http + newListUri.toString(), ListGetDto.class); - } - - protected ListGetDto updateList(UUID id, String title) { - ListPostDto post = new ListPostDto(null, title); - String listUri = getListUrl(service) + "/" + id.toString(); - template.put(listUri, post); - - return template.getForObject(listUri, ListGetDto.class); - } - - protected ItemGetDto addItem(UUID listId, ItemPostDto item) { - String url = getItemPostUrl(listId); - return template.postForObject(url, item, ItemGetDto.class); - } - - protected ItemGetDto getItem(UUID itemId) { - String url = getItemUrl(itemId); - return template.getForObject(url, ItemGetDto.class); - } -} diff --git a/src/integrationTest/java/cloud/cosmin/checklister/ItemUpdateIT.java b/src/integrationTest/java/cloud/cosmin/checklister/ItemUpdateIT.java deleted file mode 100644 index a5d473a..0000000 --- a/src/integrationTest/java/cloud/cosmin/checklister/ItemUpdateIT.java +++ /dev/null @@ -1,41 +0,0 @@ -package cloud.cosmin.checklister; - -import cloud.cosmin.checklister.dto.ItemPostDto; -import org.junit.Test; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; - -import java.util.UUID; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -public class ItemUpdateIT extends BaseIT { - @Test - public void itemUpdate() { - var newList = createList("testlist"); - var itemPost = new ItemPostDto("content", "text/plain", null); - UUID itemId; - { - var itemAdded = addItem(newList.getId(), itemPost); - assertNotNull(itemAdded); - assertEquals("content", itemAdded.getContent()); - assertEquals("text/plain", itemAdded.getContentType()); - assertEquals(0, itemAdded.getRank()); - itemId = itemAdded.getId(); - }{ - itemPost.setContent("content1"); - itemPost.setContentType("application/json"); - var itemAdded = addItem(newList.getId(), itemPost); - assertNotNull(itemAdded); - assertEquals("content1", itemAdded.getContent()); - assertEquals("application/json", itemAdded.getContentType()); - assertEquals(1, itemAdded.getRank()); - }{ - var item = getItem(itemId); - assertEquals("content", item.getContent()); - assertEquals("text/plain", item.getContentType()); - assertEquals(0, item.getRank()); - } - } -} diff --git a/src/integrationTest/java/cloud/cosmin/checklister/ListCreationIT.java b/src/integrationTest/java/cloud/cosmin/checklister/ListCreationIT.java deleted file mode 100644 index 599ae89..0000000 --- a/src/integrationTest/java/cloud/cosmin/checklister/ListCreationIT.java +++ /dev/null @@ -1,43 +0,0 @@ -package cloud.cosmin.checklister; - -import cloud.cosmin.checklister.dto.ItemGetDto; -import cloud.cosmin.checklister.dto.ItemPostDto; -import cloud.cosmin.checklister.dto.ListGetDto; -import org.junit.Test; - -import java.net.URI; -import java.util.UUID; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -public class ListCreationIT extends BaseIT { - @Test - public void listCreation() { - ListGetDto newList = createList("testlist"); - assertEquals("testlist", newList.getTitle()); - } - - @Test - public void itemCreation() { - ListGetDto newList = createList("testtitle"); - String itemPostUrl = service.http + "/api/v1/list/" + newList.getId().toString() + "/item"; - ItemPostDto item = new ItemPostDto("testcontnet", null, null); - - URI newItemUri = template.postForLocation(itemPostUrl, item); - assertNotNull(newItemUri); - - String newItemUriString = service.http + newItemUri.toString(); - ItemGetDto newItem = template.getForObject(newItemUriString, ItemGetDto.class); - assertEquals("testcontent", newItem.getContent()); - assertEquals("text/plain", newItem.getContentType()); - assertEquals(0, newItem.getRank()); - } - - @Test - public void listCreationWithId() { - UUID uuid = UUID.randomUUID(); - ListGetDto newList = createList(uuid, "title"); - assertEquals(uuid, newList.getId()); - } -} diff --git a/src/integrationTest/java/cloud/cosmin/checklister/ListUpdateIT.java b/src/integrationTest/java/cloud/cosmin/checklister/ListUpdateIT.java deleted file mode 100644 index fe9da50..0000000 --- a/src/integrationTest/java/cloud/cosmin/checklister/ListUpdateIT.java +++ /dev/null @@ -1,15 +0,0 @@ -package cloud.cosmin.checklister; - -import cloud.cosmin.checklister.dto.ListGetDto; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class ListUpdateIT extends BaseIT { - @Test - public void listUpdate() { - ListGetDto newList = createList("testlist"); - ListGetDto updatedList = updateList(newList.getId(), "newtitle"); - assertEquals("newtitle", updatedList.getTitle()); - } -} diff --git a/src/integrationTest/java/cloud/cosmin/checklister/LoginTest.java b/src/integrationTest/java/cloud/cosmin/checklister/LoginTest.java deleted file mode 100644 index dd9da3c..0000000 --- a/src/integrationTest/java/cloud/cosmin/checklister/LoginTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package cloud.cosmin.checklister; - -import org.junit.Test; - -import java.net.MalformedURLException; - -public class LoginTest { - - @Test - public void test() throws MalformedURLException { - // TODO - } -} diff --git a/src/integrationTest/java/cloud/cosmin/checklister/discovery/Service.java b/src/integrationTest/java/cloud/cosmin/checklister/discovery/Service.java deleted file mode 100644 index 32a6bf1..0000000 --- a/src/integrationTest/java/cloud/cosmin/checklister/discovery/Service.java +++ /dev/null @@ -1,15 +0,0 @@ -package cloud.cosmin.checklister.discovery; - -import static java.lang.String.format; - -public class Service { - public final String host; - public final int port; - public final String http; - - public Service(String host, int port) { - this.host = host; - this.port = port; - this.http = format("http://%s:%d", host, port); - } -} diff --git a/src/integrationTest/java/cloud/cosmin/checklister/discovery/ServiceDiscovery.java b/src/integrationTest/java/cloud/cosmin/checklister/discovery/ServiceDiscovery.java deleted file mode 100644 index 7fcbddf..0000000 --- a/src/integrationTest/java/cloud/cosmin/checklister/discovery/ServiceDiscovery.java +++ /dev/null @@ -1,43 +0,0 @@ -package cloud.cosmin.checklister.discovery; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; - -import java.io.File; -import java.io.IOException; - -public class ServiceDiscovery { - private static ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); - private static int getServicePort(String serviceName, int internalPort) throws IOException { - JsonNode tree = mapper.readTree(new File("docker-compose.yml")); - - JsonNode ports = tree.get("services").get(serviceName).get("ports"); - - for(int i = 0; i < ports.size(); i++) { - String port = ports.get(i).asText(); - if(port.contains(":")) { - String[] portParts = port.split(":"); - if(Integer.parseInt(portParts[1]) == internalPort) { - return Integer.parseInt(portParts[0]); - } - } - } - return -1; - } - - public static Service getService(String name) throws IOException { - String host = System.getenv(name + "_HOST"); - String port = System.getenv(name + "_TCP_8080"); - - if(host == null) { - host = "localhost"; - } - - if(port == null) { - return new Service(host, getServicePort("checklister", 8080)); - } - - return new Service(host, Integer.valueOf(port)); - } -} diff --git a/src/integrationTest/kotlin/cloud/cosmin/checklister/BaseIT.kt b/src/integrationTest/kotlin/cloud/cosmin/checklister/BaseIT.kt new file mode 100644 index 0000000..9962b5b --- /dev/null +++ b/src/integrationTest/kotlin/cloud/cosmin/checklister/BaseIT.kt @@ -0,0 +1,67 @@ +package cloud.cosmin.checklister + +import cloud.cosmin.checklister.discovery.Service +import cloud.cosmin.checklister.discovery.ServiceDiscovery +import cloud.cosmin.checklister.dto.ItemGetDto +import cloud.cosmin.checklister.dto.ItemPostDto +import cloud.cosmin.checklister.dto.ListGetDto +import cloud.cosmin.checklister.dto.ListPostDto +import org.junit.Before +import org.springframework.web.client.RestTemplate + +import java.io.IOException +import java.util.UUID + +import org.junit.Assert.assertNotNull +import java.lang.IllegalStateException + +open class BaseIT { + protected val service: Service = ServiceDiscovery.getService("checklister") + protected val template = RestTemplate() + + protected fun getListUrl(service: Service): String { + return service.http + "/api/v1/list" + } + + private fun getItemPostUrl(listId: UUID): String { + return getListUrl(service) + "/" + listId.toString() + "/item" + } + + private fun getItemUrl(itemId: UUID): String { + return service.http + "/api/v1/item/" + itemId.toString() + } + + protected fun createList(title: String): ListGetDto { + val post = ListPostDto(null, title) + val newListUri = template.postForLocation(getListUrl(service), post, ListGetDto::class.java) + assertNotNull(newListUri) + + return template.getForObject(service.http + newListUri!!.toString(), ListGetDto::class.java)!! + } + + protected fun createList(uuid: UUID, title: String): ListGetDto { + val post = ListPostDto(uuid, title) + val newListUri = template.postForLocation(getListUrl(service), post, ListGetDto::class.java) + assertNotNull(newListUri) + + return template.getForObject(service.http + newListUri!!.toString(), ListGetDto::class.java)!! + } + + protected fun updateList(id: UUID, title: String): ListGetDto { + val post = ListPostDto(null, title) + val listUri = getListUrl(service) + "/" + id.toString() + template.put(listUri, post) + + return template.getForObject(listUri, ListGetDto::class.java)!! + } + + protected fun addItem(listId: UUID, item: ItemPostDto): ItemGetDto { + val url = getItemPostUrl(listId) + return template.postForObject(url, item, ItemGetDto::class.java)!! + } + + protected fun getItem(itemId: UUID): ItemGetDto { + val url = getItemUrl(itemId) + return template.getForObject(url, ItemGetDto::class.java)!! + } +} diff --git a/src/integrationTest/kotlin/cloud/cosmin/checklister/ItemUpdateIT.kt b/src/integrationTest/kotlin/cloud/cosmin/checklister/ItemUpdateIT.kt new file mode 100644 index 0000000..46c14b9 --- /dev/null +++ b/src/integrationTest/kotlin/cloud/cosmin/checklister/ItemUpdateIT.kt @@ -0,0 +1,39 @@ +package cloud.cosmin.checklister + +import cloud.cosmin.checklister.dto.ItemPostDto +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Test +import java.util.* + +class ItemUpdateIT : BaseIT() { + @Test + fun itemUpdate() { + val (id) = createList("testlist") + val itemPost = ItemPostDto("content", "text/plain", null) + val itemId: UUID? + run { + val itemAdded = addItem(id!!, itemPost) + assertNotNull(itemAdded) + assertEquals("content", itemAdded.content) + assertEquals("text/plain", itemAdded.contentType) + assertEquals(0, itemAdded.rank) + itemId = itemAdded.id + } + run { + itemPost.content = "content1" + itemPost.contentType = "application/json" + val itemAdded = addItem(id!!, itemPost) + assertNotNull(itemAdded) + assertEquals("content1", itemAdded.content) + assertEquals("application/json", itemAdded.contentType) + assertEquals(1, itemAdded.rank) + } + run { + val (_, _, content, contentType, rank) = getItem(itemId!!) + assertEquals("content", content) + assertEquals("text/plain", contentType) + assertEquals(0, rank) + } + } +} diff --git a/src/integrationTest/kotlin/cloud/cosmin/checklister/ListCreationIT.kt b/src/integrationTest/kotlin/cloud/cosmin/checklister/ListCreationIT.kt new file mode 100644 index 0000000..36f42d9 --- /dev/null +++ b/src/integrationTest/kotlin/cloud/cosmin/checklister/ListCreationIT.kt @@ -0,0 +1,39 @@ +package cloud.cosmin.checklister + +import cloud.cosmin.checklister.dto.ItemGetDto +import cloud.cosmin.checklister.dto.ItemPostDto +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Test +import java.util.* + +class ListCreationIT : BaseIT() { + @Test + fun listCreation() { + val (_, title) = createList("testlist") + assertEquals("testlist", title) + } + + @Test + fun itemCreation() { + val (id) = createList("testtitle") + val itemPostUrl = service.http + "/api/v1/list/" + id!!.toString() + "/item" + val item = ItemPostDto("testcontent", null, null) + + val newItemUri = template.postForLocation(itemPostUrl, item) + assertNotNull(newItemUri) + + val newItemUriString = service.http + newItemUri!!.toString() + val newItem = template.getForObject(newItemUriString, ItemGetDto::class.java) + assertEquals("testcontent", newItem!!.content) + assertEquals("text/plain", newItem.contentType) + assertEquals(0, newItem.rank) + } + + @Test + fun listCreationWithId() { + val uuid = UUID.randomUUID() + val (id) = createList(uuid, "title") + assertEquals(uuid, id) + } +} diff --git a/src/integrationTest/kotlin/cloud/cosmin/checklister/ListUpdateIT.kt b/src/integrationTest/kotlin/cloud/cosmin/checklister/ListUpdateIT.kt new file mode 100644 index 0000000..7a8f668 --- /dev/null +++ b/src/integrationTest/kotlin/cloud/cosmin/checklister/ListUpdateIT.kt @@ -0,0 +1,15 @@ +package cloud.cosmin.checklister + +import cloud.cosmin.checklister.dto.ListGetDto +import org.junit.Test + +import org.junit.Assert.assertEquals + +class ListUpdateIT : BaseIT() { + @Test + fun listUpdate() { + val (id) = createList("testlist") + val (_, title) = updateList(id!!, "newtitle") + assertEquals("newtitle", title) + } +} diff --git a/src/integrationTest/kotlin/cloud/cosmin/checklister/LoginTest.kt b/src/integrationTest/kotlin/cloud/cosmin/checklister/LoginTest.kt new file mode 100644 index 0000000..832a060 --- /dev/null +++ b/src/integrationTest/kotlin/cloud/cosmin/checklister/LoginTest.kt @@ -0,0 +1,14 @@ +package cloud.cosmin.checklister + +import org.junit.Test + +import java.net.MalformedURLException + +class LoginTest { + + @Test + @Throws(MalformedURLException::class) + fun test() { + // TODO + } +} diff --git a/src/integrationTest/kotlin/cloud/cosmin/checklister/discovery/Service.kt b/src/integrationTest/kotlin/cloud/cosmin/checklister/discovery/Service.kt new file mode 100644 index 0000000..71d3529 --- /dev/null +++ b/src/integrationTest/kotlin/cloud/cosmin/checklister/discovery/Service.kt @@ -0,0 +1,11 @@ +package cloud.cosmin.checklister.discovery + +import java.lang.String.format + +class Service(val host: String, val port: Int) { + val http: String + + init { + this.http = format("http://%s:%d", host, port) + } +} diff --git a/src/integrationTest/kotlin/cloud/cosmin/checklister/discovery/ServiceDiscovery.kt b/src/integrationTest/kotlin/cloud/cosmin/checklister/discovery/ServiceDiscovery.kt new file mode 100644 index 0000000..92647d0 --- /dev/null +++ b/src/integrationTest/kotlin/cloud/cosmin/checklister/discovery/ServiceDiscovery.kt @@ -0,0 +1,45 @@ +package cloud.cosmin.checklister.discovery + +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory + +import java.io.File +import java.io.IOException + +object ServiceDiscovery { + private val mapper = ObjectMapper(YAMLFactory()) + + @Throws(IOException::class) + private fun getServicePort(serviceName: String, internalPort: Int): Int { + val tree = mapper.readTree(File("docker-compose.yml")) + + val ports = tree.get("services").get(serviceName).get("ports") + + for (i in 0 until ports.size()) { + val port = ports.get(i).asText() + if (port.contains(":")) { + val portParts = port.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + if (Integer.parseInt(portParts[1]) == internalPort) { + return Integer.parseInt(portParts[0]) + } + } + } + return -1 + } + + @Throws(IOException::class) + fun getService(name: String): Service { + var host: String? = System.getenv(name + "_HOST") + val port = System.getenv(name + "_TCP_8080") + + if (host == null) { + host = "localhost" + } + + return if (port == null) { + Service(host, getServicePort("checklister", 8080)) + } else Service(host, Integer.valueOf(port)) + + } +} diff --git a/src/main/java/cloud/cosmin/checklister/ChecklisterApplication.java b/src/main/java/cloud/cosmin/checklister/ChecklisterApplication.java deleted file mode 100644 index 43cb039..0000000 --- a/src/main/java/cloud/cosmin/checklister/ChecklisterApplication.java +++ /dev/null @@ -1,12 +0,0 @@ -package cloud.cosmin.checklister; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class ChecklisterApplication { - - public static void main(String[] args) { - SpringApplication.run(ChecklisterApplication.class, args); - } -} diff --git a/src/main/java/cloud/cosmin/checklister/ChecklisterApplication.kt b/src/main/java/cloud/cosmin/checklister/ChecklisterApplication.kt new file mode 100644 index 0000000..ba7818b --- /dev/null +++ b/src/main/java/cloud/cosmin/checklister/ChecklisterApplication.kt @@ -0,0 +1,11 @@ +package cloud.cosmin.checklister + +import org.springframework.boot.SpringApplication +import org.springframework.boot.autoconfigure.SpringBootApplication + +@SpringBootApplication +class ChecklisterApplication + +fun main(args: Array) { + SpringApplication.run(ChecklisterApplication::class.java, *args) +} \ No newline at end of file diff --git a/src/main/java/cloud/cosmin/checklister/dao/ItemEntity.java b/src/main/java/cloud/cosmin/checklister/dao/ItemEntity.java deleted file mode 100644 index 14f69b0..0000000 --- a/src/main/java/cloud/cosmin/checklister/dao/ItemEntity.java +++ /dev/null @@ -1,93 +0,0 @@ -package cloud.cosmin.checklister.dao; - -import org.hibernate.annotations.DynamicInsert; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; -import java.util.Objects; -import java.util.UUID; - -@Entity -@DynamicInsert -@Table(name = "item") -public class ItemEntity { - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private UUID id; - - @Column(nullable = false) - private String content; - - @Column(nullable = false) - private int rank; - - @Column(nullable = false) - private String contentType; - - @ManyToOne - @JoinColumn(nullable = false) - private ListEntity list; - - public UUID getId() { - return id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - public String getContentType() { - return contentType; - } - - public void setContentType(String contentType) { - this.contentType = contentType; - } - - public int getRank() { - return rank; - } - - public void setRank(int rank) { - this.rank = rank; - } - - public ListEntity getList() { - return list; - } - - public void setList(ListEntity list) { - this.list = list; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ItemEntity that = (ItemEntity) o; - return rank == that.rank && - Objects.equals(id, that.id) && - Objects.equals(content, that.content) && - Objects.equals(contentType, that.contentType) && - Objects.equals(list, that.list); - } - - @Override - public int hashCode() { - return Objects.hash(id, content, rank, contentType, list); - } -} diff --git a/src/main/java/cloud/cosmin/checklister/dao/ItemEntity.kt b/src/main/java/cloud/cosmin/checklister/dao/ItemEntity.kt new file mode 100644 index 0000000..9259206 --- /dev/null +++ b/src/main/java/cloud/cosmin/checklister/dao/ItemEntity.kt @@ -0,0 +1,51 @@ +package cloud.cosmin.checklister.dao + +import org.hibernate.annotations.DynamicInsert + +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne +import javax.persistence.Table +import java.util.Objects +import java.util.UUID + +@Entity +@DynamicInsert +@Table(name = "item") +class ItemEntity { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + var id: UUID? = null + + @Column(nullable = false) + var content: String? = null + + @Column(nullable = false) + var rank: Int = 0 + + @Column(nullable = false) + var contentType: String? = null + + @ManyToOne + @JoinColumn(nullable = false) + var list: ListEntity? = null + + override fun equals(o: Any?): Boolean { + if (this === o) return true + if (o == null || javaClass != o.javaClass) return false + val that = o as ItemEntity? + return rank == that!!.rank && + id == that.id && + content == that.content && + contentType == that.contentType && + list == that.list + } + + override fun hashCode(): Int { + return Objects.hash(id, content, rank, contentType, list) + } +} diff --git a/src/main/java/cloud/cosmin/checklister/dao/ListEntity.java b/src/main/java/cloud/cosmin/checklister/dao/ListEntity.java deleted file mode 100644 index 803bece..0000000 --- a/src/main/java/cloud/cosmin/checklister/dao/ListEntity.java +++ /dev/null @@ -1,68 +0,0 @@ -package cloud.cosmin.checklister.dao; - -import org.hibernate.annotations.Fetch; -import org.hibernate.annotations.FetchMode; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import java.util.List; -import java.util.Objects; -import java.util.UUID; - -@Entity -@Table(name = "list") -public class ListEntity { - @Id - private UUID id; - - @Column(nullable = false) - private String title; - - @OneToMany(mappedBy = "list") - @Fetch(FetchMode.JOIN) - private List items; - - public UUID getId() { - return id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ListEntity that = (ListEntity) o; - return Objects.equals(id, that.id) && - Objects.equals(title, that.title) && - Objects.equals(items, that.items); - } - - @Override - public int hashCode() { - return Objects.hash(id, title, items); - } -} diff --git a/src/main/java/cloud/cosmin/checklister/dao/ListEntity.kt b/src/main/java/cloud/cosmin/checklister/dao/ListEntity.kt new file mode 100644 index 0000000..0ce0dac --- /dev/null +++ b/src/main/java/cloud/cosmin/checklister/dao/ListEntity.kt @@ -0,0 +1,41 @@ +package cloud.cosmin.checklister.dao + +import org.hibernate.annotations.Fetch +import org.hibernate.annotations.FetchMode + +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.OneToMany +import javax.persistence.Table +import java.util.Objects +import java.util.UUID + +@Entity +@Table(name = "list") +class ListEntity { + @Id + var id: UUID? = null + + @Column(nullable = false) + var title: String? = null + + @OneToMany(mappedBy = "list") + @Fetch(FetchMode.JOIN) + var items: List? = null + + override fun equals(o: Any?): Boolean { + if (this === o) return true + if (o == null || javaClass != o.javaClass) return false + val that = o as ListEntity? + return id == that!!.id && + title == that.title && + items == that.items + } + + override fun hashCode(): Int { + return Objects.hash(id, title, items) + } +} diff --git a/src/main/java/cloud/cosmin/checklister/dto/Dtos.kt b/src/main/java/cloud/cosmin/checklister/dto/Dtos.kt index 2c9df26..55bfe6c 100644 --- a/src/main/java/cloud/cosmin/checklister/dto/Dtos.kt +++ b/src/main/java/cloud/cosmin/checklister/dto/Dtos.kt @@ -3,30 +3,30 @@ package cloud.cosmin.checklister.dto import com.fasterxml.jackson.annotation.JsonProperty import java.util.* -data class ItemGetDto(var id: UUID, - var list: UUID, - var content: String, - var contentType: String, - var rank: Int) +data class ItemGetDto(var id: UUID?, + var list: UUID?, + var content: String?, + var contentType: String?, + var rank: Int?) data class ItemPostDto( - @JsonProperty var content: String, + @JsonProperty var content: String?, @JsonProperty var contentType: String?, @JsonProperty var rank: Int? ) data class ListGetDto( - var id: UUID, - var title: String + var id: UUID?, + var title: String? ) data class ListPostDto( @JsonProperty var uuid: UUID?, - @JsonProperty var title: String + @JsonProperty var title: String? ) data class ListWithItemsDto( - var id: UUID, - var title: String, - var items: List + var id: UUID?, + var title: String?, + var items: MutableList? ) \ No newline at end of file diff --git a/src/main/java/cloud/cosmin/checklister/repo/ItemRepo.java b/src/main/java/cloud/cosmin/checklister/repo/ItemRepo.java deleted file mode 100644 index b35bdf9..0000000 --- a/src/main/java/cloud/cosmin/checklister/repo/ItemRepo.java +++ /dev/null @@ -1,9 +0,0 @@ -package cloud.cosmin.checklister.repo; - -import cloud.cosmin.checklister.dao.ItemEntity; -import org.springframework.data.repository.PagingAndSortingRepository; - -import java.util.UUID; - -public interface ItemRepo extends PagingAndSortingRepository { -} diff --git a/src/main/java/cloud/cosmin/checklister/repo/ItemRepo.kt b/src/main/java/cloud/cosmin/checklister/repo/ItemRepo.kt new file mode 100644 index 0000000..2c4458e --- /dev/null +++ b/src/main/java/cloud/cosmin/checklister/repo/ItemRepo.kt @@ -0,0 +1,8 @@ +package cloud.cosmin.checklister.repo + +import cloud.cosmin.checklister.dao.ItemEntity +import org.springframework.data.repository.PagingAndSortingRepository + +import java.util.UUID + +interface ItemRepo : PagingAndSortingRepository diff --git a/src/main/java/cloud/cosmin/checklister/repo/ListRepo.java b/src/main/java/cloud/cosmin/checklister/repo/ListRepo.java deleted file mode 100644 index d95d630..0000000 --- a/src/main/java/cloud/cosmin/checklister/repo/ListRepo.java +++ /dev/null @@ -1,9 +0,0 @@ -package cloud.cosmin.checklister.repo; - -import cloud.cosmin.checklister.dao.ListEntity; -import org.springframework.data.repository.PagingAndSortingRepository; - -import java.util.UUID; - -public interface ListRepo extends PagingAndSortingRepository { -} diff --git a/src/main/java/cloud/cosmin/checklister/repo/ListRepo.kt b/src/main/java/cloud/cosmin/checklister/repo/ListRepo.kt new file mode 100644 index 0000000..fd0c2e6 --- /dev/null +++ b/src/main/java/cloud/cosmin/checklister/repo/ListRepo.kt @@ -0,0 +1,8 @@ +package cloud.cosmin.checklister.repo + +import cloud.cosmin.checklister.dao.ListEntity +import org.springframework.data.repository.PagingAndSortingRepository + +import java.util.UUID + +interface ListRepo : PagingAndSortingRepository diff --git a/src/main/java/cloud/cosmin/checklister/rest/IndexController.java b/src/main/java/cloud/cosmin/checklister/rest/IndexController.java deleted file mode 100644 index dfe4633..0000000 --- a/src/main/java/cloud/cosmin/checklister/rest/IndexController.java +++ /dev/null @@ -1,12 +0,0 @@ -package cloud.cosmin.checklister.rest; - -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class IndexController { - @RequestMapping(path = "/", produces = "text/plain") - public String index() { - return "Hello!"; - } -} diff --git a/src/main/java/cloud/cosmin/checklister/rest/IndexController.kt b/src/main/java/cloud/cosmin/checklister/rest/IndexController.kt new file mode 100644 index 0000000..33fe916 --- /dev/null +++ b/src/main/java/cloud/cosmin/checklister/rest/IndexController.kt @@ -0,0 +1,12 @@ +package cloud.cosmin.checklister.rest + +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +class IndexController { + @RequestMapping(path = arrayOf("/"), produces = arrayOf("text/plain")) + fun index(): String { + return "Hello!" + } +} diff --git a/src/main/java/cloud/cosmin/checklister/rest/ItemController.java b/src/main/java/cloud/cosmin/checklister/rest/ItemController.java deleted file mode 100644 index 983bd16..0000000 --- a/src/main/java/cloud/cosmin/checklister/rest/ItemController.java +++ /dev/null @@ -1,64 +0,0 @@ -package cloud.cosmin.checklister.rest; - -import cloud.cosmin.checklister.dao.ItemEntity; -import cloud.cosmin.checklister.dto.ItemGetDto; -import cloud.cosmin.checklister.dto.ItemPostDto; -import cloud.cosmin.checklister.repo.ItemRepo; -import cloud.cosmin.checklister.service.ConverterService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; - -import java.util.Optional; -import java.util.UUID; - -@Controller -public class ItemController { - @Autowired - private ItemRepo itemRepo; - - @Autowired - private ConverterService converterService; - - @GetMapping("/api/v1/item/{itemId}") - public ResponseEntity getListItem(@PathVariable UUID itemId) { - if(itemId == null) { - return ResponseEntity.badRequest().build(); - } - - Optional optionalItem = itemRepo.findById(itemId); - - if(!optionalItem.isPresent()) { - return ResponseEntity.notFound().build(); - } - - ItemGetDto dto = converterService.itemDto(optionalItem.get()); - return ResponseEntity.ok(dto); - } - - @PutMapping("/api/v1/item/{itemId}") - public ResponseEntity updateItem(@PathVariable UUID itemId, - @RequestBody ItemPostDto itemPost) { - if(itemId == null) { - return ResponseEntity.badRequest().build(); - } - - Optional optionalItem = itemRepo.findById(itemId); - if(!optionalItem.isPresent()) { - return ResponseEntity.notFound().build(); - } - - ItemEntity item = optionalItem.get(); - item.setContent(itemPost.getContent()); - item.setContentType(itemPost.getContentType()); - - ItemEntity saved = itemRepo.save(item); - ItemGetDto dto = converterService.itemDto(saved); - return ResponseEntity.ok(dto); - - } -} diff --git a/src/main/java/cloud/cosmin/checklister/rest/ItemController.kt b/src/main/java/cloud/cosmin/checklister/rest/ItemController.kt new file mode 100644 index 0000000..4e8586d --- /dev/null +++ b/src/main/java/cloud/cosmin/checklister/rest/ItemController.kt @@ -0,0 +1,64 @@ +package cloud.cosmin.checklister.rest + +import cloud.cosmin.checklister.dao.ItemEntity +import cloud.cosmin.checklister.dto.ItemGetDto +import cloud.cosmin.checklister.dto.ItemPostDto +import cloud.cosmin.checklister.repo.ItemRepo +import cloud.cosmin.checklister.service.ConverterService +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody + +import java.util.Optional +import java.util.UUID + +@Controller +class ItemController { + @Autowired + private val itemRepo: ItemRepo? = null + + @Autowired + private val converterService: ConverterService? = null + + @GetMapping("/api/v1/item/{itemId}") + fun getListItem(@PathVariable itemId: UUID?): ResponseEntity { + if (itemId == null) { + return ResponseEntity.badRequest().build() + } + + val optionalItem = itemRepo!!.findById(itemId) + + if (!optionalItem.isPresent) { + return ResponseEntity.notFound().build() + } + + val dto = converterService!!.itemDto(optionalItem.get()) + return ResponseEntity.ok(dto) + } + + @PutMapping("/api/v1/item/{itemId}") + fun updateItem(@PathVariable itemId: UUID?, + @RequestBody itemPost: ItemPostDto): ResponseEntity { + if (itemId == null) { + return ResponseEntity.badRequest().build() + } + + val optionalItem = itemRepo!!.findById(itemId) + if (!optionalItem.isPresent) { + return ResponseEntity.notFound().build() + } + + val item = optionalItem.get() + item.content = itemPost.content + item.contentType = itemPost.contentType + + val saved = itemRepo.save(item) + val dto = converterService!!.itemDto(saved) + return ResponseEntity.ok(dto) + + } +} diff --git a/src/main/java/cloud/cosmin/checklister/rest/ListController.java b/src/main/java/cloud/cosmin/checklister/rest/ListController.java deleted file mode 100644 index d20f29b..0000000 --- a/src/main/java/cloud/cosmin/checklister/rest/ListController.java +++ /dev/null @@ -1,182 +0,0 @@ -package cloud.cosmin.checklister.rest; - -import cloud.cosmin.checklister.dao.ItemEntity; -import cloud.cosmin.checklister.dao.ListEntity; -import cloud.cosmin.checklister.dto.ItemGetDto; -import cloud.cosmin.checklister.dto.ItemPostDto; -import cloud.cosmin.checklister.dto.ListGetDto; -import cloud.cosmin.checklister.dto.ListPostDto; -import cloud.cosmin.checklister.dto.ListWithItemsDto; -import cloud.cosmin.checklister.repo.ItemRepo; -import cloud.cosmin.checklister.repo.ListRepo; -import cloud.cosmin.checklister.service.ConverterService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -@RestController -public class ListController { - private final ListRepo listRepo; - private final ItemRepo itemRepo; - private final ConverterService converterService; - - @Autowired - public ListController( - ListRepo listRepo, - ItemRepo itemRepo, - ConverterService converterService - ) { - this.listRepo = listRepo; - this.itemRepo = itemRepo; - this.converterService = converterService; - } - - @GetMapping("/api/v1/list") - public ResponseEntity> getAllLists() { - List lists = new ArrayList<>(); - for(ListEntity list : listRepo.findAll()) { - ListGetDto dto = converterService.listDto(list); - lists.add(dto); - } - return ResponseEntity.ok(lists); - } - - @PostMapping(value = "/api/v1/list", consumes = "application/json") - public ResponseEntity createList(@RequestBody ListPostDto listDto) { - ListEntity newList = new ListEntity(); - if(listDto.getUuid() != null) { - newList.setId(listDto.getUuid()); - } else { - newList.setId(UUID.randomUUID()); - } - newList.setTitle(listDto.getTitle()); - ListEntity saved = listRepo.save(newList); - return ResponseEntity - .created(URI.create("/api/v1/list/" + saved.getId())) - .build(); - } - - @GetMapping("/api/v1/list/{listId}") - public ResponseEntity getList(@PathVariable UUID listId) { - if(listId == null) { - return ResponseEntity.badRequest().build(); - } - - Optional optionalList = listRepo.findById(listId); - if(!optionalList.isPresent()) { - return ResponseEntity.notFound().build(); - } - - ListEntity list = optionalList.get(); - return ResponseEntity.ok(converterService.listDto(list)); - } - - @PutMapping(value = "/api/v1/list/{listId}") - public ResponseEntity updateList(@PathVariable UUID listId, - @RequestBody ListPostDto listDto) { - if(listId == null) { - return ResponseEntity.badRequest().build(); - } - - Optional optionalList = listRepo.findById(listId); - if(!optionalList.isPresent()) { - return ResponseEntity.notFound().build(); - } - - ListEntity list = optionalList.get(); - list.setTitle(listDto.getTitle()); - - ListEntity saved = listRepo.save(list); - ListGetDto dto = converterService.listDto(saved); - return ResponseEntity.ok(dto); - } - - @GetMapping("/api/v1/list/{listId}/item") - public ResponseEntity getListWithItems(@PathVariable UUID listId) { - if(listId == null) { - return ResponseEntity.badRequest().build(); - } - - Optional optionalList = listRepo.findById(listId); - if(!optionalList.isPresent()) { - return ResponseEntity.notFound().build(); - } - - ListEntity list = optionalList.get(); - ListWithItemsDto dto = new ListWithItemsDto( - list.getId(), - list.getTitle(), - new ArrayList<>() - ); - dto.setItems(new ArrayList<>()); - for(ItemEntity item : list.getItems()) { - ItemGetDto itemDto = converterService.itemDto(item); - dto.getItems().add(itemDto); - } - return ResponseEntity.ok(dto); - } - - @PostMapping("/api/v1/list/{listId}/item") - public ResponseEntity createListItem(@PathVariable UUID listId, - @RequestBody ItemPostDto itemDto) { - if(listId == null) { - return ResponseEntity.badRequest().build(); - } - - Optional optionalList = listRepo.findById(listId); - if(!optionalList.isPresent()) { - return ResponseEntity.notFound().build(); - } - - ListEntity list = optionalList.get(); - - ItemEntity newItem = new ItemEntity(); - newItem.setContent(itemDto.getContent()); - newItem.setContentType(itemDto.getContentType()); - newItem.setRank(list.getItems().size()); - newItem.setList(list); - - ItemEntity savedItem = itemRepo.save(newItem); - ItemGetDto dto = converterService.itemDto(savedItem); - - return ResponseEntity - .created(URI.create("/api/v1/list/" + listId.toString() + "/item/" + savedItem.getId())) - .build(); - } - - // TODO: Add endpoint for direct item access (/api/v1/item/{itemId}) ? - @GetMapping("/api/v1/list/{listId}/item/{itemId}") - public ResponseEntity getListItem(@PathVariable UUID listId, - @PathVariable UUID itemId) { - if(listId == null || itemId == null) { - return ResponseEntity.badRequest().build(); - } - - Optional optionalList = listRepo.findById(listId); - if(!optionalList.isPresent()) { - return ResponseEntity.notFound().build(); - } - - Optional optionalItem = optionalList.get().getItems().stream() - .filter(i -> i.getId().equals(itemId)) - .findFirst(); - - if(!optionalItem.isPresent()) { - return ResponseEntity.notFound().build(); - } - - ItemGetDto dto = converterService.itemDto(optionalItem.get()); - return ResponseEntity.ok(dto); - } -} diff --git a/src/main/java/cloud/cosmin/checklister/rest/ListController.kt b/src/main/java/cloud/cosmin/checklister/rest/ListController.kt new file mode 100644 index 0000000..480df68 --- /dev/null +++ b/src/main/java/cloud/cosmin/checklister/rest/ListController.kt @@ -0,0 +1,173 @@ +package cloud.cosmin.checklister.rest + +import cloud.cosmin.checklister.dao.ItemEntity +import cloud.cosmin.checklister.dao.ListEntity +import cloud.cosmin.checklister.dto.ItemGetDto +import cloud.cosmin.checklister.dto.ItemPostDto +import cloud.cosmin.checklister.dto.ListGetDto +import cloud.cosmin.checklister.dto.ListPostDto +import cloud.cosmin.checklister.dto.ListWithItemsDto +import cloud.cosmin.checklister.repo.ItemRepo +import cloud.cosmin.checklister.repo.ListRepo +import cloud.cosmin.checklister.service.ConverterService +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RestController + +import java.net.URI +import java.util.ArrayList +import java.util.Optional +import java.util.UUID + +@RestController +class ListController @Autowired +constructor( + private val listRepo: ListRepo, + private val itemRepo: ItemRepo, + private val converterService: ConverterService +) { + + val allLists: ResponseEntity> + @GetMapping("/api/v1/list") + get() { + val lists = ArrayList() + for (list in listRepo.findAll()) { + val dto = converterService.listDto(list) + lists.add(dto) + } + return ResponseEntity.ok(lists) + } + + @PostMapping(value = arrayOf("/api/v1/list"), consumes = arrayOf("application/json")) + fun createList(@RequestBody listDto: ListPostDto): ResponseEntity { + val newList = ListEntity() + if (listDto.uuid != null) { + newList.id = listDto.uuid + } else { + newList.id = UUID.randomUUID() + } + newList.title = listDto.title + val saved = listRepo.save(newList) + return ResponseEntity + .created(URI.create("/api/v1/list/" + saved.id)) + .build() + } + + @GetMapping("/api/v1/list/{listId}") + fun getList(@PathVariable listId: UUID?): ResponseEntity { + if (listId == null) { + return ResponseEntity.badRequest().build() + } + + val optionalList = listRepo.findById(listId) + if (!optionalList.isPresent) { + return ResponseEntity.notFound().build() + } + + val list = optionalList.get() + return ResponseEntity.ok(converterService.listDto(list)) + } + + @PutMapping(value = arrayOf("/api/v1/list/{listId}")) + fun updateList(@PathVariable listId: UUID?, + @RequestBody listDto: ListPostDto): ResponseEntity { + if (listId == null) { + return ResponseEntity.badRequest().build() + } + + val optionalList = listRepo.findById(listId) + if (!optionalList.isPresent) { + return ResponseEntity.notFound().build() + } + + val list = optionalList.get() + list.title = listDto.title + + val saved = listRepo.save(list) + val dto = converterService.listDto(saved) + return ResponseEntity.ok(dto) + } + + @GetMapping("/api/v1/list/{listId}/item") + fun getListWithItems(@PathVariable listId: UUID?): ResponseEntity { + if (listId == null) { + return ResponseEntity.badRequest().build() + } + + val optionalList = listRepo.findById(listId) + if (!optionalList.isPresent) { + return ResponseEntity.notFound().build() + } + + val list = optionalList.get() + val dto = ListWithItemsDto( + list.id, + list.title, + ArrayList() + ) + dto.items = ArrayList() + for (item in list.items!!) { + val itemDto = converterService.itemDto(item) + dto.items!!.add(itemDto) + } + return ResponseEntity.ok(dto) + } + + @PostMapping("/api/v1/list/{listId}/item") + fun createListItem(@PathVariable listId: UUID?, + @RequestBody itemDto: ItemPostDto): ResponseEntity { + if (listId == null) { + return ResponseEntity.badRequest().build() + } + + val optionalList = listRepo.findById(listId) + if (!optionalList.isPresent) { + return ResponseEntity.notFound().build() + } + + val list = optionalList.get() + + val newItem = ItemEntity() + newItem.content = itemDto.content + newItem.contentType = itemDto.contentType + newItem.rank = list.items!!.size + newItem.list = list + + val savedItem = itemRepo.save(newItem) + val dto = converterService.itemDto(savedItem) + + return ResponseEntity + .created(URI.create("/api/v1/list/" + listId.toString() + "/item/" + savedItem.id)) + .body(dto) + } + + // TODO: Add endpoint for direct item access (/api/v1/item/{itemId}) ? + @GetMapping("/api/v1/list/{listId}/item/{itemId}") + fun getListItem(@PathVariable listId: UUID?, + @PathVariable itemId: UUID?): ResponseEntity { + if (listId == null || itemId == null) { + return ResponseEntity.badRequest().build() + } + + val optionalList = listRepo.findById(listId) + if (!optionalList.isPresent) { + return ResponseEntity.notFound().build() + } + + val optionalItem = optionalList.get().items!!.stream() + .filter { i -> i.id == itemId } + .findFirst() + + if (!optionalItem.isPresent) { + return ResponseEntity.notFound().build() + } + + val dto = converterService.itemDto(optionalItem.get()) + return ResponseEntity.ok(dto) + } +} diff --git a/src/main/java/cloud/cosmin/checklister/service/ConverterService.java b/src/main/java/cloud/cosmin/checklister/service/ConverterService.java deleted file mode 100644 index f00e382..0000000 --- a/src/main/java/cloud/cosmin/checklister/service/ConverterService.java +++ /dev/null @@ -1,27 +0,0 @@ -package cloud.cosmin.checklister.service; - -import cloud.cosmin.checklister.dao.ItemEntity; -import cloud.cosmin.checklister.dao.ListEntity; -import cloud.cosmin.checklister.dto.ItemGetDto; -import cloud.cosmin.checklister.dto.ListGetDto; -import org.springframework.stereotype.Service; - -@Service -public class ConverterService { - public ListGetDto listDto(ListEntity listEntity) { - return new ListGetDto( - listEntity.getId(), - listEntity.getTitle() - ); - } - - public ItemGetDto itemDto(ItemEntity itemEntity) { - return new ItemGetDto( - itemEntity.getId(), - itemEntity.getList().getId(), - itemEntity.getContent(), - itemEntity.getContentType(), - itemEntity.getRank() - ); - } -} diff --git a/src/main/java/cloud/cosmin/checklister/service/ConverterService.kt b/src/main/java/cloud/cosmin/checklister/service/ConverterService.kt new file mode 100644 index 0000000..35944e4 --- /dev/null +++ b/src/main/java/cloud/cosmin/checklister/service/ConverterService.kt @@ -0,0 +1,27 @@ +package cloud.cosmin.checklister.service + +import cloud.cosmin.checklister.dao.ItemEntity +import cloud.cosmin.checklister.dao.ListEntity +import cloud.cosmin.checklister.dto.ItemGetDto +import cloud.cosmin.checklister.dto.ListGetDto +import org.springframework.stereotype.Service + +@Service +class ConverterService { + fun listDto(listEntity: ListEntity): ListGetDto { + return ListGetDto( + listEntity.id, + listEntity.title + ) + } + + fun itemDto(itemEntity: ItemEntity): ItemGetDto { + return ItemGetDto( + itemEntity.id, + itemEntity.list?.id, + itemEntity.content, + itemEntity.contentType, + itemEntity.rank + ) + } +} diff --git a/src/test/java/cloud/cosmin/checklister/dto/ListPostDtoTest.kt b/src/test/java/cloud/cosmin/checklister/dto/ListPostDtoTest.kt new file mode 100644 index 0000000..eb8f544 --- /dev/null +++ b/src/test/java/cloud/cosmin/checklister/dto/ListPostDtoTest.kt @@ -0,0 +1,25 @@ +package cloud.cosmin.checklister.dto + +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.KotlinModule +import java.util.* + +@DisplayName("ListPostDto") +internal class ListPostDtoTest { + @Test @DisplayName("should be de-serialized by ObjectMapper") + fun canBeSerialized(): Unit { + val objectMapper = ObjectMapper().registerModule(KotlinModule()) + val randomUUID = UUID.randomUUID() + val dto = objectMapper.readValue(""" + { + "uuid": "${randomUUID}", + "title": "mytitle" + } + """.trimIndent(), ListPostDto::class.java) + assertEquals("mytitle", dto.title) + assertEquals(randomUUID, dto.uuid) + } +} \ No newline at end of file diff --git a/src/test/java/cloud/cosmin/checklister/service/ConverterServiceTest.java b/src/test/java/cloud/cosmin/checklister/service/ConverterServiceTest.java index 4165ccc..b026cba 100644 --- a/src/test/java/cloud/cosmin/checklister/service/ConverterServiceTest.java +++ b/src/test/java/cloud/cosmin/checklister/service/ConverterServiceTest.java @@ -44,6 +44,6 @@ public void itemConvert() { assertEquals(list.getId(), itemDto.getList()); assertEquals("content", itemDto.getContent()); assertEquals("text/plain", itemDto.getContentType()); - assertEquals(0, itemDto.getRank()); + assertEquals(Integer.valueOf(0), itemDto.getRank()); } } \ No newline at end of file