dockerized structure
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
|
||||
A simple shopping list app:
|
||||
|
||||
* Runs on gunicorn+flask (python2.7)
|
||||
* Runs on gunicorn+flask (python3)
|
||||
* Dockerizes
|
||||
* Multi-user
|
||||
* Data saved as flat files, can contain markdown
|
||||
* Syntaxes parsed:
|
||||
|
||||
10
code/Dockerfile
Normal file
10
code/Dockerfile
Normal file
@@ -0,0 +1,10 @@
|
||||
#FROM alpine:3.10
|
||||
FROM python:3
|
||||
COPY requirements.txt /requirements.txt
|
||||
RUN python3 -m venv /venv && \
|
||||
. /venv/bin/activate && \
|
||||
pip3 install --upgrade pip && \
|
||||
pip3 install -r /requirements.txt
|
||||
COPY . /code/
|
||||
WORKDIR /code
|
||||
CMD . /venv/bin/activate && ./start.me
|
||||
613
code/shop.py
Normal file
613
code/shop.py
Normal file
@@ -0,0 +1,613 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# all the imports
|
||||
import sqlite3, time, datetime, hashlib, os, re
|
||||
from shutil import copyfile, move
|
||||
from flask import (
|
||||
Flask,
|
||||
request,
|
||||
session,
|
||||
g,
|
||||
redirect,
|
||||
url_for,
|
||||
abort,
|
||||
render_template,
|
||||
flash,
|
||||
)
|
||||
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")
|
||||
URLFINDER = re.compile("((news|telnet|nttp|file|http|ftp|https)://[^ ]+)")
|
||||
URLPARSER = re.compile(r"(\[)([^\]]+)(\])\(([^\)]+)\)")
|
||||
BOLDFINDER = re.compile(r"\*([^\*]+)\*")
|
||||
CODEFINDER = re.compile(r"\`([^\`]+)\`")
|
||||
|
||||
# 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"
|
||||
print(app.config)
|
||||
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] + ".md")
|
||||
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] + ".md.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(".md"):
|
||||
if row[:-3] not in existing:
|
||||
non_existing.append(row[:-3])
|
||||
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)
|
||||
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)
|
||||
|
||||
|
||||
@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] + ".md")
|
||||
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 "[ ]" in row:
|
||||
icon = u" "
|
||||
extra_class = ""
|
||||
if "[x]" in row:
|
||||
icon = u"\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 + ".md")
|
||||
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("[ ] %s\n" % 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 + ".md")
|
||||
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 + ".md")
|
||||
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)
|
||||
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 + ".md")
|
||||
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 "[ ]" in row:
|
||||
contents[i] = row.replace("[ ]", "[x]")
|
||||
if "[x]" in row:
|
||||
contents[i] = row.replace("[x]", "[ ]")
|
||||
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 + ".md")
|
||||
backup = data_file + ".bkp"
|
||||
contents_file = open(data_file, "rt")
|
||||
contents = []
|
||||
changed = False
|
||||
for i, row in enumerate(contents_file.read().split("\n")):
|
||||
if "[x]" not in 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, string
|
||||
|
||||
pattern = re.compile("[\W]+")
|
||||
shopname = pattern.sub("", request.form["shop"])
|
||||
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 + ".md")
|
||||
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, string
|
||||
|
||||
pattern = re.compile("[\W]+")
|
||||
username = pattern.sub("", request.form["share"])
|
||||
shopid = pattern.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, string
|
||||
|
||||
pattern = re.compile("[\W]+")
|
||||
username = pattern.sub("", request.form["user"])
|
||||
shopid = pattern.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 + ".md")
|
||||
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, string
|
||||
|
||||
pattern = re.compile("[\W]+")
|
||||
username = pattern.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, string
|
||||
|
||||
pattern = re.compile("[\W]+")
|
||||
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()
|
||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
4
debug.py
4
debug.py
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
from shop import app
|
||||
print('http://127.0.0.1:5000/')
|
||||
app.run(debug=True,host="0.0.0.0")
|
||||
15
docker-compose.example
Normal file
15
docker-compose.example
Normal file
@@ -0,0 +1,15 @@
|
||||
version: "3.5"
|
||||
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: code
|
||||
ports:
|
||||
- "127.0.0.1:8166:8166"
|
||||
volumes:
|
||||
- ./data/:/data/
|
||||
environment:
|
||||
- SECRET_KEY=gifodjgoifdjgoejr903
|
||||
user: "1000:1000"
|
||||
restart: unless-stopped
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export SESSION_COOKIE_NAME=mdshop
|
||||
#export ENABLE_REGISTER=false
|
||||
exec gunicorn -b 127.0.0.1:8000 -w 2 shop:app
|
||||
540
shop.py
540
shop.py
@@ -1,540 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# all the imports
|
||||
import sqlite3, time, datetime, hashlib, os, re
|
||||
from shutil import copyfile, move
|
||||
from flask import Flask, request, session, g, redirect, url_for, \
|
||||
abort, render_template, flash
|
||||
from revprox import ReverseProxied
|
||||
|
||||
# configuration
|
||||
DATABASE = 'shop.db'
|
||||
DATADIR = 'data'
|
||||
DEBUG = False
|
||||
SECRET_KEY = 'development key'
|
||||
USERNAME = 'admin'
|
||||
PASSWORD = 'default'
|
||||
URLFINDER = re.compile("((news|telnet|nttp|file|http|ftp|https)://[^ ]+)")
|
||||
URLPARSER = re.compile(r'(\[)([^\]]+)(\])\(([^\)]+)\)')
|
||||
BOLDFINDER = re.compile(r'\*([^\*]+)\*')
|
||||
CODEFINDER = re.compile(r'\`([^\`]+)\`')
|
||||
|
||||
# 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'
|
||||
print(app.config)
|
||||
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]+".md")
|
||||
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]+".md.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(".md"):
|
||||
if row[:-3] not in existing:
|
||||
non_existing.append(row[:-3])
|
||||
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)
|
||||
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)
|
||||
|
||||
@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]+".md")
|
||||
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 "[ ]" in row:
|
||||
icon=u" "
|
||||
extra_class=""
|
||||
if "[x]" in row:
|
||||
icon=u"\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+".md")
|
||||
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("[ ] %s\n"%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+".md")
|
||||
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+".md")
|
||||
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)
|
||||
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+".md")
|
||||
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 '[ ]' in row:
|
||||
contents[i]=row.replace('[ ]','[x]')
|
||||
if '[x]' in row:
|
||||
contents[i]=row.replace('[x]','[ ]')
|
||||
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+".md")
|
||||
backup=data_file+".bkp"
|
||||
contents_file=open(data_file,'rt')
|
||||
contents=[]
|
||||
changed=False
|
||||
for i,row in enumerate(contents_file.read().split("\n")):
|
||||
if '[x]' not in 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, string
|
||||
pattern = re.compile('[\W]+')
|
||||
shopname=pattern.sub('', request.form['shop'])
|
||||
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+".md")
|
||||
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, string
|
||||
pattern = re.compile('[\W]+')
|
||||
username=pattern.sub('', request.form['share'])
|
||||
shopid=pattern.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, string
|
||||
pattern = re.compile('[\W]+')
|
||||
username=pattern.sub('', request.form['user'])
|
||||
shopid=pattern.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+".md")
|
||||
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, string
|
||||
pattern = re.compile('[\W]+')
|
||||
username=pattern.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, string
|
||||
pattern = re.compile('[\W]+')
|
||||
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()
|
||||
Reference in New Issue
Block a user