add is_active to login, add account and seating management to user management, redirect to base page on logout

This commit is contained in:
David Rodenkirchen
2024-11-30 12:32:31 +01:00
parent 18ff806d3b
commit 82b16b868f
4 changed files with 259 additions and 35 deletions
+161 -13
View File
@@ -1,26 +1,26 @@
import logging
from dataclasses import field
from typing import Optional, Coroutine
from typing import Optional
import rio
from rio import Column, Component, event, TextStyle, Text, TextInput, ThemeContextSwitcher, Grid, \
PointerEventListener, PointerEvent, Rectangle, CursorStyle, Color, TextInputChangeEvent, Spacer
PointerEventListener, PointerEvent, Rectangle, CursorStyle, Color, TextInputChangeEvent, Spacer, Row, Switch, \
SwitchChangeEvent, EventHandler
from src.ez_lan_manager import ConfigurationService, UserService
from src.ez_lan_manager import ConfigurationService, UserService, AccountingService, SeatingService
from src.ez_lan_manager.components.MainViewContentBox import MainViewContentBox
from src.ez_lan_manager.components.NewTransactionForm import NewTransactionForm
from src.ez_lan_manager.components.UserEditForm import UserEditForm
from src.ez_lan_manager.services.AccountingService import InsufficientFundsError
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
logger = logging.getLogger(__name__.split(".")[-1])
# Helps type checker grasp the concept of "lambda _: None" as a Coroutine
async def noop(_) -> None:
pass
class ClickableGridContent(Component):
text: str = ""
is_hovered: bool = False
clicked_cb: Coroutine = noop
clicked_cb: EventHandler[str] = None
async def on_mouse_enter(self, _: PointerEvent) -> None:
self.is_hovered = True
@@ -29,9 +29,9 @@ class ClickableGridContent(Component):
self.is_hovered = False
async def on_mouse_click(self, _: PointerEvent) -> None:
await self.clicked_cb(self.text)
await self.call_event_handler(self.clicked_cb, self.text)
def build(self) -> rio.Component:
def build(self) -> Component:
return PointerEventListener(
content=Rectangle(
content=Text(
@@ -51,19 +51,63 @@ class ManageUsersPage(Component):
selected_user: Optional[User] = None
all_users: Optional[list] = None
search_results: list[User] = field(default_factory=list)
accounting_section_result_text: str = ""
accounting_section_result_success: bool = True
user_account_balance: str = "0.00 €"
user_seat: str = "-"
is_user_account_locked: bool = False
@event.on_populate
async def on_populate(self) -> None:
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - News Verwaltung")
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Nutzer Verwaltung")
self.all_users = await self.session[UserService].get_all_users()
self.search_results = self.all_users
async def on_user_clicked(self, user_name: str) -> None:
self.selected_user = next(filter(lambda user: user.user_name == user_name, self.all_users))
user_account_balance_raw = await self.session[AccountingService].get_balance(self.selected_user.user_id)
self.user_account_balance = AccountingService.make_euro_string_from_int(user_account_balance_raw)
seat = await self.session[SeatingService].get_user_seat(self.selected_user.user_id)
self.user_seat = seat.seat_id if seat else "-"
self.is_user_account_locked = not self.selected_user.is_active
async def on_search_parameters_changed(self, e: TextInputChangeEvent) -> None:
self.search_results = list(filter(lambda user: (e.text.lower() in user.user_name.lower()) or e.text.lower() in str(user.user_id), self.all_users))
async def change_account_active(self, _: SwitchChangeEvent) -> None:
self.selected_user.is_active = not self.is_user_account_locked
await self.session[UserService].update_user(self.selected_user)
async def on_new_transaction(self, transaction: Transaction) -> None:
if not self.session[SessionStorage].is_team_member: # Better safe than sorry
return
logger.info(f"Got new transaction for user with ID '{transaction.user_id}' over "
f"{'-' if transaction.is_debit else '+'}"
f"{AccountingService.make_euro_string_from_int(transaction.value)} "
f"with reference '{transaction.reference}'")
if transaction.is_debit:
try:
await self.session[AccountingService].remove_balance(
transaction.user_id,
transaction.value,
transaction.reference
)
except InsufficientFundsError:
self.accounting_section_result_text = "Guthaben nicht ausreichend!"
self.accounting_section_result_success = False
return
else:
await self.session[AccountingService].add_balance(
transaction.user_id,
transaction.value,
transaction.reference
)
self.accounting_section_result_text = f"Guthaben {'entfernt' if transaction.is_debit else 'hinzugefügt'}!"
self.accounting_section_result_success = True
def build(self) -> Component:
return Column(
@@ -128,6 +172,110 @@ class ManageUsersPage(Component):
margin_top=2,
margin_bottom=2,
align_x=0.5
))),
)
)
),
MainViewContentBox(
Column(
Text(
text="Konto & Sitzplatz",
style=TextStyle(
fill=self.session.theme.background_color,
font_size=1.2
),
margin_top=2,
margin_bottom=2,
align_x=0.5
),
Row(
Text(
text="Kontostand:",
style=TextStyle(
fill=self.session.theme.background_color,
font_size=1
),
margin_top=0.5,
margin_bottom=1,
margin_left=2
),
Text(
text=self.bind().user_account_balance,
style=TextStyle(
fill=self.session.theme.neutral_color,
font_size=1
),
margin_top=0.5,
margin_bottom=1,
margin_right=2,
justify="right"
),
),
Row(
Text(
text="Kontosperrung:",
style=TextStyle(
fill=self.session.theme.background_color,
font_size=1
),
margin_top=0.5,
margin_bottom=1,
margin_left=2,
grow_x=True
),
ThemeContextSwitcher(
content=Switch(
is_on=self.bind().is_user_account_locked,
margin_top=0.5,
margin_bottom=1,
margin_right=2,
on_change=self.change_account_active
),
color="primary"
),
),
Row(
Text(
text="Sitzplatz:",
style=TextStyle(
fill=self.session.theme.background_color,
font_size=1
),
margin_top=0.5,
margin_bottom=1,
margin_left=2
),
Text(
text=self.bind().user_seat,
style=TextStyle(
fill=self.session.theme.neutral_color,
font_size=1
),
margin_top=0.5,
margin_bottom=1,
margin_right=2,
justify="right"
),
),
Text(
text="Geld hinzufügen/entfernen",
style=TextStyle(
fill=self.session.theme.background_color,
font_size=1
),
margin_top=0.5,
margin_bottom=1,
align_x=0.5
),
NewTransactionForm(user=self.selected_user, new_transaction_cb=self.on_new_transaction),
Text(
text=self.bind().accounting_section_result_text,
style=TextStyle(
fill=self.session.theme.success_color if self.accounting_section_result_success else self.session.theme.danger_color
),
margin_left=1,
margin_bottom=1
)
)
) if self.selected_user else Spacer(),
align_y=0
)