133 lines
5.5 KiB
Python
133 lines
5.5 KiB
Python
import json
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy import String, Text, Integer, DateTime, ForeignKey, func
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.db.base import Base
|
|
|
|
|
|
class Class_(Base):
|
|
__tablename__ = "classes"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
name: Mapped[str] = mapped_column(String(100), nullable=False)
|
|
cohort_year: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime, server_default=func.now(), onupdate=func.now()
|
|
)
|
|
|
|
members: Mapped[list["User"]] = relationship("User", back_populates="class_")
|
|
timelines: Mapped[list["Timeline"]] = relationship(
|
|
"Timeline", back_populates="class_", cascade="all, delete-orphan"
|
|
)
|
|
schedules: Mapped[list["Schedule"]] = relationship(
|
|
"Schedule", back_populates="class_", cascade="all, delete-orphan"
|
|
)
|
|
|
|
|
|
class User(Base):
|
|
__tablename__ = "users"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
email: Mapped[str] = mapped_column(String(255), unique=True, nullable=False, index=True)
|
|
password_hash: Mapped[str] = mapped_column(Text, nullable=False)
|
|
name: Mapped[str] = mapped_column(String(100), nullable=False)
|
|
student_id: Mapped[str | None] = mapped_column(String(50), nullable=True, unique=True)
|
|
|
|
# role: super_admin | class_admin | student
|
|
role: Mapped[str] = mapped_column(String(20), default="student", nullable=False)
|
|
# status: pending | approved | rejected | disabled
|
|
status: Mapped[str] = mapped_column(String(20), default="pending", nullable=False)
|
|
|
|
class_id: Mapped[int | None] = mapped_column(
|
|
Integer, ForeignKey("classes.id"), nullable=True
|
|
)
|
|
class_: Mapped["Class_ | None"] = relationship("Class_", back_populates="members")
|
|
|
|
# Profile
|
|
industry: Mapped[str | None] = mapped_column(String(100), nullable=True)
|
|
company: Mapped[str | None] = mapped_column(String(100), nullable=True)
|
|
position: Mapped[str | None] = mapped_column(String(100), nullable=True)
|
|
skills_tags: Mapped[str | None] = mapped_column(Text, nullable=True) # JSON array
|
|
wechat_id: Mapped[str | None] = mapped_column(String(100), nullable=True)
|
|
avatar_url: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
bio: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime, server_default=func.now(), onupdate=func.now()
|
|
)
|
|
|
|
timeline_posts: Mapped[list["Timeline"]] = relationship(
|
|
"Timeline", back_populates="author"
|
|
)
|
|
|
|
def get_skills_list(self) -> list[str]:
|
|
if not self.skills_tags:
|
|
return []
|
|
try:
|
|
return json.loads(self.skills_tags)
|
|
except (json.JSONDecodeError, TypeError):
|
|
return []
|
|
|
|
def set_skills_list(self, tags: list[str]):
|
|
self.skills_tags = json.dumps(tags, ensure_ascii=False) if tags else None
|
|
|
|
|
|
class Timeline(Base):
|
|
__tablename__ = "timelines"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
class_id: Mapped[int] = mapped_column(
|
|
Integer, ForeignKey("classes.id"), nullable=False, index=True
|
|
)
|
|
author_id: Mapped[int] = mapped_column(
|
|
Integer, ForeignKey("users.id"), nullable=False
|
|
)
|
|
title: Mapped[str] = mapped_column(String(200), nullable=False)
|
|
content: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
image_urls: Mapped[str | None] = mapped_column(Text, nullable=True) # JSON array
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime, server_default=func.now(), onupdate=func.now()
|
|
)
|
|
|
|
class_: Mapped["Class_"] = relationship("Class_", back_populates="timelines")
|
|
author: Mapped["User"] = relationship("User", back_populates="timeline_posts")
|
|
|
|
def get_image_urls_list(self) -> list[str]:
|
|
if not self.image_urls:
|
|
return []
|
|
try:
|
|
return json.loads(self.image_urls)
|
|
except (json.JSONDecodeError, TypeError):
|
|
return []
|
|
|
|
def set_image_urls_list(self, urls: list[str]):
|
|
self.image_urls = json.dumps(urls) if urls else None
|
|
|
|
|
|
class Schedule(Base):
|
|
__tablename__ = "schedules"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
class_id: Mapped[int] = mapped_column(
|
|
Integer, ForeignKey("classes.id"), nullable=False, index=True
|
|
)
|
|
# type: course | deadline | activity
|
|
type: Mapped[str] = mapped_column(String(20), nullable=False)
|
|
title: Mapped[str] = mapped_column(String(200), nullable=False)
|
|
start_time: Mapped[datetime] = mapped_column(DateTime, nullable=False)
|
|
end_time: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
location: Mapped[str | None] = mapped_column(String(200), nullable=True)
|
|
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime, server_default=func.now(), onupdate=func.now()
|
|
)
|
|
|
|
class_: Mapped["Class_"] = relationship("Class_", back_populates="schedules")
|