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']