Adds document search.
This commit is contained in:
parent
c44fa80d7f
commit
3045f46525
11 changed files with 129 additions and 13 deletions
|
@ -10,6 +10,7 @@ plugins {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation("org.apache.pdfbox:pdfbox:3.0.4")
|
||||
implementation("app.cash.sqldelight:sqlite-driver:2.0.2")
|
||||
// implementation("org.xerial:sqlite-jdbc:3.48.0.0")
|
||||
implementation("com.fasterxml.jackson.core:jackson-databind:2.18.2")
|
||||
|
|
|
@ -17,6 +17,7 @@ class FilemureApp(repository: SqliteRepository) {
|
|||
private val limboController = LimboController(modifiers, repository)
|
||||
private val uploadController = UploadController(modifiers, repository)
|
||||
private val documentController = DocumentController(modifiers, repository)
|
||||
private val searchController = SearchController(modifiers, repository)
|
||||
|
||||
fun register(server: Javalin) {
|
||||
server.beforeMatched { ctx ->
|
||||
|
@ -49,6 +50,8 @@ class FilemureApp(repository: SqliteRepository) {
|
|||
server.get("/file/{extId}/download", documentController::downloadFile, Role.USER)
|
||||
server.get("/file/{extId}/delete", documentController::deleteFileAction, Role.USER)
|
||||
|
||||
server.get("/search", searchController::search, Role.USER)
|
||||
|
||||
server.exception(UnauthorizedResponse::class.java) { e, ctx ->
|
||||
ctx.tempolin(
|
||||
Frame(
|
||||
|
|
|
@ -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 {
|
||||
net.h34t.filemure.tpl.Document.Modifiers, OverviewDocuments.Modifiers, Search.Modifiers {
|
||||
|
||||
fun hashPrefix(arg: String): String {
|
||||
return URLEncoder.encode(arg, Charsets.UTF_8)
|
||||
|
|
|
@ -6,7 +6,10 @@ import io.javalin.http.HttpStatus
|
|||
import io.javalin.http.UnauthorizedResponse
|
||||
import java.io.BufferedOutputStream
|
||||
import java.io.OutputStreamWriter
|
||||
import java.time.LocalDateTime
|
||||
import java.time.Month
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.FormatStyle
|
||||
|
||||
/**
|
||||
* Outputs an HTML page rendered via TempolinTemplate.
|
||||
|
@ -58,3 +61,8 @@ fun List<Document>.grouped(): Map<Int, Map<Month, List<Document>>> =
|
|||
values.groupBy { it.referenceDate.month }
|
||||
}
|
||||
|
||||
private val htmlDtf = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT, FormatStyle.SHORT)
|
||||
val formDtf = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm")
|
||||
|
||||
fun LocalDateTime.formatHuman() = this.format(htmlDtf)
|
||||
fun LocalDateTime.formatHtmlForm() = this.format(formDtf)
|
||||
|
|
|
@ -16,7 +16,6 @@ import java.time.format.FormatStyle
|
|||
class DocumentController(val modifiers: TemplateModifiers, val repository: SqliteRepository) {
|
||||
|
||||
private val dtf = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT)
|
||||
private val formDtf = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm")
|
||||
|
||||
fun documentDetail(ctx: Context) {
|
||||
val session = ctx.requireSession()
|
||||
|
@ -86,7 +85,7 @@ class DocumentController(val modifiers: TemplateModifiers, val repository: Sqlit
|
|||
content = DocumentCreateForm(
|
||||
modifiers = modifiers,
|
||||
title = title,
|
||||
referenceDate = formDtf.format(referenceDate),
|
||||
referenceDate = referenceDate.formatHtmlForm(),
|
||||
tags = { tags.map { TagsBlock(it) } },
|
||||
description = description,
|
||||
fileId = { selectedFiles.map { FileIdBlock(it.extId.value) }.asSequence() },
|
||||
|
|
|
@ -1,21 +1,14 @@
|
|||
package net.h34t.filemure.controller
|
||||
|
||||
import io.javalin.http.Context
|
||||
import net.h34t.filemure.TemplateModifiers
|
||||
import net.h34t.filemure.grouped
|
||||
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.Overview
|
||||
import net.h34t.filemure.tpl.OverviewDocuments
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.FormatStyle
|
||||
|
||||
class OverviewController(val modifiers: TemplateModifiers, val repository: SqliteRepository) {
|
||||
|
||||
private val htmlDtf = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT, FormatStyle.SHORT)
|
||||
|
||||
fun overview(ctx: Context) {
|
||||
val session = ctx.requireSession()
|
||||
|
||||
|
@ -71,10 +64,10 @@ class OverviewController(val modifiers: TemplateModifiers, val repository: Sqlit
|
|||
modifiers = modifiers,
|
||||
category = "$year-$month",
|
||||
document = {
|
||||
documents.map { document ->
|
||||
documents.sortedBy { it.referenceDate }.map { document ->
|
||||
DocumentBlock(
|
||||
extId = document.extId.value,
|
||||
referenceDate = htmlDtf.format(document.referenceDate),
|
||||
referenceDate = document.referenceDate.formatHtmlForm(),
|
||||
title = document.title.ifBlank { "untitled" },
|
||||
)
|
||||
}.asSequence()
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package net.h34t.filemure.controller
|
||||
|
||||
import io.javalin.http.Context
|
||||
import net.h34t.filemure.TemplateModifiers
|
||||
import net.h34t.filemure.formatHuman
|
||||
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
|
||||
|
||||
class SearchController(val modifiers: TemplateModifiers, val repository: SqliteRepository) {
|
||||
|
||||
fun search(ctx: Context) {
|
||||
val session = ctx.requireSession()
|
||||
|
||||
val q = ctx.queryParam("q")
|
||||
|
||||
val documents = repository.searchDocuments(accountId = session.id, query = "%$q%")
|
||||
|
||||
ctx.tempolin(
|
||||
Frame(
|
||||
modifiers = modifiers,
|
||||
title = "Overview",
|
||||
isTarget = true,
|
||||
content = Search(
|
||||
modifiers = modifiers,
|
||||
search = q ?: "",
|
||||
document = {
|
||||
documents.map { d ->
|
||||
DocumentBlock(
|
||||
extId = d.extId.value,
|
||||
title = d.title,
|
||||
referenceDate = d.referenceDate.formatHuman()
|
||||
)
|
||||
}.asSequence()
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -231,6 +231,24 @@ class SqliteRepository(url: String) {
|
|||
}
|
||||
}
|
||||
|
||||
fun searchDocuments(accountId: Long, state: State = State.ACTIVE, query: String): List<Document> {
|
||||
return database.databaseQueries.searchDocument(account_id = accountId, state = state, query = query)
|
||||
.executeAsList()
|
||||
.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()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun loadFile(accountId: Long, extId: ExtId): FileContent {
|
||||
return database
|
||||
.databaseQueries
|
||||
|
@ -251,6 +269,7 @@ class SqliteRepository(url: String) {
|
|||
fun setDocumentState(accountId: Long, extId: ExtId, state: State) {
|
||||
database.databaseQueries.setDocumentState(account_id = accountId, ext_id = extId, state = state)
|
||||
}
|
||||
|
||||
fun setFileState(accountId: Long, extId: ExtId, state: State) {
|
||||
database.databaseQueries.setFileState(account_id = accountId, ext_id = extId, state = state)
|
||||
}
|
||||
|
|
|
@ -209,3 +209,24 @@ UPDATE file SET state=? WHERE account_id=? AND ext_id=?;
|
|||
|
||||
setFilesState:
|
||||
UPDATE file SET state=? WHERE account_id=? AND ext_id IN ?;
|
||||
|
||||
searchDocument:
|
||||
SELECT
|
||||
id,
|
||||
account_id,
|
||||
ext_id,
|
||||
title,
|
||||
description,
|
||||
tags,
|
||||
created,
|
||||
reference_date,
|
||||
state
|
||||
FROM
|
||||
document
|
||||
WHERE
|
||||
account_id = :account_id AND
|
||||
state = :state AND
|
||||
(title LIKE :query OR
|
||||
description LIKE :query AND
|
||||
tags LIKE :query);
|
||||
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
<p>Files in <a href="/limbo">limbo: {$limboFileCount}</a>.</p>
|
||||
|
||||
<form action="/search" method="get">
|
||||
<input type="search" name="q"> <input type="submit" value="search">
|
||||
</form>
|
||||
|
||||
<table>
|
||||
{for $year}
|
||||
<tr>
|
||||
|
|
25
app/src/main/tpl/net.h34t.filemure.tpl/Search.tpl.html
Normal file
25
app/src/main/tpl/net.h34t.filemure.tpl/Search.tpl.html
Normal file
|
@ -0,0 +1,25 @@
|
|||
<h1>Search for "{*$search}"</h1>
|
||||
|
||||
<form action="/search" method="get">
|
||||
<input type="search" name="q" value="{*$search}"> <input type="submit" value="search">
|
||||
</form>
|
||||
|
||||
<h2>Results</h2>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Title</th>
|
||||
<th>Details</th>
|
||||
</tr>
|
||||
|
||||
{for $document}
|
||||
<tr>
|
||||
<td>{*$referenceDate}</td>
|
||||
<td>{*$title}</td>
|
||||
<td><a href="/document/{*$extId}">
|
||||
<button>details</button>
|
||||
</a></td>
|
||||
</tr>
|
||||
{/for}
|
||||
</table>
|
Loading…
Reference in a new issue