First functions
Added first functions in backend The homepage can now show the most recent archives
This commit is contained in:
parent
a2f9b4f978
commit
d4016ce80c
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -5,4 +5,6 @@
|
||||||
!/flask**
|
!/flask**
|
||||||
!/.gitignore
|
!/.gitignore
|
||||||
!/README.md
|
!/README.md
|
||||||
!/requirements.txt
|
!/requirements.txt
|
||||||
|
|
||||||
|
**__pycache__**
|
13
Dockerfile
13
Dockerfile
|
@ -1,13 +0,0 @@
|
||||||
#Download Python from DockerHub and use it
|
|
||||||
FROM python:3.11.3
|
|
||||||
|
|
||||||
#Set the working directory in the Docker container
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
#Copy the dependencies file to the working directory
|
|
||||||
COPY ./requirements.txt .
|
|
||||||
|
|
||||||
#Install the dependencies
|
|
||||||
RUN pip install -r requirements.txt
|
|
||||||
|
|
||||||
COPY ./flask/ .
|
|
|
@ -49,7 +49,7 @@
|
||||||
<node id="n0">
|
<node id="n0">
|
||||||
<data key="d0">1</data>
|
<data key="d0">1</data>
|
||||||
<data key="d5">
|
<data key="d5">
|
||||||
<y:RectD X="-268.5" Y="-250" Width="130" Height="130"/>
|
<y:RectD X="-268.5" Y="-273.25" Width="130" Height="176.5"/>
|
||||||
</data>
|
</data>
|
||||||
<data key="d7">
|
<data key="d7">
|
||||||
<x0:EntityNodeStyle fill="{y:GraphMLReference 1}" insetFill="{y:GraphMLReference 2}" stroke="BLACK">
|
<x0:EntityNodeStyle fill="{y:GraphMLReference 1}" insetFill="{y:GraphMLReference 2}" stroke="BLACK">
|
||||||
|
@ -61,6 +61,7 @@
|
||||||
<sys:String>ID</sys:String>
|
<sys:String>ID</sys:String>
|
||||||
<sys:String>NAME</sys:String>
|
<sys:String>NAME</sys:String>
|
||||||
<sys:String>HASH</sys:String>
|
<sys:String>HASH</sys:String>
|
||||||
|
<sys:String>SIZE</sys:String>
|
||||||
<sys:String>IMPORTED</sys:String>
|
<sys:String>IMPORTED</sys:String>
|
||||||
<sys:String>CATEGORY</sys:String>
|
<sys:String>CATEGORY</sys:String>
|
||||||
<sys:String>OWNER</sys:String>
|
<sys:String>OWNER</sys:String>
|
||||||
|
@ -100,9 +101,9 @@
|
||||||
<x0:EntityRelationshipModel.attributes>
|
<x0:EntityRelationshipModel.attributes>
|
||||||
<x:Array Type="sys:Object">
|
<x:Array Type="sys:Object">
|
||||||
<sys:String>ID</sys:String>
|
<sys:String>ID</sys:String>
|
||||||
<sys:String>NAME</sys:String>
|
<sys:String>CATEGORY</sys:String>
|
||||||
<sys:String>PARENT</sys:String>
|
<sys:String>PARENT</sys:String>
|
||||||
<sys:String>DESC</sys:String>
|
<sys:String>DESCRIPTION</sys:String>
|
||||||
</x:Array>
|
</x:Array>
|
||||||
</x0:EntityRelationshipModel.attributes>
|
</x0:EntityRelationshipModel.attributes>
|
||||||
</x0:EntityRelationshipModel>
|
</x0:EntityRelationshipModel>
|
||||||
|
@ -114,6 +115,11 @@
|
||||||
<y:FreeNodePortLocationModelParameter Ratio="0.5,0.007575757575757569"/>
|
<y:FreeNodePortLocationModelParameter Ratio="0.5,0.007575757575757569"/>
|
||||||
</data>
|
</data>
|
||||||
</port>
|
</port>
|
||||||
|
<port name="p1">
|
||||||
|
<data key="d16">
|
||||||
|
<y:FreeNodePortLocationModelParameter Ratio="0.9924242424242424,0.5"/>
|
||||||
|
</data>
|
||||||
|
</port>
|
||||||
</node>
|
</node>
|
||||||
<node id="n2">
|
<node id="n2">
|
||||||
<data key="d0">3</data>
|
<data key="d0">3</data>
|
||||||
|
@ -128,7 +134,7 @@
|
||||||
<x0:EntityRelationshipModel.attributes>
|
<x0:EntityRelationshipModel.attributes>
|
||||||
<x:Array Type="sys:Object">
|
<x:Array Type="sys:Object">
|
||||||
<sys:String>ID</sys:String>
|
<sys:String>ID</sys:String>
|
||||||
<sys:String>NAME</sys:String>
|
<sys:String>LABEL</sys:String>
|
||||||
<sys:String>CATEGORY</sys:String>
|
<sys:String>CATEGORY</sys:String>
|
||||||
<sys:String>TYPE</sys:String>
|
<sys:String>TYPE</sys:String>
|
||||||
</x:Array>
|
</x:Array>
|
||||||
|
@ -147,6 +153,11 @@
|
||||||
<y:FreeNodePortLocationModelParameter Ratio="0.5,0.007575757575757569"/>
|
<y:FreeNodePortLocationModelParameter Ratio="0.5,0.007575757575757569"/>
|
||||||
</data>
|
</data>
|
||||||
</port>
|
</port>
|
||||||
|
<port name="p2">
|
||||||
|
<data key="d16">
|
||||||
|
<y:FreeNodePortLocationModelParameter Ratio="0.5,0.9924242424242424"/>
|
||||||
|
</data>
|
||||||
|
</port>
|
||||||
</node>
|
</node>
|
||||||
<node id="n3">
|
<node id="n3">
|
||||||
<data key="d0">4</data>
|
<data key="d0">4</data>
|
||||||
|
@ -161,8 +172,8 @@
|
||||||
<x0:EntityRelationshipModel.attributes>
|
<x0:EntityRelationshipModel.attributes>
|
||||||
<x:Array Type="sys:Object">
|
<x:Array Type="sys:Object">
|
||||||
<sys:String>ID</sys:String>
|
<sys:String>ID</sys:String>
|
||||||
<sys:String>ARCH</sys:String>
|
<sys:String>ARCHID</sys:String>
|
||||||
<sys:String>LAB</sys:String>
|
<sys:String>LABID</sys:String>
|
||||||
</x:Array>
|
</x:Array>
|
||||||
</x0:EntityRelationshipModel.attributes>
|
</x0:EntityRelationshipModel.attributes>
|
||||||
</x0:EntityRelationshipModel>
|
</x0:EntityRelationshipModel>
|
||||||
|
@ -225,7 +236,7 @@
|
||||||
<sys:String>ID</sys:String>
|
<sys:String>ID</sys:String>
|
||||||
<sys:String>SESSKEY</sys:String>
|
<sys:String>SESSKEY</sys:String>
|
||||||
<sys:String>CREATED</sys:String>
|
<sys:String>CREATED</sys:String>
|
||||||
<sys:String>LIMIT</sys:String>
|
<sys:String>LIFE</sys:String>
|
||||||
</x:Array>
|
</x:Array>
|
||||||
</x0:EntityRelationshipModel.attributes>
|
</x0:EntityRelationshipModel.attributes>
|
||||||
</x0:EntityRelationshipModel>
|
</x0:EntityRelationshipModel>
|
||||||
|
@ -251,8 +262,8 @@
|
||||||
<x0:EntityRelationshipModel.attributes>
|
<x0:EntityRelationshipModel.attributes>
|
||||||
<x:Array Type="sys:Object">
|
<x:Array Type="sys:Object">
|
||||||
<sys:String>ID</sys:String>
|
<sys:String>ID</sys:String>
|
||||||
<sys:String>NAME</sys:String>
|
<sys:String>TYPE</sys:String>
|
||||||
<sys:String>DESC</sys:String>
|
<sys:String>DESCRIPTION</sys:String>
|
||||||
</x:Array>
|
</x:Array>
|
||||||
</x0:EntityRelationshipModel.attributes>
|
</x0:EntityRelationshipModel.attributes>
|
||||||
</x0:EntityRelationshipModel>
|
</x0:EntityRelationshipModel>
|
||||||
|
@ -311,5 +322,14 @@
|
||||||
</yjs:PolylineEdgeStyle>
|
</yjs:PolylineEdgeStyle>
|
||||||
</data>
|
</data>
|
||||||
</edge>
|
</edge>
|
||||||
|
<edge id="e5" source="n2" target="n1" sourceport="p2" targetport="p1">
|
||||||
|
<data key="d13">
|
||||||
|
<yjs:PolylineEdgeStyle stroke="{y:GraphMLReference 5}" targetArrow="{y:GraphMLReference 6}">
|
||||||
|
<yjs:PolylineEdgeStyle.sourceArrow>
|
||||||
|
<yjs:Arrow type="NONE" scale="0.75" stroke="#FF663800" fill="{y:GraphMLReference 4}"/>
|
||||||
|
</yjs:PolylineEdgeStyle.sourceArrow>
|
||||||
|
</yjs:PolylineEdgeStyle>
|
||||||
|
</data>
|
||||||
|
</edge>
|
||||||
</graph>
|
</graph>
|
||||||
</graphml>
|
</graphml>
|
26
flask/app.py
26
flask/app.py
|
@ -1,17 +1,31 @@
|
||||||
|
|
||||||
# Importing flask module in the project is mandatory
|
|
||||||
# An object of Flask class is our WSGI application.
|
|
||||||
from flask import Flask,redirect,url_for,request,render_template
|
from flask import Flask,redirect,url_for,request,render_template
|
||||||
|
from datetime import datetime
|
||||||
# Flask constructor takes the name of
|
## Import db class from func.py and initialise it
|
||||||
# current module (__name__) as argument.
|
from func import db
|
||||||
|
db=db()
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
## CUSTOM FILTERS
|
||||||
|
@app.template_filter('ctime')
|
||||||
|
def timectime(s):
|
||||||
|
return datetime.utcfromtimestamp(s).strftime('%Y-%m-%d %H:%M')
|
||||||
|
@app.template_filter('spacer')
|
||||||
|
def timectime(s):
|
||||||
|
sizes=("B","KB","MB","GB","TB")
|
||||||
|
n=0
|
||||||
|
while s > 1000:
|
||||||
|
n+=1
|
||||||
|
s=s/1000
|
||||||
|
return str("%.2f" % s)+sizes[n]
|
||||||
|
|
||||||
|
|
||||||
## WEB FRONTEND
|
## WEB FRONTEND
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def homepage():
|
def homepage():
|
||||||
return render_template("home.html", title="Homepage")
|
archives=db.get_n_archives()
|
||||||
|
return render_template("home.html", title="Homepage",archives=archives)
|
||||||
|
|
||||||
## API CALLS
|
## API CALLS
|
||||||
|
|
||||||
|
|
106
flask/func.py
Normal file
106
flask/func.py
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
## MAIN FUNCTIONS FILE FOR BACK-BACKEND OF FLASK
|
||||||
|
import mariadb as sql
|
||||||
|
from os import environ
|
||||||
|
|
||||||
|
## params populated with environment variables, defaults can be changed for a permanent solution
|
||||||
|
conn_params={
|
||||||
|
"user" : environ.get('MARIADB_USER') if environ.get('MARIADB_USER') else "rar_index_app",
|
||||||
|
"password" : environ.get('MARIADB_PASSWORD') if environ.get('MARIADB_PASSWORD') else "password",
|
||||||
|
"host" : environ.get('MARIADB_HOST') if environ.get('MARIADB_HOST') else "marcelsite.com",
|
||||||
|
"database" : environ.get('MARIADB_DB') if environ.get('MARIADB_DB') else "rar_index"
|
||||||
|
}
|
||||||
|
|
||||||
|
class db:
|
||||||
|
def __init__(self):
|
||||||
|
self.conn=sql.connect(**conn_params)
|
||||||
|
self.cur=self.conn.cursor()
|
||||||
|
|
||||||
|
## Creates all archives, if they don't exist already
|
||||||
|
## Called only on startup, hence the name
|
||||||
|
def startup(self):
|
||||||
|
self.cur.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS Archs(
|
||||||
|
ID int PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
NAME text NOT NULL,
|
||||||
|
HASH text NOT NULL,
|
||||||
|
SIZE int NOT NULL,
|
||||||
|
IMPORTED int,
|
||||||
|
CATEGORY int,
|
||||||
|
OWNER int
|
||||||
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS Users(
|
||||||
|
ID int PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
UNAME text NOT NULL,
|
||||||
|
DNAME text NOT NULL,
|
||||||
|
CREATED int NOT NULL,
|
||||||
|
STATE text,
|
||||||
|
PASSHASH text NOT NULL
|
||||||
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS Sessions(
|
||||||
|
ID int PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
SESSKEY text NOT NULL,
|
||||||
|
CREATED int NOT NULL,
|
||||||
|
LIFE int
|
||||||
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS Cats(
|
||||||
|
ID int PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
CATEGORY text NOT NULL,
|
||||||
|
PARENT int,
|
||||||
|
DESCRIPTION text
|
||||||
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS ArchLab(
|
||||||
|
ID int PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
ARCHID int NOT NULL,
|
||||||
|
LABID int NOT NULL
|
||||||
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS Labs(
|
||||||
|
ID int PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
LABEL text NOT NULL,
|
||||||
|
CATEGORY text,
|
||||||
|
TYPE int NOT NULL
|
||||||
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS LabType(
|
||||||
|
ID int PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
NAME text NOT NULL,
|
||||||
|
DESCRIPTION text
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
|
||||||
|
## 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):
|
||||||
|
#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
|
||||||
|
WHERE hash='{hash}'""")
|
||||||
|
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
|
||||||
|
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;""")
|
||||||
|
labels=self.cur.fetchall()
|
||||||
|
return archive, labels
|
||||||
|
|
||||||
|
## Returns n archives, sorted by (imported )time or size
|
||||||
|
## OUTPUT: archives:array=[…,(NAME:str,SIZE:str,IMPORTED[UNIX]:int),…]
|
||||||
|
def get_n_archives(self, sorttype:str="time",category:int=0, count:int=20):
|
||||||
|
global cur
|
||||||
|
match sorttype:
|
||||||
|
case "size":
|
||||||
|
sorttype="SIZE"
|
||||||
|
case _:
|
||||||
|
sorttype="IMPORTED"
|
||||||
|
self.cur.execute(f"""SELECT NAME,SIZE,IMPORTED FROM Archs{"" if category==0 else " WHERE CATEGORY=" + category} ORDER BY {sorttype} DESC LIMIT {count};""")
|
||||||
|
archives=self.cur.fetchall()
|
||||||
|
return archives
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
#startup()
|
||||||
|
db=db(conn_params)
|
||||||
|
db.cur.close()
|
||||||
|
db.conn.close()
|
||||||
|
exit()
|
11
flask/static/home.css
Normal file
11
flask/static/home.css
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
div.grid-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto auto;
|
||||||
|
}
|
||||||
|
div.grid-item {
|
||||||
|
border: 2px black solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.clickable:hover {
|
||||||
|
background: grey;
|
||||||
|
}
|
|
@ -2,6 +2,8 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<link rel="stylesheet" href="/static/base.css" />
|
<link rel="stylesheet" href="/static/base.css" />
|
||||||
|
{% block meta %}
|
||||||
|
{% endblock %}
|
||||||
<title>RAR-Index – {{title}}</title>
|
<title>RAR-Index – {{title}}</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,20 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block meta %}
|
||||||
|
<link rel="stylesheet" href="/static/home.css" />
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<p>Test</p>
|
{% if archives|length > 0 %}
|
||||||
|
<div class="grid-container">
|
||||||
|
{% for arch in archives %}
|
||||||
|
<div class="grid-item clickable"><b>{{arch[0]}}</b></div>
|
||||||
|
<div class="grid-item"><p>{{arch[1]|spacer}}</p></div>
|
||||||
|
<div class="grid-item"><p>{{arch[2]|ctime}}</p></div>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<p>No matching archives</p>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
Loading…
Reference in a new issue