Compare commits

..

No commits in common. "master" and "j3d1-patch-1" have entirely different histories.

26 changed files with 286 additions and 6588 deletions

2
.gitignore vendored
View file

@ -1,4 +1,5 @@
*.db *.db
socket.io.js
__pycache__/ __pycache__/
logs/* logs/*
venv/* venv/*
@ -10,4 +11,3 @@ flask_session/
/test/flask_session/ /test/flask_session/
/Website/__pycache__/ /Website/__pycache__/
/Website/.pytest_cache/ /Website/.pytest_cache/
/.idea

4
README
View file

@ -5,6 +5,8 @@ How to get started:
source venv/bin/activate source venv/bin/activate
install requiremens: install requiremens:
pip install -r requirements.txt pip install -r requirements.txt
create the log folder:
mkdir logs
start the program: start the program:
venv/bin/gunicorn -b "127.0.0.1:5000" -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 main:app python main.py
You can now accses the Website on http://127.0.0.1:5000 You can now accses the Website on http://127.0.0.1:5000

View file

@ -1,21 +1,27 @@
import queue, time, uuid, json, logging, datetime, os import queue, time, uuid, json, logging, datetime, os
from flask import Flask, render_template, render_template_string, request, make_response, session, send_file, g from flask import Flask, render_template, request, make_response, session, send_file, g
from flask_socketio import SocketIO, join_room, leave_room from flask_socketio import SocketIO, join_room, leave_room
from flask_session import Session from flask_session import Session
from Website.db import get_db from markupsafe import escape
import Website.db as db_handler from .db import get_db
from datetime import datetime from datetime import datetime
finished = None finished = None
preis = -150 #Ein Getraenk
#flask_config #flask_config
DATABASE = './Website/mate.db' DATABASE = './Website/mate.db'
def limit_length(text, length=50): #def create_logs(app):
if type(text) != str: # now = datetime.datetime.now().strftime('%d-%m-%Y-%H-%M-%S')
text = str(text) # logging.basicConfig(filename=f"logs/matekasse-{now}.log",filemode='w', format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ,encoding='utf-8', level=logging.INFO)
if len(text) > length: # app.logger = logging.getLogger('db')
return f"{text[:(length -3)]}..." #
return text # app.logger.info("Website is starting")
def log(type=None, userid=None, before=None, after=None):
db = get_db()
c = db.cursor()
c.execute("INSERT or IGNORE INTO transaction_log (timestamp, userid, type, before, after) VALUES (?, ?, ?, ?, ?)", [datetime.now(), userid, type, before, after])
db.commit()
def create_app(test_config=None): def create_app(test_config=None):
app = Flask(__name__) app = Flask(__name__)
@ -24,15 +30,15 @@ def create_app(test_config=None):
app.config['SESSION_TYPE'] = 'filesystem' app.config['SESSION_TYPE'] = 'filesystem'
app.config['SECRET_KEY'] = key app.config['SECRET_KEY'] = key
app.config['DATABASE'] = DATABASE app.config['DATABASE'] = DATABASE
app.jinja_env.filters['limit_length'] = limit_length
else: else:
app.config.from_mapping(test_config) app.config.from_mapping(test_config)
try: try:
os.makedirs(app.instance_path) os.makedirs(app.instance_path)
except OSError: except OSError:
pass pass
#with app.app_context():
# create_logs(app)
Session(app) Session(app)
socketio = SocketIO(app) socketio = SocketIO(app)
@ -42,32 +48,32 @@ def create_app(test_config=None):
# db = getattr(g, '_database', None) # db = getattr(g, '_database', None)
# if db is not None: # if db is not None:
# db.close() # db.close()
# appt.logger.info("Website exited") # app.logger.info("Website exited")
#var #var
user_queue = queue.Queue() user_queue = queue.Queue()
#website #website
@app.route('/favicon.ico') @app.route('/favicon.ico')
@app.route('/ccc_logo.png')
def favicon(): def favicon():
return send_file("../static/Logo_CCC.svg.png") return send_file("../static/Logo_CCC.svg.png")
@app.route('/socket.io.js') #@app.route('/socket.io.js')
def socketiojs(): #def socketiojs():
return send_file('../static/socket.io.js') # return url_for('static', filename='socket.io.js')
@app.route('/ka-ching.wav')
def kaching():
return send_file('../static/ka-ching.wav')
@app.route('/new.css')
def newcss():
return send_file('../static/new.min.css')
@app.route("/") @app.route("/")
def index(): def index():
return render_template("index.html") return """
<a href="/list">user and tag list</a>
<p>The creator of this website accepts no liability for any linguistic or technical errors!</p>
<br style="line-height: 500%;"></br>
<a href="/documentation">Doumentation</a><script src="/socket.io.js" integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA==" crossorigin="anonymous">
</script>
<script type="text/javascript" charset="utf-8">
window.location="/list"
</script>
"""
@app.route("/list") @app.route("/list")
def list(): def list():
@ -75,57 +81,35 @@ def create_app(test_config=None):
c = db.cursor() c = db.cursor()
c.execute("SELECT * FROM users") c.execute("SELECT * FROM users")
users = c.fetchall() users = c.fetchall()
return render_template("list.html", users=users, preis=(preis/100), min_value=-50000) text = ""
for i in users:
text = text + f'<p><a href="list/user?id={i[0]}">{escape(i[1])}</a>: {i[2]/100}€ <form action="/change" method="post"><input name="id" type="hidden" value="{i[0]}"> <input name="change" type="number" step="0.1" placeholder="add to balance"></form></p> <br style="line-height: 50%;"></br>'
return '''<!DOCTYPE html>
<html lang="en">
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js" integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA==" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8">
var socket = io();
socket.on("update", function(){
window.location="http://matekasse.server.c3h/list"
});
</script>
<title>Strichliste</title>
<p><a href="/list">user and tag list</a> | <a href="/documentation">Documentation</a></p>
<form action="/list/user" method="get"><input name="user" type="search" placeholder="Search for user"><button>Search</button></form>
<form action="/adduser" method="post"><button type="submit">Add User</button></form>
<br></br>
''' + text + '</html>'
@app.route("/transactionlist") @app.route("/transactionlist")
def transactionlist(): def transactionlist():
db = get_db() db = get_db()
c = db.cursor() c = db.cursor()
action_list = [] text = ""
c.execute("SELECT * FROM transaction_log ORDER BY ROWID DESC LIMIT 1000") c.execute("SELECT * FROM transaction_log ORDER BY ROWID DESC LIMIT 100")
transactionlist = c.fetchall() transactionlist = c.fetchall()
for i in transactionlist: for i in transactionlist:
action = { text = text + f"<p>{i[0]} userid: {i[1]} {i[2]} {i[3]} to {i[4]}</p>"
"statement":i[0], return text
"user_id":i[1],
"before":i[2],
"after":i[3],
"change":i[4]
}
if action["statement"] == "balance":
action["reverse_statement"] = "balance"
action["reverse_user_id"] = action["user_id"]
action["reverse_before"] = None
action["reverse_after"] = None
action["reverse_change"] = action["change"] *(-1)
elif action["statement"] == "add_user":
action["reverse_statement"] = "remove_user"
action["reverse_user_id"] = action["user_id"]
action["reverse_before"] = action["after"]
action["reverse_after"] = None
action["reverse_change"] = None
elif action["statement"] == "remove_user":
action["reverse_statement"] = "add_user"
action["reverse_user_id"] = action["user_id"]
action["reverse_before"] = None
action["reverse_after"] = action["before"]
action["reverse_change"] = None
elif action["statement"] == "add_tag":
action["reverse_statement"] = "remove_tag"
action["reverse_user_id"] = action["user_id"]
action["reverse_before"] = action["after"]
action["reverse_after"] = None
action["reverse_change"] = None
elif action["statement"] == "remove_tag":
action["reverse_statement"] = "add_tag"
action["reverse_user_id"] = action["user_id"]
action["reverse_before"] = None
action["reverse_after"] = action["before"]
action["reverse_change"] = None
else:
raise Exception(statement)
action_list.append(action)
return render_template("transactionlist.html", action_list=action_list)
@app.route("/list/user", methods=['GET']) @app.route("/list/user", methods=['GET'])
def user_info(): def user_info():
@ -133,12 +117,35 @@ def create_app(test_config=None):
c = db.cursor() c = db.cursor()
id = request.args.get("id") id = request.args.get("id")
c.execute(f"SELECT * FROM users WHERE id=?", [id]) c.execute(f"SELECT * FROM users WHERE id=?", [id])
user = c.fetchone() user_list = c.fetchall()
if user != None : if user_list != []:
user = user_list[0]
c.execute(f"SELECT * FROM tags WHERE userid={user[0]}") c.execute(f"SELECT * FROM tags WHERE userid={user[0]}")
tags = c.fetchall() tags = c.fetchall()
return render_template("user.html", user=user, tags=tags, min_value=-50000) text = ""
for tag in tags:
text = text + f'<p><form action="/removetag" method="post"><label for="removetag">{tag[0]} </label><input name="id" type="hidden" value="{user[0]}"><input name="tagid" type="hidden" value="{tag[0]}"><button id="removetag" type="submit">Remove Tag</button></form> </p>'
return f"""<!DOCTYPE html>
<html lang="en">
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js" integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA==" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8">
var socket = io();
""" + 'socket.on("update", function(){ window.location="http://matekasse.server.c3h/list/user?id=' + id + '"});' + f"""
</script>
<title>{escape(user[1])}</title>
<p><a href="/list">user and tag list</a> | <a href="/documentation">Documentation</a></p>
<p> {escape(user[1])} : {escape(user[2]/100)} <p>
<form action="/addtag" method="post"><input name="id" type="hidden" value="{user[0]}"><button type="submit">Add Tag</button></form>
<form action="/removetag" method="post"><input name="id" type="hidden" value="{user[0]}"><button type="submit">Remove Tag</button></form>
</p><form action="/change" method="post"><input name="id" type="hidden" value="{user[0]}"> <input name="change" type="number" step="0.1" placeholder="change balance"></form>
</p>
<br></br>
<p>Tags:</p>
{text}
<br></br>
<form action="/removeuser" method="post"><input name="id" type="hidden" value="{user[0]}"><button type="submit">Remove User</button></form>
</html>
"""
else: else:
return render_template("error.html", error_code="043") return render_template("error.html", error_code="043")
@ -152,12 +159,16 @@ def create_app(test_config=None):
c = db.cursor() c = db.cursor()
user_id = request.form["id"] user_id = request.form["id"]
c.execute(f"SELECT * FROM users WHERE id=?", [user_id]) c.execute(f"SELECT * FROM users WHERE id=?", [user_id])
user = c.fetchone() users = c.fetchall()
if user != None: if users != []:
user_name = user[1] user_name = users[0][1]
db_handler.remove_user(user_id) c.execute(f"DELETE FROM tags WHERE userid=?", [user_id])
app.logger.info(f"Deleted all tags from user ?", [user_id])
c.execute(f"DELETE FROM users WHERE id=?", [user_id])
db.commit()
log(type="removeuser", userid=user_id, before=user_name)
socketio.emit("update", "update") socketio.emit("update", "update")
return render_template("removeuser.html", user_name=user_name) return f'<title>remove user</title><p><p><a href="/list">user and tag list</a> | <a href="/documentation">Documentation</a></p> <p>Deleted user {escape(user_name)}</p><a href="/list">return to the tags and user list</a></p>'
else: else:
return render_template("error.html", error_code="043") return render_template("error.html", error_code="043")
@ -170,11 +181,20 @@ def create_app(test_config=None):
return render_template("error.html", error_code="418") return render_template("error.html", error_code="418")
c.execute("SELECT * FROM users WHERE username=?", [username]) c.execute("SELECT * FROM users WHERE username=?", [username])
if c.fetchall() == []: if c.fetchall() == []:
db_handler.add_user(username) c.execute("INSERT or IGNORE INTO users (username, balance) VALUES (?, 0)", [username])
db.commit()
socketio.emit("update", "update") socketio.emit("update", "update")
c.execute(f"SELECT * FROM users WHERE username=?", [username]) c.execute(f"SELECT * FROM users WHERE username=?", [username])
user = c.fetchone() user = c.fetchone()
return render_template("redirect.html") log(type="adduser", userid=user[0], after=user[1])
return """<html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js" integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA==" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8">
window.location="/list";
</script>
<p>tag was sucsesfully added</p>
</html>
"""
else: else:
return render_template("error.html", error_code="757") return render_template("error.html", error_code="757")
@ -185,16 +205,27 @@ def create_app(test_config=None):
c = db.cursor() c = db.cursor()
try: try:
user_id = request.form["id"] user_id = request.form["id"]
change = int(float(request.form["change"]) * float(100)) change = float(request.form["change"])
print(change)
except: except:
return render_template("error.html", error_code="095") return render_template("error.html", error_code="095")
c.execute(f"SELECT * FROM users WHERE id=?", [user_id]) c.execute(f"SELECT * FROM users WHERE id=?", [user_id])
users = c.fetchall() users = c.fetchall()
if users != []: if users != []:
balance_old = users[0][2] balance_old = users[0][2]
db_handler.change_balance(user_id, change) c.execute(f"UPDATE users SET balance = balance + {change*100} WHERE id={user_id}")
db.commit()
c.execute(f"SELECT * FROM users WHERE id={user_id}")
user = c.fetchone()
log(type="balance", userid=user[0], before=balance_old, after=user[2])
socketio.emit("update", "update") socketio.emit("update", "update")
return render_template("redirect.html") return """<html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js" integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA==" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8">
window.location="/list";
</script>
</html>
"""
else: else:
return render_template("error.html", error_code="043") return render_template("error.html", error_code="043")
@ -254,9 +285,17 @@ def create_app(test_config=None):
c = db.cursor() c = db.cursor()
c.execute(f"SELECT * FROM tags WHERE (tagid = ? AND userid = ?)", [tag_id, user_id]) c.execute(f"SELECT * FROM tags WHERE (tagid = ? AND userid = ?)", [tag_id, user_id])
if c.fetchall != []: if c.fetchall != []:
db_handler.remove_tag(tag_id) c.execute(f"DELETE FROM tags WHERE (tagid = ? AND userid = ?)", [tag_id, user_id])
db.commit()
message = f"Removed {tag_id} from user {user_id}" message = f"Removed {tag_id} from user {user_id}"
return render_template("redirect.html") log(type="removetag", userid=user_id, before=tag_id)
return f"""
<html>
<script>
window.location="/"
</script>
</html>
"""
else: else:
return render_template("error.html", error_code="054") return render_template("error.html", error_code="054")
@ -287,37 +326,15 @@ def create_app(test_config=None):
socketio.emit("error", "418", to=session[id]) socketio.emit("error", "418", to=session[id])
leave_room(session[id]) leave_room(session[id])
@app.route("/transfare") #api
def transfare(): @app.route("/api/change", methods=['GET', 'POST'])
db = get_db()
c = db.cursor()
c.execute("SELECT * FROM users")
user_list = c.fetchall()
return render_template("transfare.html", user_list=user_list)
@app.route("/api/transfare", methods=['POST'])
def api_transfare():
db = get_db()
c = db.cursor()
transfare_from = request.form["transfarefrom"]
transfare_to = request.form["transfareto"]
change = int(float(request.form["change"]) * float(100))
c.execute("SELECT * FROM users WHERE id=?", [transfare_from])
if c.fetchall() == []:
return render_template("error.html", error_code="043")
c.execute("SELECT * FROM users WHERE id=?", [transfare_to])
if c.fetchall() == []:
return render_template("error.html", error_code="043")
db_handler.change_balance(transfare_from, -change)
db_handler.change_balance(transfare_to, change)
return render_template("redirect.html")
@app.route("/api/balance", methods=['POST', 'GET'])
def api_change(): def api_change():
if request.method == 'POST':
db = get_db() db = get_db()
c = db.cursor() c = db.cursor()
try:
userid = request.form["id"] userid = request.form["id"]
except:
userid = request.args.get("id")
c.execute("SELECT * FROM users WHERE id=?", [userid]) c.execute("SELECT * FROM users WHERE id=?", [userid])
user_list = c.fetchall() user_list = c.fetchall()
if user_list != []: if user_list != []:
@ -325,37 +342,28 @@ def create_app(test_config=None):
try: try:
change = int(request.args.get("change")) change = int(request.args.get("change"))
except: except:
change = preis change = -1.5
db_handler.change_balance(userid, change) c.execute(f"UPDATE users SET balance = balance + {change*100} WHERE id={user[0]}")
db.commit()
c.execute(f"SELECT * FROM users WHERE id = {userid}")
user_new = c.fetchone()
log(type="balance", userid=user[0], before=user[2], after=user_new[2])
socketio.emit("update", "update") socketio.emit("update", "update")
c.execute("SELECT * FROM users WHERE id=?",[userid]) return make_response(json.dumps({"mode":"balance", "username":user[1], "balance":user_new[2]}))
return make_response(json.dumps({"mode":"balance", "username":user[1], "balance":c.fetchone()[2]}))
else: else:
return make_response(json.dumps({"mode":"error","error":"043"})) return make_response(json.dumps({"mode":"error","error":"043"}))
elif request.method == 'GET':
db = get_db()
c = db.cursor()
userid = request.args.get("id")
c.execute("SELECT * FROM users WHERE id=?", [userid])
user = c.fetchone()
if user != None:
return make_response(json.dumps({"mode":"balance", "username":user[1], "balance":user[2]}))
else:
return make_response(json.dumps({"mode":"error", "error":"043"}))
@app.route("/api/tag_id", methods=['GET', 'POST'])
@app.route("/api/tag_id", methods=['POST'])
def get_id(): def get_id():
db = get_db()
c = db.cursor()
global finished global finished
global message global message
db = get_db()
c = db.cursor()
try: try:
tag_id = request.form["id"] tag_id = request.form["id"]
except: except:
return make_response(json.dumps({"mode":"error", "error":"638"})) tag_id = request.args.get("id")
c.execute(f"SELECT * FROM tags WHERE tagid=?", [tag_id]) c.execute(f"SELECT * FROM tags WHERE tagid=?", [tag_id])
tag_list = c.fetchall() tag_list = c.fetchall()
@ -375,16 +383,20 @@ def create_app(test_config=None):
finished = queue_item finished = queue_item
return make_response(json.dumps({"mode":"error","error":"170"})) return make_response(json.dumps({"mode":"error","error":"170"}))
else: else:
db_handler.add_tag(user_id, tag_id) c.execute(f"INSERT OR IGNORE INTO tags (tagid, userid) VALUES ({tag_id}, ?)", [user_id])
db.commit()
message = f"Added {tag_id} to {username}" message = f"Added {tag_id} to {username}"
log(type="addtag", userid=user_id ,after=tag_id)
finished = queue_item finished = queue_item
return make_response(json.dumps({"mode":"message","username":"{}".format(username),"message":"A tag was added"})) return make_response(json.dumps({"mode":"message","username":"{}".format(username),"message":"A tag was added"}))
elif state == "remove": elif state == "remove":
c.execute(f"SELECT * FROM tags WHERE (tagid = {tag_id} AND userid = ?)", [user_id]) c.execute(f"SELECT * FROM tags WHERE (tagid = {tag_id} AND userid = ?)", [user_id])
tags = c.fetchall() tags = c.fetchall()
if tags != []: if tags != []:
c.execute(f"DELETE FROM tags WHERE (tagid = {tag_id} AND userid = ?)", [user_id])
db.commit() db.commit()
message = f"Removed {tag_id} from {username}" message = f"Removed {tag_id} from {username}"
log(type="removetag", userid=user_id, before=tag_id)
finished = queue_item finished = queue_item
return make_response(json.dumps({"mode":"message","username":"{}".format(username),"message":"A tag was removed"})) return make_response(json.dumps({"mode":"message","username":"{}".format(username),"message":"A tag was removed"}))
else: else:
@ -402,9 +414,11 @@ def create_app(test_config=None):
if user_list != []: if user_list != []:
balance_old = user_list[0][2] balance_old = user_list[0][2]
if user_queue.qsize() == 0: if user_queue.qsize() == 0:
db_handler.change_balance(tag[1], preis) c.execute(f"UPDATE users SET balance = balance - 150 WHERE id={tag[1]}")
db.commit()
c.execute(f"SELECT * FROM users WHERE id={tag[1]}") c.execute(f"SELECT * FROM users WHERE id={tag[1]}")
user = c.fetchone() user = c.fetchone()
log(type="balance", userid=user[0], before=balance_old, after=user[2])
socketio.emit("update", "update") socketio.emit("update", "update")
return make_response(json.dumps({"mode":"balance", "username":user[1], "balance":user[2]/100})) return make_response(json.dumps({"mode":"balance", "username":user[1], "balance":user[2]/100}))
else: else:
@ -412,35 +426,9 @@ def create_app(test_config=None):
socketio.emit("update", "update") socketio.emit("update", "update")
return make_response(json.dumps({"mode":"error","error":"054"})) return make_response(json.dumps({"mode":"error","error":"054"}))
@app.route("/api/change", methods=['POST'])
def reroll():
statement = request.form["statement"]
user_id = request.form["user_id"]
before = request.form["before"]
after = request.form["after"]
change = request.form["change"]
if statement == "add_user":
db_handler.add_user(after)
elif statement == "remove_user":
db_handler.remove_user(user_id)
elif statement == "add_tag":
db_handler.add_tag(user_id, after)
elif statement == "remove_tag":
db_handler.remove_tag(befor)
elif statement == "balance":
db_handler.change_balance(user_id, change)
else:
return make_response(json.dumps({"mode":"error", "error":"418"})) #Error code
socketio.emit("update", "update")
return render_template("index.html")
#Documentation #Documentation
@app.route("/documentation") @app.route("/documentation")
def documentation(): def documentation():
return render_template("documentation.html") return render_template("documentation.html")
return {"app":app,"socketio":socketio} return {"app":app,"socketio":socketio}

View file

@ -1,58 +1,9 @@
from re import M from re import M
from markupsafe import escape
import sqlite3 import sqlite3
from datetime import datetime
import click import click
from flask import current_app, g from flask import current_app, g
def log(statement, user_id=None, before=None, after=None, change=None):
db = get_db()
c = db.cursor()
c.execute("INSERT INTO transaction_log (type, user_id, before, after, change) VALUES (?, ?, ?, ?, ?)", [ statement, user_id, before, after, change])
db.commit()
def add_user(after):
db = get_db()
c = db.cursor()
c.execute("INSERT or IGNORE INTO users (username, balance) VALUES (?, 0)", [after])
user_id = c.lastrowid
log("add_user", user_id=user_id, after=after)
db.commit()
def remove_user(user_id):
db = get_db()
c = db.cursor()
c.execute("SELECT * FROM users WHERE id = ?", [user_id])
user_name = c.fetchone()[1]
c.execute("SELECT * FROM tags WHERE userid = ?", [user_id])
for tag in c.fetchall():
remove_tag(tag[0])
c.execute("DELETE FROM users WHERE id = ?", [user_id])
log("remove_user", user_id=user_id, before=user_name)
db.commit()
def add_tag(user_id, tag_id):
db = get_db()
c = db.cursor()
c.execute("INSERT OR IGNORE INTO tags (tagid, userid) VALUES (?, ?)", [tag_id, user_id])
db.commit()
log("add_tag", after=tag_id, user_id=user_id)
def remove_tag(tag_id):
db = get_db()
c = db.cursor()
c.execute("SELECT * FROM tags WHERE tagid = ?", [tag_id])
user_id = c.fetchone()[1]
c.execute("DELETE FROM tags WHERE tagid = ?", [tag_id])
log("remove_tag", before=tag_id, user_id=user_id)
db.commit()
def change_balance(user_id, change):
db = get_db()
c = db.cursor()
c.execute("UPDATE users SET balance = balance + ? WHERE id=?", [change, user_id])
log("balance", user_id=user_id, change=change)
db.commit()
def get_db(): def get_db():
if 'db' not in g: if 'db' not in g:

14
Website/mate.db.sql.txt Normal file
View file

@ -0,0 +1,14 @@
BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS "users" (
"id" INTEGER NOT NULL,
"username" TEXT NOT NULL,
"balance" INTEGER NOT NULL,
PRIMARY KEY("id")
);
CREATE TABLE IF NOT EXISTS "tags" (
"tagid" INEGER NOT NULL,
"userid" INTEGER,
FOREIGN KEY("userid") REFERENCES "users"("id"),
PRIMARY KEY("tagid")
);
COMMIT;

View file

@ -12,10 +12,10 @@ CREATE TABLE IF NOT EXISTS "tags" (
PRIMARY KEY("tagid") PRIMARY KEY("tagid")
); );
CREATE TABLE IF NOT EXISTS "transaction_log" ( CREATE TABLE IF NOT EXISTS "transaction_log" (
"timestamp" INTEGER NOT NULL,
"userid" INTEGER NOT NULL,
"type" TEXT NOT NULL, "type" TEXT NOT NULL,
"user_id" INTEGER,
"before" TEXT, "before" TEXT,
"after" TEXT, "after" TEXT
"change" INTEGER
); );
COMMIT; COMMIT;

View file

@ -1,6 +1,7 @@
{% extends "base.html" %} <!DOCTYPE html>
{% block customscript %} <html lang="en">
<script type="text/javascript" charset="utf-8"> <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js" integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA==" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8">
var socket = io(); var socket = io();
var user = {{ user }} var user = {{ user }}
socket.on('connect', function() { socket.on('connect', function() {
@ -21,5 +22,5 @@
alert(data) alert(data)
window.location="http://matekasse.server.c3h/" window.location="http://matekasse.server.c3h/"
}); });
</script> </script>
{% endblock %} </html>

View file

@ -1,10 +1,8 @@
{% extends "base.html" %} <!DOCTYPE html>
{% block title %} <html lang="en">
add user <title>add user</title>
{% endblock %} <p><a href="/list">user and tag list</a> | <a href="/documentation">Documentation</a></p>
{% block content %} <p>
<form action="/adduser/user" method="post"><input name="username" type="search" placeholder="Username"> <form action="/adduser/user" method="post"><input name="username" type="search" placeholder="Username"><button>Add user</button></form>
<button>Add user</button> </p>
</form> </html>
</p>
{% endblock %}

View file

@ -1,29 +1,17 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<title>{% block title %}{% endblock %}</title> <title>
<script src="/socket.io.js" {% block title %} {% endblock %} - FlaskApp
integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA==" </title>
crossorigin="anonymous" </head>
></script> <body>
<link rel="stylesheet" href="/new.css"> <nav>
<p><a href="/list">user and tag list</a> | <a href="/documentation">Documentation</a></p>
<link rel="prefetch" href="/ka-ching.wav" /> </nav>
<link rel="shortcut icon" type="Logo/png" href="/ccc_logo.png"/> <hr>
{% block customscript %}{% endblock %} <div class="conntent">
</head>
<body>
<nav>
<p><a href="/">index page</a>
| <a href="/list">user and tag list</a>
| <a href="/documentation">Documentation</a>
| <a href="/transactionlist">transactionlist</a>
| <a href="/transfare">transfare<font face="emoji">🎺⚧</font></a>
</p>
</nav>
<hr>
<div class="conntent">
{% block content %} {% endblock %} {% block content %} {% endblock %}
</div> </div>
</body> </body>
</html> </html>

View file

@ -1,5 +1,6 @@
{% extends "base.html" %} <!DOCTYPE html>
{% block customscript %} <html lang="en">
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js" integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA==" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8"> <script type="text/javascript" charset="utf-8">
var socket = io(); var socket = io();
var change = {{change}} var change = {{change}}
@ -15,11 +16,11 @@
}); });
socket.on("error", function(data) { socket.on("error", function(data) {
alert(data) alert(data)
window.location="/list" window.location="http://matekasse.server.c3h/"
}); });
socket.on("finished", function(data){ socket.on("finished", function(data){
alert(data) alert(data)
window.location="/list" window.location="http://matekasse.server.c3h/"
}); });
</script> </script>
{% endblock %} </html>

View file

@ -1,16 +0,0 @@
{% extends "base.html" %}
{% block customscript %}
<script type="text/javascript" charset="utf-8">
if (confirm("{message}") == true) {
fetch("{{destination}}", {
method: "POST",
body: JSON.stringify({data}),
headers: {
"Content-type": "application/json; charset=UTF-8"
}
})
} else {
window.location = "/list"
}
</script>
{% endblock %}

View file

@ -1,30 +1,32 @@
{% extends "base.html" %} <html>
{% block title %}
Documentation <head>
{% endblock %} <title>Documentation</title>
{% block customscript %} <link rel="stylesheet" type="text/css" href="documentation.css">
<link rel="stylesheet" type="text/css" href="documentation.css"> <link rel="shortcut icon" type="Logo/png" href="ccc_logo.png"/>
{% endblock %} </head>
{% block content %}
<body>
<div id="Infos">
<p> <a href="/">index page</a> | <a href="/list">user and tag list</a></p>
<p><a href="https://hannover.ccc.de/gitlab/anton/matekasse">https://hannover.ccc.de/gitlab/anton/matekasse</a></p>
</div>
<h1 class="header"> <u>Documentation</u> </h1> <h1 class="header"> <u>Documentation</u> </h1>
<p>&nbsp;</p> <p>&nbsp;</p>
<div id="text"> <div id="text">
<h2>API:</h2> <h2>API:</h2>
<p>http://matekasse.server.c3h/api/tag_id</p> <p>http://matekasse.server.c3h/api/tag_id?={tag_id}</p>
<p>Post method {"id":tag_id}</p>
<p>Response: <p>Response:
{"mode":"error" "error":"{error}"} or {"mode":"error" "error":"{error}"} or
{"mode":"message","username":"{username}","message":"{message}"} or {"mode":"message","username":"{username}","message":"{message}"} or
{"mode":"balance", "username":"{username}", "balance":"{balance}"} {"mode":"balance", "username":"{username}", "balance":"{balance}"}
</p> </p>
<br></br> <br></br>
<p>http://matekasse.server.c3h/api/balance</p> <p>http://matekasse.server.c3h/api/change?id={user_id}&?change={change}</p>
<p>Post method {"id":user_id, "change":change}</p>
<p> <p>
If change = None or NaN the change will be -1 If change = None or NaN the change will be -1
</p> </p>
<p>Get method ?id=user_id</p>
<p> <p>
Response: Response:
{"mode":"error" "error":"{error}"} or {"mode":"error" "error":"{error}"} or
@ -38,7 +40,8 @@ Documentation
<p>043: User does not exists</p> <p>043: User does not exists</p>
<p>352: Timeout</p> <p>352: Timeout</p>
<p>095: Input is not a Number</p> <p>095: Input is not a Number</p>
<p>638: Wrong Input</p>
<P>418: I'm a teapot</P> <P>418: I'm a teapot</P>
</div> </div>
{% endblock %} </body>
</html>

View file

@ -1,8 +1,8 @@
{% extends "base.html" %} <!DOCTYPE html>
{% block title %}Error{% endblock %} <html lang="en">
{% block customscript %} <title>Error</title>
<p><a href="/list">user and tag list</a> | <a href="/documentation">Documentation</a></p> <p><a href="/list">user and tag list</a> | <a href="/documentation">Documentation</a></p>
<p> <p>
Error: {{error_code}} Error: {{error_code}}
</p> </p>
{% endblock %} </html>

View file

@ -1,12 +0,0 @@
{% extends "base.html" %}
{% block customscript %}
<script type="text/javascript" charset="utf-8">
window.location="/list"
</script>
{% endblock %}
{% block content %}
<a href="/list">user and tag list</a>
<p>The creator of this website accepts no liability for any linguistic or technical errors!</p>
<br style="line-height: 500%;"></br>
<a href="/documentation">Doumentation</a>
{% endblock %}

View file

@ -1,51 +0,0 @@
{% extends "base.html" %}
{% block title %}
Strichliste
{% endblock %}
{% block customscript %}
<script type="text/javascript" charset="utf-8">
function play() {
return new Promise((resolve, reject) => {
var audio = new Audio('/ka-ching.wav');
audio.play();
audio.addEventListener("ended", function(){
resolve()
});
});
}
async function ka_ching(element) {
await play();
element.parentElement.submit();
}
var socket = io();
socket.on("update", function () {
window.location = "http://matekasse.server.c3h/list"
});
</script>
{% endblock %}
{% block content %}
<form action="/list/user" method="get"><input name="user" type="search" placeholder="Search for user">
<button>Search</button>
</form>
<form action="/adduser" method="post">
<button type="submit">Add User</button>
</form>
<br></br>
{% for user in users %}
<form action="/change" method="post" style="display: inline;">
<p style="display: inline;">
<a href="list/user?id={{user[0]}}">{{user[1]|limit_length}}</a>: {{user[2]/100}}€
</p>
<input name="id" type="hidden" value="{{user[0]}}">
<input name="change" type="number" lang="nb" step="0.01" max={{50000-user[2]/100}} min={{min_value-user[2]/100}} placeholder="add to balance">
</form>
<form action="/change" method="post" style="display: inline">
<input name="id" type="hidden" value="{{user[0]}}">
<input name="change" value={{preis}} type="hidden">
<button onclick="ka_ching(this)" type="button">{{preis}}€</button>
</form>
<br style="line-height: 50%;"></br>
{% endfor %}
{% endblock %}

View file

@ -1,12 +0,0 @@
{% extends "base.html" %}
{% block title %}
{% endblock %}
{% block content %}
<p>redirekting</p>
<a href="/list">destination</a>
{% endblock %}
{% block customscript %}
<script type="text/javascript" charset="utf-8">
window.location = "/list";
</script>
{% endblock %}

View file

@ -1,6 +1,7 @@
{% extends "base.html" %} <!DOCTYPE html>
{% block customscript %} <html lang="en">
<script type="text/javascript" charset="utf-8"> <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js" integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA==" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8">
var socket = io(); var socket = io();
var user = {{ user }} var user = {{ user }}
socket.on('connect', function() { socket.on('connect', function() {
@ -22,4 +23,4 @@
window.location="http://matekasse.server.c3h/" window.location="http://matekasse.server.c3h/"
}); });
</script> </script>
{% endblock %} </html>

View file

@ -1,10 +0,0 @@
{% extends "base.html" %}
{% block title %}
remove user
{% endblock %}
{% block content %}
<p>
<p>Deleted user {{user_name|safe}}</p>
<a href="/list">return to the tags and user list</a>
</p>
{% endblock %}

View file

@ -1,17 +0,0 @@
{% extends "base.html" %}
{% block title %}
Transactionlist
{% endblock %}
{% block content %}
{% for action in action_list%}
<form action="/api/change" method="post">
<p style="display: inline;">{{action["statement"]}} userid:{{action["user_id"]}} {{action["before"]|limit_length}} {{action["after"]|limit_length}} {{action["change"]}}</p>
<input type="hidden" name="statement" value={{action["reverse_statement"]}}>
<input type="hidden" name="user_id" value={{action["reverse_user_id"]}}>
<input type="hidden" name="before" value={{action["reverse_before"]}}>
<input type="hidden" name="after" value={{action["reverse_after"]}}>
<input type="hidden" name="change" value={{action["reverse_change"]}}>
<button type="submit">rollback</button></form><br></br>
{% endfor %}
{% endblock %}

View file

@ -1,34 +0,0 @@
{% extends "base.html" %}
{% block title %}
transfare
{% endblock %}
{% block content %}
<form action="/api/transfare" method="post">
<p>
<select name="transfarefrom">
<option value="">Select the user to transfare from</option>
{% for user in user_list %}
<option value={{user[0]}}>{{user[1]}}</option>
{% endfor %}
</select>
</p>
<p>
<select name="transfareto">
<option value="">Select the user to transfare to</option>
{% for user in user_list %}
<option value={{user[0]}}>{{user[1]}}</option>
{% endfor %}
</select>
</p>
<p>
<input name="change" type="number" lang="nb" step="0.01" max=1000 min=-1000 placeholder="money to transfare">
</p>
<p>
<button type="submit">transfare money</button>
</p>
</form>
{% endblock %}

View file

@ -1,45 +0,0 @@
{% extends "base.html" %}
{% block customscript %}
<script type="text/javascript" charset="utf-8">
var socket = io();
socket.on("update", function () {
window.location = "/list/user?id={{user[0]}}"
});
</script>
{% endblock %}
{% block title %}
{{user[1]}}
{% endblock %}
{% block content %}
<p> {{user[1]}} : {{user[2]/100}}€ <p>
<form action="/addtag" method="post">
<input name="id" type="hidden" value="{{user[0]}}">
<button type="submit">Add Tag</button>
</form>
<form action="/removetag" method="post">
<input name="id" type="hidden" value="{{user[0]}}">
<button type="submit">Remove Tag</button>
</form>
</p>
<form action="/change" method="post">
<input name="id" type="hidden" value="{{user[0]}}">
<input name="change" type="number" lang="nb" step="0.01" max={{50000-user[2]/100}} min={{min_value-user[2]/100}} placeholder="add to balance">
</form>
</p>
<br></br>
<p>Tags:</p>
{% for tag in tags %}
<p>
<form action="/removetag" method="post">
<label for="removetag">{{tag[0]}} </label>
<input name="id" type="hidden" value="{{user[0]}}">
<input name="tagid" type="hidden" value="{{tag[0]}}">
<button id="removetag" type="submit">Remove Tag</button>
</form>
</p>
{% endfor %}
<br></br>
<form action="/removeuser" method="post"><input name="id" type="hidden" value="{{user[0]}}">
<button type="submit">Remove User</button>
</form>
{% endblock %}

View file

@ -10,6 +10,8 @@ def exit_handler():
sys.exit("Program sucsesfully exited") sys.exit("Program sucsesfully exited")
def main(): def main():
app_data = create_app()
app = app_data["app"]
socketio = app_data["socketio"] socketio = app_data["socketio"]
atexit.register(exit_handler) atexit.register(exit_handler)
socketio.run(app, host='0.0.0.0', port=5000) socketio.run(app, host='0.0.0.0', port=5000)

Binary file not shown.

8
static/new.min.css vendored
View file

@ -1,8 +0,0 @@
/**
* Minified by jsDelivr using clean-css v4.2.1.
* Original file: /npm/@exampledev/new.css@1.1.2/new.css
*
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
*/
:root{--nc-font-sans:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--nc-font-mono:Consolas,monaco,'Ubuntu Mono','Liberation Mono','Courier New',Courier,monospace;--nc-tx-1:#000000;--nc-tx-2:#1A1A1A;--nc-bg-1:#FFFFFF;--nc-bg-2:#F6F8FA;--nc-bg-3:#E5E7EB;--nc-lk-1:#0070F3;--nc-lk-2:#0366D6;--nc-lk-tx:#FFFFFF;--nc-ac-1:#79FFE1;--nc-ac-tx:#0C4047}@media (prefers-color-scheme:dark){:root{--nc-tx-1:#ffffff;--nc-tx-2:#eeeeee;--nc-bg-1:#000000;--nc-bg-2:#111111;--nc-bg-3:#222222;--nc-lk-1:#3291FF;--nc-lk-2:#0070F3;--nc-lk-tx:#FFFFFF;--nc-ac-1:#7928CA;--nc-ac-tx:#FFFFFF}}*{margin:0;padding:0}address,area,article,aside,audio,blockquote,datalist,details,dl,fieldset,figure,form,iframe,img,input,meter,nav,ol,optgroup,option,output,p,pre,progress,ruby,section,table,textarea,ul,video{margin-bottom:1rem}button,html,input,select{font-family:var(--nc-font-sans)}body{margin:0 auto;max-width:750px;padding:2rem;border-radius:6px;overflow-x:hidden;word-break:break-word;overflow-wrap:break-word;background:var(--nc-bg-1);color:var(--nc-tx-2);font-size:1.03rem;line-height:1.5}::selection{background:var(--nc-ac-1);color:var(--nc-ac-tx)}h1,h2,h3,h4,h5,h6{line-height:1;color:var(--nc-tx-1);padding-top:.875rem}h1,h2,h3{color:var(--nc-tx-1);padding-bottom:2px;margin-bottom:8px;border-bottom:1px solid var(--nc-bg-2)}h4,h5,h6{margin-bottom:.3rem}h1{font-size:2.25rem}h2{font-size:1.85rem}h3{font-size:1.55rem}h4{font-size:1.25rem}h5{font-size:1rem}h6{font-size:.875rem}a{color:var(--nc-lk-1)}a:hover{color:var(--nc-lk-2)}abbr:hover{cursor:help}blockquote{padding:1.5rem;background:var(--nc-bg-2);border-left:5px solid var(--nc-bg-3)}abbr{cursor:help}blockquote :last-child{padding-bottom:0;margin-bottom:0}header{background:var(--nc-bg-2);border-bottom:1px solid var(--nc-bg-3);padding:2rem 1.5rem;margin:-2rem calc(0px - (50vw - 50%)) 2rem;padding-left:calc(50vw - 50%);padding-right:calc(50vw - 50%)}header h1,header h2,header h3{padding-bottom:0;border-bottom:0}header>:first-child{margin-top:0;padding-top:0}header>:last-child{margin-bottom:0}a button,button,input[type=button],input[type=reset],input[type=submit]{font-size:1rem;display:inline-block;padding:6px 12px;text-align:center;text-decoration:none;white-space:nowrap;background:var(--nc-lk-1);color:var(--nc-lk-tx);border:0;border-radius:4px;box-sizing:border-box;cursor:pointer;color:var(--nc-lk-tx)}a button[disabled],button[disabled],input[type=button][disabled],input[type=reset][disabled],input[type=submit][disabled]{cursor:default;opacity:.5;cursor:not-allowed}.button:focus,.button:hover,button:focus,button:hover,input[type=button]:focus,input[type=button]:hover,input[type=reset]:focus,input[type=reset]:hover,input[type=submit]:focus,input[type=submit]:hover{background:var(--nc-lk-2)}code,kbd,pre,samp{font-family:var(--nc-font-mono)}code,kbd,pre,samp{background:var(--nc-bg-2);border:1px solid var(--nc-bg-3);border-radius:4px;padding:3px 6px;font-size:.9rem}kbd{border-bottom:3px solid var(--nc-bg-3)}pre{padding:1rem 1.4rem;max-width:100%;overflow:auto}pre code{background:inherit;font-size:inherit;color:inherit;border:0;padding:0;margin:0}code pre{display:inline;background:inherit;font-size:inherit;color:inherit;border:0;padding:0;margin:0}details{padding:.6rem 1rem;background:var(--nc-bg-2);border:1px solid var(--nc-bg-3);border-radius:4px}summary{cursor:pointer;font-weight:700}details[open]{padding-bottom:.75rem}details[open] summary{margin-bottom:6px}details[open]>:last-child{margin-bottom:0}dt{font-weight:700}dd::before{content:'→ '}hr{border:0;border-bottom:1px solid var(--nc-bg-3);margin:1rem auto}fieldset{margin-top:1rem;padding:2rem;border:1px solid var(--nc-bg-3);border-radius:4px}legend{padding:auto .5rem}table{border-collapse:collapse;width:100%}td,th{border:1px solid var(--nc-bg-3);text-align:left;padding:.5rem}th{background:var(--nc-bg-2)}tr:nth-child(even){background:var(--nc-bg-2)}table caption{font-weight:700;margin-bottom:.5rem}textarea{max-width:100%}ol,ul{padding-left:2rem}li{margin-top:.4rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}mark{padding:3px 6px;background:var(--nc-ac-1);color:var(--nc-ac-tx)}input,select,textarea{padding:6px 12px;margin-bottom:.5rem;background:var(--nc-bg-2);color:var(--nc-tx-2);border:1px solid var(--nc-bg-3);border-radius:4px;box-shadow:none;box-sizing:border-box}img{max-width:100%}
/*# sourceMappingURL=/sm/4a51164882967d28a74fabce02685c18fa45a529b77514edc75d708f04dd08b9.map */

File diff suppressed because it is too large Load diff

View file

@ -23,14 +23,14 @@ def test_index(client):
#/adduser #/adduser
def test_adduser(client): def test_adduser(client):
response = client.post('/adduser/user', data={}) response = client.get('/adduser/user')
assert "418" in response.data.decode('utf-8') assert "418" in response.data.decode('utf-8')
def test_adduser_new(app, client): def test_adduser_new(app, client):
with app.app_context(): with app.app_context():
db = get_db() db = get_db()
assert db is get_db() assert db is get_db()
response = client.post('/adduser/user', data={user_name:"test"}) response = client.get('/adduser/user?username=test')
c = db.cursor() c = db.cursor()
c.execute("SELECT * FROM users WHERE username = ?", ["test"]) c.execute("SELECT * FROM users WHERE username = ?", ["test"])
data = c.fetchone() data = c.fetchone()
@ -40,7 +40,7 @@ def test_adduser_new(app, client):
assert data[2] == 0 assert data[2] == 0
def test_adduser_allreadyexists(client): def test_adduser_allreadyexists(client):
response = client.post('/adduser/user', data={username:"test"}) response = client.get('/adduser/user?username=test')
assert "Error: 757" in response.data.decode('utf-8') assert "Error: 757" in response.data.decode('utf-8')
#/addtag #/addtag
@ -49,7 +49,7 @@ def test_addtag(client):
assert response.data.decode('utf-8') == "Error: 095" assert response.data.decode('utf-8') == "Error: 095"
def test_addtag_userid_nan(client): def test_addtag_userid_nan(client):
response = client.post('/addtag', data={id:1}) response = client.get('/addtag?id=test')
assert response.data.decode('utf-8') == "Error: 095" assert response.data.decode('utf-8') == "Error: 095"
def test_add_tag_direktli(app): def test_add_tag_direktli(app):