begin of file upload - background 'development' paused'
authorPhiTux <redacted>
Tue, 21 Jan 2025 22:20:31 +0000 (23:20 +0100)
committerPhiTux <redacted>
Tue, 21 Jan 2025 22:20:31 +0000 (23:20 +0100)
backend/server/routers/logs.py
backend/server/utils/fileHandling.py
backend/server/utils/security.py
frontend/package-lock.json
frontend/package.json
frontend/src/lib/Datepicker.svelte
frontend/src/lib/Sidenav.svelte
frontend/src/lib/settingsStore.js
frontend/src/routes/+layout.svelte
frontend/src/routes/write/+page.svelte

index 14a7044e50704bbbbff9568c3d2bd027b630c21a..e272015461338500c29813a16cca5441d00d6aca 100644 (file)
@@ -1,13 +1,14 @@
 import datetime
 import logging
 import re
-from fastapi import APIRouter, Cookie
+from fastapi import APIRouter, Cookie, Depends, Form, UploadFile, File, HTTPException
 from pydantic import BaseModel
-from fastapi import Depends
 from . import users
 from ..utils import fileHandling
 from ..utils import security
 import html
+from typing import Annotated
+import time
 
 
 logger = logging.getLogger("dailytxtLogger")
@@ -225,4 +226,34 @@ async def loadMonthForReading(month: int, year: int, cookie = Depends(users.isLo
     
     days.sort(key=lambda x: x["day"])
 
-    return days
\ No newline at end of file
+    return days
+
+'''
+Data ist sent as FormData, not as JSON
+'''
+@router.post("/uploadFile")
+async def uploadFile(day: Annotated[int, Form()], month: Annotated[int, Form()], year: Annotated[int, Form()], uuid: Annotated[str, Form()], file: Annotated[UploadFile, File()], cookie = Depends(users.isLoggedIn)):
+    
+    # encrypt file
+    enc_key = security.get_enc_key(cookie["user_id"], cookie["derived_key"])
+    encrypted_file = security.encrypt_file(file.file.read(), enc_key)
+    if not fileHandling.writeFile(encrypted_file, cookie["user_id"], uuid):
+        return {"success": False}
+    
+    # save file in log
+    content:dict = fileHandling.getDay(cookie["user_id"], year, month)
+    if "days" not in content.keys():
+        content["days"] = []
+        content["days"].append({"day": day, "files": [uuid]})
+###########
+
+
+    print(file.size)
+    print(file.filename)
+    print(uuid)
+    print(file.headers.get("content-type"))
+    print(day, month, year)
+
+    # wait 3 s
+    time.sleep(3)
+    return {"success": True}
\ No newline at end of file
index 0bc50acedb44ce8ff1ea3c01ab8ac0ec62112c6d..207880bce6b0684460b9133dd8bd251e47c1e315 100644 (file)
@@ -71,4 +71,25 @@ def get_years(user_id):
 def get_months(user_id, year):
     for entry in os.scandir(os.path.join(settings.data_path, str(user_id), year)):
         if entry.is_file() and entry.name.endswith(".json"):
-            yield entry.name.split(".")[0]
\ No newline at end of file
+            yield entry.name.split(".")[0]
+
+def writeFile(str, user_id, uuid):
+    try:
+        os.makedirs(os.path.join(settings.data_path, str(user_id), 'files'), exist_ok=True)
+        f = open(os.path.join(settings.data_path, str(user_id), 'files', uuid), "w")
+    except Exception as e:
+        logger.exception(e)
+        return False
+    else:
+        with f:
+            f.write(str)
+            return True
+        
+def removeFile(user_id, uuid):
+    try:
+        os.remove(os.path.join(settings.data_path, str(user_id), 'files', uuid))
+    except Exception as e:
+        logger.exception(e)
+        return False
+    else:
+        return True
\ No newline at end of file
index d745296f40763eb34c8470e1dcd35f3e6521c0c4..349f5d30700252dd684f261c9fab8acd6735f03b 100644 (file)
@@ -39,4 +39,8 @@ def encrypt_text(text: str, key: str) -> str:
 
 def decrypt_text(text: str, key: str) -> str:
     f = Fernet(key)
-    return f.decrypt(text.encode()).decode()
\ No newline at end of file
+    return f.decrypt(text.encode()).decode()
+
+def encrypt_file(file: bytes, key: str) -> str:
+    f = Fernet(key)
+    return f.encrypt(file).decode()
\ No newline at end of file
index 6329ac0bb5600e2278655f90a8ed99f1c683e8b2..e8ddcf76db22899774b02f2f2116ad5708f40d0a 100644 (file)
@@ -16,7 +16,8 @@
                                "marked": "^15.0.6",
                                "svelte-outside": "^0.0.3",
                                "tiny-markdown-editor": "^0.1.31",
-                               "trianglify": "^4.1.1"
+                               "trianglify": "^4.1.1",
+                               "uuid": "^11.0.5"
                        },
                        "devDependencies": {
                                "@sveltejs/adapter-auto": "^3.0.0",
                        "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
                        "license": "MIT"
                },
+               "node_modules/uuid": {
+                       "version": "11.0.5",
+                       "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.5.tgz",
+                       "integrity": "sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==",
+                       "funding": [
+                               "https://github.com/sponsors/broofa",
+                               "https://github.com/sponsors/ctavan"
+                       ],
+                       "license": "MIT",
+                       "bin": {
+                               "uuid": "dist/esm/bin/uuid"
+                       }
+               },
                "node_modules/vite": {
                        "version": "5.4.11",
                        "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz",
index e02e06fd326b23718ae79035ba090fc2fca2911e..f50dac44c4d4a6aa8b71d915ece209c073a1d610 100644 (file)
@@ -40,6 +40,7 @@
                "marked": "^15.0.6",
                "svelte-outside": "^0.0.3",
                "tiny-markdown-editor": "^0.1.31",
-               "trianglify": "^4.1.1"
+               "trianglify": "^4.1.1",
+               "uuid": "^11.0.5"
        }
 }
index e600171d53920ae007b39a05231447f38be32549..2613ed1853324975aac3d9c7f896e10dfcbc9adf 100644 (file)
        .datepicker {
                display: inline-block;
                font-family: Arial, sans-serif;
-               border: 1px solid #ccc;
+               border: 1px solid #ececec77;
                border-radius: 8px;
                /* overflow: hidden; */
                /* width: 300px; */
                box-sizing: border-box;
-               backdrop-filter: blur(5px) saturate(150%);
-               background-color: rgba(182, 183, 185, 0.75);
+               backdrop-filter: blur(8px) saturate(150%);
+               background-color: rgba(219, 219, 219, 0.45);
        }
        .datepicker-header {
                display: flex;
index 648a9a0e6abaa00975544234ff8151ed5492cf7b..5bbb8d101787b4df02cce972490ca7d9562041bd 100644 (file)
                border-top-right-radius: 0;
                overflow-y: auto;
                min-height: 250px;
+               backdrop-filter: blur(8px) saturate(150%);
+               background-color: rgba(219, 219, 219, 0.45);
+               border: 1px solid #ececec77;
        }
 
        .input-group {
index f80b1e9d8d9b4b890c0550f8d43d4d0aae9ce1bb..2e30ae0937ef599d00477cab91ca8f82cdb371d3 100644 (file)
@@ -3,6 +3,6 @@ import {writable} from 'svelte/store';
 export const readingMode = writable(false);
 
 export const useTrianglify = writable(true);
-export const trianglifyOpacity = writable(0.8);
+export const trianglifyOpacity = writable(0.4);
 export const trianglifyColor = writable('');
 export const backgroundColor = writable('');
\ No newline at end of file
index 7cbf8a3df9ed9641eac08706fdd64d1bbee4f6c9..92749be81a13dc878fcdc84209d6ad71a565af09 100644 (file)
                                oldCanvas.remove();
                        }
 
+                       //xColors: ['#F3F3F3', '#FEFEFE', '#E5E5E5'],
                        const canvas = trianglify({
                                width: window.innerWidth,
-                               height: window.innerHeight
+                               height: window.innerHeight,
+                               xColors: ['#FA2'],
+                               fill: false,
+                               strokeWidth: 1,
+                               cellSize: 100
                        });
 
                        document.body.appendChild(canvas.toCanvas());
                        document.querySelector('canvas').style =
-                               'position: fixed; top: 0; left: 0; z-index: -1; opacity: 0.8; width: 100%; height: 100%;';
+                               'position: fixed; top: 0; left: 0; z-index: -1; opacity: 0.4; width: 100%; height: 100%; background-color: #eaeaea;';
                }
        }
 
index b6c465ab591799cdea2b874b85727ea3dd554490..eca3ea8e06a65d81eb438277adc8cff6d48ffb6a 100644 (file)
@@ -11,6 +11,9 @@
        import '../../../node_modules/tiny-markdown-editor/dist/tiny-mde.css';
        import { API_URL } from '$lib/APIurl.js';
        import DatepickerLogic from '$lib/DatepickerLogic.svelte';
+       import { faCloudArrowUp } from '@fortawesome/free-solid-svg-icons';
+       import Fa from 'svelte-fa';
+       import { v4 as uuidv4 } from 'uuid';
 
        axios.interceptors.request.use((config) => {
                config.withCredentials = true;
                                toast.show();
                        });
        }
+
+       function triggerFileInput() {
+               document.getElementById('fileInput').click();
+       }
+
+       function onFileChange(event) {
+               for (let i = 0; i < event.target.files.length; i++) {
+                       uploadFile(event.target.files[i]);
+               }
+       }
+
+       let uploadingFiles = $state([]);
+
+       function uploadFile(f) {
+               let uuid = uuidv4();
+
+               uploadingFiles = [...uploadingFiles, { name: f.name, progress: 0, size: f.size, uuid: uuid }];
+
+               const config = {
+                       onUploadProgress: (progressEvent) => {
+                               uploadingFiles = uploadingFiles.map((file) => {
+                                       if (file.uuid === uuid) {
+                                               file.progress = Math.round(progressEvent.progress * 100);
+                                       }
+                                       return file;
+                               });
+                       }
+               };
+
+               const formData = new FormData();
+               formData.append('day', $selectedDate.getDate());
+               formData.append('month', $selectedDate.getMonth() + 1);
+               formData.append('year', $selectedDate.getFullYear());
+               formData.append('file', f);
+               formData.append('uuid', uuid);
+
+               axios
+                       .post(API_URL + '/logs/uploadFile', formData, {
+                               ...config
+                       })
+                       .then((response) => {
+                               console.log(response);
+                       })
+                       .catch((error) => {
+                               console.error(error);
+                       })
+                       .finally(() => {
+                               uploadingFiles = uploadingFiles.filter((file) => file.uuid !== uuid);
+                       });
+       }
 </script>
 
 <DatepickerLogic />
                </div>
        </div>
 
-       <div id="right">Right</div>
+       <div id="right" class="d-flex flex-column">
+               <div>Tags</div>
+
+               <div class="files">
+                       <button class="btn btn-secondary" id="uploadBtn" onclick={triggerFileInput}
+                               ><Fa icon={faCloudArrowUp} class="me-2" id="uploadIcon" />Upload</button
+                       >
+                       <input type="file" id="fileInput" multiple style="display: none;" onchange={onFileChange} />
+
+                       {#each uploadingFiles as file}
+                               <div>
+                                       {file.name}
+                                       <div
+                                               class="progress"
+                                               role="progressbar"
+                                               aria-label="Upload progress"
+                                               aria-valuemin="0"
+                                               aria-valuemax="100"
+                                       >
+                                               <div
+                                                       class="progress-bar {file.progress === 100
+                                                               ? 'progress-bar-striped progress-bar-animated'
+                                                               : ''}"
+                                                       style:width={file.progress + '%'}
+                                               >
+                                                       {#if file.progress !== 100}
+                                                               {file.progress}%
+                                                       {:else}
+                                                               Wird verschlüsselt...
+                                                       {/if}
+                                               </div>
+                                       </div>
+                               </div>
+                       {/each}
+               </div>
+       </div>
 
        <div class="toast-container position-fixed bottom-0 end-0 p-3">
                <div
 </div>
 
 <style>
+       :global(#uploadIcon) {
+               transition: all ease 0.3s;
+       }
+
+       :global(#uploadBtn:hover > #uploadIcon) {
+               transform: scale(1.2);
+       }
+
        :global(.TMCommandBar) {
                border-top: 1px solid #ccc;
                border-left: 1px solid #ccc;
git clone https://git.99rst.org/PROJECT