Compare commits

...

8 Commits

9 changed files with 606 additions and 180 deletions

1
.gitignore vendored
View File

@@ -3,4 +3,5 @@ app/files/
app/pwfile.json
app/dest
app.log
init.log
app/__pycache__/

Binary file not shown.

View File

@@ -1,10 +1,12 @@
import paramiko
from os.path import isdir
from stat import S_ISDIR, S_ISREG
import re
import pathlib
# from base64 import decodebytes
import json
import mariadb
import logging
CATEGORIES = [
"Prüfungen",
@@ -16,7 +18,18 @@ CATEGORIES = [
"Multimedia",
]
SUBCAT_CATEGORIES = ["Klausuren", "Übungen", "Labore"]
unizeug_path = "/mnt/save/daten/Unizeug/"
unizeug_path = "/home/wildarch/web/fet_unizeug/unizeug/"
log = logging.getLogger(__name__)
logging.basicConfig(
filename="init.log",
level=logging.INFO,
format="[%(asctime)s, %(filename)s:%(lineno)s -> %(funcName)10s() ]%(levelname)s: %(message)s",
)
debug = log.debug
info = log.info
error = log.error
db = mariadb.connect(
host="localhost", user="wildserver", password="DBPassword", database="Unizeug"
)
@@ -53,29 +66,31 @@ db.commit()
def get_dirstruct():
with open("app/pwfile.json", "r") as f:
cred = json.load(f)
ssh = paramiko.SSHClient()
print(cred["sftpurl"])
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# with open("app/pwfile.json", "r") as f:
# cred = json.load(f)
# ssh = paramiko.SSHClient()
# print(cred["sftpurl"])
# ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# key=paramiko.RSAKey(data=decodebytes(bytes(cred["key"],"utf-8")))
# ssh.get_host_keys().add(cred["sftpurl"], 'ssh-rsa', key)
ssh.connect(cred["sftpurl"], username=cred["sftpuser"], password=cred["sftpPW"])
sftp = ssh.open_sftp()
folders = sftp.listdir_attr(unizeug_path)
for entry in folders:
# ssh.connect(cred["sftpurl"], username=cred["sftpuser"], password=cred["sftpPW"])
# sftp = ssh.open_sftp()
# folders = sftp.listdir_attr(unizeug_path)
folders=pathlib.Path(unizeug_path)
for entry in folders.iterdir():
if entry is None:
continue
if not S_ISDIR(entry.st_mode):
if not entry.is_dir():
continue
fname = str(entry.filename)
fname = str(entry.name)
regex = re.compile(r"Multimedia_only")
if regex.search(fname):
continue
# print(fname)
lvid = re.search(r"[a-zA-Z0-9]{3}\.[a-zA-Z0-9]{3}", fname)
print(lvid)
# print(lvid)
if lvid is None:
error(f"Didnt Find LVA ID in Directory {fname}")
continue
lvid = lvid.group()[:3] + lvid.group()[4:]
# name = fname[:-8]
@@ -89,39 +104,35 @@ def get_dirstruct():
cur.execute("SELECT id FROM LVAs WHERE lvid=?", (lvid,))
lid = cur.fetchone()[0]
db.commit()
for profsdir in sftp.listdir_attr(unizeug_path + fname + "/"):
if profsdir is None or not S_ISDIR(profsdir.st_mode):
for profsdir in entry.iterdir():
if profsdir is None:
continue
if not profsdir.is_dir():
continue
# print(profsdir.filename)
try:
lastname, firstname = re.split(r"[_\-\s]", str(profsdir.filename))
lastname, firstname = re.split(r"[_\-\s]", str(profsdir.name))
pid = link_prof(firstname, lastname, lid)
except ValueError:
print(f"{name} is broken")
error(f"Couldnt get Profs from {fname}")
continue
for cat in sftp.listdir_attr(
unizeug_path + fname + "/" + profsdir.filename + "/"
):
if cat is None or not S_ISDIR(cat.st_mode):
for cat in profsdir.iterdir():
if cat is None:
continue
if cat.filename not in SUBCAT_CATEGORIES:
if not cat.is_dir():
continue
idx = CATEGORIES.index(cat.filename)
for subcat in sftp.listdir_attr(
unizeug_path
+ fname
+ "/"
+ profsdir.filename
+ "/"
+ cat.filename
+ "/"
):
if subcat is None or not S_ISDIR(subcat.st_mode):
if cat.name not in SUBCAT_CATEGORIES:
continue
idx = CATEGORIES.index(cat.name)
for subcat in cat.iterdir():
if subcat is None:
continue
if not subcat.is_dir():
continue
cur = db.cursor()
cur.execute(
"INSERT INTO SubCats (LId,PId,cat,name) VALUES(?,?,?,?)",
(lid, pid, idx, subcat.filename),
(lid, pid, idx, subcat.name),
)
db.commit()

152
app/init_ssh.py Normal file
View File

@@ -0,0 +1,152 @@
import paramiko
from stat import S_ISDIR, S_ISREG
import re
# from base64 import decodebytes
import json
import mariadb
CATEGORIES = [
"Prüfungen",
"Klausuren",
"Übungen",
"Labore",
"Unterlagen",
"Zusammenfassungen",
"Multimedia",
]
SUBCAT_CATEGORIES = ["Klausuren", "Übungen", "Labore"]
unizeug_path = "/mnt/save/daten/Unizeug/"
db = mariadb.connect(
host="localhost", user="wildserver", password="DBPassword", database="Unizeug"
)
c = db.cursor()
try:
c.execute("DROP TABLE LVAs")
except mariadb.OperationalError:
pass
c.execute(
"CREATE TABLE LVAs(id BIGINT(20) unsigned NOT NULL AUTO_INCREMENT,lvid VARCHAR(6), lvname VARCHAR(256), lvpath VARCHAR(256),PRIMARY KEY(id))"
)
try:
c.execute("DROP TABLE Profs")
except mariadb.OperationalError:
pass
c.execute(
"CREATE TABLE Profs(id BIGINT(20) unsigned NOT NULL AUTO_INCREMENT,name VARCHAR(256),PRIMARY KEY(id))"
)
try:
c.execute("DROP TABLE LPLink")
except mariadb.OperationalError:
pass
c.execute(
"CREATE TABLE LPLink(id BIGINT(20) unsigned NOT NULL AUTO_INCREMENT,LId bigint(20),PId bigint(20),PRIMARY KEY(id))"
)
try:
c.execute("DROP TABLE SubCats")
except mariadb.OperationalError:
pass
c.execute(
"CREATE TABLE SubCats(id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,LId BIGINT(20),PId BIGINT(20),cat TINYINT UNSIGNED,name VARCHAR(256), PRIMARY KEY(id))"
)
db.commit()
def get_dirstruct():
with open("app/pwfile.json", "r") as f:
cred = json.load(f)
ssh = paramiko.SSHClient()
print(cred["sftpurl"])
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# key=paramiko.RSAKey(data=decodebytes(bytes(cred["key"],"utf-8")))
# ssh.get_host_keys().add(cred["sftpurl"], 'ssh-rsa', key)
ssh.connect(cred["sftpurl"], username=cred["sftpuser"], password=cred["sftpPW"])
sftp = ssh.open_sftp()
folders = sftp.listdir_attr(unizeug_path)
for entry in folders:
if entry is None:
continue
if not S_ISDIR(entry.st_mode):
continue
fname = str(entry.filename)
regex = re.compile(r"Multimedia_only")
if regex.search(fname):
continue
# print(fname)
lvid = re.search(r"[a-zA-Z0-9]{3}\.[a-zA-Z0-9]{3}", fname)
print(lvid)
if lvid is None:
continue
lvid = lvid.group()[:3] + lvid.group()[4:]
# name = fname[:-8]
name = re.sub(r"[a-zA-Z0-9]{3}\.[a-zA-Z0-9]{3}", "", fname)
# print(name)
# print(lvid)
cur = db.cursor()
cur.execute(
"INSERT INTO LVAs (lvid, lvname, lvpath) VALUES(?,?,?)", (lvid, name, fname)
)
cur.execute("SELECT id FROM LVAs WHERE lvid=?", (lvid,))
lid = cur.fetchone()[0]
db.commit()
for profsdir in sftp.listdir_attr(unizeug_path + fname + "/"):
if profsdir is None or not S_ISDIR(profsdir.st_mode):
continue
# print(profsdir.filename)
try:
lastname, firstname = re.split(r"[_\-\s]", str(profsdir.filename))
pid = link_prof(firstname, lastname, lid)
except ValueError:
print(f"{name} is broken")
continue
for cat in sftp.listdir_attr(
unizeug_path + fname + "/" + profsdir.filename + "/"
):
if cat is None or not S_ISDIR(cat.st_mode):
continue
if cat.filename not in SUBCAT_CATEGORIES:
continue
idx = CATEGORIES.index(cat.filename)
for subcat in sftp.listdir_attr(
unizeug_path
+ fname
+ "/"
+ profsdir.filename
+ "/"
+ cat.filename
+ "/"
):
if subcat is None or not S_ISDIR(subcat.st_mode):
continue
cur = db.cursor()
cur.execute(
"INSERT INTO SubCats (LId,PId,cat,name) VALUES(?,?,?,?)",
(lid, pid, idx, subcat.filename),
)
db.commit()
def link_prof(firstname, lastname, lid):
cur = db.cursor()
cur.execute("SELECT id from Profs WHERE name=?", (lastname + " " + firstname,))
res = cur.fetchone()
if res is not None:
cur.execute("INSERT INTO LPLink (LId,PId) VALUES(?,?)", (lid, res[0]))
db.commit()
return res[0]
cur.execute("SELECT id from Profs WHERE name=?", (firstname + " " + lastname,))
res = cur.fetchone()
if res is not None:
cur.execute("INSERT INTO LPLink (LId,PId) VALUES(?,?)", (lid, res[0]))
db.commit()
return res[0]
cur.execute("INSERT INTO Profs (name) VALUES(?)", (lastname + " " + firstname,))
cur.execute("SELECT id FROM Profs WHERE name=?", (lastname + " " + firstname,))
res = cur.fetchone()
cur.execute("INSERT INTO LPLink (LId,PId) VALUES(?,?)", (lid, res[0]))
db.commit()
return res[0]
if __name__ == "__main__":
get_dirstruct()

View File

@@ -1,16 +1,21 @@
from typing import Annotated
from typing import List, Dict, Tuple, Sequence
from starlette.responses import StreamingResponse
from annotated_types import IsDigit
from fastapi import FastAPI, File, HTTPException, UploadFile, Request, Form
from fastapi.responses import FileResponse
# import multiprocessing
# import threading
# import concurrent.futures
# import asyncio
import asyncio
# import fastapi
from fastapi.staticfiles import StaticFiles
import pymupdf
# import fitz as pymupdf
import json
import re
@@ -24,6 +29,7 @@ import datetime
import logging
import inspect
import pathlib
from starlette.types import HTTPExceptionHandler
@@ -76,6 +82,9 @@ GREETINGFILE = "./app/graphics/greeting.pdf"
# for l in cur:
# print(l)
# locpaths = ["./VO_Mathematik_3.pdf"] # replace this with a database
censor_status_update_events: Dict[str, asyncio.Event] = {}
censor_status_datas: Dict[str, Dict[str, int | None | str | bool]] = {}
# censor_finished_flags: Dict[str, asyncio.Event] = {}
def _sql_quarry(
@@ -405,14 +414,14 @@ async def get_submission(
pagescales: Annotated[
str, Form()
], # Scales of Pages # Annotated[List[Dict[str, float]], Form()],
censor: Annotated[str, Form()],
ocr: Annotated[str, Form()],
):
"""handles submission"""
print(
f"lva: {lva}, prof: {prof}, fname {fname}, stype: {stype}, subcat: {subcat}, sem: {sem}, ex_date: {ex_date}, rects: {rects}, pagescales: {pagescales}, censor: {censor}"
f"lva: {lva}, prof: {prof}, fname {fname}, stype: {stype}, subcat: {subcat}, sem: {sem}, ex_date: {ex_date}, rects: {rects}, pagescales: {pagescales}, ocr: {ocr}"
)
info(
f"lva: {lva}, prof: {prof}, fname {fname}, stype: {stype}, subcat: {subcat}, sem: {sem}, ex_date: {ex_date}, rects: {rects}, pagescales: {pagescales}, censor: {censor}"
f"lva: {lva}, prof: {prof}, fname {fname}, stype: {stype}, subcat: {subcat}, sem: {sem}, ex_date: {ex_date}, rects: {rects}, pagescales: {pagescales}, ocr: {ocr}"
)
rects_p = json.loads(rects)
scales_p = json.loads(pagescales)
@@ -441,25 +450,123 @@ async def get_submission(
except ValueError as e:
error(f"Error creating savepath: {e}")
raise HTTPException(status_code=400, detail=f"Error creation savepath: {e}")
await censor_pdf(
filepath, dest, rects_p, scales_p, False if censor == "False" else True
# censor_finished_flags[fileId] = asyncio.Event()
censor_status_datas[fileId] = {}
if fileId not in censor_status_update_events:
censor_status_update_events[fileId] = asyncio.Event()
if ocr == "True":
await asyncio.to_thread(
censor_pdf_ocr,
filepath,
dest,
rects_p,
scales_p,
fileId,
)
else:
await asyncio.to_thread(
censor_pdf,
filepath,
dest,
rects_p,
scales_p,
fileId,
)
# return {"done": "ok"}
# print(dest)
# await censor_finished_flags[fileId].wait()
# censor_finished_flags[fileId].clear()
info(f"Saved file {fileId} as {dest}")
delete_from_FIP(fileId)
return FileResponse(dest, content_disposition_type="inline")
async def censor_pdf(
@app.get("/get_censor_status/{file_id}")
async def get_censor_status(file_id: str):
"""Yields the currrent page being censored and the total number of pages"""
if len(sql("Select filename from FIP where id=?", (file_id,))) < 1:
raise HTTPException(
400,
detail="You are trying to get a status updater for a file that dosent exist.",
)
if file_id not in censor_status_update_events:
censor_status_update_events[file_id] = asyncio.Event()
return StreamingResponse(
yield_censor_status(file_id), media_type="text/event-stream"
)
async def yield_censor_status(file_id: str):
"""Internal function to yield updates to the stream"""
while True:
await censor_status_update_events[file_id].wait()
censor_status_update_events[file_id].clear()
yield f"event: censorUpdate\ndata: {json.dumps(censor_status_datas[file_id])}\n\n"
if censor_status_datas[file_id]["done"]:
del censor_status_update_events[file_id]
del censor_status_datas[file_id]
return
def censor_pdf(
path: str,
destpath: str,
rects: List[List[List[float]]],
scales: List[Dict[str, float]],
secure: bool,
file_id: str,
):
"""Censors pdf and saves the file to the given Destpath.
Args:
path: path to the pdf document
destpath: Path where the result is supposed to be saved to
rects: Coordinates of rectangles to be placed on the pdf document
scales: Scales of the rects coordinates for the pdf document
secure: weather or not the pdf document is supposed to be converted into an Image (and back) to make shure, the censoring is irreversible
Returns:
None
"""
doc = pymupdf.open(path)
page = doc[0]
npage = doc.page_count
for i in range(npage):
page = doc[i]
if i < len(rects) and rects[i] != []:
print(i)
wfac = page.rect.width / scales[i]["width"]
hfac = page.rect.height / scales[i]["height"]
for rect in rects[i]:
prect = pymupdf.Rect(
rect[0] * wfac,
rect[1] * hfac,
(rect[0] + rect[2]) * wfac,
(rect[1] + rect[3]) * hfac,
)
page.add_redact_annot(
prect,
fill=(0, 0, 0),
)
page.apply_redactions()
censor_status_datas[file_id]["page"] = i + 1
censor_status_datas[file_id]["pages"] = npage
censor_status_datas[file_id]["done"] = False
censor_status_update_events[file_id].set()
doc.set_metadata({})
doc.save(destpath, garbage=4, deflate=True, clean=True)
censor_status_datas[file_id]["done"] = True
censor_status_update_events[file_id].set()
def censor_pdf_ocr(
path: str,
destpath: str,
rects: List[List[List[float]]],
scales: List[Dict[str, float]],
file_id: str,
):
"""Censors pdf and runs OCR
If Secure is True the file is converted to Pixels and then recreated; else the censored sections are just covering the text below and can be easiliy removed with e.g. Inkscape
The file is converted to Pixels and then recreated.
Saves the file to the given Destpath.
Args:
path: path to the pdf document
destpath: Path where the result is supposed to be saved to
@@ -472,12 +579,7 @@ async def censor_pdf(
doc = pymupdf.open(path)
output = pymupdf.open()
page = doc[0]
# width = page.rect.width
# height = page.rect.height
# print(width, height)
npage = doc.page_count
# pages = []
# tasks = []
for i in range(npage):
page = doc[i]
if i < len(rects) and rects[i] != []:
@@ -496,38 +598,22 @@ async def censor_pdf(
color=(0, 0, 0),
fill=(0, 0, 0),
)
if secure:
# pages.append(page)
censor_status_datas[file_id]["page"] = i + 1
censor_status_datas[file_id]["pages"] = npage
censor_status_datas[file_id]["done"] = False
censor_status_update_events[file_id].set()
# THis Costs us dearly
bitmap = page.get_pixmap(dpi=400)
pdf_bytes = bitmap.pdfocr_tobytes(
language="deu",
tessdata="/usr/share/tessdata/", # tesseract needs to be installed; this is the path to thetesseract files
)
output.insert_pdf(pymupdf.Document(stream=pdf_bytes))
# tasks.append(asyncio.create_task(censor_page(page)))
# End of the costly part
print(f"Page {i + 1}/{npage}: CENSORING DONE")
else:
output.insert_pdf(doc, i, i)
# if secure:
# pages_bytes: List[bytes] = []
# censor_page(pages[0])
# with multiprocessing.Pool(npage) as p:
# pages_bytes = p.map(censor_page, pages)
# pages_bytes = p.map(test_function, [1, 2, 3, 4])
# for pdf_bytes in pages_bytes:
# output.insert_pdf(pymupdf.Document(stream=pdf_bytes))
# with concurrent.futures.ThreadPoolExecutor() as executor:
# futures = []
# for page in pages:
# futures.append(executor.submit(censor_page, page))
# for future in futures:
# output.insert_pdf(pymupdf.Document(stream=future.result()))
#
# for task in tasks:
# output.insert_pdf(pymupdf.Document(stream=await task))
# print("CENSORING DONE")
output.save(destpath)
censor_status_datas[file_id]["done"] = True
censor_status_update_events[file_id].set()
def test_function(i: int) -> bytes:
@@ -607,9 +693,18 @@ def make_savepath(
400,
"You have not specified a date for an upload that requires a date like an exam.",
)
filename += yyyy + "_" + mm + "_" + dd + "_"
filename += fname + "." + ftype
return savepath + filename
filename = yyyy + "_" + mm + "_" + dd + "_"
filename += fname
file = filename + "." + ftype
destpath = pathlib.Path(savepath + file)
i = 0
while destpath.is_file():
file = filename + f"_{i}." + ftype
i += 1
destpath = pathlib.Path(savepath + file)
destpath.touch()
return savepath + file
def get_lvpath(lva: str) -> Tuple[int, str]:

View File

@@ -1,7 +1,6 @@
<!doctype html>
<html lang="de">
<head>
<head>
<title>Unizeug uploader</title>
<link rel="stylesheet" href="static/style.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.4.456/pdf.min.js"></script>
@@ -9,22 +8,47 @@
<script src="static/autocomplete.js" defer></script>
<script src="static/dynhide.js" defer></script>
<script src="static/filedrop.js" defer></script>
<link rel="icon" type="image/png" href="/favicon/favicon-96x96.png" sizes="96x96" />
<link
rel="icon"
type="image/png"
href="/favicon/favicon-96x96.png"
sizes="96x96"
/>
<link rel="icon" type="image/svg+xml" href="/favicon/favicon.svg" />
<link rel="shortcut icon" href="/favicon/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png" />
<link
rel="apple-touch-icon"
sizes="180x180"
href="/favicon/apple-touch-icon.png"
/>
<meta name="apple-mobile-web-app-title" content="Unizeug" />
<link rel="manifest" href="/favicon/site.webmanifest" />
</head>
</head>
<body>
<body>
<!-- The Modal -->
<div id="loading" class="modal">
<!-- Modal content -->
<div class="loading-content">
<!-- <span class="close">&times;</span> -->
<div class="loader"></div>
<p id="upload_status" class="upload_status_text">Uploading</p>
</div>
</div>
<!-- main -->
<div class="main">
<div class="left" id="controldiv">
<div id="fileupload">
<form id="uploadform" enctype="multipart/form-data">
<div class="filetop">
<!-- <label for="filepicker">Choose a file</label> -->
<input type="file" name="files" id="filepicker" multiple placeholder="Drop File" />
<input
type="file"
name="files"
id="filepicker"
multiple
placeholder="Drop File"
/>
</div>
<button type="submit" id="upload" method="POST" class="fileupload">
Upload
@@ -35,21 +59,44 @@
<form id="submitform" ,onsubmit="submitFile(event)">
<label for="lva">Lehrveranstaltung:</label>
<div class="autocomplete">
<input type="text" id="lva" name="lva" placeholder="Lehrveranstaltung" autocomplete="off" />
<input
type="text"
id="lva"
name="lva"
placeholder="Lehrveranstaltung"
autocomplete="off"
/>
</div>
<br />
<!-- <br /> -->
<label for="prof">Vortragende*r:</label>
<div class="autocomplete">
<input type="text" id="prof" name="prof" placeholder="Vortragende*r" autocomplete="off" />
<input
type="text"
id="prof"
name="prof"
placeholder="Vortragende*r"
autocomplete="off"
/>
</div>
<br />
<!-- <br /> -->
<label for="name">Name:</label>
<input type="text" id="name" name="fname" placeholder="Prüfung" /><br />
<input
type="text"
id="name"
name="fname"
placeholder="Prüfung"
/><br />
<label for="sem">Semester:</label>
<input type="text" id="sem" name="sem" placeholder="2024W" /><br />
<input type="radio" id="pruefung" name="stype" value="0" checked="checked" />
<input
type="radio"
id="pruefung"
name="stype"
value="0"
checked="checked"
/>
<label for="pruefung">Prüfung</label><br />
<input type="radio" id="klausur" name="stype" value="1" />
<label for="klausur">Klausur</label><br />
@@ -67,15 +114,30 @@
<div id="subcatdiv">
<label for="subcat">Veranstaltung</label>
<div class="autocomplete">
<input type="text" id="subcat" name="subcat" placeholder="Klausur 1" autocomplete="off" />
<input
type="text"
id="subcat"
name="subcat"
placeholder="Klausur 1"
autocomplete="off"
/>
</div>
</div>
<div id="datediv">
<label for="date">Datum</label>
<input type="date" id="date" name="ex_date" placeholder="Drop File" /><br />
<input
type="date"
id="date"
name="ex_date"
placeholder="Drop File"
/><br />
</div>
<input type="checkbox" name="censor" id="sec_censor" value="True" checked /><label
for="sec_censor">Zensieren</label><br /><br />
<input
type="checkbox"
name="ocr"
id="sec_censor"
value="True"
/><label for="sec_censor">OCR</label><br /><br />
<button type="submit" id="send">Senden</button>
</form>
</div>
@@ -98,6 +160,5 @@
</div>
</div>
</div>
</body>
</body>
</html>

View File

@@ -188,6 +188,9 @@ class PDFDocument {
}
}
var mouseIsDown = false;
var modal;
var close_loading;
var upload_status;
//var startX = 0;
//var startY = 0;
//var pdf;
@@ -273,18 +276,31 @@ function submitPdf(eve) {
formdata.append("fileId", doc.fID);
//formdata.append("filename", doc.filename);
formdata.append("ftype", doc.filetype);
if (!formdata.has("censor")) {
formdata.append("censor", "False");
if (!formdata.has("ocr")) {
formdata.append("ocr", "False");
}
console.log(formdata);
submitForm(formdata);
}
async function submitForm(formData) {
try {
const updateEventSource = new EventSource(
"http://127.0.0.1:8000/get_censor_status/" + doc.fID,
);
modal.style.display = "flex";
// console.log("http://127.0.0.1:8000/get_censor_status/" + doc.fID);
updateEventSource.addEventListener("censorUpdate", function(eve) {
console.log(eve.data);
var data = JSON.parse(eve.data);
upload_status.innerText =
"Censoring Page " + data.page + "/" + data.pages;
});
const response = await fetch("http://127.0.0.1:8000/submit", {
method: "POST",
body: formData,
});
updateEventSource.close();
modal.style.display = "none";
//let responseJSON=await response.json();
if (response.ok) {
console.log("Submit OK");
@@ -366,6 +382,14 @@ function initListeners() {
doc.clearAll();
});
}
function initLoading() {
modal = document.querySelector("#loading");
// close_loading = document.querySelector(".close");
upload_status = document.querySelector("#upload_status");
// close_loading.addEventListener("click", function() {
// modal.style.display = "none";
// });
}
const startPdf = () => {
// doc = new PDFDocument(
// "./files/b78c869f-e0bb-11ef-9b58-84144d05d665",
@@ -374,6 +398,7 @@ const startPdf = () => {
// );
//pdf = new PDFView("./VO_Mathematik_3.pdf");
doc = new PDFDocument("./files/greeting", "greeting", "pdf");
initLoading();
initDraw();
initUpload();
initListeners();

View File

@@ -21,7 +21,7 @@ function autocomplete(inp, type) {
i,
apirq,
iname,
val = this.value;
val = inp.value;
/*close any already open lists of autocompleted values*/
closeAllLists();
if (!val && type === "lva" && pid === null) {
@@ -56,7 +56,7 @@ function autocomplete(inp, type) {
a.setAttribute("id", this.id + "autocomplete-list");
a.setAttribute("class", "autocomplete-items");
/*append the DIV element as a child of the autocomplete container:*/
this.parentNode.appendChild(a);
inp.parentNode.appendChild(a);
/*for each item in the array...*/
//await response;
if (response.ok) {

View File

@@ -238,3 +238,84 @@ input[type="file"]::file-selector-button {
width: 100%;
/* background-color: purple; */
}
/* The Modal (background) */
.modal {
display: none;
/* Hidden by default */
position: fixed;
/* Stay in place */
z-index: 1;
/* Sit on top */
left: 0;
top: 0;
width: 100%;
/* Full width */
height: 100%;
/* Full height */
overflow: auto;
/* Enable scroll if needed */
background-color: #4f5977;
/* Fallback color */
background-color: rgba(0, 0, 0, 0.4);
/* Black w/ opacity */
justify-content: center;
}
/* Modal Content/Box */
.loading-content {
background-color: #4f5977;
margin: auto;
/* 15% from the top and centered */
padding: 20px;
/* border: 1px solid #888; */
/* width: 80%; */
border-radius: 15px;
display: flex;
flex-direction: column;
/* Could be more or less, depending on screen size */
align-items: center;
text-align: center;
}
/* The Close Button */
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
.upload_status_text {
color: #ffffff;
font-size: 16pt;
}
.loader {
margin: auto;
border: 16px solid #f3f3f3;
/* Light grey */
border-top: 16px solid #3498db;
/* Blue */
border-radius: 50%;
width: 120px;
height: 120px;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}