Compare commits
10 Commits
8a717f38fd
...
09e1e74af2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09e1e74af2 | ||
|
|
6b1805c0ac | ||
|
|
8a69b7fbaf | ||
|
|
ec08eea910 | ||
|
|
46f44901e8 | ||
|
|
4a6e74aada | ||
|
|
f13e8711a7 | ||
|
|
d6d3f46c78 | ||
|
|
ac16b1ea7b | ||
|
|
b4c5daa212 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,3 +2,5 @@ app/venv/
|
|||||||
app/files/
|
app/files/
|
||||||
app/pwfile.json
|
app/pwfile.json
|
||||||
app/dest
|
app/dest
|
||||||
|
app.log
|
||||||
|
app/__pycache__/
|
||||||
|
|||||||
Binary file not shown.
BIN
app/graphics/empty.pdf
Normal file
BIN
app/graphics/empty.pdf
Normal file
Binary file not shown.
65
app/graphics/empty.svg
Normal file
65
app/graphics/empty.svg
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="210mm"
|
||||||
|
height="297mm"
|
||||||
|
viewBox="0 0 210 297"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||||
|
sodipodi:docname="empty.svg"
|
||||||
|
inkscape:export-filename="empty.pdf"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:zoom="0.85670232"
|
||||||
|
inkscape:cx="566.70793"
|
||||||
|
inkscape:cy="542.77896"
|
||||||
|
inkscape:window-width="1504"
|
||||||
|
inkscape:window-height="931"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:#ffffff;stroke-width:0.407001;stroke-opacity:0.247707"
|
||||||
|
d="m 48.79125,72.679957 0.7721,56.517593 27.949953,0.7721 0.30884,-5.25027 -22.545267,-0.7721 -0.772099,-8.33866 22.390848,-0.15442 0.30884,-5.55911 -23.008528,0.46326 -0.926518,-30.72951 23.471787,-0.308837 -0.61768,-7.875403 z"
|
||||||
|
id="path1" />
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:#ffffff;stroke-width:0.407001;stroke-opacity:0.247707"
|
||||||
|
d="m 88.01384,130.27848 -1.389777,-57.444103 21.309907,25.942499 24.39831,-25.63366 2.00745,56.672004 -5.86794,0.30884 -0.61768,-43.237495 -19.30246,18.993615 -18.067096,-21.155491 1.853035,44.936111 z"
|
||||||
|
id="path2" />
|
||||||
|
<path
|
||||||
|
id="path3"
|
||||||
|
style="fill:#000000;stroke:#ffffff;stroke-width:0.407001;stroke-opacity:0.247707"
|
||||||
|
d="m 158.99066,69.906981 c -5.69894,0.0074 -10.75335,1.691886 -10.75335,1.691886 l 0.61805,58.525113 h 8.02949 l -0.46303,-28.25874 c 0,0 18.53005,6.02224 18.37563,-16.523026 -0.0869,-12.681712 -8.47959,-15.444734 -15.80679,-15.435233 z m 1.53117,5.377966 c 2.78363,-0.0438 5.81711,1.425874 6.09162,7.895642 0.48035,11.32111 -8.86154,11.068264 -10.18077,10.976591 0.1175,0.12788 -0.16537,-0.01292 -0.16537,-0.01292 0,0 0.0655,0.006 0.16537,0.01292 -0.004,-0.0048 -0.005,-0.0073 -0.0109,-0.01292 -0.15442,-0.154419 -0.61753,-17.603576 -0.61753,-17.603576 0,0 2.2614,-1.217094 4.71754,-1.255738 z" />
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:#ffffff;stroke-width:0.407001;stroke-opacity:0.247707"
|
||||||
|
d="m 45.548438,148.65442 h 34.126741 v 6.48562 H 64.387633 l 0.308841,37.83282 -6.331207,-0.30884 -0.308837,-37.83281 H 45.239599 Z"
|
||||||
|
id="path4" />
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:#ffffff;stroke-width:0.407001;stroke-opacity:0.247707"
|
||||||
|
d="M 98.668793,148.34558 105,148.5 l 8.18424,19.61129 12.66241,-19.76571 h 8.33866 l -29.49415,47.25241 -7.103303,-0.46326 12.044733,-22.08201 z"
|
||||||
|
id="path5" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.2 KiB |
BIN
app/graphics/greeting.pdf
Normal file
BIN
app/graphics/greeting.pdf
Normal file
Binary file not shown.
193
app/graphics/greeting.svg
Normal file
193
app/graphics/greeting.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 89 KiB |
BIN
app/graphics/text2.pdf
Normal file
BIN
app/graphics/text2.pdf
Normal file
Binary file not shown.
BIN
app/graphics/unsupported.pdf
Normal file
BIN
app/graphics/unsupported.pdf
Normal file
Binary file not shown.
89
app/graphics/unsupported.svg
Normal file
89
app/graphics/unsupported.svg
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="210mm"
|
||||||
|
height="297mm"
|
||||||
|
viewBox="0 0 210 297"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||||
|
sodipodi:docname="unsupported.svg"
|
||||||
|
inkscape:export-filename="unsupported.pdf"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:zoom="0.60578002"
|
||||||
|
inkscape:cx="149.39416"
|
||||||
|
inkscape:cy="642.14729"
|
||||||
|
inkscape:window-width="1504"
|
||||||
|
inkscape:window-height="931"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:#ffffff;stroke-width:0.407001;stroke-opacity:0.247707"
|
||||||
|
d="M 9.4195981,19.765714 9.1107587,86.16616 45.708215,86.320579 45.862634,19.920134 38.759331,20.074553 39.22259,80.607052 14.361026,80.452634 v -60.68692 z"
|
||||||
|
id="path1" />
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:#ffffff;stroke-width:0.407001;stroke-opacity:0.247707"
|
||||||
|
d="m 57.135267,86.320579 -0.926518,-66.400445 11.118215,0.154419 30.11183,56.672009 -1.080937,-58.061785 8.493083,-0.15442 0.46326,66.400445 -11.890318,0.30884 -31.501606,-60.5325 0.463259,62.076696 z"
|
||||||
|
id="path2" />
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:#ffffff;stroke-width:0.407001;stroke-opacity:0.247707"
|
||||||
|
d="M 45.553793,98.674152 C 43.08308,98.82857 10.037277,98.210893 10.037277,98.210893 c 0,0 -1.0809379,31.810447 -0.4632594,31.656027 0.6176784,-0.15442 27.0234374,-0.15442 27.0234374,-0.15442 l 0.154418,27.48669 -26.869016,-0.77209 0.15442,6.48562 31.964866,0.15442 c 0,0 0.926518,-39.22259 0,-39.22259 -0.926518,0 -26.714599,-0.46326 -26.714599,-0.46326 l -1.235357,-21.30991 31.501606,0.61768 z"
|
||||||
|
id="path3" />
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:#ffffff;stroke-width:0.407001;stroke-opacity:0.247707"
|
||||||
|
d="m 56.363168,98.82857 c 0,0.772099 0.926518,65.16509 0.926518,65.16509 l 38.296072,0.15442 0.154418,-66.246028 -7.875399,-0.154418 1.080937,60.532496 -24.861562,-0.15442 -0.926518,-58.988299 z"
|
||||||
|
id="path4" />
|
||||||
|
<path
|
||||||
|
id="path5"
|
||||||
|
style="fill:#000000;stroke:#ffffff;stroke-width:0.407001;stroke-opacity:0.247707"
|
||||||
|
d="M 109.7318 98.26377 C 107.54339 98.239641 106.08655 98.365055 106.08655 98.365055 L 106.08655 165.22919 L 113.4985 164.61114 L 112.88097 124.61668 C 112.88097 124.61668 129.7124 123.5357 129.55798 109.94678 C 129.44217 99.755078 116.29705 98.336154 109.7318 98.26377 z M 113.65301 103.46139 C 113.65301 103.46139 122.45454 104.54227 122.45454 111.95441 C 122.45454 119.36655 113.65301 118.90334 113.65301 118.90334 L 113.65301 103.46139 z " />
|
||||||
|
<path
|
||||||
|
id="path6"
|
||||||
|
style="fill:#000000;stroke:#ffffff;stroke-width:0.407001;stroke-opacity:0.247707"
|
||||||
|
d="M 139.54187 99.033748 C 138.14225 99.050713 137.27896 99.137618 137.27896 99.137618 C 137.27896 100.68182 137.7425 165.38319 137.7425 165.38319 L 146.54403 165.07468 L 146.39003 132.02863 C 146.39003 132.02863 160.90518 134.34533 161.36844 115.50613 C 161.74484 100.19928 145.60687 98.960233 139.54187 99.033748 z M 146.85305 106.08655 C 146.85305 106.08655 155.19184 107.63034 155.6551 116.58668 C 156.11836 125.54302 146.85305 125.85227 146.85305 125.85227 C 146.85305 125.85227 147.00747 124.61691 146.85305 106.08655 z " />
|
||||||
|
<path
|
||||||
|
id="path7"
|
||||||
|
style="fill:#000000;stroke:#ffffff;stroke-width:0.407001;stroke-opacity:0.247707"
|
||||||
|
d="M 8.0300008 183.60481 L 3.8607463 250.77746 L 43.855204 251.08648 L 43.855204 184.06835 L 8.0300008 183.60481 z M 37.67832 191.17128 L 35.825203 244.44606 L 11.272697 245.21862 L 14.515393 191.32579 C 16.522849 191.63463 37.67832 191.17128 37.67832 191.17128 z " />
|
||||||
|
<path
|
||||||
|
id="path8"
|
||||||
|
style="fill:#000000;stroke:#ffffff;stroke-width:0.407001;stroke-opacity:0.247707"
|
||||||
|
d="M 59.1783 184.00479 C 55.307442 184.00008 52.502738 184.37686 52.502738 184.37686 L 52.657251 250.62295 L 60.532739 250.62295 L 60.532739 218.19495 L 77.673295 248.92434 L 86.474825 248.46132 L 61.458781 210.01095 C 61.458781 210.01095 82.151296 214.79777 81.688037 197.65719 C 81.369547 185.87304 67.694188 184.01516 59.1783 184.00479 z M 61.767806 189.16416 C 61.767806 189.16416 72.113748 193.02454 73.503524 198.42923 C 74.893301 203.83392 61.304785 204.14258 61.304785 204.14258 L 61.767806 189.16416 z " />
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:#ffffff;stroke-width:0.407001;stroke-opacity:0.247707"
|
||||||
|
d="m 94.96808,185.61241 41.07562,-0.15442 0.61768,8.33866 -17.60384,-0.30884 0.30884,53.89245 h -7.72098 l -0.7721,-54.51013 -16.677319,-0.15442 z"
|
||||||
|
id="path9" />
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:#ffffff;stroke-width:0.407001;stroke-opacity:0.247707"
|
||||||
|
d="m 142.22049,185.45799 0.46326,62.69437 h 26.40576 l -0.30884,-6.79446 -20.53782,-0.61768 -0.46325,-23.16295 20.69223,0.46326 v -8.33866 h -19.76572 l -0.15442,-19.30245 19.14804,-0.7721 0.15442,-5.40469 z"
|
||||||
|
id="path10" />
|
||||||
|
<path
|
||||||
|
id="path11"
|
||||||
|
style="fill:#000000;stroke:#ffffff;stroke-width:0.407001;stroke-opacity:0.247707"
|
||||||
|
d="M 186.10389 183.67096 C 184.99641 183.67051 184.24207 183.78828 184.06835 183.75933 C 183.14183 183.60491 176.50189 184.22286 176.50189 184.22286 L 176.65588 248.61583 L 182.83277 248.61583 C 182.83277 248.61583 201.20876 243.82841 201.82644 211.86355 C 202.32831 185.8921 190.90296 183.67292 186.10389 183.67096 z M 182.67826 190.39923 C 182.67826 190.39923 193.79653 191.17146 193.95095 212.94462 C 194.10537 234.71779 182.83277 242.28444 182.83277 242.28444 L 182.67826 190.39923 z " />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 6.1 KiB |
@@ -78,7 +78,8 @@ def get_dirstruct():
|
|||||||
if lvid is None:
|
if lvid is None:
|
||||||
continue
|
continue
|
||||||
lvid = lvid.group()[:3] + lvid.group()[4:]
|
lvid = lvid.group()[:3] + lvid.group()[4:]
|
||||||
name = fname[:-8]
|
# name = fname[:-8]
|
||||||
|
name = re.sub(r"[a-zA-Z0-9]{3}\.[a-zA-Z0-9]{3}", "", fname)
|
||||||
# print(name)
|
# print(name)
|
||||||
# print(lvid)
|
# print(lvid)
|
||||||
cur = db.cursor()
|
cur = db.cursor()
|
||||||
|
|||||||
553
app/main.py
553
app/main.py
@@ -1,8 +1,12 @@
|
|||||||
from typing import Annotated
|
from typing import Annotated
|
||||||
from typing import List, Dict, Tuple
|
from typing import List, Dict, Tuple, Sequence
|
||||||
from annotated_types import IsDigit
|
from annotated_types import IsDigit
|
||||||
from fastapi import FastAPI, File, HTTPException, UploadFile, Request, Form
|
from fastapi import FastAPI, File, HTTPException, UploadFile, Request, Form
|
||||||
from fastapi.responses import FileResponse
|
from fastapi.responses import FileResponse
|
||||||
|
# import multiprocessing
|
||||||
|
# import threading
|
||||||
|
# import concurrent.futures
|
||||||
|
# import asyncio
|
||||||
|
|
||||||
# import fastapi
|
# import fastapi
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
@@ -18,14 +22,35 @@ import filetype
|
|||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import inspect
|
||||||
|
|
||||||
app = FastAPI()
|
from starlette.types import HTTPExceptionHandler
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
logging.basicConfig(
|
||||||
|
filename="app.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
|
||||||
|
|
||||||
app.mount("/favicon", StaticFiles(directory="./favicon"), name="favicon")
|
|
||||||
app.mount("/static", StaticFiles(directory="./static"), name="static")
|
|
||||||
db = mariadb.connect(
|
db = mariadb.connect(
|
||||||
host="localhost", user="wildserver", password="DBPassword", database="Unizeug"
|
host="localhost", user="wildserver", password="DBPassword", database="Unizeug"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
info("App Started")
|
||||||
|
# remove_old_FIP_entrys()
|
||||||
|
|
||||||
|
|
||||||
|
# startup()
|
||||||
|
app = FastAPI()
|
||||||
|
app.mount("/favicon", StaticFiles(directory="./favicon"), name="favicon")
|
||||||
|
app.mount("/static", StaticFiles(directory="./static"), name="static")
|
||||||
|
|
||||||
|
|
||||||
CATEGORIES = [
|
CATEGORIES = [
|
||||||
"Prüfungen",
|
"Prüfungen",
|
||||||
"Klausuren",
|
"Klausuren",
|
||||||
@@ -41,6 +66,9 @@ EX_DATE_CATEGORIES = ["Prüfungen", "Klausuren"]
|
|||||||
EX_DATE_CATEGORIES_I = [0, 1]
|
EX_DATE_CATEGORIES_I = [0, 1]
|
||||||
UNIZEUG_PATH = "./app/dest/"
|
UNIZEUG_PATH = "./app/dest/"
|
||||||
FILES_IN_PROGRESS = "./app/files/"
|
FILES_IN_PROGRESS = "./app/files/"
|
||||||
|
EMPTYFILE = "./app/graphics/empty.pdf"
|
||||||
|
UNSUPPORTEDFILE = "./app/graphics/unsupported.pdf"
|
||||||
|
GREETINGFILE = "./app/graphics/greeting.pdf"
|
||||||
|
|
||||||
|
|
||||||
# cur = db.cursor()
|
# cur = db.cursor()
|
||||||
@@ -48,51 +76,145 @@ FILES_IN_PROGRESS = "./app/files/"
|
|||||||
# for l in cur:
|
# for l in cur:
|
||||||
# print(l)
|
# print(l)
|
||||||
# locpaths = ["./VO_Mathematik_3.pdf"] # replace this with a database
|
# locpaths = ["./VO_Mathematik_3.pdf"] # replace this with a database
|
||||||
|
|
||||||
|
|
||||||
|
def _sql_quarry(
|
||||||
|
cursor: mariadb.Cursor,
|
||||||
|
querry: str,
|
||||||
|
data: Tuple[str | int, ...] | int | str,
|
||||||
|
return_result: bool,
|
||||||
|
commit: bool,
|
||||||
|
) -> List:
|
||||||
|
datas: Tuple[str | int, ...]
|
||||||
|
if type(data) is str or type(data) is int:
|
||||||
|
datas = (data,)
|
||||||
|
elif type(data) is tuple:
|
||||||
|
datas = data
|
||||||
|
try:
|
||||||
|
cursor.execute(querry, datas)
|
||||||
|
if commit:
|
||||||
|
db.commit()
|
||||||
|
if return_result:
|
||||||
|
return cursor.fetchall()
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
except mariadb.Error as e:
|
||||||
|
error(f"Mariadb Error: '{e}' from Querry: '{querry}' with variables: {data}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500, detail="Somethings wrong with the database"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def sql(
|
||||||
|
querry: str,
|
||||||
|
data: Tuple[str | int, ...] | str | int = (),
|
||||||
|
return_result: bool = True,
|
||||||
|
commit: bool = False,
|
||||||
|
) -> List[Tuple]:
|
||||||
|
cur = db.cursor(dictionary=False)
|
||||||
|
return _sql_quarry(cur, querry, data, return_result, commit)
|
||||||
|
|
||||||
|
|
||||||
|
def sqlT(
|
||||||
|
querry: str,
|
||||||
|
data: tuple[str | int, ...] | str | int = (),
|
||||||
|
return_result: bool = True,
|
||||||
|
commit: bool = False,
|
||||||
|
) -> List[Dict]:
|
||||||
|
cur = db.cursor(dictionary=True)
|
||||||
|
return _sql_quarry(cur, querry, data, return_result, commit)
|
||||||
|
|
||||||
|
# datas:Tuple[str|int,...]
|
||||||
|
# if type(data) is str or type(data) is int:
|
||||||
|
# datas = (data,)
|
||||||
|
# else:
|
||||||
|
# datas = data
|
||||||
|
# try:
|
||||||
|
# cur.execute(querry, datas)
|
||||||
|
# return cur.fetchall()
|
||||||
|
# except mariadb.Error as e:
|
||||||
|
# error(f"Mariadb Error: {e}")
|
||||||
|
# raise HTTPException(
|
||||||
|
# status_code=500, detail="Somethings wrong with the database"
|
||||||
|
# )
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
async def get_index():
|
async def get_index():
|
||||||
|
"""gives the Index.html file"""
|
||||||
return FileResponse("./index.html")
|
return FileResponse("./index.html")
|
||||||
|
|
||||||
|
|
||||||
@app.get("/files/{file_id}")
|
@app.get("/files/{file_id}")
|
||||||
async def get_file(file_id: str):
|
async def get_file(file_id: str):
|
||||||
|
"""returns the file that cooorosponds with the given ID"""
|
||||||
if file_id == "unsupported":
|
if file_id == "unsupported":
|
||||||
return FileResponse(FILES_IN_PROGRESS + "unsupported.pdf")
|
error("User uploadad unsupported file")
|
||||||
|
return FileResponse(UNSUPPORTEDFILE)
|
||||||
if file_id == "empty":
|
if file_id == "empty":
|
||||||
return FileResponse(FILES_IN_PROGRESS + "empty.pdf")
|
error("User uploaded empty file")
|
||||||
cur = db.cursor()
|
return FileResponse(EMPTYFILE)
|
||||||
try:
|
if file_id == "greeting":
|
||||||
cur.execute("Select filename from FIP where id=?", (file_id,))
|
return FileResponse(GREETINGFILE)
|
||||||
except mariadb.Error as e:
|
# cur = db.cursor()
|
||||||
print(f"Mariadb Error: {e}")
|
# try:
|
||||||
raise HTTPException(
|
res = sql("Select filename from FIP where id=?", (file_id,))
|
||||||
status_code=500, detail="Somethings wrong with the database"
|
if len(res) < 1:
|
||||||
)
|
error("File ID a user is trying to reach dose not exist")
|
||||||
filename = cur.fetchone()[0]
|
raise HTTPException(status_code=404, detail="File dose ot exist")
|
||||||
|
filename = res[0][0]
|
||||||
|
# except mariadb.Error as e:
|
||||||
|
# error(f"Mariadb Error: {e}")
|
||||||
|
# raise HTTPException(
|
||||||
|
# status_code=500, detail="Somethings wrong with the database"
|
||||||
|
# )
|
||||||
|
# filename = cur.fetchone()[0]
|
||||||
return FileResponse(FILES_IN_PROGRESS + filename)
|
return FileResponse(FILES_IN_PROGRESS + filename)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/search/lva")
|
@app.get("/search/lva")
|
||||||
async def search_lva(
|
async def search_lva(
|
||||||
searchterm: str, searchlim: int = 10
|
searchterm: str = "", pid: str | None = None, searchlim: int = 10
|
||||||
) -> List[Dict[str, int | str]]:
|
) -> List[Dict[str, int | str]]:
|
||||||
res = []
|
"""returns the LVA for a search in the database"""
|
||||||
cur = db.cursor(dictionary=True)
|
res: List[Dict[str, str | int]] = []
|
||||||
|
zw: List[Dict[str, str | int]] = []
|
||||||
|
# cur = db.cursor(dictionary=True)
|
||||||
if await is_LVID(searchterm):
|
if await is_LVID(searchterm):
|
||||||
cur.execute(
|
res += sqlT(
|
||||||
"SELECT lvid,lvname FROM LVAs WHERE lvid LIKE ?", (searchterm + "%",)
|
"SELECT id,lvid,lvname FROM LVAs WHERE lvid LIKE ?",
|
||||||
)
|
|
||||||
res = cur.fetchall()
|
|
||||||
else:
|
|
||||||
cur.execute(
|
|
||||||
"SELECT id,lvid,lvname FROM LVAs WHERE lvname LIKE ?",
|
|
||||||
(searchterm + "%",),
|
(searchterm + "%",),
|
||||||
)
|
)
|
||||||
res = cur.fetchall()
|
# res = cur.fetchall()
|
||||||
cur.execute(
|
else:
|
||||||
"SELECT id,lvid,lvname FROM LVAs WHERE lvname LIKE ?",
|
if pid is not None:
|
||||||
("%" + searchterm + "%",),
|
res += sqlT(
|
||||||
)
|
"SELECT LVAs.id,LVAs.lvid,LVAs.lvname FROM LVAs LEFT JOIN LPLink ON LVAs.id=LPLink.lid WHERE lvname like ? AND pid=?",
|
||||||
res = remove_duplicates(res + cur.fetchall())
|
(searchterm + "%", pid),
|
||||||
|
)
|
||||||
|
# res += cur.fetchall()
|
||||||
|
res += sqlT(
|
||||||
|
"SELECT LVAs.id,LVAs.lvid,LVAs.lvname FROM LVAs LEFT JOIN LPLink ON LVAs.id=LPLink.lid WHERE lvname like ? AND pid=?",
|
||||||
|
("%" + searchterm + "%", pid),
|
||||||
|
)
|
||||||
|
# res += cur.fetchall()
|
||||||
|
zw += sqlT(
|
||||||
|
"SELECT LVAs.id,LVAs.lvid,LVAs.lvname FROM LVAs LEFT JOIN LPLink ON LVAs.id=LPLink.lid WHERE pid=?",
|
||||||
|
(pid,),
|
||||||
|
)
|
||||||
|
# zw = cur.fetchall()
|
||||||
|
if searchterm != "":
|
||||||
|
res += sqlT(
|
||||||
|
"SELECT id,lvid,lvname FROM LVAs WHERE lvname LIKE ?",
|
||||||
|
(searchterm + "%",),
|
||||||
|
)
|
||||||
|
# res += cur.fetchall()
|
||||||
|
res += sqlT(
|
||||||
|
"SELECT id,lvid,lvname FROM LVAs WHERE lvname LIKE ?",
|
||||||
|
("%" + searchterm + "%",),
|
||||||
|
)
|
||||||
|
# res += cur.fetchall()
|
||||||
|
res = remove_duplicates(res + zw)
|
||||||
if searchlim == 0:
|
if searchlim == 0:
|
||||||
return res
|
return res
|
||||||
else:
|
else:
|
||||||
@@ -103,27 +225,29 @@ async def search_lva(
|
|||||||
async def search_profs(
|
async def search_profs(
|
||||||
searchterm: str = "", lid: int | None = None, searchlim: int = 10
|
searchterm: str = "", lid: int | None = None, searchlim: int = 10
|
||||||
) -> List[Dict[str, str | int]]:
|
) -> List[Dict[str, str | int]]:
|
||||||
res = []
|
"""returns the Prof for a searchterm and LVA id"""
|
||||||
zw = []
|
res: List[Dict[str, str | int]] = []
|
||||||
cur = db.cursor(dictionary=True)
|
zw: List[Dict[str, str | int]] = []
|
||||||
|
# cur = db.cursor(dictionary=True)
|
||||||
if lid is not None:
|
if lid is not None:
|
||||||
# cur.execute("SELECT id FROM LVAs WHERE LVId=?", (lvid,))
|
# cur.execute("SELECT id FROM LVAs WHERE LVId=?", (lvid,))
|
||||||
# lid = cur.fetchall()[0]["id"]
|
# lid = cur.fetchall()[0]["id"]
|
||||||
cur.execute(
|
res += sqlT(
|
||||||
"SELECT Profs.id,Profs.name FROM Profs LEFT JOIN LPLink ON Profs.id=LPLink.pid WHERE name like ? AND lid=?",
|
"SELECT Profs.id,Profs.name FROM Profs LEFT JOIN LPLink ON Profs.id=LPLink.pid WHERE name like ? AND lid=?",
|
||||||
("%" + searchterm + "%", lid),
|
("%" + searchterm + "%", lid),
|
||||||
)
|
)
|
||||||
res = cur.fetchall()
|
# res = cur.fetchall()
|
||||||
cur.execute(
|
zw += sqlT(
|
||||||
"SELECT Profs.id,Profs.name FROM Profs LEFT JOIN LPLink ON Profs.id=LPLink.pid WHERE name NOT like ? AND lid=?",
|
"SELECT Profs.id,Profs.name FROM Profs LEFT JOIN LPLink ON Profs.id=LPLink.pid WHERE name NOT like ? AND lid=?",
|
||||||
("%" + searchterm + "%", lid),
|
("%" + searchterm + "%", lid),
|
||||||
)
|
)
|
||||||
zw = cur.fetchall()
|
# zw = cur.fetchall()
|
||||||
if searchterm != "":
|
if searchterm != "":
|
||||||
cur.execute(
|
res += sqlT(
|
||||||
"SELECT id,name FROM Profs WHERE name LIKE ?", ("%" + searchterm + "%",)
|
"SELECT id,name FROM Profs WHERE name LIKE ?",
|
||||||
|
("%" + searchterm + "%",),
|
||||||
)
|
)
|
||||||
res += cur.fetchall()
|
# res += cur.fetchall()
|
||||||
res = remove_duplicates(res + zw)
|
res = remove_duplicates(res + zw)
|
||||||
if searchlim == 0:
|
if searchlim == 0:
|
||||||
return res
|
return res
|
||||||
@@ -141,28 +265,29 @@ async def search_subcats(
|
|||||||
cat: int | None = None,
|
cat: int | None = None,
|
||||||
searchlim: int = 10,
|
searchlim: int = 10,
|
||||||
) -> List[Dict[str, str | int]]:
|
) -> List[Dict[str, str | int]]:
|
||||||
|
"""searches for avaliable subcatrgories in a specific LVA with a specific Prof(optional)"""
|
||||||
res = []
|
res = []
|
||||||
rest = []
|
rest = []
|
||||||
cur = db.cursor(dictionary=True)
|
# cur = db.cursor(dictionary=True)
|
||||||
if not (lid is None or pid is None or cat is None): # Rest is available
|
if not (lid is None or pid is None or cat is None): # Rest is available
|
||||||
# cur.execute("SELECT id FROM LVAs WHERE LVId=?", (lvid,))
|
# cur.execute("SELECT id FROM LVAs WHERE LVId=?", (lvid,))
|
||||||
# lid = cur.fetchall()[0]["id"]
|
# lid = cur.fetchall()[0]["id"]
|
||||||
cur.execute(
|
rest = sqlT(
|
||||||
"SELECT id,name FROM SubCats WHERE lid=? AND pid=? AND cat=?",
|
"SELECT id,name FROM SubCats WHERE lid=? AND pid=? AND cat=?",
|
||||||
(lid, pid, cat),
|
(lid, pid, cat),
|
||||||
)
|
)
|
||||||
rest = cur.fetchall()
|
# rest = cur.fetchall()
|
||||||
if searchterm != "": # searchterm is available
|
if searchterm != "": # searchterm is available
|
||||||
if not (lid is None or pid is None or cat is None):
|
if not (lid is None or pid is None or cat is None):
|
||||||
cur.execute(
|
res = sqlT(
|
||||||
"SELECT id,name FROM SubCats WHERE lid=? AND pid=? AND cat=? AND name LIKE ?",
|
"SELECT id,name FROM SubCats WHERE lid=? AND pid=? AND cat=? AND name LIKE ?",
|
||||||
(lid, pid, cat, "%" + searchterm + "%"),
|
(lid, pid, cat, "%" + searchterm + "%"),
|
||||||
)
|
)
|
||||||
res = cur.fetchall()
|
# res = cur.fetchall()
|
||||||
cur.execute(
|
res += sqlT(
|
||||||
"SELECT id,name FROM SubCats WHERE name LIKE ?", ("%" + searchterm + "%",)
|
"SELECT id,name FROM SubCats WHERE name LIKE ?", ("%" + searchterm + "%",)
|
||||||
)
|
)
|
||||||
res += cur.fetchall()
|
# res += cur.fetchall()
|
||||||
res = remove_duplicates(res + rest)
|
res = remove_duplicates(res + rest)
|
||||||
if searchlim == 0:
|
if searchlim == 0:
|
||||||
return res
|
return res
|
||||||
@@ -177,12 +302,13 @@ async def search_subcats(
|
|||||||
|
|
||||||
@app.post("/uploadfile/")
|
@app.post("/uploadfile/")
|
||||||
async def create_upload_file(files: List[UploadFile], c2pdf: bool = True):
|
async def create_upload_file(files: List[UploadFile], c2pdf: bool = True):
|
||||||
|
"""Handles files uploaded. generates ID; saves file; saves path in database"""
|
||||||
if len(files) == 0:
|
if len(files) == 0:
|
||||||
raise HTTPException(status_code=400, detail="No files found in file submission")
|
raise HTTPException(status_code=400, detail="No files found in file submission")
|
||||||
filename = files[0].filename if files[0].filename is not None else "None"
|
filename = files[0].filename if files[0].filename is not None else "None"
|
||||||
if len(files) == 1:
|
if len(files) == 1:
|
||||||
content = await files[0].read()
|
content = await files[0].read()
|
||||||
ft = filetype.guess(content).extension
|
ft: str = guess_filetype(content, filename)
|
||||||
if c2pdf and ft != "pdf":
|
if c2pdf and ft != "pdf":
|
||||||
ret = convert_to_pdf(content)
|
ret = convert_to_pdf(content)
|
||||||
if ret is not None:
|
if ret is not None:
|
||||||
@@ -193,7 +319,7 @@ async def create_upload_file(files: List[UploadFile], c2pdf: bool = True):
|
|||||||
filecontents = []
|
filecontents = []
|
||||||
for file in files:
|
for file in files:
|
||||||
content = await file.read()
|
content = await file.read()
|
||||||
ft = filetype.guess(content).extension
|
ft = guess_filetype(content, filename)
|
||||||
if ft == "pdf":
|
if ft == "pdf":
|
||||||
filecontents.append(content)
|
filecontents.append(content)
|
||||||
continue
|
continue
|
||||||
@@ -221,30 +347,35 @@ async def create_upload_file(files: List[UploadFile], c2pdf: bool = True):
|
|||||||
filename = make_filename_unique(filename)
|
filename = make_filename_unique(filename)
|
||||||
locpath = FILES_IN_PROGRESS + filename
|
locpath = FILES_IN_PROGRESS + filename
|
||||||
# locpaths.append(locpath)
|
# locpaths.append(locpath)
|
||||||
cur = db.cursor()
|
# cur = db.cursor()
|
||||||
try:
|
# try:
|
||||||
cur.execute(
|
sql(
|
||||||
"Insert Into FIP (filename,filetype,initTimeStamp) Values(?,?,?)",
|
"INSERT INTO FIP (filename,filetype,initTimeStamp) Values(?,?,NOW())",
|
||||||
(filename, ft, str(datetime.datetime.now())),
|
(filename, ft), # str(datetime.datetime.now())
|
||||||
)
|
return_result=False,
|
||||||
except mariadb.Error as e:
|
)
|
||||||
print(f"Error: {e}")
|
# except mariadb.Error as e:
|
||||||
raise HTTPException(
|
# print(f"Error: {e}")
|
||||||
status_code=500, detail="Somethings wrong with the database"
|
# raise HTTPException(
|
||||||
)
|
# status_code=500, detail="Somethings wrong with the database"
|
||||||
try:
|
# )
|
||||||
cur.execute("Select id From FIP where filename=?", (filename,))
|
# try:
|
||||||
except mariadb.Error as e:
|
db.commit()
|
||||||
print(f"Error: {e}")
|
sqlres = sql("SELECT id FROM FIP WHERE filename=?", (filename,))
|
||||||
raise HTTPException(
|
if len(sqlres) < 1:
|
||||||
status_code=500, detail="Somethings wrong with the database"
|
error(f"FIP Entry with filename {filename} I just created dose not exist")
|
||||||
)
|
raise HTTPException(status_code=500, detail="Error with the Database")
|
||||||
id = cur.fetchone()[0]
|
id = sqlres[0][0]
|
||||||
|
# except mariadb.Error as e:
|
||||||
|
# print(f"Error: {e}")
|
||||||
|
# raise HTTPException(
|
||||||
|
# status_code=500, detail="Somethings wrong with the database"
|
||||||
|
# )
|
||||||
|
# id = cur.fetchone()[0]
|
||||||
if content is not None:
|
if content is not None:
|
||||||
with open(locpath, "wb") as f:
|
with open(locpath, "wb") as f:
|
||||||
f.write(content)
|
f.write(content)
|
||||||
# app.mount("/files", StaticFiles(directory="./app/files/"), name="files")
|
# app.mount("/files", StaticFiles(directory="./app/files/"), name="files")
|
||||||
db.commit()
|
|
||||||
fname = "".join(filename.split(".")[0:-1])
|
fname = "".join(filename.split(".")[0:-1])
|
||||||
# ftype = filename.split(".")[-1]
|
# ftype = filename.split(".")[-1]
|
||||||
return {
|
return {
|
||||||
@@ -274,42 +405,83 @@ async def get_submission(
|
|||||||
pagescales: Annotated[
|
pagescales: Annotated[
|
||||||
str, Form()
|
str, Form()
|
||||||
], # Scales of Pages # Annotated[List[Dict[str, float]], Form()],
|
], # Scales of Pages # Annotated[List[Dict[str, float]], Form()],
|
||||||
|
censor: Annotated[str, Form()],
|
||||||
):
|
):
|
||||||
print(lva, prof, fname, stype, subcat, sem, ex_date, rects, pagescales)
|
"""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}"
|
||||||
|
)
|
||||||
|
info(
|
||||||
|
f"lva: {lva}, prof: {prof}, fname {fname}, stype: {stype}, subcat: {subcat}, sem: {sem}, ex_date: {ex_date}, rects: {rects}, pagescales: {pagescales}, censor: {censor}"
|
||||||
|
)
|
||||||
rects_p = json.loads(rects)
|
rects_p = json.loads(rects)
|
||||||
scales_p = json.loads(pagescales)
|
scales_p = json.loads(pagescales)
|
||||||
cur = db.cursor()
|
# cur = db.cursor()
|
||||||
try:
|
# try:
|
||||||
cur.execute("Select filename from FIP where id=?", (fileId,))
|
res = sql("Select filename from FIP where id=?", (fileId,))
|
||||||
except mariadb.Error as e:
|
if len(res) < 1:
|
||||||
print(f"Mariadb Error: {e}")
|
error(f"Submited file ID {fileId} dose not exist in database")
|
||||||
raise HTTPException(
|
if fileId == "greeting":
|
||||||
status_code=500, detail="Somethings wrong with the database"
|
raise HTTPException(400, "You need to upload a file before submitting")
|
||||||
)
|
raise HTTPException(status_code=400, detail="Submited file dose not exist.")
|
||||||
filepath = "./app/files/" + cur.fetchone()[0]
|
for th in [(lva, "LVA"), (prof, "Prof"), (fname, "Filename"), (sem, "Semmester")]:
|
||||||
|
if th[0] == "":
|
||||||
|
error(f"User tried to upload a file without specifying the {th[1]}")
|
||||||
|
raise HTTPException(400, f"You need to specify a {th[1]}")
|
||||||
|
|
||||||
|
filepath = "./app/files/" + res[0][0]
|
||||||
|
# except mariadb.Error as e:
|
||||||
|
# print(f"Mariadb Error: {e}")
|
||||||
|
# raise HTTPException(
|
||||||
|
# status_code=500, detail="Somethings wrong with the database"
|
||||||
|
# )
|
||||||
|
# filepath = "./app/files/" + cur.fetchone()[0]
|
||||||
try:
|
try:
|
||||||
dest = make_savepath(lva, prof, stype, subcat, sem, ex_date, fname, ftype)
|
dest = make_savepath(lva, prof, stype, subcat, sem, ex_date, fname, ftype)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
raise HTTPException(status_code=400, detail=str(e))
|
error(f"Error creating savepath: {e}")
|
||||||
censor_pdf(filepath, dest, rects_p, scales_p)
|
raise HTTPException(status_code=400, detail=f"Error creation savepath: {e}")
|
||||||
return {"done": "ok"}
|
await censor_pdf(
|
||||||
|
filepath, dest, rects_p, scales_p, False if censor == "False" else True
|
||||||
|
)
|
||||||
|
# return {"done": "ok"}
|
||||||
|
# print(dest)
|
||||||
|
info(f"Saved file {fileId} as {dest}")
|
||||||
|
delete_from_FIP(fileId)
|
||||||
|
return FileResponse(dest, content_disposition_type="inline")
|
||||||
|
|
||||||
|
|
||||||
def censor_pdf(
|
async def censor_pdf(
|
||||||
path: str,
|
path: str,
|
||||||
destpath: str,
|
destpath: str,
|
||||||
rects: List[List[List[float]]],
|
rects: List[List[List[float]]],
|
||||||
scales: List[Dict[str, float]],
|
scales: List[Dict[str, float]],
|
||||||
|
secure: bool,
|
||||||
):
|
):
|
||||||
|
"""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
|
||||||
|
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)
|
doc = pymupdf.open(path)
|
||||||
output = pymupdf.open()
|
output = pymupdf.open()
|
||||||
page = doc[0]
|
page = doc[0]
|
||||||
width = page.rect.width
|
# width = page.rect.width
|
||||||
height = page.rect.height
|
# height = page.rect.height
|
||||||
print(width, height)
|
# print(width, height)
|
||||||
for i in range(doc.page_count):
|
npage = doc.page_count
|
||||||
|
# pages = []
|
||||||
|
# tasks = []
|
||||||
|
for i in range(npage):
|
||||||
page = doc[i]
|
page = doc[i]
|
||||||
if i < len(rects):
|
if i < len(rects) and rects[i] != []:
|
||||||
|
print(i)
|
||||||
wfac = page.rect.width / scales[i]["width"]
|
wfac = page.rect.width / scales[i]["width"]
|
||||||
hfac = page.rect.height / scales[i]["height"]
|
hfac = page.rect.height / scales[i]["height"]
|
||||||
for rect in rects[i]:
|
for rect in rects[i]:
|
||||||
@@ -324,17 +496,59 @@ def censor_pdf(
|
|||||||
color=(0, 0, 0),
|
color=(0, 0, 0),
|
||||||
fill=(0, 0, 0),
|
fill=(0, 0, 0),
|
||||||
)
|
)
|
||||||
bitmap = page.get_pixmap(dpi=300)
|
if secure:
|
||||||
pdf_bytes = bitmap.pdfocr_tobytes(
|
# pages.append(page)
|
||||||
language="deu",
|
bitmap = page.get_pixmap(dpi=400)
|
||||||
tessdata="/usr/share/tessdata/", # tesseract needs to be installed; this is the path to thetesseract files
|
pdf_bytes = bitmap.pdfocr_tobytes(
|
||||||
)
|
language="deu",
|
||||||
output.insert_pdf(pymupdf.Document(stream=pdf_bytes))
|
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)))
|
||||||
|
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)
|
output.save(destpath)
|
||||||
print("CENSORING DONE")
|
|
||||||
|
|
||||||
|
def test_function(i: int) -> bytes:
|
||||||
|
return b"\x00\x66\x99"
|
||||||
|
|
||||||
|
|
||||||
|
async def censor_page(page: pymupdf.Page) -> bytes:
|
||||||
|
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
|
||||||
|
)
|
||||||
|
# print(pdf_bytes)
|
||||||
|
return pdf_bytes
|
||||||
|
|
||||||
|
|
||||||
|
# def save_without_censoring(dest)
|
||||||
|
|
||||||
|
|
||||||
async def is_LVID(term: str) -> bool:
|
async def is_LVID(term: str) -> bool:
|
||||||
|
"""Returns weather a string has the format of a LVA ID"""
|
||||||
if re.match(r"[a-zA-Z0-9]{3}\.[a-zA-Z0-9]*", term):
|
if re.match(r"[a-zA-Z0-9]{3}\.[a-zA-Z0-9]*", term):
|
||||||
return True
|
return True
|
||||||
if term.isdigit():
|
if term.isdigit():
|
||||||
@@ -345,6 +559,7 @@ async def is_LVID(term: str) -> bool:
|
|||||||
def remove_duplicates(
|
def remove_duplicates(
|
||||||
results: List[Dict[str, str | int]],
|
results: List[Dict[str, str | int]],
|
||||||
) -> List[Dict[str, str | int]]:
|
) -> List[Dict[str, str | int]]:
|
||||||
|
"""removes duplicate file Ids"""
|
||||||
ids = []
|
ids = []
|
||||||
res = []
|
res = []
|
||||||
for result in results:
|
for result in results:
|
||||||
@@ -365,6 +580,7 @@ def make_savepath(
|
|||||||
fname: str,
|
fname: str,
|
||||||
ftype: str,
|
ftype: str,
|
||||||
) -> str:
|
) -> str:
|
||||||
|
"""Generates the path, the file is saved to after the upload process is finished. It creates all nessecery directories."""
|
||||||
lv = get_lvpath(lva)
|
lv = get_lvpath(lva)
|
||||||
lvpath = lv[1] + "/"
|
lvpath = lv[1] + "/"
|
||||||
pf = get_profpath(prof, lv[0])
|
pf = get_profpath(prof, lv[0])
|
||||||
@@ -374,56 +590,71 @@ def make_savepath(
|
|||||||
if int(cat) in SUBCAT_CATEGORIES_I and subcat != "":
|
if int(cat) in SUBCAT_CATEGORIES_I and subcat != "":
|
||||||
sc = get_subcatpath(subcat, int(cat), pf[0], lv[0])
|
sc = get_subcatpath(subcat, int(cat), pf[0], lv[0])
|
||||||
scpath = sc[1] + "/"
|
scpath = sc[1] + "/"
|
||||||
savepath = UNIZEUG_PATH + lvpath + pfpath + catpath + scpath
|
if int(cat) == 6:
|
||||||
|
savepath = UNIZEUG_PATH + lv[1] + "_Multimedia_only/" + pfpath
|
||||||
|
else:
|
||||||
|
savepath = UNIZEUG_PATH + lvpath + pfpath + catpath + scpath
|
||||||
os.makedirs(savepath, exist_ok=True)
|
os.makedirs(savepath, exist_ok=True)
|
||||||
filename = sem + "_"
|
filename = sem + "_"
|
||||||
if int(cat) in EX_DATE_CATEGORIES_I:
|
if int(cat) in EX_DATE_CATEGORIES_I:
|
||||||
_, mm, dd = ex_date.split("-")
|
try:
|
||||||
filename += mm + "_" + dd + "_"
|
yyyy, mm, dd = ex_date.split("-")
|
||||||
|
except ValueError as e:
|
||||||
|
error(
|
||||||
|
f"ValueError: f{e}. Probably caused by user not specifying a date where a date is required"
|
||||||
|
)
|
||||||
|
raise HTTPException(
|
||||||
|
400,
|
||||||
|
"You have not specified a date for an upload that requires a date like an exam.",
|
||||||
|
)
|
||||||
|
filename += yyyy + "_" + mm + "_" + dd + "_"
|
||||||
filename += fname + "." + ftype
|
filename += fname + "." + ftype
|
||||||
return savepath + filename
|
return savepath + filename
|
||||||
|
|
||||||
|
|
||||||
def get_lvpath(lva: str) -> Tuple[int, str]:
|
def get_lvpath(lva: str) -> Tuple[int, str]:
|
||||||
cur = db.cursor()
|
"""returns the path in UNIZEUG from a LVA based on its LVID (or name) that may be within a string. It uses the path within the database. If there is no Entry with a fitting LVID in the database it creates a new LVA. Returns: (id,path)"""
|
||||||
|
# cur = db.cursor()
|
||||||
lvid = re.search(r"[a-zA-Z0-9]{3}\.[a-zA-Z0-9]{3}", lva)
|
lvid = re.search(r"[a-zA-Z0-9]{3}\.[a-zA-Z0-9]{3}", lva)
|
||||||
if lvid is not None:
|
if lvid is not None:
|
||||||
cur.execute(
|
res = sql(
|
||||||
"SELECT id,lvpath FROM LVAs WHERE lvid=?",
|
"SELECT id,lvpath FROM LVAs WHERE lvid=?",
|
||||||
(lvid.group()[:3] + lvid.group()[4:],),
|
(lvid.group()[:3] + lvid.group()[4:],),
|
||||||
)
|
)
|
||||||
res = cur.fetchone()
|
# res = cur.fetchone()
|
||||||
if res is not None:
|
if len(res) > 0:
|
||||||
return res
|
return res[0]
|
||||||
else:
|
else:
|
||||||
return makenew(lva, "LVAs")
|
return makenew(lva, "LVAs")
|
||||||
else:
|
else:
|
||||||
cur.execute("SELECT id,lvpath FROM LVAs WHERE lvname=?", (lva,))
|
res = sql("SELECT id,lvpath FROM LVAs WHERE lvname=?", (lva,))
|
||||||
res = cur.fetchone()
|
# res = cur.fetchone()
|
||||||
if res is not None:
|
if len(res) > 0:
|
||||||
return res
|
return res[0]
|
||||||
else:
|
else:
|
||||||
return makenew(lva, "LVAs")
|
return makenew(lva, "LVAs")
|
||||||
|
|
||||||
|
|
||||||
def get_profpath(prof: str, lid: int) -> Tuple[int, str]:
|
def get_profpath(prof: str, lid: int) -> Tuple[int, str]:
|
||||||
cur = db.cursor()
|
"""Generates the foldername for a prof based on his name. It searches the database for matches. Returns: (id,name)"""
|
||||||
|
# cur = db.cursor()
|
||||||
prof = prof.replace("_", " ")
|
prof = prof.replace("_", " ")
|
||||||
cur.execute("SELECT id,name FROM Profs WHERE name=?", (prof,))
|
res = sql("SELECT id,name FROM Profs WHERE name=?", (prof,))
|
||||||
res = cur.fetchall()
|
# res = cur.fetchall()
|
||||||
if res is not None:
|
print(res != [])
|
||||||
|
if res is not None and res != []:
|
||||||
ret = (res[0][0], res[0][1].replace(" ", "_"))
|
ret = (res[0][0], res[0][1].replace(" ", "_"))
|
||||||
cur.execute("SELECT * FROM LPLink WHERE LId=? AND PId=?", (lid, ret[0]))
|
# sql("SELECT * FROM LPLink WHERE LId=? AND PId=?", (lid, ret[0]))
|
||||||
if cur.fetchall() is None:
|
if sql("SELECT * FROM LPLink WHERE LId=? AND PId=?", (lid, ret[0])) is None:
|
||||||
linkLP(lid, ret[0])
|
linkLP(lid, ret[0])
|
||||||
return ret
|
return ret
|
||||||
fname, lname = prof.split(" ")
|
fname, lname = prof.split(" ")
|
||||||
cur.execute("SELECT id,name FROM Profs WHERE name like ?", (lname + " " + fname,))
|
res = sql("SELECT id,name FROM Profs WHERE name like ?", (lname + " " + fname,))
|
||||||
res = cur.fetchall()
|
# res = cur.fetchall()
|
||||||
if res is not None:
|
if res is not None and res != []:
|
||||||
ret = (res[0][0], res[0][1].replace(" ", "_"))
|
ret = (res[0][0], res[0][1].replace(" ", "_"))
|
||||||
cur.execute("SELECT * FROM LPLink WHERE LId=? AND PId=?", (lid, ret[0]))
|
# sql("SELECT * FROM LPLink WHERE LId=? AND PId=?", (lid, ret[0]))
|
||||||
if cur.fetchall() is None:
|
if sql("SELECT * FROM LPLink WHERE LId=? AND PId=?", (lid, ret[0])) is None:
|
||||||
linkLP(lid, ret[0])
|
linkLP(lid, ret[0])
|
||||||
return ret
|
return ret
|
||||||
ret = makenew(prof, "Profs")
|
ret = makenew(prof, "Profs")
|
||||||
@@ -432,19 +663,21 @@ def get_profpath(prof: str, lid: int) -> Tuple[int, str]:
|
|||||||
|
|
||||||
|
|
||||||
def get_subcatpath(subcat: str, cat: int, pid: int, lid: int) -> Tuple[int, str]:
|
def get_subcatpath(subcat: str, cat: int, pid: int, lid: int) -> Tuple[int, str]:
|
||||||
cur = db.cursor()
|
"""Generates the subcat path from a subcat name. Returns: (id,name)"""
|
||||||
cur.execute(
|
# cur = db.cursor()
|
||||||
|
res = sql(
|
||||||
"SELECT id,name FROM SubCats WHERE LId=? AND PId=? AND cat=? AND name=?",
|
"SELECT id,name FROM SubCats WHERE LId=? AND PId=? AND cat=? AND name=?",
|
||||||
(lid, pid, cat, subcat),
|
(lid, pid, cat, subcat),
|
||||||
)
|
)
|
||||||
res = cur.fetchone()
|
# res = cur.fetchone()
|
||||||
if res is None:
|
if res == []:
|
||||||
return makenew(subcat, "SubCats", LId=lid, PId=pid, cat=cat)
|
return makenew(subcat, "SubCats", LId=lid, PId=pid, cat=cat)
|
||||||
return res
|
return res[0]
|
||||||
|
|
||||||
|
|
||||||
def makenew(input: str, table: str, **kwargs) -> Tuple[int, str]:
|
def makenew(input: str, table: str, **kwargs) -> Tuple[int, str]:
|
||||||
cur = db.cursor()
|
"""Generates new Entrys in the database for LVAs, Profs, SUBCATS. Returns: (id,name/path)"""
|
||||||
|
# cur = db.cursor()
|
||||||
if table == "LVAs":
|
if table == "LVAs":
|
||||||
lvaid = re.search(r"[a-zA-Z0-9]{3}\.[a-zA-Z0-9]{3}", input)
|
lvaid = re.search(r"[a-zA-Z0-9]{3}\.[a-zA-Z0-9]{3}", input)
|
||||||
if lvaid is None:
|
if lvaid is None:
|
||||||
@@ -452,12 +685,14 @@ def makenew(input: str, table: str, **kwargs) -> Tuple[int, str]:
|
|||||||
lvid = lvaid.group()[:3] + lvaid.group()[4:]
|
lvid = lvaid.group()[:3] + lvaid.group()[4:]
|
||||||
lvname = re.sub(r"[_ -]*[a-zA-Z0-9]{3}\.[a-zA-Z0-9]{3}[_ -]*", "", input)
|
lvname = re.sub(r"[_ -]*[a-zA-Z0-9]{3}\.[a-zA-Z0-9]{3}[_ -]*", "", input)
|
||||||
lvpath = lvname + "_" + lvaid.group()
|
lvpath = lvname + "_" + lvaid.group()
|
||||||
cur.execute(
|
sql(
|
||||||
"INSERT INTO LVAs(lvid,lvname,lvpath) VALUES(?,?,?)", (lvid, lvname, lvpath)
|
"INSERT INTO LVAs(lvid,lvname,lvpath) VALUES(?,?,?)",
|
||||||
|
(lvid, lvname, lvpath),
|
||||||
|
return_result=False,
|
||||||
)
|
)
|
||||||
cur.execute("SELECT id,lvpath FROM LVAs WHERE lvid=?", (lvid,))
|
# cur.execute("SELECT id,lvpath FROM LVAs WHERE lvid=?", (lvid,))
|
||||||
db.commit()
|
db.commit()
|
||||||
return cur.fetchone()
|
return sql("SELECT id,lvpath FROM LVAs WHERE lvid=?", (lvid,))[0]
|
||||||
querry = "INSERT INTO " + table + "(name"
|
querry = "INSERT INTO " + table + "(name"
|
||||||
values = [input]
|
values = [input]
|
||||||
nvals = 0
|
nvals = 0
|
||||||
@@ -466,22 +701,28 @@ def makenew(input: str, table: str, **kwargs) -> Tuple[int, str]:
|
|||||||
querry += "," + k
|
querry += "," + k
|
||||||
nvals += 1
|
nvals += 1
|
||||||
querry += ") VALUES(?" + nvals * ",?" + ")"
|
querry += ") VALUES(?" + nvals * ",?" + ")"
|
||||||
cur.execute(querry, tuple(values))
|
sql(querry, tuple(values), return_result=False)
|
||||||
cur.execute("SELECT id,name FROM " + table + " WHERE name=?", (input,))
|
sqlres = sql("SELECT id,name FROM " + table + " WHERE name=?", (input,))
|
||||||
res = cur.fetchone()
|
|
||||||
db.commit()
|
db.commit()
|
||||||
|
if len(sqlres) < 1:
|
||||||
|
error(f"Entry into {table} with name {input}, I just created dose not exist")
|
||||||
|
raise HTTPException(status_code=500, detail="Error with Database")
|
||||||
|
res = sqlres[0]
|
||||||
|
# res = cur.fetchone()
|
||||||
if table == "Profs":
|
if table == "Profs":
|
||||||
return (res[0], res[1].replace(" ", "_"))
|
return (res[0], res[1].replace(" ", "_"))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def linkLP(lid: int, pid: int):
|
def linkLP(lid: int, pid: int):
|
||||||
cur = db.cursor()
|
"""declares that a Prof (id in database) offers a LVA (id in database)"""
|
||||||
cur.execute("INSERT INTO LPLink(LId,PId) VALUES(?,?)", (lid, pid))
|
# cur = db.cursor()
|
||||||
|
sql("INSERT INTO LPLink(LId,PId) VALUES(?,?)", (lid, pid), return_result=False)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
|
||||||
def convert_to_pdf(file: bytes) -> bytes | None:
|
def convert_to_pdf(file: bytes) -> bytes | None:
|
||||||
|
"""Converts an image(thats all thats implemented right now) into a pdf."""
|
||||||
# ft = filetype.guess(file)
|
# ft = filetype.guess(file)
|
||||||
# cid = hash(file)
|
# cid = hash(file)
|
||||||
# if (
|
# if (
|
||||||
@@ -516,11 +757,13 @@ def convert_to_pdf(file: bytes) -> bytes | None:
|
|||||||
doc = pymupdf.Document(stream=file)
|
doc = pymupdf.Document(stream=file)
|
||||||
return doc.convert_to_pdf()
|
return doc.convert_to_pdf()
|
||||||
except (pymupdf.mupdf.FzErrorUnsupported, pymupdf.FileDataError) as e:
|
except (pymupdf.mupdf.FzErrorUnsupported, pymupdf.FileDataError) as e:
|
||||||
|
error(f"Error converting Image to pdf file: {e}")
|
||||||
print(e)
|
print(e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def filename_to_pdf(filename: str) -> str:
|
def filename_to_pdf(filename: str) -> str:
|
||||||
|
"""converts any filename.any to filename.pdf"""
|
||||||
farr = filename.split(".")
|
farr = filename.split(".")
|
||||||
if len(farr) > 1:
|
if len(farr) > 1:
|
||||||
farr[-1] = "pdf"
|
farr[-1] = "pdf"
|
||||||
@@ -531,9 +774,10 @@ def filename_to_pdf(filename: str) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def make_filename_unique(filename: str, idx: int | None = None) -> str:
|
def make_filename_unique(filename: str, idx: int | None = None) -> str:
|
||||||
cur = db.cursor()
|
"""makes sure, there are no duplicate filenames in the temporary folder"""
|
||||||
cur.execute("SELECT id FROM FIP WHERE filename=?", (filename,))
|
# cur = db.cursor()
|
||||||
res = cur.fetchall()
|
res = sql("SELECT id FROM FIP WHERE filename=?", (filename,))
|
||||||
|
# res = cur.fetchall()
|
||||||
if res is not None and len(res) > 0:
|
if res is not None and len(res) > 0:
|
||||||
farr = filename.split(".")
|
farr = filename.split(".")
|
||||||
if len(farr) > 1:
|
if len(farr) > 1:
|
||||||
@@ -552,6 +796,7 @@ def make_filename_unique(filename: str, idx: int | None = None) -> str:
|
|||||||
|
|
||||||
|
|
||||||
async def save_files_to_folder(files: List[UploadFile]) -> str:
|
async def save_files_to_folder(files: List[UploadFile]) -> str:
|
||||||
|
"""saves file to files in prograss folder"""
|
||||||
filename = files[0].filename if files[0].filename is not None else "None"
|
filename = files[0].filename if files[0].filename is not None else "None"
|
||||||
filename = filename.split(".")[0]
|
filename = filename.split(".")[0]
|
||||||
if filename == "":
|
if filename == "":
|
||||||
@@ -569,3 +814,37 @@ async def save_files_to_folder(files: List[UploadFile]) -> str:
|
|||||||
# reqJson = await request.form()
|
# reqJson = await request.form()
|
||||||
# print(reqJson)
|
# print(reqJson)
|
||||||
# return {"done": "ok"}
|
# return {"done": "ok"}
|
||||||
|
def guess_filetype(content: bytes, filename: str) -> str:
|
||||||
|
"""Guesses the filetype of a file based on first the sontent, If that fails the extension in teh filename. If no conclusion can be reached it reutrns an empty string"""
|
||||||
|
ftyp = filetype.guess(content)
|
||||||
|
if ftyp is not None:
|
||||||
|
return ftyp.extension
|
||||||
|
farr = filename.split(".")
|
||||||
|
if len(farr) > 1:
|
||||||
|
return filename.split(".")[-1]
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/remove_old")
|
||||||
|
async def remove_old_FIP_entrys():
|
||||||
|
files = sqlT(
|
||||||
|
"SELECT id,filename FROM FIP WHERE HOUR(TIMEDIFF(NOW(),initTimeStamp)) > 24 "
|
||||||
|
)
|
||||||
|
info(f"Remove Files: {files}")
|
||||||
|
for file in files:
|
||||||
|
sql("DELETE FROM FIP WHERE id=?", (file["id"]), return_result=False)
|
||||||
|
os.remove(FILES_IN_PROGRESS + file["filename"])
|
||||||
|
# sql(
|
||||||
|
# "DELETE FROM FIP WHERE HOUR(TIMEDIFF(NOW(),initTimeStamp)) > 24",
|
||||||
|
# return_result=False,
|
||||||
|
# )
|
||||||
|
db.commit()
|
||||||
|
return FileResponse("./index.html")
|
||||||
|
|
||||||
|
|
||||||
|
def delete_from_FIP(uuid: str):
|
||||||
|
res = sqlT("SELECT filename FROM FIP WHERE id=?", (uuid,))
|
||||||
|
if len(res) < 1:
|
||||||
|
raise HTTPException(500, "I am trying to delete a file that dose not exist")
|
||||||
|
sql("DELETE FROM FIP WHERE id=?", (uuid,), return_result=False, commit=True)
|
||||||
|
os.remove(FILES_IN_PROGRESS + res[0]["filename"])
|
||||||
|
|||||||
37
index.html
37
index.html
@@ -7,6 +7,8 @@
|
|||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.4.456/pdf.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.4.456/pdf.min.js"></script>
|
||||||
<script src="static/app.js" defer></script>
|
<script src="static/app.js" defer></script>
|
||||||
<script src="static/autocomplete.js" defer></script>
|
<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="icon" type="image/svg+xml" href="/favicon/favicon.svg" />
|
||||||
<link rel="shortcut icon" href="/favicon/favicon.ico" />
|
<link rel="shortcut icon" href="/favicon/favicon.ico" />
|
||||||
@@ -20,23 +22,29 @@
|
|||||||
<div class="left" id="controldiv">
|
<div class="left" id="controldiv">
|
||||||
<div id="fileupload">
|
<div id="fileupload">
|
||||||
<form id="uploadform" enctype="multipart/form-data">
|
<form id="uploadform" enctype="multipart/form-data">
|
||||||
<label for="filepicker">Choose a pdf file</label>
|
<div class="filetop">
|
||||||
<input type="file" name="files" id="filepicker" multiple />
|
<!-- <label for="filepicker">Choose a file</label> -->
|
||||||
<button type="submit" id="upload" method="POST">Upload</button>
|
<input type="file" name="files" id="filepicker" multiple placeholder="Drop File" />
|
||||||
|
</div>
|
||||||
|
<button type="submit" id="upload" method="POST" class="fileupload">
|
||||||
|
Upload
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div id="submitdiv">
|
<div id="submitdiv">
|
||||||
<form id="submitform" ,onsubmit="submitFile(event)">
|
<form id="submitform" ,onsubmit="submitFile(event)">
|
||||||
<label for="lva">Lehrveranstaltung:</label>
|
<label for="lva">Lehrveranstaltung:</label>
|
||||||
<div class="autocomplete">
|
<div class="autocomplete">
|
||||||
<input type="text" id="lva" name="lva" placeholder="Lehrveranstaltung" autocomplete="off" /><br />
|
<input type="text" id="lva" name="lva" placeholder="Lehrveranstaltung" autocomplete="off" />
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
<!-- <br /> -->
|
||||||
<label for="prof">Vortragende*r:</label>
|
<label for="prof">Vortragende*r:</label>
|
||||||
<div class="autocomplete">
|
<div class="autocomplete">
|
||||||
<input type="text" id="prof" name="prof" placeholder="Vortragende*r" autocomplete="off" /><br />
|
<input type="text" id="prof" name="prof" placeholder="Vortragende*r" autocomplete="off" />
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
<!-- <br /> -->
|
||||||
<label for="name">Name:</label>
|
<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>
|
<label for="sem">Semester:</label>
|
||||||
@@ -55,14 +63,19 @@
|
|||||||
<label for="zusammenfassungen">Zusammenfassung</label><br />
|
<label for="zusammenfassungen">Zusammenfassung</label><br />
|
||||||
<input type="radio" id="multimedia" name="stype" value="6" />
|
<input type="radio" id="multimedia" name="stype" value="6" />
|
||||||
<label for="multimedia">Multimedia</label><br />
|
<label for="multimedia">Multimedia</label><br />
|
||||||
<label for="subcat">Veranstaltung</label>
|
<br />
|
||||||
<div class="autocomplete">
|
<div id="subcatdiv">
|
||||||
<input type="text" id="subcat" name="subcat" placeholder="Klausur 1" autocomplete="off" />
|
<label for="subcat">Veranstaltung</label>
|
||||||
|
<div class="autocomplete">
|
||||||
|
<input type="text" id="subcat" name="subcat" placeholder="Klausur 1" autocomplete="off" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<div id="datediv">
|
||||||
<br />
|
<label for="date">Datum</label>
|
||||||
<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" /><br />
|
</div>
|
||||||
|
<input type="checkbox" name="censor" id="sec_censor" value="True" checked /><label
|
||||||
|
for="sec_censor">Zensieren</label><br /><br />
|
||||||
<button type="submit" id="send">Senden</button>
|
<button type="submit" id="send">Senden</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
64
requirements.txt
Normal file
64
requirements.txt
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
annotated-types==0.7.0
|
||||||
|
anyio==4.8.0
|
||||||
|
bcrypt==4.2.1
|
||||||
|
certifi==2024.12.14
|
||||||
|
cffi==1.17.1
|
||||||
|
charset-normalizer==3.4.1
|
||||||
|
click==8.1.8
|
||||||
|
comtypes==1.4.10
|
||||||
|
cryptography==44.0.0
|
||||||
|
dnspython==2.7.0
|
||||||
|
docopt==0.6.2
|
||||||
|
email_validator==2.2.0
|
||||||
|
fastapi==0.115.7
|
||||||
|
fastapi-cli==0.0.7
|
||||||
|
filetype==1.2.0
|
||||||
|
h11==0.14.0
|
||||||
|
httpcore==1.0.7
|
||||||
|
httptools==0.6.4
|
||||||
|
httpx==0.28.1
|
||||||
|
idna==3.10
|
||||||
|
itsdangerous==2.2.0
|
||||||
|
Jinja2==3.1.5
|
||||||
|
mariadb==1.1.11
|
||||||
|
markdown-it-py==3.0.0
|
||||||
|
MarkupSafe==3.0.2
|
||||||
|
mdurl==0.1.2
|
||||||
|
mysql-connector-python==9.2.0
|
||||||
|
mysqlclient==2.2.7
|
||||||
|
orjson==3.10.15
|
||||||
|
packaging==24.2
|
||||||
|
paramiko==3.5.1
|
||||||
|
pdf2image==1.17.0
|
||||||
|
pillow==11.1.0
|
||||||
|
pipreqs==0.4.13
|
||||||
|
pycparser==2.22
|
||||||
|
pydantic==2.10.6
|
||||||
|
pydantic-extra-types==2.10.2
|
||||||
|
pydantic-settings==2.7.1
|
||||||
|
pydantic_core==2.27.2
|
||||||
|
Pygments==2.19.1
|
||||||
|
PyMuPDF==1.25.2
|
||||||
|
PyNaCl==1.5.0
|
||||||
|
pypdf==5.2.0
|
||||||
|
pytesseract==0.3.13
|
||||||
|
python-dotenv==1.0.1
|
||||||
|
python-multipart==0.0.20
|
||||||
|
PyYAML==6.0.2
|
||||||
|
requests==2.32.3
|
||||||
|
rich==13.9.4
|
||||||
|
rich-toolkit==0.13.2
|
||||||
|
shellingham==1.5.4
|
||||||
|
sniffio==1.3.1
|
||||||
|
starlette==0.45.3
|
||||||
|
tesseract==0.1.3
|
||||||
|
tqdm==4.67.1
|
||||||
|
typer==0.15.1
|
||||||
|
typing_extensions==4.12.2
|
||||||
|
ujson==5.10.0
|
||||||
|
urllib3==2.3.0
|
||||||
|
uvicorn==0.34.0
|
||||||
|
uvloop==0.21.0
|
||||||
|
watchfiles==1.0.4
|
||||||
|
websockets==14.2
|
||||||
|
yarg==0.1.10
|
||||||
9
run.md
Normal file
9
run.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
sudo systemctl start mariadb.service
|
||||||
|
python -m uvicorn app.main:app --reload
|
||||||
|
Requirements:
|
||||||
|
|
||||||
|
- For pymupdf tesseract needs to be installed for the language deu on the system.
|
||||||
|
- All the tables in daatabase_init.sql must be in a database called Unizeug with password: DBPassword
|
||||||
|
- requirements.txt or just all the python modules until pytohn stops complaining. I recommend to use a venv for this project.
|
||||||
|
Just information I dont want to forget:
|
||||||
|
- TISS API maby not nessecarry: https://tiss.tuwien.ac.at/api/course/101685-2024W
|
||||||
4
run.txt
4
run.txt
@@ -1,4 +0,0 @@
|
|||||||
sudo systemctl start mariadb.service
|
|
||||||
python -m uvicorn app.main:app --reload
|
|
||||||
Requirements: For pymupdf tesseract needs to be installed for the language deu un the system.
|
|
||||||
TISS API maby not nessecarry: https://tiss.tuwien.ac.at/api/course/101685-2024W
|
|
||||||
@@ -273,6 +273,9 @@ function submitPdf(eve) {
|
|||||||
formdata.append("fileId", doc.fID);
|
formdata.append("fileId", doc.fID);
|
||||||
//formdata.append("filename", doc.filename);
|
//formdata.append("filename", doc.filename);
|
||||||
formdata.append("ftype", doc.filetype);
|
formdata.append("ftype", doc.filetype);
|
||||||
|
if (!formdata.has("censor")) {
|
||||||
|
formdata.append("censor", "False");
|
||||||
|
}
|
||||||
console.log(formdata);
|
console.log(formdata);
|
||||||
submitForm(formdata);
|
submitForm(formdata);
|
||||||
}
|
}
|
||||||
@@ -285,9 +288,20 @@ async function submitForm(formData) {
|
|||||||
//let responseJSON=await response.json();
|
//let responseJSON=await response.json();
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
console.log("Submit OK");
|
console.log("Submit OK");
|
||||||
console.log(response);
|
doc = new PDFDocument("./files/greeting", "greeting", "pdf");
|
||||||
|
// console.log(response);
|
||||||
|
// window.open(response);
|
||||||
|
// console.log(URL.createObjectURL(response.body));
|
||||||
|
// window.open(response);
|
||||||
|
// window.open(response, (target = "_blank"));
|
||||||
|
// var newWindow = window.open();
|
||||||
|
// newWindow.document.write(response);
|
||||||
|
// var blob = response.blob();
|
||||||
|
const blobURL = URL.createObjectURL(await response.blob());
|
||||||
|
window.open(blobURL, "_blank");
|
||||||
} else {
|
} else {
|
||||||
console.log("Submit failed");
|
console.log("Submit failed");
|
||||||
|
window.alert("Error: " + (await response.json())["detail"]);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error" + error);
|
console.error("Error" + error);
|
||||||
@@ -327,6 +341,7 @@ async function uploadFile(formData) {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log("upload failed");
|
console.log("upload failed");
|
||||||
|
window.alert("Error: " + (await response.json())["detail"]);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error: " + error);
|
console.error("Error: " + error);
|
||||||
@@ -352,12 +367,13 @@ function initListeners() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
const startPdf = () => {
|
const startPdf = () => {
|
||||||
doc = new PDFDocument(
|
// doc = new PDFDocument(
|
||||||
"./files/b78c869f-e0bb-11ef-9b58-84144d05d665",
|
// "./files/b78c869f-e0bb-11ef-9b58-84144d05d665",
|
||||||
"b78c869f-e0bb-11ef-9b58-84144d05d665",
|
// "b78c869f-e0bb-11ef-9b58-84144d05d665",
|
||||||
"pdf",
|
// "pdf",
|
||||||
);
|
// );
|
||||||
//pdf = new PDFView("./VO_Mathematik_3.pdf");
|
//pdf = new PDFView("./VO_Mathematik_3.pdf");
|
||||||
|
doc = new PDFDocument("./files/greeting", "greeting", "pdf");
|
||||||
initDraw();
|
initDraw();
|
||||||
initUpload();
|
initUpload();
|
||||||
initListeners();
|
initListeners();
|
||||||
|
|||||||
@@ -8,7 +8,11 @@ function autocomplete(inp, type) {
|
|||||||
the text field element and an array of possible autocompleted values:*/
|
the text field element and an array of possible autocompleted values:*/
|
||||||
var currentFocus;
|
var currentFocus;
|
||||||
/*execute a function when someone writes in the text field:*/
|
/*execute a function when someone writes in the text field:*/
|
||||||
inp.addEventListener("focus", updateAutocomplete);
|
inp.addEventListener("focus", (e) => {
|
||||||
|
e.target.select();
|
||||||
|
// this.select();
|
||||||
|
updateAutocomplete();
|
||||||
|
});
|
||||||
inp.addEventListener("input", updateAutocomplete);
|
inp.addEventListener("input", updateAutocomplete);
|
||||||
async function updateAutocomplete() {
|
async function updateAutocomplete() {
|
||||||
activeAutocompletion = type;
|
activeAutocompletion = type;
|
||||||
@@ -20,10 +24,13 @@ function autocomplete(inp, type) {
|
|||||||
val = this.value;
|
val = this.value;
|
||||||
/*close any already open lists of autocompleted values*/
|
/*close any already open lists of autocompleted values*/
|
||||||
closeAllLists();
|
closeAllLists();
|
||||||
if (!val && type === "lva") {
|
if (!val && type === "lva" && pid === null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (type === "prof" && lid !== null) {
|
if (type === "lva" && pid !== null) {
|
||||||
|
apirq =
|
||||||
|
url + type + "?searchterm=" + val + "&pid=" + pid + "&searchlim=10";
|
||||||
|
} else if (type === "prof" && lid !== null) {
|
||||||
apirq =
|
apirq =
|
||||||
url + type + "?searchterm=" + val + "&lid=" + lid + "&searchlim=10";
|
url + type + "?searchterm=" + val + "&lid=" + lid + "&searchlim=10";
|
||||||
} else if (type === "subcat" && lid !== null && pid !== null) {
|
} else if (type === "subcat" && lid !== null && pid !== null) {
|
||||||
@@ -167,9 +174,21 @@ function autocomplete(inp, type) {
|
|||||||
closeAllLists(e.target);
|
closeAllLists(e.target);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function enter_current_semeseter() {
|
||||||
|
var semField = document.getElementById("sem");
|
||||||
|
var today = new Date();
|
||||||
|
var year = today.getFullYear();
|
||||||
|
var month = today.getMonth();
|
||||||
|
if (month < 9 && month > 1) {
|
||||||
|
semField.value = String(year) + "S";
|
||||||
|
} else {
|
||||||
|
semField.value = String(year) + "W";
|
||||||
|
}
|
||||||
|
}
|
||||||
function init() {
|
function init() {
|
||||||
autocomplete(document.getElementById("lva"), "lva");
|
autocomplete(document.getElementById("lva"), "lva");
|
||||||
autocomplete(document.getElementById("prof"), "prof");
|
autocomplete(document.getElementById("prof"), "prof");
|
||||||
autocomplete(document.getElementById("subcat"), "subcat");
|
autocomplete(document.getElementById("subcat"), "subcat");
|
||||||
|
enter_current_semeseter();
|
||||||
}
|
}
|
||||||
window.addEventListener("load", init);
|
window.addEventListener("load", init);
|
||||||
|
|||||||
42
static/dynhide.js
Normal file
42
static/dynhide.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
var radiobuttons;
|
||||||
|
var datediv;
|
||||||
|
var subcatdiv;
|
||||||
|
var rdbarr;
|
||||||
|
var subcatcategories = [1, 2, 3];
|
||||||
|
var datecategorires = [0, 1];
|
||||||
|
function changevis() {
|
||||||
|
for (let i = 0; i < rdbarr.length; i++) {
|
||||||
|
if (rdbarr[i].checked) {
|
||||||
|
if (subcatcategories.includes(i)) {
|
||||||
|
subcatdiv.style.display = "block";
|
||||||
|
} else {
|
||||||
|
subcatdiv.style.display = "none";
|
||||||
|
}
|
||||||
|
if (datecategorires.includes(i)) {
|
||||||
|
datediv.style.display = "block";
|
||||||
|
} else {
|
||||||
|
datediv.style.display = "none";
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function starthide() {
|
||||||
|
radiobuttons = document.getElementsByName("stype");
|
||||||
|
datediv = document.getElementById("datediv");
|
||||||
|
subcatdiv = document.getElementById("subcatdiv");
|
||||||
|
rdbarr = [
|
||||||
|
document.getElementById("pruefung"),
|
||||||
|
document.getElementById("klausur"),
|
||||||
|
document.getElementById("uebung"),
|
||||||
|
document.getElementById("labor"),
|
||||||
|
document.getElementById("unterlagen"),
|
||||||
|
document.getElementById("zusammenfassungen"),
|
||||||
|
document.getElementById("multimedia"),
|
||||||
|
];
|
||||||
|
changevis();
|
||||||
|
radiobuttons.forEach((rdb) => {
|
||||||
|
rdb.addEventListener("change", changevis);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
window.addEventListener("load", starthide);
|
||||||
10
static/filedrop.js
Normal file
10
static/filedrop.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
var fileinput;
|
||||||
|
function dropHandler(eve) {
|
||||||
|
eve.preventDefault();
|
||||||
|
fileinput.files = eve.dataTransfer.files;
|
||||||
|
}
|
||||||
|
function init() {
|
||||||
|
fileinput = document.getElementById("filepicker");
|
||||||
|
document.getElementById("filepicker").addEventListener("drop", dropHandler);
|
||||||
|
}
|
||||||
|
window.addEventListener("load", init);
|
||||||
137
static/style.css
137
static/style.css
@@ -6,7 +6,7 @@ body {
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background-color: slategrey;
|
background-color: #2f3957;
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,11 +15,11 @@ body {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
width: 75vw;
|
width: 75vw;
|
||||||
float: right;
|
float: right;
|
||||||
background-color: navy;
|
/* background-color: navy; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.left {
|
.left {
|
||||||
background-color: blueviolet;
|
/* background-color: blueviolet; */
|
||||||
height: 100%;
|
height: 100%;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
@@ -39,6 +39,15 @@ span {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background-color: #0872a9;
|
||||||
|
/* border-radius: 20px; */
|
||||||
|
border-top-left-radius: 10px;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
border-bottom-right-radius: 0px;
|
||||||
|
border-bottom-left-radius: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
@@ -77,6 +86,16 @@ span {
|
|||||||
#submitdiv {
|
#submitdiv {
|
||||||
/*position: relative;*/
|
/*position: relative;*/
|
||||||
width: 500px;
|
width: 500px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
/* color: white; */
|
||||||
|
background-color: grey;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
/* margin: 10px; */
|
||||||
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Things I've stolen from https://www.w3schools.com/howto/howto_js_autocomplete.asp*/
|
/*Things I've stolen from https://www.w3schools.com/howto/howto_js_autocomplete.asp*/
|
||||||
@@ -84,29 +103,59 @@ span {
|
|||||||
/*the container must be positioned relative:*/
|
/*the container must be positioned relative:*/
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 300px;
|
/* width: 400px; */
|
||||||
|
width: 100%;
|
||||||
|
padding: none;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#name {
|
||||||
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
border: 1px solid transparent;
|
border: 1px solid #818181;
|
||||||
background-color: #f1f1f1;
|
background-color: #a1a1a1;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
font-size: 16px;
|
/* height: 50px; */
|
||||||
|
font-size: 12pt;
|
||||||
|
border-radius: 20px;
|
||||||
|
margin-top: 10px;
|
||||||
|
/* margin-bottom: 10px; */
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="text"] {
|
input[type="text"] {
|
||||||
background-color: #f1f1f1;
|
background-color: #b1b1b1;
|
||||||
width: 100%;
|
/* width: 100%; */
|
||||||
|
width: 478px;
|
||||||
|
border-radius: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="submit"] {
|
/* input[type="text"]:focus { */
|
||||||
background-color: DodgerBlue;
|
/* border-bottom-right-radius: 0px; */
|
||||||
color: #fff;
|
/* border-bottom-left-radius: 0px; */
|
||||||
|
/* outline: none; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
div>input[type="text"]:focus {
|
||||||
|
border-bottom-right-radius: 0px;
|
||||||
|
border-bottom-left-radius: 0px;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button[type="submit"] {
|
||||||
|
background-color: #0872a9;
|
||||||
|
/* color: #fff; */
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.autocomplete-items {
|
.autocomplete-items {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border: 1px solid #d4d4d4;
|
/* border: 1px solid #d4d4d4; */
|
||||||
|
border: 1px solid #818181;
|
||||||
|
background-color: #b1b1b1;
|
||||||
|
/* background-color: #b1b1b1; */
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
z-index: 99;
|
z-index: 99;
|
||||||
@@ -114,22 +163,78 @@ input[type="submit"] {
|
|||||||
top: 100%;
|
top: 100%;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
border-bottom-left-radius: 20px;
|
||||||
|
border-bottom-right-radius: 20px;
|
||||||
|
/* padding: 20px; */
|
||||||
|
/* padding-top: 10px; */
|
||||||
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.autocomplete-items div {
|
.autocomplete-items div {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-color: #fff;
|
/* border-radius: 20px; */
|
||||||
|
background-color: #b1b1b1;
|
||||||
border-bottom: 1px solid #d4d4d4;
|
border-bottom: 1px solid #d4d4d4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.autocomplete-items div:hover {
|
.autocomplete-items div:hover {
|
||||||
/*when hovering an item:*/
|
/*when hovering an item:*/
|
||||||
background-color: #e9e9e9;
|
background-color: #0872a9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.autocomplete-active {
|
.autocomplete-active {
|
||||||
/*when navigating through the items using the arrow keys:*/
|
/*when navigating through the items using the arrow keys:*/
|
||||||
background-color: DodgerBlue !important;
|
background-color: #0872a9 !important;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* filedrop */
|
||||||
|
input[type="file"] {
|
||||||
|
/* flex: 1; */
|
||||||
|
display: flex;
|
||||||
|
background-color: #b1b1b1;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 10px;
|
||||||
|
width: 100%;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
/* margin-bottom: auto; */
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="file"]::file-selector-button {
|
||||||
|
background-color: #d1d1d1;
|
||||||
|
border-radius: 20px;
|
||||||
|
border-color: #a1a1a1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#fileupload {
|
||||||
|
/* display: inline-flex; */
|
||||||
|
width: 500px;
|
||||||
|
border-radius: 20px;
|
||||||
|
background-color: #4f5977;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fileupload {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
width: 25%;
|
||||||
|
/* align-self: right; */
|
||||||
|
/* float: right; */
|
||||||
|
}
|
||||||
|
|
||||||
|
#uploadform {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filetop {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
/* background-color: purple; */
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user