forked from Dniel97/artemis
frontend: add management pages
This commit is contained in:
parent
b943807904
commit
6c89a97fe3
200
core/frontend.py
200
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'
|
||||
@ -241,8 +285,103 @@ class FE_User(FE_Base):
|
||||
|
||||
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")
|
4
core/frontend/arcade/index.jinja
Normal file
4
core/frontend/arcade/index.jinja
Normal file
@ -0,0 +1,4 @@
|
||||
{% extends "core/frontend/index.jinja" %}
|
||||
{% block content %}
|
||||
<h1>{{ arcade.name }}</h1>
|
||||
{% endblock content %}
|
5
core/frontend/machine/index.jinja
Normal file
5
core/frontend/machine/index.jinja
Normal file
@ -0,0 +1,5 @@
|
||||
{% extends "core/frontend/index.jinja" %}
|
||||
{% block content %}
|
||||
{% include "core/frontend/widgets/err_banner.jinja" %}
|
||||
<h1>Machine Management</h1>
|
||||
{% endblock content %}
|
98
core/frontend/sys/index.jinja
Normal file
98
core/frontend/sys/index.jinja
Normal file
@ -0,0 +1,98 @@
|
||||
{% extends "core/frontend/index.jinja" %}
|
||||
{% block content %}
|
||||
<h1>System Management</h1>
|
||||
|
||||
<div class="row" id="rowForm">
|
||||
{% if sesh.permissions >= 2 %}
|
||||
<div class="col-sm-6" style="max-width: 25%;">
|
||||
<form id="usrLookup" name="usrLookup" action="/sys/lookup.user" class="form-inline">
|
||||
<h3>User Search</h3>
|
||||
<div class="form-group">
|
||||
<label for="usrEmail">Email address</label>
|
||||
<input type="email" class="form-control" id="usrEmail" name="usrEmail" aria-describedby="emailHelp">
|
||||
</div>
|
||||
OR
|
||||
<div class="form-group">
|
||||
<label for="usrName">Username</label>
|
||||
<input type="text" class="form-control" id="usrName" name="usrName">
|
||||
</div>
|
||||
OR
|
||||
<div class="form-group">
|
||||
<label for="usrId">User ID</label>
|
||||
<input type="number" class="form-control" id="usrId" name="usrId">
|
||||
</div>
|
||||
<br />
|
||||
<button type="submit" class="btn btn-primary">Search</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if sesh.permissions >= 4 %}
|
||||
<div class="col-sm-6" style="max-width: 25%;">
|
||||
<form id="arcadeLookup" name="arcadeLookup" action="/sys/lookup.arcade" class="form-inline" >
|
||||
<h3>Arcade Search</h3>
|
||||
<div class="form-group">
|
||||
<label for="arcadeName">Arcade Name</label>
|
||||
<input type="text" class="form-control" id="arcadeName" name="arcadeName">
|
||||
</div>
|
||||
OR
|
||||
<div class="form-group">
|
||||
<label for="arcadeId">Arcade ID</label>
|
||||
<input type="number" class="form-control" id="arcadeId" name="arcadeId">
|
||||
</div>
|
||||
OR
|
||||
<div class="form-group">
|
||||
<label for="arcadeUser">Owner User ID</label>
|
||||
<input type="number" class="form-control" id="arcadeUser" name="arcadeUser">
|
||||
</div>
|
||||
<br />
|
||||
<button type="submit" class="btn btn-primary">Search</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-sm-6" style="max-width: 25%;">
|
||||
<form id="cabLookup" name="cabLookup" action="/sys/lookup.cab" class="form-inline" >
|
||||
<h3>Machine Search</h3>
|
||||
<div class="form-group">
|
||||
<label for="cabSerial">Machine Serial</label>
|
||||
<input type="text" class="form-control" id="cabSerial" name="cabSerial">
|
||||
</div>
|
||||
OR
|
||||
<div class="form-group">
|
||||
<label for="cabId">Machine ID</label>
|
||||
<input type="number" class="form-control" id="cabId" name="cabId">
|
||||
</div>
|
||||
OR
|
||||
<div class="form-group">
|
||||
<label for="cabAcId">Arcade ID</label>
|
||||
<input type="number" class="form-control" id="cabAcId" name="cabAcId">
|
||||
</div>
|
||||
<br />
|
||||
<button type="submit" class="btn btn-primary">Search</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="row" id="rowResult" style="margin: 10px;">
|
||||
{% if sesh.permissions >= 2 %}
|
||||
<div id="userSearchResult" class="col-sm-6" style="max-width: 25%;">
|
||||
{% for usr in usrlist %}
|
||||
<pre><a href=/user/{{ usr.id }}>{{ usr.id }} | {{ usr.username }}</a></pre>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if sesh.permissions >= 4 %}
|
||||
<div id="arcadeSearchResult" class="col-sm-6" style="max-width: 25%;">
|
||||
{% for ac in aclist %}
|
||||
<pre><a href=/arcade/{{ ac.id }}>{{ ac.id }} | {{ ac.name }}</a></pre>
|
||||
{% endfor %}
|
||||
</div
|
||||
><div id="cabSearchResult" class="col-sm-6" style="max-width: 25%;">
|
||||
{% for cab in cablist %}
|
||||
<a href=/cab/{{ cab.id }}><pre>{{ cab.id }} | {{ cab.game if cab.game is defined else "ANY " }} | {{ cab.serial }}</pre></a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="row" id="rowAdd">
|
||||
|
||||
</div>
|
||||
{% endblock content %}
|
@ -2,11 +2,21 @@
|
||||
{% block content %}
|
||||
<h1>Management for {{ username }}</h1>
|
||||
<h2>Cards <button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#card_add">Add</button></h2>
|
||||
<ul>
|
||||
<ul style="font-size: 20px;">
|
||||
{% for c in cards %}
|
||||
<li>{{ c.access_code }}: {{ c.status }} <button class="btn-danger btn">Delete</button></li>
|
||||
<li>{{ c.access_code }}: {{ c.status }} {% if c.status == 'Active'%}<button class="btn-warning btn">Lock</button>{% elif c.status == 'Locked' %}<button class="btn-warning btn">Unlock</button>{% endif %} <button class="btn-danger btn">Delete</button></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% if arcades is defined %}
|
||||
<h2>Arcades</h2>
|
||||
<ul style="font-size: 20px;">
|
||||
{% for a in arcades %}
|
||||
<li><a href=/arcade/{{ a.id }}>{{ a.name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
<div class="modal fade" id="card_add" tabindex="-1" aria-labelledby="card_add_label" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
|
@ -7,6 +7,10 @@ Card not registered, or wrong password
|
||||
Missing or malformed access code
|
||||
{% elif error == 3 %}
|
||||
Failed to create user
|
||||
{% elif error == 4 %}
|
||||
Arcade not found
|
||||
{% elif error == 5 %}
|
||||
Machine not found
|
||||
{% else %}
|
||||
An unknown error occoured
|
||||
{% endif %}
|
||||
|
@ -9,6 +9,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div style="background: #333; color: #f9f9f9; width: 10%; height: 50px; line-height: 50px; text-align: center; float: left;">
|
||||
{% if sesh is defined and sesh["permissions"] >= 2 %}
|
||||
<a href="/sys"><button class="btn btn-primary">System</button></a>
|
||||
{% endif %}
|
||||
{% if sesh is defined and sesh["userId"] > 0 %}
|
||||
<a href="/user"><button class="btn btn-primary">Account</button></a>
|
||||
{% else %}
|
||||
|
Loading…
Reference in New Issue
Block a user