import os
import base64
import streamlit as st
from app.db import supabase
from urllib.parse import parse_qsl
def auth_view():
"""Render Supabase authentication with Login, Register, and Forgot Password tabs."""
# Wrapper (centered) for all auth content
left, center, right = st.columns([1, 2, 1])
with center:
# Header: PNP logo + title
logo_path = os.path.join("assets", "pnp-logo.png")
def get_base64_image(path):
with open(path, "rb") as f:
return base64.b64encode(f.read()).decode()
encoded_logo = get_base64_image(logo_path)
st.markdown(
f"""
PNP bot
""",
unsafe_allow_html=True
)
# --- Auto convert hash (#) to query (?) using streamlit-url-fragment ---
fragment_detected = False
try:
from streamlit_url_fragment import get_fragment
fragment = get_fragment()
if fragment and not st.session_state.get("hash_migrated"):
# Remove leading # if present and parse fragment parameters
clean_fragment = fragment.lstrip('#')
params = dict(parse_qsl(clean_fragment))
if params.get("type") == "recovery" and params.get("access_token"):
# Set query params so existing recovery flow works
if hasattr(st, "query_params"):
for key, value in params.items():
st.query_params[key] = value
else:
st.experimental_set_query_params(**params)
st.session_state["hash_migrated"] = True
fragment_detected = True
st.rerun()
except Exception:
pass
# Always run JS fallback for reliability
if not fragment_detected:
st.markdown(
"""
""",
unsafe_allow_html=True
)
# --- Recovery flow ---
if hasattr(st, "query_params"):
qp = st.query_params
get_q = lambda k: qp.get(k)
else:
qp = st.experimental_get_query_params()
get_q = lambda k: (qp.get(k, [None])[0] if isinstance(qp.get(k, None), list) else qp.get(k))
q_type = get_q("type")
if q_type == "recovery":
st.info("Reset password: silakan masukkan password baru Anda.")
access_token = get_q("access_token")
refresh_token = get_q("refresh_token")
with st.form("reset_password_form"):
npw = st.text_input("Password Baru", type="password")
npw2 = st.text_input("Konfirmasi Password Baru", type="password")
submit_reset = st.form_submit_button("Set Password Baru")
if submit_reset:
if not npw or len(npw) < 6:
st.error("Password minimal 6 karakter.")
elif npw != npw2:
st.error("Konfirmasi password tidak sama.")
elif not access_token or not refresh_token:
st.error("Token pemulihan tidak ditemukan. Coba klik ulang tautan dari email.")
else:
try:
# Set session temporarily to update password
supabase.auth.set_session(access_token, refresh_token)
supabase.auth.update_user({"password": npw})
# Sign out after password update
supabase.auth.sign_out()
st.success("Password berhasil diubah. Silakan login dengan password baru.")
# Clear session and query params
if hasattr(st, "query_params"):
st.query_params.clear()
else:
st.experimental_set_query_params()
st.session_state.clear()
st.rerun()
except Exception as e:
st.error(f"Gagal mengubah password: {e}")
return
# --- Auth tabs ---
tab_login, tab_register, tab_forgot = st.tabs(["Login", "Register", "Forgot Password"])
# LOGIN
with tab_login:
with st.form("login_form"):
email = st.text_input("Email")
password = st.text_input("Password", type="password")
submitted = st.form_submit_button("Login")
if submitted:
shared_pw = os.getenv("APP_DEMO_PASSWORD")
if shared_pw and password == shared_pw:
st.session_state["user"] = {"id": "demo-user", "email": email or "demo@example.com"}
st.success("Login demo berhasil")
st.rerun()
try:
auth_res = supabase.auth.sign_in_with_password({
"email": email,
"password": password,
})
user = getattr(auth_res, "user", None)
if user:
st.session_state["user"] = {"id": user.id, "email": getattr(user, "email", email)}
session_obj = getattr(auth_res, "session", None)
if session_obj:
st.session_state["sb_session"] = {
"access_token": getattr(session_obj, "access_token", None),
"refresh_token": getattr(session_obj, "refresh_token", None),
}
st.success("Login berhasil")
st.rerun()
else:
st.error("Email atau password salah.")
except Exception as e:
st.error(f"Gagal login: {e}")
# REGISTER
with tab_register:
st.caption("Buat akun baru. Anda akan menerima email konfirmasi.")
with st.form("register_form"):
r_email = st.text_input("Email", key="reg_email")
r_password = st.text_input("Password", type="password", key="reg_password")
r_password2 = st.text_input("Konfirmasi Password", type="password", key="reg_password2")
submitted_r = st.form_submit_button("Register")
if submitted_r:
if r_password != r_password2:
st.error("Password tidak sama.")
else:
try:
redirect_url = os.getenv(
"SUPABASE_EMAIL_REDIRECT",
os.getenv("NEXT_PUBLIC_SITE_URL", "https://yozora721-pnp-chatbot-v1.hf.space"),
)
supabase.auth.sign_up({
"email": r_email,
"password": r_password,
"options": {"email_redirect_to": redirect_url}
})
st.success("Registrasi berhasil. Silakan cek email untuk konfirmasi.")
except Exception as e:
st.error(f"Gagal registrasi: {e}")
# FORGOT PASSWORD
with tab_forgot:
st.caption("Kirim tautan reset password ke email Anda.")
with st.form("forgot_form"):
f_email = st.text_input("Email", key="forgot_email")
submitted_f = st.form_submit_button("Kirim Link Reset")
if submitted_f:
try:
redirect_url = os.getenv(
"SUPABASE_EMAIL_REDIRECT",
os.getenv("NEXT_PUBLIC_SITE_URL", "https://yozora721-pnp-chatbot-v1.hf.space"),
)
supabase.auth.reset_password_for_email(f_email, {"redirect_to": redirect_url})
st.success("Email reset password telah dikirim. Periksa kotak masuk Anda.")
except Exception as e:
st.error(f"Gagal mengirim email reset password: {e}")