From 97fe0acdeac6b07170d5eb3c7755fc58f2c23303 Mon Sep 17 00:00:00 2001 From: Josha von Gizycki Date: Mon, 28 Jul 2025 21:02:22 +0200 Subject: [PATCH] delete tags --- .../kotlin/wanijo/wanijo2/domain/document.kt | 7 ++-- .../domain/event/DeleteTaggingCommand.kt | 15 +++++++++ .../domain/handler/DeleteTaggingHandler.kt | 19 +++++++++++ ...ommandHandler.kt => NewDocumentHandler.kt} | 2 +- src/main/kotlin/wanijo/wanijo2/domain/tag.kt | 28 ++++++++++++---- .../wanijo2/http/controller/NewController.kt | 4 +-- .../http/controller/TaggingController.kt | 32 +++++++++++++++++++ src/main/resources/static/stylesheet.css | 26 ++++++++++++--- src/main/resources/templates/show.html | 11 ++++++- 9 files changed, 125 insertions(+), 19 deletions(-) create mode 100644 src/main/kotlin/wanijo/wanijo2/domain/event/DeleteTaggingCommand.kt create mode 100644 src/main/kotlin/wanijo/wanijo2/domain/handler/DeleteTaggingHandler.kt rename src/main/kotlin/wanijo/wanijo2/domain/handler/{NewDocumentCommandHandler.kt => NewDocumentHandler.kt} (97%) create mode 100644 src/main/kotlin/wanijo/wanijo2/http/controller/TaggingController.kt diff --git a/src/main/kotlin/wanijo/wanijo2/domain/document.kt b/src/main/kotlin/wanijo/wanijo2/domain/document.kt index aa4ea4b..ea364f1 100644 --- a/src/main/kotlin/wanijo/wanijo2/domain/document.kt +++ b/src/main/kotlin/wanijo/wanijo2/domain/document.kt @@ -1,16 +1,17 @@ package wanijo.wanijo2.domain import org.springframework.data.annotation.Id -import org.springframework.data.annotation.Transient import org.springframework.data.jdbc.repository.query.Query import org.springframework.data.relational.core.mapping.Table import org.springframework.data.repository.Repository import java.time.ZonedDateTime +typealias DocumentId = Long + @Table("T_DOCUMENT") data class Document( @Id - val id: Long = 0, + val id: DocumentId = 0, val name: String, val description: String = "", val updatedAt: ZonedDateTime = ZonedDateTime.now(), @@ -19,7 +20,7 @@ data class Document( val dateFields: Set = emptySet(), ) -interface DocumentDao: Repository { +interface DocumentDao: Repository { fun findAll(): List fun findById(id: Long): Document? fun findByName(name: String): List diff --git a/src/main/kotlin/wanijo/wanijo2/domain/event/DeleteTaggingCommand.kt b/src/main/kotlin/wanijo/wanijo2/domain/event/DeleteTaggingCommand.kt new file mode 100644 index 0000000..4fc8d4c --- /dev/null +++ b/src/main/kotlin/wanijo/wanijo2/domain/event/DeleteTaggingCommand.kt @@ -0,0 +1,15 @@ +package wanijo.wanijo2.domain.event + +import jakarta.validation.constraints.Min +import jakarta.validation.constraints.NotEmpty +import wanijo.wanijo2.domain.DocumentId +import wanijo.wanijo2.domain.TagId + +data class DeleteTaggingCommand( + @NotEmpty + @Min(1) + val tagId: TagId, + @NotEmpty + @Min(1) + val documentId: DocumentId +) diff --git a/src/main/kotlin/wanijo/wanijo2/domain/handler/DeleteTaggingHandler.kt b/src/main/kotlin/wanijo/wanijo2/domain/handler/DeleteTaggingHandler.kt new file mode 100644 index 0000000..2a770f8 --- /dev/null +++ b/src/main/kotlin/wanijo/wanijo2/domain/handler/DeleteTaggingHandler.kt @@ -0,0 +1,19 @@ +package wanijo.wanijo2.domain.handler + +import org.springframework.stereotype.Service +import wanijo.wanijo2.domain.DocumentTaggingDao +import wanijo.wanijo2.domain.event.DeleteTaggingCommand + +@Service +class DeleteTaggingHandler( + val taggingDao: DocumentTaggingDao +) { + + fun exec(command: DeleteTaggingCommand) { + taggingDao.delete( + command.documentId, + command.tagId + ) + } + +} diff --git a/src/main/kotlin/wanijo/wanijo2/domain/handler/NewDocumentCommandHandler.kt b/src/main/kotlin/wanijo/wanijo2/domain/handler/NewDocumentHandler.kt similarity index 97% rename from src/main/kotlin/wanijo/wanijo2/domain/handler/NewDocumentCommandHandler.kt rename to src/main/kotlin/wanijo/wanijo2/domain/handler/NewDocumentHandler.kt index a661adf..bf12438 100644 --- a/src/main/kotlin/wanijo/wanijo2/domain/handler/NewDocumentCommandHandler.kt +++ b/src/main/kotlin/wanijo/wanijo2/domain/handler/NewDocumentHandler.kt @@ -10,7 +10,7 @@ import wanijo.wanijo2.domain.TagDao import wanijo.wanijo2.domain.event.NewDocumentCommand @Service -class NewDocumentCommandHandler( +class NewDocumentHandler( val tagDao: TagDao, val documentDao: DocumentDao, val documentTaggingDao: DocumentTaggingDao diff --git a/src/main/kotlin/wanijo/wanijo2/domain/tag.kt b/src/main/kotlin/wanijo/wanijo2/domain/tag.kt index cc0cfdf..1321c22 100644 --- a/src/main/kotlin/wanijo/wanijo2/domain/tag.kt +++ b/src/main/kotlin/wanijo/wanijo2/domain/tag.kt @@ -2,28 +2,33 @@ package wanijo.wanijo2.domain import org.springframework.data.annotation.Id import org.springframework.data.jdbc.core.mapping.AggregateReference +import org.springframework.data.jdbc.repository.query.Modifying import org.springframework.data.jdbc.repository.query.Query import org.springframework.data.relational.core.mapping.Table import org.springframework.data.repository.Repository import java.time.ZonedDateTime +typealias TagId = Long + @Table("T_TAG") data class Tag( @Id - val id: Long = 0, + val id: TagId = 0, val name: String, val createdAt: ZonedDateTime = ZonedDateTime.now() ) +typealias DocumentTaggingId = Long + @Table("T_DOCUMENT_TAGGING") data class DocumentTagging( @Id - val id: Long = 0, - val tagId: AggregateReference, - val documentId: AggregateReference + val id: DocumentTaggingId = 0, + val tagId: AggregateReference, + val documentId: AggregateReference ) { companion object { - fun between(doc: Document, tagId: Long) = + fun between(doc: Document, tagId: TagId) = DocumentTagging( tagId = AggregateReference.to(tagId), documentId = AggregateReference.to(doc.id) @@ -31,11 +36,20 @@ data class DocumentTagging( } } -interface DocumentTaggingDao : Repository { +interface DocumentTaggingDao : Repository { fun save(tagging: DocumentTagging) + @Modifying + @Query( + """ + DELETE FROM t_document_tagging + WHERE document_id = :documentId + AND tag_id = :tagId + """ + ) + fun delete(documentId: DocumentId, tagId: TagId) } -interface TagDao : Repository { +interface TagDao : Repository { fun save(tag: Tag): Tag fun findByName(name: String): Tag? fun findAll(): Set diff --git a/src/main/kotlin/wanijo/wanijo2/http/controller/NewController.kt b/src/main/kotlin/wanijo/wanijo2/http/controller/NewController.kt index 28e4a3d..0801009 100644 --- a/src/main/kotlin/wanijo/wanijo2/http/controller/NewController.kt +++ b/src/main/kotlin/wanijo/wanijo2/http/controller/NewController.kt @@ -10,13 +10,13 @@ import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestMapping import wanijo.wanijo2.domain.TagDao import wanijo.wanijo2.domain.event.NewDocumentCommand -import wanijo.wanijo2.domain.handler.NewDocumentCommandHandler +import wanijo.wanijo2.domain.handler.NewDocumentHandler @Controller @RequestMapping("/document") class NewController( private val tagDao: TagDao, - private val newDocumentCommandHandler: NewDocumentCommandHandler, + private val newDocumentCommandHandler: NewDocumentHandler, ) { @GetMapping("/new") diff --git a/src/main/kotlin/wanijo/wanijo2/http/controller/TaggingController.kt b/src/main/kotlin/wanijo/wanijo2/http/controller/TaggingController.kt new file mode 100644 index 0000000..3d5199f --- /dev/null +++ b/src/main/kotlin/wanijo/wanijo2/http/controller/TaggingController.kt @@ -0,0 +1,32 @@ +package wanijo.wanijo2.http.controller + +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestParam +import wanijo.wanijo2.domain.DocumentId +import wanijo.wanijo2.domain.TagId +import wanijo.wanijo2.domain.event.DeleteTaggingCommand +import wanijo.wanijo2.domain.handler.DeleteTaggingHandler + +@Controller +class TaggingController( + val deleteTaggingHandler: DeleteTaggingHandler +) { + + @PostMapping("/tagging/delete") + fun delete( + @RequestParam("docId") + documentId: DocumentId, + @RequestParam("tagId") + tagId: TagId + ): String { + deleteTaggingHandler.exec( + DeleteTaggingCommand( + tagId = tagId, + documentId = documentId + ) + ) + return "redirect:/document/${documentId}" + } + +} diff --git a/src/main/resources/static/stylesheet.css b/src/main/resources/static/stylesheet.css index 0f1b3f9..0bc7bb2 100644 --- a/src/main/resources/static/stylesheet.css +++ b/src/main/resources/static/stylesheet.css @@ -38,14 +38,14 @@ main { display: flex; justify-content: space-evenly; - - li { - border-left: .5rem solid AccentColor; - padding-left: .5rem; - } } } + .tag-block { + border-left: .5rem solid AccentColor; + padding-left: .5rem; + } + fieldset { border: 1px solid AccentColor; margin-bottom: 1rem; @@ -96,3 +96,19 @@ form { min-height: 10rem; } } + +.form-link { + display: inline; + + [type=submit] { + border: none; + background: none; + + color: LinkText; + + &:hover { + text-decoration: underline; + cursor: pointer; + } + } +} diff --git a/src/main/resources/templates/show.html b/src/main/resources/templates/show.html index 4a8d5b2..13486df 100644 --- a/src/main/resources/templates/show.html +++ b/src/main/resources/templates/show.html @@ -34,7 +34,14 @@ tags
    -
  • +
  • + + +
@@ -42,6 +49,8 @@ beschreibung
+ +

taggen