+import base64
import datetime
import logging
import re
raise HTTPException(status_code=500, detail="Failed to write changes of deleted file!")
return {"success": True}
- raise HTTPException(status_code=500, detail="Failed to delete file - not found in log")
\ No newline at end of file
+ raise HTTPException(status_code=500, detail="Failed to delete file - not found in log")
+
+@router.get("/downloadFile")
+async def downloadFile(uuid: str, cookie = Depends(users.isLoggedIn)):
+ enc_key = security.get_enc_key(cookie["user_id"], cookie["derived_key"])
+ file = fileHandling.readFile(cookie["user_id"], uuid)
+ if file is None:
+ raise HTTPException(status_code=500, detail="Failed to read file")
+ return {"file": base64.b64encode(security.decrypt_file(file, enc_key))}
\ No newline at end of file
f.write(file)
return True
+def readFile(user_id, uuid):
+ try:
+ f = open(os.path.join(settings.data_path, str(user_id), 'files', uuid), "r")
+ except FileNotFoundError:
+ logger.info(f"{user_id}/files/{uuid} - File not found")
+ raise HTTPException(status_code=404, detail="File not found")
+ except Exception as e:
+ logger.exception(e)
+ raise HTTPException(status_code=500, detail="Internal Server Error when trying to open file {uuid}")
+ else:
+ with f:
+ return f.read()
+
def removeFile(user_id, uuid):
try:
os.remove(os.path.join(settings.data_path, str(user_id), 'files', uuid))
import { faCloudArrowUp, faTrash } from '@fortawesome/free-solid-svg-icons';
import Fa from 'svelte-fa';
import { v4 as uuidv4 } from 'uuid';
- import { slide } from 'svelte/transition';
+ import { slide, fade } from 'svelte/transition';
axios.interceptors.request.use((config) => {
config.withCredentials = true;
});
let lastSelectedDate = $state($selectedDate);
+ let images = $state([]);
let loading = false;
$effect(() => {
loading = true;
if ($selectedDate !== lastSelectedDate) {
+ images = [];
+ filesOfDay = [];
+
clearTimeout(timeout);
const result = getLog();
if (result) {
}
}
+ const imageExtensions = ['jpeg', 'jpg', 'gif', 'png'];
+
+ function base64ToArrayBuffer(base64) {
+ var binaryString = atob(base64);
+ var bytes = new Uint8Array(binaryString.length);
+ for (var i = 0; i < binaryString.length; i++) {
+ bytes[i] = binaryString.charCodeAt(i);
+ }
+ return bytes.buffer;
+ }
+
+ $effect(() => {
+ if (filesOfDay) {
+ // add all files to images if correct extension
+ filesOfDay.forEach((file) => {
+ // if image -> load it!
+ if (
+ imageExtensions.includes(file.filename.split('.').pop().toLowerCase()) &&
+ !images.find((image) => image.uuid_filename === file.uuid_filename)
+ ) {
+ images = [...images, file];
+ axios
+ .get(API_URL + '/logs/downloadFile', { params: { uuid: file.uuid_filename } })
+ .then((response) => {
+ images = images.map((image) => {
+ if (image.uuid_filename === file.uuid_filename) {
+ image.src = response.data.file;
+ }
+ return image;
+ });
+ })
+ .catch((error) => {
+ console.error(error);
+ });
+ }
+ });
+ }
+ });
+
async function saveLog() {
if (currentLog === savedLog) {
return true;
if (!+bytes) return '0 Bytes';
const k = 1024;
- const dm = 2;
- const sizes = ['Bytes', 'KB', 'MB', 'GB'];
+ //const dm = 2; // decimal places
+ const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
- return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(0))} ${sizes[i]}`;
}
function downloadFile(uuid) {
})
.then((response) => {
filesOfDay = filesOfDay.filter((file) => file.uuid_filename !== uuid);
+ images = images.filter((image) => image.uuid_filename !== uuid);
})
.catch((error) => {
console.error(error);
<div id="toolbar"></div>
<div id="editor"></div>
</div>
+ {#if images.length > 0}
+ <div class="d-flex flex-row images mt-3">
+ {#each images as image (image.uuid_filename)}
+ <div class="imageContainer d-flex align-items-center" transition:slide={{ axis: 'x' }}>
+ {#if image.src}
+ <img
+ transition:fade
+ class="image"
+ alt={image.filename}
+ src={'data:image/jpg;base64,' + image.src}
+ />
+ {:else}
+ <div class="spinner-border" role="status">
+ <span class="visually-hidden">Loading...</span>
+ </div>
+ {/if}
+ </div>
+ {/each}
+ </div>
+ {/if}
{$selectedDate}<br />
{lastSelectedDate}
</div>
</div>
<style>
+ .image,
+ .imageContainer {
+ border-radius: 8px;
+ }
+
+ .imageContainer {
+ min-height: 80px;
+ }
+
+ .image:hover {
+ transform: scale(1.1);
+ box-shadow: 0 0 12px 3px rgba(0, 0, 0, 0.2);
+ }
+
+ .image {
+ max-width: 250px;
+ max-height: 150px;
+ transition: all ease 0.3s;
+ }
+
+ .images {
+ gap: 1rem;
+ }
+
:global(.modal.show) {
background-color: rgba(80, 80, 80, 0.1) !important;
backdrop-filter: blur(2px) saturate(150%);
.filesize {
opacity: 0.7;
font-size: 0.8rem;
+ white-space: nowrap;
}
.fileBtn {