Spaces:
Sleeping
Sleeping
File size: 9,376 Bytes
daa81fb b17b0dd daa81fb 486c2a9 daa81fb 245e2db daa81fb ba4a352 5b8619b b17b0dd 4119d3c b17b0dd 5b8619b b17b0dd ba4a352 5b8619b b17b0dd 5b8619b b17b0dd 5dd6e15 245e2db 1b6f6c4 245e2db 0a5edbb 245e2db 0a5edbb 245e2db 1b6f6c4 245e2db 1b6f6c4 245e2db 0a5edbb ba4a352 245e2db ba4a352 245e2db 0a5edbb 245e2db daa81fb 245e2db 1b6f6c4 daa81fb 245e2db daa81fb 245e2db 1b6f6c4 245e2db daa81fb 1b6f6c4 daa81fb 245e2db daa81fb 245e2db daa81fb 245e2db daa81fb 245e2db daa81fb 245e2db 1b6f6c4 245e2db daa81fb 245e2db daa81fb 245e2db d99d7ed 245e2db daa81fb 245e2db daa81fb 245e2db daa81fb 245e2db daa81fb 245e2db daa81fb 245e2db d99d7ed 245e2db |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
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"""
<div style="text-align:center;">
<img src="data:image/png;base64,{encoded_logo}" width="100">
<h1 style="margin-top:0.25rem;">PNP bot</h1>
</div>
""",
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(
"""
<script>
(function() {
try {
const hash = window.location.hash;
console.log('DEBUG: Hash found:', hash);
if (hash && hash.length > 1 && !sessionStorage.getItem("hash_migrated")) {
const query = hash.substring(1);
const newUrl = window.location.pathname + "?" + query;
sessionStorage.setItem("hash_migrated", "true");
window.history.replaceState(null, "", newUrl);
window.location.reload();
}
} catch (e) {
console.error('Hash migration error:', e);
}
})();
</script>
""",
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}")
|