prerelease/0.6.0 (#1)

Co-authored-by: David Rodenkirchen <drodenkirchen@linetco.com>
Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
2026-05-27 23:17:52 +00:00
parent ef685bba40
commit 1753d67752
93 changed files with 5354 additions and 2 deletions
+106
View File
@@ -0,0 +1,106 @@
from __future__ import annotations
from copy import copy
from typing import Any, Optional
from uuid import uuid4
from rio import Component, Column, Row, Text, Spacer, page, Color, Rectangle, TextInput, GuardEvent
from elm.types import UserSession, User
from elm.services import UserService, LocalData, LocalDataService, ConfigurationService
from elm.components import ElmButton
def login_page_guard(event: GuardEvent) -> Optional[str]:
try:
_ = event.session[UserSession].user_name
return "/"
except KeyError:
return None
@page(name="Login", url_segment="login", guard=login_page_guard)
class LoginPage(Component):
user_name: str = ""
password: str = ""
error_on_last_attempt: bool = False
login_in_progress: bool = False
async def on_login_confirmed(self, _: Any) -> None:
""" Handler for pressing ENTER inside the text inputs """
await self.on_login_pressed()
async def on_login_pressed(self) -> None:
self.login_in_progress = True
user_name = copy(self.user_name) # Prevents race condition name swap
is_valid = await self.session[UserService].is_login_valid(user_name, self.password)
if is_valid:
user: User = await self.session[UserService].get_user(user_name)
self.error_on_last_attempt = False
user_session = UserSession(id=uuid4(), user_name=user.user_name, is_team_member=user.is_team_member)
self.session.attach(user_session)
token = self.session[LocalDataService].set_session(user_session)
self.session[LocalData].stored_session_token = token
self.session[UserSession].profile_picture = await self.load_user_picture()
self.session.attach(self.session[LocalData])
self.login_in_progress = False
self.session.navigate_to("./")
else:
self.login_in_progress = False
self.error_on_last_attempt = True
async def load_user_picture(self) -> bytes:
try:
user_picture = await self.session[UserService].get_user_picture(self.session[UserSession].user_name)
if user_picture is not None and len(user_picture) > 0:
return user_picture
except KeyError:
return self.session[ConfigurationService].DEFAULT_PROFILE_PICTURE
return self.session[ConfigurationService].DEFAULT_PROFILE_PICTURE
def on_register_pressed(self) -> None:
self.session.navigate_to("./register")
def on_lost_password_pressed(self) -> None:
self.session.navigate_to("./lost-pw")
def build(self) -> Component:
return Row(
Rectangle(
content=Column(
Rectangle(
content=Rectangle(
content=Text("Login", margin=0.5, selectable=False, overflow="wrap"),
fill=self.session.theme.header_box_background_color,
margin=0.4
),
stroke_width=0.1,
stroke_color=self.session.theme.box_border_color,
),
Column(
TextInput(
text=self.bind().user_name,
label="Nutzername",
on_confirm=self.on_login_confirmed
),
TextInput(
text=self.bind().password,
label="Passwort",
is_secret=True,
on_confirm=self.on_login_confirmed
),
Text("Falscher Nutzername oder Passwort", fill=self.session.theme.danger_color, overflow="wrap", justify="center") if self.error_on_last_attempt else Spacer(grow_x=False, grow_y=False),
ElmButton(text="Login", style="small" if self.session.is_mobile() else "normal", on_press=self.on_login_pressed, is_loading=self.login_in_progress),
ElmButton(text="Passwort\nvergessen" if self.session.is_mobile() else "Passwort vergessen", style="small" if self.session.is_mobile() else "normal", on_press=self.on_lost_password_pressed),
ElmButton(text="Account anlegen", style="small" if self.session.is_mobile() else "normal", on_press=self.on_register_pressed),
margin=1,
spacing=1
),
Spacer()
),
fill=self.session.theme.box_color,
stroke_width=0.1,
stroke_color=self.session.theme.box_border_color,
min_height=15
),
align_x=0.5,
align_y=0.5
)