update rio and fix broken user sessions #5

Merged
Typhus merged 1 commits from bugfix/fix-broken-user-session into main 2025-02-01 23:43:21 +00:00
18 changed files with 87 additions and 31 deletions

Binary file not shown.

View File

@ -11,6 +11,7 @@ from from_root import from_root
from src.ez_lan_manager import pages, init_services
from src.ez_lan_manager.helpers.LoggedInGuard import logged_in_guard, not_logged_in_guard, team_guard
from src.ez_lan_manager.services.DatabaseService import NoDatabaseConnectionError
from src.ez_lan_manager.services.LocalDataService import LocalData
from src.ez_lan_manager.types.SessionStorage import SessionStorage
logger = logging.getLogger("EzLanManager")
@ -29,16 +30,17 @@ if __name__ == "__main__":
corner_radius_large=0,
font=Font(from_root("src/ez_lan_manager/assets/fonts/joystix.otf"))
)
services = init_services()
default_attachments = [LocalData()]
default_attachments.extend(init_services())
lan_info = services[2].get_lan_info()
lan_info = default_attachments[3].get_lan_info()
async def on_session_start(session: Session) -> 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"),

View File

@ -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

View File

@ -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

View File

@ -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
),

View File

@ -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(

View File

@ -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)

View File

@ -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

View File

@ -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(

View File

@ -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]

View File

@ -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()

View File

@ -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!"

View File

@ -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:

View File

@ -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]

View File

@ -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)

View File

@ -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!")

View File

@ -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)

View File

@ -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)