616 lines
21 KiB
Python
616 lines
21 KiB
Python
# -*- coding: utf-8 -*-
|
|
# all the imports
|
|
import datetime
|
|
import hashlib
|
|
import os
|
|
import re
|
|
import sqlite3
|
|
import time
|
|
from shutil import copyfile, move
|
|
|
|
from flask import (
|
|
Flask,
|
|
abort,
|
|
flash,
|
|
g,
|
|
redirect,
|
|
render_template,
|
|
request,
|
|
session,
|
|
url_for,
|
|
)
|
|
from revprox import ReverseProxied
|
|
|
|
# configuration
|
|
DATABASE = "/data/shop.db"
|
|
DATADIR = "/data"
|
|
DEBUG = False
|
|
SECRET_KEY = os.getenv("SECRET_KEY", "development key")
|
|
USERNAME = os.getenv("ADMIN_USER", "admin")
|
|
PASSWORD = os.getenv("ADMIN_PASSWD", "default")
|
|
MARKDOWN_STYLE = os.getenv("MARKDOWN_STYLE", "markdown")
|
|
URLFINDER = re.compile("((news|telnet|nttp|file|http|ftp|https)://[^ ]+)")
|
|
URLPARSER = re.compile(r"(\[)([^\]]+)(\])\(([^\)]+)\)")
|
|
BOLDFINDER = re.compile(r"\*([^\*]+)\*")
|
|
CODEFINDER = re.compile(r"\`([^\`]+)\`")
|
|
CHECKBOX_DOKUWIKI_TICKED = re.compile(r"<todo #([^>]*)>([^<]+)</todo>")
|
|
CHECKBOX_DOKUWIKI_UNTICKED = re.compile(r"<todo>([^<]+)</todo>")
|
|
SHOPNAME_INVALIDCHARS = re.compile("[^A-Za-z0-9_]+")
|
|
|
|
# create our little application :)
|
|
app = Flask(__name__)
|
|
app.config.from_object(__name__)
|
|
app.config["SESSION_COOKIE_NAME"] = os.getenv("SESSION_COOKIE_NAME", "mdshop")
|
|
app.config["register"] = os.getenv("ENABLE_REGISTER", "true") != "false"
|
|
app.wsgi_app = ReverseProxied(app.wsgi_app)
|
|
|
|
|
|
def connect_db():
|
|
if not os.path.exists(app.config["DATABASE"]):
|
|
db = sqlite3.connect(app.config["DATABASE"])
|
|
for command in open("schema.sql", "rt").read().split(";"):
|
|
db.execute(command)
|
|
db.commit()
|
|
return sqlite3.connect(app.config["DATABASE"])
|
|
|
|
|
|
def password_hash(s):
|
|
return hashlib.sha224(s.encode("utf8")).hexdigest()
|
|
|
|
|
|
def get_username(id):
|
|
cur = g.db.execute("select * from users")
|
|
for row in cur.fetchall():
|
|
if id == row[0]:
|
|
return row[1]
|
|
return None
|
|
|
|
|
|
def get_userid(name):
|
|
cur = g.db.execute("select * from users")
|
|
for row in cur.fetchall():
|
|
if name == row[1]:
|
|
return row[0]
|
|
return None
|
|
|
|
|
|
def get_shares(id):
|
|
cur = g.db.execute("select * from shares")
|
|
shares = []
|
|
for row in cur.fetchall():
|
|
if id == row[1]:
|
|
shares.append(row[0])
|
|
return shares
|
|
|
|
|
|
def get_shop_date(id):
|
|
date = ""
|
|
cur = g.db.execute("select * from shops")
|
|
for row in cur.fetchall():
|
|
if id == row[0]:
|
|
data_dir = os.path.join(DATADIR, get_username(row[2]))
|
|
data_file = os.path.join(data_dir, row[1] + ".txt")
|
|
if os.path.exists(data_file):
|
|
date = datetime.datetime.fromtimestamp(os.path.getmtime(data_file)).strftime("%m/%d %H:%M")
|
|
return date
|
|
|
|
|
|
def get_shop_backup_date(id):
|
|
date = ""
|
|
cur = g.db.execute("select * from shops")
|
|
for row in cur.fetchall():
|
|
if id == row[0]:
|
|
data_dir = os.path.join(DATADIR, get_username(row[2]))
|
|
data_file = os.path.join(data_dir, row[1] + ".txt.bkp")
|
|
if os.path.exists(data_file):
|
|
date = datetime.datetime.fromtimestamp(os.path.getmtime(data_file)).strftime("%m/%d %H:%M")
|
|
return date
|
|
|
|
|
|
def scan_for_new_documents(id):
|
|
user = get_username(id)
|
|
data_dir = os.path.join(DATADIR, user)
|
|
if not os.path.exists(data_dir):
|
|
return
|
|
cur = g.db.execute("select * from shops")
|
|
existing = []
|
|
non_existing = []
|
|
for row in cur.fetchall():
|
|
if row[2] != id:
|
|
continue
|
|
existing.append(row[1])
|
|
for row in os.listdir(data_dir):
|
|
if row.endswith(".txt"):
|
|
if row[:-4] not in existing:
|
|
non_existing.append(row[:-4])
|
|
for shop in non_existing:
|
|
g.db.execute("insert into shops (shop,owner) values (?, ?)", [shop, id])
|
|
g.db.commit()
|
|
|
|
|
|
def markdown_parse(s):
|
|
s = s.decode("utf8")
|
|
s = BOLDFINDER.sub(r'*<span class="md_bold">\1</span>*', s)
|
|
s = CODEFINDER.sub(r'`<span class="md_code">\1</span>`', s)
|
|
s = CHECKBOX_DOKUWIKI_TICKED.sub(r"\2 (\1)", s)
|
|
s = CHECKBOX_DOKUWIKI_UNTICKED.sub(r"\1", s)
|
|
return s
|
|
|
|
|
|
def urlify(s):
|
|
if URLPARSER.search(s):
|
|
return URLPARSER.sub(r'[<a href="\4" target="_blank">\2</a>]', s)
|
|
return URLFINDER.sub(r'<a href="\1" target="_blank">\1</a>', s)
|
|
|
|
|
|
def checkbox_add(item):
|
|
if MARKDOWN_STYLE == "markdown":
|
|
return f"[ ] {item}" + "\n"
|
|
if MARKDOWN_STYLE == "dokuwiki":
|
|
return f"- <todo>{item}</todo>" + "\n"
|
|
|
|
|
|
def untick(item):
|
|
if MARKDOWN_STYLE == "markdown":
|
|
return item.replace("[x]", "[ ]")
|
|
if MARKDOWN_STYLE == "dokuwiki":
|
|
return CHECKBOX_DOKUWIKI_TICKED.sub(r"<todo>\2</todo>", item)
|
|
return item
|
|
|
|
|
|
def tick(item, user=""):
|
|
if MARKDOWN_STYLE == "markdown":
|
|
return item.replace("[ ]", "[x]")
|
|
if MARKDOWN_STYLE == "dokuwiki":
|
|
return CHECKBOX_DOKUWIKI_UNTICKED.sub(r"<todo #{}>\1</todo>".format(user), item)
|
|
return item
|
|
|
|
|
|
def is_ticked(item):
|
|
return "[x]" in item or "<todo #" in item
|
|
|
|
|
|
def is_unticked(item):
|
|
return "[ ]" in item or "<todo>" in item
|
|
|
|
|
|
@app.before_request
|
|
def before_request():
|
|
g.db = connect_db()
|
|
|
|
|
|
@app.teardown_request
|
|
def teardown_request(exception):
|
|
db = getattr(g, "db", None)
|
|
if db is not None:
|
|
db.close()
|
|
|
|
|
|
@app.route("/shop/<shopid>")
|
|
def show_shop(shopid):
|
|
if not session.get("logged_in"):
|
|
return redirect(url_for("login", error=None))
|
|
try:
|
|
shopid = int(shopid)
|
|
except ValueError:
|
|
return redirect(url_for("login", error=None))
|
|
has_access = False
|
|
cur = g.db.execute("select * from shops")
|
|
shared = get_shares(session.get("user"))
|
|
for row in cur.fetchall():
|
|
if row[0] == shopid:
|
|
if row[2] == session.get("user") or row[0] in shared:
|
|
has_access = True
|
|
shopname = row[1]
|
|
break
|
|
if not has_access:
|
|
return redirect(url_for("list_shops"))
|
|
data_dir = os.path.join(DATADIR, get_username(row[2]))
|
|
data_file = os.path.join(data_dir, row[1] + ".txt")
|
|
if not os.path.exists(data_file):
|
|
open(data_file, "wt").close()
|
|
entries = []
|
|
content = open(data_file, "rt").read() # .decode('utf-8')
|
|
for i, row in enumerate(open(data_file, "rt").read().split("\n")):
|
|
# any parsing magick would be here
|
|
row = row.rstrip()
|
|
if row == "":
|
|
continue
|
|
icon = " "
|
|
extra_class = "noitem"
|
|
if is_unticked(row):
|
|
icon = " "
|
|
extra_class = ""
|
|
if is_ticked(row):
|
|
icon = "\u2714"
|
|
extra_class = ""
|
|
row = urlify(row).encode("ascii", "xmlcharrefreplace")
|
|
row = markdown_parse(row)
|
|
if row.startswith("#"):
|
|
row = "<span class=md_head>" + row + "</span>"
|
|
if row.startswith(">"):
|
|
row = "<span class=md_quote>" + row + "</span>"
|
|
entries.append(dict(row=i, text=row, icon=icon, extra_class=extra_class))
|
|
shared_to = []
|
|
cur = g.db.execute("select * from shares")
|
|
for row in cur.fetchall():
|
|
if row[0] == shopid:
|
|
shared_to.append(get_username(row[1]))
|
|
# invalidate autosort in 60 minutes:
|
|
if session.get("sort_update"):
|
|
if time.time() - session.get("sort_update") > 3600:
|
|
session["sort_view"] = False
|
|
session["sort_update"] = time.time()
|
|
|
|
return render_template(
|
|
"show_shop.html",
|
|
entries=entries,
|
|
shop=shopname,
|
|
shopid=shopid,
|
|
content=content,
|
|
shares=shared_to,
|
|
date=get_shop_date(shopid),
|
|
date_bkp=get_shop_backup_date(shopid),
|
|
autosort=session.get("sort_view", False),
|
|
)
|
|
|
|
|
|
@app.route("/")
|
|
def list_shops():
|
|
if not session.get("logged_in"):
|
|
return redirect(url_for("login", error=None))
|
|
scan_for_new_documents(session.get("user"))
|
|
cur = g.db.execute("select * from shops order by shop")
|
|
entries = []
|
|
for row in cur.fetchall():
|
|
if session.get("user") == row[2]: # owner
|
|
date = get_shop_date(row[0])
|
|
entries.append(dict(shop=row[1], shopid=row[0], owner=get_username(row[2]), date=date))
|
|
cur = g.db.execute("select * from shops order by shop")
|
|
shares = get_shares(session.get("user"))
|
|
for row in cur.fetchall():
|
|
if row[0] in shares: # Has been shared to
|
|
date = get_shop_date(row[0])
|
|
entries.append(dict(shop=row[1], shopid=row[0], owner=get_username(row[2]), date=date))
|
|
|
|
return render_template("list_shops.html", entries=entries)
|
|
|
|
|
|
@app.route("/add", methods=["POST"])
|
|
def add_items():
|
|
if not session.get("logged_in"):
|
|
abort(401)
|
|
shopid = int(request.form["shopid"])
|
|
ownerid = g.db.execute("select owner from shops where id=?", (request.form["shopid"],)).fetchall()[0][0]
|
|
shopname = g.db.execute("select shop from shops where id=?", (request.form["shopid"],)).fetchall()[0][0]
|
|
ownername = get_username(ownerid)
|
|
data_dir = os.path.join(DATADIR, ownername)
|
|
data_file = os.path.join(data_dir, shopname + ".txt")
|
|
count = 0
|
|
contents_file = open(data_file, "at")
|
|
for row in request.form["add_md"].split("\n"):
|
|
if row.strip() == "":
|
|
continue
|
|
count += 1
|
|
contents_file.write(checkbox_add(row.strip()))
|
|
contents_file.close()
|
|
flash("Added %d items" % (count))
|
|
return redirect(url_for("show_shop", shopid=shopid))
|
|
|
|
|
|
@app.route("/edit", methods=["POST"])
|
|
def edit_md():
|
|
if not session.get("logged_in"):
|
|
abort(401)
|
|
shopid = int(request.form["shopid"])
|
|
ownerid = g.db.execute("select owner from shops where id=?", (request.form["shopid"],)).fetchall()[0][0]
|
|
shopname = g.db.execute("select shop from shops where id=?", (request.form["shopid"],)).fetchall()[0][0]
|
|
ownername = get_username(ownerid)
|
|
data_dir = os.path.join(DATADIR, ownername)
|
|
data_file = os.path.join(data_dir, shopname + ".txt")
|
|
backup = data_file + ".bkp"
|
|
copyfile(data_file, backup)
|
|
contents_file = open(data_file, "wt")
|
|
contents_list = request.form["edit_md"].split("\n")
|
|
while contents_list[-1].strip() == "":
|
|
contents_list.pop()
|
|
for row in contents_list:
|
|
contents_file.write("%s\n" % (row,))
|
|
contents_file.close()
|
|
flash("Saved new file.")
|
|
return redirect(url_for("show_shop", shopid=shopid))
|
|
|
|
|
|
@app.route("/restore", methods=["POST"])
|
|
def restore_md():
|
|
if not session.get("logged_in"):
|
|
abort(401)
|
|
shopid = int(request.form["shopid"])
|
|
ownerid = g.db.execute("select owner from shops where id=?", (request.form["shopid"],)).fetchall()[0][0]
|
|
shopname = g.db.execute("select shop from shops where id=?", (request.form["shopid"],)).fetchall()[0][0]
|
|
ownername = get_username(ownerid)
|
|
data_dir = os.path.join(DATADIR, ownername)
|
|
data_file = os.path.join(data_dir, shopname + ".txt")
|
|
backup = data_file + ".bkp"
|
|
backup_tmp = data_file + ".tmp"
|
|
if not os.path.exists(backup):
|
|
flash("Backup does not exist")
|
|
return redirect(url_for("show_shop", shopid=shopid))
|
|
copyfile(data_file, backup_tmp)
|
|
copyfile(backup, data_file)
|
|
move(backup_tmp, backup)
|
|
flash("Backup restored")
|
|
return redirect(url_for("show_shop", shopid=shopid))
|
|
|
|
|
|
@app.route("/toggle", methods=["POST"])
|
|
def toggle_item():
|
|
if not session.get("logged_in"):
|
|
abort(401)
|
|
shopid = int(request.form["shopid"])
|
|
ownerid = g.db.execute("select owner from shops where id=?", (request.form["shopid"],)).fetchall()[0][0]
|
|
shopname = g.db.execute("select shop from shops where id=?", (request.form["shopid"],)).fetchall()[0][0]
|
|
ownername = get_username(ownerid)
|
|
user = get_username(session.get("user"))
|
|
req_row = None
|
|
for key in request.form:
|
|
if key.startswith("item"):
|
|
req_row = int(key[4:])
|
|
if key == "toggleAll":
|
|
# Special meaning: toggle all rows
|
|
req_row = -1
|
|
if key == "unTickAll":
|
|
# Special meaning: untick all rows
|
|
req_row = -2
|
|
if req_row == None:
|
|
return redirect(url_for("show_shop", shopid=shopid))
|
|
data_dir = os.path.join(DATADIR, ownername)
|
|
data_file = os.path.join(data_dir, shopname + ".txt")
|
|
backup = data_file + ".bkp"
|
|
contents_file = open(data_file, "rt")
|
|
contents = contents_file.read().split("\n")
|
|
contents_file.close()
|
|
changed = False
|
|
for i, row in enumerate(contents):
|
|
if i == req_row or req_row < 0:
|
|
if req_row != -2: # no ticking if unticking all
|
|
if is_unticked(row):
|
|
contents[i] = tick(row, user)
|
|
if is_ticked(row):
|
|
contents[i] = untick(row)
|
|
if row != contents[i]:
|
|
changed = True
|
|
if changed:
|
|
if req_row == -1 or req_row == -2:
|
|
copyfile(data_file, backup)
|
|
contents_file = open(data_file, "wt")
|
|
contents_file.write("\n".join(contents))
|
|
contents_file.close()
|
|
return redirect(url_for("show_shop", shopid=shopid))
|
|
|
|
|
|
@app.route("/remove_toggled", methods=["POST"])
|
|
def remove_toggled():
|
|
if not session.get("logged_in"):
|
|
abort(401)
|
|
shopid = int(request.form["shopid"])
|
|
ownerid = g.db.execute("select owner from shops where id=?", (request.form["shopid"],)).fetchall()[0][0]
|
|
shopname = g.db.execute("select shop from shops where id=?", (request.form["shopid"],)).fetchall()[0][0]
|
|
ownername = get_username(ownerid)
|
|
data_dir = os.path.join(DATADIR, ownername)
|
|
data_file = os.path.join(data_dir, shopname + ".txt")
|
|
backup = data_file + ".bkp"
|
|
contents_file = open(data_file, "rt")
|
|
contents = []
|
|
changed = False
|
|
for i, row in enumerate(contents_file.read().split("\n")):
|
|
if not is_ticked(row):
|
|
contents.append(row)
|
|
else:
|
|
changed = True
|
|
contents_file.close()
|
|
if changed:
|
|
copyfile(data_file, backup)
|
|
contents_file = open(data_file, "wt")
|
|
contents_file.write("\n".join(contents))
|
|
contents_file.close()
|
|
# ~ flash('successfully posted %s (%d)'%(row,req_row))
|
|
return redirect(url_for("show_shop", shopid=shopid))
|
|
|
|
|
|
@app.route("/add_shop", methods=["POST"])
|
|
def add_shop():
|
|
if not session.get("logged_in"):
|
|
abort(401)
|
|
import re
|
|
import string
|
|
|
|
shopname = SHOPNAME_INVALIDCHARS.sub("", request.form["shop"].lower())
|
|
|
|
if shopname == "":
|
|
flash("Shop name empty!")
|
|
return redirect(url_for("list_shops"))
|
|
cur = g.db.execute("select * from shops order by shop")
|
|
for row in cur.fetchall():
|
|
if shopname == row[1]:
|
|
flash("Shop already exists! " + shopname)
|
|
return redirect(url_for("list_shops"))
|
|
g.db.execute("insert into shops (shop,owner) values (?, ?)", [shopname, session["user"]])
|
|
g.db.commit()
|
|
new_dir = os.path.join(DATADIR, get_username(session["user"]))
|
|
new_file = os.path.join(new_dir, shopname + ".txt")
|
|
if not os.path.exists(new_dir):
|
|
os.mkdir(new_dir)
|
|
open(new_file, "at")
|
|
flash("successfully created new shop: " + shopname)
|
|
return redirect(url_for("list_shops"))
|
|
|
|
|
|
@app.route("/add_share", methods=["POST"])
|
|
def add_share():
|
|
if not session.get("logged_in"):
|
|
abort(401)
|
|
import re
|
|
import string
|
|
|
|
username = SHOPNAME_INVALIDCHARS.sub("", request.form["share"])
|
|
shopid = SHOPNAME_INVALIDCHARS.sub("", request.form["shopid"])
|
|
if username == "":
|
|
flash("User name empty!")
|
|
return redirect(url_for("show_shop", shopid=shopid))
|
|
userid = get_userid(username)
|
|
if userid == None:
|
|
flash("No such user!")
|
|
return redirect(url_for("show_shop", shopid=shopid))
|
|
ownerid = g.db.execute("select owner from shops where id=?", (request.form["shopid"],)).fetchall()[0][0]
|
|
if session.get("user") != ownerid:
|
|
flash("Not your shop!")
|
|
return redirect(url_for("show_shop", shopid=shopid))
|
|
g.db.execute("insert into shares (shopid,userid) values (?, ?)", [shopid, userid])
|
|
g.db.commit()
|
|
flash("Shared to %s" % (username))
|
|
return redirect(url_for("show_shop", shopid=shopid))
|
|
|
|
|
|
@app.route("/remove_share", methods=["POST"])
|
|
def remove_share():
|
|
if not session.get("logged_in"):
|
|
abort(401)
|
|
import re
|
|
import string
|
|
|
|
username = SHOPNAME_INVALIDCHARS.sub("", request.form["user"])
|
|
shopid = SHOPNAME_INVALIDCHARS.sub("", request.form["shopid"])
|
|
if username == "":
|
|
flash("User name empty!")
|
|
return redirect(url_for("show_shop", shopid=shopid))
|
|
userid = get_userid(username)
|
|
if userid == None:
|
|
flash("No such user!")
|
|
return redirect(url_for("show_shop", shopid=shopid))
|
|
ownerid = g.db.execute("select owner from shops where id=?", (request.form["shopid"],)).fetchall()[0][0]
|
|
if session.get("user") != ownerid:
|
|
flash("Not your shop!")
|
|
return redirect(url_for("show_shop", shopid=shopid))
|
|
|
|
g.db.execute("delete from shares where shopid=? and userid=?", [shopid, userid])
|
|
g.db.commit()
|
|
return redirect(url_for("show_shop", shopid=shopid))
|
|
|
|
|
|
@app.route("/remove_shop", methods=["POST"])
|
|
def remove_shop():
|
|
if not session.get("logged_in"):
|
|
abort(401)
|
|
shopid = int(request.form["shopid"])
|
|
ownerid = g.db.execute("select owner from shops where id=?", (request.form["shopid"],)).fetchall()[0][0]
|
|
shopname = g.db.execute("select shop from shops where id=?", (request.form["shopid"],)).fetchall()[0][0]
|
|
ownername = get_username(ownerid)
|
|
data_dir = os.path.join(DATADIR, ownername)
|
|
data_file = os.path.join(data_dir, shopname + ".txt")
|
|
if session.get("user") != ownerid:
|
|
flash("Not your shop!")
|
|
return redirect(url_for("show_shop", shopid=shopid))
|
|
# remove shop DB
|
|
g.db.execute("delete from shops where id=?", [shopid])
|
|
g.db.commit()
|
|
# backup data, and remove
|
|
backup = data_file + ".bkp"
|
|
copyfile(data_file, backup)
|
|
os.remove(data_file)
|
|
# remove shares
|
|
g.db.execute("delete from shares where shopid=?", [shopid])
|
|
g.db.commit()
|
|
flash("successfully deleted shop %s" % (shopname))
|
|
return redirect(url_for("list_shops"))
|
|
|
|
|
|
@app.route("/sort_flip", methods=["POST"])
|
|
def sort_flip():
|
|
if not session.get("sort_view"):
|
|
session["sort_view"] = True
|
|
session["sort_update"] = time.time()
|
|
else:
|
|
session["sort_view"] = False
|
|
session["sort_update"] = time.time()
|
|
shopid = int(request.form["shopid"])
|
|
return redirect(url_for("show_shop", shopid=shopid))
|
|
|
|
|
|
@app.route("/login", methods=["GET", "POST"])
|
|
def login():
|
|
error = None
|
|
if request.method == "POST":
|
|
cur = g.db.execute("select * from users")
|
|
for row in cur.fetchall():
|
|
if request.form["username"] == row[1]:
|
|
if password_hash(request.form["password"]) == row[2]:
|
|
session["logged_in"] = True
|
|
session["user"] = row[0]
|
|
# scan_for_new_documents(row[0])
|
|
return redirect(url_for("list_shops"))
|
|
error = "Invalid user/pass"
|
|
return render_template("login.html", error=error)
|
|
|
|
|
|
@app.route("/register", methods=["GET", "POST"])
|
|
def register():
|
|
error = None
|
|
if not app.config["register"]:
|
|
return ""
|
|
if request.method == "POST":
|
|
import re
|
|
import string
|
|
|
|
username = SHOPNAME_INVALIDCHARS.sub("", request.form["username"])
|
|
password = password_hash(request.form["password"])
|
|
if len(username) == 0:
|
|
error = "No username given"
|
|
return render_template("register.html", error=error)
|
|
if len(request.form["password"]) < 5:
|
|
error = "Password too short"
|
|
return render_template("register.html", error=error)
|
|
cur = g.db.execute("select * from users")
|
|
for row in cur.fetchall():
|
|
if username == row[1]:
|
|
error = "Username already exists"
|
|
return render_template("register.html", error=error)
|
|
g.db.execute("insert into users (user,pass) values (?, ?)", [username, password])
|
|
g.db.commit()
|
|
flash('successfully registered user "%s". Now login.' % username)
|
|
return redirect(url_for("login"))
|
|
return render_template("register.html", error=error)
|
|
|
|
|
|
@app.route("/profile", methods=["GET", "POST"])
|
|
def profile():
|
|
if not session.get("logged_in"):
|
|
return redirect(url_for("login"))
|
|
error = None
|
|
user = get_username(session.get("user"))
|
|
if request.method == "POST":
|
|
import re
|
|
import string
|
|
|
|
password = password_hash(request.form["password"])
|
|
if len(request.form["password"]) < 5:
|
|
error = "Password too short"
|
|
return render_template("profile.html", error=error, user=user)
|
|
g.db.execute("update users set pass=? where id=?", [password, session.get("user")])
|
|
g.db.commit()
|
|
flash("successfully updated profile.")
|
|
return redirect(url_for("profile"))
|
|
return render_template("profile.html", error=error, user=user)
|
|
|
|
|
|
@app.route("/logout")
|
|
def logout():
|
|
session.pop("logged_in", None)
|
|
session.pop("user", None)
|
|
flash("You were logged out")
|
|
return render_template("login.html", error=None)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
app.run()
|