110 lines
4.9 KiB
Python
110 lines
4.9 KiB
Python
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 not is_valid: # Migrated users
|
|
user_name = user_name.lower().capitalize()
|
|
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
|
|
)
|