eafc1c33fc
- FastAPI backend with SQLite database - React + TailwindCSS frontend - JWT authentication - Excel upload/download for attendance and accident records - Shift roster management with S7a/S7b split - Lateness/OT calculation based on shift times - Roster info API endpoints - Export API with token query parameter support - Docker compose deployment
73 lines
2.2 KiB
Python
73 lines
2.2 KiB
Python
import os
|
|
from datetime import datetime, timezone
|
|
from sqlalchemy import create_engine, Column, Integer, String, Text, Float, Boolean, DateTime, Date, Time, JSON
|
|
from sqlalchemy.ext.declarative import declarative_base
|
|
from sqlalchemy.orm import sessionmaker
|
|
from passlib.context import CryptContext
|
|
from jose import jwt
|
|
from typing import Optional, List
|
|
from pydantic import BaseModel
|
|
import secret
|
|
|
|
# Database setup
|
|
DATABASE_URL = "sqlite:///./data/aars.db"
|
|
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
|
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
Base = declarative_base()
|
|
|
|
pwd_context = CryptContext(schemes=["sha256_crypt"], deprecated="auto")
|
|
|
|
# JWT Settings
|
|
SECRET_KEY = secret.JWT_SECRET if hasattr(secret, 'JWT_SECRET') else "aars-dev-secret-change-in-production"
|
|
ALGORITHM = "HS256"
|
|
ACCESS_TOKEN_EXPIRE_HOURS = 24
|
|
|
|
|
|
def create_access_token(data: dict) -> str:
|
|
expire = datetime.now(timezone.utc).timestamp() + (ACCESS_TOKEN_EXPIRE_HOURS * 3600)
|
|
to_encode = data.copy()
|
|
to_encode.update({"exp": expire})
|
|
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
|
|
|
|
|
def verify_password(plain_password: str, hashed_password: str) -> bool:
|
|
return pwd_context.verify(plain_password, hashed_password)
|
|
|
|
|
|
def get_password_hash(password: str) -> str:
|
|
return pwd_context.hash(password)
|
|
|
|
|
|
def get_db():
|
|
db = SessionLocal()
|
|
try:
|
|
yield db
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
def init_db():
|
|
"""Initialize database with tables and default admin user."""
|
|
Base.metadata.create_all(bind=engine)
|
|
db = SessionLocal()
|
|
try:
|
|
# Check if admin exists
|
|
from models import User
|
|
admin = db.query(User).filter(User.email == "admin@aars.hk").first()
|
|
if not admin:
|
|
# Create default admin
|
|
admin = User(
|
|
email="admin@aars.hk",
|
|
password_hash=get_password_hash("admin123"),
|
|
name="系統管理員",
|
|
role="admin",
|
|
is_active=True
|
|
)
|
|
db.add(admin)
|
|
db.commit()
|
|
print("✅ Default admin user created: admin@aars.hk / admin123")
|
|
else:
|
|
print("✅ Admin user already exists")
|
|
finally:
|
|
db.close()
|