forked from Hay1tsme/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
|
from twisted.python.components import registerAdapter
|
||||||
import jinja2
|
import jinja2
|
||||||
import bcrypt
|
import bcrypt
|
||||||
|
import re
|
||||||
|
from enum import Enum
|
||||||
|
from urllib import parse
|
||||||
|
|
||||||
from core import CoreConfig, Utils
|
from core import CoreConfig, Utils
|
||||||
from core.data import Data
|
from core.data import Data
|
||||||
@ -19,6 +22,13 @@ class IUserSession(Interface):
|
|||||||
current_ip = Attribute("User's current ip address")
|
current_ip = Attribute("User's current ip address")
|
||||||
permissions = Attribute("User's permission level")
|
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)
|
@implementer(IUserSession)
|
||||||
class UserSession(object):
|
class UserSession(object):
|
||||||
@ -80,6 +90,9 @@ class FrontendServlet(resource.Resource):
|
|||||||
self.environment.globals["game_list"] = self.game_list
|
self.environment.globals["game_list"] = self.game_list
|
||||||
self.putChild(b"gate", FE_Gate(cfg, self.environment))
|
self.putChild(b"gate", FE_Gate(cfg, self.environment))
|
||||||
self.putChild(b"user", FE_User(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.putChild(b"game", fe_game)
|
||||||
|
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
@ -154,6 +167,7 @@ class FE_Gate(FE_Base):
|
|||||||
passwd = None
|
passwd = None
|
||||||
|
|
||||||
uid = self.data.card.get_user_id_from_card(access_code)
|
uid = self.data.card.get_user_id_from_card(access_code)
|
||||||
|
user = self.data.user.get_user(uid)
|
||||||
if uid is None:
|
if uid is None:
|
||||||
return redirectTo(b"/gate?e=1", request)
|
return redirectTo(b"/gate?e=1", request)
|
||||||
|
|
||||||
@ -175,6 +189,7 @@ class FE_Gate(FE_Base):
|
|||||||
usr_sesh = IUserSession(sesh)
|
usr_sesh = IUserSession(sesh)
|
||||||
usr_sesh.userId = uid
|
usr_sesh.userId = uid
|
||||||
usr_sesh.current_ip = ip
|
usr_sesh.current_ip = ip
|
||||||
|
usr_sesh.permissions = user['permissions']
|
||||||
|
|
||||||
return redirectTo(b"/user", request)
|
return redirectTo(b"/user", request)
|
||||||
|
|
||||||
@ -192,7 +207,7 @@ class FE_Gate(FE_Base):
|
|||||||
hashed = bcrypt.hashpw(passwd, salt)
|
hashed = bcrypt.hashpw(passwd, salt)
|
||||||
|
|
||||||
result = self.data.user.create_user(
|
result = self.data.user.create_user(
|
||||||
uid, username, email, hashed.decode(), 1
|
uid, username, email.lower(), hashed.decode(), 1
|
||||||
)
|
)
|
||||||
if result is None:
|
if result is None:
|
||||||
return redirectTo(b"/gate?e=3", request)
|
return redirectTo(b"/gate?e=3", request)
|
||||||
@ -210,17 +225,29 @@ class FE_Gate(FE_Base):
|
|||||||
return redirectTo(b"/gate?e=2", request)
|
return redirectTo(b"/gate?e=2", request)
|
||||||
|
|
||||||
ac = request.args[b"ac"][0].decode()
|
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")
|
template = self.environment.get_template("core/frontend/gate/create.jinja")
|
||||||
return template.render(
|
return template.render(
|
||||||
title=f"{self.core_config.server.name} | Create User",
|
title=f"{self.core_config.server.name} | Create User",
|
||||||
code=ac,
|
code=ac,
|
||||||
sesh={"userId": 0},
|
sesh={"userId": 0, "permissions": 0},
|
||||||
).encode("utf-16")
|
).encode("utf-16")
|
||||||
|
|
||||||
|
|
||||||
class FE_User(FE_Base):
|
class FE_User(FE_Base):
|
||||||
def render_GET(self, request: Request):
|
def render_GET(self, request: Request):
|
||||||
|
uri = request.uri.decode()
|
||||||
template = self.environment.get_template("core/frontend/user/index.jinja")
|
template = self.environment.get_template("core/frontend/user/index.jinja")
|
||||||
|
|
||||||
sesh: Session = request.getSession()
|
sesh: Session = request.getSession()
|
||||||
@ -228,9 +255,26 @@ class FE_User(FE_Base):
|
|||||||
if usr_sesh.userId == 0:
|
if usr_sesh.userId == 0:
|
||||||
return redirectTo(b"/gate", request)
|
return redirectTo(b"/gate", request)
|
||||||
|
|
||||||
cards = self.data.card.get_user_cards(usr_sesh.userId)
|
m = re.match("\/user\/(\d*)", uri)
|
||||||
user = self.data.user.get_user(usr_sesh.userId)
|
|
||||||
|
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 = []
|
card_data = []
|
||||||
|
arcade_data = []
|
||||||
|
|
||||||
for c in cards:
|
for c in cards:
|
||||||
if c['is_locked']:
|
if c['is_locked']:
|
||||||
status = 'Locked'
|
status = 'Locked'
|
||||||
@ -240,9 +284,104 @@ class FE_User(FE_Base):
|
|||||||
status = 'Active'
|
status = 'Active'
|
||||||
|
|
||||||
card_data.append({'access_code': c['access_code'], 'status': status})
|
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(
|
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")
|
).encode("utf-16")
|
||||||
|
|
||||||
|
|
||||||
@ -257,3 +396,54 @@ class FE_Game(FE_Base):
|
|||||||
|
|
||||||
def render_GET(self, request: Request) -> bytes:
|
def render_GET(self, request: Request) -> bytes:
|
||||||
return redirectTo(b"/user", request)
|
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 %}
|
{% block content %}
|
||||||
<h1>Management for {{ username }}</h1>
|
<h1>Management for {{ username }}</h1>
|
||||||
<h2>Cards <button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#card_add">Add</button></h2>
|
<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 %}
|
{% 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 %}
|
{% endfor %}
|
||||||
</ul>
|
</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 fade" id="card_add" tabindex="-1" aria-labelledby="card_add_label" aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
|
@ -7,6 +7,10 @@ Card not registered, or wrong password
|
|||||||
Missing or malformed access code
|
Missing or malformed access code
|
||||||
{% elif error == 3 %}
|
{% elif error == 3 %}
|
||||||
Failed to create user
|
Failed to create user
|
||||||
|
{% elif error == 4 %}
|
||||||
|
Arcade not found
|
||||||
|
{% elif error == 5 %}
|
||||||
|
Machine not found
|
||||||
{% else %}
|
{% else %}
|
||||||
An unknown error occoured
|
An unknown error occoured
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -9,6 +9,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="background: #333; color: #f9f9f9; width: 10%; height: 50px; line-height: 50px; text-align: center; float: left;">
|
<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 %}
|
{% if sesh is defined and sesh["userId"] > 0 %}
|
||||||
<a href="/user"><button class="btn btn-primary">Account</button></a>
|
<a href="/user"><button class="btn btn-primary">Account</button></a>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
Loading…
Reference in New Issue
Block a user