Spaces:
Running
Running
Commit ·
4b022cd
1
Parent(s): cc01c7a
feat: add password reset functionality
Browse files- frontend/app.py +16 -2
- frontend/firebase_utils.py +25 -0
frontend/app.py
CHANGED
|
@@ -44,7 +44,7 @@ import uuid
|
|
| 44 |
from PIL import Image
|
| 45 |
from streamlit_drawable_canvas import st_canvas
|
| 46 |
from dotenv import load_dotenv
|
| 47 |
-
from firebase_utils import sign_in_with_email, sign_up_with_email
|
| 48 |
|
| 49 |
logging.basicConfig(level=logging.INFO)
|
| 50 |
logger = logging.getLogger(__name__)
|
|
@@ -374,7 +374,7 @@ def _render_login():
|
|
| 374 |
</div>
|
| 375 |
""", unsafe_allow_html=True)
|
| 376 |
|
| 377 |
-
tab_in, tab_up = st.tabs(["Login", "Sign Up"])
|
| 378 |
|
| 379 |
with tab_in:
|
| 380 |
with st.form("login_form"):
|
|
@@ -412,6 +412,20 @@ def _render_login():
|
|
| 412 |
else:
|
| 413 |
st.error("Please fill all fields.")
|
| 414 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 415 |
st.markdown(
|
| 416 |
"<p style='text-align:center;font-size:0.8rem;color:#6b7280;'>Powered by Gemini & SymPy</p>",
|
| 417 |
unsafe_allow_html=True,
|
|
|
|
| 44 |
from PIL import Image
|
| 45 |
from streamlit_drawable_canvas import st_canvas
|
| 46 |
from dotenv import load_dotenv
|
| 47 |
+
from firebase_utils import sign_in_with_email, sign_up_with_email, send_password_reset_email
|
| 48 |
|
| 49 |
logging.basicConfig(level=logging.INFO)
|
| 50 |
logger = logging.getLogger(__name__)
|
|
|
|
| 374 |
</div>
|
| 375 |
""", unsafe_allow_html=True)
|
| 376 |
|
| 377 |
+
tab_in, tab_up, tab_reset = st.tabs(["Login", "Sign Up", "Reset Password"])
|
| 378 |
|
| 379 |
with tab_in:
|
| 380 |
with st.form("login_form"):
|
|
|
|
| 412 |
else:
|
| 413 |
st.error("Please fill all fields.")
|
| 414 |
|
| 415 |
+
with tab_reset:
|
| 416 |
+
with st.form("reset_form"):
|
| 417 |
+
st.markdown("Enter your email address to receive a secure password reset link.")
|
| 418 |
+
reset_email = st.text_input("Email", placeholder="student@university.edu", key="reset_email_input")
|
| 419 |
+
if st.form_submit_button("Send Reset Link", use_container_width=True, type="primary"):
|
| 420 |
+
if reset_email:
|
| 421 |
+
success, error = send_password_reset_email(reset_email)
|
| 422 |
+
if success:
|
| 423 |
+
st.success("✅ Password reset link sent! Please check your email inbox.")
|
| 424 |
+
else:
|
| 425 |
+
st.error(f"Failed to send reset link: {error}")
|
| 426 |
+
else:
|
| 427 |
+
st.error("Please enter your email.")
|
| 428 |
+
|
| 429 |
st.markdown(
|
| 430 |
"<p style='text-align:center;font-size:0.8rem;color:#6b7280;'>Powered by Gemini & SymPy</p>",
|
| 431 |
unsafe_allow_html=True,
|
frontend/firebase_utils.py
CHANGED
|
@@ -58,3 +58,28 @@ def sign_up_with_email(email, password):
|
|
| 58 |
return None, None, None, error_msg
|
| 59 |
except Exception as e:
|
| 60 |
return None, None, None, str(e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
return None, None, None, error_msg
|
| 59 |
except Exception as e:
|
| 60 |
return None, None, None, str(e)
|
| 61 |
+
|
| 62 |
+
def send_password_reset_email(email):
|
| 63 |
+
"""
|
| 64 |
+
Sends a password reset email using Firebase Auth REST API.
|
| 65 |
+
"""
|
| 66 |
+
if not FIREBASE_WEB_API_KEY:
|
| 67 |
+
return False, "FIREBASE_WEB_API_KEY is not set in .env"
|
| 68 |
+
|
| 69 |
+
url = f"https://identitytoolkit.googleapis.com/v1/accounts:sendOobCode?key={FIREBASE_WEB_API_KEY}"
|
| 70 |
+
payload = {
|
| 71 |
+
"requestType": "PASSWORD_RESET",
|
| 72 |
+
"email": email
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
try:
|
| 76 |
+
response = requests.post(url, json=payload)
|
| 77 |
+
data = response.json()
|
| 78 |
+
|
| 79 |
+
if response.status_code == 200:
|
| 80 |
+
return True, None
|
| 81 |
+
else:
|
| 82 |
+
error_msg = data.get("error", {}).get("message", "Unknown error")
|
| 83 |
+
return False, error_msg
|
| 84 |
+
except Exception as e:
|
| 85 |
+
return False, str(e)
|