aiomysql refactor

This commit is contained in:
David Rodenkirchen 2024-09-03 14:30:32 +02:00
parent a9597b5c4f
commit 30b32a4c02
24 changed files with 901 additions and 755 deletions

Binary file not shown.

View File

@ -1,4 +1,6 @@
import logging
from asyncio import get_event_loop
import sys
from pathlib import Path
@ -27,13 +29,7 @@ if __name__ == "__main__":
corner_radius_large=0,
font=Font(from_root("src/ez_lan_manager/assets/fonts/joystix.otf"))
)
try:
services = init_services()
except NoDatabaseConnectionError:
logger.fatal("Could not connect to database, exiting...")
sys.exit(1)
services = init_services()
lan_info = services[2].get_lan_info()
@ -41,6 +37,12 @@ if __name__ == "__main__":
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()
if not init_result:
logger.fatal("Could not connect to database, exiting...")
sys.exit(1)
app = App(
name="EZ LAN Manager",
pages=[
@ -138,6 +140,7 @@ if __name__ == "__main__":
assets_dir=Path(__file__).parent / "assets",
default_attachments=services,
on_session_start=on_session_start,
on_app_start=on_app_start,
icon=from_root("src/ez_lan_manager/assets/img/favicon.png"),
meta_tags={
"robots": "INDEX,FOLLOW",

View File

@ -1,10 +1,8 @@
from datetime import datetime
from typing import Callable
import rio
from rio import Component, Row, Text, IconButton, TextStyle, Color
from rio import Component, Row, Text, TextStyle, Color
from src.ez_lan_manager import AccountingService
from src.ez_lan_manager.types.CateringOrder import CateringOrderStatus
MAX_LEN = 24

View File

@ -6,19 +6,13 @@ from src.ez_lan_manager.components.UserInfoAndLoginBox import UserInfoAndLoginBo
from src.ez_lan_manager.types.SessionStorage import SessionStorage
class DesktopNavigation(Component):
def __post_init__(self) -> None:
self.session[SessionStorage].subscribe_to_logged_in_or_out_event(self.__class__.__name__, self.refresh_cb)
async def refresh_cb(self) -> None:
await self.force_refresh()
def build(self) -> Component:
lan_info = self.session[ConfigurationService].get_lan_info()
return Card(
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(refresh_cb=self.refresh_cb),
UserInfoAndLoginBox(),
DesktopNavigationButton("News", "./news"),
Spacer(min_height=1),
DesktopNavigationButton(f"Über {lan_info.name} {lan_info.iteration}", "./overview"),

View File

@ -1,3 +1,5 @@
from typing import Optional
import rio
from rio import Component, Column, Text, TextStyle, Button, Row, ScrollContainer, Spacer
@ -11,9 +13,11 @@ from src.ez_lan_manager.types.SessionStorage import SessionStorage
class ShoppingCartAndOrders(Component):
show_cart: bool = True
orders: list[CateringOrder] = []
async def switch(self) -> None:
self.show_cart = not self.show_cart
self.orders = await self.session[CateringService].get_orders_for_user(self.session[SessionStorage].user_id)
async def on_remove_item(self, list_id: int) -> None:
catering_service = self.session[CateringService]
@ -36,7 +40,7 @@ class ShoppingCartAndOrders(Component):
if not user_id:
return
cart = catering_service.get_cart(user_id)
cart.append(catering_service.get_menu_item_by_id(article_id))
cart.append(await catering_service.get_menu_item_by_id(article_id))
catering_service.save_cart(user_id, cart)
await self.force_refresh()
@ -99,14 +103,13 @@ class ShoppingCartAndOrders(Component):
)
)
else:
orders = catering_service.get_orders_for_user(user_id)
orders_container = ScrollContainer(
content=Column(
*[CateringOrderItem(
order_id=order_item.order_id,
order_datetime=order_item.order_date,
order_status=order_item.status,
) for order_item in orders],
) for order_item in self.orders],
Spacer(grow_y=True)
),
min_height=8,

View File

@ -1,15 +1,17 @@
import logging
from random import choice
from typing import Callable
from typing import Optional
from rio import Component, Column, Text, Row, Rectangle, Button, TextStyle, Color, Spacer, TextInput, Link
from rio import Component, Column, Text, Row, Rectangle, Button, TextStyle, Color, Spacer, TextInput, Link, event
from src.ez_lan_manager import UserService
from src.ez_lan_manager.components.UserInfoBoxButton import UserInfoBoxButton
from src.ez_lan_manager.services.AccountingService import AccountingService
from src.ez_lan_manager.services.DatabaseService import NoDatabaseConnectionError, DatabaseService
from src.ez_lan_manager.services.TicketingService import TicketingService
from src.ez_lan_manager.services.SeatingService import SeatingService
from src.ez_lan_manager.types.Seat import Seat
from src.ez_lan_manager.types.Ticket import Ticket
from src.ez_lan_manager.types.User import User
from src.ez_lan_manager.types.SessionStorage import SessionStorage
logger = logging.getLogger(__name__.split(".")[-1])
@ -39,9 +41,20 @@ class StatusButton(Component):
class UserInfoAndLoginBox(Component):
refresh_cb: Callable
TEXT_STYLE = TextStyle(fill=Color.from_hex("02dac5"), font_size=0.9)
show_login: bool = True
user: Optional[User] = None
user_balance: Optional[int] = 0
user_ticket: Optional[Ticket] = None
user_seat: Optional[Seat] = None
@event.on_populate
async def async_init(self) -> None:
if self.session[SessionStorage].user_id:
self.user = await self.session[UserService].get_user(self.session[SessionStorage].user_id)
self.user_balance = await self.session[AccountingService].get_balance(self.user.user_id)
self.user_ticket = await self.session[TicketingService].get_user_ticket(self.user.user_id)
self.user_seat = await self.session[SeatingService].get_user_seat(self.user.user_id)
@staticmethod
def get_greeting() -> str:
@ -64,13 +77,13 @@ class UserInfoAndLoginBox(Component):
async def _on_login_pressed(self) -> None:
user_name = self.user_name_input.text.lower()
if self.session[UserService].is_login_valid(user_name, self.password_input.text):
if await self.session[UserService].is_login_valid(user_name, self.password_input.text):
self.user_name_input.is_valid = True
self.password_input.is_valid = True
self.login_button.is_loading = False
await self.session[SessionStorage].set_user_id(self.session[UserService].get_user(user_name).user_id)
await self.session[SessionStorage].set_user_id((await self.session[UserService].get_user(user_name)).user_id)
await self.async_init()
self.show_login = False
await self.refresh_cb()
else:
self.user_name_input.is_valid = False
self.password_input.is_valid = False
@ -114,7 +127,7 @@ class UserInfoAndLoginBox(Component):
on_press=lambda: self.session.navigate_to("./forgot-password")
)
if self.show_login and self.session[SessionStorage].user_id is None:
if self.user is None and self.session[SessionStorage].user_id is None:
return Rectangle(
content=Column(
self.user_name_input,
@ -139,25 +152,31 @@ class UserInfoAndLoginBox(Component):
margin_top=0.3,
margin_bottom=2
)
elif self.user is None and self.session[SessionStorage].user_id is not None:
return Rectangle(
content=Column(),
fill=Color.TRANSPARENT,
min_height=8,
min_width=12,
align_x=0.5,
margin_top=0.3,
margin_bottom=2
)
else:
user = self.session[UserService].get_user(self.session[SessionStorage].user_id)
if user is None:
logger.warning("User could not be found, this should not have happend.")
a_s = self.session[AccountingService]
return Rectangle(
content=Column(
Text(f"{self.get_greeting()},", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=0.9), justify="center"),
Text(f"{user.user_name}", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=1.2), justify="center"),
Text(f"{self.user.user_name}", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=1.2), justify="center"),
Row(
StatusButton(label="TICKET", target_url="./buy_ticket",
enabled=self.session[TicketingService].get_user_ticket(user.user_id) is not None),
enabled=self.user_ticket is not None),
StatusButton(label="SITZPLATZ", target_url="./seating",
enabled=self.session[SeatingService].get_user_seat(user.user_id) is not None),
enabled=self.user_seat is not None),
proportions=(50, 50),
grow_y=False
),
UserInfoBoxButton("Profil bearbeiten", "./edit-profile"),
UserInfoBoxButton(f"Guthaben: {a_s.make_euro_string_from_int(a_s.get_balance(user.user_id))}", "./account"),
UserInfoBoxButton(f"Guthaben: {self.session[AccountingService].make_euro_string_from_int(self.user_balance)}", "./account"),
Button(
content=Text("Ausloggen", style=TextStyle(fill=Color.from_hex("02dac5"), font_size=0.6)),
shape="rectangle",

View File

@ -1,22 +1,47 @@
from rio import Column, Component, event, Text, TextStyle, Button, Color, Spacer, Revealer, Row
from asyncio import sleep
from typing import Optional
from rio import Column, Component, event, Text, TextStyle, Button, Color, Spacer, Revealer, Row, ProgressCircle
from src.ez_lan_manager import ConfigurationService, UserService, AccountingService
from src.ez_lan_manager.components.MainViewContentBox import MainViewContentBox
from src.ez_lan_manager.pages import BasePage
from src.ez_lan_manager.types.SessionStorage import SessionStorage
from src.ez_lan_manager.types.Transaction import Transaction
from src.ez_lan_manager.types.User import User
class AccountPage(Component):
user: Optional[User] = None
balance: Optional[int] = None
transaction_history: list[Transaction] = list()
@event.on_populate
async def on_populate(self) -> None:
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Guthabenkonto")
self.user = await self.session[UserService].get_user(self.session[SessionStorage].user_id)
self.balance = await self.session[AccountingService].get_balance(self.user.user_id)
self.transaction_history = await self.session[AccountingService].get_transaction_history(self.user.user_id)
async def _on_banking_info_press(self):
self.banking_info_revealer.is_open = not self.banking_info_revealer.is_open
def build(self) -> Component:
user = self.session[UserService].get_user(self.session[SessionStorage].user_id)
a_s = self.session[AccountingService]
if not self.user and not self.balance:
return BasePage(
content=Column(
MainViewContentBox(
ProgressCircle(
color="secondary",
align_x=0.5,
margin_top=2,
margin_bottom=2
)
),
align_y = 0,
)
)
self.banking_info_revealer = Revealer(
header=None,
content=Column(
@ -45,7 +70,7 @@ class AccountPage(Component):
align_x=0.2
),
Text(
f"AUFLADUNG - {user.user_id} - {user.user_name}",
f"AUFLADUNG - {self.user.user_id} - {self.user.user_name}",
style=TextStyle(
fill=self.session.theme.neutral_color
),
@ -73,7 +98,7 @@ class AccountPage(Component):
)
)
for transaction in sorted(self.session[AccountingService].get_transaction_history(user.user_id), key=lambda t: t.transaction_date, reverse=True):
for transaction in sorted(self.transaction_history, key=lambda t: t.transaction_date, reverse=True):
transaction_history.add(
Row(
Text(
@ -89,7 +114,7 @@ class AccountPage(Component):
align_x=0
),
Text(
f"{'-' if transaction.is_debit else '+'}{a_s.make_euro_string_from_int(transaction.value)}",
f"{'-' if transaction.is_debit else '+'}{AccountingService.make_euro_string_from_int(transaction.value)}",
style=TextStyle(
fill=self.session.theme.danger_color if transaction.is_debit else self.session.theme.success_color,
font_size=0.8
@ -106,7 +131,7 @@ class AccountPage(Component):
content=Column(
MainViewContentBox(
content=Text(
f"Kontostand: {a_s.make_euro_string_from_int(a_s.get_balance(user.user_id))}",
f"Kontostand: {AccountingService.make_euro_string_from_int(self.balance)}",
style=TextStyle(
fill=self.session.theme.background_color,
font_size=1.2

View File

@ -4,7 +4,7 @@ from typing import * # type: ignore
from rio import Component, event, Spacer, Card, Container, Column, Row, TextStyle, Color, Text
from src.ez_lan_manager import ConfigurationService, DatabaseService
from src.ez_lan_manager import ConfigurationService
from src.ez_lan_manager.components.DesktopNavigation import DesktopNavigation
class BasePage(Component):
@ -14,11 +14,6 @@ class BasePage(Component):
async def on_window_size_change(self):
await self.force_refresh()
@event.on_populate
async def check_db_connection(self):
if not self.session[DatabaseService].is_connected:
self.session.navigate_to("./db-error")
def build(self) -> Component:
if self.content is None:
content = Spacer()

View File

@ -1,16 +1,19 @@
from rio import Column, Component, event, TextStyle, Text, Spacer, Revealer, SwitcherBar, SwitcherBarChangeEvent
from typing import Optional
from rio import Column, Component, event, TextStyle, Text, Spacer, Revealer, SwitcherBar, SwitcherBarChangeEvent, ProgressCircle
from src.ez_lan_manager import ConfigurationService, CateringService
from src.ez_lan_manager.components.CateringSelectionItem import CateringSelectionItem
from src.ez_lan_manager.components.MainViewContentBox import MainViewContentBox
from src.ez_lan_manager.components.ShoppingCartAndOrders import ShoppingCartAndOrders
from src.ez_lan_manager.pages import BasePage
from src.ez_lan_manager.types.CateringMenuItem import CateringMenuItemCategory
from src.ez_lan_manager.types.CateringMenuItem import CateringMenuItemCategory, CateringMenuItem
from src.ez_lan_manager.types.SessionStorage import SessionStorage
class CateringPage(Component):
show_cart = True
all_menu_items: Optional[list[CateringMenuItem]] = None
def __post_init__(self) -> None:
self.session[SessionStorage].subscribe_to_logged_in_or_out_event(self.__class__.__name__, self.on_user_logged_in_status_changed)
@ -18,6 +21,8 @@ class CateringPage(Component):
@event.on_populate
async def on_populate(self) -> None:
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Catering")
self.all_menu_items = await self.session[CateringService].get_menu()
async def on_user_logged_in_status_changed(self) -> None:
await self.force_refresh()
@ -25,9 +30,13 @@ class CateringPage(Component):
async def on_switcher_bar_changed(self, _: SwitcherBarChangeEvent) -> None:
await self.shopping_cart_and_orders.switch()
@staticmethod
def get_menu_items_by_category(all_menu_items: list[CateringMenuItem], category: Optional[CateringMenuItemCategory]) -> list[CateringMenuItem]:
return list(filter(lambda item: item.category == category, all_menu_items))
def build(self) -> Component:
user_id = self.session[SessionStorage].user_id
catering_service = self.session[CateringService]
self.shopping_cart_and_orders = ShoppingCartAndOrders()
switcher_bar = SwitcherBar(
values=["cart", "orders"],
@ -58,12 +67,14 @@ class CateringPage(Component):
)
) if user_id else Spacer()
return BasePage(
content=Column(
# SHOPPING CART
shopping_cart_and_orders_container,
# ITEM SELECTION
MainViewContentBox(
menu = [MainViewContentBox(
ProgressCircle(
color="secondary",
align_x=0.5,
margin_top=2,
margin_bottom=2
)
)] if not self.all_menu_items else [MainViewContentBox(
Revealer(
header="Snacks",
content=Column(
@ -75,7 +86,7 @@ class CateringPage(Component):
is_sensitive=(user_id is not None) and not catering_menu_item.is_disabled,
additional_info=catering_menu_item.additional_info,
is_grey=idx % 2 == 0
) for idx, catering_menu_item in enumerate(catering_service.get_menu(CateringMenuItemCategory.SNACK))],
) for idx, catering_menu_item in enumerate(self.get_menu_items_by_category(self.all_menu_items, CateringMenuItemCategory.SNACK))],
),
header_style=TextStyle(
fill=self.session.theme.background_color,
@ -97,7 +108,7 @@ class CateringPage(Component):
is_sensitive=(user_id is not None) and not catering_menu_item.is_disabled,
additional_info=catering_menu_item.additional_info,
is_grey=idx % 2 == 0
) for idx, catering_menu_item in enumerate(catering_service.get_menu(CateringMenuItemCategory.BREAKFAST))],
) for idx, catering_menu_item in enumerate(self.get_menu_items_by_category(self.all_menu_items, CateringMenuItemCategory.BREAKFAST))],
),
header_style=TextStyle(
fill=self.session.theme.background_color,
@ -119,7 +130,7 @@ class CateringPage(Component):
is_sensitive=(user_id is not None) and not catering_menu_item.is_disabled,
additional_info=catering_menu_item.additional_info,
is_grey=idx % 2 == 0
) for idx, catering_menu_item in enumerate(catering_service.get_menu(CateringMenuItemCategory.MAIN_COURSE))],
) for idx, catering_menu_item in enumerate(self.get_menu_items_by_category(self.all_menu_items, CateringMenuItemCategory.MAIN_COURSE))],
),
header_style=TextStyle(
fill=self.session.theme.background_color,
@ -141,7 +152,7 @@ class CateringPage(Component):
is_sensitive=(user_id is not None) and not catering_menu_item.is_disabled,
additional_info=catering_menu_item.additional_info,
is_grey=idx % 2 == 0
) for idx, catering_menu_item in enumerate(catering_service.get_menu(CateringMenuItemCategory.DESSERT))],
) for idx, catering_menu_item in enumerate(self.get_menu_items_by_category(self.all_menu_items, CateringMenuItemCategory.DESSERT))],
),
header_style=TextStyle(
fill=self.session.theme.background_color,
@ -163,7 +174,7 @@ class CateringPage(Component):
is_sensitive=(user_id is not None) and not catering_menu_item.is_disabled,
additional_info=catering_menu_item.additional_info,
is_grey=idx % 2 == 0
) for idx, catering_menu_item in enumerate(catering_service.get_menu(CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC))],
) for idx, catering_menu_item in enumerate(self.get_menu_items_by_category(self.all_menu_items, CateringMenuItemCategory.BEVERAGE_NON_ALCOHOLIC))],
),
header_style=TextStyle(
fill=self.session.theme.background_color,
@ -185,7 +196,7 @@ class CateringPage(Component):
is_sensitive=(user_id is not None) and not catering_menu_item.is_disabled,
additional_info=catering_menu_item.additional_info,
is_grey=idx % 2 == 0
) for idx, catering_menu_item in enumerate(catering_service.get_menu(CateringMenuItemCategory.BEVERAGE_ALCOHOLIC))],
) for idx, catering_menu_item in enumerate(self.get_menu_items_by_category(self.all_menu_items, CateringMenuItemCategory.BEVERAGE_ALCOHOLIC))],
),
header_style=TextStyle(
fill=self.session.theme.background_color,
@ -207,7 +218,7 @@ class CateringPage(Component):
is_sensitive=(user_id is not None) and not catering_menu_item.is_disabled,
additional_info=catering_menu_item.additional_info,
is_grey=idx % 2 == 0
) for idx, catering_menu_item in enumerate(catering_service.get_menu(CateringMenuItemCategory.BEVERAGE_COCKTAIL))],
) for idx, catering_menu_item in enumerate(self.get_menu_items_by_category(self.all_menu_items, CateringMenuItemCategory.BEVERAGE_COCKTAIL))],
),
header_style=TextStyle(
fill=self.session.theme.background_color,
@ -229,7 +240,7 @@ class CateringPage(Component):
is_sensitive=(user_id is not None) and not catering_menu_item.is_disabled,
additional_info=catering_menu_item.additional_info,
is_grey=idx % 2 == 0
) for idx, catering_menu_item in enumerate(catering_service.get_menu(CateringMenuItemCategory.BEVERAGE_SHOT))],
) for idx, catering_menu_item in enumerate(self.get_menu_items_by_category(self.all_menu_items, CateringMenuItemCategory.BEVERAGE_SHOT))],
),
header_style=TextStyle(
fill=self.session.theme.background_color,
@ -251,7 +262,7 @@ class CateringPage(Component):
is_sensitive=(user_id is not None) and not catering_menu_item.is_disabled,
additional_info=catering_menu_item.additional_info,
is_grey=idx % 2 == 0
) for idx, catering_menu_item in enumerate(catering_service.get_menu(CateringMenuItemCategory.NON_FOOD))],
) for idx, catering_menu_item in enumerate(self.get_menu_items_by_category(self.all_menu_items, CateringMenuItemCategory.NON_FOOD))],
),
header_style=TextStyle(
fill=self.session.theme.background_color,
@ -260,7 +271,14 @@ class CateringPage(Component):
margin=1,
align_y=0.5
)
),
)]
return BasePage(
content=Column(
# SHOPPING CART
shopping_cart_and_orders_container,
# ITEM SELECTION
*menu,
align_y=0
)
)

View File

@ -1,4 +1,5 @@
from datetime import datetime, timedelta
from typing import Optional
from rio import Text, Column, TextStyle, Component, event, TextInput, MultiLineTextInput, Row, Button
@ -7,6 +8,7 @@ from src.ez_lan_manager.components.AnimatedText import AnimatedText
from src.ez_lan_manager.components.MainViewContentBox import MainViewContentBox
from src.ez_lan_manager.pages import BasePage
from src.ez_lan_manager.types.SessionStorage import SessionStorage
from src.ez_lan_manager.types.User import User
class ContactPage(Component):
@ -14,10 +16,15 @@ class ContactPage(Component):
# Using list to bypass this behavior
last_message_sent: list[datetime] = [datetime(day=1, month=1, year=2000)]
display_printing: list[bool] = [False]
user: Optional[User] = None
@event.on_populate
async def on_populate(self) -> None:
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Kontakt")
if self.session[SessionStorage].user_id is not None:
self.user = await self.session[UserService].get_user(self.session[SessionStorage].user_id)
else:
self.user = None
async def on_send_pressed(self) -> None:
error_msg = ""
@ -51,11 +58,6 @@ class ContactPage(Component):
await self.animated_text.display_text(True, "Nachricht erfolgreich gesendet!")
def build(self) -> Component:
if self.session[SessionStorage].user_id is not None:
user = self.session[UserService].get_user(self.session[SessionStorage].user_id)
else:
user = None
self.animated_text = AnimatedText(
margin_top = 2,
margin_bottom = 1,
@ -64,7 +66,7 @@ class ContactPage(Component):
self.email_input = TextInput(
label="E-Mail Adresse",
text="" if not user else user.user_mail,
text="" if not self.user else self.user.user_mail,
margin_left=1,
margin_right=1,
margin_bottom=1,

View File

@ -15,12 +15,12 @@ class DbErrorPage(Component):
async def on_window_size_change(self) -> None:
await self.force_refresh()
@event.on_mount
async def retry_db_connect(self) -> None:
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Fehler")
while not self.session[DatabaseService].is_connected:
await sleep(2)
self.session.navigate_to("./")
# @event.on_mount
# async def retry_db_connect(self) -> None:
# await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Fehler")
# while not self.session[DatabaseService].is_connected:
# await sleep(2)
# self.session.navigate_to("./")
def build(self) -> Component:
content = Card(

View File

@ -3,7 +3,8 @@ from hashlib import sha256
from typing import Optional
from from_root import from_root
from rio import Column, Component, event, Text, TextStyle, Button, Color, Row, TextInput, Image, TextInputChangeEvent, NoFileSelectedError
from rio import Column, Component, event, Text, TextStyle, Button, Color, Row, TextInput, Image, TextInputChangeEvent, NoFileSelectedError, \
ProgressCircle
from email_validator import validate_email, EmailNotValidError
from src.ez_lan_manager import ConfigurationService, UserService
@ -15,6 +16,8 @@ from src.ez_lan_manager.types.User import User
class EditProfilePage(Component):
user: Optional[User] = None
pfp: Optional[bytes] = None
@staticmethod
def optional_date_to_str(d: Optional[date]) -> str:
if not d:
@ -24,6 +27,8 @@ class EditProfilePage(Component):
@event.on_populate
async def on_populate(self) -> None:
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Profil bearbeiten")
self.user = await self.session[UserService].get_user(self.session[SessionStorage].user_id)
self.pfp = await self.session[UserService].get_profile_picture(self.user.user_id)
def on_email_changed(self, change_event: TextInputChangeEvent) -> None:
try:
@ -58,7 +63,7 @@ class EditProfilePage(Component):
return
image_data = await new_pfp.read_bytes()
self.session[UserService].set_profile_picture(self.session[SessionStorage].user_id, image_data)
await self.session[UserService].set_profile_picture(self.session[SessionStorage].user_id, image_data)
self.pfp_image_container.image = image_data
await self.animated_text.display_text(True, "Gespeichert!")
@ -72,7 +77,7 @@ class EditProfilePage(Component):
await self.animated_text.display_text(False, "Passwörter nicht gleich!")
return
user: User = self.session[UserService].get_user(self.session[SessionStorage].user_id)
user: User = await self.session[UserService].get_user(self.session[SessionStorage].user_id)
user.user_mail = self.email_input.text
if len(self.birthday_input.text) == 0:
@ -86,12 +91,24 @@ class EditProfilePage(Component):
if len(self.new_pw_1_input.text.strip()) > 0:
user.user_password = sha256(self.new_pw_1_input.text.encode(encoding="utf-8")).hexdigest()
self.session[UserService].update_user(user)
await self.session[UserService].update_user(user)
await self.animated_text.display_text(True, "Gespeichert!")
def build(self) -> Component:
user = self.session[UserService].get_user(self.session[SessionStorage].user_id)
pfp = self.session[UserService].get_profile_picture(user.user_id)
if not self.user:
return BasePage(
content=Column(
MainViewContentBox(
ProgressCircle(
color="secondary",
align_x=0.5,
margin_top=2,
margin_bottom=2
)
),
align_y = 0
)
)
self.animated_text = AnimatedText(
margin_top=2,
@ -101,7 +118,7 @@ class EditProfilePage(Component):
self.email_input = TextInput(
label="E-Mail Adresse",
text=user.user_mail,
text=self.user.user_mail,
margin_left=1,
margin_right=1,
margin_bottom=1,
@ -110,20 +127,20 @@ class EditProfilePage(Component):
)
self.first_name_input = TextInput(
label="Vorname",
text=user.user_first_name,
text=self.user.user_first_name,
margin_left=1,
margin_right=1,
grow_x=True
)
self.last_name_input = TextInput(
label="Nachname",
text=user.user_last_name,
text=self.user.user_last_name,
margin_right=1,
grow_x=True
)
self.birthday_input = TextInput(
label="Geburtstag (TT.MM.JJJJ)",
text=self.optional_date_to_str(user.user_birth_day),
text=self.optional_date_to_str(self.user.user_birth_day),
margin_left=1,
margin_right=1,
margin_bottom=1,
@ -150,7 +167,7 @@ class EditProfilePage(Component):
)
self.pfp_image_container = Image(
from_root("src/ez_lan_manager/assets/img/anon_pfp.png") if pfp is None else pfp,
from_root("src/ez_lan_manager/assets/img/anon_pfp.png") if self.pfp is None else self.pfp,
align_x=0.5,
min_width=10,
min_height=10,
@ -176,8 +193,8 @@ class EditProfilePage(Component):
on_press=self.upload_new_pfp
),
Row(
TextInput(label="Deine User-ID", text=user.user_id, is_sensitive=False, margin_left=1, grow_x=False),
TextInput(label="Dein Nickname", text=user.user_name, is_sensitive=False, margin_left=1, margin_right=1, grow_x=True),
TextInput(label="Deine User-ID", text=self.user.user_id, is_sensitive=False, margin_left=1, grow_x=False),
TextInput(label="Dein Nickname", text=self.user.user_name, is_sensitive=False, margin_left=1, margin_right=1, grow_x=True),
margin_bottom=1
),
self.email_input,

View File

@ -24,11 +24,11 @@ class ForgotPasswordPage(Component):
lan_info = self.session[ConfigurationService].get_lan_info()
user_service = self.session[UserService]
mailing_service = self.session[MailingService]
user = user_service.get_user(self.email_input.text.strip())
user = await user_service.get_user(self.email_input.text.strip())
if user is not None:
new_password = "".join(choices(user_service.ALLOWED_USER_NAME_SYMBOLS, k=16))
user.user_password = sha256(new_password.encode(encoding="utf-8")).hexdigest()
user_service.update_user(user)
await user_service.update_user(user)
await mailing_service.send_email(
subject=f"Dein neues Passwort für {lan_info.name}",
body=f"Du hast für den EZ-LAN Manager der {lan_info.name} ein neues Passwort angefragt. "

View File

@ -5,37 +5,50 @@ from rio import Column, Component, event, TextStyle, Text, Button, Row, TextInpu
from src.ez_lan_manager import ConfigurationService, UserService, TicketingService, SeatingService
from src.ez_lan_manager.components.MainViewContentBox import MainViewContentBox
from src.ez_lan_manager.pages import BasePage
from src.ez_lan_manager.types.Seat import Seat
from src.ez_lan_manager.types.User import User
class GuestsPage(Component):
table_elements: list[Button] = []
users_with_tickets: list[User] = []
users_with_seats: dict[User, Seat] = {}
user_filter: Optional[str] = None
def __post_init__(self) -> None:
user_service = self.session[UserService]
all_users = user_service.get_all_users()
ticketing_service = self.session[TicketingService]
self.users_with_tickets = list(filter(lambda user: ticketing_service.get_user_ticket(user.user_id) is not None, all_users))
@event.on_populate
async def on_populate(self) -> None:
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Teilnehmer")
user_service = self.session[UserService]
all_users = await user_service.get_all_users()
ticketing_service = self.session[TicketingService]
seating_service = self.session[SeatingService]
u_w_t = []
u_w_s = {}
for user in all_users:
ticket = await ticketing_service.get_user_ticket(user.user_id)
seat = await seating_service.get_user_seat(user.user_id)
if ticket is not None:
u_w_t.append(user)
if seat is not None:
u_w_s[user] = seat
self.users_with_tickets = u_w_t
self.users_with_seats = u_w_s
def on_searchbar_content_change(self, change_event: TextInputChangeEvent) -> None:
self.user_filter = change_event.text
def build(self) -> Component:
seating_service = self.session[SeatingService]
if self.user_filter:
users = [user for user in self.users_with_tickets if self.user_filter.lower() in user.user_name or self.user_filter.lower() in str(user.user_id)]
else:
users = self.users_with_tickets
self.table_elements.clear()
for idx, user in enumerate(users):
seat = seating_service.get_user_seat(user.user_id)
try:
seat = self.users_with_seats[user]
except KeyError:
seat = None
self.table_elements.append(
Button(
content=Row(Text(text=f"{user.user_id:0>4}", align_x=0, margin_right=1), Text(text=user.user_name, grow_x=True, wrap="ellipsize"), Text(text="-" if seat is None else seat.seat_id, align_x=1)),

View File

@ -12,7 +12,7 @@ class NewsPage(Component):
@event.on_populate
async def on_populate(self) -> None:
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Neuigkeiten")
self.news_posts = self.session[NewsService].get_news()[:8]
self.news_posts = (await self.session[NewsService].get_news())[:8]
def build(self) -> Component:
posts = [NewsPost(

View File

@ -62,13 +62,13 @@ class RegisterPage(Component):
mailing_service = self.session[MailingService]
lan_info = self.session[ConfigurationService].get_lan_info()
if user_service.get_user(self.email_input.text) is not None or user_service.get_user(self.user_name_input.text) is not None:
if await user_service.get_user(self.email_input.text) is not None or await user_service.get_user(self.user_name_input.text) is not None:
await self.animated_text.display_text(False, "Benutzername oder E-Mail bereits regestriert!")
self.submit_button.is_loading = False
return
try:
new_user = user_service.create_user(self.user_name_input.text, self.email_input.text, self.pw_1.text)
new_user = await user_service.create_user(self.user_name_input.text, self.email_input.text, self.pw_1.text)
if not new_user:
raise RuntimeError("User could not be created")
except Exception as e:

View File

@ -13,8 +13,8 @@ class AccountingService:
def __init__(self, db_service: DatabaseService) -> None:
self._db_service = db_service
def add_balance(self, user_id: int, balance_to_add: int, reference: str) -> int:
self._db_service.add_transaction(Transaction(
async def add_balance(self, user_id: int, balance_to_add: int, reference: str) -> int:
await self._db_service.add_transaction(Transaction(
user_id=user_id,
value=balance_to_add,
is_debit=False,
@ -22,13 +22,13 @@ class AccountingService:
transaction_date=datetime.now()
))
logger.debug(f"Added balance of {self.make_euro_string_from_int(balance_to_add)} to user with ID {user_id}")
return self.get_balance(user_id)
return await self.get_balance(user_id)
def remove_balance(self, user_id: int, balance_to_remove: int, reference: str) -> int:
current_balance = self.get_balance(user_id)
async def remove_balance(self, user_id: int, balance_to_remove: int, reference: str) -> int:
current_balance = await self.get_balance(user_id)
if (current_balance - balance_to_remove) < 0:
raise InsufficientFundsError
self._db_service.add_transaction(Transaction(
await self._db_service.add_transaction(Transaction(
user_id=user_id,
value=balance_to_remove,
is_debit=True,
@ -36,19 +36,19 @@ class AccountingService:
transaction_date=datetime.now()
))
logger.debug(f"Removed balance of {self.make_euro_string_from_int(balance_to_remove)} to user with ID {user_id}")
return self.get_balance(user_id)
return await self.get_balance(user_id)
def get_balance(self, user_id: int) -> int:
async def get_balance(self, user_id: int) -> int:
balance_buffer = 0
for transaction in self._db_service.get_all_transactions_for_user(user_id):
for transaction in await self._db_service.get_all_transactions_for_user(user_id):
if transaction.is_debit:
balance_buffer -= transaction.value
else:
balance_buffer += transaction.value
return balance_buffer
def get_transaction_history(self, user_id: int) -> list[Transaction]:
return self._db_service.get_all_transactions_for_user(user_id)
async def get_transaction_history(self, user_id: int) -> list[Transaction]:
return await self._db_service.get_all_transactions_for_user(user_id)
@staticmethod
def make_euro_string_from_int(cent_int: int) -> str:

View File

@ -23,93 +23,93 @@ class CateringService:
# ORDERS
def place_order(self, menu_items: CateringMenuItemsWithAmount, user_id: int, is_delivery: bool = True) -> CateringOrder:
async def place_order(self, menu_items: CateringMenuItemsWithAmount, user_id: int, is_delivery: bool = True) -> CateringOrder:
for menu_item in menu_items:
if menu_item.is_disabled:
raise CateringError("Order includes disabled items")
user = self._user_service.get_user(user_id)
user = await self._user_service.get_user(user_id)
if not user:
raise CateringError("User does not exist")
total_price = sum([item.price * quantity for item, quantity in menu_items.items()])
if self._accounting_service.get_balance(user_id) < total_price:
if await self._accounting_service.get_balance(user_id) < total_price:
raise CateringError("Insufficient funds")
order = self._db_service.add_new_order(menu_items, user_id, is_delivery)
order = await self._db_service.add_new_order(menu_items, user_id, is_delivery)
if order:
self._accounting_service.remove_balance(user_id, total_price, f"CATERING - {order.order_id}")
await self._accounting_service.remove_balance(user_id, total_price, f"CATERING - {order.order_id}")
logger.info(f"User '{order.customer.user_name}' (ID:{order.customer.user_id}) ordered from catering for {self._accounting_service.make_euro_string_from_int(total_price)}")
return order
def update_order_status(self, order_id: int, new_status: CateringOrderStatus) -> bool:
async def update_order_status(self, order_id: int, new_status: CateringOrderStatus) -> bool:
if new_status == CateringOrderStatus.CANCELED:
# Cancelled orders need to be refunded
raise CateringError("Orders cannot be canceled this way, use CateringService.cancel_order")
return self._db_service.change_order_status(order_id, new_status)
return await self._db_service.change_order_status(order_id, new_status)
def get_orders(self) -> list[CateringOrder]:
return self._db_service.get_orders()
async def get_orders(self) -> list[CateringOrder]:
return await self._db_service.get_orders()
def get_orders_for_user(self, user_id: int) -> list[CateringOrder]:
return self._db_service.get_orders(user_id=user_id)
async def get_orders_for_user(self, user_id: int) -> list[CateringOrder]:
return await self._db_service.get_orders(user_id=user_id)
def get_orders_by_status(self, status: CateringOrderStatus) -> list[CateringOrder]:
return self._db_service.get_orders(status=status)
async def get_orders_by_status(self, status: CateringOrderStatus) -> list[CateringOrder]:
return await self._db_service.get_orders(status=status)
def cancel_order(self, order: CateringOrder) -> bool:
async def cancel_order(self, order: CateringOrder) -> bool:
if self._db_service.change_order_status(order.order_id, CateringOrderStatus.CANCELED):
self._accounting_service.add_balance(order.customer.user_id, order.price, f"CATERING REFUND - {order.order_id}")
await self._accounting_service.add_balance(order.customer.user_id, order.price, f"CATERING REFUND - {order.order_id}")
return True
return False
# MENU ITEMS
def get_menu(self, category: Optional[CateringMenuItemCategory] = None) -> list[CateringMenuItem]:
items = self._db_service.get_menu_items()
async def get_menu(self, category: Optional[CateringMenuItemCategory] = None) -> list[CateringMenuItem]:
items = await self._db_service.get_menu_items()
if not category:
return items
return list(filter(lambda item: item.category == category, items))
def get_menu_item_by_id(self, menu_item_id: int) -> CateringMenuItem:
item = self._db_service.get_menu_item(menu_item_id)
async def get_menu_item_by_id(self, menu_item_id: int) -> CateringMenuItem:
item = await self._db_service.get_menu_item(menu_item_id)
if not item:
raise CateringError("Menu item not found")
return item
def add_menu_item(self, name: str, info: str, price: int, category: CateringMenuItemCategory, is_disabled: bool = False) -> CateringMenuItem:
if new_item := self._db_service.add_menu_item(name, info, price, category, is_disabled):
async def add_menu_item(self, name: str, info: str, price: int, category: CateringMenuItemCategory, is_disabled: bool = False) -> CateringMenuItem:
if new_item := await self._db_service.add_menu_item(name, info, price, category, is_disabled):
return new_item
raise CateringError(f"Could not add item '{name}' to the menu.")
def remove_menu_item(self, menu_item_id: int) -> bool:
return self._db_service.delete_menu_item(menu_item_id)
async def remove_menu_item(self, menu_item_id: int) -> bool:
return await self._db_service.delete_menu_item(menu_item_id)
def change_menu_item(self, updated_item: CateringMenuItem) -> bool:
return self._db_service.update_menu_item(updated_item)
async def change_menu_item(self, updated_item: CateringMenuItem) -> bool:
return await self._db_service.update_menu_item(updated_item)
def disable_menu_item(self, menu_item_id: int) -> bool:
async def disable_menu_item(self, menu_item_id: int) -> bool:
try:
item = self.get_menu_item_by_id(menu_item_id)
item = await self.get_menu_item_by_id(menu_item_id)
except CateringError:
return False
item.is_disabled = True
return self._db_service.update_menu_item(item)
return await self._db_service.update_menu_item(item)
def enable_menu_item(self, menu_item_id: int) -> bool:
async def enable_menu_item(self, menu_item_id: int) -> bool:
try:
item = self.get_menu_item_by_id(menu_item_id)
item = await self.get_menu_item_by_id(menu_item_id)
except CateringError:
return False
item.is_disabled = False
return self._db_service.update_menu_item(item)
return await self._db_service.update_menu_item(item)
def disable_menu_items_by_category(self, category: CateringMenuItemCategory) -> bool:
items = self.get_menu(category=category)
async def disable_menu_items_by_category(self, category: CateringMenuItemCategory) -> bool:
items = await self.get_menu(category=category)
return all([self.disable_menu_item(item.item_id) for item in items])
def enable_menu_items_by_category(self, category: CateringMenuItemCategory) -> bool:
items = self.get_menu(category=category)
async def enable_menu_items_by_category(self, category: CateringMenuItemCategory) -> bool:
items = await self.get_menu(category=category)
return all([self.enable_menu_item(item.item_id) for item in items])
# CART

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
import logging
from datetime import date, datetime
from datetime import date
from typing import Optional
from src.ez_lan_manager.services.DatabaseService import DatabaseService
@ -11,21 +11,22 @@ class NewsService:
def __init__(self, db_service: DatabaseService) -> None:
self._db_service = db_service
def add_news(self, news: News) -> None:
async def add_news(self, news: News) -> None:
if news.news_id is not None:
logger.warning("Can not add news with ID, ignoring...")
return
self._db_service.add_news(news)
await self._db_service.add_news(news)
def get_news(self, dt_start: Optional[date] = None, dt_end: Optional[date] = None) -> list[News]:
async def get_news(self, dt_start: Optional[date] = None, dt_end: Optional[date] = None) -> list[News]:
if not dt_end:
dt_end = date.today()
if not dt_start:
dt_start = date(1900, 1, 1)
return self._db_service.get_news(dt_start, dt_end)
return await self._db_service.get_news(dt_start, dt_end)
def get_latest_news(self) -> Optional[News]:
async def get_latest_news(self) -> Optional[News]:
try:
return self.get_news(None, date.today())[0]
all_news = await self.get_news(None, date.today())
return all_news[0]
except IndexError:
logger.debug("There are no news to fetch")

View File

@ -36,27 +36,27 @@ class SeatingService:
ElementTree.parse(self._seating_configuration.base_svg_path).write(self._seating_plan, encoding="unicode")
def get_seating(self) -> list[Seat]:
return self._db_service.get_seating_info()
async def get_seating(self) -> list[Seat]:
return await self._db_service.get_seating_info()
def get_seat(self, seat_id: str, cached_data: Optional[list[Seat]] = None) -> Optional[Seat]:
all_seats = self.get_seating() if not cached_data else cached_data
async def get_seat(self, seat_id: str, cached_data: Optional[list[Seat]] = None) -> Optional[Seat]:
all_seats = await self.get_seating() if not cached_data else cached_data
for seat in all_seats:
if seat.seat_id == seat_id:
return seat
def get_user_seat(self, user_id: int) -> Optional[Seat]:
all_seats = self.get_seating()
async def get_user_seat(self, user_id: int) -> Optional[Seat]:
all_seats = await self.get_seating()
for seat in all_seats:
if seat.user and seat.user.user_id == user_id:
return seat
def seat_user(self, user_id: int, seat_id: str) -> None:
user_ticket = self._ticketing_service.get_user_ticket(user_id)
async def seat_user(self, user_id: int, seat_id: str) -> None:
user_ticket = await self._ticketing_service.get_user_ticket(user_id)
if not user_ticket:
raise NoTicketError
seat = self.get_seat(seat_id)
seat = await self.get_seat(seat_id)
if not seat:
raise SeatNotFoundError
@ -66,10 +66,10 @@ class SeatingService:
if seat.user is not None:
raise SeatAlreadyTakenError
self._db_service.seat_user(seat_id, user_id)
self.update_svg_with_seating_status()
await self._db_service.seat_user(seat_id, user_id)
await self.update_svg_with_seating_status()
def generate_new_seating_table(self, seating_plan_fp: Path, no_confirm: bool = False) -> None:
async def generate_new_seating_table(self, seating_plan_fp: Path, no_confirm: bool = False) -> None:
if not no_confirm:
confirm = input("WARNING: THIS ACTION WILL DELETE ALL SEATING DATA! TYPE 'AGREE' TO CONTINUE: ")
if confirm != "AGREE":
@ -95,10 +95,10 @@ class SeatingService:
except TypeError:
continue
self._db_service.generate_fresh_seats_table(sorted(seat_ids, key=lambda sd: sd[0]))
self.update_svg_with_seating_status()
await self._db_service.generate_fresh_seats_table(sorted(seat_ids, key=lambda sd: sd[0]))
await self.update_svg_with_seating_status()
def update_svg_with_seating_status(self) -> None:
async def update_svg_with_seating_status(self) -> None:
et = ElementTree.parse(self._seating_configuration.base_svg_path)
root = et.getroot()
namespace = {'svg': root.tag.split('}')[0].strip('{')} if '}' in root.tag else {}
@ -113,13 +113,13 @@ class SeatingService:
rect_g_pairs.append((last_rect, elem))
last_rect = None
all_seats = self.get_seating()
all_seats = await self.get_seating()
for rect, g in rect_g_pairs:
seat_id = self.get_seat_id_from_element(g, namespace)
if not seat_id:
continue
seat = self.get_seat(seat_id, cached_data=all_seats)
seat = await self.get_seat(seat_id, cached_data=all_seats)
if not seat.is_blocked and seat.user is None:
rect.set("fill", "rgb(102, 255, 51)")
elif not seat.is_blocked and seat.user is not None:

View File

@ -21,30 +21,30 @@ class TicketingService:
self._db_service = db_service
self._accounting_service = accounting_service
def get_total_tickets(self) -> int:
async def get_total_tickets(self) -> int:
return sum([self._lan_info.ticket_info.get_available_tickets(c) for c in self._lan_info.ticket_info.categories])
def get_available_tickets(self) -> dict[str, int]:
async def get_available_tickets(self) -> dict[str, int]:
result = self._lan_info.ticket_info.total_available_tickets
all_tickets = self._db_service.get_tickets()
all_tickets = await self._db_service.get_tickets()
for ticket in all_tickets:
result[ticket.category] -= 1
return result
def purchase_ticket(self, user_id: int, category: str) -> Ticket:
if category not in self._lan_info.ticket_info.categories or self.get_available_tickets()[category] < 1:
async def purchase_ticket(self, user_id: int, category: str) -> Ticket:
if category not in self._lan_info.ticket_info.categories or (await self.get_available_tickets())[category] < 1:
raise TicketNotAvailableError(category)
user_balance = self._accounting_service.get_balance(user_id)
user_balance = await self._accounting_service.get_balance(user_id)
if self._lan_info.ticket_info.get_price(category) > user_balance:
raise InsufficientFundsError
if self.get_user_ticket(user_id):
raise UserAlreadyHasTicketError
if new_ticket := self._db_service.generate_ticket_for_user(user_id, category):
self._accounting_service.remove_balance(
if new_ticket := await self._db_service.generate_ticket_for_user(user_id, category):
await self._accounting_service.remove_balance(
user_id,
self._lan_info.ticket_info.get_price(new_ticket.category),
f"TICKET {new_ticket.ticket_id}"
@ -54,20 +54,20 @@ class TicketingService:
raise RuntimeError("An unknown error occurred while purchasing ticket")
def refund_ticket(self, user_id: int) -> bool:
user_ticket = self.get_user_ticket(user_id)
async def refund_ticket(self, user_id: int) -> bool:
user_ticket = await self.get_user_ticket(user_id)
if not user_ticket:
return False
if self._db_service.delete_ticket(user_ticket.ticket_id):
self._accounting_service.add_balance(user_id, self._lan_info.ticket_info.get_price(user_ticket.category), f"TICKET REFUND {user_ticket.ticket_id}")
await self._accounting_service.add_balance(user_id, self._lan_info.ticket_info.get_price(user_ticket.category), f"TICKET REFUND {user_ticket.ticket_id}")
logger.debug(f"User {user_id} refunded ticket {user_ticket.ticket_id}")
return True
return False
def transfer_ticket(self, ticket_id: int, user_id: int) -> bool:
return self._db_service.change_ticket_owner(ticket_id, user_id)
async def transfer_ticket(self, ticket_id: int, user_id: int) -> bool:
return await self._db_service.change_ticket_owner(ticket_id, user_id)
def get_user_ticket(self, user_id: int) -> Optional[Ticket]:
return self._db_service.get_ticket_for_user(user_id)
async def get_user_ticket(self, user_id: int) -> Optional[Ticket]:
return await self._db_service.get_ticket_for_user(user_id)

View File

@ -17,26 +17,26 @@ class UserService:
def __init__(self, db_service: DatabaseService) -> None:
self._db_service = db_service
def get_all_users(self) -> list[User]:
return self._db_service.get_all_users()
async def get_all_users(self) -> list[User]:
return await self._db_service.get_all_users()
def get_user(self, accessor: Optional[Union[str, int]]) -> Optional[User]:
async def get_user(self, accessor: Optional[Union[str, int]]) -> Optional[User]:
if accessor is None:
return
if isinstance(accessor, int):
return self._db_service.get_user_by_id(accessor)
return await self._db_service.get_user_by_id(accessor)
accessor = accessor.lower()
if "@" in accessor:
return self._db_service.get_user_by_mail(accessor)
return self._db_service.get_user_by_name(accessor)
return await self._db_service.get_user_by_mail(accessor)
return await self._db_service.get_user_by_name(accessor)
def set_profile_picture(self, user_id: int, picture: bytes) -> None:
self._db_service.set_user_profile_picture(user_id, picture)
async def set_profile_picture(self, user_id: int, picture: bytes) -> None:
await self._db_service.set_user_profile_picture(user_id, picture)
def get_profile_picture(self, user_id: int) -> bytes:
return self._db_service.get_user_profile_picture(user_id)
async def get_profile_picture(self, user_id: int) -> bytes:
return await self._db_service.get_user_profile_picture(user_id)
def create_user(self, user_name: str, user_mail: str, password_clear_text: str) -> User:
async def create_user(self, user_name: str, user_mail: str, password_clear_text: str) -> User:
disallowed_char = self._check_for_disallowed_char(user_name)
if disallowed_char:
raise NameNotAllowedError(disallowed_char)
@ -44,17 +44,17 @@ class UserService:
user_name = user_name.lower()
hashed_pw = sha256(password_clear_text.encode(encoding="utf-8")).hexdigest()
return self._db_service.create_user(user_name, user_mail, hashed_pw)
return await self._db_service.create_user(user_name, user_mail, hashed_pw)
def update_user(self, user: User) -> User:
async def update_user(self, user: User) -> User:
disallowed_char = self._check_for_disallowed_char(user.user_name)
if disallowed_char:
raise NameNotAllowedError(disallowed_char)
user.user_name = user.user_name.lower()
return self._db_service.update_user(user)
return await self._db_service.update_user(user)
def is_login_valid(self, user_name_or_mail: str, password_clear_text: str) -> bool:
user = self.get_user(user_name_or_mail)
async def is_login_valid(self, user_name_or_mail: str, password_clear_text: str) -> bool:
user = await self.get_user(user_name_or_mail)
if not user:
return False
return user.user_password == sha256(password_clear_text.encode(encoding="utf-8")).hexdigest()

View File

@ -17,3 +17,6 @@ class User:
is_admin: bool
created_at: datetime
last_updated_at: datetime
def __hash__(self) -> int:
return hash(f"{self.user_id}{self.user_name}{self.user_mail}")