Spaces:
Sleeping
Sleeping
FauziIsyrinApridal
commited on
Commit
·
486c2a9
1
Parent(s):
1266fe8
..
Browse files- app/auth.py +56 -49
app/auth.py
CHANGED
@@ -6,41 +6,21 @@ from app.db import supabase
|
|
6 |
|
7 |
def auth_view():
|
8 |
"""Render Supabase authentication with Login, Register, and Forgot Password tabs."""
|
9 |
-
|
10 |
-
# --- Redirect handler: ubah fragment (#...) jadi query (?) sekali saja ---
|
11 |
-
st.markdown(
|
12 |
-
"""
|
13 |
-
<script>
|
14 |
-
(function(){
|
15 |
-
const hash = window.location.hash.startsWith('#') ? window.location.hash.substring(1) : window.location.hash;
|
16 |
-
if (hash && !window.__hashMigrated) {
|
17 |
-
const h = new URLSearchParams(hash);
|
18 |
-
const qp = new URLSearchParams(window.location.search);
|
19 |
-
for (const [k,v] of h.entries()) { qp.set(k, v); }
|
20 |
-
const newUrl = window.location.pathname + '?' + qp.toString();
|
21 |
-
window.history.replaceState(null, '', newUrl);
|
22 |
-
window.location.hash = '';
|
23 |
-
window.__hashMigrated = true;
|
24 |
-
window.location.replace(newUrl); // redirect bersih
|
25 |
-
}
|
26 |
-
})();
|
27 |
-
</script>
|
28 |
-
""",
|
29 |
-
unsafe_allow_html=True,
|
30 |
-
)
|
31 |
-
|
32 |
-
# --- Wrapper (centered) for all auth content ---
|
33 |
left, center, right = st.columns([1, 2, 1])
|
34 |
with center:
|
35 |
-
# Header: PNP logo
|
|
|
36 |
logo_path = os.path.join("assets", "pnp-logo.png")
|
37 |
|
|
|
38 |
def get_base64_image(path):
|
39 |
with open(path, "rb") as f:
|
40 |
return base64.b64encode(f.read()).decode()
|
41 |
|
42 |
encoded_logo = get_base64_image(logo_path)
|
43 |
|
|
|
44 |
st.markdown(
|
45 |
f"""
|
46 |
<div style="text-align:center;">
|
@@ -51,7 +31,32 @@ def auth_view():
|
|
51 |
unsafe_allow_html=True
|
52 |
)
|
53 |
|
54 |
-
# --- Password recovery
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
try:
|
56 |
qp = st.query_params # Streamlit >= 1.30
|
57 |
get_q = lambda k: qp.get(k, None)
|
@@ -77,42 +82,44 @@ def auth_view():
|
|
77 |
st.error("Token pemulihan tidak ditemukan. Coba klik ulang tautan dari email.")
|
78 |
else:
|
79 |
try:
|
|
|
80 |
supabase.auth.set_session(access_token, refresh_token)
|
|
|
81 |
supabase.auth.update_user({"password": npw})
|
82 |
st.success("Password berhasil diubah. Silakan login kembali.")
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
except Exception as e:
|
103 |
st.error(f"Gagal mengubah password: {e}")
|
|
|
104 |
return
|
105 |
|
106 |
-
#
|
107 |
tab_login, tab_register, tab_forgot = st.tabs(["Login", "Register", "Forgot Password"])
|
108 |
|
109 |
-
# Login tab
|
110 |
with tab_login:
|
111 |
with st.form("login_form"):
|
112 |
email = st.text_input("Email")
|
113 |
password = st.text_input("Password", type="password")
|
114 |
submitted = st.form_submit_button("Login")
|
115 |
if submitted:
|
|
|
116 |
shared_pw = os.getenv("APP_DEMO_PASSWORD")
|
117 |
if shared_pw and password == shared_pw:
|
118 |
st.session_state["user"] = {"id": "demo-user", "email": email or "demo@example.com"}
|
@@ -139,7 +146,6 @@ def auth_view():
|
|
139 |
except Exception as e:
|
140 |
st.error(f"Gagal login: {e}")
|
141 |
|
142 |
-
# Register tab
|
143 |
with tab_register:
|
144 |
st.caption("Buat akun baru. Anda akan menerima email konfirmasi.")
|
145 |
with st.form("register_form"):
|
@@ -152,6 +158,7 @@ def auth_view():
|
|
152 |
st.error("Password tidak sama.")
|
153 |
else:
|
154 |
try:
|
|
|
155 |
redirect_url = os.getenv(
|
156 |
"SUPABASE_EMAIL_REDIRECT",
|
157 |
os.getenv("NEXT_PUBLIC_SITE_URL", "http://localhost:8501"),
|
@@ -165,7 +172,6 @@ def auth_view():
|
|
165 |
except Exception as e:
|
166 |
st.error(f"Gagal registrasi: {e}")
|
167 |
|
168 |
-
# Forgot password tab
|
169 |
with tab_forgot:
|
170 |
st.caption("Kirim tautan reset password ke email Anda.")
|
171 |
with st.form("forgot_form"):
|
@@ -173,6 +179,7 @@ def auth_view():
|
|
173 |
submitted_f = st.form_submit_button("Kirim Link Reset")
|
174 |
if submitted_f:
|
175 |
try:
|
|
|
176 |
redirect_url = os.getenv(
|
177 |
"SUPABASE_EMAIL_REDIRECT",
|
178 |
os.getenv("NEXT_PUBLIC_SITE_URL", "http://localhost:8501"),
|
|
|
6 |
|
7 |
def auth_view():
|
8 |
"""Render Supabase authentication with Login, Register, and Forgot Password tabs."""
|
9 |
+
# Wrapper (centered) for all auth content
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
left, center, right = st.columns([1, 2, 1])
|
11 |
with center:
|
12 |
+
# Header: smaller PNP logo and centered title
|
13 |
+
# Path logo
|
14 |
logo_path = os.path.join("assets", "pnp-logo.png")
|
15 |
|
16 |
+
# Convert ke base64 biar bisa di-embed langsung
|
17 |
def get_base64_image(path):
|
18 |
with open(path, "rb") as f:
|
19 |
return base64.b64encode(f.read()).decode()
|
20 |
|
21 |
encoded_logo = get_base64_image(logo_path)
|
22 |
|
23 |
+
# Render dalam satu div center
|
24 |
st.markdown(
|
25 |
f"""
|
26 |
<div style="text-align:center;">
|
|
|
31 |
unsafe_allow_html=True
|
32 |
)
|
33 |
|
34 |
+
# --- Password recovery handler (Supabase redirect) ---
|
35 |
+
# 1) Move hash params to query params on first load, then reload once
|
36 |
+
if not st.session_state.get("_hash_migrated"):
|
37 |
+
st.markdown(
|
38 |
+
"""
|
39 |
+
<script>
|
40 |
+
(function(){
|
41 |
+
const hash = window.location.hash.startsWith('#') ? window.location.hash.substring(1) : window.location.hash;
|
42 |
+
if (hash && !window.__hashMigrated) {
|
43 |
+
const h = new URLSearchParams(hash);
|
44 |
+
const qp = new URLSearchParams(window.location.search);
|
45 |
+
for (const [k,v] of h.entries()) { qp.set(k, v); }
|
46 |
+
const newUrl = window.location.pathname + '?' + qp.toString();
|
47 |
+
window.history.replaceState(null, '', newUrl);
|
48 |
+
window.location.hash = '';
|
49 |
+
window.__hashMigrated = true;
|
50 |
+
window.location.reload();
|
51 |
+
}
|
52 |
+
})();
|
53 |
+
</script>
|
54 |
+
""",
|
55 |
+
unsafe_allow_html=True,
|
56 |
+
)
|
57 |
+
st.session_state["_hash_migrated"] = True
|
58 |
+
|
59 |
+
# 2) Read query params for recovery flow
|
60 |
try:
|
61 |
qp = st.query_params # Streamlit >= 1.30
|
62 |
get_q = lambda k: qp.get(k, None)
|
|
|
82 |
st.error("Token pemulihan tidak ditemukan. Coba klik ulang tautan dari email.")
|
83 |
else:
|
84 |
try:
|
85 |
+
# Set current session using tokens from redirect
|
86 |
supabase.auth.set_session(access_token, refresh_token)
|
87 |
+
# Update user password
|
88 |
supabase.auth.update_user({"password": npw})
|
89 |
st.success("Password berhasil diubah. Silakan login kembali.")
|
90 |
+
# Optional: clear recovery query params
|
91 |
+
try:
|
92 |
+
# Best-effort to clear params
|
93 |
+
st.markdown(
|
94 |
+
"""
|
95 |
+
<script>
|
96 |
+
(function(){
|
97 |
+
const qp = new URLSearchParams(window.location.search);
|
98 |
+
["type","access_token","refresh_token","expires_in","expires_at","token_type"].forEach(k=>qp.delete(k));
|
99 |
+
const newUrl = window.location.pathname + (qp.toString()?('?'+qp.toString()):'');
|
100 |
+
window.history.replaceState(null, '', newUrl);
|
101 |
+
})();
|
102 |
+
</script>
|
103 |
+
""",
|
104 |
+
unsafe_allow_html=True,
|
105 |
+
)
|
106 |
+
except Exception:
|
107 |
+
pass
|
|
|
108 |
except Exception as e:
|
109 |
st.error(f"Gagal mengubah password: {e}")
|
110 |
+
# When in recovery mode, do not render login/register tabs
|
111 |
return
|
112 |
|
113 |
+
# Auth tabs inside wrapper
|
114 |
tab_login, tab_register, tab_forgot = st.tabs(["Login", "Register", "Forgot Password"])
|
115 |
|
|
|
116 |
with tab_login:
|
117 |
with st.form("login_form"):
|
118 |
email = st.text_input("Email")
|
119 |
password = st.text_input("Password", type="password")
|
120 |
submitted = st.form_submit_button("Login")
|
121 |
if submitted:
|
122 |
+
# Demo password fallback
|
123 |
shared_pw = os.getenv("APP_DEMO_PASSWORD")
|
124 |
if shared_pw and password == shared_pw:
|
125 |
st.session_state["user"] = {"id": "demo-user", "email": email or "demo@example.com"}
|
|
|
146 |
except Exception as e:
|
147 |
st.error(f"Gagal login: {e}")
|
148 |
|
|
|
149 |
with tab_register:
|
150 |
st.caption("Buat akun baru. Anda akan menerima email konfirmasi.")
|
151 |
with st.form("register_form"):
|
|
|
158 |
st.error("Password tidak sama.")
|
159 |
else:
|
160 |
try:
|
161 |
+
# Prefer explicit env, then generic site URL, then localhost for dev
|
162 |
redirect_url = os.getenv(
|
163 |
"SUPABASE_EMAIL_REDIRECT",
|
164 |
os.getenv("NEXT_PUBLIC_SITE_URL", "http://localhost:8501"),
|
|
|
172 |
except Exception as e:
|
173 |
st.error(f"Gagal registrasi: {e}")
|
174 |
|
|
|
175 |
with tab_forgot:
|
176 |
st.caption("Kirim tautan reset password ke email Anda.")
|
177 |
with st.form("forgot_form"):
|
|
|
179 |
submitted_f = st.form_submit_button("Kirim Link Reset")
|
180 |
if submitted_f:
|
181 |
try:
|
182 |
+
# Prefer explicit env, then generic site URL, then localhost for dev
|
183 |
redirect_url = os.getenv(
|
184 |
"SUPABASE_EMAIL_REDIRECT",
|
185 |
os.getenv("NEXT_PUBLIC_SITE_URL", "http://localhost:8501"),
|