Spaces:
Sleeping
Sleeping
| # auth/login.py | |
| from dash import html, dcc, Input, Output, State, callback, no_update | |
| import dash_bootstrap_components as dbc # Import dbc | |
| from database import engine, users | |
| from sqlalchemy import select | |
| from werkzeug.security import check_password_hash # PENTING: Import untuk verifikasi hash | |
| login_layout = dbc.Container( | |
| fluid=True, | |
| className="d-flex flex-column justify-content-center align-items-center min-vh-100 p-0 m-0", | |
| style={'background': 'linear-gradient(135deg, #1e2a47, #2c3e50)'}, | |
| children=[ | |
| dcc.Location(id='login-url-redirect', refresh=True), | |
| dbc.Row( | |
| dbc.Col( | |
| dbc.Card( | |
| dbc.CardBody([ | |
| html.H2("Disease Dashboard Login", className="text-center mb-4", style={'color': '#2c3e50'}), | |
| html.Div(id='login-message', className="mb-3 text-center"), | |
| dbc.Form([ | |
| dbc.Row([ | |
| dbc.Label("Username", width=4, className="text-md-end"), | |
| dbc.Col( | |
| dbc.Input(id='login-username', type='text', placeholder="Masukkan username Anda"), | |
| width=8 | |
| ) | |
| ], className="mb-3 align-items-center"), | |
| dbc.Row([ | |
| dbc.Label("Password", width=4, className="text-md-end"), | |
| dbc.Col( | |
| dbc.Input(id='login-password', type='password', placeholder="Masukkan password Anda"), | |
| width=8 | |
| ) | |
| ], className="mb-3 align-items-center"), | |
| dbc.Button("Login", id='login-button', color="primary", className="w-100 mt-4", n_clicks=0, size="lg"), | |
| ]), | |
| html.Div( | |
| dcc.Link("Belum punya akun? Daftar di sini", href="/signup", className="d-block mt-3 text-center"), | |
| ) | |
| ]), | |
| className="shadow-lg", | |
| style={'padding': '2rem'} | |
| ), | |
| width=12, sm=10, md=8, lg=5, xl=4 # Sesuaikan lebar card login | |
| ), | |
| justify="center", | |
| className="w-100" | |
| ) | |
| ] | |
| ) | |
| layout = login_layout | |
| # Callback untuk handle login | |
| def handle_login(n_clicks_login, username, password_input): | |
| if not username or not password_input: | |
| return no_update, no_update, dbc.Alert("Username dan password harus diisi.", color="warning", dismissable=True, duration=4000) | |
| username = username.strip() | |
| with engine.connect() as conn: | |
| # Ambil id_user, username, password (hash), dan nama_lengkap | |
| stmt = select( | |
| users.c.id_user, # Pastikan ini adalah nama PK di tabel users | |
| users.c.username, | |
| users.c.password, | |
| users.c.nama_lengkap | |
| ).where(users.c.username == username) | |
| user_record = conn.execute(stmt).fetchone() | |
| print(f"--- LOGIN DEBUG: Mencoba login untuk user: {username} ---") | |
| if user_record: | |
| hashed_password_from_db = user_record.password | |
| # print(f"--- LOGIN DEBUG: Hashed Password dari DB: {str(hashed_password_from_db)[:20]}... ---") | |
| # print(f"--- LOGIN DEBUG: Password Input: '{password_input}' ---") | |
| if check_password_hash(str(hashed_password_from_db), str(password_input).strip()): | |
| session_data = { | |
| 'logged_in': True, | |
| 'username': user_record.username, | |
| 'nama_lengkap': user_record.nama_lengkap, | |
| 'id_user': user_record.id_user # <--- TAMBAHKAN BARIS INI | |
| } | |
| print(f"--- LOGIN DEBUG: Login BERHASIL. Session data: {session_data} ---") | |
| return session_data, '/beranda', dbc.Alert(f"Login berhasil, selamat datang {user_record.nama_lengkap}!", color="success", duration=4000) | |
| else: | |
| print(f"--- LOGIN DEBUG: Password SALAH untuk user: {username} ---") | |
| return no_update, no_update, dbc.Alert("Username atau password salah.", color="danger", dismissable=True, duration=4000) | |
| else: | |
| print(f"--- LOGIN DEBUG: Username '{username}' TIDAK DITEMUKAN ---") | |
| return no_update, no_update, dbc.Alert("Username atau password salah.", color="danger", dismissable=True, duration=4000) | |
| # Layout export | |
| layout = login_layout |