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}")