frontend: arcade management rework
parent
20d9a2da9c
commit
b6d22ef41d
|
@ -45,6 +45,14 @@ class AllnetCountryCode(Enum):
|
|||
SOUTH_KOREA = "KOR"
|
||||
TAIWAN = "TWN"
|
||||
CHINA = "CHN"
|
||||
AUSTRALIA = "AUS"
|
||||
INDONESIA = "IDN"
|
||||
MYANMAR = "MMR"
|
||||
MALAYSIA = "MYS"
|
||||
NEW_ZEALAND = "NZL"
|
||||
PHILIPPINES = "PHL"
|
||||
THAILAND = "THA"
|
||||
VIETNAM = "VNM"
|
||||
|
||||
|
||||
class AllnetJapanRegionId(Enum):
|
||||
|
|
|
@ -115,6 +115,15 @@ class ArcadeData(BaseData):
|
|||
return None
|
||||
return result.lastrowid
|
||||
|
||||
async def set_machine_arcade(self, machine_id: int, new_arcade: int) -> bool:
|
||||
sql = machine.update(machine.c.id == machine_id).values(arcade = new_arcade)
|
||||
|
||||
result = await self.execute(sql)
|
||||
if result is None:
|
||||
self.logger.error(f"Failed to update machine {machine_id} arcade to {new_arcade}")
|
||||
return False
|
||||
return True
|
||||
|
||||
async def set_machine_serial(self, machine_id: int, serial: str) -> None:
|
||||
result = await self.execute(
|
||||
machine.update(machine.c.id == machine_id).values(keychip=serial)
|
||||
|
@ -134,6 +143,60 @@ class ArcadeData(BaseData):
|
|||
f"Failed to update board id for machine {machine_id} -> {boardid}"
|
||||
)
|
||||
|
||||
async def set_machine_game(self, machine_id: int, new_game: Optional[str]) -> bool:
|
||||
sql = machine.update(machine.c.id == machine_id).values(game = new_game)
|
||||
|
||||
result = await self.execute(sql)
|
||||
if result is None:
|
||||
self.logger.error(f"Failed to update machine {machine_id} game to {new_game}")
|
||||
return False
|
||||
return True
|
||||
|
||||
async def set_machine_country(self, machine_id: int, new_country: Optional[str]) -> bool:
|
||||
sql = machine.update(machine.c.id == machine_id).values(country = new_country)
|
||||
|
||||
result = await self.execute(sql)
|
||||
if result is None:
|
||||
self.logger.error(f"Failed to update machine {machine_id} country to {new_country}")
|
||||
return False
|
||||
return True
|
||||
|
||||
async def set_machine_timezone(self, machine_id: int, new_timezone: Optional[str]) -> bool:
|
||||
sql = machine.update(machine.c.id == machine_id).values(timezone = new_timezone)
|
||||
|
||||
result = await self.execute(sql)
|
||||
if result is None:
|
||||
self.logger.error(f"Failed to update machine {machine_id} timezone to {new_timezone}")
|
||||
return False
|
||||
return True
|
||||
|
||||
async def set_machine_real_cabinet(self, machine_id: int, is_real: bool = False) -> bool:
|
||||
sql = machine.update(machine.c.id == machine_id).values(is_cab = is_real)
|
||||
|
||||
result = await self.execute(sql)
|
||||
if result is None:
|
||||
self.logger.error(f"Failed to update machine {machine_id} is_cab to {is_real}")
|
||||
return False
|
||||
return True
|
||||
|
||||
async def set_machine_can_ota(self, machine_id: int, can_ota: bool = False) -> bool:
|
||||
sql = machine.update(machine.c.id == machine_id).values(ota_enable = can_ota)
|
||||
|
||||
result = await self.execute(sql)
|
||||
if result is None:
|
||||
self.logger.error(f"Failed to update machine {machine_id} ota_enable to {can_ota}")
|
||||
return False
|
||||
return True
|
||||
|
||||
async def set_machine_memo(self, machine_id: int, new_memo: Optional[str]) -> bool:
|
||||
sql = machine.update(machine.c.id == machine_id).values(memo = new_memo)
|
||||
|
||||
result = await self.execute(sql)
|
||||
if result is None:
|
||||
self.logger.error(f"Failed to update machine {machine_id} memo")
|
||||
return False
|
||||
return True
|
||||
|
||||
async def get_arcade(self, id: int) -> Optional[Row]:
|
||||
sql = arcade.select(arcade.c.id == id)
|
||||
result = await self.execute(sql)
|
||||
|
@ -187,8 +250,11 @@ class ArcadeData(BaseData):
|
|||
sql = select(arcade_owner.c.permissions).where(and_(arcade_owner.c.user == user_id, arcade_owner.c.arcade == arcade_id))
|
||||
result = await self.execute(sql)
|
||||
if result is None:
|
||||
return False
|
||||
return result.fetchone()
|
||||
return None
|
||||
row = result.fetchone()
|
||||
if row:
|
||||
return row['permissions']
|
||||
return None
|
||||
|
||||
async def get_arcade_owners(self, arcade_id: int) -> Optional[Row]:
|
||||
sql = select(arcade_owner).where(arcade_owner.c.arcade == arcade_id)
|
||||
|
@ -198,7 +264,7 @@ class ArcadeData(BaseData):
|
|||
return None
|
||||
return result.fetchall()
|
||||
|
||||
async def add_arcade_owner(self, arcade_id: int, user_id: int) -> None:
|
||||
async def add_arcade_owner(self, arcade_id: int, user_id: int, permissions: int = 1) -> Optional[int]:
|
||||
sql = insert(arcade_owner).values(arcade=arcade_id, user=user_id)
|
||||
|
||||
result = await self.execute(sql)
|
||||
|
@ -206,6 +272,17 @@ class ArcadeData(BaseData):
|
|||
return None
|
||||
return result.lastrowid
|
||||
|
||||
async def set_arcade_owner_permissions(self, arcade_id: int, user_id: int, new_permissions: int = 1) -> bool:
|
||||
sql = arcade_owner.update(
|
||||
and_(arcade_owner.c.arcade == arcade_id, arcade_owner.c.user == user_id)
|
||||
).values(permissions = new_permissions)
|
||||
|
||||
result = await self.execute(sql)
|
||||
if result is None:
|
||||
self.logger.error(f"Failed to update arcade owner permissions to {new_permissions} for user {user_id} arcade {arcade_id}")
|
||||
return False
|
||||
return True
|
||||
|
||||
async def get_arcade_by_name(self, name: str) -> Optional[List[Row]]:
|
||||
sql = arcade.select(or_(arcade.c.name.like(f"%{name}%"), arcade.c.nickname.like(f"%{name}%")))
|
||||
result = await self.execute(sql)
|
||||
|
@ -219,7 +296,49 @@ class ArcadeData(BaseData):
|
|||
if result is None:
|
||||
return None
|
||||
return result.fetchall()
|
||||
|
||||
|
||||
async def set_arcade_name_nickname(self, arcade_id: int, new_name: Optional[str], new_nickname: Optional[str]) -> bool:
|
||||
sql = arcade.update(arcade.c.id == arcade_id).values(name = new_name, nickname = new_nickname)
|
||||
|
||||
result = await self.execute(sql)
|
||||
if result is None:
|
||||
self.logger.error(f"Failed to update arcade {arcade_id} name to {new_name}/{new_nickname}")
|
||||
return False
|
||||
return True
|
||||
|
||||
async def set_arcade_region_info(self, arcade_id: int, new_country: Optional[str], new_state: Optional[str], new_city: Optional[str], new_region_id: Optional[int], new_country_id: Optional[int]) -> bool:
|
||||
sql = arcade.update(arcade.c.id == arcade_id).values(
|
||||
country = new_country,
|
||||
state = new_state,
|
||||
city = new_city,
|
||||
region_id = new_region_id,
|
||||
country_id = new_country_id
|
||||
)
|
||||
|
||||
result = await self.execute(sql)
|
||||
if result is None:
|
||||
self.logger.error(f"Failed to update arcade {arcade_id} regional info to {new_country}/{new_state}/{new_city}/{new_region_id}/{new_country_id}")
|
||||
return False
|
||||
return True
|
||||
|
||||
async def set_arcade_timezone(self, arcade_id: int, new_timezone: Optional[str]) -> bool:
|
||||
sql = arcade.update(arcade.c.id == arcade_id).values(timezone = new_timezone)
|
||||
|
||||
result = await self.execute(sql)
|
||||
if result is None:
|
||||
self.logger.error(f"Failed to update arcade {arcade_id} timezone to {new_timezone}")
|
||||
return False
|
||||
return True
|
||||
|
||||
async def set_arcade_vpn_ip(self, arcade_id: int, new_ip: Optional[str]) -> bool:
|
||||
sql = arcade.update(arcade.c.id == arcade_id).values(ip = new_ip)
|
||||
|
||||
result = await self.execute(sql)
|
||||
if result is None:
|
||||
self.logger.error(f"Failed to update arcade {arcade_id} VPN address to {new_ip}")
|
||||
return False
|
||||
return True
|
||||
|
||||
async def get_num_generated_keychips(self) -> Optional[int]:
|
||||
result = await self.execute(select(func.count("serial LIKE 'A69A%'")).select_from(machine))
|
||||
if result:
|
||||
|
|
241
core/frontend.py
241
core/frontend.py
|
@ -12,7 +12,6 @@ import jwt
|
|||
import yaml
|
||||
import secrets
|
||||
import string
|
||||
import random
|
||||
from base64 import b64decode
|
||||
from enum import Enum
|
||||
from datetime import datetime, timezone
|
||||
|
@ -20,6 +19,7 @@ from os import path, environ, mkdir, W_OK, access
|
|||
|
||||
from core import CoreConfig, Utils
|
||||
from core.data import Data
|
||||
from core.const import AllnetCountryCode
|
||||
|
||||
# A-HJ-NP-Z
|
||||
SERIAL_LETTERS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
|
||||
|
@ -37,8 +37,7 @@ class ShopPermissionOffset(Enum):
|
|||
VIEW = 0 # View info and cabs
|
||||
BOOKKEEP = 1 # View bookeeping info
|
||||
EDITOR = 2 # Can edit name, settings
|
||||
REGISTRAR = 3 # Can add cabs
|
||||
# 4 - 6 reserved for future use
|
||||
# 3 - 6 reserved for future use
|
||||
OWNER = 7 # Can do anything
|
||||
|
||||
class ShopOwner():
|
||||
|
@ -149,10 +148,13 @@ class FrontendServlet():
|
|||
Mount("/shop", routes=[
|
||||
Route("/", self.arcade.render_GET, methods=['GET']),
|
||||
Route("/{shop_id:int}", self.arcade.render_GET, methods=['GET']),
|
||||
Route("/{shop_id:int}/info.update", self.arcade.update_shop, methods=['POST']),
|
||||
]),
|
||||
Mount("/cab", routes=[
|
||||
Route("/", self.machine.render_GET, methods=['GET']),
|
||||
Route("/{machine_id:int}", self.machine.render_GET, methods=['GET']),
|
||||
Route("/{machine_id:int}/info.update", self.machine.update_cab, methods=['POST']),
|
||||
Route("/{machine_id:int}/reassign", self.machine.reassign_cab, methods=['POST']),
|
||||
]),
|
||||
Mount("/game", routes=g_routes),
|
||||
Route("/robots.txt", self.robots)
|
||||
|
@ -455,6 +457,16 @@ class FE_User(FE_Base):
|
|||
card_data = []
|
||||
arcade_data = []
|
||||
|
||||
managed_arcades = await self.data.arcade.get_arcades_managed_by_user(user_id)
|
||||
if managed_arcades:
|
||||
for arcade in managed_arcades:
|
||||
ac = await self.data.arcade.get_arcade(arcade['id'])
|
||||
if ac:
|
||||
arcade_data.append({
|
||||
"id": ac['id'],
|
||||
"name": ac['name'],
|
||||
})
|
||||
|
||||
for c in cards:
|
||||
if c['is_locked']:
|
||||
status = 'Locked'
|
||||
|
@ -861,14 +873,16 @@ class FE_System(FE_Base):
|
|||
name = frm.get("shopName", None)
|
||||
country = frm.get("shopCountry", "JPN")
|
||||
ip = frm.get("shopIp", None)
|
||||
owner = frm.get("shopOwner", None)
|
||||
|
||||
acid = await self.data.arcade.create_arcade(name if name else None, name if name else None, country)
|
||||
if not acid:
|
||||
return RedirectResponse("/sys/?e=99", 303)
|
||||
|
||||
if ip:
|
||||
# TODO: set IP
|
||||
pass
|
||||
await self.data.arcade.set_arcade_vpn_ip(acid, ip if ip else None)
|
||||
|
||||
if owner:
|
||||
await self.data.arcade.add_arcade_owner(acid, int(owner), 255)
|
||||
|
||||
return Response(template.render(
|
||||
title=f"{self.core_config.server.name} | System",
|
||||
|
@ -947,15 +961,20 @@ class FE_Arcade(FE_Base):
|
|||
shop_id = request.path_params.get('shop_id', None)
|
||||
|
||||
usr_sesh = self.validate_session(request)
|
||||
if not usr_sesh or not self.test_perm(usr_sesh.permissions, PermissionOffset.ACMOD):
|
||||
self.logger.warning(f"User {usr_sesh.user_id} does not have permission to view shops!")
|
||||
if not usr_sesh:
|
||||
return RedirectResponse("/gate/", 303)
|
||||
|
||||
|
||||
if not shop_id:
|
||||
return Response(template.render(
|
||||
title=f"{self.core_config.server.name} | Arcade",
|
||||
sesh=vars(usr_sesh),
|
||||
), media_type="text/html; charset=utf-8")
|
||||
return Response('Not Found', status_code=404)
|
||||
|
||||
is_acmod = self.test_perm(usr_sesh.permissions, PermissionOffset.ACMOD)
|
||||
if not is_acmod:
|
||||
usr_shop_perm = await self.data.arcade.get_manager_permissions(usr_sesh.user_id, shop_id)
|
||||
if usr_shop_perm is None or usr_shop_perm == 0:
|
||||
self.logger.warning(f"User {usr_sesh.user_id} does not have permission to view shop {shop_id}!")
|
||||
return RedirectResponse("/", 303)
|
||||
else:
|
||||
usr_shop_perm = 15 # view, bookeep, edit
|
||||
|
||||
sinfo = await self.data.arcade.get_arcade(shop_id)
|
||||
if not sinfo:
|
||||
|
@ -974,38 +993,204 @@ class FE_Arcade(FE_Base):
|
|||
"game": x['game'],
|
||||
})
|
||||
|
||||
managers = []
|
||||
if (usr_shop_perm & 1 << ShopPermissionOffset.OWNER.value) or is_acmod:
|
||||
mgrs = await self.data.arcade.get_arcade_owners(sinfo['id'])
|
||||
if mgrs:
|
||||
for mgr in mgrs:
|
||||
usr = await self.data.user.get_user(mgr['user'])
|
||||
managers.append({
|
||||
'user': mgr['user'],
|
||||
'name': usr['username'] if usr['username'] else 'No Name Set',
|
||||
'is_view': bool(mgr['permissions'] & 1 << ShopPermissionOffset.VIEW.value),
|
||||
'is_bookkeep': bool(mgr['permissions'] & 1 << ShopPermissionOffset.BOOKKEEP.value),
|
||||
'is_edit': bool(mgr['permissions'] & 1 << ShopPermissionOffset.EDITOR.value),
|
||||
'is_owner': bool(mgr['permissions'] & 1 << ShopPermissionOffset.OWNER.value),
|
||||
})
|
||||
|
||||
if request.query_params.get("e", None):
|
||||
err = int(request.query_params.get("e"))
|
||||
else:
|
||||
err = 0
|
||||
|
||||
if request.query_params.get("s", None):
|
||||
suc = int(request.query_params.get("s"))
|
||||
else:
|
||||
suc = 0
|
||||
|
||||
return Response(template.render(
|
||||
title=f"{self.core_config.server.name} | Arcade",
|
||||
sesh=vars(usr_sesh),
|
||||
arcade={
|
||||
"name": sinfo['name'],
|
||||
"id": sinfo['id'],
|
||||
"cabs": cablst
|
||||
}
|
||||
|
||||
cablst=cablst,
|
||||
arcade=sinfo._asdict(),
|
||||
can_bookkeep=bool(usr_shop_perm & 1 << ShopPermissionOffset.BOOKKEEP.value) or is_acmod,
|
||||
can_edit=bool(usr_shop_perm & 1 << ShopPermissionOffset.EDITOR.value) or is_acmod,
|
||||
is_owner=usr_shop_perm & 1 << ShopPermissionOffset.OWNER.value,
|
||||
is_acmod=is_acmod,
|
||||
managers=managers,
|
||||
error=err,
|
||||
success=suc
|
||||
), media_type="text/html; charset=utf-8")
|
||||
|
||||
async def update_shop(self, request: Request):
|
||||
shop_id = request.path_params.get('shop_id', None)
|
||||
usr_sesh = self.validate_session(request)
|
||||
if not usr_sesh:
|
||||
return RedirectResponse("/gate/", 303)
|
||||
|
||||
sinfo = await self.data.arcade.get_arcade(shop_id)
|
||||
|
||||
if not shop_id or not sinfo:
|
||||
return RedirectResponse("/", 303)
|
||||
|
||||
if not self.test_perm(usr_sesh.permissions, PermissionOffset.ACMOD):
|
||||
usr_shop_perm = await self.data.arcade.get_manager_permissions(usr_sesh.user_id, sinfo['id'])
|
||||
if usr_shop_perm is None or usr_shop_perm == 0:
|
||||
self.logger.warning(f"User {usr_sesh.user_id} does not have permission to view shop {sinfo['id']}!")
|
||||
return RedirectResponse("/", 303)
|
||||
|
||||
frm = await request.form()
|
||||
new_name = frm.get('name', None)
|
||||
new_nickname = frm.get('nickname', None)
|
||||
new_country = frm.get('country', None)
|
||||
new_region1 = frm.get('region1', None)
|
||||
new_region2 = frm.get('region2', None)
|
||||
new_tz = frm.get('tz', None)
|
||||
new_ip = frm.get('ip', None)
|
||||
|
||||
try:
|
||||
AllnetCountryCode(new_country)
|
||||
except ValueError:
|
||||
new_country = 'JPN'
|
||||
|
||||
did_name = await self.data.arcade.set_arcade_name_nickname(sinfo['id'], new_name if new_name else f'Arcade{sinfo["id"]}', new_nickname if new_nickname else None)
|
||||
did_region = await self.data.arcade.set_arcade_region_info(sinfo['id'], new_country, new_region1 if new_region1 else None, new_region2 if new_region2 else None, None, None)
|
||||
did_timezone = await self.data.arcade.set_arcade_timezone(sinfo['id'], new_tz if new_tz else None)
|
||||
did_vpn = await self.data.arcade.set_arcade_vpn_ip(sinfo['id'], new_ip if new_ip else None)
|
||||
|
||||
if not did_name or not did_region or not did_timezone or not did_vpn:
|
||||
self.logger.error(f"Failed to update some shop into: Name: {did_name} Region: {did_region} TZ: {did_timezone} VPN: {did_vpn}")
|
||||
return RedirectResponse(f"/shop/{shop_id}?e=15", 303)
|
||||
|
||||
return RedirectResponse(f"/shop/{shop_id}?s=1", 303)
|
||||
|
||||
class FE_Machine(FE_Base):
|
||||
async def render_GET(self, request: Request):
|
||||
template = self.environment.get_template("core/templates/machine/index.jinja")
|
||||
cab_id = request.path_params.get('cab_id', None)
|
||||
cab_id = request.path_params.get('machine_id', None)
|
||||
|
||||
usr_sesh = self.validate_session(request)
|
||||
if not usr_sesh or not self.test_perm(usr_sesh.permissions, PermissionOffset.ACMOD):
|
||||
self.logger.warning(f"User {usr_sesh.user_id} does not have permission to view shops!")
|
||||
if not usr_sesh:
|
||||
return RedirectResponse("/gate/", 303)
|
||||
|
||||
cab = await self.data.arcade.get_machine(id=cab_id)
|
||||
|
||||
if not cab_id:
|
||||
return Response(template.render(
|
||||
title=f"{self.core_config.server.name} | Machine",
|
||||
sesh=vars(usr_sesh),
|
||||
), media_type="text/html; charset=utf-8")
|
||||
if not cab_id or not cab:
|
||||
return Response('Not Found', status_code=404)
|
||||
|
||||
shop = await self.data.arcade.get_arcade(cab['arcade'])
|
||||
|
||||
is_acmod = self.test_perm(usr_sesh.permissions, PermissionOffset.ACMOD)
|
||||
if not is_acmod:
|
||||
usr_shop_perm = await self.data.arcade.get_manager_permissions(usr_sesh.user_id, shop['id'])
|
||||
if usr_shop_perm is None or usr_shop_perm == 0:
|
||||
self.logger.warning(f"User {usr_sesh.user_id} does not have permission to view shop {shop['id']}!")
|
||||
return RedirectResponse("/", 303)
|
||||
else:
|
||||
usr_shop_perm = 15 # view, bookeep, edit
|
||||
|
||||
if request.query_params.get("e", None):
|
||||
err = int(request.query_params.get("e"))
|
||||
else:
|
||||
err = 0
|
||||
|
||||
if request.query_params.get("s", None):
|
||||
suc = int(request.query_params.get("s"))
|
||||
else:
|
||||
suc = 0
|
||||
|
||||
return Response(template.render(
|
||||
title=f"{self.core_config.server.name} | Machine",
|
||||
sesh=vars(usr_sesh),
|
||||
arcade={}
|
||||
arcade=shop._asdict(),
|
||||
machine=cab._asdict(),
|
||||
can_bookkeep=bool(usr_shop_perm & 1 << ShopPermissionOffset.BOOKKEEP.value) or is_acmod,
|
||||
can_edit=bool(usr_shop_perm & 1 << ShopPermissionOffset.EDITOR.value) or is_acmod,
|
||||
is_owner=usr_shop_perm & 1 << ShopPermissionOffset.OWNER.value,
|
||||
is_acmod=is_acmod,
|
||||
error=err,
|
||||
success=suc
|
||||
), media_type="text/html; charset=utf-8")
|
||||
|
||||
async def update_cab(self, request: Request):
|
||||
cab_id = request.path_params.get('machine_id', None)
|
||||
usr_sesh = self.validate_session(request)
|
||||
if not usr_sesh:
|
||||
return RedirectResponse("/gate/", 303)
|
||||
|
||||
cab = await self.data.arcade.get_machine(id=cab_id)
|
||||
|
||||
if not cab_id or not cab:
|
||||
return RedirectResponse("/", 303)
|
||||
|
||||
if not self.test_perm(usr_sesh.permissions, PermissionOffset.ACMOD):
|
||||
usr_shop_perm = await self.data.arcade.get_manager_permissions(usr_sesh.user_id, cab['arcade'])
|
||||
if usr_shop_perm is None or usr_shop_perm == 0:
|
||||
self.logger.warning(f"User {usr_sesh.user_id} does not have permission to view shop {cab['arcade']}!")
|
||||
return RedirectResponse("/", 303)
|
||||
|
||||
frm = await request.form()
|
||||
new_game = frm.get('game', None)
|
||||
new_country = frm.get('country', None)
|
||||
new_tz = frm.get('tz', None)
|
||||
new_is_cab = frm.get('is_cab', False) == 'on'
|
||||
new_is_ota = frm.get('is_ota', False) == 'on'
|
||||
new_memo = frm.get('memo', None)
|
||||
|
||||
try:
|
||||
AllnetCountryCode(new_country)
|
||||
except ValueError:
|
||||
new_country = None
|
||||
|
||||
did_game = await self.data.arcade.set_machine_game(cab['id'], new_game if new_game else None)
|
||||
did_country = await self.data.arcade.set_machine_country(cab['id'], new_country if new_country else None)
|
||||
did_timezone = await self.data.arcade.set_machine_timezone(cab['id'], new_tz if new_tz else None)
|
||||
did_real_cab = await self.data.arcade.set_machine_real_cabinet(cab['id'], new_is_cab)
|
||||
did_ota = await self.data.arcade.set_machine_can_ota(cab['id'], new_is_ota)
|
||||
did_memo = await self.data.arcade.set_machine_memo(cab['id'], new_memo if new_memo else None)
|
||||
|
||||
if not did_game or not did_country or not did_timezone or not did_real_cab or not did_ota or not did_memo:
|
||||
self.logger.error(f"Failed to update some shop into: Game: {did_game} Country: {did_country} TZ: {did_timezone} Real: {did_real_cab} OTA: {did_ota} Memo: {did_memo}")
|
||||
return RedirectResponse(f"/cab/{cab['id']}?e=15", 303)
|
||||
|
||||
return RedirectResponse(f"/cab/{cab_id}?s=1", 303)
|
||||
|
||||
async def reassign_cab(self, request: Request):
|
||||
cab_id = request.path_params.get('machine_id', None)
|
||||
usr_sesh = self.validate_session(request)
|
||||
if not usr_sesh:
|
||||
return RedirectResponse("/gate/", 303)
|
||||
|
||||
cab = await self.data.arcade.get_machine(id=cab_id)
|
||||
|
||||
if not cab_id or not cab:
|
||||
return RedirectResponse("/", 303)
|
||||
|
||||
frm = await request.form()
|
||||
new_shop = frm.get('new_arcade', None)
|
||||
|
||||
if not self.test_perm(usr_sesh.permissions, PermissionOffset.ACMOD):
|
||||
self.logger.warning(f"User {usr_sesh.user_id} does not have permission to reassign cab {cab['id']} to arcade !")
|
||||
return RedirectResponse(f"/cab/{cab_id}?e=11", 303)
|
||||
|
||||
new_sinfo = await self.data.arcade.get_arcade(new_shop)
|
||||
if not new_sinfo:
|
||||
return RedirectResponse(f"/cab/{cab_id}?e=14", 303)
|
||||
|
||||
if not await self.data.arcade.set_machine_arcade(cab['id'], new_sinfo['id']):
|
||||
return RedirectResponse(f"/cab/{cab_id}?e=99", 303)
|
||||
|
||||
return RedirectResponse(f"/cab/{cab_id}?s=2", 303)
|
||||
|
||||
cfg_dir = environ.get("ARTEMIS_CFG_DIR", "config")
|
||||
cfg: CoreConfig = CoreConfig()
|
||||
|
|
|
@ -2,18 +2,104 @@
|
|||
{% block content %}
|
||||
{% if arcade is defined %}
|
||||
<h1>{{ arcade.name }}</h1>
|
||||
<h2>PCBs assigned to this arcade <button class="btn btn-success" id="btn_add_cab" onclick="toggle_add_cab_form()">Add</button></h2>
|
||||
<h2>Assigned Machines</h2>
|
||||
{% if success is defined and success == 3 %}
|
||||
<div style="background-color: #00AA00; padding: 20px; margin-bottom: 10px; width: 15%;">
|
||||
Cab added successfully
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if success is defined and success == 1 %}
|
||||
<div style="background-color: #00AA00; padding: 20px; margin-bottom: 10px; width: 15%;">
|
||||
Info Updated
|
||||
</div>
|
||||
{% endif %}
|
||||
{% include "core/templates/widgets/err_banner.jinja" %}
|
||||
<ul style="font-size: 20px;">
|
||||
{% for c in arcade.cabs %}
|
||||
<li><a href="/cab/{{ c.id }}">{{ c.serial }}</a> ({{ c.game if c.game else "Any" }}) <button class="btn btn-secondary" onclick="prep_edit_form()">Edit</button> <button class="btn-danger btn">Delete</button></li>
|
||||
{% for c in cablst %}
|
||||
<li><a href="/cab/{{ c.id }}">{{ c.serial }}</a> ({{ c.game if c.game else "Any" }})</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
Info
|
||||
<form style="max-width: 50%;" action="/shop/{{ arcade.id }}/info.update" method="post" id="shop_info">
|
||||
<div class="row">
|
||||
<div class="col mb-3">
|
||||
<label for="name" class="form-label">Name</label>
|
||||
<input type="text" class="form-control" id="name" name="name" maxlength="255" value="{{ arcade.name if arcade.name is not none else "" }}">
|
||||
</div>
|
||||
<div class="col mb-3">
|
||||
<label for="nickname" class="form-label">Nickname</label>
|
||||
<input type="text" class="form-control" id="nickname" name="nickname" maxlength="255" value="{{ arcade.nickname if arcade.nickname is not none else "" }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col mb-3">
|
||||
<label for="country" class="form-label">Country</label>
|
||||
<select id="country" name="country" class="form-select bg-dark text-white">
|
||||
<option value="JPN" {{ 'selected' if arcade.country == 'JPN' else ''}}>Japan</option>
|
||||
<option value="USA" {{ 'selected' if arcade.country == 'USA' else ''}}>USA</option>
|
||||
<option value="HKG" {{ 'selected' if arcade.country == 'HKG' else ''}}>Hong Kong</option>
|
||||
<option value="SGP" {{ 'selected' if arcade.country == 'SGP' else ''}}>Singapore</option>
|
||||
<option value="KOR" {{ 'selected' if arcade.country == 'KOR' else ''}}>South Korea</option>
|
||||
<option value="TWN" {{ 'selected' if arcade.country == 'TWN' else ''}}>Taiwan</option>
|
||||
<option value="CHN" {{ 'selected' if arcade.country == 'CHN' else ''}}>China</option>
|
||||
<option value="AUS" {{ 'selected' if arcade.country == 'AUS' else ''}}>Australia</option>
|
||||
<option value="IDN" {{ 'selected' if arcade.country == 'IDN' else ''}}>Indonesia</option>
|
||||
<option value="MMR" {{ 'selected' if arcade.country == 'MMR' else ''}}>Myanmar</option>
|
||||
<option value="MYS" {{ 'selected' if arcade.country == 'MYS' else ''}}>Malaysia</option>
|
||||
<option value="NZL" {{ 'selected' if arcade.country == 'NZL' else ''}}>New Zealand</option>
|
||||
<option value="PHL" {{ 'selected' if arcade.country == 'PHL' else ''}}>Philippines</option>
|
||||
<option value="THA" {{ 'selected' if arcade.country == 'THA' else ''}}>Thailand</option>
|
||||
<option value="VNM" {{ 'selected' if arcade.country == 'VNM' else ''}}>Vietnam</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col mb-3">
|
||||
<label for="region1" class="form-label">Region 1</label>
|
||||
<input type="text" class="form-control" id="region1" name="region1" maxlength="255" value="{{ arcade.state if arcade.state is not none else "" }}">
|
||||
</div>
|
||||
<div class="col mb-3">
|
||||
<label for="region2" class="form-label">Region 2</label>
|
||||
<input type="text" class="form-control" id="region2" name="region2" maxlength="255" value="{{ arcade.city if arcade.city is not none else "" }}">
|
||||
</div>
|
||||
<div class="col mb-3">
|
||||
<label for="tz" class="form-label">Timezone</label>
|
||||
<input type="text" class="form-control" id="tz" name="tz" placeholder="+09:00" maxlength="255" value="{{ arcade.timezone if arcade.timezone is not none else "" }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col mb-3">
|
||||
<label for="ip" class="form-label">VPN IP</label>
|
||||
<input type="text" class="form-control" id="ip" name="ip" maxlength="39" value="{{ arcade.ip if arcade.ip is not none else "" }}">
|
||||
</div>
|
||||
</div>
|
||||
{% if can_edit %}
|
||||
<div class="row">
|
||||
<div class="col mb-3">
|
||||
<input type="submit" value="Update" class="btn btn-primary">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
{% if is_owner or is_acmod %}
|
||||
<br>
|
||||
<h2>Arcade Managers <button type="button" class="btn btn-success">Add</button></h2>
|
||||
<ul style="font-size: 20px;">
|
||||
{% for u in managers %}
|
||||
<li>{{ u.name }}:
|
||||
<label for="is_view_{{ u.user }}" class="form-label">View Arcade</label>
|
||||
<input type="checkbox" class="form-control-check" id="is_view_{{ u.user }}" name="is_view" {{ 'checked' if u.is_view else ''}}> |
|
||||
<label for="is_bookkeep_{{ u.user }}" class="form-label">View Bookkeeping</label>
|
||||
<input type="checkbox" class="form-control-check" id="is_bookkeep_{{ u.user }}" name="is_bookkeep" {{ 'checked' if u.is_bookkeep else ''}}> |
|
||||
<label for="is_edit_{{ u.user }}" class="form-label">Edit Arcade</label>
|
||||
<input type="checkbox" class="form-control-check" id="is_edit_{{ u.user }}" name="is_edit" {{ 'checked' if u.is_edit else ''}}> |
|
||||
<label for="is_owner_{{ u.user }}" class="form-label">Owner</label>
|
||||
<input type="checkbox" class="form-control-check" id="is_owner_{{ u.user }}" name="is_owner" {{ 'checked' if u.is_owner else ''}}> |
|
||||
<button type="submit" class="btn btn-primary">Update</button>
|
||||
<button type="button" class="btn btn-danger">Delete</button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<h3>Arcade Not Found</h3>
|
||||
{% endif %}
|
||||
{% endblock content %}
|
||||
{% endblock content %}
|
||||
|
|
|
@ -1,4 +1,113 @@
|
|||
{% extends "core/templates/index.jinja" %}
|
||||
{% block content %}
|
||||
<h1>Machine Management</h1>
|
||||
{% endblock content %}
|
||||
<script type="text/javascript">
|
||||
function swap_ota() {
|
||||
let is_cab = document.getElementById("is_cab").checked;
|
||||
let cbx_ota = document.getElementById("is_ota");
|
||||
|
||||
cbx_ota.disabled = !is_cab;
|
||||
|
||||
if (cbx_ota.disabled) {
|
||||
cbx_ota.checked = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<h1>Machine: {{machine.serial}}</h1>
|
||||
<h3>Arcade: <a href=/shop/{{ arcade.id }}>{{ arcade.name }}</a>{% if is_acmod %} <button class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#reassign_modal">Reassign</button>{% endif %}</h3>
|
||||
{% include "core/templates/widgets/err_banner.jinja" %}
|
||||
{% if success is defined and success == 1 %}
|
||||
<div style="background-color: #00AA00; padding: 20px; margin-bottom: 10px; width: 15%;">
|
||||
Info Updated
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if success is defined and success == 2 %}
|
||||
<div style="background-color: #00AA00; padding: 20px; margin-bottom: 10px; width: 15%;">
|
||||
Machine successfully reassigned
|
||||
</div>
|
||||
{% endif %}
|
||||
Info
|
||||
<form style="max-width: 50%;" action="/cab/{{ machine.id }}/info.update" method="post" id="mech_info">
|
||||
<div class="row">
|
||||
<div class="col mb-3">
|
||||
<label for="game" class="form-label">Game</label>
|
||||
<input type="text" class="form-control" id="game" name="game" placeholder="SXXX" maxlength="4" value="{{ machine.game if machine.game is not none else "" }}">
|
||||
</div>
|
||||
<div class="col mb-3">
|
||||
<label for="country" class="form-label">Country Override</label>
|
||||
<select id="country" name="country" class="form-select bg-dark text-white">
|
||||
<option value="" {{ 'selected' if machine.country is none else ''}}>Same As Arcade</option>
|
||||
<option value="JPN" {{ 'selected' if machine.country == 'JPN' else ''}}>Japan</option>
|
||||
<option value="USA" {{ 'selected' if machine.country == 'USA' else ''}}>USA</option>
|
||||
<option value="HKG" {{ 'selected' if machine.country == 'HKG' else ''}}>Hong Kong</option>
|
||||
<option value="SGP" {{ 'selected' if machine.country == 'SGP' else ''}}>Singapore</option>
|
||||
<option value="KOR" {{ 'selected' if machine.country == 'KOR' else ''}}>South Korea</option>
|
||||
<option value="TWN" {{ 'selected' if machine.country == 'TWN' else ''}}>Taiwan</option>
|
||||
<option value="CHN" {{ 'selected' if machine.country == 'CHN' else ''}}>China</option>
|
||||
<option value="AUS" {{ 'selected' if machine.country == 'AUS' else ''}}>Australia</option>
|
||||
<option value="IDN" {{ 'selected' if machine.country == 'IDN' else ''}}>Indonesia</option>
|
||||
<option value="MMR" {{ 'selected' if machine.country == 'MMR' else ''}}>Myanmar</option>
|
||||
<option value="MYS" {{ 'selected' if machine.country == 'MYS' else ''}}>Malaysia</option>
|
||||
<option value="NZL" {{ 'selected' if machine.country == 'NZL' else ''}}>New Zealand</option>
|
||||
<option value="PHL" {{ 'selected' if machine.country == 'PHL' else ''}}>Philippines</option>
|
||||
<option value="THA" {{ 'selected' if machine.country == 'THA' else ''}}>Thailand</option>
|
||||
<option value="VNM" {{ 'selected' if machine.country == 'VNM' else ''}}>Vietnam</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col mb-3">
|
||||
<label for="tz" class="form-label">Timezone Override</label>
|
||||
<input type="text" class="form-control" id="tz" name="tz" placeholder="+09:00" maxlength="6" value="{{ machine.timezone if machine.timezone is not none else "" }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col mb-3">
|
||||
<input type="checkbox" class="form-control-check" id="is_cab" name="is_cab" {{ 'checked' if machine.is_cab else ''}} onchange="swap_ota()">
|
||||
<label for="is_cab" class="form-label">Real Cabinet</label>
|
||||
</div>
|
||||
<div class="col mb-3">
|
||||
<input type="checkbox" class="form-control-check" id="is_ota" name="is_ota" {{ 'checked' if machine.ota_enable else ''}}>
|
||||
<label for="is_ota" class="form-label">Allow OTA updates</label>
|
||||
</div>
|
||||
<div class="col mb-3">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col mb-3">
|
||||
<label for="memo" class="form-label">Memo</label>
|
||||
<input type="text" class="form-control" id="memo" name="memo" maxlength="255" value="{{ machine.memo if machine.memo is not none else "" }}">
|
||||
</div>
|
||||
</div>
|
||||
{% if can_edit %}
|
||||
<div class="row">
|
||||
<div class="col mb-3">
|
||||
<input type="submit" value="Update" class="btn btn-primary">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
{% if is_acmod %}
|
||||
<form id="frm_reassign" method="post" action="/cab/{{ machine.id }}/reassign" style="outline: 0px;">
|
||||
<div class="modal" tabindex="-1" id="reassign_modal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Reassign {{ machine.serial }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>This will reassign this cabinet from the current arcade "{{ arcade.name }}" to the arcade who's ID you enter below.</p>
|
||||
<label for="new_arcade" class="form-label">New Arcade</label>
|
||||
<input type="text" class="form-control" id="new_arcade" name="new_arcade" value="{{ arcade.id }}">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-primary">Save changes</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endif %}
|
||||
<script type="text/javascript">
|
||||
swap_ota();
|
||||
</script>
|
||||
{% endblock content %}
|
||||
|
|
|
@ -137,6 +137,11 @@
|
|||
<input type="text" class="form-control" id="shopIp" name="shopIp">
|
||||
</div>
|
||||
<br />
|
||||
<div class="form-group">
|
||||
<label for="shopOwner">Owner User ID</label>
|
||||
<input type="text" class="form-control" id="shopOwner" name="shopOwner">
|
||||
</div>
|
||||
<br />
|
||||
<button type="submit" class="btn btn-primary">Add</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -159,19 +159,10 @@ Update successful
|
|||
</form>
|
||||
|
||||
{% if arcades is defined and arcades|length > 0 %}
|
||||
<h2>Arcades</h2>
|
||||
<h2>Arcades you manage</h2>
|
||||
<ul>
|
||||
{% for a in arcades %}
|
||||
<li><h3>{{ a.name }}</h3>
|
||||
{% if a.machines|length > 0 %}
|
||||
<table>
|
||||
<tr><th>Serial</th><th>Game</th><th>Last Seen</th></tr>
|
||||
{% for m in a.machines %}
|
||||
<tr><td>{{ m.serial }}</td><td>{{ m.game }}</td><td>{{ m.last_seen }}</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endif %}
|
||||
</li>
|
||||
<li><h3><a href=/shop/{{a.id}}>{{ a.name }}</a></h3></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
|
|
@ -27,6 +27,10 @@ Access Denied
|
|||
Card already registered
|
||||
{% elif error == 13 %}
|
||||
AmusementIC Access Codes beginning with 5 must have IDm
|
||||
{% elif error == 14 %}
|
||||
Arcade does not exist
|
||||
{% elif error == 15 %}
|
||||
Some info failed to update
|
||||
{% else %}
|
||||
An unknown error occoured
|
||||
{% endif %}
|
||||
|
|
Loading…
Reference in New Issue