comments
This commit is contained in:
parent
30575bcf20
commit
c548e8c406
|
@ -1,2 +1,2 @@
|
|||
database.db
|
||||
database.db
|
||||
uploads
|
12
config.ini
12
config.ini
|
@ -1,7 +1,7 @@
|
|||
[config]
|
||||
HOST = 0.0.0.0
|
||||
PORT = 8080
|
||||
SECRET_KEY = placeholder
|
||||
UPLOAD_FOLDER = uploads
|
||||
PASSWORD_REQUIREMENT = 12
|
||||
[config]
|
||||
HOST = 0.0.0.0
|
||||
PORT = 8080
|
||||
SECRET_KEY = placeholder
|
||||
UPLOAD_FOLDER = uploads
|
||||
PASSWORD_REQUIREMENT = 12
|
||||
UPLOAD_LIMIT = 4
|
40
edituser
40
edituser
|
@ -1,21 +1,21 @@
|
|||
#!/usr/bin/python3
|
||||
import sqlite3
|
||||
import os
|
||||
|
||||
userid = input("Insert ID: ")
|
||||
changewhat = input("Change what value?: ")
|
||||
towhat = input("What should " + changewhat + " be changed to?: ")
|
||||
|
||||
def get_db_connection():
|
||||
conn = sqlite3.connect("database.db")
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
|
||||
conn = get_db_connection()
|
||||
conn.execute("UPDATE users SET " + changewhat + " = ?"
|
||||
" WHERE id = ?",
|
||||
(str(towhat), userid))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
#!/usr/bin/python3
|
||||
import sqlite3
|
||||
import os
|
||||
|
||||
userid = input("Insert ID: ")
|
||||
changewhat = input("Change what value?: ")
|
||||
towhat = input("What should " + changewhat + " be changed to?: ")
|
||||
|
||||
def get_db_connection():
|
||||
conn = sqlite3.connect("database.db")
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
|
||||
conn = get_db_connection()
|
||||
conn.execute("UPDATE users SET " + changewhat + " = ?"
|
||||
" WHERE id = ?",
|
||||
(str(towhat), userid))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
print("Success!")
|
56
init_db
56
init_db
|
@ -1,29 +1,29 @@
|
|||
#!/usr/bin/python3
|
||||
import sqlite3
|
||||
import os
|
||||
|
||||
def generatedb():
|
||||
connection = sqlite3.connect("database.db")
|
||||
|
||||
with open("schema.sql") as f:
|
||||
connection.executescript(f.read())
|
||||
|
||||
cur = connection.cursor()
|
||||
|
||||
connection.commit()
|
||||
connection.close()
|
||||
|
||||
print("[INFO] Generated database")
|
||||
|
||||
if not os.path.exists("database.db"):
|
||||
generatedb()
|
||||
else:
|
||||
answer = input("Proceeding will overwrite the database. Proceed? (y/N)")
|
||||
if "y" in answer.lower():
|
||||
generatedb()
|
||||
elif "n" in answer.lower():
|
||||
print("Stopped")
|
||||
elif ":3" in answer:
|
||||
print(":3")
|
||||
else:
|
||||
#!/usr/bin/python3
|
||||
import sqlite3
|
||||
import os
|
||||
|
||||
def generatedb():
|
||||
connection = sqlite3.connect("database.db")
|
||||
|
||||
with open("schema.sql") as f:
|
||||
connection.executescript(f.read())
|
||||
|
||||
cur = connection.cursor()
|
||||
|
||||
connection.commit()
|
||||
connection.close()
|
||||
|
||||
print("[INFO] Generated database")
|
||||
|
||||
if not os.path.exists("database.db"):
|
||||
generatedb()
|
||||
else:
|
||||
answer = input("Proceeding will overwrite the database. Proceed? (y/N)")
|
||||
if "y" in answer.lower():
|
||||
generatedb()
|
||||
elif "n" in answer.lower():
|
||||
print("Stopped")
|
||||
elif ":3" in answer:
|
||||
print(":3")
|
||||
else:
|
||||
print("Stopped")
|
684
main
684
main
|
@ -1,317 +1,367 @@
|
|||
#!/usr/bin/python3
|
||||
import os
|
||||
import configparser
|
||||
import sqlite3
|
||||
import json
|
||||
import secrets
|
||||
from werkzeug.utils import secure_filename
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
from flask import Flask, render_template, request, url_for, flash, redirect, session, make_response, send_from_directory, stream_with_context, Response, request
|
||||
|
||||
# read config file
|
||||
config = configparser.ConfigParser()
|
||||
config.read("config.ini")
|
||||
|
||||
HOST = config["config"]["HOST"]
|
||||
PORT = config["config"]["PORT"]
|
||||
SECRET_KEY = config["config"]["SECRET_KEY"]
|
||||
UPLOAD_FOLDER = config["config"]["UPLOAD_FOLDER"]
|
||||
UPLOAD_LIMIT = config["config"]["UPLOAD_LIMIT"]
|
||||
PASSWORD_REQUIREMENT = config["config"]["PASSWORD_REQUIREMENT"]
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config["SECRET_KEY"] = SECRET_KEY
|
||||
app.config["MAX_CONTENT_LENGTH"] = int(UPLOAD_LIMIT) * 1000 * 1000
|
||||
|
||||
if SECRET_KEY == "placeholder":
|
||||
print("[WARNING] Secret key is not set")
|
||||
|
||||
if not os.path.exists(UPLOAD_FOLDER):
|
||||
print("[WARNING] Upload folder doesn't exist, creating one")
|
||||
os.mkdir(UPLOAD_FOLDER)
|
||||
|
||||
if not os.path.exists("database.db"):
|
||||
print("[ERROR] No database exists, please run init_db")
|
||||
exit()
|
||||
|
||||
|
||||
def makeStrSafe(url):
|
||||
return str(urllib.parse.quote(url)).replace("%20", " ")
|
||||
|
||||
|
||||
def get_db_connection():
|
||||
conn = sqlite3.connect("database.db")
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
|
||||
|
||||
def get_user(id):
|
||||
conn = get_db_connection()
|
||||
post = conn.execute("SELECT * FROM users WHERE id = ?",
|
||||
(id,)).fetchone()
|
||||
conn.close()
|
||||
if post is None:
|
||||
return "error"
|
||||
return post
|
||||
|
||||
|
||||
def get_post(id):
|
||||
conn = get_db_connection()
|
||||
post = conn.execute("SELECT * FROM posts WHERE id = ?",
|
||||
(id,)).fetchone()
|
||||
conn.close()
|
||||
if post is None:
|
||||
return "error"
|
||||
return post
|
||||
|
||||
|
||||
app.jinja_env.globals.update(getUser=get_user)
|
||||
|
||||
|
||||
def check_username_taken(username):
|
||||
conn = get_db_connection()
|
||||
post = conn.execute("SELECT * FROM users WHERE username = ?",
|
||||
(username,)).fetchone()
|
||||
conn.close()
|
||||
if post is None:
|
||||
return "error"
|
||||
return post["id"]
|
||||
|
||||
|
||||
def get_session(id):
|
||||
conn = get_db_connection()
|
||||
post = conn.execute("SELECT * FROM sessions WHERE session = ?",
|
||||
(id,)).fetchone()
|
||||
conn.close()
|
||||
if post is None:
|
||||
return "error"
|
||||
return post
|
||||
|
||||
|
||||
ALLOWED_EXTENSIONS = {"png", "apng", "jpg", "jpeg", "gif", "svg", "webp"}
|
||||
|
||||
|
||||
def allowed_file(filename):
|
||||
return '.' in filename and \
|
||||
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
||||
|
||||
|
||||
@app.route("/", methods=("GET", "POST"))
|
||||
def main():
|
||||
usersession = request.cookies.get("session_DO_NOT_SHARE")
|
||||
conn = get_db_connection()
|
||||
posts = conn.execute(
|
||||
"SELECT * FROM posts ORDER BY created DESC;").fetchall()
|
||||
conn.close()
|
||||
|
||||
if usersession:
|
||||
userCookie = get_session(usersession)
|
||||
user = get_user(userCookie["id"])
|
||||
return render_template("main.html", userdata=user, posts=posts)
|
||||
else:
|
||||
return render_template("main.html", posts=posts)
|
||||
|
||||
|
||||
@app.route("/post", methods=("GET", "POST"))
|
||||
def post():
|
||||
usersession = request.cookies.get("session_DO_NOT_SHARE")
|
||||
if usersession:
|
||||
if request.method == "POST":
|
||||
title = request.form["title"]
|
||||
if title == "":
|
||||
flash("Text required :3")
|
||||
return redirect(request.url)
|
||||
|
||||
if "file" not in request.files:
|
||||
flash("No file selected :3")
|
||||
return redirect(request.url)
|
||||
|
||||
file = request.files["file"]
|
||||
if file.filename == "":
|
||||
flash("No file selected :3")
|
||||
return redirect(request.url)
|
||||
|
||||
if not allowed_file(file.filename):
|
||||
flash("File is not an image!")
|
||||
return redirect(request.url)
|
||||
|
||||
filename = secure_filename(file.filename)
|
||||
finalfilename = secrets.token_hex(64) + filename
|
||||
|
||||
file.save(os.path.join(UPLOAD_FOLDER, finalfilename))
|
||||
imgurl = "/cdn/" + finalfilename
|
||||
|
||||
userCookie = get_session(usersession)
|
||||
user = get_user(userCookie["id"])
|
||||
|
||||
if not user["banned"] == "0":
|
||||
flash("Your account has been banned. Reason: " +
|
||||
user["banned"])
|
||||
return redirect(request.url)
|
||||
|
||||
print(userCookie)
|
||||
|
||||
conn = get_db_connection()
|
||||
conn.execute("INSERT INTO posts (textstr, imageurl, creator) VALUES (?, ?, ?)",
|
||||
(title, imgurl, userCookie["id"]))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return redirect("/")
|
||||
|
||||
else:
|
||||
userCookie = get_session(usersession)
|
||||
user = get_user(userCookie["id"])
|
||||
return render_template("post.html", userdata=user)
|
||||
else:
|
||||
flash("A burgercat account is required to post :3")
|
||||
return redirect("/login")
|
||||
|
||||
|
||||
@app.route("/cdn/<filename>", methods=("GET", "POST"))
|
||||
def cdn(filename):
|
||||
if os.path.exists(os.path.join(UPLOAD_FOLDER, filename)):
|
||||
return send_from_directory(UPLOAD_FOLDER, filename)
|
||||
else:
|
||||
return "file doesn't exist!!"
|
||||
|
||||
|
||||
@app.route("/signup", methods=("GET", "POST"))
|
||||
def signup():
|
||||
usersession = request.cookies.get("session_DO_NOT_SHARE")
|
||||
if usersession:
|
||||
return redirect("/")
|
||||
if request.method == "POST":
|
||||
if not check_username_taken(request.form["username"]) == "error":
|
||||
flash("Username already taken :3")
|
||||
return redirect(request.url)
|
||||
|
||||
if not request.form["username"].isalnum():
|
||||
flash("Username must be alphanumeric :3")
|
||||
return redirect(request.url)
|
||||
|
||||
if not len(request.form["password"]) > int(PASSWORD_REQUIREMENT):
|
||||
flash("Password must contain at least " + PASSWORD_REQUIREMENT + " characters")
|
||||
return redirect(request.url)
|
||||
|
||||
hashedpassword = generate_password_hash(request.form["password"])
|
||||
|
||||
conn = get_db_connection()
|
||||
conn.execute("INSERT INTO users (username, password) VALUES (?, ?)",
|
||||
(request.form["username"], hashedpassword))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
return redirect("/login")
|
||||
else:
|
||||
return render_template("signup.html")
|
||||
|
||||
|
||||
@app.route("/login", methods=("GET", "POST"))
|
||||
def login():
|
||||
usersession = request.cookies.get("session_DO_NOT_SHARE")
|
||||
if usersession:
|
||||
return redirect("/")
|
||||
if request.method == "POST":
|
||||
userID = check_username_taken(request.form["username"])
|
||||
user = get_user(userID)
|
||||
|
||||
if user == "error":
|
||||
flash("Wrong username or password :3")
|
||||
return redirect(request.url)
|
||||
|
||||
if not check_password_hash(user["password"], (request.form["password"])):
|
||||
flash("Wrong username or password :3")
|
||||
return redirect(request.url)
|
||||
|
||||
randomCharacters = secrets.token_hex(512)
|
||||
|
||||
conn = get_db_connection()
|
||||
conn.execute("INSERT INTO sessions (session, id) VALUES (?, ?)",
|
||||
(randomCharacters, userID))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
resp = make_response(redirect("/"))
|
||||
resp.set_cookie("session_DO_NOT_SHARE", randomCharacters)
|
||||
|
||||
return resp
|
||||
else:
|
||||
return render_template("login.html")
|
||||
|
||||
|
||||
@app.route("/settings", methods=("GET", "POST"))
|
||||
def settings():
|
||||
usersession = request.cookies.get("session_DO_NOT_SHARE")
|
||||
if usersession:
|
||||
userCookie = get_session(usersession)
|
||||
user = get_user(userCookie["id"])
|
||||
|
||||
return render_template("settings.html", userdata=user)
|
||||
else:
|
||||
return redirect("/")
|
||||
|
||||
|
||||
@app.route("/remove/<postid>", methods=("GET", "POST"))
|
||||
def remove(postid):
|
||||
usersession = request.cookies.get("session_DO_NOT_SHARE")
|
||||
if usersession:
|
||||
userCookie = get_session(usersession)
|
||||
user = get_user(userCookie["id"])
|
||||
if str(user["administrator"]) == "1":
|
||||
post = get_post(postid)
|
||||
conn = get_db_connection()
|
||||
conn.execute("DELETE FROM posts WHERE id = ?", (postid,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return "Deleted post!"
|
||||
else:
|
||||
return "nice try"
|
||||
else:
|
||||
return redirect("/login")
|
||||
|
||||
@app.route("/listusers", methods=("GET", "POST"))
|
||||
def listusers():
|
||||
usersession = request.cookies.get("session_DO_NOT_SHARE")
|
||||
if usersession:
|
||||
userCookie = get_session(usersession)
|
||||
user = get_user(userCookie["id"])
|
||||
if str(user["administrator"]) == "1":
|
||||
thing = ""
|
||||
|
||||
conn = get_db_connection()
|
||||
users = conn.execute("SELECT * FROM users").fetchall()
|
||||
conn.close()
|
||||
for x in users:
|
||||
thing = str(x["id"]) + " - " + x["username"] + "<br>" + thing
|
||||
|
||||
return thing
|
||||
else:
|
||||
return "nice try"
|
||||
else:
|
||||
return redirect("/login")
|
||||
|
||||
|
||||
@app.route("/settings/logout", methods=("GET", "POST"))
|
||||
def logout():
|
||||
resp = redirect("/")
|
||||
session = request.cookies.get("session_DO_NOT_SHARE")
|
||||
resp.delete_cookie("session_DO_NOT_SHARE")
|
||||
|
||||
return resp
|
||||
|
||||
|
||||
@app.errorhandler(413)
|
||||
def page_not_found(e):
|
||||
return "the server decided to commit die"
|
||||
|
||||
|
||||
@app.errorhandler(413)
|
||||
def page_not_found(e):
|
||||
return "Images can't be larger than 4MB"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from waitress import serve
|
||||
print("[INFO] Server started")
|
||||
serve(app, host=HOST, port=PORT)
|
||||
print("[INFO] Server stopped")
|
||||
#!/usr/bin/python3
|
||||
import os
|
||||
import configparser
|
||||
import sqlite3
|
||||
import time
|
||||
import json
|
||||
import secrets
|
||||
from itertools import groupby
|
||||
from werkzeug.utils import secure_filename
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
from flask import Flask, render_template, request, url_for, flash, redirect, session, make_response, send_from_directory, stream_with_context, Response, request
|
||||
|
||||
# read config file
|
||||
config = configparser.ConfigParser()
|
||||
config.read("config.ini")
|
||||
|
||||
HOST = config["config"]["HOST"]
|
||||
PORT = config["config"]["PORT"]
|
||||
SECRET_KEY = config["config"]["SECRET_KEY"]
|
||||
UPLOAD_FOLDER = config["config"]["UPLOAD_FOLDER"]
|
||||
UPLOAD_LIMIT = config["config"]["UPLOAD_LIMIT"]
|
||||
PASSWORD_REQUIREMENT = config["config"]["PASSWORD_REQUIREMENT"]
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config["SECRET_KEY"] = SECRET_KEY
|
||||
app.config["MAX_CONTENT_LENGTH"] = int(UPLOAD_LIMIT) * 1000 * 1000
|
||||
|
||||
if SECRET_KEY == "placeholder":
|
||||
print("[WARNING] Secret key is not set")
|
||||
|
||||
if not os.path.exists(UPLOAD_FOLDER):
|
||||
print("[WARNING] Upload folder doesn't exist, creating")
|
||||
os.mkdir(UPLOAD_FOLDER)
|
||||
|
||||
if not os.path.exists("database.db"):
|
||||
print("[ERROR] No database exists, please run init_db")
|
||||
exit()
|
||||
|
||||
|
||||
def makeStrSafe(url):
|
||||
return str(urllib.parse.quote(url)).replace("%20", " ")
|
||||
|
||||
|
||||
def get_db_connection():
|
||||
conn = sqlite3.connect("database.db")
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
|
||||
|
||||
def get_user(id):
|
||||
conn = get_db_connection()
|
||||
post = conn.execute("SELECT * FROM users WHERE id = ?",
|
||||
(id,)).fetchone()
|
||||
conn.close()
|
||||
if post is None:
|
||||
return "error"
|
||||
return post
|
||||
|
||||
|
||||
def get_comments(id):
|
||||
conn = get_db_connection()
|
||||
post = conn.execute("SELECT * FROM comments WHERE post_id = ?",
|
||||
(id,)).fetchall()
|
||||
conn.close()
|
||||
if post is None:
|
||||
return "error"
|
||||
return post
|
||||
|
||||
|
||||
app.jinja_env.globals.update(getComments=get_comments)
|
||||
|
||||
def get_post(id):
|
||||
conn = get_db_connection()
|
||||
post = conn.execute("SELECT * FROM posts WHERE id = ?",
|
||||
(id,)).fetchone()
|
||||
conn.close()
|
||||
if post is None:
|
||||
return "error"
|
||||
return post
|
||||
|
||||
|
||||
app.jinja_env.globals.update(getUser=get_user)
|
||||
|
||||
|
||||
def check_username_taken(username):
|
||||
conn = get_db_connection()
|
||||
post = conn.execute("SELECT * FROM users WHERE username = ?",
|
||||
(username,)).fetchone()
|
||||
conn.close()
|
||||
if post is None:
|
||||
return "error"
|
||||
return post["id"]
|
||||
|
||||
|
||||
def get_session(id):
|
||||
conn = get_db_connection()
|
||||
post = conn.execute("SELECT * FROM sessions WHERE session = ?",
|
||||
(id,)).fetchone()
|
||||
conn.close()
|
||||
if post is None:
|
||||
return "error"
|
||||
return post
|
||||
|
||||
|
||||
ALLOWED_EXTENSIONS = {"png", "apng", "jpg", "jpeg", "gif", "svg", "webp"}
|
||||
|
||||
|
||||
def allowed_file(filename):
|
||||
return '.' in filename and \
|
||||
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
||||
|
||||
|
||||
@app.route("/", methods=("GET", "POST"))
|
||||
def main():
|
||||
usersession = request.cookies.get("session_DO_NOT_SHARE")
|
||||
conn = get_db_connection()
|
||||
posts = conn.execute("SELECT * FROM posts ORDER BY created DESC;").fetchall()
|
||||
conn.close()
|
||||
|
||||
if usersession:
|
||||
userCookie = get_session(usersession)
|
||||
user = get_user(userCookie["id"])
|
||||
return render_template("main.html", userdata=user, posts=posts)
|
||||
else:
|
||||
return render_template("main.html", posts=posts)
|
||||
|
||||
@app.route("/post", methods=("GET", "POST"))
|
||||
def post():
|
||||
usersession = request.cookies.get("session_DO_NOT_SHARE")
|
||||
if usersession:
|
||||
if request.method == "POST":
|
||||
title = request.form["title"]
|
||||
if title == "":
|
||||
flash("Text required :3")
|
||||
return redirect(url_for("post"))
|
||||
|
||||
if "file" not in request.files:
|
||||
flash("No file selected :3")
|
||||
return redirect(url_for("post"))
|
||||
|
||||
file = request.files["file"]
|
||||
if file.filename == "":
|
||||
flash("No file selected :3")
|
||||
return redirect(url_for("post"))
|
||||
|
||||
if not allowed_file(file.filename):
|
||||
flash("File is not an image!")
|
||||
return redirect(url_for("post"))
|
||||
|
||||
filename = secure_filename(file.filename)
|
||||
finalfilename = secrets.token_hex(64) + filename
|
||||
|
||||
file.save(os.path.join(UPLOAD_FOLDER, finalfilename))
|
||||
imgurl = "/cdn/" + finalfilename
|
||||
|
||||
userCookie = get_session(usersession)
|
||||
user = get_user(userCookie["id"])
|
||||
|
||||
if not user["banned"] == "0":
|
||||
flash("Your account has been banned. Reason: " +
|
||||
user["banned"])
|
||||
return redirect(url_for("post"))
|
||||
|
||||
conn = get_db_connection()
|
||||
conn.execute("INSERT INTO posts (textstr, imageurl, creator, created) VALUES (?, ?, ?, ?)",
|
||||
(title, imgurl, userCookie["id"], str(time.time())))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return redirect(url_for("main"))
|
||||
|
||||
else:
|
||||
userCookie = get_session(usersession)
|
||||
user = get_user(userCookie["id"])
|
||||
return render_template("post.html", userdata=user)
|
||||
else:
|
||||
flash("A burgercat account is required to post :3")
|
||||
return redirect(url_for("login"))
|
||||
|
||||
|
||||
@app.route("/comment", methods=("GET", "POST"))
|
||||
def comment():
|
||||
usersession = request.cookies.get("session_DO_NOT_SHARE")
|
||||
if usersession:
|
||||
if request.method == "POST":
|
||||
|
||||
data = request.get_json()
|
||||
uid = data["id"]
|
||||
title = data["title"]
|
||||
|
||||
userCookie = get_session(usersession)
|
||||
user = get_user(userCookie["id"])
|
||||
|
||||
if not user["banned"] == "0":
|
||||
flash("Your account has been banned. Reason: " +
|
||||
user["banned"])
|
||||
return redirect(url_for("comment"))
|
||||
|
||||
conn = get_db_connection()
|
||||
conn.execute("INSERT INTO comments (textstr, post_id, creator, created) VALUES (?, ?, ?, ?)",
|
||||
(title, uid, userCookie["id"], str(time.time())))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
return "success"
|
||||
|
||||
else:
|
||||
return """<img src="https://http.cat/images/400.jpg">""", 400
|
||||
else:
|
||||
flash("A burgercat account is required to post :3")
|
||||
return redirect(url_for("login"))
|
||||
|
||||
|
||||
@app.route("/cdn/<filename>", methods=("GET", "POST"))
|
||||
def cdn(filename):
|
||||
if os.path.exists(os.path.join(UPLOAD_FOLDER, filename)):
|
||||
return send_from_directory(UPLOAD_FOLDER, filename)
|
||||
else:
|
||||
return "file doesn't exist!!"
|
||||
|
||||
|
||||
@app.route("/signup", methods=("GET", "POST"))
|
||||
def signup():
|
||||
usersession = request.cookies.get("session_DO_NOT_SHARE")
|
||||
if usersession:
|
||||
return redirect(url_for("main"))
|
||||
if request.method == "POST":
|
||||
if not check_username_taken(request.form["username"]) == "error":
|
||||
flash("Username already taken :3")
|
||||
return redirect(url_for("signup"))
|
||||
|
||||
if not request.form["username"].isalnum():
|
||||
flash("Username must be alphanumeric :3")
|
||||
return redirect(url_for("signup"))
|
||||
|
||||
if not len(request.form["password"]) > int(PASSWORD_REQUIREMENT):
|
||||
flash("Password must contain at least " + PASSWORD_REQUIREMENT + " characters")
|
||||
return redirect(url_for("signup"))
|
||||
|
||||
hashedpassword = generate_password_hash(request.form["password"])
|
||||
|
||||
conn = get_db_connection()
|
||||
conn.execute("INSERT INTO users (username, password, created) VALUES (?, ?, ?)",
|
||||
(request.form["username"], hashedpassword, str(time.time())))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
return redirect(url_for("login"))
|
||||
else:
|
||||
return render_template("signup.html")
|
||||
|
||||
|
||||
@app.route("/login", methods=("GET", "POST"))
|
||||
def login():
|
||||
usersession = request.cookies.get("session_DO_NOT_SHARE")
|
||||
if usersession:
|
||||
redirect(url_for("main"))
|
||||
if request.method == "POST":
|
||||
userID = check_username_taken(request.form["username"])
|
||||
user = get_user(userID)
|
||||
|
||||
if user == "error":
|
||||
flash("Wrong username or password :3")
|
||||
return redirect(url_for("login"))
|
||||
|
||||
if not check_password_hash(user["password"], (request.form["password"])):
|
||||
flash("Wrong username or password :3")
|
||||
return redirect(url_for("login"))
|
||||
|
||||
randomCharacters = secrets.token_hex(512)
|
||||
|
||||
conn = get_db_connection()
|
||||
conn.execute("INSERT INTO sessions (session, id) VALUES (?, ?)",
|
||||
(randomCharacters, userID))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
resp = make_response(redirect("/"))
|
||||
resp.set_cookie("session_DO_NOT_SHARE", randomCharacters)
|
||||
|
||||
return resp
|
||||
else:
|
||||
return render_template("login.html")
|
||||
|
||||
|
||||
@app.route("/settings", methods=("GET", "POST"))
|
||||
def settings():
|
||||
usersession = request.cookies.get("session_DO_NOT_SHARE")
|
||||
if usersession:
|
||||
userCookie = get_session(usersession)
|
||||
user = get_user(userCookie["id"])
|
||||
|
||||
return render_template("settings.html", userdata=user)
|
||||
else:
|
||||
return redirect("/")
|
||||
|
||||
|
||||
@app.route("/remove/<postid>", methods=("GET", "POST"))
|
||||
def remove(postid):
|
||||
usersession = request.cookies.get("session_DO_NOT_SHARE")
|
||||
if usersession:
|
||||
userCookie = get_session(usersession)
|
||||
user = get_user(userCookie["id"])
|
||||
if str(user["administrator"]) == "1":
|
||||
post = get_post(postid)
|
||||
conn = get_db_connection()
|
||||
conn.execute("DELETE FROM posts WHERE id = ?", (postid,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return "Deleted post!"
|
||||
else:
|
||||
return "nice try"
|
||||
else:
|
||||
return redirect(url_for("login"))
|
||||
|
||||
@app.route("/listusers", methods=("GET", "POST"))
|
||||
def listusers():
|
||||
usersession = request.cookies.get("session_DO_NOT_SHARE")
|
||||
if usersession:
|
||||
userCookie = get_session(usersession)
|
||||
user = get_user(userCookie["id"])
|
||||
if str(user["administrator"]) == "1":
|
||||
thing = ""
|
||||
|
||||
conn = get_db_connection()
|
||||
users = conn.execute("SELECT * FROM users").fetchall()
|
||||
conn.close()
|
||||
for x in users:
|
||||
thing = str(x["id"]) + " - " + x["username"] + "<br>" + thing
|
||||
|
||||
return thing
|
||||
else:
|
||||
return """<img src="https://http.cat/images/403.jpg">"""
|
||||
else:
|
||||
return redirect(url_for("login"))
|
||||
|
||||
|
||||
@app.route("/settings/logout", methods=("GET", "POST"))
|
||||
def logout():
|
||||
resp = redirect(url_for("main"))
|
||||
session = request.cookies.get("session_DO_NOT_SHARE")
|
||||
resp.delete_cookie("session_DO_NOT_SHARE")
|
||||
|
||||
return resp
|
||||
|
||||
@app.errorhandler(500)
|
||||
def page_not_found(e):
|
||||
return """<img src="https://http.cat/images/500.jpg">""", 500
|
||||
|
||||
@app.errorhandler(400)
|
||||
def page_not_found(e):
|
||||
return """<img src="https://http.cat/images/400.jpg">""", 400
|
||||
|
||||
@app.errorhandler(404)
|
||||
def page_not_found(e):
|
||||
return """<img src="https://http.cat/images/404.jpg">""", 404
|
||||
|
||||
@app.errorhandler(413)
|
||||
def page_not_found(e):
|
||||
return "Images can't be larger than 4MB", 413
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from waitress import serve
|
||||
print("[INFO] Server started")
|
||||
serve(app, host=HOST, port=PORT)
|
||||
#app.run(host=HOST, port=PORT, debug=True)
|
||||
print("[INFO] Server stopped")
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
burger social media
|
||||
|
||||
self hosting:
|
||||
- git clone https://codeberg.org/burger-software/burgercat
|
||||
- cd burgercat
|
||||
- python init_db
|
||||
- python main
|
|
@ -1,2 +1,3 @@
|
|||
flask
|
||||
werkzeug
|
||||
flask
|
||||
werkzeug
|
||||
waitress
|
57
schema.sql
57
schema.sql
|
@ -1,25 +1,34 @@
|
|||
DROP TABLE IF EXISTS users;
|
||||
DROP TABLE IF EXISTS posts;
|
||||
DROP TABLE IF EXISTS sessions;
|
||||
|
||||
CREATE TABLE users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
username TEXT NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
banned TEXT NOT NULL DEFAULT 0,
|
||||
administrator INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE posts (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
creator TEXT NOT NULL,
|
||||
imageurl TEXT NOT NULL,
|
||||
textstr TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE sessions (
|
||||
session TEXT PRIMARY KEY NOT NULL,
|
||||
id INTEGER NOT NULL
|
||||
DROP TABLE IF EXISTS users;
|
||||
DROP TABLE IF EXISTS posts;
|
||||
DROP TABLE IF EXISTS comments;
|
||||
DROP TABLE IF EXISTS sessions;
|
||||
|
||||
CREATE TABLE users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created TEXT NOT NULL,
|
||||
username TEXT NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
banned TEXT NOT NULL DEFAULT 0,
|
||||
administrator INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE posts (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created TEXT NOT NULL,
|
||||
creator TEXT NOT NULL,
|
||||
imageurl TEXT NOT NULL,
|
||||
textstr TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE comments (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
post_id INTEGER NOT NULL,
|
||||
created TEXT NOT NULL,
|
||||
creator TEXT NOT NULL,
|
||||
textstr TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE sessions (
|
||||
session TEXT PRIMARY KEY NOT NULL,
|
||||
id INTEGER NOT NULL
|
||||
);
|
|
@ -1,94 +1,136 @@
|
|||
@import url("https://fonts.googleapis.com/css2?family=Inter&display=swap");
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Inter", sans-serif;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
border: solid;
|
||||
border-color: grey;
|
||||
border-width: 0;
|
||||
border-bottom-width: 1px;
|
||||
background-color: white;
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
}
|
||||
.navbar .selected {
|
||||
border: solid;
|
||||
border-color: #f1b739;
|
||||
border-width: 0;
|
||||
border-bottom-width: 2px;
|
||||
}
|
||||
|
||||
.accountform {
|
||||
margin-left: 20%;
|
||||
margin-right: 20%;
|
||||
}
|
||||
.accountform input {
|
||||
padding: 7px;
|
||||
border: solid;
|
||||
border-width: 1px;
|
||||
border-color: grey;
|
||||
width: calc(100% - 15px);
|
||||
font-size: 16px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.accountform .flash {
|
||||
padding: 7px;
|
||||
border: solid;
|
||||
border-width: 1px;
|
||||
border-color: #f1b739;
|
||||
width: calc(100% - 15px);
|
||||
font-size: 16px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.accountform button {
|
||||
padding: 7px;
|
||||
border: solid;
|
||||
border-width: 1px;
|
||||
color: black;
|
||||
border-color: grey;
|
||||
background-color: white;
|
||||
font-size: 16px;
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.navbar a {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.navbar .right {
|
||||
float: right;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.navbar .r {
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.post {
|
||||
margin: 10px;
|
||||
padding: 5px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 10px;
|
||||
background-color: rgb(250, 250, 250);
|
||||
}
|
||||
|
||||
.post img {
|
||||
min-height: 200px;
|
||||
max-height: 300px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.post .username {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.post .date {
|
||||
color: rgb(175, 175, 175);
|
||||
@import url("https://fonts.googleapis.com/css2?family=Inter&display=swap");
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Inter", sans-serif;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
border: solid;
|
||||
border-color: grey;
|
||||
border-width: 0;
|
||||
border-bottom-width: 1px;
|
||||
background-color: white;
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
}
|
||||
.navbar .selected {
|
||||
border: solid;
|
||||
border-color: #f1b739;
|
||||
border-width: 0;
|
||||
border-bottom-width: 2px;
|
||||
}
|
||||
.postDiv {
|
||||
padding-top: 120px;
|
||||
}
|
||||
|
||||
.accountform {
|
||||
margin-left: 20%;
|
||||
margin-right: 20%;
|
||||
}
|
||||
.accountform input {
|
||||
padding: 7px;
|
||||
border: solid;
|
||||
border-width: 1px;
|
||||
border-color: grey;
|
||||
width: calc(100% - 15px);
|
||||
font-size: 16px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.accountform .flash {
|
||||
padding: 7px;
|
||||
border: solid;
|
||||
border-width: 1px;
|
||||
border-color: #f1b739;
|
||||
width: calc(100% - 15px);
|
||||
font-size: 16px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.accountform button {
|
||||
padding: 7px;
|
||||
border: solid;
|
||||
border-width: 1px;
|
||||
color: black;
|
||||
border-color: grey;
|
||||
background-color: white;
|
||||
font-size: 16px;
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.navbar a {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.navbar .right {
|
||||
float: right;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.navbar .r {
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.post {
|
||||
margin: 10px;
|
||||
padding: 5px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 10px;
|
||||
background-color: rgb(250, 250, 250);
|
||||
}
|
||||
|
||||
.post img {
|
||||
min-height: 200px;
|
||||
max-height: 300px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.post button {
|
||||
background-color: rgb(250, 250, 250);
|
||||
border: solid;
|
||||
border-color: rgb(197, 197, 197);
|
||||
border-width: 1px;
|
||||
border-radius: 6px;
|
||||
font-size: 16px;
|
||||
font-family: "Inter", sans-serif;
|
||||
}
|
||||
.post button:hover {
|
||||
border-color: #f1b739;
|
||||
}
|
||||
|
||||
.post .commentdiv input {
|
||||
background-color: rgb(250, 250, 250);
|
||||
border: solid;
|
||||
border-color: rgb(197, 197, 197);
|
||||
border-width: 1px;
|
||||
border-radius: 6px;
|
||||
font-size: 16px;
|
||||
margin-top: 5px;
|
||||
font-family: "Inter", sans-serif;
|
||||
}
|
||||
.post hr {
|
||||
color: rgb(255, 255, 255);
|
||||
background-color: rgb(255, 255, 255);
|
||||
border-color: rgb(255, 255, 255);
|
||||
}
|
||||
.post .commentsdiv {
|
||||
background-color: #f5f5f5;
|
||||
padding: 5px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.post .username {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.post .date {
|
||||
color: rgb(175, 175, 175);
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
const posts = document.getElementsByClassName("post")
|
||||
for (let i = 0; i < posts.length; i++) {
|
||||
let post = posts[i]
|
||||
let commentButton = post.children["commentButton"]
|
||||
let commentId = post.children["commentId"]
|
||||
let commentDiv = post.children["commentDiv"]
|
||||
let commentBox = commentDiv.children["commentBox"]
|
||||
let commentSave = commentDiv.children["commentDivSave"]
|
||||
let commentCancel = commentDiv.children["commentDivCancel"]
|
||||
|
||||
commentButton.addEventListener("click", (e) => {
|
||||
commentDiv.classList.remove("hidden")
|
||||
commentBox.value = ""
|
||||
});
|
||||
commentCancel.addEventListener("click", (e) => {
|
||||
commentDiv.classList.add("hidden")
|
||||
});
|
||||
commentSave.addEventListener("click", (e) => {
|
||||
console.log(commentId.innerHTML)
|
||||
title = String(commentBox.value)
|
||||
id = String(commentId.innerHTML)
|
||||
|
||||
fetch("/comment", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
id: id,
|
||||
title: title,
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((json) => console.log(json));
|
||||
|
||||
commentDiv.classList.add("hidden")
|
||||
});
|
||||
}
|
|
@ -1,35 +1,35 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>burgercat</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form class="accountform" method="post">
|
||||
<br>
|
||||
<a href="/">back</a>
|
||||
<br><br>
|
||||
<h1>Log in to burgercat</h1>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<p class="flash">{{ message }}</p>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<input name="username" type="text" placeholder="Username" required>
|
||||
<br><br>
|
||||
<input name="password" type="password" placeholder="Password" required>
|
||||
<br>
|
||||
<br>
|
||||
<button type="submit">Log in</button>
|
||||
<br><br>
|
||||
Don't have an account? <a href="/signup">Sign up!</a>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>burgercat</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form class="accountform" method="post">
|
||||
<br>
|
||||
<a href="/">back</a>
|
||||
<br><br>
|
||||
<h1>Log in to burgercat</h1>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<p class="flash">{{ message }}</p>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<input name="username" type="text" placeholder="Username" required>
|
||||
<br><br>
|
||||
<input name="password" type="password" placeholder="Password" required>
|
||||
<br>
|
||||
<br>
|
||||
<button type="submit">Log in</button>
|
||||
<br><br>
|
||||
Don't have an account? <a href="/signup">Sign up!</a>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,45 +1,98 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>burgercat</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="navbar">
|
||||
<h1>burgercat</h1>
|
||||
<a class="selected" href="/">home</a>
|
||||
<a href="/post">post</a>
|
||||
{% if userdata %}
|
||||
<a href="/settings/logout" class="right r">log out</a>
|
||||
<a href="/settings" class="right">{{ userdata.username }}</a>
|
||||
{% else %}
|
||||
<a href="/signup" class="right r">sign up</a>
|
||||
<a href="/login" class="right">log in</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<br><br><br><br><br><br>
|
||||
|
||||
{% for post in posts %}
|
||||
<div class="post">
|
||||
<p class="username">{{ getUser(post["creator"])["username"] }}</p>
|
||||
<p class="date">{{ post["created"] }}</p>
|
||||
{% if userdata %}
|
||||
{% if userdata.administrator == 1 %}
|
||||
<a class="date" href='/remove/{{post["id"]}}'>Remove post</a>
|
||||
<br><br>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<img loading="lazy" src='{{ post["imageurl"] }}'>
|
||||
<p class="text">{{ post["textstr"] }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
</body>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>burgercat</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="navbar">
|
||||
<h1>burgercat</h1>
|
||||
<a class="selected" href="/">home</a>
|
||||
<a href="/post">post</a>
|
||||
{% if userdata %}
|
||||
<a href="/settings/logout" class="right r">log out</a>
|
||||
<a href="/settings" class="right">{{ userdata.username }}</a>
|
||||
{% else %}
|
||||
<a href="/signup" class="right r">sign up</a>
|
||||
<a href="/login" class="right">log in</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let timeStampElement
|
||||
let unixTime
|
||||
</script>
|
||||
|
||||
<div class="postDiv">
|
||||
{% for post in posts %}
|
||||
<div class="post" id="post">
|
||||
<p class="username">{{ getUser(post["creator"])["username"] }}</p>
|
||||
<p class="date" id='timestamp_{{post["id"]}}'> </p>
|
||||
{% if userdata %}
|
||||
{% if userdata.administrator == 1 %}
|
||||
<a class="date" href='/remove/{{post["id"]}}'>Remove post</a>
|
||||
<br><br>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<img loading="lazy" src='{{ post["imageurl"] }}'>
|
||||
<p class="text">{{ post["textstr"] }}</p>
|
||||
<div class="commentsdiv">
|
||||
{% for comment in getComments(post["id"]) %}
|
||||
<p>{{ getUser(comment["creator"])["username"] }}: {{ comment.textstr }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<p id="commentId" class="hidden">{{ post.id }}</p>
|
||||
<button id="commentButton" class="comment">comment</button>
|
||||
<div id="commentDiv" class="commentdiv hidden">
|
||||
<input id="commentBox" type="text" placeholder="content">
|
||||
<button id="commentDivSave">save</button>
|
||||
<button id="commentDivCancel">cancel</button>
|
||||
</div>
|
||||
<script>
|
||||
function time2TimeAgo(ts) {
|
||||
var d = new Date();
|
||||
var nowTs = Math.floor(d.getTime() / 1000);
|
||||
var seconds = nowTs - ts;
|
||||
|
||||
var interval = seconds / 31536000;
|
||||
|
||||
if (interval > 1) {
|
||||
return Math.floor(interval) + " years ago";
|
||||
}
|
||||
interval = seconds / 2592000;
|
||||
if (interval > 1) {
|
||||
return Math.floor(interval) + " months ago";
|
||||
}
|
||||
interval = seconds / 86400;
|
||||
if (interval > 1) {
|
||||
return Math.floor(interval) + " days ago";
|
||||
}
|
||||
interval = seconds / 3600;
|
||||
if (interval > 1) {
|
||||
return Math.floor(interval) + " hours ago";
|
||||
}
|
||||
interval = seconds / 60;
|
||||
if (interval > 1) {
|
||||
return Math.floor(interval) + " minutes ago";
|
||||
}
|
||||
return Math.floor(seconds) + " seconds";
|
||||
}
|
||||
|
||||
timeStampElement = document.getElementById('timestamp_{{post["id"]}}')
|
||||
unixTime = '{{post["created"]}}'
|
||||
|
||||
timeStampElement.innerHTML = time2TimeAgo(unixTime)
|
||||
</script>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<script src="/static/js/main.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,65 +1,63 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>burgercat</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="navbar">
|
||||
<h1>burgercat</h1>
|
||||
<a href="/">home</a>
|
||||
<a class="selected" href="/post">post</a>
|
||||
{% if userdata %}
|
||||
<a href="/settings/logout" class="right r">log out</a>
|
||||
<a href="/settings" class="right">{{ userdata.username }}</a>
|
||||
{% else %}
|
||||
<a href="/signup" class="right r">sign up</a>
|
||||
<a href="/login" class="right">log in</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<br><br><br><br><br><br>
|
||||
<div class="post">
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<p class="flash">{{ message }}</p>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<h2>Post</h2>
|
||||
<p>Image</p>
|
||||
<input type="file" name="file" required>
|
||||
<br>
|
||||
<p>Text</p>
|
||||
<input name="title" type="text" placeholder="Text" required>
|
||||
<br><br>
|
||||
<input class="submit" type="submit" value="Post">
|
||||
</form>
|
||||
</div>
|
||||
<div class="post">
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<h2>Rules</h2>
|
||||
<ul>
|
||||
<li>Please do not spam</li>
|
||||
<li>Treat everyone with respect, respect each others opinions</li>
|
||||
<li>Posting NSFW content is strictly prohibited, doing so will get you an instant ban</li>
|
||||
<li>Discussions regarding politics and related controversial topics are disallowed</li>
|
||||
<li>Advertising is not allowed</li>
|
||||
<li>Do not post links</li>
|
||||
<li>Do not create alt-accounts to evade bans</li>
|
||||
<br>
|
||||
In general, just be a good person.
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>burgercat</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="navbar">
|
||||
<h1>burgercat</h1>
|
||||
<a href="/">home</a>
|
||||
<a class="selected" href="/post">post</a>
|
||||
{% if userdata %}
|
||||
<a href="/settings/logout" class="right r">log out</a>
|
||||
<a href="/settings" class="right">{{ userdata.username }}</a>
|
||||
{% else %}
|
||||
<a href="/signup" class="right r">sign up</a>
|
||||
<a href="/login" class="right">log in</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<br><br><br><br><br><br>
|
||||
<div class="post">
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<p class="flash">{{ message }}</p>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<h2>Post</h2>
|
||||
<p>Image</p>
|
||||
<input type="file" name="file" required>
|
||||
<br>
|
||||
<p>Text</p>
|
||||
<input name="title" type="text" placeholder="Text" required>
|
||||
<br><br>
|
||||
<input class="submit" type="submit" value="Post">
|
||||
</form>
|
||||
</div>
|
||||
<div class="post">
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<h2>Rules</h2>
|
||||
<ul>
|
||||
<li>Please do not spam</li>
|
||||
<li>Treat everyone with respect, respect each others opinions</li>
|
||||
<li>Posting NSFW content is strictly prohibited, doing so will get you an instant ban</li>
|
||||
<li>Discussions regarding politics and related controversial topics are disallowed</li>
|
||||
<li>Advertising is not allowed</li>
|
||||
<li>Do not post links</li>
|
||||
<li>Do not create alt-accounts to evade bans</li>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,39 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>burgercat</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="navbar">
|
||||
<h1>burgercat</h1>
|
||||
<a href="/">home</a>
|
||||
<a href="/post">post</a>
|
||||
{% if userdata %}
|
||||
<a href="/settings/logout" class="right r">log out</a>
|
||||
<a href="/settings" class="right selected">{{ userdata.username }}</a>
|
||||
{% else %}
|
||||
<a href="/signup" class="right r">sign up</a>
|
||||
<a href="/login" class="right">log in</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<br><br><br><br><br><br>
|
||||
<div class="post">
|
||||
{% if userdata.administrator == 1 %}
|
||||
Administrator<br><br>
|
||||
{% endif %}
|
||||
Logged in as {{ userdata.username }}<br>
|
||||
Your user ID is {{ userdata.id }}
|
||||
<br><br>
|
||||
<a href="/settings/logout">Log out</a>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>burgercat</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="navbar">
|
||||
<h1>burgercat</h1>
|
||||
<a href="/">home</a>
|
||||
<a href="/post">post</a>
|
||||
{% if userdata %}
|
||||
<a href="/settings/logout" class="right r">log out</a>
|
||||
<a href="/settings" class="right selected">{{ userdata.username }}</a>
|
||||
{% else %}
|
||||
<a href="/signup" class="right r">sign up</a>
|
||||
<a href="/login" class="right">log in</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<br><br><br><br><br><br><br>
|
||||
<div class="post">
|
||||
{% if userdata.administrator == 1 %}
|
||||
Administrator<br><br>
|
||||
{% endif %}
|
||||
Logged in as {{ userdata.username }}
|
||||
<br><br>
|
||||
<a href="/settings/logout">Log out</a>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,35 +1,35 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>burgercat</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form class="accountform" method="post">
|
||||
<br>
|
||||
<a href="/">back</a>
|
||||
<br><br>
|
||||
<h1>Create a burgercat account</h1>
|
||||
<p>Create a burgercat acccount to create posts and more!</p>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<p class="flash">{{ message }}</p>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<input name="username" type="text" placeholder="Username" required>
|
||||
<br><br>
|
||||
<input name="password" type="password" placeholder="Password" required>
|
||||
<br><br>
|
||||
<button type="submit">Sign up</button>
|
||||
<br><br>
|
||||
Already have an account? <a href="/login">Log in!</a>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>burgercat</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form class="accountform" method="post">
|
||||
<br>
|
||||
<a href="/">back</a>
|
||||
<br><br>
|
||||
<h1>Create a burgercat account</h1>
|
||||
<p>Create a burgercat acccount to create posts and more!</p>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<p class="flash">{{ message }}</p>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<input name="username" type="text" placeholder="Username" required>
|
||||
<br><br>
|
||||
<input name="password" type="password" placeholder="Password" required>
|
||||
<br><br>
|
||||
<button type="submit">Sign up</button>
|
||||
<br><br>
|
||||
Already have an account? <a href="/login">Log in!</a>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Reference in New Issue