login_system.py
unknown
plain_text
10 months ago
17 kB
7
Indexable
#!/usr/bin/env python3
import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
import mysql.connector
from datetime import datetime
import os
import hashlib
import re
from parkmanager import ParkingManagerApp
# Database Configuration
DB_CONFIG = {
"host": "localhost",
"user": "root",
"password": "",
"database": "parkfinder",
}
# --- Configuration for Locked Company ---
def load_locked_company():
"""Load the locked company from file; default to 'olpcc' if not found."""
if os.path.exists("locked_company.txt"):
try:
with open("locked_company.txt", "r") as f:
company = f.read().strip()
if company:
return company
except Exception as e:
print("Error reading locked_company.txt:", e)
return "OLPCC"
def save_locked_company(company):
"""Save the locked company to a file for persistence."""
try:
with open("locked_company.txt", "w") as f:
f.write(company)
print(f"Successfully saved company: {company} to locked_company.txt")
return True
except Exception as e:
print("Error writing locked_company.txt:", e)
return False
def hash_password(password):
"""Create a SHA-256 hash of the password."""
return hashlib.sha256(password.encode()).hexdigest()
class LoginWindow(tk.Tk):
def __init__(self):
super().__init__()
self.title("Parking Management System - Login")
self.geometry("400x500")
self.resizable(False, False)
# Center the window
self.update_idletasks()
width = self.winfo_width()
height = self.winfo_height()
x = (self.winfo_screenwidth() // 2) - (width // 2)
y = (self.winfo_screenheight() // 2) - (height // 2)
self.geometry(f'+{x}+{y}')
self.create_widgets()
# Load the locked company
self.locked_company = load_locked_company()
self.update_company_display()
# Fetch companies for the dropdown
self.load_companies()
def create_widgets(self):
# Main frame
main_frame = ttk.Frame(self, padding=20)
main_frame.pack(fill="both", expand=True)
# Title
title_label = ttk.Label(main_frame, text="Parking Management System", font=("Arial", 16, "bold"))
title_label.pack(pady=(0, 20))
# Login frame
login_frame = ttk.LabelFrame(main_frame, text="Staff Login", padding=10)
login_frame.pack(fill="both", expand=True, padx=10, pady=10)
# Username
ttk.Label(login_frame, text="Username:").pack(anchor="w", pady=(10, 5))
self.username_entry = ttk.Entry(login_frame, width=30)
self.username_entry.pack(fill="x", pady=(0, 10))
# Password
ttk.Label(login_frame, text="Password:").pack(anchor="w", pady=(5, 5))
self.password_entry = ttk.Entry(login_frame, width=30, show="*")
self.password_entry.pack(fill="x", pady=(0, 10))
# Company selection
ttk.Label(login_frame, text="Company:").pack(anchor="w", pady=(5, 5))
self.company_frame = ttk.Frame(login_frame)
self.company_frame.pack(fill="x", pady=(0, 10))
self.company_label = ttk.Label(self.company_frame, text="Loading companies...", font=("Arial", 10))
self.company_label.pack(side="left", fill="x", expand=True)
self.change_company_btn = ttk.Button(self.company_frame, text="Change", command=self.select_company)
self.change_company_btn.pack(side="right")
# Login button
self.login_button = ttk.Button(login_frame, text="Login", command=self.login)
self.login_button.pack(pady=20)
# Register link
register_frame = ttk.Frame(main_frame)
register_frame.pack(fill="x", pady=10)
register_label = ttk.Label(register_frame, text="Don't have an account?")
register_label.pack(side="left")
register_link = ttk.Label(register_frame, text="Register", foreground="blue", cursor="hand2")
register_link.pack(side="left", padx=5)
register_link.bind("<Button-1>", self.show_register)
# Status bar
self.status_var = tk.StringVar()
self.status_var.set("Ready")
status_bar = ttk.Label(self, textvariable=self.status_var, relief="sunken", anchor="w")
status_bar.pack(side="bottom", fill="x")
def update_company_display(self):
"""Update the company label with the current locked company"""
if hasattr(self, 'company_label'):
self.company_label.config(text=f"Current: {self.locked_company}")
def load_companies(self):
"""Load companies from the database for the dropdown"""
try:
conn = mysql.connector.connect(**DB_CONFIG)
cursor = conn.cursor()
cursor.execute("SELECT id, company_name FROM parking_lots")
self.companies = [(row[0], row[1]) for row in cursor.fetchall()]
conn.close()
if not self.companies:
self.status_var.set("Warning: No companies found in database")
else:
self.update_company_display()
except mysql.connector.Error as err:
self.status_var.set(f"Error: {err}")
self.companies = []
def select_company(self):
"""Open a dialog to select a company"""
if not hasattr(self, 'companies') or not self.companies:
messagebox.showerror("Error", "No companies available to select")
return
# Create a new window with a dropdown to select a company
top = tk.Toplevel(self)
top.title("Select Company")
top.geometry("300x200")
top.resizable(False, False)
# Center the window
top.update_idletasks()
width = top.winfo_width()
height = top.winfo_height()
x = (top.winfo_screenwidth() // 2) - (width // 2)
y = (top.winfo_screenheight() // 2) - (height // 2)
top.geometry(f'+{x}+{y}')
ttk.Label(top, text="Select a company:", font=("Arial", 12)).pack(pady=(20, 10), padx=10)
# Create StringVar with the current company as default
company_var = tk.StringVar()
# Find the current company name in the list
current_company_name = None
for company_id, company_name in self.companies:
if company_name == self.locked_company:
current_company_name = company_name
break
if current_company_name:
company_var.set(current_company_name)
else:
company_var.set(self.companies[0][1]) # Default to first company
# Create the dropdown with company names only
company_names = [name for _, name in self.companies]
combobox = ttk.Combobox(top, textvariable=company_var, values=company_names, state="readonly", width=25)
combobox.pack(pady=10, padx=10)
def on_confirm():
selected_company_name = company_var.get()
if selected_company_name:
# Update the locked company
self.locked_company = selected_company_name
# Save to file
save_locked_company(selected_company_name)
# Update the label
self.update_company_display()
messagebox.showinfo("Success", f"Company set to {selected_company_name}")
top.destroy()
button_frame = ttk.Frame(top)
button_frame.pack(pady=20)
confirm_button = ttk.Button(button_frame, text="Confirm", command=on_confirm)
confirm_button.pack(side="left", padx=5)
cancel_button = ttk.Button(button_frame, text="Cancel", command=top.destroy)
cancel_button.pack(side="left", padx=5)
# Make the window modal
top.transient(self)
top.grab_set()
self.wait_window(top)
def login(self):
username = self.username_entry.get().strip()
password = self.password_entry.get()
if not username or not password:
messagebox.showerror("Login Error", "Please enter both username and password")
return
try:
conn = mysql.connector.connect(**DB_CONFIG)
cursor = conn.cursor(dictionary=True)
# Check if user exists and password matches
hashed_password = hash_password(password)
cursor.execute(
"SELECT * FROM staff WHERE username = %s AND password = %s",
(username, hashed_password)
)
staff = cursor.fetchone()
if not staff:
messagebox.showerror("Login Error", "Invalid username or password")
conn.close()
return
# Record login time in staffrecords
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
cursor.execute(
"INSERT INTO staffrecords (staff_id, time_in, company) VALUES (%s, %s, %s)",
(staff['id'], now, self.locked_company)
)
conn.commit()
# Get the record ID for logout
record_id = cursor.lastrowid
conn.close()
# Hide login window
self.withdraw()
# Create user info dictionary
user_info = {
'id': staff['id'],
'name': staff['name'],
'username': staff['username'],
'role': staff['role']
}
# Launch main application
app = ParkingManagerApp(user=user_info, record_id=record_id)
# Set logout callback to show login window again
app.set_logout_callback(self.on_logout)
# Pass the locked company to the main app
app.locked_company = self.locked_company
app.mainloop()
except mysql.connector.Error as err:
messagebox.showerror("Database Error", f"Error: {err}")
def on_logout(self):
"""Callback function when user logs out of main app"""
# Clear login fields
self.username_entry.delete(0, tk.END)
self.password_entry.delete(0, tk.END)
# Show login window again
self.deiconify()
self.username_entry.focus()
def show_register(self, event=None):
self.withdraw() # Hide login window
register_window = RegisterWindow(self)
register_window.mainloop()
class RegisterWindow(tk.Toplevel):
def __init__(self, parent):
super().__init__(parent)
self.parent = parent
self.title("Parking Management System - Register")
self.geometry("400x500")
self.resizable(False, False)
# Center the window
self.update_idletasks()
width = self.winfo_width()
height = self.winfo_height()
x = (self.winfo_screenwidth() // 2) - (width // 2)
y = (self.winfo_screenheight() // 2) - (height // 2)
self.geometry(f'+{x}+{y}')
self.protocol("WM_DELETE_WINDOW", self.on_close)
self.create_widgets()
def create_widgets(self):
# Main frame
main_frame = ttk.Frame(self, padding=20)
main_frame.pack(fill="both", expand=True)
# Title
title_label = ttk.Label(main_frame, text="Staff Registration", font=("Arial", 16, "bold"))
title_label.pack(pady=(0, 20))
# Register frame
register_frame = ttk.LabelFrame(main_frame, text="Create Account", padding=10)
register_frame.pack(fill="both", expand=True, padx=10, pady=10)
# Full Name
ttk.Label(register_frame, text="Full Name:").pack(anchor="w", pady=(10, 5))
self.name_entry = ttk.Entry(register_frame, width=30)
self.name_entry.pack(fill="x", pady=(0, 10))
# Username
ttk.Label(register_frame, text="Username:").pack(anchor="w", pady=(5, 5))
self.username_entry = ttk.Entry(register_frame, width=30)
self.username_entry.pack(fill="x", pady=(0, 10))
# Password
ttk.Label(register_frame, text="Password:").pack(anchor="w", pady=(5, 5))
self.password_entry = ttk.Entry(register_frame, width=30, show="*")
self.password_entry.pack(fill="x", pady=(0, 10))
# Confirm Password
ttk.Label(register_frame, text="Confirm Password:").pack(anchor="w", pady=(5, 5))
self.confirm_password_entry = ttk.Entry(register_frame, width=30, show="*")
self.confirm_password_entry.pack(fill="x", pady=(0, 10))
# Role selection
ttk.Label(register_frame, text="Role:").pack(anchor="w", pady=(5, 5))
self.role_var = tk.StringVar(value="attendant")
role_frame = ttk.Frame(register_frame)
role_frame.pack(fill="x", pady=(0, 10))
ttk.Radiobutton(role_frame, text="Attendant", variable=self.role_var, value="attendant").pack(side="left", padx=(0, 10))
ttk.Radiobutton(role_frame, text="Admin", variable=self.role_var, value="admin").pack(side="left")
# Register button
self.register_button = ttk.Button(register_frame, text="Register", command=self.register)
self.register_button.pack(pady=20)
# Login link
login_frame = ttk.Frame(main_frame)
login_frame.pack(fill="x", pady=10)
login_label = ttk.Label(login_frame, text="Already have an account?")
login_label.pack(side="left")
login_link = ttk.Label(login_frame, text="Login", foreground="blue", cursor="hand2")
login_link.pack(side="left", padx=5)
login_link.bind("<Button-1>", self.show_login)
# Status bar
self.status_var = tk.StringVar()
self.status_var.set("Ready")
status_bar = ttk.Label(self, textvariable=self.status_var, relief="sunken", anchor="w")
status_bar.pack(side="bottom", fill="x")
def register(self):
name = self.name_entry.get().strip()
username = self.username_entry.get().strip()
password = self.password_entry.get()
confirm_password = self.confirm_password_entry.get()
role = self.role_var.get()
# Validate inputs
if not name or not username or not password:
messagebox.showerror("Registration Error", "Please fill in all fields")
return
if password != confirm_password:
messagebox.showerror("Registration Error", "Passwords do not match")
return
if len(password) < 6:
messagebox.showerror("Registration Error", "Password must be at least 6 characters")
return
if not re.match(r'^[a-zA-Z0-9_]+$', username):
messagebox.showerror("Registration Error", "Username can only contain letters, numbers, and underscores")
return
try:
conn = mysql.connector.connect(**DB_CONFIG)
cursor = conn.cursor()
# Check if username already exists
cursor.execute("SELECT id FROM staff WHERE username = %s", (username,))
if cursor.fetchone():
messagebox.showerror("Registration Error", "Username already exists")
conn.close()
return
# Hash the password
hashed_password = hash_password(password)
# Insert new staff
cursor.execute(
"INSERT INTO staff (name, username, password, role) VALUES (%s, %s, %s, %s)",
(name, username, hashed_password, role)
)
conn.commit()
conn.close()
messagebox.showinfo("Registration Successful", "Your account has been created. You can now login.")
self.show_login()
except mysql.connector.Error as err:
messagebox.showerror("Database Error", f"Error: {err}")
def show_login(self, event=None):
self.destroy()
self.parent.deiconify() # Show login window
def on_close(self):
self.parent.deiconify() # Show login window when register window is closed
self.destroy()
if __name__ == "__main__":
login_app = LoginWindow()
login_app.mainloop()Editor is loading...
Leave a Comment