From 6c89a97fe34f28920996c3d13414d28db36dfcb5 Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Sun, 23 Jul 2023 22:21:49 -0400 Subject: [PATCH] frontend: add management pages --- core/frontend.py | 200 ++++++++++++++++++++++++- core/frontend/arcade/index.jinja | 4 + core/frontend/machine/index.jinja | 5 + core/frontend/sys/index.jinja | 98 ++++++++++++ core/frontend/user/index.jinja | 14 +- core/frontend/widgets/err_banner.jinja | 4 + core/frontend/widgets/topbar.jinja | 3 + 7 files changed, 321 insertions(+), 7 deletions(-) create mode 100644 core/frontend/arcade/index.jinja create mode 100644 core/frontend/machine/index.jinja create mode 100644 core/frontend/sys/index.jinja diff --git a/core/frontend.py b/core/frontend.py index f01be50..a79bd94 100644 --- a/core/frontend.py +++ b/core/frontend.py @@ -9,6 +9,9 @@ from zope.interface import Interface, Attribute, implementer from twisted.python.components import registerAdapter import jinja2 import bcrypt +import re +from enum import Enum +from urllib import parse from core import CoreConfig, Utils from core.data import Data @@ -19,6 +22,13 @@ class IUserSession(Interface): current_ip = Attribute("User's current ip address") permissions = Attribute("User's permission level") +class PermissionOffset(Enum): + USER = 0 # Regular user + USERMOD = 1 # Can moderate other users + ACMOD = 2 # Can add arcades and cabs + SYSADMIN = 3 # Can change settings + # 4 - 6 reserved for future use + OWNER = 7 # Can do anything @implementer(IUserSession) class UserSession(object): @@ -80,6 +90,9 @@ class FrontendServlet(resource.Resource): self.environment.globals["game_list"] = self.game_list self.putChild(b"gate", FE_Gate(cfg, self.environment)) self.putChild(b"user", FE_User(cfg, self.environment)) + self.putChild(b"sys", FE_System(cfg, self.environment)) + self.putChild(b"arcade", FE_Arcade(cfg, self.environment)) + self.putChild(b"cab", FE_Machine(cfg, self.environment)) self.putChild(b"game", fe_game) self.logger.info( @@ -154,6 +167,7 @@ class FE_Gate(FE_Base): passwd = None uid = self.data.card.get_user_id_from_card(access_code) + user = self.data.user.get_user(uid) if uid is None: return redirectTo(b"/gate?e=1", request) @@ -175,6 +189,7 @@ class FE_Gate(FE_Base): usr_sesh = IUserSession(sesh) usr_sesh.userId = uid usr_sesh.current_ip = ip + usr_sesh.permissions = user['permissions'] return redirectTo(b"/user", request) @@ -192,7 +207,7 @@ class FE_Gate(FE_Base): hashed = bcrypt.hashpw(passwd, salt) result = self.data.user.create_user( - uid, username, email, hashed.decode(), 1 + uid, username, email.lower(), hashed.decode(), 1 ) if result is None: return redirectTo(b"/gate?e=3", request) @@ -210,17 +225,29 @@ class FE_Gate(FE_Base): return redirectTo(b"/gate?e=2", request) ac = request.args[b"ac"][0].decode() + card = self.data.card.get_card_by_access_code(ac) + if card is None: + return redirectTo(b"/gate?e=1", request) + + user = self.data.user.get_user(card['user']) + if user is None: + self.logger.warn(f"Card {ac} exists with no/invalid associated user ID {card['user']}") + return redirectTo(b"/gate?e=0", request) + + if user['password'] is not None: + return redirectTo(b"/gate?e=1", request) template = self.environment.get_template("core/frontend/gate/create.jinja") return template.render( title=f"{self.core_config.server.name} | Create User", code=ac, - sesh={"userId": 0}, + sesh={"userId": 0, "permissions": 0}, ).encode("utf-16") class FE_User(FE_Base): def render_GET(self, request: Request): + uri = request.uri.decode() template = self.environment.get_template("core/frontend/user/index.jinja") sesh: Session = request.getSession() @@ -228,9 +255,26 @@ class FE_User(FE_Base): if usr_sesh.userId == 0: return redirectTo(b"/gate", request) - cards = self.data.card.get_user_cards(usr_sesh.userId) - user = self.data.user.get_user(usr_sesh.userId) + m = re.match("\/user\/(\d*)", uri) + + if m is not None: + usrid = m.group(1) + if usr_sesh.permissions < 1 << PermissionOffset.USERMOD.value or not usrid == usr_sesh.userId: + return redirectTo(b"/user", request) + + else: + usrid = usr_sesh.userId + + user = self.data.user.get_user(usrid) + if user is None: + return redirectTo(b"/user", request) + + cards = self.data.card.get_user_cards(usrid) + arcades = self.data.arcade.get_arcades_managed_by_user(usrid) + card_data = [] + arcade_data = [] + for c in cards: if c['is_locked']: status = 'Locked' @@ -240,9 +284,104 @@ class FE_User(FE_Base): status = 'Active' card_data.append({'access_code': c['access_code'], 'status': status}) + + for a in arcades: + arcade_data.append({'id': a['id'], 'name': a['name']}) return template.render( - title=f"{self.core_config.server.name} | Account", sesh=vars(usr_sesh), cards=card_data, username=user['username'] + title=f"{self.core_config.server.name} | Account", + sesh=vars(usr_sesh), + cards=card_data, + username=user['username'], + arcades=arcade_data + ).encode("utf-16") + + def render_POST(self, request: Request): + pass + + +class FE_System(FE_Base): + def render_GET(self, request: Request): + uri = request.uri.decode() + template = self.environment.get_template("core/frontend/sys/index.jinja") + usrlist = [] + aclist = [] + cablist = [] + + sesh: Session = request.getSession() + usr_sesh = IUserSession(sesh) + if usr_sesh.userId == 0 or usr_sesh.permissions < 1 << PermissionOffset.USERMOD.value: + return redirectTo(b"/gate", request) + + if uri.startswith("/sys/lookup.user?"): + uri_parse = parse.parse_qs(uri.replace("/sys/lookup.user?", "")) # lop off the first bit + uid_search = uri_parse.get("usrId") + email_search = uri_parse.get("usrEmail") + uname_search = uri_parse.get("usrName") + + if uid_search is not None: + u = self.data.user.get_user(uid_search[0]) + if u is not None: + usrlist.append(u._asdict()) + + elif email_search is not None: + u = self.data.user.find_user_by_email(email_search[0]) + if u is not None: + usrlist.append(u._asdict()) + + elif uname_search is not None: + ul = self.data.user.find_user_by_username(uname_search[0]) + for u in ul: + usrlist.append(u._asdict()) + + elif uri.startswith("/sys/lookup.arcade?"): + uri_parse = parse.parse_qs(uri.replace("/sys/lookup.arcade?", "")) # lop off the first bit + ac_id_search = uri_parse.get("arcadeId") + ac_name_search = uri_parse.get("arcadeName") + ac_user_search = uri_parse.get("arcadeUser") + + if ac_id_search is not None: + u = self.data.arcade.get_arcade(ac_id_search[0]) + if u is not None: + aclist.append(u._asdict()) + + elif ac_name_search is not None: + ul = self.data.arcade.find_arcade_by_name(ac_name_search[0]) + for u in ul: + aclist.append(u._asdict()) + + elif ac_user_search is not None: + ul = self.data.arcade.get_arcades_managed_by_user(ac_user_search[0]) + for u in ul: + aclist.append(u._asdict()) + + elif uri.startswith("/sys/lookup.cab?"): + uri_parse = parse.parse_qs(uri.replace("/sys/lookup.cab?", "")) # lop off the first bit + cab_id_search = uri_parse.get("cabId") + cab_serial_search = uri_parse.get("cabSerial") + cab_acid_search = uri_parse.get("cabAcId") + + if cab_id_search is not None: + u = self.data.arcade.get_machine(id=cab_id_search[0]) + if u is not None: + cablist.append(u._asdict()) + + elif cab_serial_search is not None: + u = self.data.arcade.get_machine(serial=cab_serial_search[0]) + if u is not None: + cablist.append(u._asdict()) + + elif cab_acid_search is not None: + ul = self.data.arcade.get_arcade_machines(cab_acid_search[0]) + for u in ul: + cablist.append(u._asdict()) + + return template.render( + title=f"{self.core_config.server.name} | System", + sesh=vars(usr_sesh), + usrlist=usrlist, + aclist=aclist, + cablist=cablist, ).encode("utf-16") @@ -257,3 +396,54 @@ class FE_Game(FE_Base): def render_GET(self, request: Request) -> bytes: return redirectTo(b"/user", request) + + +class FE_Arcade(FE_Base): + def render_GET(self, request: Request): + uri = request.uri.decode() + template = self.environment.get_template("core/frontend/arcade/index.jinja") + managed = [] + + sesh: Session = request.getSession() + usr_sesh = IUserSession(sesh) + if usr_sesh.userId == 0: + return redirectTo(b"/gate", request) + + m = re.match("\/arcade\/(\d*)", uri) + + if m is not None: + arcadeid = m.group(1) + perms = self.data.arcade.get_manager_permissions(usr_sesh.userId, arcadeid) + arcade = self.data.arcade.get_arcade(arcadeid) + + if perms is None: + perms = 0 + + else: + return redirectTo(b"/user", request) + + return template.render( + title=f"{self.core_config.server.name} | Arcade", + sesh=vars(usr_sesh), + error=0, + perms=perms, + arcade=arcade._asdict() + ).encode("utf-16") + + +class FE_Machine(FE_Base): + def render_GET(self, request: Request): + uri = request.uri.decode() + template = self.environment.get_template("core/frontend/machine/index.jinja") + + sesh: Session = request.getSession() + usr_sesh = IUserSession(sesh) + if usr_sesh.userId == 0: + return redirectTo(b"/gate", request) + + return template.render( + title=f"{self.core_config.server.name} | Machine", + sesh=vars(usr_sesh), + arcade={}, + error=0, + ).encode("utf-16") \ No newline at end of file diff --git a/core/frontend/arcade/index.jinja b/core/frontend/arcade/index.jinja new file mode 100644 index 0000000..20a1f46 --- /dev/null +++ b/core/frontend/arcade/index.jinja @@ -0,0 +1,4 @@ +{% extends "core/frontend/index.jinja" %} +{% block content %} +

{{ arcade.name }}

+{% endblock content %} \ No newline at end of file diff --git a/core/frontend/machine/index.jinja b/core/frontend/machine/index.jinja new file mode 100644 index 0000000..01e90a0 --- /dev/null +++ b/core/frontend/machine/index.jinja @@ -0,0 +1,5 @@ +{% extends "core/frontend/index.jinja" %} +{% block content %} +{% include "core/frontend/widgets/err_banner.jinja" %} +

Machine Management

+{% endblock content %} \ No newline at end of file diff --git a/core/frontend/sys/index.jinja b/core/frontend/sys/index.jinja new file mode 100644 index 0000000..2da821e --- /dev/null +++ b/core/frontend/sys/index.jinja @@ -0,0 +1,98 @@ +{% extends "core/frontend/index.jinja" %} +{% block content %} +

System Management

+ +
+ {% if sesh.permissions >= 2 %} +
+
+

User Search

+
+ + +
+ OR +
+ + +
+ OR +
+ + +
+
+ +
+
+ {% endif %} + {% if sesh.permissions >= 4 %} +
+
+

Arcade Search

+
+ + +
+ OR +
+ + +
+ OR +
+ + +
+
+ +
+
+
+
+

Machine Search

+
+ + +
+ OR +
+ + +
+ OR +
+ + +
+
+ +
+
+ {% endif %} +
+
+ {% if sesh.permissions >= 2 %} +
+ {% for usr in usrlist %} +
{{ usr.id }} | {{ usr.username }}
+ {% endfor %} +
+ {% endif %} + {% if sesh.permissions >= 4 %} +
+ {% for ac in aclist %} +
{{ ac.id }} | {{ ac.name }}
+ {% endfor %} +
+ {% endif %} +
+
+ +
+{% endblock content %} \ No newline at end of file diff --git a/core/frontend/user/index.jinja b/core/frontend/user/index.jinja index 2911e67..2f76b14 100644 --- a/core/frontend/user/index.jinja +++ b/core/frontend/user/index.jinja @@ -2,11 +2,21 @@ {% block content %}

Management for {{ username }}

Cards

-