Compare commits
8 Commits
09e1e74af2
...
improve_ce
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c6a8dfba2 | ||
|
|
c30d69d205 | ||
|
|
56d3468889 | ||
|
|
26ea274023 | ||
|
|
0c96d04326 | ||
|
|
352540a3b1 | ||
|
|
7d828a7c3b | ||
|
|
93f2c59997 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,4 +3,5 @@ app/files/
|
||||
app/pwfile.json
|
||||
app/dest
|
||||
app.log
|
||||
init.log
|
||||
app/__pycache__/
|
||||
|
||||
Binary file not shown.
81
app/init.py
81
app/init.py
@@ -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
152
app/init_ssh.py
Normal 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()
|
||||
177
app/main.py
177
app/main.py
@@ -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]:
|
||||
|
||||
95
index.html
95
index.html
@@ -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">×</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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user