Files
Document_translator_V2_nodo…/app/models/user.py
beabigegg 4cace93934 NO docker
2025-10-02 18:50:53 +08:00

124 lines
4.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
使用者資料模型
Author: PANJIT IT Team
Created: 2024-01-28
Modified: 2024-01-28
"""
from datetime import datetime, timedelta
from sqlalchemy.sql import func
from app import db
from app.utils.timezone import format_taiwan_time
class User(db.Model):
"""使用者資訊表 (dt_users)"""
__tablename__ = 'dt_users'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(100), unique=True, nullable=False, index=True, comment='AD帳號')
display_name = db.Column(db.String(200), nullable=False, comment='顯示名稱')
email = db.Column(db.String(255), nullable=False, index=True, comment='電子郵件')
department = db.Column(db.String(100), comment='部門')
is_admin = db.Column(db.Boolean, default=False, comment='是否為管理員')
last_login = db.Column(db.DateTime, comment='最後登入時間')
created_at = db.Column(db.DateTime, default=func.now(), comment='建立時間')
updated_at = db.Column(
db.DateTime,
default=func.now(),
onupdate=func.now(),
comment='更新時間'
)
# 關聯關係
translation_jobs = db.relationship('TranslationJob', backref='user', lazy='dynamic', cascade='all, delete-orphan')
api_usage_stats = db.relationship('APIUsageStats', backref='user', lazy='dynamic', cascade='all, delete-orphan')
system_logs = db.relationship('SystemLog', backref='user', lazy='dynamic')
def __repr__(self):
return f'<User {self.username}>'
def to_dict(self, include_stats=False):
"""轉換為字典格式"""
data = {
'id': self.id,
'username': self.username,
'display_name': self.display_name,
'email': self.email,
'department': self.department,
'is_admin': self.is_admin,
'last_login': format_taiwan_time(self.last_login, "%Y-%m-%d %H:%M:%S") if self.last_login else None,
'created_at': format_taiwan_time(self.created_at, "%Y-%m-%d %H:%M:%S") if self.created_at else None,
'updated_at': format_taiwan_time(self.updated_at, "%Y-%m-%d %H:%M:%S") if self.updated_at else None
}
if include_stats:
data.update({
'total_jobs': self.translation_jobs.count(),
'completed_jobs': self.translation_jobs.filter_by(status='COMPLETED').count(),
'failed_jobs': self.translation_jobs.filter_by(status='FAILED').count(),
'total_cost': self.get_total_cost()
})
return data
def get_total_cost(self):
"""計算使用者總成本"""
try:
from app.models.stats import APIUsageStats
return db.session.query(
func.sum(APIUsageStats.cost)
).filter(APIUsageStats.user_id == self.id).scalar() or 0.0
except Exception:
return 0.0
def update_last_login(self):
"""更新最後登入時間"""
self.last_login = datetime.utcnow()
db.session.commit()
@classmethod
def get_or_create(cls, username, display_name, email, department=None):
"""取得或建立使用者 (方案A: 使用 email 作為主要識別鍵)"""
# 先嘗試用 email 查找 (因為 email 是唯一且穩定的識別碼)
user = cls.query.filter_by(email=email).first()
if user:
# 更新使用者資訊 (API name 格式: 姓名+email)
user.username = username # API 的 name (姓名+email 格式)
user.display_name = display_name # API 的 name (姓名+email 格式)
if department:
user.department = department
user.updated_at = datetime.utcnow()
else:
# 建立新使用者
user = cls(
username=username, # API 的 name (姓名+email 格式)
display_name=display_name, # API 的 name (姓名+email 格式)
email=email, # 純 email唯一識別鍵
department=department,
is_admin=(email.lower() == 'ymirliu@panjit.com.tw') # 硬編碼管理員
)
db.session.add(user)
db.session.commit()
return user
@classmethod
def get_by_email(cls, email):
"""根據 email 查找使用者"""
return cls.query.filter_by(email=email).first()
@classmethod
def get_admin_users(cls):
"""取得所有管理員使用者"""
return cls.query.filter_by(is_admin=True).all()
@classmethod
def get_active_users(cls, days=30):
"""取得活躍使用者(指定天數內有登入)"""
cutoff_date = datetime.utcnow() - timedelta(days=days)
return cls.query.filter(cls.last_login >= cutoff_date).all()