初次提交
This commit is contained in:
4
backend/app/models/__init__.py
Normal file
4
backend/app/models/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from .user import User
|
||||
from .file import File
|
||||
|
||||
__all__ = ["User", "File"]
|
||||
86
backend/app/models/file.py
Normal file
86
backend/app/models/file.py
Normal file
@@ -0,0 +1,86 @@
|
||||
from sqlalchemy import Column, Integer, String, BigInteger, DateTime, ForeignKey, Boolean, Text
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from app.core.database import Base
|
||||
|
||||
class File(Base):
|
||||
__tablename__ = "files"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False, index=True)
|
||||
|
||||
# 文件基本信息
|
||||
filename = Column(String(255), nullable=False, index=True)
|
||||
original_filename = Column(String(255), nullable=False) # 用户上传时的原始文件名
|
||||
file_path = Column(String(500), nullable=False) # 服务器上的存储路径
|
||||
file_size = Column(BigInteger, nullable=False) # 文件大小(字节)
|
||||
mime_type = Column(String(100), nullable=False) # 文件MIME类型
|
||||
file_hash = Column(String(64), nullable=False, index=True) # SHA-256哈希,用于去重和完整性检查
|
||||
|
||||
# 文件状态
|
||||
is_public = Column(Boolean, default=False) # 是否公开分享
|
||||
download_count = Column(BigInteger, default=0) # 下载次数
|
||||
|
||||
# 文件元数据
|
||||
description = Column(Text, nullable=True) # 文件描述
|
||||
tags = Column(Text, nullable=True) # 标签,用逗号分隔
|
||||
|
||||
# 时间戳
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
last_accessed_at = Column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
# 关联关系
|
||||
user = relationship("User", back_populates="files")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<File(id={self.id}, filename='{self.filename}', user_id={self.user_id})>"
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"user_id": self.user_id,
|
||||
"filename": self.filename,
|
||||
"original_filename": self.original_filename,
|
||||
"file_size": self.file_size,
|
||||
"mime_type": self.mime_type,
|
||||
"file_hash": self.file_hash,
|
||||
"is_public": self.is_public,
|
||||
"download_count": self.download_count,
|
||||
"description": self.description,
|
||||
"tags": self.tags,
|
||||
"created_at": self.created_at.isoformat() if self.created_at else None,
|
||||
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
||||
"last_accessed_at": self.last_accessed_at.isoformat() if self.last_accessed_at else None,
|
||||
}
|
||||
|
||||
def get_file_extension(self) -> str:
|
||||
"""获取文件扩展名"""
|
||||
return self.filename.split('.')[-1].lower() if '.' in self.filename else ''
|
||||
|
||||
def is_image(self) -> bool:
|
||||
"""判断是否为图片文件"""
|
||||
return self.mime_type.startswith('image/')
|
||||
|
||||
def is_document(self) -> bool:
|
||||
"""判断是否为文档文件"""
|
||||
document_types = [
|
||||
'application/pdf',
|
||||
'application/msword',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'application/vnd.ms-excel',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'application/vnd.ms-powerpoint',
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
'text/plain',
|
||||
'text/csv'
|
||||
]
|
||||
return self.mime_type in document_types
|
||||
|
||||
def get_size_formatted(self) -> str:
|
||||
"""获取格式化的文件大小"""
|
||||
for unit in ['B', 'KB', 'MB', 'GB']:
|
||||
if self.file_size < 1024.0:
|
||||
return f"{self.file_size:.1f} {unit}"
|
||||
self.file_size /= 1024.0
|
||||
return f"{self.file_size:.1f} TB"
|
||||
59
backend/app/models/user.py
Normal file
59
backend/app/models/user.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from sqlalchemy import Column, Integer, String, Boolean, DateTime, BigInteger, Text
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from app.core.database import Base
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
username = Column(String(50), unique=True, index=True, nullable=False)
|
||||
email = Column(String(100), index=True, nullable=False)
|
||||
password_hash = Column(String(255), nullable=False)
|
||||
|
||||
# 用户资料
|
||||
avatar_url = Column(String(500), nullable=True)
|
||||
|
||||
# 存储配额
|
||||
storage_quota = Column(BigInteger, default=104857600) # 100MB in bytes
|
||||
storage_used = Column(BigInteger, default=0)
|
||||
|
||||
# 用户状态
|
||||
is_active = Column(Boolean, default=True)
|
||||
is_verified = Column(Boolean, default=False)
|
||||
|
||||
# 时间戳
|
||||
last_login_at = Column(DateTime(timezone=True), nullable=True)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
# 关联关系
|
||||
files = relationship("File", back_populates="user")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<User(id={self.id}, username='{self.username}', email='{self.email}')>"
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"username": self.username,
|
||||
"email": self.email,
|
||||
"avatar_url": self.avatar_url,
|
||||
"storage_quota": self.storage_quota,
|
||||
"storage_used": self.storage_used,
|
||||
"is_active": self.is_active,
|
||||
"is_verified": self.is_verified,
|
||||
"last_login_at": self.last_login_at.isoformat() if self.last_login_at else None,
|
||||
"created_at": self.created_at.isoformat() if self.created_at else None,
|
||||
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
||||
}
|
||||
|
||||
def is_storage_available(self, required_size: int) -> bool:
|
||||
"""检查是否有足够的存储空间"""
|
||||
return (self.storage_used + required_size) <= self.storage_quota
|
||||
|
||||
def get_storage_percentage(self) -> float:
|
||||
"""获取已使用存储空间的百分比"""
|
||||
if self.storage_quota == 0:
|
||||
return 0.0
|
||||
return (self.storage_used / self.storage_quota) * 100
|
||||
Reference in New Issue
Block a user