diff --git a/tui.py b/tui.py index 0982625..6486629 100644 --- a/tui.py +++ b/tui.py @@ -8,9 +8,11 @@ import bcrypt import secrets import string from sqlalchemy.engine import Row +import inflection from core.data import Data from core.config import CoreConfig +from core.const import AllnetCountryCode try: from asciimatics.widgets import Frame, Layout, Text, Button, RadioButtons, CheckBox, Divider, Label @@ -139,7 +141,7 @@ class MainView(Frame): layout.add_widget(Button("User Management", self._user_mgmt)) layout.add_widget(Button("Card Management", self._card_mgmt)) layout.add_widget(Button("Arcade Management", self._arcade_mgmt)) - layout.add_widget(Button("Machine Management", self._mech_mgmt)) + layout.add_widget(Button("Machine Management", self._machine_mgmt)) layout.add_widget(Button("Quit", self._quit)) self.fix() @@ -156,9 +158,9 @@ class MainView(Frame): self.save() raise NextScene("Arcade Management") - def _mech_mgmt(self): + def _machine_mgmt(self): self.save() - raise NextScene("Mech Management") + raise NextScene("Machine Management") @staticmethod def _quit(): @@ -193,7 +195,7 @@ class ManageUserView(Frame): usr_cards = [] if state.selected_user.id != 0: cards = loop.run_until_complete(data.card.get_user_cards(state.selected_user.id)) - for card in cards: + for card in cards or []: usr_cards.append(card._asdict()) if len(usr_cards) > 0: @@ -693,6 +695,65 @@ class ManageArcadeView(Frame): self.save() raise NextScene("Main") +class CreateArcadeView(Frame): + def __init__(self, screen: Screen): + super(CreateArcadeView, self).__init__( + screen, + screen.height * 2 // 3, + screen.width * 2 // 3, + hover_focus=True, + can_scroll=False, + title="Create Arcade" + ) + + layout = Layout([100], fill_frame=True) + self.add_layout(layout) + layout.add_widget(Text("Name:", "name")) + layout.add_widget(Text("Nickname:", "nickname")) + layout.add_widget(Text("Timezone:", "timezone")) + layout.add_widget(Text("VPN IP:", "ip")) + layout.add_widget(CheckBox("", "Add Machine:", "is_add_machine", )) + layout.add_widget(RadioButtons([ + (inflection.titleize(x.name), x.value) for x in AllnetCountryCode + ], "Country:", "country")) + + layout3 = Layout([100]) + self.add_layout(layout3) + layout3.add_widget(Text("", f"status", readonly=True, disabled=True)) + + layout2 = Layout([1, 1, 1, 1]) + self.add_layout(layout2) + layout2.add_widget(Button("OK", self._ok), 0) + layout2.add_widget(Button("Cancel", self._cancel), 3) + + self.fix() + + def _ok(self): + self.save() + state.clear_last_err() + self.find_widget('status').value = state.last_err + + loop.run_until_complete(self._create_arcade_async(self.data.get("name"), self.data.get("nickname"), self.data.get("country"), self.data.get('timezone'), self.data.get('ip'))) + + raise NextScene("Create Machine" if self.data.get("is_add_machine") else "Arcade Management") + + async def _create_arcade_async(self, name: str, nickname: Optional[str], country: str, timezone: Optional[str], ip: Optional[str]): + arcade_id = await data.arcade.create_arcade(name, nickname if nickname != "" else None, country) + + if timezone: + data.arcade.set_arcade_timezone(arcade_id, timezone) + + if ip: + data.arcade.set_arcade_vpn_ip(arcade_id, ip) + + if arcade_id: + state.set_arcade(arcade_id, country, name) + + def _cancel(self): + state.clear_last_err() + self.find_widget('status').value = state.last_err + raise NextScene("Arcade Management") + class LookupArcadeView(Frame): def __init__(self, screen): super(LookupArcadeView, self).__init__( @@ -800,6 +861,231 @@ class LookupArcadeView(Frame): self.find_widget('status').value = state.last_err raise NextScene("Arcade Management") +class ManageMachineView(Frame): + def __init__(self, screen: Screen): + super(ManageMachineView, self).__init__( + screen, + screen.height * 2 // 3, + screen.width * 2 // 3, + hover_focus=True, + can_scroll=False, + title="Machine Management", + on_load=self._redraw + ) + + layout = Layout([3]) + self.add_layout(layout) + layout.add_widget(Button("Create Machine", self._create)) + layout.add_widget(Button("Lookup Machine", self._lookup)) + + def _redraw(self): + self._layouts = [self._layouts[0]] + + layout = Layout([3]) + self.add_layout(layout) + layout.add_widget(Button("Reassign Machine", self._reassign, disabled=state.selected_machine.id == 0 or state.selected_machine.id is None)) + layout.add_widget(Button("Edit Machine", self._edit, disabled=state.selected_machine.id == 0 or state.selected_machine.id is None)) + layout.add_widget(Button("Delete Machine", self._del, disabled=state.selected_machine.id == 0 or state.selected_machine.id is None)) + layout.add_widget((Divider())) + + layout2 = Layout([1, 1, 1]) + self.add_layout(layout2) + a = Text("", f"status", readonly=True, disabled=True) + a.value = f"Selected Machine: {state.selected_arcade}" + layout2.add_widget(a) + layout2.add_widget(Button("Back", self._back), 2) + + self.fix() + + def _create(self): + self.save() + raise NextScene("Create Machine") + + def _lookup(self): + self.save() + raise NextScene("Lookup Machine") + + def _reassign(self): + self.save() + raise NextScene("Reassign Machine") + + def _edit(self): + self.save() + raise NextScene("Edit Machine") + + def _del(self): + self.save() + raise NextScene("Delete Machine") + + def _back(self): + self.save() + raise NextScene("Main") + +class CreateMachineView(Frame): + def __init__(self, screen: Screen): + super(CreateMachineView, self).__init__( + screen, + screen.height - 10, + screen.width * 2 // 3, + hover_focus=True, + can_scroll=False, + title="Create Machine" + ) + + layout = Layout([100], fill_frame=True) + self.add_layout(layout) + layout.add_widget(Text("Arcade:", "arcade_id")) + layout.add_widget(Text("Serial:", "serial")) + layout.add_widget(Text("Game:", "game_id")) + layout.add_widget(CheckBox("", "Real Cabinet:", "is_cab", )) + layout.add_widget(RadioButtons([("Not Set", None)] + [ + (inflection.titleize(x.name), x.value) for x in AllnetCountryCode + ], "Country Override:", "country")) + + layout3 = Layout([100]) + self.add_layout(layout3) + layout3.add_widget(Text("", f"status", readonly=True, disabled=True)) + + layout2 = Layout([1, 1, 1, 1]) + self.add_layout(layout2) + layout2.add_widget(Button("OK", self._ok), 0) + layout2.add_widget(Button("Cancel", self._cancel), 3) + + self.fix() + + def _redraw(self): + self.find_widget("arcade_id").value = state.selected_arcade.id + + def _ok(self): + self.save() + state.clear_last_err() + self.find_widget('status').value = state.last_err + + loop.run_until_complete(self._create_arcade_async(self.data.get("name"), self.data.get("nickname"), self.data.get("country"), self.data.get('timezone'), self.data.get('ip'))) + + raise NextScene("Arcade Management") + + async def _create_arcade_async(self, arcade_id: int, serial: str, game: Optional[str], is_cab: bool, country: Optional[str]): + machine_id = await data.arcade.create_machine(arcade_id, serial, None, game, is_cab) + + if country: + data.arcade.set_machine_country(machine_id, country) + + if machine_id: + state.set_machine(machine_id, serial) + + def _cancel(self): + state.clear_last_err() + self.find_widget('status').value = state.last_err + raise NextScene("Machine Management") + +class LookupMachineView(Frame): + def __init__(self, screen): + super(LookupMachineView, self).__init__( + screen, + screen.height * 2 // 3, + screen.width * 2 // 3, + hover_focus=True, + can_scroll=False, + title="Lookup Machine" + ) + + layout = Layout([1, 1], fill_frame=True) + self.add_layout(layout) + layout.add_widget(RadioButtons([ + ("Name", "1"), + ("Serial", "2"), + ("Arcade ID", "3"), + ("Machine ID", "4"), + ], "Search By:", "search_type")) + layout.add_widget(Text("Search:", "search_str"), 1) + + layout3 = Layout([100]) + self.add_layout(layout3) + layout3.add_widget(Text("", f"status", readonly=True, disabled=True)) + + layout2 = Layout([1, 1, 1, 1]) + self.add_layout(layout2) + layout2.add_widget(Button("Search", self._lookup), 0) + layout2.add_widget(Button("Cancel", self._cancel), 3) + + self.fix() + + def _lookup(self): + self.save() + if not self.data.get("search_str"): + state.set_last_err("Search cannot be blank") + self.find_widget('status').value = state.last_err + self.screen.reset() + return + + state.clear_last_err() + self.find_widget('status').value = state.last_err + + search_type = self.data.get("search_type") + if search_type == "1": + loop.run_until_complete(self._lookup_arcade_by_name(self.data.get("search_str"))) + elif search_type == "2": + loop.run_until_complete(self._lookup_arcade_by_serial(self.data.get("search_str"))) + elif search_type == "3": + real_id = int(self.data.get("search_str"), 16) + loop.run_until_complete(self._lookup_arcade_by_id(real_id)) + elif search_type == "4": + loop.run_until_complete(self._lookup_arcade_by_id(self.data.get("search_str"))) + else: + state.set_last_err("Unknown search type") + self.find_widget('status').value = state.last_err + self.screen.reset() + return + + if len(state.search_results) < 1: + state.set_last_err("Search returned no results") + self.find_widget('status').value = state.last_err + self.screen.reset() + return + + state.search_type = "user" + raise NextScene("Search Results") + + async def _lookup_arcade_by_id(self, ac_id: str): + ac = await data.arcade.get_arcade(ac_id) + + if ac is not None: + res = ac._asdict() + num_cabs = await data.arcade.get_arcade_machines(ac_id) + res['mech_ct'] = len(num_cabs) if num_cabs else 0 + state.search_results = [res] + + async def _lookup_arcade_by_name(self, name: str): + ac = await data.arcade.get_arcade_by_name(name) + + if ac is not None: + res = [] + for ac_res in ac: + t = ac_res._asdict() + num_cabs = await data.arcade.get_arcade_machines(t['id']) + t['mech_ct'] = len(num_cabs) if num_cabs else 0 + res.append(t) + + state.search_results = res + + async def _lookup_arcade_by_serial(self, serial: str): + mech = await data.arcade.get_machine(serial) + + if mech is not None: + ac = await data.arcade.get_arcade(mech['arcade']) + + if ac is not None: + res = ac._asdict() + num_cabs = await data.arcade.get_arcade_machines(mech['arcade']) + res['mech_ct'] = len(num_cabs) if num_cabs else 0 + state.search_results = [res] + + def _cancel(self): + state.clear_last_err() + self.find_widget('status').value = state.last_err + raise NextScene("Machine Management") + def demo(screen:Screen, scene: Scene): scenes = [ Scene([MainView(screen)], -1, name="Main"), @@ -810,7 +1096,11 @@ def demo(screen:Screen, scene: Scene): Scene([ManageCardView(screen)], -1, name="Card Management"), Scene([EditUserView(screen)], -1, name="Edit User"), Scene([ManageArcadeView(screen)], -1, name="Arcade Management"), + Scene([CreateArcadeView(screen)], -1, name="Create Arcade"), Scene([LookupArcadeView(screen)], -1, name="Lookup Arcade"), + Scene([ManageMachineView(screen)], -1, name="Machine Management"), + Scene([LookupMachineView(screen)], -1, name="Lookup Machine"), + Scene([CreateMachineView(screen)], -1, name="Create Machine"), ] screen.play(scenes, stop_on_resize=False, start_scene=scene, allow_int=True)