eigent/server/app/model/user/user.py
2025-09-03 10:43:17 +08:00

92 lines
2.9 KiB
Python

from datetime import datetime, date
from enum import IntEnum
from sqlalchemy import Integer, SmallInteger, text
from sqlalchemy_utils import ChoiceType
from pydantic import BaseModel, EmailStr, field_validator
from sqlmodel import Field, Column
from app.model.abstract.model import AbstractModel, DefaultTimes
from typing import Optional
from app.component.encrypt import password_hash
class Status(IntEnum):
Normal = 1
Block = -1
class User(AbstractModel, DefaultTimes, table=True):
id: int = Field(default=None, primary_key=True)
stack_id: str | None = Field(default=None, unique=True, max_length=255)
username: str | None = Field(default=None, unique=True, max_length=128)
email: EmailStr = Field(unique=True, max_length=128)
password: str | None = Field(default=None, max_length=256)
avatar: str = Field(default="", max_length=256)
nickname: str = Field(default="", max_length=64)
fullname: str = Field(default="", max_length=128)
work_desc: str = Field(default="", max_length=255)
credits: int = Field(default=0, description="credits", sa_column=Column(Integer, server_default=text("0")))
last_daily_credit_date: date | None = Field(default=None, description="Last date daily credits were granted")
last_monthly_credit_date: date | None = Field(default=None, description="Last month monthly credits were granted")
inviter_user_id: int | None = Field(default=None, foreign_key="user.id", description="Inviter user ID")
status: Status = Field(default=Status.Normal.value, sa_column=Column(ChoiceType(Status, SmallInteger())))
class UserProfile(BaseModel):
fullname: str = ""
nickname: str = ""
work_desc: str = ""
class LoginByPasswordIn(BaseModel):
email: EmailStr
password: str
class LoginResponse(BaseModel):
token: str
email: EmailStr
class UserIn(BaseModel):
username: str
class UserCreate(UserIn):
password: str
class UserOut(BaseModel):
email: EmailStr
avatar: Optional[str] = ""
username: Optional[str] = ""
nickname: Optional[str] = ""
fullname: Optional[str] = ""
work_desc: Optional[str] = ""
credits: int
status: Status
created_at: datetime
class UpdatePassword(BaseModel):
password: str
new_password: str
re_new_password: str
class RegisterIn(BaseModel):
email: EmailStr
password: str
invite_code: Optional[str] = None
@field_validator("password", mode="before")
def password_strength(cls, v):
# At least 8 chars, must contain letters and numbers
if len(v) < 8:
raise ValueError("Password must be at least 8 characters long")
if not any(c.isdigit() for c in v) or not any(c.isalpha() for c in v):
raise ValueError("Password must contain both letters and numbers")
return v
@field_validator("password", mode="after")
def password_hash(cls, v):
return password_hash(v)