Compare commits

..

3 Commits

Author SHA1 Message Date
David Rodenkirchen
09d7178ea0 add edit profile page and default profile picture 2024-08-26 16:38:32 +02:00
David Rodenkirchen
bdae7b266b add email validator lib 2024-08-26 16:37:31 +02:00
David Rodenkirchen
473358229e make BLOB to MEDIUMBLOB 2024-08-26 16:37:19 +02:00
6 changed files with 243 additions and 3 deletions

Binary file not shown.

View File

@ -155,7 +155,7 @@ DROP TABLE IF EXISTS `user_profile_picture`;
/*!40101 SET character_set_client = utf8 */; /*!40101 SET character_set_client = utf8 */;
CREATE TABLE `user_profile_picture` ( CREATE TABLE `user_profile_picture` (
`user_id` int(11) NOT NULL, `user_id` int(11) NOT NULL,
`picture` blob DEFAULT NULL, `picture` mediumblob DEFAULT NULL,
PRIMARY KEY (`user_id`), PRIMARY KEY (`user_id`),
CONSTRAINT `fk_user_profile_picture_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION CONSTRAINT `fk_user_profile_picture_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

View File

@ -109,7 +109,7 @@ if __name__ == "__main__":
Page( Page(
name="EditProfile", name="EditProfile",
page_url="edit-profile", page_url="edit-profile",
build=lambda: pages.PlaceholderPage(placeholder_name="Profil bearbeiten"), build=pages.EditProfilePage,
guard=logged_in_guard guard=logged_in_guard
), ),
Page( Page(

View File

@ -0,0 +1,239 @@
from datetime import date, datetime
from asyncio import sleep
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 email_validator import validate_email, EmailNotValidError
from src.ez_lan_manager import ConfigurationService, UserService
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 EditProfilePage(Component):
@staticmethod
def optional_date_to_str(d: Optional[date]) -> str:
if not d:
return ""
return d.strftime("%d.%m.%Y")
@event.on_populate
async def on_populate(self) -> None:
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Profil bearbeiten")
def on_email_changed(self, change_event: TextInputChangeEvent) -> None:
try:
validate_email(change_event.text, check_deliverability=False)
self.email_input.is_valid = True
except EmailNotValidError:
self.email_input.is_valid = False
def on_birthday_changed(self, change_event: TextInputChangeEvent) -> None:
if len(change_event.text) == 0:
self.birthday_input.is_valid = True
return
try:
day, month, year = change_event.text.split(".")
year = int(year)
if year < 1900 or year > datetime.now().year - 12:
raise ValueError
date(day=int(day), month=int(month), year=year)
self.birthday_input.is_valid = True
except (ValueError, TypeError, IndexError):
self.birthday_input.is_valid = False
async def upload_new_pfp(self) -> None:
try:
new_pfp = await self.session.file_chooser(file_extensions=("png", "jpg", "jpeg"), multiple=False)
except NoFileSelectedError:
return
if new_pfp.size_in_bytes > 2 * 1_000_000:
await self.display_save_result_animation(False, optional_text="Bild zu groß! (> 2MB)")
return
image_data = await new_pfp.read_bytes()
self.session[UserService].set_profile_picture(self.session[SessionStorage].user_id, image_data)
self.pfp_image_container.image = image_data
await self.display_save_result_animation(True)
async def display_save_result_animation(self, success: bool, optional_text: Optional[str] = None) -> None:
self.saved_text.text = ""
if success:
self.saved_text.style = TextStyle(
fill=self.session.theme.success_color,
font_size=0.9
)
t = "Gespeichert!" if not optional_text else optional_text
for c in t:
self.saved_text.text = self.saved_text.text + c
await self.saved_text.force_refresh()
await sleep(0.08)
else:
self.saved_text.style = TextStyle(
fill=self.session.theme.danger_color,
font_size=0.9
)
t = "Fehler!" if not optional_text else optional_text
for c in t:
self.saved_text.text = self.saved_text.text + c
await self.saved_text.force_refresh()
await sleep(0.08)
async def on_save_pressed(self) -> None:
if not all((self.email_input.is_valid, self.birthday_input.is_valid)):
await self.display_save_result_animation(False)
return
if len(self.new_pw_1_input.text.strip()) > 0:
if self.new_pw_1_input.text.strip() != self.new_pw_2_input.text.strip():
await self.display_save_result_animation(False)
return
user: User = self.session[UserService].get_user(self.session[SessionStorage].user_id)
user.user_mail = self.email_input.text
if len(self.birthday_input.text) == 0:
user.user_birth_day = None
else:
day, month, year = self.birthday_input.text.split(".")
user.user_birth_day = date(day=int(day), month=int(month), year=int(year))
user.user_first_name = self.first_name_input.text
user.user_last_name = self.last_name_input.text
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.display_save_result_animation(True)
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)
self.saved_text = Text(
"",
margin_top=2,
margin_bottom=1,
align_x=0.1
)
self.email_input = TextInput(
label="E-Mail Adresse",
text=user.user_mail,
margin_left=1,
margin_right=1,
margin_bottom=1,
grow_x=True,
on_change=self.on_email_changed
)
self.first_name_input = TextInput(
label="Vorname",
text=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,
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),
margin_left=1,
margin_right=1,
margin_bottom=1,
grow_x=True,
on_change=self.on_birthday_changed
)
self.new_pw_1_input = TextInput(
label="Neues Passwort setzen",
text="",
margin_left=1,
margin_right=1,
margin_bottom=1,
grow_x=True,
is_secret=True
)
self.new_pw_2_input = TextInput(
label="Neues Passwort wiederholen",
text="",
margin_left=1,
margin_right=1,
margin_bottom=1,
grow_x=True,
is_secret=True
)
self.pfp_image_container = Image(
from_root("src/ez_lan_manager/assets/img/anon_pfp.png") if pfp is None else pfp,
align_x=0.5,
min_width=10,
min_height=10,
margin_top=1,
margin_bottom=1
)
return BasePage(
content=Column(
MainViewContentBox(
content=Column(
self.pfp_image_container,
Button(
content=Text(
"Neues Bild hochladen",
style=TextStyle(fill=Color.from_hex("02dac5"), font_size=0.9)
),
align_x=0.5,
margin_bottom=1,
shape="rectangle",
style="major",
color="primary",
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),
margin_bottom=1
),
self.email_input,
Row(
self.first_name_input,
self.last_name_input,
margin_bottom=1
),
self.birthday_input,
self.new_pw_1_input,
self.new_pw_2_input,
Row(
self.saved_text,
Button(
content=Text(
"Speichern",
style=TextStyle(fill=self.session.theme.success_color, font_size=0.9),
align_x=0.2
),
align_x=0.9,
margin_top=2,
margin_bottom=1,
shape="rectangle",
style="major",
color="primary",
on_press=self.on_save_pressed
),
)
)
),
align_y=0,
)
)

View File

@ -2,4 +2,5 @@ from .BasePage import BasePage
from .NewsPage import NewsPage from .NewsPage import NewsPage
from .PlaceholderPage import PlaceholderPage from .PlaceholderPage import PlaceholderPage
from .Logout import LogoutPage from .Logout import LogoutPage
from.Account import AccountPage from .Account import AccountPage
from .EditProfile import EditProfilePage