Changes new file upload target to "new document".

This commit is contained in:
Stefan Schallerl 2025-02-07 09:27:19 +01:00
parent caa63fdc71
commit 07c8758182
6 changed files with 131 additions and 73 deletions

View file

@ -95,3 +95,8 @@ enum class State(val code: Int) {
} }
} }
} }
/**
* Tuple for internal and external ID.
*/
data class IdPair(val id: Long, val extId: ExtId)

View file

@ -10,8 +10,6 @@ import java.time.format.FormatStyle
class LimboController(val modifiers: TemplateModifiers, val repository: SqliteRepository) { class LimboController(val modifiers: TemplateModifiers, val repository: SqliteRepository) {
private val dtf = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT)
fun formLimbo(ctx: Context) { fun formLimbo(ctx: Context) {
val session = ctx.requireSession() val session = ctx.requireSession()

View file

@ -12,24 +12,45 @@ class UploadController(val modifiers: TemplateModifiers, val repository: SqliteR
val accountid = session.id val accountid = session.id
val target = ctx.queryParam("target")
val files = ctx.uploadedFiles() val files = ctx.uploadedFiles()
files.forEach { when (target) {
println("filename: " + it.filename()) "document" -> {
println("ext: " + it.extension()) val extIds = files.map {
println("contentType: " + it.contentType()) // mime it.contentAndClose { content ->
println("size: " + it.size()) repository.addFileToLimbo(accountid, it.filename(), it.contentType(), it.size(), content).extId
}
}
ctx.status(200)
ctx.json(
Result(
files = files.size,
redirect = "/document/new?${extIds.joinToString("&") { "file_id=$it" }}"
)
)
}
it.contentAndClose { content -> "limbo" -> {
repository.addFileToLimbo(accountid, it.filename(), it.contentType(), it.size(), content) files.forEach {
it.contentAndClose { content ->
repository.addFileToLimbo(accountid, it.filename(), it.contentType(), it.size(), content)
}
}
ctx.status(200)
ctx.json(
Result(
files = files.size,
redirect = "/limbo"
)
)
} }
} }
ctx.status(200)
ctx.json(Result(files = files.size))
} }
data class Result( data class Result(
val files: Int val files: Int,
val redirect: String
) )
} }

View file

@ -69,16 +69,52 @@ class SqliteRepository(url: String) {
) )
} }
fun addFileToLimbo(accountId: Long, filename: String, contentType: String?, size: Long, content: InputStream) { fun addFileToLimbo(
database.databaseQueries.insertFileIntoLimbo( accountId: Long,
account_id = accountId, filename: String,
ext_id = ExtId.generate(), contentType: String?,
filename = filename, size: Long,
content_type = contentType, content: InputStream
file_size = size, ): IdPair =
content = content.readAllBytes() database.databaseQueries.transactionWithResult {
) val extId = ExtId.generate()
} database.databaseQueries.insertFileIntoLimbo(
account_id = accountId,
ext_id = extId,
filename = filename,
content_type = contentType,
file_size = size,
content = content.readAllBytes()
)
IdPair(
id = lastInsertedId(),
extId = extId
)
}
fun addNewFileToDocument(
accountId: Long,
documentId: Long,
filename: String,
contentType: String?,
size: Long,
content: InputStream
) =
database.databaseQueries.transactionWithResult {
ExtId.generate().let { extId ->
database.databaseQueries.insertFileForDocument(
account_id = accountId,
document_id = documentId,
ext_id = extId,
filename = filename,
content_type = contentType,
file_size = size,
content = content.readAllBytes()
)
IdPair(id = lastInsertedId(), extId = extId)
}
}
fun getLimboFileCount(accountId: Long, state: State = State.ACTIVE): Long { fun getLimboFileCount(accountId: Long, state: State = State.ACTIVE): Long {
return database.databaseQueries.getLimboFileCount(account_id = accountId, state = state) return database.databaseQueries.getLimboFileCount(account_id = accountId, state = state)
@ -273,4 +309,6 @@ class SqliteRepository(url: String) {
fun setFileState(accountId: Long, extId: ExtId, state: State) { fun setFileState(accountId: Long, extId: ExtId, state: State) {
database.databaseQueries.setFileState(account_id = accountId, ext_id = extId, state = state) database.databaseQueries.setFileState(account_id = accountId, ext_id = extId, state = state)
} }
private fun lastInsertedId() = database.databaseQueries.getLastInsertRowId().executeAsOne()
} }

View file

@ -60,6 +60,9 @@ CREATE INDEX file_state_IDX ON file (state);
CREATE UNIQUE INDEX file_ext_id_IDX ON file (ext_id); CREATE UNIQUE INDEX file_ext_id_IDX ON file (ext_id);
--- ---
insertFileForDocument:
INSERT INTO file (account_id, document_id, ext_id, filename, content_type, file_size, content) VALUES (?, ?,?,?,?,?,?);
insertFileIntoLimbo: insertFileIntoLimbo:
INSERT INTO file (account_id, ext_id, filename, content_type, file_size, content) VALUES (?,?,?,?,?,?); INSERT INTO file (account_id, ext_id, filename, content_type, file_size, content) VALUES (?,?,?,?,?,?);

View file

@ -1,73 +1,66 @@
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function () {
console.log("filemure ready")
const dropzone = document.querySelector('html'); const dropzone = document.querySelector('html');
let progressDialog = document.querySelector('#upload_progress_dialog') let progressDialog = document.querySelector('#upload_progress_dialog')
let progressBar = document.querySelector('#upload_progress') let progressBar = document.querySelector('#upload_progress')
// window.addEventListener
// Prevent default behavior for drag-over and drop
dropzone.addEventListener('dragover', (e) => { dropzone.addEventListener('dragover', (e) => {
console.log("over")
e.preventDefault(); e.preventDefault();
dropzone.classList.add('dragactive'); dropzone.classList.add('dragactive');
}); });
dropzone.addEventListener('dragleave', (e) => { dropzone.addEventListener('dragleave', (e) => {
console.log("out")
dropzone.classList.remove('dragactive'); dropzone.classList.remove('dragactive');
}); });
dropzone.addEventListener('drop', (e) => { dropzone.addEventListener('drop', (e) => {
console.log("drop") e.preventDefault();
e.preventDefault(); dropzone.classList.remove('dragactive');
dropzone.classList.remove('dragactive');
// Handle dropped files // Handle dropped files
const files = e.dataTransfer.files; const files = e.dataTransfer.files;
if (files.length > 0) { if (files.length > 0) {
console.log('Files dropped:', files); console.log('Files dropped:', files);
// Process the files for (const file of files) {
for (const file of files) { // show progress dialog
progressDialog.showModal(); // warning: this way the progress dialog is shown for each file individually
console.log('File name:', file.name); progressDialog.showModal();
console.log('File size:', file.size, 'bytes'); const formData = new FormData();
console.log('File type:', file.type); formData.append('file', file);
const formData = new FormData(); const xhr = new XMLHttpRequest();
formData.append('file', file); xhr.upload.addEventListener("progress", (event) => {
if (event.lengthComputable) {
// console.log("upload progress:", event.loaded / event.total);
progressBar.value = 100.0 * event.loaded / event.total;
}
});
xhr.addEventListener("progress", (event) => {
if (event.lengthComputable) {
// console.log("download progress:", event.loaded / event.total);
progressBar.value = event.loaded / event.total;
}
});
xhr.addEventListener("load", (event) => {
console.log(xhr.readyState, xhr.status)
progressDialog.close();
let res = JSON.parse(xhr.response);
window.location = res.redirect;
});
const xhr = new XMLHttpRequest(); xhr.addEventListener("error", event => {
xhr.upload.addEventListener("progress", (event) => { progressDialog.close();
if (event.lengthComputable) { alert("An error occurred.")
console.log("upload progress:", event.loaded / event.total); });
progressBar.value = 100.0 * event.loaded / event.total; xhr.addEventListener("abort", event => {
} progressDialog.close();
}); alert("Upload has been cancelled.")
xhr.addEventListener("progress", (event) => { });
if (event.lengthComputable) {
console.log("download progress:", event.loaded / event.total);
progressBar.value = event.loaded / event.total;
}
});
xhr.addEventListener("loadend", () => {
console.log(xhr.readyState, xhr.status)
progressDialog.close();
});
xhr.open('POST', '/upload', false); xhr.open('POST', '/upload?target=document', false);
xhr.send(formData); xhr.send(formData);
}
// fetch('/upload', {
// method: 'POST',
// body: formData,
// })
// .then(response => response.json())
// .then(data => console.log('Upload successful:', data))
// .catch(error => console.error('Upload failed:', error));
} }
}
}); });
}); });