diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 0e1e30b892c76f654a2596fb8415f891f05eedfb..398f1633077b69fdad5eda27883d2524ea31c141 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -12,6 +12,7 @@ services: container_name: 'test_corporate_builder2' depends_on: - test_db + - test_mbroker working_dir: '/app' networks: - test_corporate_network @@ -31,4 +32,12 @@ services: networks: test_corporate_network: aliases: - - corporate_db2 \ No newline at end of file + - corporate_db2 + + test_mbroker: + image: 'rmohr/activemq:5.15.9' + container_name: 'test_corporate_broker2' + networks: + test_corporate_network: + aliases: + - actvemq \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 09eba51bf484cfc2417414989601d199d170c9c5..c3b27178a1c4a2380333d6f8ff7320a6d953da01 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,7 @@ version: '3.7' - +networks: + corporate_app2_prod_net: + name: 'ca2pd' services: boot: @@ -12,6 +14,8 @@ services: depends_on: - db working_dir: '/app' + networks: + - corporate_app2_prod_net volumes: - .:/app - m2:/root/.m2 @@ -31,6 +35,8 @@ services: image: 'postgres:10-alpine' container_name: 'corporate_db2' restart: always + networks: + - corporate_app2_prod_net environment: POSTGRES_DB: cinema POSTGRES_USER: postgres @@ -40,6 +46,21 @@ services: volumes: - db_data:/var/lib/postgresql/data + mbroker: + image: 'rmohr/activemq:5.15.9' + container_name: 'corporate_broker2' + networks: + corporate_app2_prod_net: + aliases: + - actvemq + volumes: + - active_mq_data:/opt/activemq/data + - active_mq_conf:/opt/activemq/conf + ports: + - 8161:8161 + volumes: m2: - db_data: \ No newline at end of file + db_data: + active_mq_data: + active_mq_conf: \ No newline at end of file diff --git a/pom.xml b/pom.xml index 46dd59469a2d448aa4bd8878f619a921ed2d1309..889e40ea4b08d480b43a9cc14bd4037184c0e272 100644 --- a/pom.xml +++ b/pom.xml @@ -32,6 +32,22 @@ <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-jms</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-mail</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-activemq</artifactId> + </dependency> + <dependency> + <groupId>org.apache.activemq</groupId> + <artifactId>activemq-broker</artifactId> + </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> @@ -89,26 +105,6 @@ <excludeDevtools>false</excludeDevtools> </configuration> </plugin> - <plugin> - <groupId>org.jacoco</groupId> - <artifactId>jacoco-maven-plugin</artifactId> - <version>0.8.3</version> - <executions> - <execution> - <id>pre-unit-test</id> - <goals> - <goal>prepare-agent</goal> - </goals> - </execution> - <execution> - <id>post-unit-test</id> - <phase>test</phase> - <goals> - <goal>report</goal> - </goals> - </execution> - </executions> - </plugin> <plugin> <artifactId>exec-maven-plugin</artifactId> <groupId>org.codehaus.mojo</groupId> @@ -144,6 +140,25 @@ </dependency> </dependencies> </plugin> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>0.8.5</version> + <executions> + <execution> + <goals> + <goal>prepare-agent</goal> + </goals> + </execution> + <execution> + <id>report</id> + <phase>test</phase> + <goals> + <goal>report</goal> + </goals> + </execution> + </executions> + </plugin> </plugins> </build> diff --git a/src/main/kotlin/com/s3ai/corporate_app2/CorporateApp2Application.kt b/src/main/kotlin/com/s3ai/corporate_app2/CorporateApp2Application.kt index feef50de9919ca0ca70044ac405dc7c9a1bc1589..151fdcb95dfbfbd0da685dd500e733cc86de2088 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/CorporateApp2Application.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/CorporateApp2Application.kt @@ -2,8 +2,11 @@ package com.s3ai.corporate_app2 import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication +import org.springframework.jms.annotation.EnableJms + @SpringBootApplication +@EnableJms class CorporateApp2Application fun main(args: Array<String>) { diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/CinemasController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/CinemasController.kt index 7d6f4a938ff4621c66f54926ffab3b310bb9d2b4..0d17a4b4fcb76b8f76335734efdb00b570e3db8e 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/CinemasController.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/CinemasController.kt @@ -2,13 +2,18 @@ package com.s3ai.corporate_app2.controllers import com.s3ai.corporate_app2.Cinema import com.s3ai.corporate_app2.CinemaService +import com.s3ai.corporate_app2.jms.JMSPublisher import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.HttpStatus import org.springframework.stereotype.Controller import org.springframework.ui.Model import org.springframework.web.bind.annotation.* +import org.springframework.web.client.HttpClientErrorException +import org.springframework.web.server.ResponseStatusException import org.springframework.web.servlet.view.RedirectView +import java.lang.IllegalArgumentException +import java.util.* import java.util.UUID.fromString -import java.util.UUID.randomUUID @Controller @RequestMapping("/cinemas") @@ -16,9 +21,13 @@ class CinemasController { @Autowired lateinit var cinemaService: CinemaService + @Autowired + lateinit var publisher: JMSPublisher + @GetMapping("/list") fun getCinemasBrowsePage(model: Model): String? { - model.addAttribute("cinemas", cinemaService.findAll()) + val items = getAllItems(cinemaService, publisher) + model.addAttribute("cinemas", items) return "cinemas/list" } @@ -27,10 +36,16 @@ class CinemasController { val cinema: Cinema? if (id.isEmpty()) { cinema = Cinema() - cinema.id = randomUUID() model.addAttribute("action", "Create") } else { - cinema = cinemaService.findById(fromString(id)) + val idParsed: UUID + try { + idParsed = fromString(id) + } + catch (e: IllegalArgumentException){ + throw ResponseStatusException(HttpStatus.BAD_REQUEST) + } + cinema = cinemaService.findById(idParsed) model.addAttribute("action", "Edit") } model.addAttribute("cinema", cinema) @@ -39,7 +54,7 @@ class CinemasController { @PostMapping("/update") fun updateCinema(@ModelAttribute cinema: Cinema): RedirectView { - cinemaService.save(cinema) + updateItem(cinemaService, cinema, cinema.id, publisher) return RedirectView("/cinemas/list") } } \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/SubscribersController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/SubscribersController.kt new file mode 100644 index 0000000000000000000000000000000000000000..6974267b9402aeb68a6dac26ea51a983861091ad --- /dev/null +++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/SubscribersController.kt @@ -0,0 +1,63 @@ +package com.s3ai.corporate_app2.controllers + +import com.s3ai.corporate_app2.jms.persistance.* +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Controller +import org.springframework.ui.Model +import org.springframework.web.bind.annotation.* +import org.springframework.web.servlet.view.RedirectView +import java.util.* + +class FilterForm { + var actions: MutableList<JMSEntityAction> = mutableListOf() +} + +@Controller +@RequestMapping("/subscription") +class SubscribersController { + + @Autowired + lateinit var subscriberRepository: SubscribersRepository + + @Autowired + lateinit var subTypeRepo: SubscriptionTypeRepository + + @GetMapping("/subscribe") + fun getSubscribePage(model: Model): String? { + val subscriber: Subscriber? + subscriber = Subscriber() + subscriber.id = UUID.randomUUID() + model.addAttribute("subscriber", subscriber) + model.addAttribute("types", JMSEntityAction.values()) + return "subscription/subscribe" + } + + @GetMapping("/unsubscribe") + fun getUnsubscribePage(model: Model): String { + return "subscription/unsubscribe" + } + + + @PostMapping("/subscribe") + fun addSubscriber(@ModelAttribute sub: Subscriber, @ModelAttribute(name = "actions") actionsForm: FilterForm, model: Model): RedirectView { + if (actionsForm.actions.size < 1) return RedirectView("/") + val subscriber = subscriberRepository.save(sub) + for (action in actionsForm.actions) { + val newType = SubscriptionType() + newType.type = action + newType.subscriber = subscriber + subTypeRepo.save(newType) + } + return RedirectView("/") + } + + @PostMapping("/unsubscribe") + fun unsubscribeByEmail(@RequestParam(name = "email", required = true) email: String, model: Model): RedirectView { + val user = subscriberRepository.findSubscriberByEmail(email) + if (user.isPresent) { + subscriberRepository.delete(user.get()) + } + return RedirectView("/") + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/TicketsController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/TicketsController.kt index 389362562e7f362a0ef9f33609ad32d32ce0fcd4..878cce6b4030d8f9a4ee6b1c50662c88ae215695 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/TicketsController.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/TicketsController.kt @@ -4,11 +4,15 @@ import com.s3ai.corporate_app2.CinemaService import com.s3ai.corporate_app2.Ticket import com.s3ai.corporate_app2.TicketService import com.s3ai.corporate_app2.UserService +import com.s3ai.corporate_app2.jms.JMSPublisher import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.HttpStatus import org.springframework.stereotype.Controller import org.springframework.ui.Model import org.springframework.web.bind.annotation.* +import org.springframework.web.server.ResponseStatusException import org.springframework.web.servlet.view.RedirectView +import java.lang.IllegalArgumentException import java.util.* @Controller @@ -20,10 +24,13 @@ class TicketsController { lateinit var userService: UserService @Autowired lateinit var cinemaService: CinemaService + @Autowired + lateinit var publisher: JMSPublisher @GetMapping("/list") fun getTicketsBrowsePage(model: Model): String? { - model.addAttribute("tickets", ticketService.findAll()) + val items = getAllItems(ticketService, publisher) + model.addAttribute("tickets", items) return "tickets/list" } @@ -32,10 +39,16 @@ class TicketsController { val ticket: Ticket? if (id.isEmpty()) { ticket = Ticket() - ticket.id = UUID.randomUUID() model.addAttribute("action", "Create") } else { - ticket = ticketService.findById(UUID.fromString(id)) + val idParsed: UUID + try { + idParsed = UUID.fromString(id) + } + catch (e: IllegalArgumentException){ + throw ResponseStatusException(HttpStatus.BAD_REQUEST) + } + ticket = ticketService.findById(idParsed) model.addAttribute("action", "Edit") } model.addAttribute("ticket", ticket) @@ -46,7 +59,7 @@ class TicketsController { @PostMapping("/update") fun updateTicket(@ModelAttribute ticket: Ticket): RedirectView { - ticketService.save(ticket) + updateItem(ticketService, ticket, ticket.id, publisher) return RedirectView("/tickets/list") } diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/UsersController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/UsersController.kt index 54179542bdaaead96f607c570c8f7046bb4dc781..5ea71ad523abf891aaf7d031fd42f35c0c481130 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/UsersController.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/UsersController.kt @@ -2,11 +2,15 @@ package com.s3ai.corporate_app2.controllers import com.s3ai.corporate_app2.User import com.s3ai.corporate_app2.UserService +import com.s3ai.corporate_app2.jms.JMSPublisher import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.HttpStatus import org.springframework.stereotype.Controller import org.springframework.ui.Model import org.springframework.web.bind.annotation.* +import org.springframework.web.server.ResponseStatusException import org.springframework.web.servlet.view.RedirectView +import java.lang.IllegalArgumentException import java.util.* @Controller @@ -15,9 +19,13 @@ class UsersController { @Autowired lateinit var userService: UserService + @Autowired + lateinit var publisher: JMSPublisher + @GetMapping("/list") fun getUsersBrowsePage(model: Model): String? { - model.addAttribute("users", userService.findAll()) + val items = getAllItems(userService, publisher) + model.addAttribute("users", items) return "users/list" } @@ -26,10 +34,16 @@ class UsersController { val user: User? if (id.isEmpty()) { user = User() - user.id = UUID.randomUUID() model.addAttribute("action", "Create") } else { - user = userService.findById(UUID.fromString(id)) + val idParsed: UUID + try { + idParsed = UUID.fromString(id) + } + catch (e: IllegalArgumentException){ + throw ResponseStatusException(HttpStatus.BAD_REQUEST) + } + user = userService.findById(idParsed) model.addAttribute("action", "Edit") } model.addAttribute("user", user) @@ -38,7 +52,7 @@ class UsersController { @PostMapping("/update") fun updateUser(@ModelAttribute user: User): RedirectView { - userService.save(user) + updateItem(userService, user, user.id, publisher) return RedirectView("/users/list") } } \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/controllerUtils.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/controllerUtils.kt index 1ae2e7b11f4484631bbdb02307aaec482838d2f5..f08a73a77c534d19c6978ea5b778ddda4b1c06aa 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/controllerUtils.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/controllerUtils.kt @@ -2,6 +2,9 @@ package com.s3ai.corporate_app2.controllers import com.fasterxml.jackson.dataformat.xml.XmlMapper import com.s3ai.corporate_app2.CinemaServices +import com.s3ai.corporate_app2.jms.JMSPublisher +import com.s3ai.corporate_app2.jms.persistance.JMSAction +import com.s3ai.corporate_app2.jms.persistance.JMSEntityAction import org.springframework.util.ResourceUtils import java.io.StringReader import java.io.StringWriter @@ -11,16 +14,25 @@ import javax.xml.transform.TransformerFactory import javax.xml.transform.stream.StreamResult import javax.xml.transform.stream.StreamSource +fun publishMessage(publisher: JMSPublisher, entity: String, actionJMS: JMSEntityAction, description: String) { + val jmsAction = JMSAction() + jmsAction.entity = entity + jmsAction.actionJMS = actionJMS + jmsAction.actionDescription = description + publisher.publish(jmsAction) +} -fun <T> deleteInstance(id: String, instanceName: String, jpaService: CinemaServices<T>, response: HttpServletResponse): String? { +fun <T> deleteInstance(id: String, jpaService: CinemaServices<T>, response: HttpServletResponse, publisher: JMSPublisher): String? { var responseString: String? = null try { val itemId = UUID.fromString(id) - val user = jpaService.findById(itemId) - if (null != user) jpaService.delete(user) - else { + val item = jpaService.findById(itemId) + if (null != item) { + jpaService.delete(item) + publishMessage(publisher, jpaService.itemName(), JMSEntityAction.DELETE, "Deleted object: $item") + } else { response.status = HttpServletResponse.SC_NOT_FOUND - responseString = "$instanceName was not Found" + responseString = "${jpaService.itemName()} was not Found" } } catch (e: IllegalArgumentException) { response.status = HttpServletResponse.SC_BAD_REQUEST @@ -29,14 +41,30 @@ fun <T> deleteInstance(id: String, instanceName: String, jpaService: CinemaServi return responseString } -fun <T> getInstance(id: UUID, jpaService: CinemaServices<T>, response: HttpServletResponse): T? { +fun <T : Any> getInstance(id: UUID, jpaService: CinemaServices<T>, response: HttpServletResponse, publisher: JMSPublisher): T? { val item = jpaService.findById(id) - if (null != item) return item - else response.status = HttpServletResponse.SC_NOT_FOUND + publishMessage(publisher, jpaService.itemName(), JMSEntityAction.QUERY, "Queried object with id: $id, Found: $item") + if (null != item) { + return item + } else response.status = HttpServletResponse.SC_NOT_FOUND return null } -fun XMLTransform(item: Any, resource_name: String): String { +fun <T : Any> getAllItems(jpaService: CinemaServices<T>, publisher: JMSPublisher): MutableList<T> { + val items = jpaService.findAll() + publishMessage(publisher, jpaService.itemName(), JMSEntityAction.QUERY, "Queried all items, found ${items.size}.") + return items +} + +fun <T : Any> updateItem(jpaService: CinemaServices<T>, item: T, item_id: UUID?, publisher: JMSPublisher) { + var action = JMSEntityAction.UPDATE + val updatedItem = jpaService.save(item) + val description = "New item data: $updatedItem" + if (null == item_id) action = JMSEntityAction.CREATE + publishMessage(publisher, jpaService.itemName(), action, description) +} + +fun xsltTransform(item: Any, resource_name: String): String { val xmlMapper = XmlMapper() val xslt = StreamSource(ResourceUtils.getFile("classpath:xslt/$resource_name")) val xml = StreamSource(StringReader(xmlMapper.writeValueAsString(item))) @@ -44,13 +72,4 @@ fun XMLTransform(item: Any, resource_name: String): String { val sw = StringWriter() transformer.transform(xml, StreamResult(sw)) return sw.toString() -} - -fun <T> getXSLTransformedInstance(id: UUID, jpaService: CinemaServices<T>, resource_name: String, response: HttpServletResponse): String { - val item = jpaService.findById(id) - if (null == item) response.status = HttpServletResponse.SC_NOT_FOUND - else { - return XMLTransform(item, resource_name) - } - return "" -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/CinemaApiController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/CinemaApiController.kt index b734aa12a01e7d566a5d02fcbb8693177abef7b1..a679374c9834c6eacf36c445c2b71c105e49b619 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/CinemaApiController.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/CinemaApiController.kt @@ -3,6 +3,7 @@ package com.s3ai.corporate_app2.controllers.rest import com.s3ai.corporate_app2.Cinema import com.s3ai.corporate_app2.CinemaService import com.s3ai.corporate_app2.controllers.deleteInstance +import com.s3ai.corporate_app2.jms.JMSPublisher import org.springframework.beans.factory.annotation.Autowired import org.springframework.web.bind.annotation.* import java.util.* @@ -15,6 +16,9 @@ class CinemaApiController { @Autowired lateinit var cinemaService: CinemaService + @Autowired + lateinit var publisher: JMSPublisher + @GetMapping("/fill") fun fillCinemas(): String? { val locations: List<String> = listOf("Samara", "Izhevsk", "NeoTokyo", "Bangladesh", "Moscow", "Grozny"); @@ -34,7 +38,7 @@ class CinemaApiController { @DeleteMapping("/delete") fun deleteCinema(@RequestParam(name = "id", required = true) id: String, response: HttpServletResponse): String? { - return deleteInstance(id, "Cinema", cinemaService, response) + return deleteInstance(id, cinemaService, response, publisher) } } \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/TicketApiController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/TicketApiController.kt index d7b371151653b0989cb5c912c2e866a67b9d37a4..6de73ce6ee8c794673faa0be57b245872c870425 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/TicketApiController.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/TicketApiController.kt @@ -5,6 +5,7 @@ import com.s3ai.corporate_app2.Ticket import com.s3ai.corporate_app2.TicketService import com.s3ai.corporate_app2.UserService import com.s3ai.corporate_app2.controllers.deleteInstance +import com.s3ai.corporate_app2.jms.JMSPublisher import org.springframework.beans.factory.annotation.Autowired import org.springframework.web.bind.annotation.* import java.util.* @@ -15,11 +16,16 @@ import javax.servlet.http.HttpServletResponse class TicketApiController { @Autowired lateinit var userService: UserService + @Autowired lateinit var ticketService: TicketService + @Autowired lateinit var cinemaService: CinemaService + @Autowired + lateinit var publisher: JMSPublisher + @GetMapping("/fill") fun fillTickets(): String? { val wordsFirst = arrayOf("Pirates", "Ladies", "Goblins", "Gangsters", "Programmers", "Hackers", "Wrestlers", "Animals", "Guardians") @@ -44,7 +50,7 @@ class TicketApiController { @DeleteMapping("/delete") fun deleteTicket(@RequestParam(name = "id", required = true) id: String, response: HttpServletResponse): String? { - return deleteInstance(id, "Ticket", ticketService, response) + return deleteInstance(id, ticketService, response, publisher) } } diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/UserApiController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/UserApiController.kt index b9a0a8ca1612c25436ca6f78f8441506a585c79e..193396cb30d3d7f6645b849bbe15b576ec3ee871 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/UserApiController.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/UserApiController.kt @@ -3,6 +3,7 @@ package com.s3ai.corporate_app2.controllers.rest; import com.s3ai.corporate_app2.User import com.s3ai.corporate_app2.UserService import com.s3ai.corporate_app2.controllers.deleteInstance +import com.s3ai.corporate_app2.jms.JMSPublisher import org.springframework.beans.factory.annotation.Autowired import org.springframework.web.bind.annotation.* import java.util.* @@ -12,9 +13,13 @@ import kotlin.random.Random @RestController @RequestMapping("/api/users") class UserApiController { + @Autowired lateinit var userService: UserService + @Autowired + lateinit var publisher: JMSPublisher + @GetMapping("/fill") fun fillCinemas(): String? { val names = arrayOf("Jane", "Mary", "Paul", "Jason", "Keanu", "Andrew", "Joseph", "Jotaro", "Ivan", "Jolyne", "Walther"); @@ -25,7 +30,8 @@ class UserApiController { user.id = UUID.randomUUID(); user.name = "${names.random()} ${surnames.random()}"; generatedNames.add(user.name.toString()) - user.age = Random.nextInt(15, 70); + user.age = Random.nextInt(15, 70) + userService.save(user); } return generatedNames.toString() @@ -33,6 +39,6 @@ class UserApiController { @DeleteMapping("/delete") fun deleteUser(@RequestParam(name = "id", required = true) id: String, response: HttpServletResponse): String? { - return deleteInstance(id, "User", userService, response) + return deleteInstance(id, userService, response, publisher) } } diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/CinemasJsonController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/CinemasJsonController.kt index 033ea39a4dc654989dd0656349f037526162a3c1..6cd1a4959c9e088f9fe85495ea532e83d70a219d 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/CinemasJsonController.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/CinemasJsonController.kt @@ -2,7 +2,9 @@ package com.s3ai.corporate_app2.controllers.rest.json import com.s3ai.corporate_app2.Cinema import com.s3ai.corporate_app2.CinemaService +import com.s3ai.corporate_app2.controllers.getAllItems import com.s3ai.corporate_app2.controllers.getInstance +import com.s3ai.corporate_app2.jms.JMSPublisher import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.MediaType import org.springframework.web.bind.annotation.GetMapping @@ -18,14 +20,17 @@ class CinemasJsonController { @Autowired lateinit var cinemaService: CinemaService + @Autowired + lateinit var publisher: JMSPublisher + @GetMapping("/all", produces = [MediaType.APPLICATION_JSON_VALUE]) fun getCinemas(response: HttpServletResponse): MutableList<Cinema> { - return cinemaService.findAll() + return getAllItems(cinemaService, publisher) } @GetMapping("/item/{id}", produces = [MediaType.APPLICATION_JSON_VALUE]) fun getCinema(@PathVariable id: UUID, response: HttpServletResponse): Cinema? { - return getInstance(id, cinemaService, response) + return getInstance(id, cinemaService, response, publisher) } } \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/TicketsJsonController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/TicketsJsonController.kt index 12e7eec1804795371bfe8cd0a22c2b943da871c9..95474bdcaeb0976c7ace981adc14ffcd2c5d34e5 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/TicketsJsonController.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/TicketsJsonController.kt @@ -2,7 +2,9 @@ package com.s3ai.corporate_app2.controllers.rest.json import com.s3ai.corporate_app2.Ticket import com.s3ai.corporate_app2.TicketService +import com.s3ai.corporate_app2.controllers.getAllItems import com.s3ai.corporate_app2.controllers.getInstance +import com.s3ai.corporate_app2.jms.JMSPublisher import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.MediaType import org.springframework.web.bind.annotation.GetMapping @@ -18,14 +20,17 @@ class TicketsJsonController { @Autowired lateinit var ticketService: TicketService + @Autowired + lateinit var publisher: JMSPublisher + @GetMapping("/all", produces = [MediaType.APPLICATION_JSON_VALUE]) fun getTickets(response: HttpServletResponse): MutableList<Ticket> { - return ticketService.findAll() + return getAllItems(ticketService, publisher) } @GetMapping("/item/{id}", produces = [MediaType.APPLICATION_JSON_VALUE]) fun getTicket(@PathVariable id: UUID, response: HttpServletResponse): Ticket? { - return getInstance(id, ticketService, response) + return getInstance(id, ticketService, response, publisher) } } \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/UsersJsonController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/UsersJsonController.kt index 72cb67d4e148604740d5f3d14a4526ca545bf35f..a6d10f556184aefd3a21acd28b65babd746fad1b 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/UsersJsonController.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/UsersJsonController.kt @@ -2,7 +2,9 @@ package com.s3ai.corporate_app2.controllers.rest.json import com.s3ai.corporate_app2.User import com.s3ai.corporate_app2.UserService +import com.s3ai.corporate_app2.controllers.getAllItems import com.s3ai.corporate_app2.controllers.getInstance +import com.s3ai.corporate_app2.jms.JMSPublisher import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.MediaType import org.springframework.web.bind.annotation.GetMapping @@ -18,14 +20,17 @@ class UsersJsonController { @Autowired lateinit var userService: UserService + @Autowired + lateinit var publisher: JMSPublisher + @GetMapping("/all", produces = [MediaType.APPLICATION_JSON_VALUE]) fun getUsers(response: HttpServletResponse): MutableList<User> { - return userService.findAll() + return getAllItems(userService, publisher) } @GetMapping("/item/{id}", produces = [MediaType.APPLICATION_JSON_VALUE]) fun getUser(@PathVariable id: UUID, response: HttpServletResponse): User? { - return getInstance(id, userService, response) + return getInstance(id, userService, response, publisher) } } \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/CinemasXmlController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/CinemasXmlController.kt index c5664290c659e70456f6097df0a31c91e7bef535..295c82cc3a6d1ce712bd1a0634a0e0db42c4c5b9 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/CinemasXmlController.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/CinemasXmlController.kt @@ -2,7 +2,9 @@ package com.s3ai.corporate_app2.controllers.rest.xml import com.s3ai.corporate_app2.Cinema import com.s3ai.corporate_app2.CinemaService +import com.s3ai.corporate_app2.controllers.getAllItems import com.s3ai.corporate_app2.controllers.getInstance +import com.s3ai.corporate_app2.jms.JMSPublisher import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.MediaType import org.springframework.web.bind.annotation.GetMapping @@ -18,14 +20,17 @@ class CinemasXmlController { @Autowired lateinit var cinemaService: CinemaService + @Autowired + lateinit var publisher: JMSPublisher + @GetMapping("/all", produces = [MediaType.APPLICATION_XML_VALUE]) fun getCinemas(response: HttpServletResponse): MutableList<Cinema> { - return cinemaService.findAll() + return getAllItems(cinemaService, publisher) } @GetMapping("/item/{id}", produces = [MediaType.APPLICATION_XML_VALUE]) fun getCinema(@PathVariable id: UUID, response: HttpServletResponse): Cinema? { - return getInstance(id, cinemaService, response) + return getInstance(id, cinemaService, response, publisher) } } \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/TicketsXmlController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/TicketsXmlController.kt index ddd5b7910103e9e6c005a47f3d4551ea08fd8c7f..4648abedae86ecea36b5d1d34a4b107c78516afb 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/TicketsXmlController.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/TicketsXmlController.kt @@ -2,7 +2,9 @@ package com.s3ai.corporate_app2.controllers.rest.xml import com.s3ai.corporate_app2.Ticket import com.s3ai.corporate_app2.TicketService +import com.s3ai.corporate_app2.controllers.getAllItems import com.s3ai.corporate_app2.controllers.getInstance +import com.s3ai.corporate_app2.jms.JMSPublisher import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.MediaType import org.springframework.web.bind.annotation.GetMapping @@ -18,13 +20,16 @@ class TicketsXmlController { @Autowired lateinit var ticketService: TicketService + @Autowired + lateinit var publisher: JMSPublisher + @GetMapping("/all", produces = [MediaType.APPLICATION_XML_VALUE]) fun getTickets(response: HttpServletResponse): MutableList<Ticket> { - return ticketService.findAll() + return getAllItems(ticketService, publisher) } @GetMapping("/item/{id}", produces = [MediaType.APPLICATION_XML_VALUE]) fun getTicket(@PathVariable id: UUID, response: HttpServletResponse): Ticket? { - return getInstance(id, ticketService, response) + return getInstance(id, ticketService, response, publisher) } } \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/UsersXmlController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/UsersXmlController.kt index 4de521bf1ec6d54200eb2d943ab6d8b1082d3bc9..cb633d5bad351b0bb80098e838b866d942f6ed5f 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/UsersXmlController.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/UsersXmlController.kt @@ -2,7 +2,9 @@ package com.s3ai.corporate_app2.controllers.rest.xml import com.s3ai.corporate_app2.User import com.s3ai.corporate_app2.UserService +import com.s3ai.corporate_app2.controllers.getAllItems import com.s3ai.corporate_app2.controllers.getInstance +import com.s3ai.corporate_app2.jms.JMSPublisher import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.MediaType import org.springframework.web.bind.annotation.GetMapping @@ -18,13 +20,16 @@ class UsersXmlController { @Autowired lateinit var userService: UserService + @Autowired + lateinit var publisher: JMSPublisher + @GetMapping("/all", produces = [MediaType.APPLICATION_XML_VALUE]) fun getUsers(response: HttpServletResponse): MutableList<User> { - return userService.findAll() + return getAllItems(userService, publisher) } @GetMapping("/item/{id}", produces = [MediaType.APPLICATION_XML_VALUE]) fun getUser(@PathVariable id: UUID, response: HttpServletResponse): User? { - return getInstance(id, userService, response) + return getInstance(id, userService, response, publisher) } } \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/CinemasXsltController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/CinemasXsltController.kt index 498cd0a4c3c3e7330ee2e3eb1e19bbbf61a68898..c7253791b17443e9dd538894f18ab78b12890eb3 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/CinemasXsltController.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/CinemasXsltController.kt @@ -1,8 +1,10 @@ package com.s3ai.corporate_app2.controllers.rest.xslt import com.s3ai.corporate_app2.CinemaService -import com.s3ai.corporate_app2.controllers.XMLTransform -import com.s3ai.corporate_app2.controllers.getXSLTransformedInstance +import com.s3ai.corporate_app2.controllers.xsltTransform +import com.s3ai.corporate_app2.controllers.getAllItems +import com.s3ai.corporate_app2.controllers.getInstance +import com.s3ai.corporate_app2.jms.JMSPublisher import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.MediaType import org.springframework.web.bind.annotation.GetMapping @@ -18,16 +20,23 @@ class CinemasXsltController { @Autowired lateinit var cinemaService: CinemaService + @Autowired + lateinit var publisher: JMSPublisher + val xsltResourceName: String = "cinema-process.xslt" @GetMapping("/all", produces = [MediaType.TEXT_HTML_VALUE]) fun getCinemas(response: HttpServletResponse): String { - return XMLTransform(cinemaService.findAll(), xsltResourceName) + return xsltTransform(getAllItems(cinemaService, publisher), xsltResourceName) } @GetMapping("/item/{id}", produces = [MediaType.TEXT_HTML_VALUE]) fun getCinema(@PathVariable id: UUID, response: HttpServletResponse): String? { - return getXSLTransformedInstance(id, cinemaService, xsltResourceName, response) + val item = getInstance(id, cinemaService, response, publisher) + if (null != item) { + return xsltTransform(item, xsltResourceName) + } + return "" } } \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/TicketsXsltController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/TicketsXsltController.kt index 896eca4cfa2307bd44cbbd5248e43eb0414dfc77..698b878de1173e24fa10ceb196b92e18a5b0bfd7 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/TicketsXsltController.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/TicketsXsltController.kt @@ -1,8 +1,10 @@ package com.s3ai.corporate_app2.controllers.rest.xslt import com.s3ai.corporate_app2.TicketService -import com.s3ai.corporate_app2.controllers.XMLTransform -import com.s3ai.corporate_app2.controllers.getXSLTransformedInstance +import com.s3ai.corporate_app2.controllers.xsltTransform +import com.s3ai.corporate_app2.controllers.getAllItems +import com.s3ai.corporate_app2.controllers.getInstance +import com.s3ai.corporate_app2.jms.JMSPublisher import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.MediaType import org.springframework.web.bind.annotation.GetMapping @@ -18,16 +20,23 @@ class TicketsXsltController { @Autowired lateinit var ticketService: TicketService + @Autowired + lateinit var publisher: JMSPublisher + val xsltResourceName: String = "ticket-process.xslt" @GetMapping("/all", produces = [MediaType.TEXT_HTML_VALUE]) - fun getCinemas(response: HttpServletResponse): String { - return XMLTransform(ticketService.findAll(), xsltResourceName) + fun getTickets(response: HttpServletResponse): String { + return xsltTransform(getAllItems(ticketService, publisher), xsltResourceName) } @GetMapping("/item/{id}", produces = [MediaType.TEXT_HTML_VALUE]) - fun getCinema(@PathVariable id: UUID, response: HttpServletResponse): String? { - return getXSLTransformedInstance(id, ticketService, xsltResourceName, response) + fun getTicket(@PathVariable id: UUID, response: HttpServletResponse): String? { + val item = getInstance(id, ticketService, response, publisher) + if (null != item) { + return xsltTransform(item, xsltResourceName) + } + return "" } } \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/UsersXsltController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/UsersXsltController.kt index f07ee83001d9f34d50759b285b85bfaac6f733d5..c798bd48b177065a54169a2dd6c0102d111fc233 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/UsersXsltController.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/UsersXsltController.kt @@ -1,8 +1,10 @@ package com.s3ai.corporate_app2.controllers.rest.xslt import com.s3ai.corporate_app2.UserService -import com.s3ai.corporate_app2.controllers.XMLTransform -import com.s3ai.corporate_app2.controllers.getXSLTransformedInstance +import com.s3ai.corporate_app2.controllers.getAllItems +import com.s3ai.corporate_app2.controllers.getInstance +import com.s3ai.corporate_app2.controllers.xsltTransform +import com.s3ai.corporate_app2.jms.JMSPublisher import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.MediaType import org.springframework.web.bind.annotation.GetMapping @@ -18,16 +20,23 @@ class UsersXsltController { @Autowired lateinit var userService: UserService + @Autowired + lateinit var publisher: JMSPublisher + val xsltResourceName: String = "user-process.xslt" @GetMapping("/all", produces = [MediaType.TEXT_HTML_VALUE]) - fun getCinemas(response: HttpServletResponse): String { - return XMLTransform(userService.findAll(), xsltResourceName) + fun getUsers(response: HttpServletResponse): String { + return xsltTransform(getAllItems(userService, publisher), xsltResourceName) } @GetMapping("/item/{id}", produces = [MediaType.TEXT_HTML_VALUE]) - fun getCinema(@PathVariable id: UUID, response: HttpServletResponse): String? { - return getXSLTransformedInstance(id, userService, xsltResourceName, response) + fun getUser(@PathVariable id: UUID, response: HttpServletResponse): String? { + val item = getInstance(id, userService, response, publisher) + if (null != item) { + return xsltTransform(item, xsltResourceName) + } + return "" } } \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/entities.kt b/src/main/kotlin/com/s3ai/corporate_app2/entities.kt index 28ceb6de27ba2516cba897c2e0c56c4c03ca1897..e3f4d8dee784b5ea2c71a427657120d78b4c9981 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/entities.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/entities.kt @@ -1,8 +1,6 @@ package com.s3ai.corporate_app2 import com.fasterxml.jackson.annotation.JsonAutoDetect -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement import org.hibernate.annotations.OnDelete import org.hibernate.annotations.OnDeleteAction import java.util.* @@ -73,5 +71,4 @@ class Ticket { override fun toString(): String { return "Ticket{id=$id, user=$user, cinema=$cinema, movie='$movie'}" } -} - +} \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/jms/Config.kt b/src/main/kotlin/com/s3ai/corporate_app2/jms/Config.kt new file mode 100644 index 0000000000000000000000000000000000000000..55e003c54139624724f8ec4f96e279d4d46ad18e --- /dev/null +++ b/src/main/kotlin/com/s3ai/corporate_app2/jms/Config.kt @@ -0,0 +1,29 @@ +package com.s3ai.corporate_app2.jms + +import org.apache.activemq.ActiveMQConnectionFactory +import org.apache.activemq.command.ActiveMQQueue +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.jms.core.JmsTemplate +import javax.jms.Queue + +@Configuration +class Config { + @Value("\${spring.activemq.broker-url}") + lateinit var brokerURL: String + + @Bean + fun queue(): Queue = ActiveMQQueue("cinemas.queue") + + @Bean + fun connectionFactory(): ActiveMQConnectionFactory { + val factory = ActiveMQConnectionFactory() + factory.brokerURL = brokerURL + return factory + } + + @Bean + fun jmsTemplate(): JmsTemplate = JmsTemplate(connectionFactory()) + +} \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/jms/JMSPublisher.kt b/src/main/kotlin/com/s3ai/corporate_app2/jms/JMSPublisher.kt new file mode 100644 index 0000000000000000000000000000000000000000..631df1b2bc79efa432a5e63907aac8a4743aa6d8 --- /dev/null +++ b/src/main/kotlin/com/s3ai/corporate_app2/jms/JMSPublisher.kt @@ -0,0 +1,25 @@ +package com.s3ai.corporate_app2.jms + +import com.fasterxml.jackson.databind.ObjectMapper +import com.s3ai.corporate_app2.jms.persistance.JMSAction +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.jms.core.JmsTemplate +import org.springframework.stereotype.Component +import javax.jms.Queue + +@Component +class JMSPublisher { + @Autowired + private lateinit var jmsTemplate: JmsTemplate + + + @Autowired + private lateinit var queue: Queue + + private final val mapper: ObjectMapper = ObjectMapper() + + fun publish(message_obj: JMSAction) { + val messageText = mapper.writeValueAsString(message_obj) + jmsTemplate.convertAndSend(queue, messageText) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/jms/JmsConsumer.kt b/src/main/kotlin/com/s3ai/corporate_app2/jms/JmsConsumer.kt new file mode 100644 index 0000000000000000000000000000000000000000..a9b3b8a5218432d8025d952f340a4cb6e10b9e76 --- /dev/null +++ b/src/main/kotlin/com/s3ai/corporate_app2/jms/JmsConsumer.kt @@ -0,0 +1,63 @@ +package com.s3ai.corporate_app2.jms + +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import com.s3ai.corporate_app2.jms.persistance.JMSAction +import com.s3ai.corporate_app2.jms.persistance.JMSActionRepository +import com.s3ai.corporate_app2.jms.persistance.SubscriptionTypeRepository +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Value +import org.springframework.jms.annotation.JmsListener +import org.springframework.mail.javamail.JavaMailSender +import org.springframework.mail.javamail.MimeMessageHelper +import org.springframework.messaging.MessagingException +import org.springframework.stereotype.Component + + +@Component +class JmsConsumer { + + @Value("\${spring.mail.username}") + private lateinit var sourceUser: String + + @Autowired + private lateinit var jmsActionService: JMSActionRepository + + @Autowired + private lateinit var sender: JavaMailSender + + @Autowired + private lateinit var subTypeRepo: SubscriptionTypeRepository + + private final val mapper = jacksonObjectMapper() + + fun sendEmail(action: JMSAction, targetUsers: Array<String>): Boolean { + val message = sender.createMimeMessage() + val helper = MimeMessageHelper(message) + try { + helper.setFrom(sourceUser) + helper.setTo(targetUsers) + helper.setText("Entity ${action.entity} was ${action.actionJMS.str}. ${action.actionDescription}") + helper.setSubject("Cinemas service notification") + sender.send(message) + } catch (e: MessagingException) { + e.printStackTrace() + return false + } + return true + + } + + fun notifySubscribers(action: JMSAction) { + val users = subTypeRepo.findSubscriptionTypeByType(action.actionJMS) + val emails = users.map { u -> u.subscriber.email!! }.distinct().toTypedArray() + if (emails.isNotEmpty()) sendEmail(action, emails) + } + + @JmsListener(destination = "cinemas.queue") + fun consume(action_text: String) { + val action: JMSAction = mapper.readValue(action_text) + jmsActionService.save(action) + notifySubscribers(action) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/entities.kt b/src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/entities.kt new file mode 100644 index 0000000000000000000000000000000000000000..5c221cd0e40c278ff0be4cddd7ac44702b8f7491 --- /dev/null +++ b/src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/entities.kt @@ -0,0 +1,75 @@ +package com.s3ai.corporate_app2.jms.persistance + +import com.fasterxml.jackson.annotation.JsonAutoDetect +import org.hibernate.annotations.CreationTimestamp +import org.hibernate.annotations.OnDelete +import org.hibernate.annotations.OnDeleteAction +import java.time.LocalDateTime +import java.util.* +import javax.persistence.* + + +enum class JMSEntityAction(val str: String) { + UPDATE("updated"), + QUERY("queried"), + CREATE("created"), + DELETE("deleted") +} + +@Entity +@Table(name = "jms_action") +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) +class JMSAction { + @Id + @Column(name = "ID") + @GeneratedValue(strategy = GenerationType.AUTO) + var id: UUID? = null + @Enumerated(EnumType.STRING) + @Column(length = 8, name = "action") + lateinit var actionJMS: JMSEntityAction + @Column(name = "entity") + lateinit var entity: String + @Column(name = "description", columnDefinition = "TEXT") + lateinit var actionDescription: String + @CreationTimestamp + private val createDateTime: LocalDateTime? = null + @Column(name = "delivered") + var delivered: Boolean = true + + override fun toString(): String { + return "JMSAction{id=$id, action=$actionJMS, entity='$entity', actionDescription='$actionDescription'}" + } +} + +@Entity +@Table(name = "subscriber") +class Subscriber { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + var id: UUID? = null + + @Column(name = "email") + var email: String? = null + + @CreationTimestamp + private val createDateTime: LocalDateTime? = null + + @OneToMany + var types: List<SubscriptionType> = mutableListOf() +} + +@Entity +@Table(name = "subscription_type") +class SubscriptionType { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + var id: Long? = null + + @Enumerated(EnumType.STRING) + @Column(length = 8, name = "type") + lateinit var type: JMSEntityAction + + @OneToOne + @OnDelete(action = OnDeleteAction.CASCADE) + lateinit var subscriber: Subscriber +} \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/repositories.kt b/src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/repositories.kt new file mode 100644 index 0000000000000000000000000000000000000000..d33f03567beaa9979924620d23ba187a21152d81 --- /dev/null +++ b/src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/repositories.kt @@ -0,0 +1,25 @@ +package com.s3ai.corporate_app2.jms.persistance + +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.* + +@Repository +interface JMSActionRepository : JpaRepository<JMSAction, UUID> { + @Query(value = "SELECT * FROM public.jms_action WHERE delivered = FALSE", nativeQuery = true) + fun findUndelivered(): MutableList<JMSAction> +} + +@Repository +interface SubscribersRepository : JpaRepository<Subscriber, UUID> { + @Query("FROM Subscriber WHERE email = :email") + fun findSubscriberByEmail(@Param("email") email: String): Optional<Subscriber> +} + +@Repository +interface SubscriptionTypeRepository : JpaRepository<SubscriptionType, Long> { + @Query("FROM SubscriptionType WHERE type = :type") + fun findSubscriptionTypeByType(@Param("type") type: JMSEntityAction): List<SubscriptionType> +} \ No newline at end of file diff --git a/src/main/kotlin/com/s3ai/corporate_app2/repositories.kt b/src/main/kotlin/com/s3ai/corporate_app2/repositories.kt index 6077d0af27e30232e62504301f20b3cf4d1769ac..3eed32fda03c68a06b4a0df1d5d079b440b13d55 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/repositories.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/repositories.kt @@ -1,6 +1,7 @@ package com.s3ai.corporate_app2 import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query import org.springframework.stereotype.Repository import java.util.* diff --git a/src/main/kotlin/com/s3ai/corporate_app2/services.kt b/src/main/kotlin/com/s3ai/corporate_app2/services.kt index 51cf0fbcd93065f44c259907c8861916d8f35ad9..0f51ab0ed7745a51432beed02dce246764129433 100644 --- a/src/main/kotlin/com/s3ai/corporate_app2/services.kt +++ b/src/main/kotlin/com/s3ai/corporate_app2/services.kt @@ -1,5 +1,6 @@ package com.s3ai.corporate_app2 +import org.springframework.data.jpa.repository.Query import org.springframework.stereotype.Service import java.util.* @@ -9,6 +10,7 @@ interface CinemaServices<T> { fun findById(id: UUID): T? fun save(item: T): T fun delete(item: T) + fun itemName(): String } @Service @@ -17,6 +19,7 @@ class CinemaService(private val cinemaRepository: CinemaRepository) : CinemaServ override fun findById(id: UUID): Cinema? = cinemaRepository.findById(id).orElse(null) override fun save(item: Cinema): Cinema = cinemaRepository.save(item) override fun delete(item: Cinema) = cinemaRepository.delete(item) + override fun itemName(): String = "Cinema" } @Service @@ -25,6 +28,7 @@ class UserService(private val userRepository: UserRepository) : CinemaServices<U override fun findById(id: UUID): User? = userRepository.findById(id).orElse(null) override fun save(item: User): User = userRepository.save(item) override fun delete(item: User) = userRepository.delete(item) + override fun itemName(): String = "User" } @Service @@ -33,4 +37,5 @@ class TicketService(private val ticketRepository: TicketRepository) : CinemaServ override fun findById(id: UUID): Ticket? = ticketRepository.findById(id).orElse(null) override fun save(item: Ticket): Ticket = ticketRepository.save(item) override fun delete(item: Ticket) = ticketRepository.delete(item) + override fun itemName(): String = "Ticket" } \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 2b046747b6b61873c2a783b6c5240ea6750b4f25..174500c59db2965eb5978115e1fd81579a9e8390 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,10 +1,31 @@ spring.thymeleaf.cache=false + spring.datasource.driver-class-name=org.postgresql.Driver spring.datasource.url=jdbc:postgresql://corporate_db2:5432/cinema spring.datasource.username=postgres spring.datasource.password=postgres spring.datasource.platform=postgres + spring.jpa.hibernate.ddl-auto=update spring.jpa.database=postgresql spring.jpa.database-platform=postgres -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL10Dialect \ No newline at end of file +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL10Dialect + +spring.activemq.in-memory=false +spring.activemq.pool.enabled=true +spring.activemq.broker-url=tcp://actvemq:61616 +spring.activemq.user=admin +spring.activemq.password=admin + + +spring.mail.port=465 +spring.mail.host=smtp.yandex.com +spring.mail.username=username +spring.mail.password=password + +spring.mail.properties.mail.smtp.starttls.enable=true +spring.mail.properties.mail.smtp.auth = true +spring.mail.properties.mail.smtp.socketFactory.port = 465 +spring.mail.properties.mail.smtp.socketFactory.class = javax.net.ssl.SSLSocketFactory +spring.mail.properties.mail.smtp.socketFactory.fallback = false +spring.mail.properties.mail.smtp.ssl.enable=false \ No newline at end of file diff --git a/src/main/resources/static/css/index.css b/src/main/resources/static/css/index.css index debb6d5093a78a712339848412fe77c5f4ad9378..2b1e279bc8a5e9ae24160b4489e0a8dcbc12ba5a 100644 --- a/src/main/resources/static/css/index.css +++ b/src/main/resources/static/css/index.css @@ -1 +1 @@ -.index-gradient{background:linear-gradient(to bottom, #283048 0%, #859398 100%)}.projects-section{padding:10rem 0}.projects-section .featured-text{padding:2rem}@media(min-width: 992px){.projects-section .featured-text{padding:0 0 0 2rem;border-left:.5rem solid #64a19d}}.projects-section .project-text{padding:3rem;font-size:90%}@media(min-width: 992px){.projects-section .project-text{padding:5rem}.projects-section .project-text hr{border-color:#64a19d;border-width:.25rem;width:30%}}.masthead{object-fit:cover !important;text-align:center !important;background-repeat:no-repeat !important;background-attachment:fixed !important;background-position:center !important}.masthead .white{color:#fff}.hide-y{overflow-y:hidden}.landing-info-row{height:100px}.landing-info-row .landing-info-image{height:100px;object-fit:cover;width:100%;text-align:center;background-repeat:no-repeat;background-attachment:fixed;background-position:center}.masthead{position:relative;width:100%;height:auto;min-height:35rem;padding:15rem 0;background-position:center;background-repeat:no-repeat;background-attachment:scroll;background-size:cover}.masthead h1{font-family:"Varela Round";font-size:2.5rem;line-height:2.5rem;letter-spacing:.8rem;background:-webkit-linear-gradient(rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0));-webkit-text-fill-color:transparent;-webkit-background-clip:text}.masthead h2{max-width:20rem;font-size:1rem}@media(min-width: 768px){.masthead h1{font-size:4rem;line-height:4rem}}@media(min-width: 992px){.masthead{height:100vh;padding:0}.masthead h1{font-size:6.5rem;line-height:6.5rem;letter-spacing:.8rem}.masthead h2{max-width:30rem;font-size:1.25rem}}.contact-section{padding:5rem 0 0}.contact-section .card{border:0;border-bottom:.25rem solid #64a19d}.contact-section .card h4{font-size:.8rem;font-family:"Varela Round";text-transform:uppercase;letter-spacing:.15rem}.contact-section .card hr{border-color:#64a19d;border-width:.25rem;width:3rem}.contact-section .social{margin-top:5rem}.contact-section .social a{text-align:center;height:3rem;width:3rem;background:rgba(255,255,255,.1);border-radius:100%;line-height:3rem;color:rgba(255,255,255,.3)}.contact-section .social a:hover{color:rgba(255,255,255,.5)}.contact-section .social a:active{color:#fff}.btn{box-shadow:0 .1875rem .1875rem 0 rgba(0,0,0,.1) !important;padding:1.25rem 2rem;font-family:"Varela Round";font-size:80%;text-transform:uppercase;letter-spacing:.15rem;border:0}.btn-interact{background-color:#64a19d}.btn-interact:hover{background-color:#4f837f}.btn-interact:focus{background-color:#4f837f;color:#fff}.btn-interact:active{background-color:#467370 !important}.about-section{padding-top:10rem}.about-section p{margin-bottom:5rem}/*# sourceMappingURL=index.css.map */ +.index-gradient{background:linear-gradient(to bottom, #283048 0%, #859398 100%)}.projects-section{padding:10rem 0}.projects-section .featured-text{padding:2rem}@media(min-width: 992px){.projects-section .featured-text{padding:0 0 0 2rem;border-left:.5rem solid #64a19d}}.projects-section .project-text{padding:3rem;font-size:90%}@media(min-width: 992px){.projects-section .project-text{padding:5rem}.projects-section .project-text hr{border-color:#64a19d;border-width:.25rem;width:30%}}.masthead{object-fit:cover !important;text-align:center !important;background-repeat:no-repeat !important;background-attachment:fixed !important;background-position:center !important}.masthead .white{color:#fff}.hide-y{overflow-y:hidden}.landing-info-row{height:100px}.landing-info-row .landing-info-image{height:100px;object-fit:cover;width:100%;text-align:center;background-repeat:no-repeat;background-attachment:fixed;background-position:center}.masthead{position:relative;width:100%;height:auto;min-height:35rem;padding:15rem 0;background-position:center;background-repeat:no-repeat;background-attachment:scroll;background-size:cover}.masthead h1{font-family:"Varela Round";font-size:2.5rem;line-height:2.5rem;letter-spacing:.8rem;background:-webkit-linear-gradient(rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0));-webkit-text-fill-color:transparent;-webkit-background-clip:text}.masthead h2{max-width:20rem;font-size:1rem}@media(min-width: 768px){.masthead h1{font-size:4rem;line-height:4rem}}@media(min-width: 992px){.masthead{height:100vh;padding:0}.masthead h1{font-size:6.5rem;line-height:6.5rem;letter-spacing:.8rem}.masthead h2{max-width:30rem;font-size:1.25rem}}.contact-section{padding:5rem 0 0}.contact-section .card{border:0;border-bottom:.25rem solid #64a19d}.contact-section .card h4{font-size:.8rem;font-family:"Varela Round";text-transform:uppercase;letter-spacing:.15rem}.contact-section .card hr{border-color:#64a19d;border-width:.25rem;width:3rem}.contact-section .social{margin-top:5rem}.contact-section .social a{text-align:center;height:3rem;width:3rem;background:rgba(255,255,255,.1);border-radius:100%;line-height:3rem;padding-top:1rem;color:rgba(255,255,255,.3)}.contact-section .social a:hover{color:rgba(255,255,255,.5)}.contact-section .social a:active{color:#fff}.btn{box-shadow:0 .1875rem .1875rem 0 rgba(0,0,0,.1) !important;padding:1.25rem 2rem;font-family:"Varela Round";font-size:80%;text-transform:uppercase;letter-spacing:.15rem;border:0}.btn-interact{background-color:#64a19d}.btn-interact:hover{background-color:#4f837f}.btn-interact:focus{background-color:#4f837f;color:#fff}.btn-interact:active{background-color:#467370 !important}.about-section{padding-top:10rem}.about-section p{margin-bottom:5rem}/*# sourceMappingURL=index.css.map */ diff --git a/src/main/resources/static/css/index.css.map b/src/main/resources/static/css/index.css.map index ac5ec28cec5c7830247919fbb40389de5b05cde7..9de368993141b11db8c8f0765e5adb8c455ce2b7 100644 --- a/src/main/resources/static/css/index.css.map +++ b/src/main/resources/static/css/index.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["../scss/index.scss","../scss/_variables.scss"],"names":[],"mappings":"AAEA,gBACE,gEAGF,kBACE,gBAEA,iCACE,aACA,yBAFF,iCAGI,mBACA,iCAIJ,gCACE,aACA,cACA,yBAHF,gCAII,aACA,mCACE,aCXE,QDYF,oBACA,WAOR,UACE,4BACA,6BACA,uCACA,uCACA,sCAEA,iBACE,WAKJ,QACE,kBAGF,kBACE,aAEA,sCACE,aACA,iBACA,WACA,kBACA,4BACA,4BACA,2BAIJ,UACE,kBACA,WACA,YACA,iBACA,gBACA,2BACA,4BACA,6BACA,sBAEA,aACE,2BACA,iBACA,mBACA,qBACA,qFACA,oCACA,6BAGF,aACE,gBACA,eAGF,yBACE,aACE,eACA,kBAGJ,yBAhCF,UAiCI,aACA,UACA,aACE,iBACA,mBACA,qBAEF,aACE,gBACA,mBAKN,iBACE,iBAEA,uBACE,SACA,mCAEA,0BACE,gBACA,2BACA,yBACA,sBAGF,0BACE,aCjHI,QDkHJ,oBACA,WAIJ,yBACE,gBAEA,2BACE,kBACA,YACA,WACA,gCACA,mBACA,iBACA,2BAEA,iCACE,2BAGF,kCACE,MCpJA,KD0JR,KACE,2DACA,qBACA,2BACA,cACA,yBACA,sBACA,SAGF,cACE,iBCzJQ,QD2JR,oBACE,yBAGF,oBACE,yBACA,WAGF,qBACE,oCAIJ,eACE,kBAEA,iBACE","file":"index.css"} \ No newline at end of file +{"version":3,"sourceRoot":"","sources":["../scss/index.scss","../scss/_variables.scss"],"names":[],"mappings":"AAEA,gBACE,gEAGF,kBACE,gBAEA,iCACE,aACA,yBAFF,iCAGI,mBACA,iCAIJ,gCACE,aACA,cACA,yBAHF,gCAII,aACA,mCACE,aCXE,QDYF,oBACA,WAOR,UACE,4BACA,6BACA,uCACA,uCACA,sCAEA,iBACE,WAKJ,QACE,kBAGF,kBACE,aAEA,sCACE,aACA,iBACA,WACA,kBACA,4BACA,4BACA,2BAIJ,UACE,kBACA,WACA,YACA,iBACA,gBACA,2BACA,4BACA,6BACA,sBAEA,aACE,2BACA,iBACA,mBACA,qBACA,qFACA,oCACA,6BAGF,aACE,gBACA,eAGF,yBACE,aACE,eACA,kBAGJ,yBAhCF,UAiCI,aACA,UACA,aACE,iBACA,mBACA,qBAEF,aACE,gBACA,mBAKN,iBACE,iBAEA,uBACE,SACA,mCAEA,0BACE,gBACA,2BACA,yBACA,sBAGF,0BACE,aCjHI,QDkHJ,oBACA,WAIJ,yBACE,gBAEA,2BACE,kBACA,YACA,WACA,gCACA,mBACA,iBACA,iBACA,2BAEA,iCACE,2BAGF,kCACE,MCrJA,KD2JR,KACE,2DACA,qBACA,2BACA,cACA,yBACA,sBACA,SAGF,cACE,iBC1JQ,QD4JR,oBACE,yBAGF,oBACE,yBACA,WAGF,qBACE,oCAIJ,eACE,kBAEA,iBACE","file":"index.css"} \ No newline at end of file diff --git a/src/main/resources/static/css/subscribes.css b/src/main/resources/static/css/subscribes.css new file mode 100644 index 0000000000000000000000000000000000000000..bddef40a2197a7b43b64c0b9862bb535176e25a8 --- /dev/null +++ b/src/main/resources/static/css/subscribes.css @@ -0,0 +1 @@ +.editing .container{height:100%;display:flex;justify-content:center;align-items:center}.table-padding{padding-top:56px}/*# sourceMappingURL=subscribes.css.map */ diff --git a/src/main/resources/static/css/subscribes.css.map b/src/main/resources/static/css/subscribes.css.map new file mode 100644 index 0000000000000000000000000000000000000000..ca13f09148a7e341d71224b04abdbe028a09bfca --- /dev/null +++ b/src/main/resources/static/css/subscribes.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../scss/cinemas.scss"],"names":[],"mappings":"AAEE,oBACE,YACA,aACA,uBACA,mBAIJ,eACE","file":"subscribes.css"} \ No newline at end of file diff --git a/src/main/resources/static/images/email.jpg b/src/main/resources/static/images/email.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1c0b5ad82dd76e3e7c7ad4c3f1e1e7ff8a2dcfa0 Binary files /dev/null and b/src/main/resources/static/images/email.jpg differ diff --git a/src/main/resources/static/scss/index.scss b/src/main/resources/static/scss/index.scss index 9cd61da7fde0cfeb33ccd958c7eafeecebf4dd4a..eca5788b5a44fa6f3c2588a6fe73a32fce11d3e4 100644 --- a/src/main/resources/static/scss/index.scss +++ b/src/main/resources/static/scss/index.scss @@ -139,6 +139,7 @@ background: fade-out($white, 0.9); border-radius: 100%; line-height: 3rem; + padding-top: 1rem; color: fade-out($white, 0.7); &:hover { diff --git a/src/main/resources/static/scss/subscribes.scss b/src/main/resources/static/scss/subscribes.scss new file mode 100644 index 0000000000000000000000000000000000000000..5743cc609b56787d8ce5ee9d9d10e56fbdeaf990 --- /dev/null +++ b/src/main/resources/static/scss/subscribes.scss @@ -0,0 +1 @@ +@import "cinemas"; \ No newline at end of file diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index 81d4dfdba74410001268d4b148a786847b4ae90a..f61ebdb980d0fd115da98fa7d81fda45b34bd5cd 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -29,7 +29,8 @@ <h2 class="text-white mb-4">Built for cinema business. Built with passion for movies.</h2> <p class="text-white-50"> We are glad to provide you the best possible instrument to manage your cinema network. - Use it to control your cinemas, track tickets to movies, and gather precious data for your business. + Use it to control your cinemas, track tickets to movies, and gather precious data for your + business. System is established to be user-friendly and easy to get on. </p> </div> @@ -80,7 +81,7 @@ </div> <!-- Project Two Row --> - <div class="row justify-content-center hide-y no-gutters"> + <div class="row justify-content-center hide-y no-gutters mt-3"> <div class="col-lg-6"> <img class="pl-3 img-fluid landing-info-image" src="/images/landing_users.jpg" alt=""> @@ -91,7 +92,8 @@ <div class="project-text w-100 my-auto text-center text-lg-left"> <h4 class="text-white">User management</h4> <p class="mb-0 text-white-50"> - Build up your customers database. Track popularity of certain titles and places basing + Build up your customers database. Track popularity of certain titles and places + basing on precious personal data of innocent people, and enjoy the world we live in. </p> <hr class="d-none d-lg-block mb-0 mr-0"> @@ -101,12 +103,36 @@ </div> </div> + <div class="row justify-content-center no-gutters mb-5 mt-3 mb-lg-0"> + <div class="col-lg-6"> + <img class="img-fluid landing-info-image pr-3" + src="/images/email.jpg" alt=""> + </div> + <div class="col-lg-6 order-lg-first"> + <div class="bg-black text-center h-100 project"> + <div class="d-flex h-100"> + <div class="project-text w-100 my-auto text-center text-lg-right"> + <h4 class="text-white">Updates subscription</h4> + <p class="mb-0 text-white-50"> + Stay up to date with the latest site updates. + Track your database changes with only your email. + All updates will be instantly sent to you. </p> + </div> + </div> + </div> + </div> + </div> </div> </section> </div> - +<section class="subscribe-section pt-3 bg-dark"> + <div class="row justify-content-center"> + <a class="btn btn-light mr-2" href="/subscription/subscribe">Subscribe</a> + <a class="btn btn-light ml-2" href="/subscription/unsubscribe">Unsubscribe</a> + </div> +</section> <!-- Contact Section --> -<section class="contact-section mt-3 bg-black"> +<section class="contact-section pt-3 bg-dark"> <div class="container"> <div class="row"> @@ -158,7 +184,7 @@ <a href="#" class="mx-2"> <i class="fab fa-vk"></i> </a> - <a href="https://gitlab.le-memese.com/s3rius/corporative_systems" class="mx-2"> + <a href="https://gitlab.le-memese.com/s3rius/corporative_systems2" class="mx-2"> <i class="fab fa-gitlab"></i> </a> </div> @@ -167,7 +193,7 @@ </section> <!-- Footer --> -<footer class="bg-black small text-center text-black-50"> +<footer class="bg-dark small text-center text-white-50"> <div class="container"> Copyright © le-memese 2019 </div> diff --git a/src/main/resources/templates/subscription/subscribe.html b/src/main/resources/templates/subscription/subscribe.html new file mode 100644 index 0000000000000000000000000000000000000000..a66314e387a21812513695d810f5a711f31abaec --- /dev/null +++ b/src/main/resources/templates/subscription/subscribe.html @@ -0,0 +1,61 @@ +<html xmlns:th="http://www.thymeleaf.org"> +<head> + <title>Edit cinema</title> + <head th:include="commons/imports"></head> + <link rel="stylesheet" href="/css/subscribes.css"> + <script src="/js/subscribe.js"></script> +</head> +<body class="themed-gradient"> + +<!-- Navigation --> +<body th:include="commons/header"></body> + +<div class="editing"> + <div class="container justify-content-center"> + + <form id="cinemaForm" class="d-flex justify-content-center" th:object="${subscriber}" method="post" + action="/subscription/subscribe"> + <fieldset> + + <legend> + <div class="text-center"><h2><b class="white">Subscribe to updates</b></h2></div> + </legend> + <br> + <input type="hidden" name="id" th:field="*{id}"> + + <div class="form-group"> + <div class="inputGroupContainer"> + <div class="input-group"> + <div class="input-group-prepend"> + <div class="input-group-text"><i class="fas fa-envelope"></i></div> + </div> + <input type="text" + class="form-control validate" + id="Email" + name="email" + placeholder="User's email" th:field="*{email}" required> + </div> + </div> + </div> + <div class="form-group"> + <div class="inputGroupContainer"> + <div class="input-group"> +<!-- <div class="input-group-prepend">--> +<!-- <div class="input-group-text"><i class="fas fa-chair"></i></div>--> +<!-- </div>--> + <div class="form-check" th:each="item: ${types}"> + <input type="checkbox" class="form-check-input" name="actions" th:value="${item}"> + <label th:text="${item.str}" class="text-white pr-2"></label> + </div> + </div> + </div> + </div> + <div class="justify-content-center"> + <button type="submit" class="btn btn-primary w-100"><i class="fas fa-check"></i>Submit</button> + </div> + </fieldset> + </form> + </div> +</div> +</body> +</html> diff --git a/src/main/resources/templates/subscription/unsubscribe.html b/src/main/resources/templates/subscription/unsubscribe.html new file mode 100644 index 0000000000000000000000000000000000000000..3e625399c170d1a15bf9e121a62e38cb0d92e35b --- /dev/null +++ b/src/main/resources/templates/subscription/unsubscribe.html @@ -0,0 +1,46 @@ +<html xmlns:th="http://www.thymeleaf.org"> +<head> + <title>Edit cinema</title> + <head th:include="commons/imports"></head> + <link rel="stylesheet" href="/css/subscribes.css"> + <script src="/js/subscribe.js"></script> +</head> +<body class="themed-gradient"> + +<!-- Navigation --> +<body th:include="commons/header"></body> + +<div class="editing"> + <div class="container justify-content-center"> + + <form id="cinemaForm" class="d-flex justify-content-center" method="post" + action="/subscription/unsubscribe"> + <fieldset> + + <legend> + <div class="text-center"><h2><b class="white">Subscribe to updates</b></h2></div> + </legend> + <br> + + <div class="form-group"> + <div class="inputGroupContainer"> + <div class="input-group"> + <div class="input-group-prepend"> + <div class="input-group-text"><i class="fas fa-envelope"></i></div> + </div> + <input type="text" + class="form-control validate" + id="Email" + placeholder="User's email" name="email" required> + </div> + </div> + </div> + <div class="justify-content-center"> + <button type="submit" class="btn btn-primary w-100"><i class="fas fa-check"></i>Submit</button> + </div> + </fieldset> + </form> + </div> +</div> +</body> +</html> diff --git a/src/test/kotlin/com/s3ai/corporate_app2/CinemasApiTest.kt b/src/test/kotlin/com/s3ai/corporate_app2/CinemasApiTest.kt deleted file mode 100644 index 62638c0e392479447fc5b58bcfd215c8b9d24e5f..0000000000000000000000000000000000000000 --- a/src/test/kotlin/com/s3ai/corporate_app2/CinemasApiTest.kt +++ /dev/null @@ -1,108 +0,0 @@ -package com.s3ai.corporate_app2 - -import com.s3ai.corporate_app2.controllers.CinemasController -import com.s3ai.corporate_app2.controllers.rest.CinemaApiController -import org.assertj.core.api.Assertions.assertThat -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.http.MediaType -import org.springframework.test.context.jdbc.Sql -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get -import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status -import org.springframework.ui.ExtendedModelMap -import java.util.* - - -@SpringBootTest -@AutoConfigureMockMvc -class CinemasApiTest { - @Autowired - private lateinit var controller: CinemasController - - @Autowired - private lateinit var mvc: MockMvc - - @Autowired - private lateinit var apiController: CinemaApiController - - @Test - @Throws(Exception::class) - fun contextLoads() { - assertThat(controller).isNotNull - assertThat(apiController).isNotNull - } - - @Test - @Throws(Exception::class) - fun shouldUpdateCinema() { - val cinema = Cinema() - val id = UUID.randomUUID() - cinema.id = id - cinema.name = "test" - controller.updateCinema(cinema) - val cinemaFromBase = controller.cinemaService.findById(id) - assertThat(cinemaFromBase?.equals(cinema)) - } - - @Test - @Throws(Exception::class) - fun shouldRedirectToCreateCinemaIfIdNotExists() { - val model = ExtendedModelMap() - val redirect = controller.getCinemaEditPage(UUID.randomUUID().toString(), model) - assertThat(redirect.equals("cinemas/edit")) - assertThat(model.getValue("action") == "Create") - } - - @Test - @Throws(Exception::class) - fun shouldRedirectToEditCinemaIfIdExists() { - val cinema = Cinema() - val id = UUID.randomUUID() - cinema.id = id - cinema.name = "test" - controller.updateCinema(cinema) - val model = ExtendedModelMap() - val redirect = controller.getCinemaEditPage(id.toString(), model) - assertThat(redirect.equals("cinemas/edit")) - assertThat(model.getValue("action") == "Edit") - } - - @Test - @Throws(Exception::class) - fun shouldReturnCinemasBrowsePage() { - val cinema = Cinema() - val id = UUID.randomUUID() - cinema.id = id - cinema.name = "test" - controller.updateCinema(cinema) - val model = ExtendedModelMap() - val redirect = controller.getCinemasBrowsePage(model) - assertThat(redirect.equals("cinemas/list")) - assertThat(model.getValue("cinemas")).isNotNull - } - - @Test - @Sql("/cinemasFill.sql") - fun mvcTest() { - mvc.perform(get("/api/json/cinemas/all") - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk) - } - -// @Test -// @Throws(Exception::class) -// fun shouldDeleteCinema() { -// val cinema = Cinema() -// val id = UUID.randomUUID() -// cinema.id = id -// cinema.name = "test" -// controller.updateCinema(cinema) -// var responce = HttpResponseFactory -// apiController.deleteCinema(id.toString(), Http) -// val cinemaFromBase = controller.cinemaService.findById(id) -// assertThat(cinemaFromBase?.equals(cinema)) -// } -} diff --git a/src/test/kotlin/com/s3ai/corporate_app2/TestUtils.kt b/src/test/kotlin/com/s3ai/corporate_app2/TestUtils.kt index ab3d40a1fe353957cd6572e1219fd29f7c3625c3..35ecbafd6d837aa4a297382b27b97436ee26f60c 100644 --- a/src/test/kotlin/com/s3ai/corporate_app2/TestUtils.kt +++ b/src/test/kotlin/com/s3ai/corporate_app2/TestUtils.kt @@ -1,3 +1,17 @@ package com.s3ai.corporate_app2 +import com.fasterxml.jackson.databind.DeserializationFeature +import com.fasterxml.jackson.databind.MapperFeature +import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule +import com.fasterxml.jackson.dataformat.xml.XmlMapper +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.fasterxml.jackson.module.kotlin.registerKotlinModule + +internal val kotlinXmlMapper = XmlMapper(JacksonXmlModule().apply { + setDefaultUseWrapper(false) +}).registerKotlinModule() + .configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + +internal val kotlinJsonMapper = jacksonObjectMapper() \ No newline at end of file diff --git a/src/test/kotlin/com/s3ai/corporate_app2/TicketsApiTest.kt b/src/test/kotlin/com/s3ai/corporate_app2/TicketsApiTest.kt deleted file mode 100644 index 1b91a80ea29649545401550f4d643d3edf59a5d1..0000000000000000000000000000000000000000 --- a/src/test/kotlin/com/s3ai/corporate_app2/TicketsApiTest.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.s3ai.corporate_app2 - -import com.s3ai.corporate_app2.controllers.TicketsController -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.ui.ExtendedModelMap -import java.util.* - - -@SpringBootTest -class TicketsApiTest { - @Autowired - private lateinit var controller: TicketsController - - @Test - @Throws(Exception::class) - fun contextLoads() { - assertThat(controller).isNotNull - } - - @Test - @Throws(Exception::class) - fun shouldUpdateTicket() { - val ticket = Ticket() - val id = UUID.randomUUID() - ticket.id = id - ticket.movie = "test" - controller.updateTicket(ticket) - val ticketFromBase = controller.ticketService.findById(id) - assertThat(ticketFromBase?.equals(ticket)) - } - - @Test - @Throws(Exception::class) - fun shouldRedirectToCreateTicketIfIdNotExists() { - val model = ExtendedModelMap() - val redirect = controller.getTicketEditPage(UUID.randomUUID().toString(), model) - assertThat(redirect.equals("tickets/edit")) - assertThat(model.getValue("action") == "Create") - } - - @Test - @Throws(Exception::class) - fun shouldRedirectToEditCinemaIfIdExists() { - val ticket = Ticket() - val id = UUID.randomUUID() - ticket.id = id - ticket.movie = "test" - controller.updateTicket(ticket) - val model = ExtendedModelMap() - val redirect = controller.getTicketEditPage(id.toString(), model) - assertThat(redirect.equals("tickets/edit")) - assertThat(model.getValue("action") == "Edit") - } - - @Test - @Throws(Exception::class) - fun shouldReturnTicketsBrowsePage() { - val ticket = Ticket() - val id = UUID.randomUUID() - ticket.id = id - ticket.movie = "test" - controller.updateTicket(ticket) - val model = ExtendedModelMap() - val redirect = controller.getTicketsBrowsePage(model) - assertThat(redirect.equals("tickets/list")) - assertThat(model.getValue("tickets")).isNotNull - } -} \ No newline at end of file diff --git a/src/test/kotlin/com/s3ai/corporate_app2/UsersApiTest.kt b/src/test/kotlin/com/s3ai/corporate_app2/UsersApiTest.kt deleted file mode 100644 index 8ff981ce7a1460d4f2aa70771a06a0845e497a6f..0000000000000000000000000000000000000000 --- a/src/test/kotlin/com/s3ai/corporate_app2/UsersApiTest.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.s3ai.corporate_app2 - -import com.s3ai.corporate_app2.controllers.UsersController -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.ui.ExtendedModelMap -import java.util.* - - -@SpringBootTest -class UsersApiTest { - @Autowired - private lateinit var controller: UsersController - - @Test - @Throws(Exception::class) - fun contextLoads() { - assertThat(controller).isNotNull - } - - @Test - @Throws(Exception::class) - fun shouldUpdateCinema() { - val user = User() - val id = UUID.randomUUID() - user.id = id - user.name = "test" - controller.updateUser(user) - val userFromBase = controller.userService.findById(id) - assertThat(userFromBase?.equals(user)) - } - - @Test - @Throws(Exception::class) - fun shouldRedirectToCreateUserIfIdNotExists() { - val model = ExtendedModelMap() - val redirect = controller.getUserEditPage(UUID.randomUUID().toString(), model) - assertThat(redirect.equals("users/edit")) - assertThat(model.getValue("action") == "Create") - } - - @Test - @Throws(Exception::class) - fun shouldRedirectToEditCinemaIfIdExists() { - val user = User() - val id = UUID.randomUUID() - user.id = id - user.name = "test" - controller.updateUser(user) - val model = ExtendedModelMap() - val redirect = controller.getUserEditPage(id.toString(), model) - assertThat(redirect.equals("users/edit")) - assertThat(model.getValue("action") == "Edit") - } - - @Test - @Throws(Exception::class) - fun shouldReturnUsersBrowsePage() { - val user = User() - val id = UUID.randomUUID() - user.id = id - user.name = "test" - controller.updateUser(user) - val model = ExtendedModelMap() - val redirect = controller.getUsersBrowsePage(model) - assertThat(redirect.equals("users/list")) - assertThat(model.getValue("users")).isNotNull - } -} diff --git a/src/test/kotlin/com/s3ai/corporate_app2/controllers/CinemasTest.kt b/src/test/kotlin/com/s3ai/corporate_app2/controllers/CinemasTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..a159c661f33daae4542306f98cb1d877a47d27c6 --- /dev/null +++ b/src/test/kotlin/com/s3ai/corporate_app2/controllers/CinemasTest.kt @@ -0,0 +1,104 @@ +package com.s3ai.corporate_app2.controllers + +import com.fasterxml.jackson.databind.ObjectMapper +import com.s3ai.corporate_app2.Cinema +import com.s3ai.corporate_app2.CinemaService +import org.assertj.core.api.Assertions.assertThat +import org.hamcrest.Matchers +import org.hamcrest.CoreMatchers +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.http.MediaType +import org.springframework.test.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.* +import java.lang.reflect.GenericArrayType +import java.util.* + + +@SpringBootTest +@AutoConfigureMockMvc +class CinemasTest { + @Autowired + private lateinit var service: CinemaService + + @Autowired + private lateinit var controller: CinemasController + + @Autowired + private lateinit var mvc: MockMvc + + @Test + @Throws(Exception::class) + fun contextLoads() { + assertThat(controller).isNotNull + } + + @Test + @Throws(Exception::class) + @Sql("/cinemasFill.sql") + fun updateCinemaTest() { + val cinema = service.findAll().random() + print(cinema.id) + + cinema.name = UUID.randomUUID().toString() + + mvc.perform(MockMvcRequestBuilders.post("/cinemas/update") + .contentType(MediaType.APPLICATION_JSON) + .content(ObjectMapper().writeValueAsString(cinema))) + .andExpect(status().isFound) + .andExpect(redirectedUrl("/cinemas/list")) + + val updatedCinema = service.findById(cinema.id!!) + assertThat(cinema == updatedCinema) + } + + @Test + @Throws(Exception::class) + fun editNonExistingIdRedirectToCreateTest() { + mvc.perform(MockMvcRequestBuilders.get("/cinemas/edit")) + .andExpect(status().isOk) + .andExpect(model().attribute("action", Matchers.equalTo("Create"))) + .andExpect(model().attribute("cinema", Matchers.notNullValue(Cinema::class.java))) + } + + @Test + @Throws(Exception::class) + @Sql("/cinemasFill.sql") + fun editPageTest() { + val randomCinemaId = service.findAll().map { e -> e.id }.distinct().random() + mvc.perform(MockMvcRequestBuilders.get("/cinemas/edit?id=${randomCinemaId}")) + .andExpect(status().isOk) + .andExpect(model().attribute("action", Matchers.equalTo("Edit"))) + .andExpect(model().attribute("cinema", Matchers.notNullValue(Cinema::class.java))) + } + + @Test + @Throws(Exception::class) + @Sql("/cinemasFill.sql") + fun listPageTest() { + mvc.perform(MockMvcRequestBuilders.get("/cinemas/list")) + .andExpect(status().isOk) + .andExpect(model().attribute("cinemas", Matchers.notNullValue(MutableCollection::class.java))) + .andExpect(model().attribute("cinemas", CoreMatchers.everyItem(Matchers.notNullValue(Cinema::class.java)))) + } + + @Test + @Throws(Exception::class) + fun listEmptyPageTest() { + mvc.perform(MockMvcRequestBuilders.get("/cinemas/list")) + .andExpect(status().isOk) + .andExpect(model().attribute("cinemas", Matchers.notNullValue(MutableCollection::class.java))) + } + + @Test + @Throws(Exception::class) + fun editInvalidUUIDTest() { + mvc.perform(MockMvcRequestBuilders.get("/cinemas/edit?id=totallyNotAnUUID")) + .andExpect(MockMvcResultMatchers.status().isBadRequest) + } +} diff --git a/src/test/kotlin/com/s3ai/corporate_app2/controllers/TicketsTest.kt b/src/test/kotlin/com/s3ai/corporate_app2/controllers/TicketsTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..9a0b14735ca98106de3271b0e7487d3f2c86111f --- /dev/null +++ b/src/test/kotlin/com/s3ai/corporate_app2/controllers/TicketsTest.kt @@ -0,0 +1,102 @@ +package com.s3ai.corporate_app2.controllers + +import com.fasterxml.jackson.databind.ObjectMapper +import com.s3ai.corporate_app2.Ticket +import com.s3ai.corporate_app2.TicketService +import com.s3ai.corporate_app2.User +import org.assertj.core.api.Assertions.assertThat +import org.hamcrest.CoreMatchers +import org.hamcrest.Matchers +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.http.MediaType +import org.springframework.test.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import java.util.* + + +@SpringBootTest +@AutoConfigureMockMvc +class TicketsTest { + @Autowired + private lateinit var service: TicketService + + @Autowired + private lateinit var controller: TicketsController + + @Autowired + private lateinit var mvc: MockMvc + + @Test + @Throws(Exception::class) + fun contextLoads() { + assertThat(controller).isNotNull + } + + @Test + @Throws(Exception::class) + @Sql("/cinemasFill.sql", "/usersFill.sql", "/ticketsFill.sql") + fun updateTicketTest() { + val ticket = service.findAll().random() + print(ticket.id) + + ticket.movie = UUID.randomUUID().toString() + + mvc.perform(MockMvcRequestBuilders.post("/tickets/update") + .contentType(MediaType.APPLICATION_JSON) + .content(ObjectMapper().writeValueAsString(ticket))) + .andExpect(MockMvcResultMatchers.status().isFound) + .andExpect(MockMvcResultMatchers.redirectedUrl("/tickets/list")) + + val updatedTicket = service.findById(ticket.id!!) + assertThat(ticket == updatedTicket) + } + + @Test + @Throws(Exception::class) + fun editNonExistingIdRedirectToCreateTest() { + mvc.perform(MockMvcRequestBuilders.get("/tickets/edit")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andExpect(MockMvcResultMatchers.model().attribute("action", Matchers.equalTo("Create"))) + .andExpect(MockMvcResultMatchers.model().attribute("ticket", Matchers.notNullValue(Ticket::class.java))) + } + + @Test + @Throws(Exception::class) + @Sql("/cinemasFill.sql", "/usersFill.sql", "/ticketsFill.sql") + fun editPageTest() { + val randomTicketId = service.findAll().map { e -> e.id }.distinct().random() + mvc.perform(MockMvcRequestBuilders.get("/tickets/edit?id=${randomTicketId}")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andExpect(MockMvcResultMatchers.model().attribute("action", Matchers.equalTo("Edit"))) + .andExpect(MockMvcResultMatchers.model().attribute("ticket", Matchers.notNullValue(Ticket::class.java))) + } + + @Test + @Throws(Exception::class) + @Sql("/cinemasFill.sql", "/usersFill.sql", "/ticketsFill.sql") + fun listPageTest() { + mvc.perform(MockMvcRequestBuilders.get("/tickets/list")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andExpect(MockMvcResultMatchers.model().attribute("tickets", CoreMatchers.everyItem(Matchers.notNullValue(Ticket::class.java)))) + } + + @Test + @Throws(Exception::class) + fun listEmptyPageTest() { + mvc.perform(MockMvcRequestBuilders.get("/tickets/list")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andExpect(MockMvcResultMatchers.model().attribute("tickets", Matchers.notNullValue(MutableCollection::class.java))) + } + + @Test + @Throws(Exception::class) + fun editInvalidUUIDTest() { + mvc.perform(MockMvcRequestBuilders.get("/tickets/edit?id=totallyNotAnUUID")) + .andExpect(MockMvcResultMatchers.status().isBadRequest) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/s3ai/corporate_app2/controllers/UsersTest.kt b/src/test/kotlin/com/s3ai/corporate_app2/controllers/UsersTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..f58ead09f91aa5476fe0c571e19e434f58402951 --- /dev/null +++ b/src/test/kotlin/com/s3ai/corporate_app2/controllers/UsersTest.kt @@ -0,0 +1,103 @@ +package com.s3ai.corporate_app2.controllers + +import com.fasterxml.jackson.databind.ObjectMapper +import com.s3ai.corporate_app2.Cinema +import com.s3ai.corporate_app2.User +import com.s3ai.corporate_app2.UserService +import org.assertj.core.api.Assertions.assertThat +import org.hamcrest.CoreMatchers +import org.hamcrest.CoreMatchers.everyItem +import org.hamcrest.Matchers +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.http.MediaType +import org.springframework.test.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import java.util.* + + +@SpringBootTest +@AutoConfigureMockMvc +class UsersTest { + @Autowired + private lateinit var service: UserService + + @Autowired + private lateinit var controller: UsersController + + @Autowired + private lateinit var mvc: MockMvc + + @Test + @Throws(Exception::class) + fun contextLoads() { + assertThat(controller).isNotNull + } + + @Test + @Throws(Exception::class) + @Sql("/usersFill.sql") + fun updateUserTest() { + val user = service.findAll().random() + print(user.id) + + user.name = UUID.randomUUID().toString() + + mvc.perform(MockMvcRequestBuilders.post("/users/update") + .contentType(MediaType.APPLICATION_JSON) + .content(ObjectMapper().writeValueAsString(user))) + .andExpect(MockMvcResultMatchers.status().isFound) + .andExpect(MockMvcResultMatchers.redirectedUrl("/users/list")) + + val updatedUser = service.findById(user.id!!) + assertThat(user == updatedUser) + } + + @Test + @Throws(Exception::class) + fun editNonExistingIdRedirectToCreateTest() { + mvc.perform(MockMvcRequestBuilders.get("/users/edit")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andExpect(MockMvcResultMatchers.model().attribute("action", Matchers.equalTo("Create"))) + .andExpect(MockMvcResultMatchers.model().attribute("user", Matchers.notNullValue(User::class.java))) + } + + @Test + @Throws(Exception::class) + @Sql("/usersFill.sql") + fun editPageTest() { + val randomUserId = service.findAll().map { e -> e.id }.distinct().random() + mvc.perform(MockMvcRequestBuilders.get("/users/edit?id=${randomUserId}")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andExpect(MockMvcResultMatchers.model().attribute("action", Matchers.equalTo("Edit"))) + .andExpect(MockMvcResultMatchers.model().attribute("user", Matchers.notNullValue(User::class.java))) + } + + @Test + @Throws(Exception::class) + @Sql("/usersFill.sql") + fun listPageTest() { + mvc.perform(MockMvcRequestBuilders.get("/users/list")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andExpect(MockMvcResultMatchers.model().attribute("users", everyItem(Matchers.notNullValue(User::class.java)))) + } + + @Test + @Throws(Exception::class) + fun listEmptyPageTest() { + mvc.perform(MockMvcRequestBuilders.get("/users/list")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andExpect(MockMvcResultMatchers.model().attribute("users", Matchers.notNullValue(MutableCollection::class.java))) + } + + @Test + @Throws(Exception::class) + fun editInvalidUUIDTest() { + mvc.perform(MockMvcRequestBuilders.get("/users/edit?id=totallyNotAnUUID")) + .andExpect(MockMvcResultMatchers.status().isBadRequest) + } +} diff --git a/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/CinemaApiTest.kt b/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/CinemaApiTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..f2692518bd8857143bc1b807f8c49ae8bbac6f75 --- /dev/null +++ b/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/CinemaApiTest.kt @@ -0,0 +1,78 @@ +package com.s3ai.corporate_app2.controllers.rest + +import com.s3ai.corporate_app2.CinemaService +import com.s3ai.corporate_app2.TicketService +import org.assertj.core.api.Assertions +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.hasItem +import org.hamcrest.core.IsNot.not +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.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.MvcResult +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import java.util.* + +@SpringBootTest +@AutoConfigureMockMvc +class CinemaApiTest { + @Autowired + private lateinit var service: CinemaService + + @Autowired + private lateinit var ticketService: TicketService + + @Autowired + private lateinit var mvc: MockMvc + + @Test + @Throws(Exception::class) + fun contextLoads() { + Assertions.assertThat(mvc).isNotNull + Assertions.assertThat(service).isNotNull + } + + @Test + @Sql("/cinemasFill.sql") + fun fillTest() { + mvc.perform(get("/api/cinemas/fill")) + .andDo { e: MvcResult -> println(e.response) } + .andExpect(status().isOk) + assertThat(service.findAll().size, equalTo(401)) + } + + @Test + @Sql("/cinemasFill.sql", "/usersFill.sql", "/ticketsFill.sql") + fun deleteTest() { + val randomCinemaId = ticketService.findAll().map { e -> e.cinema?.id }.distinct().random() + print(randomCinemaId) + mvc.perform(delete("/api/cinemas/delete?id=${randomCinemaId}")) + .andExpect(status().isOk) + val tickets = ticketService.findAll().map { e -> e.cinema!!.id }.distinct() + assertThat(tickets, not(hasItem(randomCinemaId))) + } + + @Test + @Sql("/cinemasFill.sql", "/usersFill.sql", "/ticketsFill.sql") + fun deleteNonExistingIdReturns404Test() { + val randomCinemaId = UUID.randomUUID() + print(randomCinemaId) + mvc.perform(delete("/api/cinemas/delete?id=${randomCinemaId}")) + .andExpect(status().isNotFound) + } + + @Test + @Throws(Exception::class) + fun deleteInvalidUUIDTest() { + mvc.perform(delete("/api/cinemas/delete?id=totallyNotAnUUID")) + .andExpect(status().isBadRequest) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/TicketApiTest.kt b/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/TicketApiTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..b493ac1a651e2107b84b98e66f3949e517039be7 --- /dev/null +++ b/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/TicketApiTest.kt @@ -0,0 +1,70 @@ +package com.s3ai.corporate_app2.controllers.rest + +import com.s3ai.corporate_app2.TicketService +import org.assertj.core.api.Assertions +import org.hamcrest.MatcherAssert +import org.hamcrest.Matchers +import org.hamcrest.core.IsNot +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.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.MvcResult +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import java.util.* + +@SpringBootTest +@AutoConfigureMockMvc +class TicketApiTest { + @Autowired + private lateinit var service: TicketService + + @Autowired + private lateinit var mvc: MockMvc + + @Test + @Throws(Exception::class) + fun contextLoads() { + Assertions.assertThat(mvc).isNotNull + Assertions.assertThat(service).isNotNull + } + + @Test + @Sql("/cinemasFill.sql", "/usersFill.sql", "/ticketsFill.sql") + fun fillTest() { + mvc.perform(MockMvcRequestBuilders.get("/api/tickets/fill")) + .andDo { e: MvcResult -> println(e.response) } + .andExpect(MockMvcResultMatchers.status().isOk) + MatcherAssert.assertThat(service.findAll().size, Matchers.equalTo(401)) + } + + @Test + @Sql("/cinemasFill.sql", "/usersFill.sql", "/ticketsFill.sql") + fun deleteTest() { + val randomTicketId = service.findAll().map { e -> e.id }.distinct().random() + print(randomTicketId) + mvc.perform(MockMvcRequestBuilders.delete("/api/tickets/delete?id=${randomTicketId}")) + .andExpect(MockMvcResultMatchers.status().isOk) + val tickets = service.findAll().map { e -> e.id }.distinct() + MatcherAssert.assertThat(tickets, IsNot.not(Matchers.hasItem(randomTicketId))) + } + + @Test + @Sql("/cinemasFill.sql", "/usersFill.sql", "/ticketsFill.sql") + fun deleteNonExistingIdReturns404Test() { + val randomTicketId = UUID.randomUUID() + print(randomTicketId) + mvc.perform(MockMvcRequestBuilders.delete("/api/tickets/delete?id=${randomTicketId}")) + .andExpect(MockMvcResultMatchers.status().isNotFound) + } + + @Test + @Throws(Exception::class) + fun deleteInvalidUUIDTest() { + mvc.perform(MockMvcRequestBuilders.delete("/api/tickets/delete?id=totallyNotAnUUID")) + .andExpect(MockMvcResultMatchers.status().isBadRequest) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/UserApiTest.kt b/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/UserApiTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..55ee715ba587b189d34b3f930169adb6c6e7dbe4 --- /dev/null +++ b/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/UserApiTest.kt @@ -0,0 +1,74 @@ +package com.s3ai.corporate_app2.controllers.rest + +import com.s3ai.corporate_app2.UserService +import com.s3ai.corporate_app2.TicketService +import org.assertj.core.api.Assertions +import org.hamcrest.MatcherAssert +import org.hamcrest.Matchers +import org.hamcrest.core.IsNot +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.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.MvcResult +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import java.util.* + +@SpringBootTest +@AutoConfigureMockMvc +class UserApiTest { + @Autowired + private lateinit var service: UserService + + @Autowired + private lateinit var ticketService: TicketService + + @Autowired + private lateinit var mvc: MockMvc + + @Test + @Throws(Exception::class) + fun contextLoads() { + Assertions.assertThat(mvc).isNotNull + Assertions.assertThat(service).isNotNull + } + + @Test + @Sql("/usersFill.sql") + fun fillTest() { + mvc.perform(MockMvcRequestBuilders.get("/api/users/fill")) + .andDo { e: MvcResult -> println(e.response) } + .andExpect(MockMvcResultMatchers.status().isOk) + MatcherAssert.assertThat(service.findAll().size, Matchers.equalTo(401)) + } + + @Test + @Sql("/usersFill.sql", "/cinemasFill.sql", "/ticketsFill.sql") + fun deleteTest() { + val randomUserId = ticketService.findAll().map { e -> e.user?.id }.distinct().random() + print(randomUserId) + mvc.perform(MockMvcRequestBuilders.delete("/api/users/delete?id=${randomUserId}")) + .andExpect(MockMvcResultMatchers.status().isOk) + val tickets = ticketService.findAll().map { e -> e.user!!.id }.distinct() + MatcherAssert.assertThat(tickets, IsNot.not(Matchers.hasItem(randomUserId))) + } + + @Test + @Sql("/usersFill.sql", "/cinemasFill.sql", "/ticketsFill.sql") + fun deleteNonExistingIdReturns404Test() { + val randomUserId = UUID.randomUUID() + print(randomUserId) + mvc.perform(MockMvcRequestBuilders.delete("/api/users/delete?id=${randomUserId}")) + .andExpect(MockMvcResultMatchers.status().isNotFound) + } + + @Test + @Throws(Exception::class) + fun deleteInvalidUUIDTest() { + mvc.perform(MockMvcRequestBuilders.delete("/api/users/delete?id=totallyNotAnUUID")) + .andExpect(MockMvcResultMatchers.status().isBadRequest) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/formats/CinemasFormattingTests.kt b/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/formats/CinemasFormattingTests.kt new file mode 100644 index 0000000000000000000000000000000000000000..5428d37656617d791a2a8d38f3fdf0aab91e7e73 --- /dev/null +++ b/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/formats/CinemasFormattingTests.kt @@ -0,0 +1,84 @@ +package com.s3ai.corporate_app2.controllers.rest.formats + +import com.fasterxml.jackson.databind.DeserializationFeature +import com.fasterxml.jackson.databind.MapperFeature +import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule +import com.fasterxml.jackson.dataformat.xml.XmlMapper +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import com.fasterxml.jackson.module.kotlin.registerKotlinModule +import com.s3ai.corporate_app2.Cinema +import com.s3ai.corporate_app2.CinemaService +import com.s3ai.corporate_app2.kotlinJsonMapper +import com.s3ai.corporate_app2.kotlinXmlMapper +import org.assertj.core.api.Assertions +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +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.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers + + +@SpringBootTest +@AutoConfigureMockMvc +class CinemasFormattingTests { + @Autowired + private lateinit var service: CinemaService + + @Autowired + private lateinit var mvc: MockMvc + + @Test + @Throws(Exception::class) + fun contextLoads() { + Assertions.assertThat(mvc).isNotNull + Assertions.assertThat(service).isNotNull + } + + @Test + @Sql("/cinemasFill.sql") + fun allJSONTest() { + val mvcResult = mvc.perform(MockMvcRequestBuilders.get("/api/json/cinemas/all")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + val cinemas: List<Cinema> = kotlinJsonMapper.readValue(mvcResult.response.contentAsString) + assertThat(cinemas.size, equalTo(100)) + } + + @Test + @Sql("/cinemasFill.sql") + fun itemJSONTest() { + val randomCinema = service.findAll().random() + val mvcResult = mvc.perform(MockMvcRequestBuilders.get("/api/json/cinemas/item/${randomCinema.id}")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + val parsedCinema: Cinema = kotlinJsonMapper.readValue(mvcResult.response.contentAsString) + assertThat(parsedCinema.toString(), equalTo(randomCinema.toString())) + } + + @Test + @Sql("/cinemasFill.sql") + fun allXMLTest() { + val mvcResult = mvc.perform(MockMvcRequestBuilders.get("/api/xml/cinemas/all")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + val cinemas: List<Cinema> = kotlinXmlMapper.readValue(mvcResult.response.contentAsString) + assertThat(cinemas.size, equalTo(100)) + } + + @Test + @Sql("/cinemasFill.sql") + fun itemXMLTest() { + val randomCinema = service.findAll().random() + val mvcResult = mvc.perform(MockMvcRequestBuilders.get("/api/xml/cinemas/item/${randomCinema.id}")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + val parsedCinema: Cinema = kotlinXmlMapper.readValue(mvcResult.response.contentAsString) + assertThat(parsedCinema.toString(), equalTo(randomCinema.toString())) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/formats/TicketsFormattingTests.kt b/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/formats/TicketsFormattingTests.kt new file mode 100644 index 0000000000000000000000000000000000000000..2af121d0cada32827f2dc4632132b4022b384778 --- /dev/null +++ b/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/formats/TicketsFormattingTests.kt @@ -0,0 +1,78 @@ +package com.s3ai.corporate_app2.controllers.rest.formats + +import com.fasterxml.jackson.module.kotlin.readValue +import com.s3ai.corporate_app2.Ticket +import com.s3ai.corporate_app2.TicketService +import com.s3ai.corporate_app2.kotlinJsonMapper +import com.s3ai.corporate_app2.kotlinXmlMapper +import org.assertj.core.api.Assertions +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +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.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers + + +@SpringBootTest +@AutoConfigureMockMvc +class TicketsFormattingTests { + @Autowired + private lateinit var service: TicketService + + @Autowired + private lateinit var mvc: MockMvc + + @Test + @Throws(Exception::class) + fun contextLoads() { + Assertions.assertThat(mvc).isNotNull + Assertions.assertThat(service).isNotNull + } + + @Test + @Sql("/cinemasFill.sql", "/usersFill.sql", "/ticketsFill.sql") + fun allJSONTest() { + val mvcResult = mvc.perform(MockMvcRequestBuilders.get("/api/json/tickets/all")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + val cinemas: List<Ticket> = kotlinJsonMapper.readValue(mvcResult.response.contentAsString) + assertThat(cinemas.size, equalTo(100)) + } + + @Test + @Sql("/cinemasFill.sql", "/usersFill.sql", "/ticketsFill.sql") + fun itemJSONTest() { + val randomTicket = service.findAll().random() + val mvcResult = mvc.perform(MockMvcRequestBuilders.get("/api/json/tickets/item/${randomTicket.id}")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + val parsedTicket: Ticket = kotlinJsonMapper.readValue(mvcResult.response.contentAsString) + assertThat(parsedTicket.toString(), equalTo(randomTicket.toString())) + } + + @Test + @Sql("/cinemasFill.sql", "/usersFill.sql", "/ticketsFill.sql") + fun allXMLTest() { + val mvcResult = mvc.perform(MockMvcRequestBuilders.get("/api/xml/tickets/all")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + val cinemas: List<Ticket> = kotlinXmlMapper.readValue(mvcResult.response.contentAsString) + assertThat(cinemas.size, equalTo(100)) + } + + @Test + @Sql("/cinemasFill.sql", "/usersFill.sql", "/ticketsFill.sql") + fun itemXMLTest() { + val randomTicket = service.findAll().random() + val mvcResult = mvc.perform(MockMvcRequestBuilders.get("/api/xml/tickets/item/${randomTicket.id}")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + val parsedTicket: Ticket = kotlinXmlMapper.readValue(mvcResult.response.contentAsString) + assertThat(parsedTicket.toString(), equalTo(randomTicket.toString())) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/formats/UsersFormattingTests.kt b/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/formats/UsersFormattingTests.kt new file mode 100644 index 0000000000000000000000000000000000000000..a6cd837e536d68cd4acbdde5c6bdbb0c998d45cc --- /dev/null +++ b/src/test/kotlin/com/s3ai/corporate_app2/controllers/rest/formats/UsersFormattingTests.kt @@ -0,0 +1,83 @@ +package com.s3ai.corporate_app2.controllers.rest.formats + +import com.fasterxml.jackson.databind.DeserializationFeature +import com.fasterxml.jackson.databind.MapperFeature +import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule +import com.fasterxml.jackson.dataformat.xml.XmlMapper +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import com.fasterxml.jackson.module.kotlin.registerKotlinModule +import com.s3ai.corporate_app2.* +import com.s3ai.corporate_app2.kotlinJsonMapper +import com.s3ai.corporate_app2.kotlinXmlMapper +import org.assertj.core.api.Assertions +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +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.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers + + +@SpringBootTest +@AutoConfigureMockMvc +class UsersFormattingTests { + @Autowired + private lateinit var service: UserService + + @Autowired + private lateinit var mvc: MockMvc + + @Test + @Throws(Exception::class) + fun contextLoads() { + Assertions.assertThat(mvc).isNotNull + Assertions.assertThat(service).isNotNull + } + + @Test + @Sql("/usersFill.sql") + fun allJSONTest() { + val mvcResult = mvc.perform(MockMvcRequestBuilders.get("/api/json/users/all")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + val cinemas: List<User> = kotlinJsonMapper.readValue(mvcResult.response.contentAsString) + assertThat(cinemas.size, equalTo(100)) + } + + @Test + @Sql("/usersFill.sql") + fun itemJSONTest() { + val randomUser = service.findAll().random() + val mvcResult = mvc.perform(MockMvcRequestBuilders.get("/api/json/users/item/${randomUser.id}")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + val parsedUser: User = kotlinJsonMapper.readValue(mvcResult.response.contentAsString) + assertThat(parsedUser.toString(), equalTo(randomUser.toString())) + } + + @Test + @Sql("/usersFill.sql") + fun allXMLTest() { + val mvcResult = mvc.perform(MockMvcRequestBuilders.get("/api/xml/users/all")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + val cinemas: List<User> = kotlinXmlMapper.readValue(mvcResult.response.contentAsString) + assertThat(cinemas.size, equalTo(100)) + } + + @Test + @Sql("/usersFill.sql") + fun itemXMLTest() { + val randomUser = service.findAll().random() + val mvcResult = mvc.perform(MockMvcRequestBuilders.get("/api/xml/users/item/${randomUser.id}")) + .andExpect(MockMvcResultMatchers.status().isOk) + .andReturn() + val parsedUser: User = kotlinXmlMapper.readValue(mvcResult.response.contentAsString) + assertThat(parsedUser.toString(), equalTo(randomUser.toString())) + } +} \ No newline at end of file