import streamlit as st from datetime import datetime from supabase import create_client, Client from utilities_option_menu.option_menu import option_menu import utilities_database.user_database_utils as db_utils from utilities_database.user_database_utils import check_usr_pass from utilities_cookies.encrypted_cookie_manager import EncryptedCookieManager DB_URL = st.secrets['SUPABASE_URL'] DB_KEY = st.secrets['SUPABASE_KEY'] Client = create_client(DB_URL, DB_KEY) user_login_table = Client.table('UserLogIn') user_save_text_table = Client.table('TaskData') st.set_page_config(page_title='GenLexTasksEnter', layout="wide", page_icon=':es:') login_call = 'Зарегистрироваться' class LogIn: """ Builds the UI for the Login/ Sign Up page. """ def __init__(self, auth_token: str, company_name: str, width, height, logout_button_name: str = 'Logout', hide_menu_bool: bool = False, hide_footer_bool: bool = False, lottie_url: str = "https://assets8.lottiefiles.com/packages/lf20_ktwnwv5m.json"): """ Arguments: ----------- 1. self 2. auth_token : The unique authorization token received from - https://www.courier.com/email-api/ 3. company_name : This is the name of the person/ organization which will send the password reset email. 4. width : Width of the animation on the login page. 5. height : Height of the animation on the login page. 6. logout_button_name : The logout button name. 7. hide_menu_bool : Pass True if the streamlit menu should be hidden. 8. hide_footer_bool : Pass True if the 'made with streamlit' footer should be hidden. 9. lottie_url : The lottie animation you would like to use on the login page. Explore animations at - https://lottiefiles.com/featured """ self.auth_token = auth_token self.company_name = company_name self.width = width self.height = height self.logout_button_name = logout_button_name self.hide_menu_bool = hide_menu_bool self.hide_footer_bool = hide_footer_bool self.lottie_url = lottie_url self.cookies = EncryptedCookieManager( prefix="streamlit_login_ui_yummy_cookies", password='9d68d6f2-4258-45c9-96eb-2d6bc74ddbb5-d8f49cab-edbb-404a-94d0-b25b1d4a564b') if not self.cookies.ready(): st.stop() def get_user_name(self): if not st.session_state['LOGOUT_BUTTON_HIT']: fetched_cookies = self.cookies if '__streamlit_login_signup_ui_username__' in fetched_cookies.keys(): user_name = fetched_cookies['__streamlit_login_signup_ui_username__'] return user_name def login_widget(self) -> None: """ Creates the login widget, checks and sets cookies, authenticates the users. """ # Checks if cookie exists. if not st.session_state['LOGGED_IN'] and not st.session_state['LOGOUT_BUTTON_HIT']: fetched_cookies = self.cookies if '__streamlit_login_signup_ui_username__' in fetched_cookies.keys(): if fetched_cookies['__streamlit_login_signup_ui_username__'] \ != '1c9a923f-fb21-4a91-b3f3-5f18e3f01182': st.session_state['LOGGED_IN'] = True if not st.session_state['LOGGED_IN']: st.session_state['LOGOUT_BUTTON_HIT'] = False del_login = st.empty() with del_login.form("Login Form"): user_name = st.text_input("Имя пользователя", placeholder='Ваше имя пользователя') password = st.text_input("Пароль", placeholder='Ваш пароль', type='password') login_submit_button = st.form_submit_button(label='Войти') if login_submit_button: authenticate_user_check = check_usr_pass(user_log_in_database=user_login_table, user_name=user_name, password=password) if not authenticate_user_check: st.error("Неверное имя пользователя или пароль!") else: st.session_state['LOGGED_IN'] = True st.session_state['-USER_NAME-'] = user_name self.cookies['__streamlit_login_signup_ui_username__'] = user_name self.cookies.save() del_login.empty() st.rerun() @staticmethod def sign_up_widget() -> None: """ Creates the sign-up widget and stores the user info in a secure way in the _secret_auth_.json file. """ with st.form("Sign Up Form"): name_sign_up = st.text_input("Имя *", placeholder='Введите Ваше имя') valid_name_check = db_utils.check_valid_name(name_sign_up) email_sign_up = st.text_input("E-mail *", placeholder='Введите Ваш e-mail') valid_email_check = db_utils.check_valid_email(email_sign_up) unique_email_check = db_utils.check_unique_email(user_log_in_database=user_login_table, email_sign_up=email_sign_up) user_name_sign_up = st.text_input("Имя пользователя *", placeholder='Введите имя пользователя (латинские буквы и символы)') unique_user_name_check = db_utils.check_unique_usr(user_log_in_database=user_login_table, user_name_sign_up=user_name_sign_up) password_sign_up = st.text_input("Пароль *", placeholder='Введите пароль', type='password') professional_level = st.radio('Вы являетесь преподавателем испанского языка? *', options=['Да', 'Нет'], index=1, horizontal=True) st.markdown("\* Обязательное поле") sign_up_submit_button = st.form_submit_button(label=login_call) if sign_up_submit_button: if not valid_name_check: st.error("Пожалуйста, ведите Ваше имя!") elif not valid_email_check: st.error("Пожалуйста, введите действующий е-mail!") elif not unique_email_check: st.error("Пользователь с этим e-mail уже зарегистрирован!") elif not unique_user_name_check: st.error(f'Извините, пользователь с таким именем ({user_name_sign_up}) уже существует!') elif unique_user_name_check is None: st.error('Пожалуйста, введите имя пользователя!') if valid_name_check: if valid_email_check and unique_email_check and unique_user_name_check: db_utils.register_new_usr(user_log_in_database=user_login_table, name_sign_up=name_sign_up, email_sign_up=email_sign_up, user_name_sign_up=user_name_sign_up, password_sign_up=password_sign_up, professional_level=professional_level, created_at=str(datetime.now())[:-7]) st.success("Регистрация прошла успешно!") def forgot_password(self) -> None: """ Creates the forgot password widget and after user authentication (e-mail), triggers an e-mail to the user containing a random password. """ with st.form("Forgot Password Form"): email_forgot_passwd = st.text_input("Email", placeholder='Введите Ваш email') email_exists_check, user_name_forgot_passwd = db_utils.check_email_exists( user_log_in_database=user_login_table, email_forgot_passwd=email_forgot_passwd) forgot_passwd_submit_button = st.form_submit_button(label='Получить пароль') if forgot_passwd_submit_button: if not email_exists_check: st.error("Пользователя с таким e-mail не существует!") if email_exists_check: random_password = db_utils.generate_random_passwd() db_utils.send_passwd_in_email(self.auth_token, user_name_forgot_passwd, email_forgot_passwd, self.company_name, random_password) db_utils.change_passwd(user_log_in_database=user_login_table, email_forgot_passwd=email_forgot_passwd, random_password=random_password) st.success("Временный пароль выслан Вам на почту!") @staticmethod def reset_password() -> None: """ Creates the reset password widget and after user authentication (e-mail and the password shared over that e-mail), resets the password and updates the same in the _secret_auth_.json file. """ with st.form("Reset Password Form"): email_reset_passwd = st.text_input("Email", placeholder='Please enter your email') current_passwd = st.text_input("Временный пароль", placeholder='Введите пароль, который вы получили в письме') new_passwd = st.text_input("Новый пароль", placeholder='Введите новый пароль', type='password') new_passwd_1 = st.text_input("Повторите новый пароль", placeholder='Повторите пароль', type='password') reset_passwd_submit_button = st.form_submit_button(label='Изменить пароль') if reset_passwd_submit_button: email_exists_check, user_name_reset_passwd = db_utils.check_email_exists( user_log_in_database=user_login_table, email_forgot_passwd=email_reset_passwd) current_passwd_check = db_utils.check_current_passwd(user_log_in_database=user_login_table, email_reset_passwd=email_reset_passwd, current_passwd=current_passwd) if not email_exists_check: st.error("Пользователя с таким e-mail не существует!") elif not current_passwd_check: st.error("Неверный временный пароль!") elif new_passwd != new_passwd_1: st.error("Пароли не совпадают!") if email_exists_check and current_passwd_check: db_utils.change_passwd(user_log_in_database=user_login_table, email_forgot_passwd=email_reset_passwd, random_password=new_passwd) st.success("Пароль успешно изменен!") def logout_widget(self) -> None: """ Creates the logout widget in the sidebar only if the user is logged in. """ if st.session_state['LOGGED_IN']: del_logout = st.sidebar.empty() del_logout.markdown("#") logout_click_check = del_logout.button(self.logout_button_name) if logout_click_check: st.session_state['LOGOUT_BUTTON_HIT'] = True st.session_state['LOGGED_IN'] = False self.cookies['__streamlit_login_signup_ui_username__'] = '1c9a923f-fb21-4a91-b3f3-5f18e3f01182' del_logout.empty() st.rerun() @staticmethod def navigation(): """ Creates the side navigation bar """ selected_option = option_menu( menu_title='Навигация', menu_icon='list-columns-reverse', icons=['box-arrow-in-right', 'person-plus', 'x-circle', 'arrow-counterclockwise'], options=['Вход', login_call, 'Забыли пароль?', 'Восстановление пароля'], default_index=0, styles={ "container": {"padding": "10px", "text-align": "left"}, "nav-link": {"font-size": "16px", "text-align": "left", "margin": "0px"}}) return selected_option @staticmethod def hide_menu() -> None: """ Hides the streamlit menu situated in the top right. """ st.markdown(""" """, unsafe_allow_html=True) @staticmethod def hide_header() -> None: """ Hides the 'made with streamlit' footer. """ st.markdown(""" """, unsafe_allow_html=True) @staticmethod def hide_footer() -> None: """ Hides the 'made with streamlit' footer. """ st.markdown(""" """, unsafe_allow_html=True) def build_login_ui(self): """ Brings everything together, calls important functions. """ if 'LOGGED_IN' not in st.session_state: st.session_state['LOGGED_IN'] = False if 'LOGOUT_BUTTON_HIT' not in st.session_state: st.session_state['LOGOUT_BUTTON_HIT'] = False selected_option = self.navigation() if selected_option == 'Вход': c1, c2 = st.columns([7, 3]) with c1: self.login_widget() with c2: if not st.session_state['LOGGED_IN']: pass # self.animation() if selected_option == login_call: self.sign_up_widget() if selected_option == 'Забыли пароль?': self.forgot_password() if selected_option == 'Восстановление пароля': self.reset_password() self.logout_widget() if st.session_state['LOGGED_IN']: pass if self.hide_menu_bool: self.hide_menu() if self.hide_footer_bool: self.hide_footer() return st.session_state['LOGGED_IN']