From f0b8b1eb3d468dec95a3408e41c747b8f60dd8dc Mon Sep 17 00:00:00 2001 From: Michael Rodin Date: Thu, 19 Oct 2023 18:24:36 +0200 Subject: [PATCH] Added archive view, label editing Archives can now be viewed, a cover can optionally be inserted into the covers directory. Labels can now be edited. --- .gitignore | 2 + flask/app.py | 36 +++++++++++- flask/func.py | 92 ++++++++++++++++++++++++++----- flask/static/covers/default.webp | Bin 0 -> 6830 bytes flask/static/labels.css | 8 +++ flask/static/view.css | 27 +++++++++ flask/templates/labels.html | 21 +++++++ flask/templates/view.html | 25 +++++++++ 8 files changed, 196 insertions(+), 15 deletions(-) create mode 100644 flask/static/covers/default.webp create mode 100644 flask/static/labels.css create mode 100644 flask/static/view.css create mode 100644 flask/templates/labels.html create mode 100644 flask/templates/view.html diff --git a/.gitignore b/.gitignore index 4cef53c..7c1773c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,6 @@ !/README.md !/requirements.txt +/flask/static/covers/** +!/flask/static/covers/default.webp **__pycache__** \ No newline at end of file diff --git a/flask/app.py b/flask/app.py index 806876c..f032c05 100644 --- a/flask/app.py +++ b/flask/app.py @@ -24,6 +24,7 @@ def convsize(s): s=s/1000 return str("%.2f" % s)+sizes[n] + ## WEB FRONTEND @app.route('/') def homepage(): @@ -92,6 +93,39 @@ def loginpage(): else: return render_template("login.html", title="Login") +@app.route('/view/') +def viewpage(archid:int): + logged_in,userdata=get_login_info(request.cookies.get('session')) + archive,category,labels=db.get_archive_info(archid) + return render_template("view.html", title="View Archive",userdata=userdata,login=logged_in,archive=archive,category=category,labels=labels) + +@app.route('/labels/', methods=["GET","POST"]) +def labeleditpage(archid:int): + logged_in,userdata=get_login_info(request.cookies.get('session')) + archive,category,labels=db.get_archive_info(archid) + label_dict=db.get_label_labeltypes(category[3]) + if not logged_in or userdata[0] != archive[8]: + return make_response(redirect(f"/view/{archid}")) + + # POST: parse everything and update labels + if request.method == 'POST': + on_labels=[] + print(request.form) + for i in request.form: + on_labels.append(i) + res, data=db.update_labels(archid, on_labels) + if not res: + return f"

ERROR: {data}

Go back and try again" + return make_response(redirect(f"/view/{archid}")) + + + # GET: return normal labels page + labels_name_list=[] + for i in labels: + labels_name_list.append(i[0]) + return render_template("labels.html", title="Edit Labels",userdata=userdata,login=logged_in,archive=archive,res_labels=label_dict,labels_names=labels_name_list) + + @app.route('/search') def searchpage(): # try to get userdata, else logout state @@ -144,7 +178,7 @@ def setcookie(name:str,value:str,lifetime:int=10000): ## Gets all categories and returns them (with or without parents) ## OUTPUT: […,(ID:int,NAME:str),…] def get_category_selection(include_parents:bool=True): - catlist=db.get_all_categories() + catlist=db.get_categories() htmlcatlist=[] # parse all categories and sort them into list for cat in catlist: diff --git a/flask/func.py b/flask/func.py index b3c6d6b..9ec92fa 100644 --- a/flask/func.py +++ b/flask/func.py @@ -111,7 +111,7 @@ class db: archive["hash"]=archive["hash"].upper() if not re.match('[A-Z0-9]{40}', archive["hash"]): return False, "Hash needs to be 40 characters in hexadecimal (SHA-1)." - if re.match('.*[^A-Za-z0-9\. _-].*', archive["name"]): + if re.match('.*[^A-Za-z0-9\. +_-].*', archive["name"]): return False, "The name contains illegal characters. Allowed chars: '[A-Za-z0-9\. _-]'" print(archive["name"]) @@ -126,28 +126,93 @@ class db: ## Returns all relevant information about one (1) archive - ## OUTPUT: archive:tuple=(NAME:str,HASH:str,IMPORTED[UNIX]:int,CATEGORY,str,CATEGORY.DESCRIPTION:str,UNAME:str,DNAME:str), - ## labels:array=[…,(LABEL:str,CATEGORY:str,CATDESC:str,LABTYPE:str,LABDESC:str),…] - def get_archive_info(self, hash:str): - self.cur.execute(f"""SELECT Archs.NAME,Archs.HASH,Archs.IMPORTED,Cats.CATEGORY,Cats.DESCRIPTION,Users.UNAME,Users.DNAME FROM Archs + ## OUTPUT: archive:tuple=(ID:int,NAME:str,HASH:str,SIZE:int,IMPORTED[UNIX]:int,CATEGORY.ID:int,CATEGORY,str,CATEGORY.DESCRIPTION:str,USER.ID:int,DNAME:str), + ## category:tuple=(ID:int,CATEGORY:str,DESCRIPTION:str,PID:int,PCAT:str,PDESC:str) + ## labels:array=[…,(LABEL:str,LABTYPE:int,LABDESC:str),…] + def get_archive_info(self, archid:int): + # get info about archive itself + self.cur.execute(f"""SELECT Archs.ID,Archs.NAME,Archs.HASH,Archs.SIZE,Archs.IMPORTED,Cats.ID,Cats.CATEGORY,Cats.DESCRIPTION,Users.ID,Users.DNAME FROM Archs JOIN Cats ON Cats.ID=Archs.CATEGORY JOIN Users ON Users.ID=Archs.OWNER - WHERE hash='{hash}'""") + WHERE Archs.ID='{archid}'""") archive=self.cur.fetchone() - self.cur.execute(f"""SELECT Labs.LABEL,Cats.CATEGORY,Cats.DESCRIPTION AS CATDESC,LabType.NAME AS LABTYPE,LabType.DESCRIPTION AS LABDESC FROM ArchLab + # get info about category and it's parent + self.cur.execute(f"""SELECT c.ID,c.CATEGORY,c.DESCRIPTION,p.ID AS PID,p.CATEGORY as PCAT,p.DESCRIPTION AS PDESC FROM Cats c, Cats p + WHERE c.ID={archive[5]} AND c.PARENT=p.ID""") + category=self.cur.fetchone() + # get info about labels of archive + self.cur.execute(f"""SELECT Labs.LABEL,LabType.ID AS LABTYPE,LabType.DESCRIPTION AS LABDESC FROM ArchLab JOIN Archs ON Archs.ID=ArchLab.ARCHID JOIN Labs ON Labs.ID=ArchLab.LABID - JOIN Cats ON Labs.CATEGORY=Cats.ID JOIN LabType ON Labs.TYPE=LabType.ID - WHERE ARCHID=1;""") + WHERE ARCHID={archid};""") labels=self.cur.fetchall() - return archive, labels + return archive, category, labels ## Returns all categories. ## OUTPUT: array=[…,(ID:int,CATEGORY:str,PARENT:int,DESCRIPTION:str),…] - def get_all_categories(self): + def get_categories(self): self.cur.execute("SELECT * FROM Cats;") return self.cur.fetchall() + + ## get all labeltypes and their respective labels based on a category parent + ## OUTPUT: res_dict:dict={…,LabType.NAME:[…,(ID:int,NAME:str),…],…} + def get_label_labeltypes(self, catparentid:int): + # gets all relevant labtypes: […,(ID.int,NAME:str),…] + self.cur.execute(f"""SELECT LabType.ID,LabType.NAME FROM CatLabType + JOIN Cats ON Cats.ID=CatLabType.CATID + JOIN LabType ON LabType.ID=CatLabType.LABID + WHERE Cats.ID={catparentid} + ORDER BY LabType.NAME ASC""") + labtypes_list=self.cur.fetchall() + labtypes_ids,labtypes_names=[],[] + for w,e in labtypes_list: + labtypes_ids.append(str(w)) + labtypes_names.append(e) + ltid_string="(" + ",".join(labtypes_ids) + ")" + # gets all relevant labs: […,(ID:int,NAME:str,LTNAME:str),…] + self.cur.execute(f"""SELECT Labs.ID,Labs.LABEL,LabType.NAME AS LTNAME FROM Labs + JOIN LabType ON Labs.TYPE=LabType.ID + WHERE LabType.ID IN {ltid_string} + ORDER BY Labs.LABEL ASC""") + labs_list=self.cur.fetchall() + res_dict={} + # creates all labtype entries in dict + for i in labtypes_names: + res_dict[i]=[] + # puts all labs into their respective labtype + for entry in labs_list: + res_dict[entry[2]].append(entry[:2]) + return res_dict + + ## get a list of enabled labels and update the DB to reflect that state + ## OUTPUT: (if on_labels empty) bool=False, str + ## (else) + def update_labels(self, archid:int, on_labels:list): # TODO: CLEAN!!!! + # fail if no labels passed + if len(on_labels) == 0: + return False, "You have to select at least one label!" + + # get all relevant labels + self.cur.execute(f"""SELECT ArchLab.LABID FROM ArchLab + WHERE ArchLab.ARCHID={archid}""") + existing_labs=[] + for i in self.cur.fetchall(): + existing_labs.append(i[0]) + to_add=[] + # get all missing labels to add + for lab in on_labels: + if int(lab) not in existing_labs: + to_add.append(lab) + + # remove all labels which are not on + self.cur.execute(f"""DELETE FROM ArchLab WHERE ARCHID={archid} AND LABID NOT IN ({",".join(on_labels)})""") + to_add_list=[] + for i in to_add: + to_add_list.append("(" + str(archid) + "," + str(i) + ")") + # add all new labels + self.cur.execute(f"""INSERT INTO ArchLab(ARCHID,LABID) VALUES{",".join(to_add_list)}""") + return True, "" ## Returns n archives, sorted by (imported )time or size ## OUTPUT: archives:array=[…,(ID:int,NAME:str,SIZE:str,IMPORTED[UNIX]:int),…] @@ -167,11 +232,10 @@ class db: for w in keywords: keyword_string+=f"AND NAME LIKE '%{w}%' " if len(keywords) == 1: - for w in keywords: - keyword_string+=f"OR HASH = '{w}' " + keyword_string+=f"OR HASH = '{keywords[0]}' " # Get all children of category (if exist) and put into query string - categories=self.get_all_categories() + categories=self.get_categories() catlist=[str(category)] for i in categories: if i[2] == int(category): diff --git a/flask/static/covers/default.webp b/flask/static/covers/default.webp new file mode 100644 index 0000000000000000000000000000000000000000..08df19528de122055e04430113269581bf63d2db GIT binary patch literal 6830 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 T^43WQ9r_T|5N4#{KL!2^R8vI5 literal 0 HcmV?d00001 diff --git a/flask/static/labels.css b/flask/static/labels.css new file mode 100644 index 0000000..ea0be13 --- /dev/null +++ b/flask/static/labels.css @@ -0,0 +1,8 @@ +div.flex-container { + display: flex; + flex: auto; +} + +div.flex-item { + display: inline-block; +} \ No newline at end of file diff --git a/flask/static/view.css b/flask/static/view.css new file mode 100644 index 0000000..ccc5520 --- /dev/null +++ b/flask/static/view.css @@ -0,0 +1,27 @@ +div.grid-container { + display: grid; + grid-template-columns: auto 20%; +} + +.archive-info { + display: grid; + grid-template-columns: max-content auto; + grid-template-rows: max-content max-content max-content max-content max-content max-content; +} + +.archive-info > * { + padding: 0.3em 0; +} + +.label { + display: inline-block; + padding: 0.1em; + border-radius: 0.4em; + background: linear-gradient(160deg, white, pink 65%); +} + +img#cover { + margin: auto auto; + border-radius: 1em; + width: 90%; +} \ No newline at end of file diff --git a/flask/templates/labels.html b/flask/templates/labels.html new file mode 100644 index 0000000..c686491 --- /dev/null +++ b/flask/templates/labels.html @@ -0,0 +1,21 @@ +{% extends "base.html" %} + +{% block meta %} + +{% endblock %} + +{% block content %} +

{{archive[1]}}

+
+
+ {% for ltype in res_labels %} +
{{ltype}} + {% for for_temp in res_labels[ltype] %} + + {% endfor %} +
+ {% endfor %} +
+ +
+{% endblock %} \ No newline at end of file diff --git a/flask/templates/view.html b/flask/templates/view.html new file mode 100644 index 0000000..f837e1d --- /dev/null +++ b/flask/templates/view.html @@ -0,0 +1,25 @@ +{% extends "base.html" %} + +{% block meta %} + +{% endblock %} + +{% block content %} +

{{archive[1]}}

+
+
+ Hash: {{archive[2]}} + Owner: {{archive[-1]}} + Category: {{category[4]}}/{{category[1]}} + Imported: {{archive[4]|ctime}} + Size: {{archive[4]|spacer}} + Labels: {% if login and userdata[0] == archive[8] %}Edit{% endif %} +
+ {% for lab in labels %} +
{{lab[0]}}
+ {% endfor %} +
+
+ Cover image +
+{% endblock %} \ No newline at end of file