Search function
Added a (hopefully) functioning search function.
This commit is contained in:
parent
0d55022ba8
commit
978c634067
88
flask/app.py
88
flask/app.py
|
@ -14,6 +14,7 @@ app = Flask(__name__)
|
|||
@app.template_filter('ctime')
|
||||
def timectime(s):
|
||||
return datetime.utcfromtimestamp(s).strftime('%Y-%m-%d %H:%M')
|
||||
|
||||
@app.template_filter('spacer')
|
||||
def convsize(s):
|
||||
sizes=("B","KB","MB","GB","TB")
|
||||
|
@ -26,25 +27,30 @@ def convsize(s):
|
|||
## WEB FRONTEND
|
||||
@app.route('/')
|
||||
def homepage():
|
||||
# try to get sesskey, else logout state
|
||||
# try to get userdata, else logout state
|
||||
print(request.base_url)
|
||||
try:
|
||||
# get sesskey and get info about user
|
||||
sesskey=request.cookies.get('session')
|
||||
res,userid=db.check_sesskey(sesskey)
|
||||
if not res:
|
||||
return 500
|
||||
userdata=db.get_user_info(userid)
|
||||
logged_in=True
|
||||
logged_in,userdata=get_login_info(request.cookies.get('session'))
|
||||
except Exception as e:
|
||||
logged_in=False
|
||||
userdata=()
|
||||
logged_in,userdata=False,()
|
||||
#try: # TODO: CLEAN!
|
||||
# # get sesskey and get info about user
|
||||
# sesskey=request.cookies.get('session')
|
||||
# res,userid=db.check_sesskey(sesskey)
|
||||
# if not res:
|
||||
# return 500
|
||||
# userdata=db.get_user_info(userid)
|
||||
# logged_in=True
|
||||
#except Exception as e:
|
||||
# logged_in=False
|
||||
# userdata=()
|
||||
archives=db.get_n_archives()
|
||||
return render_template("home.html", title="Homepage",userdata=userdata,login=logged_in,archives=archives)
|
||||
|
||||
@app.route('/user')
|
||||
@app.route('/user/<userid>')
|
||||
@app.route('/user/<int:userid>')
|
||||
def userpage(userid:int=0):
|
||||
if userid==0:
|
||||
if userid == 0:
|
||||
return make_response(redirect('/'))
|
||||
|
||||
@app.route('/login', methods=["GET","POST"])
|
||||
|
@ -64,18 +70,72 @@ def loginpage():
|
|||
resp=setcookie("session",sesskey,lifetime)
|
||||
return resp
|
||||
else:
|
||||
return "<h2>You've entered the wrong password. This incident will be reported.</h2><br> Go back and try again.<br>" + password.upper() + "<br>" + passhash.upper() # TODO: DELETE
|
||||
return "<h2>You've entered the wrong password. This incident will be reported.</h2><br> Go back and try again."
|
||||
# GET: Login form
|
||||
else:
|
||||
return render_template("login.html", title="Login")
|
||||
|
||||
@app.route('/search')
|
||||
def searchpage():
|
||||
# try to get userdata, else logout state
|
||||
try:
|
||||
logged_in,userdata=get_login_info(request.cookies.get('session'))
|
||||
except Exception as e:
|
||||
logged_in,userdata=False,()
|
||||
|
||||
# try to set all required variables, else defaults
|
||||
try:
|
||||
sorttype=request.args['sort']
|
||||
except Exception as e:
|
||||
sorttype="time"
|
||||
try:
|
||||
category=request.args['category']
|
||||
except Exception as e:
|
||||
category=0
|
||||
try:
|
||||
keywords=request.args['q']
|
||||
keywords="".join(keywords).split(" ")
|
||||
except Exception as e:
|
||||
keywords=[]
|
||||
try:
|
||||
count=request.args['count']
|
||||
except Exception as e:
|
||||
count=20
|
||||
archives=db.get_n_archives(sorttype,category,keywords,count)
|
||||
|
||||
catlist=db.get_all_categories()
|
||||
htmlcatlist=[]
|
||||
# parse all categories and sort them into select box
|
||||
for cat in catlist:
|
||||
if not cat[2]:
|
||||
htmlcatlist.append((cat[0],cat[1]))
|
||||
parent=cat[1]
|
||||
parentid=cat[0]
|
||||
for i in catlist:
|
||||
if i[2] == parentid:
|
||||
htmlcatlist.append((i[0],f"{parent}/{i[1]}"))
|
||||
|
||||
return render_template("search.html", title="Advanced Search",categories=htmlcatlist,userdata=userdata,login=logged_in,archives=archives)
|
||||
|
||||
## FUNCTIONS
|
||||
|
||||
## Checks if given sesskey is valid and returns user data
|
||||
## OUTPUT: (if sesskey valid) logged_in:bool=True, userdata:tup
|
||||
## (if sesskey invalid)
|
||||
def get_login_info(sesskey:str):
|
||||
logged_in,userid=db.check_sesskey(sesskey)
|
||||
if logged_in:
|
||||
userdata=db.get_user_info(userid)
|
||||
else:
|
||||
userdata=()
|
||||
return logged_in,userdata
|
||||
|
||||
def setcookie(name:str,value:str,lifetime:int=10000):
|
||||
resp = make_response(redirect('/'))
|
||||
resp.set_cookie(name, value, max_age=lifetime)
|
||||
return resp
|
||||
|
||||
## API CALLS
|
||||
## API CALLS (NO THANKS)
|
||||
|
||||
# main driver function
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -96,7 +96,6 @@ class db:
|
|||
## Gets and returns all user info about one (1) user
|
||||
## OUTPUT: tuple=(ID:int,UNAME:str,DNAME:str,CREATED:int,STATE:text,PASSHASH:text)
|
||||
def get_user_info(self, userid:int):
|
||||
print("USERID:::::::::::" + userid)
|
||||
self.cur.execute(f"SELECT * FROM Users WHERE ID='{userid}'")
|
||||
return self.cur.fetchone()
|
||||
|
||||
|
@ -104,7 +103,6 @@ class db:
|
|||
## 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):
|
||||
#global cur
|
||||
self.cur.execute(f"""SELECT Archs.NAME,Archs.HASH,Archs.IMPORTED,Cats.CATEGORY,Cats.DESCRIPTION,Users.UNAME,Users.DNAME FROM Archs
|
||||
JOIN Cats ON Cats.ID=Archs.CATEGORY
|
||||
JOIN Users ON Users.ID=Archs.OWNER
|
||||
|
@ -119,16 +117,45 @@ class db:
|
|||
labels=self.cur.fetchall()
|
||||
return archive, labels
|
||||
|
||||
## Returns all categories.
|
||||
## OUTPUT: array=[…,(ID:int,CATEGORY:str,PARENT:int,DESCRIPTION:str),…]
|
||||
def get_all_categories(self):
|
||||
self.cur.execute("SELECT * FROM Cats;")
|
||||
return self.cur.fetchall()
|
||||
|
||||
## Returns n archives, sorted by (imported )time or size
|
||||
## OUTPUT: archives:array=[…,(ID:int,NAME:str,SIZE:str,IMPORTED[UNIX]:int),…]
|
||||
def get_n_archives(self, sorttype:str="time",category:int=0, count:int=20):
|
||||
global cur
|
||||
def get_n_archives(self, sorttype:str="time",category:int=0, keywords:list=[], count:int=20):
|
||||
match sorttype:
|
||||
case "size":
|
||||
sorttype="SIZE"
|
||||
sorttype="SIZE DESC"
|
||||
case "time":
|
||||
sorttype="IMPORTED DESC"
|
||||
case "za":
|
||||
sorttype="NAME DESC"
|
||||
case _:
|
||||
sorttype="IMPORTED"
|
||||
self.cur.execute(f"""SELECT ID,NAME,SIZE,IMPORTED FROM Archs{"" if category==0 else " WHERE CATEGORY=" + category} ORDER BY {sorttype} DESC LIMIT {count};""")
|
||||
sorttype="NAME ASC"
|
||||
|
||||
# create SQL query for keywords
|
||||
keyword_string=""
|
||||
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}' "
|
||||
|
||||
# Get all children of category (if exist) and put into query string
|
||||
categories=self.get_all_categories()
|
||||
catlist=[category]
|
||||
for i in categories:
|
||||
if i[2] == int(category):
|
||||
catlist.append(str(i[0]))
|
||||
category="(" + ",".join(catlist) + ")"
|
||||
|
||||
self.cur.execute(f"""SELECT ID,NAME,SIZE,IMPORTED FROM Archs
|
||||
{"WHERE 1=1" if category==0 else " WHERE CATEGORY IN " + category}
|
||||
{keyword_string}
|
||||
ORDER BY {sorttype} LIMIT {count};""")
|
||||
archives=self.cur.fetchall()
|
||||
return archives
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ header > div#container {
|
|||
height: 2em;
|
||||
margin: auto 0.1em;
|
||||
border: none;
|
||||
border-radius: 0.1em;
|
||||
background: linear-gradient(135deg, white, yellow);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,24 @@
|
|||
div.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto auto;
|
||||
grid-template-columns: auto max-content max-content;
|
||||
}
|
||||
div.grid-item {
|
||||
padding: 0.2em;
|
||||
border: 2px black solid;
|
||||
}
|
||||
|
||||
div.grid-header:first-child {
|
||||
border-radius: 0.5em 0 0 0;
|
||||
}
|
||||
|
||||
div.grid-header:nth-child(3) {
|
||||
border-radius: 0 0.5em 0 0;
|
||||
}
|
||||
|
||||
div.grid-header {
|
||||
text-align: center;
|
||||
background: lightyellow;
|
||||
padding: 0.4em;
|
||||
border: 2px black solid;
|
||||
}
|
||||
|
||||
|
|
0
flask/static/search.css
Normal file
0
flask/static/search.css
Normal file
|
@ -12,6 +12,11 @@
|
|||
<header>
|
||||
<span id="title">{{title}}</span>
|
||||
<div id="container">
|
||||
<!-- BUTTONS IF USER LOGGED IN -->
|
||||
{% if login %}
|
||||
<a href="/add"><button class="big-button"><b>+</b></button></a>
|
||||
{% endif %}
|
||||
<!------------------------------->
|
||||
<form action="/search" method="get">
|
||||
<input type="text" name="q" placeholder="search">
|
||||
<input type="submit" value="🔎" class="big-button" id="search-button">
|
||||
|
|
|
@ -7,13 +7,16 @@
|
|||
{% block content %}
|
||||
{% if archives|length > 0 %}
|
||||
<div class="grid-container">
|
||||
{% for arch in archives %}
|
||||
<a class="grid-item" href="/view/{{arch[0]}}"><div class="grid-item clickable"><b>{{arch[1]}}</b></div></a>
|
||||
<div class="grid-item"><p>{{arch[2]|spacer}}</p></div>
|
||||
<div class="grid-item"><p>{{arch[3]|ctime}}</p></div>
|
||||
<div class="grid-header"><b>ARCHIVE</b></div>
|
||||
<div class="grid-header"><b>SIZE</b></div>
|
||||
<div class="grid-header"><b>IMPORTED</b></div>
|
||||
{% for arch in archives %}
|
||||
<a class="grid-item" href="/view/{{arch[0]}}"><div class="grid-item clickable"><b>{{arch[1]}}</b></div></a>
|
||||
<div class="grid-item"><p> {{arch[2]|spacer}} </p></div>
|
||||
<div class="grid-item"><p> {{arch[3]|ctime}} </p></div>
|
||||
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p>No matching archives</p>
|
||||
{% endif %}
|
||||
|
|
50
flask/templates/search.html
Normal file
50
flask/templates/search.html
Normal file
|
@ -0,0 +1,50 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block meta %}
|
||||
<link rel="stylesheet" href="/static/search.css" />
|
||||
<link rel="stylesheet" href="/static/home.css" />
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form action="/search" method="get">
|
||||
<div class="grid-selection">
|
||||
<b>Sort by:</b>
|
||||
<select name="sort">
|
||||
<option value="time">Import Time</option>
|
||||
<option value="az">A-Z</option>
|
||||
<option value="za">Z-A</option>
|
||||
<option value="size">Archive Size</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="grid-selection">
|
||||
<b>Category:</b>
|
||||
<select name="category">
|
||||
{% for i in categories %}
|
||||
<option value="{{i[0]}}">{{i[1]}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{% if request.args.get('q') %}
|
||||
<input type="text" name="q" value="{{request.args.get('q')}}" placeholder="Keywords">
|
||||
{% else %}
|
||||
<input type="text" name="q" placeholder="Keywords">
|
||||
{% endif %}
|
||||
<input type="submit" value="Search!">
|
||||
<div class="grid-selection"></div>
|
||||
</form>
|
||||
{% if archives|length > 0 %}
|
||||
<div class="grid-container">
|
||||
<div class="grid-header"><b>ARCHIVE</b></div>
|
||||
<div class="grid-header"><b>SIZE</b></div>
|
||||
<div class="grid-header"><b>IMPORTED</b></div>
|
||||
{% for arch in archives %}
|
||||
<a class="grid-item" href="/view/{{arch[0]}}"><div class="grid-item clickable"><b>{{arch[1]}}</b></div></a>
|
||||
<div class="grid-item"><p> {{arch[2]|spacer}} </p></div>
|
||||
<div class="grid-item"><p> {{arch[3]|ctime}} </p></div>
|
||||
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p>No matching archives</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
Loading…
Reference in a new issue