From 6ff7adb16514452fb5a2b474bdd0607202c52166 Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Sat, 1 Feb 2025 23:43:21 +0000 Subject: [PATCH] update rio and fix broken user sessions (#5) Co-authored-by: David Rodenkirchen Reviewed-on: https://git.ezgg-ev.de/Vereins-IT/ez-lan-manager/pulls/5 --- requirements.txt | Bin 186 -> 186 bytes src/EzLanManager.py | 10 ++++--- src/ez_lan_manager/__init__.py | 6 +++-- src/ez_lan_manager/components/AnimatedText.py | 4 +-- .../components/DesktopNavigation.py | 25 +++++++++++++++--- src/ez_lan_manager/components/LoginBox.py | 8 ++++-- .../components/ShoppingCartAndOrders.py | 12 ++++----- src/ez_lan_manager/components/UserInfoBox.py | 6 ++++- src/ez_lan_manager/pages/BasePage.py | 2 +- src/ez_lan_manager/pages/BuyTicketPage.py | 2 +- src/ez_lan_manager/pages/CateringPage.py | 4 +-- src/ez_lan_manager/pages/ContactPage.py | 2 +- src/ez_lan_manager/pages/DbErrorPage.py | 2 +- src/ez_lan_manager/pages/ForgotPassword.py | 2 +- src/ez_lan_manager/pages/ManageNewsPage.py | 4 +-- src/ez_lan_manager/pages/RegisterPage.py | 2 +- src/ez_lan_manager/pages/SeatingPlanPage.py | 2 +- .../services/LocalDataService.py | 25 ++++++++++++++++++ 18 files changed, 87 insertions(+), 31 deletions(-) create mode 100644 src/ez_lan_manager/services/LocalDataService.py diff --git a/requirements.txt b/requirements.txt index 1f4254def008c892b834093480747e2ae53874fd..08c2369265a31b272fe3805856d2566ec4f2f140 100644 GIT binary patch delta 11 ScmdnRxQlT@5~JnB None: await session.set_title(lan_info.name) session.attach(SessionStorage()) async def on_app_start(a: App) -> None: - init_result = await a.default_attachments[3].init_db_pool() + init_result = await a.default_attachments[4].init_db_pool() if not init_result: logger.fatal("Could not connect to database, exiting...") sys.exit(1) @@ -163,7 +165,7 @@ if __name__ == "__main__": ], theme=theme, assets_dir=Path(__file__).parent / "assets", - default_attachments=services, + default_attachments=default_attachments, on_session_start=on_session_start, on_app_start=on_app_start, icon=from_root("src/ez_lan_manager/assets/img/favicon.png"), diff --git a/src/ez_lan_manager/__init__.py b/src/ez_lan_manager/__init__.py index 6c6712a..76fd5b7 100644 --- a/src/ez_lan_manager/__init__.py +++ b/src/ez_lan_manager/__init__.py @@ -7,6 +7,7 @@ from src.ez_lan_manager.services.AccountingService import AccountingService from src.ez_lan_manager.services.CateringService import CateringService from src.ez_lan_manager.services.ConfigurationService import ConfigurationService from src.ez_lan_manager.services.DatabaseService import DatabaseService +from src.ez_lan_manager.services.LocalDataService import LocalDataService from src.ez_lan_manager.services.MailingService import MailingService from src.ez_lan_manager.services.NewsService import NewsService from src.ez_lan_manager.services.SeatingService import SeatingService @@ -15,7 +16,7 @@ from src.ez_lan_manager.services.UserService import UserService from src.ez_lan_manager.types import * # Inits services in the correct order -def init_services() -> tuple[AccountingService, CateringService, ConfigurationService, DatabaseService, MailingService, NewsService, SeatingService, TicketingService, UserService]: +def init_services() -> tuple[AccountingService, CateringService, ConfigurationService, DatabaseService, MailingService, NewsService, SeatingService, TicketingService, UserService, LocalDataService]: logging.basicConfig(level=logging.DEBUG) configuration_service = ConfigurationService(from_root("config.toml")) db_service = DatabaseService(configuration_service.get_database_configuration()) @@ -26,5 +27,6 @@ def init_services() -> tuple[AccountingService, CateringService, ConfigurationSe ticketing_service = TicketingService(configuration_service.get_ticket_info(), db_service, accounting_service) seating_service = SeatingService(configuration_service.get_seating_configuration(), configuration_service.get_lan_info(), db_service, ticketing_service) catering_service = CateringService(db_service, accounting_service, user_service) + local_data_service = LocalDataService() - return accounting_service, catering_service, configuration_service, db_service, mailing_service, news_service, seating_service, ticketing_service, user_service + return accounting_service, catering_service, configuration_service, db_service, mailing_service, news_service, seating_service, ticketing_service, user_service, local_data_service diff --git a/src/ez_lan_manager/components/AnimatedText.py b/src/ez_lan_manager/components/AnimatedText.py index e62f7af..0e06252 100644 --- a/src/ez_lan_manager/components/AnimatedText.py +++ b/src/ez_lan_manager/components/AnimatedText.py @@ -21,7 +21,7 @@ class AnimatedText(Component): ) for c in text: self.text_comp.text = self.text_comp.text + c - await self.text_comp.force_refresh() + self.text_comp.force_refresh() await sleep(speed) else: self.text_comp.style = TextStyle( @@ -30,7 +30,7 @@ class AnimatedText(Component): ) for c in text: self.text_comp.text = self.text_comp.text + c - await self.text_comp.force_refresh() + self.text_comp.force_refresh() await sleep(speed) self._display_printing[0] = False diff --git a/src/ez_lan_manager/components/DesktopNavigation.py b/src/ez_lan_manager/components/DesktopNavigation.py index a20bc41..f9d9d4d 100644 --- a/src/ez_lan_manager/components/DesktopNavigation.py +++ b/src/ez_lan_manager/components/DesktopNavigation.py @@ -1,21 +1,38 @@ from copy import copy, deepcopy -from typing import Optional +from typing import Optional, Callable from rio import * -from src.ez_lan_manager import ConfigurationService, UserService +from src.ez_lan_manager import ConfigurationService, UserService, LocalDataService from src.ez_lan_manager.components.DesktopNavigationButton import DesktopNavigationButton from src.ez_lan_manager.components.UserInfoAndLoginBox import UserInfoAndLoginBox +from src.ez_lan_manager.services.LocalDataService import LocalData from src.ez_lan_manager.types.SessionStorage import SessionStorage from src.ez_lan_manager.types.User import User class DesktopNavigation(Component): user: Optional[User] = None + force_login_box_refresh: list[Callable] = [] @event.on_populate async def async_init(self) -> None: self.session[SessionStorage].subscribe_to_logged_in_or_out_event(str(self.__class__), self.async_init) + local_data = self.session[LocalData] + if local_data.stored_session_token: + session_ = self.session[LocalDataService].verify_token(local_data.stored_session_token) + if session_: + self.session.detach(SessionStorage) + self.session.attach(session_) + self.user = await self.session[UserService].get_user(session_.user_id) + try: + # Hack-around, maybe fix in the future + self.force_login_box_refresh[-1]() + except IndexError: + pass + + return + if self.session[SessionStorage].user_id: self.user = await self.session[UserService].get_user(self.session[SessionStorage].user_id) else: @@ -23,6 +40,8 @@ class DesktopNavigation(Component): def build(self) -> Component: lan_info = self.session[ConfigurationService].get_lan_info() + user_info_and_login_box = UserInfoAndLoginBox() + self.force_login_box_refresh.append(user_info_and_login_box.force_refresh) user_navigation = [ DesktopNavigationButton("News", "./news"), Spacer(min_height=1), @@ -62,7 +81,7 @@ class DesktopNavigation(Component): Column( Text(lan_info.name, align_x=0.5, margin_top=0.3, style=TextStyle(fill=self.session.theme.hud_color, font_size=2.5)), Text(f"Edition {lan_info.iteration}", align_x=0.5, style=TextStyle(fill=self.session.theme.hud_color, font_size=1.2), margin_top=0.3, margin_bottom=2), - UserInfoAndLoginBox(), + user_info_and_login_box, *nav_to_use, align_y=0 ), diff --git a/src/ez_lan_manager/components/LoginBox.py b/src/ez_lan_manager/components/LoginBox.py index 0a643b7..b397b6b 100644 --- a/src/ez_lan_manager/components/LoginBox.py +++ b/src/ez_lan_manager/components/LoginBox.py @@ -1,6 +1,7 @@ from rio import Component, TextStyle, Color, TextInput, Button, Text, Rectangle, Column, Row, Spacer, \ EventHandler +from src.ez_lan_manager.services.LocalDataService import LocalDataService, LocalData from src.ez_lan_manager.services.UserService import UserService from src.ez_lan_manager.types.SessionStorage import SessionStorage from src.ez_lan_manager.types.User import User @@ -27,13 +28,16 @@ class LoginBox(Component): self.login_button_is_loading = False self.is_account_locked = False await self.session[SessionStorage].set_user_id_and_team_member_flag(user.user_id, user.is_team_member) - await self.status_change_cb() + token = self.session[LocalDataService].set_session(self.session[SessionStorage]) + self.session[LocalData].stored_session_token = token + self.session.attach(self.session[LocalData]) + self.status_change_cb() else: self.user_name_input_is_valid = False self.password_input_is_valid = False self.login_button_is_loading = False self.is_account_locked = False - await self.force_refresh() + self.force_refresh() def build(self) -> Component: user_name_input = TextInput( diff --git a/src/ez_lan_manager/components/ShoppingCartAndOrders.py b/src/ez_lan_manager/components/ShoppingCartAndOrders.py index 58a860c..e738756 100644 --- a/src/ez_lan_manager/components/ShoppingCartAndOrders.py +++ b/src/ez_lan_manager/components/ShoppingCartAndOrders.py @@ -33,11 +33,11 @@ class ShoppingCartAndOrders(Component): except IndexError: return catering_service.save_cart(user_id, cart) - await self.force_refresh() + self.force_refresh() async def on_empty_cart_pressed(self) -> None: self.session[CateringService].save_cart(self.session[SessionStorage].user_id, []) - await self.force_refresh() + self.force_refresh() async def on_add_item(self, article_id: int) -> None: catering_service = self.session[CateringService] @@ -48,20 +48,20 @@ class ShoppingCartAndOrders(Component): item_to_add = await catering_service.get_menu_item_by_id(article_id) cart.append(item_to_add) catering_service.save_cart(user_id, cart) - await self.force_refresh() + self.force_refresh() async def show_popup(self, text: str, is_error: bool) -> None: self.popup_is_error = is_error self.popup_message = text self.popup_is_shown = True - await self.force_refresh() + self.force_refresh() await sleep(POPUP_CLOSE_TIMEOUT_SECONDS) self.popup_is_shown = False - await self.force_refresh() + self.force_refresh() async def on_order_pressed(self) -> None: self.order_button_loading = True - await self.force_refresh() + self.force_refresh() user_id = self.session[SessionStorage].user_id cart = self.session[CateringService].get_cart(user_id) diff --git a/src/ez_lan_manager/components/UserInfoBox.py b/src/ez_lan_manager/components/UserInfoBox.py index 0d635c8..f94c6a6 100644 --- a/src/ez_lan_manager/components/UserInfoBox.py +++ b/src/ez_lan_manager/components/UserInfoBox.py @@ -4,6 +4,7 @@ from typing import Optional from rio import Component, TextStyle, Color, Button, Text, Rectangle, Column, Row, Spacer, Link, event, EventHandler from src.ez_lan_manager.components.UserInfoBoxButton import UserInfoBoxButton +from src.ez_lan_manager.services.LocalDataService import LocalData, LocalDataService from src.ez_lan_manager.services.UserService import UserService from src.ez_lan_manager.services.AccountingService import AccountingService from src.ez_lan_manager.services.TicketingService import TicketingService @@ -52,7 +53,10 @@ class UserInfoBox(Component): async def logout(self) -> None: await self.session[SessionStorage].clear() self.user = None - await self.status_change_cb() + self.session[LocalDataService].del_session(self.session[LocalData].stored_session_token) + self.session[LocalData].stored_session_token = None + self.session.attach(self.session[LocalData]) + self.status_change_cb() self.session.navigate_to("/") @event.on_populate diff --git a/src/ez_lan_manager/pages/BasePage.py b/src/ez_lan_manager/pages/BasePage.py index a301058..2787056 100644 --- a/src/ez_lan_manager/pages/BasePage.py +++ b/src/ez_lan_manager/pages/BasePage.py @@ -18,7 +18,7 @@ class BasePage(Component): @event.on_window_size_change async def on_window_size_change(self): - await self.force_refresh() + self.force_refresh() def build(self) -> Component: content = Card( diff --git a/src/ez_lan_manager/pages/BuyTicketPage.py b/src/ez_lan_manager/pages/BuyTicketPage.py index f1ffaa2..4eb0a70 100644 --- a/src/ez_lan_manager/pages/BuyTicketPage.py +++ b/src/ez_lan_manager/pages/BuyTicketPage.py @@ -38,7 +38,7 @@ class BuyTicketPage(Component): if not self.user: return self.is_buying_enabled = False - await self.force_refresh() + self.force_refresh() try: t_s = self.session[TicketingService] diff --git a/src/ez_lan_manager/pages/CateringPage.py b/src/ez_lan_manager/pages/CateringPage.py index 21041b0..3b324b6 100644 --- a/src/ez_lan_manager/pages/CateringPage.py +++ b/src/ez_lan_manager/pages/CateringPage.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, Callable from rio import Column, Component, event, TextStyle, Text, Spacer, Revealer, SwitcherBar, SwitcherBarChangeEvent, ProgressCircle @@ -24,7 +24,7 @@ class CateringPage(Component): self.all_menu_items = await self.session[CateringService].get_menu() async def on_user_logged_in_status_changed(self) -> None: - await self.force_refresh() + self.force_refresh() async def on_switcher_bar_changed(self, _: SwitcherBarChangeEvent) -> None: await self.shopping_cart_and_orders[0].switch() diff --git a/src/ez_lan_manager/pages/ContactPage.py b/src/ez_lan_manager/pages/ContactPage.py index 65ee183..c4899c6 100644 --- a/src/ez_lan_manager/pages/ContactPage.py +++ b/src/ez_lan_manager/pages/ContactPage.py @@ -28,7 +28,7 @@ class ContactPage(Component): async def on_send_pressed(self) -> None: error_msg = "" self.submit_button.is_loading = True - await self.submit_button.force_refresh() + self.submit_button.force_refresh() now = datetime.now() if not self.email_input.text: error_msg = "E-Mail darf nicht leer sein!" diff --git a/src/ez_lan_manager/pages/DbErrorPage.py b/src/ez_lan_manager/pages/DbErrorPage.py index 4a4e7f2..23137f5 100644 --- a/src/ez_lan_manager/pages/DbErrorPage.py +++ b/src/ez_lan_manager/pages/DbErrorPage.py @@ -13,7 +13,7 @@ from src.ez_lan_manager.components.MainViewContentBox import MainViewContentBox class DbErrorPage(Component): @event.on_window_size_change async def on_window_size_change(self) -> None: - await self.force_refresh() + self.force_refresh() @event.on_mount async def retry_db_connect(self) -> None: diff --git a/src/ez_lan_manager/pages/ForgotPassword.py b/src/ez_lan_manager/pages/ForgotPassword.py index aa585c7..e7e6375 100644 --- a/src/ez_lan_manager/pages/ForgotPassword.py +++ b/src/ez_lan_manager/pages/ForgotPassword.py @@ -20,7 +20,7 @@ class ForgotPasswordPage(Component): async def on_submit_button_pressed(self) -> None: self.submit_button.is_loading = True - await self.submit_button.force_refresh() + self.submit_button.force_refresh() lan_info = self.session[ConfigurationService].get_lan_info() user_service = self.session[UserService] mailing_service = self.session[MailingService] diff --git a/src/ez_lan_manager/pages/ManageNewsPage.py b/src/ez_lan_manager/pages/ManageNewsPage.py index 36c51bf..aa41017 100644 --- a/src/ez_lan_manager/pages/ManageNewsPage.py +++ b/src/ez_lan_manager/pages/ManageNewsPage.py @@ -38,10 +38,10 @@ class ManageNewsPage(Component): )) self.news_posts = (await self.session[NewsService].get_news())[:8] self.show_success_message = True - await self.force_refresh() + self.force_refresh() await sleep(3) self.show_success_message = False - await self.force_refresh() + self.force_refresh() async def on_news_post_changed(self, post: EditableNewsPost) -> None: author = await self.session[UserService].get_user(post.author) diff --git a/src/ez_lan_manager/pages/RegisterPage.py b/src/ez_lan_manager/pages/RegisterPage.py index 451a243..5ebabec 100644 --- a/src/ez_lan_manager/pages/RegisterPage.py +++ b/src/ez_lan_manager/pages/RegisterPage.py @@ -35,7 +35,7 @@ class RegisterPage(Component): async def on_submit_button_pressed(self) -> None: self.submit_button.is_loading = True - await self.submit_button.force_refresh() + self.submit_button.force_refresh() if len(self.user_name_input.text) < 1: await self.animated_text.display_text(False, "Nutzername darf nicht leer sein!") diff --git a/src/ez_lan_manager/pages/SeatingPlanPage.py b/src/ez_lan_manager/pages/SeatingPlanPage.py index 058aba4..a67834f 100644 --- a/src/ez_lan_manager/pages/SeatingPlanPage.py +++ b/src/ez_lan_manager/pages/SeatingPlanPage.py @@ -75,7 +75,7 @@ class SeatingPlanPage(Component): async def on_purchase_confirmed(self) -> None: self.purchase_box_loading = True - await self.force_refresh() + self.force_refresh() await sleep(0.5) try: await self.session[SeatingService].seat_user(self.user.user_id, self.current_seat_id) diff --git a/src/ez_lan_manager/services/LocalDataService.py b/src/ez_lan_manager/services/LocalDataService.py new file mode 100644 index 0000000..038fd8b --- /dev/null +++ b/src/ez_lan_manager/services/LocalDataService.py @@ -0,0 +1,25 @@ +import secrets +from typing import Optional + +from rio import UserSettings + +from src.ez_lan_manager.types.SessionStorage import SessionStorage + + +class LocalData(UserSettings): + stored_session_token: Optional[str] = None + +class LocalDataService: + def __init__(self) -> None: + self._session: dict[str, SessionStorage] = {} + + def verify_token(self, token: str) -> Optional[SessionStorage]: + return self._session.get(token) + + def set_session(self, session: SessionStorage) -> str: + key = secrets.token_hex(32) + self._session[key] = session + return key + + def del_session(self, token: str) -> None: + self._session.pop(token, None)