diff --git a/app/src/main/kotlin/net/h34t/filemure/FilemureApp.kt b/app/src/main/kotlin/net/h34t/filemure/FilemureApp.kt index fc135df..34b28eb 100644 --- a/app/src/main/kotlin/net/h34t/filemure/FilemureApp.kt +++ b/app/src/main/kotlin/net/h34t/filemure/FilemureApp.kt @@ -54,6 +54,7 @@ class FilemureApp(repository: SqliteRepository) { server.post("/file/{extId}/delete", documentController::deleteFileAction, Role.USER) server.get("/search", searchController::search, Role.USER) + server.get("/tags", searchController::tags, Role.USER) server.exception(UnauthorizedResponse::class.java) { e, ctx -> ctx.tempolin( diff --git a/app/src/main/kotlin/net/h34t/filemure/TemplateModifiers.kt b/app/src/main/kotlin/net/h34t/filemure/TemplateModifiers.kt index edb08c6..9901b46 100644 --- a/app/src/main/kotlin/net/h34t/filemure/TemplateModifiers.kt +++ b/app/src/main/kotlin/net/h34t/filemure/TemplateModifiers.kt @@ -6,7 +6,7 @@ import java.net.URLEncoder class TemplateModifiers : Frame.Modifiers, Limbo.Modifiers, DocumentCreateForm.Modifiers, Overview.Modifiers, FilePreview.Modifiers, DocumentEditForm.Modifiers, FileList.Modifiers, - net.h34t.filemure.tpl.Document.Modifiers, OverviewDocuments.Modifiers, Search.Modifiers { + net.h34t.filemure.tpl.Document.Modifiers, OverviewDocuments.Modifiers, Search.Modifiers, Tags.Modifiers { fun hashPrefix(arg: String): String { return URLEncoder.encode(arg, Charsets.UTF_8) diff --git a/app/src/main/kotlin/net/h34t/filemure/Types.kt b/app/src/main/kotlin/net/h34t/filemure/Types.kt index a43361a..4ba61d2 100644 --- a/app/src/main/kotlin/net/h34t/filemure/Types.kt +++ b/app/src/main/kotlin/net/h34t/filemure/Types.kt @@ -38,10 +38,19 @@ data class Document( ) @JvmInline -value class Tag(val value: String) { - init { - // TODO proper validation - require(value.isNotBlank()) +value class Tag private constructor(val value: String) { + + companion object { + private val validator = Regex("[a-zA-Z0-9]+") + private val splitter = Regex("\\s+") + fun of(value: String): Tag = + value.trim().let { v -> + require(v.matches(validator)) + Tag(v.lowercase()) + } + + fun parse(text: String?) = + text?.split(splitter)?.map { of(it) } ?: emptyList() } } diff --git a/app/src/main/kotlin/net/h34t/filemure/Util.kt b/app/src/main/kotlin/net/h34t/filemure/Util.kt index be57ab3..7676738 100644 --- a/app/src/main/kotlin/net/h34t/filemure/Util.kt +++ b/app/src/main/kotlin/net/h34t/filemure/Util.kt @@ -52,7 +52,7 @@ private val tagSplitRegex = Regex("\\s+") object TagAdapter { fun parse(ser: String?): List { - return ser?.trim()?.let { if (it.isNotBlank()) it.split(tagSplitRegex).map { Tag(it) } else emptyList() } + return ser?.trim()?.let { if (it.isNotBlank()) it.split(tagSplitRegex).map { Tag.of(it) } else emptyList() } ?: emptyList() } diff --git a/app/src/main/kotlin/net/h34t/filemure/controller/DocumentController.kt b/app/src/main/kotlin/net/h34t/filemure/controller/DocumentController.kt index a4cf713..0c21056 100644 --- a/app/src/main/kotlin/net/h34t/filemure/controller/DocumentController.kt +++ b/app/src/main/kotlin/net/h34t/filemure/controller/DocumentController.kt @@ -10,8 +10,6 @@ import net.h34t.filemure.tpl.* import net.h34t.filemure.tpl.Document import java.io.File import java.time.LocalDateTime -import java.time.format.DateTimeFormatter -import java.time.format.FormatStyle class DocumentController(val modifiers: TemplateModifiers, val repository: SqliteRepository) { @@ -117,8 +115,7 @@ class DocumentController(val modifiers: TemplateModifiers, val repository: Sqlit ?: throw BadRequestResponse("") val referenceDate = ctx.formParam("reference_date")?.let { LocalDateTime.parse(it, formDtf) } ?: throw BadRequestResponse("") - val tags = ctx.formParam("tags")?.split("\\s+") - ?: emptyList() + val tags = Tag.parse(ctx.formParam("tags")) val description = ctx.formParam("description") ?: throw BadRequestResponse("") val fileExtIds = ctx.formParams("file_id") @@ -128,7 +125,7 @@ class DocumentController(val modifiers: TemplateModifiers, val repository: Sqlit session.id, title, referenceDate, - tags.map { Tag(it) }, + tags, description, fileExtIds.map { ExtId(it) }) diff --git a/app/src/main/kotlin/net/h34t/filemure/controller/SearchController.kt b/app/src/main/kotlin/net/h34t/filemure/controller/SearchController.kt index 9c64598..183c88c 100644 --- a/app/src/main/kotlin/net/h34t/filemure/controller/SearchController.kt +++ b/app/src/main/kotlin/net/h34t/filemure/controller/SearchController.kt @@ -1,13 +1,11 @@ package net.h34t.filemure.controller import io.javalin.http.Context -import net.h34t.filemure.TemplateModifiers -import net.h34t.filemure.formatHumanShort +import net.h34t.filemure.* import net.h34t.filemure.repository.SqliteRepository -import net.h34t.filemure.requireSession -import net.h34t.filemure.tempolin import net.h34t.filemure.tpl.Frame import net.h34t.filemure.tpl.Search +import net.h34t.filemure.tpl.Tags class SearchController(val modifiers: TemplateModifiers, val repository: SqliteRepository) { @@ -42,4 +40,36 @@ class SearchController(val modifiers: TemplateModifiers, val repository: SqliteR ) } + fun tags(ctx: Context) { + val session = ctx.requireSession() + + val t = ctx.queryParams("t").map { Tag.of(it) } + + val tags = repository.getAllTags(session.id) + + val documents = repository.getDocumentsByTags(accountId = session.id, tags = t) + + ctx.tempolin( + Frame( + modifiers = modifiers, + title = "Search", + target = "document", + back = "/", + logout = true, + content = Tags( + modifiers = modifiers, + tag = { tags.map { TagBlock(tag = it.value) }.asSequence() }, + document = { + documents.map { d -> + DocumentBlock( + extId = d.extId.value, + title = d.title, + referenceDate = d.referenceDate.formatHumanShort() + ) + }.asSequence() + } + ) + ) + ) + } } \ No newline at end of file diff --git a/app/src/main/kotlin/net/h34t/filemure/repository/SqliteRepository.kt b/app/src/main/kotlin/net/h34t/filemure/repository/SqliteRepository.kt index 1c12a8c..9496a48 100644 --- a/app/src/main/kotlin/net/h34t/filemure/repository/SqliteRepository.kt +++ b/app/src/main/kotlin/net/h34t/filemure/repository/SqliteRepository.kt @@ -317,7 +317,7 @@ class SqliteRepository(url: String) { } fun searchDocuments(accountId: Long, state: State = State.ACTIVE, query: String): List { - return database.databaseQueries.searchDocument(account_id = accountId, state = state, query = query) + return database.databaseQueries.searchDocuments(account_id = accountId, state = state, query = query) .executeAsList() .map { Document( @@ -359,5 +359,28 @@ class SqliteRepository(url: String) { database.databaseQueries.setFileState(account_id = accountId, ext_id = extId, state = state) } + fun getAllTags(accountId: Long): List = + database.databaseQueries.getAllTags(accountId).executeAsList().flatten().distinct() + + private fun lastInsertedId() = database.databaseQueries.getLastInsertRowId().executeAsOne() + + fun getDocumentsByTags(accountId: Long, state: State = State.ACTIVE, tags: List): List { + return database.databaseQueries.getDocuments(account_id = accountId, state = state) + .executeAsList() + .filter { d -> (d.tags intersect tags).isNotEmpty() } + .map { + Document( + id = it.id, + extId = it.ext_id, + title = it.title, + description = it.description, + tags = it.tags, + created = it.created, + referenceDate = it.reference_date, + state = it.state, + files = emptyList() + ) + } + } } \ No newline at end of file diff --git a/app/src/main/sqldelight/net/h34t/filemure/db/Database.sq b/app/src/main/sqldelight/net/h34t/filemure/db/Database.sq index 4db4ef7..7445690 100644 --- a/app/src/main/sqldelight/net/h34t/filemure/db/Database.sq +++ b/app/src/main/sqldelight/net/h34t/filemure/db/Database.sq @@ -219,7 +219,7 @@ UPDATE file SET state=? WHERE account_id=? AND ext_id=?; setFilesState: UPDATE file SET state=? WHERE account_id=? AND ext_id IN ?; -searchDocument: +searchDocuments: SELECT d.id, d.account_id, @@ -241,3 +241,5 @@ WHERE f.filename LIKE :query OR f.content_extracted LIKE :query); +getAllTags: +SELECT tags FROM document WHERE account_id=:accountId; diff --git a/app/src/main/tpl/net.h34t.filemure.tpl/Tags.tpl.html b/app/src/main/tpl/net.h34t.filemure.tpl/Tags.tpl.html new file mode 100644 index 0000000..bf5f336 --- /dev/null +++ b/app/src/main/tpl/net.h34t.filemure.tpl/Tags.tpl.html @@ -0,0 +1,39 @@ +
+
+ Tags +
+ {for $tag} + + {/for} +
+
+
+ +
+ Results + + + + + + + + + + + + {for $document} + + + + + + {/for} + +
DateTitleDetails
{*$referenceDate}{*$title} + +
+
\ No newline at end of file