合入家庭共享与设备消息能力
This commit is contained in:
@@ -1,10 +1,165 @@
|
||||
import asyncio
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.ext.asyncio import create_async_engine
|
||||
from database.models import Base
|
||||
from config import settings
|
||||
from utils.logger import session_logger
|
||||
import urllib.parse
|
||||
|
||||
|
||||
async def _ensure_manual_sleep_mode_column(conn) -> None:
|
||||
result = await conn.execute(
|
||||
text(
|
||||
"""
|
||||
SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'device_settings'
|
||||
AND COLUMN_NAME = 'manual_sleep_mode'
|
||||
"""
|
||||
)
|
||||
)
|
||||
if int(result.scalar() or 0) > 0:
|
||||
return
|
||||
|
||||
await conn.execute(
|
||||
text(
|
||||
"""
|
||||
ALTER TABLE device_settings
|
||||
ADD COLUMN manual_sleep_mode TINYINT NOT NULL DEFAULT 0
|
||||
AFTER sleep_mode
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def _ensure_schedule_suppressed_until_column(conn) -> None:
|
||||
result = await conn.execute(
|
||||
text(
|
||||
"""
|
||||
SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'device_settings'
|
||||
AND COLUMN_NAME = 'schedule_suppressed_until'
|
||||
"""
|
||||
)
|
||||
)
|
||||
if int(result.scalar() or 0) > 0:
|
||||
return
|
||||
|
||||
await conn.execute(
|
||||
text(
|
||||
"""
|
||||
ALTER TABLE device_settings
|
||||
ADD COLUMN schedule_suppressed_until DATETIME NULL
|
||||
AFTER manual_sleep_mode
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def _ensure_device_family_tables(conn) -> None:
|
||||
await conn.execute(
|
||||
text(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS device_family_members (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
device_id VARCHAR(64) NOT NULL,
|
||||
user_id BIGINT NOT NULL,
|
||||
role TINYINT NOT NULL DEFAULT 2,
|
||||
status TINYINT NOT NULL DEFAULT 1,
|
||||
invited_by_user_id BIGINT NULL,
|
||||
joined_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
removed_at DATETIME NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uq_device_family_member (device_id, user_id),
|
||||
KEY idx_device_family_members_device_status (device_id, status),
|
||||
KEY idx_device_family_members_user_status (user_id, status),
|
||||
KEY idx_device_family_members_invited_by (invited_by_user_id),
|
||||
CONSTRAINT fk_device_family_members_device
|
||||
FOREIGN KEY (device_id)
|
||||
REFERENCES device_auth (device_id),
|
||||
CONSTRAINT fk_device_family_members_user
|
||||
FOREIGN KEY (user_id)
|
||||
REFERENCES parents (user_id),
|
||||
CONSTRAINT fk_device_family_members_invited_by
|
||||
FOREIGN KEY (invited_by_user_id)
|
||||
REFERENCES parents (user_id)
|
||||
ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
"""
|
||||
)
|
||||
)
|
||||
await conn.execute(
|
||||
text(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS device_family_invitations (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
invite_token CHAR(36) NOT NULL,
|
||||
device_id VARCHAR(64) NOT NULL,
|
||||
owner_user_id BIGINT NOT NULL,
|
||||
status TINYINT NOT NULL DEFAULT 1,
|
||||
expires_at DATETIME NOT NULL,
|
||||
accepted_by_user_id BIGINT NULL,
|
||||
accepted_at DATETIME NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uq_device_family_invite_token (invite_token),
|
||||
KEY idx_device_family_invites_device_status (device_id, status),
|
||||
KEY idx_device_family_invites_owner_status (owner_user_id, status),
|
||||
KEY idx_device_family_invites_expires_at (expires_at),
|
||||
KEY idx_device_family_invites_accepted_by (accepted_by_user_id),
|
||||
CONSTRAINT fk_device_family_invites_device
|
||||
FOREIGN KEY (device_id)
|
||||
REFERENCES device_auth (device_id),
|
||||
CONSTRAINT fk_device_family_invites_owner
|
||||
FOREIGN KEY (owner_user_id)
|
||||
REFERENCES parents (user_id),
|
||||
CONSTRAINT fk_device_family_invites_accepted_by
|
||||
FOREIGN KEY (accepted_by_user_id)
|
||||
REFERENCES parents (user_id)
|
||||
ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
"""
|
||||
)
|
||||
)
|
||||
await conn.execute(
|
||||
text(
|
||||
"""
|
||||
INSERT INTO device_family_members (
|
||||
device_id,
|
||||
user_id,
|
||||
role,
|
||||
status,
|
||||
invited_by_user_id,
|
||||
joined_at,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
SELECT
|
||||
db.device_id,
|
||||
db.owner_user_id,
|
||||
1,
|
||||
1,
|
||||
NULL,
|
||||
COALESCE(db.bound_at, CURRENT_TIMESTAMP),
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP
|
||||
FROM device_bindings AS db
|
||||
LEFT JOIN device_family_members AS dfm
|
||||
ON dfm.device_id = db.device_id
|
||||
AND dfm.user_id = db.owner_user_id
|
||||
WHERE db.status = 1
|
||||
AND dfm.id IS NULL
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def init_db():
|
||||
"""初始化数据库,创建所有表"""
|
||||
try:
|
||||
@@ -16,6 +171,9 @@ async def init_db():
|
||||
)
|
||||
async with engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
await _ensure_manual_sleep_mode_column(conn)
|
||||
await _ensure_schedule_suppressed_until_column(conn)
|
||||
await _ensure_device_family_tables(conn)
|
||||
await engine.dispose()
|
||||
session_logger.info("system", "database", "数据库表已成功创建")
|
||||
return True
|
||||
|
||||
@@ -169,7 +169,7 @@ class Card(Base):
|
||||
class Parent(Base):
|
||||
__tablename__ = "parents"
|
||||
|
||||
user_id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
openid: Mapped[str] = mapped_column(String(64), unique=True, nullable=False)
|
||||
unionid: Mapped[Optional[str]] = mapped_column(String(64))
|
||||
nickname: Mapped[Optional[str]] = mapped_column(String(64))
|
||||
@@ -184,7 +184,7 @@ class Parent(Base):
|
||||
class Child(Base):
|
||||
__tablename__ = "children"
|
||||
|
||||
child_id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
child_id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
child_name: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
child_gender: Mapped[int] = mapped_column(Integer, server_default="2")
|
||||
child_birthday: Mapped[Optional[date]] = mapped_column(Date)
|
||||
@@ -201,9 +201,9 @@ class ParentChildRelation(Base):
|
||||
Index("idx_pcr_child_id", "child_id"),
|
||||
)
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True)
|
||||
child_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True)
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True)
|
||||
child_id: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True)
|
||||
relation_type: Mapped[int] = mapped_column(Integer, server_default="9")
|
||||
is_primary: Mapped[bool] = mapped_column(Boolean, server_default="0")
|
||||
status: Mapped[int] = mapped_column(Integer, server_default="1")
|
||||
@@ -219,10 +219,10 @@ class DeviceBinding(Base):
|
||||
Index("idx_device_bindings_owner_user_id", "owner_user_id"),
|
||||
)
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
device_id: Mapped[str] = mapped_column(String(64), nullable=False, unique=True)
|
||||
owner_user_id: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
child_id: Mapped[Optional[int]] = mapped_column(Integer)
|
||||
owner_user_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
||||
child_id: Mapped[Optional[int]] = mapped_column(BigInteger)
|
||||
status: Mapped[int] = mapped_column(Integer, server_default="1")
|
||||
bound_at: Mapped[datetime] = mapped_column(DateTime, nullable=False)
|
||||
unbound_at: Mapped[Optional[datetime]] = mapped_column(DateTime)
|
||||
@@ -230,14 +230,55 @@ class DeviceBinding(Base):
|
||||
updated_at: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=text("CURRENT_TIMESTAMP"))
|
||||
|
||||
|
||||
class DeviceFamilyMember(Base):
|
||||
__tablename__ = "device_family_members"
|
||||
__table_args__ = (
|
||||
UniqueConstraint("device_id", "user_id", name="uq_device_family_member"),
|
||||
Index("idx_device_family_members_device_status", "device_id", "status"),
|
||||
Index("idx_device_family_members_user_status", "user_id", "status"),
|
||||
)
|
||||
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
device_id: Mapped[str] = mapped_column(String(64), ForeignKey("device_auth.device_id"), nullable=False)
|
||||
user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("parents.user_id"), nullable=False)
|
||||
role: Mapped[int] = mapped_column(Integer, server_default="2")
|
||||
status: Mapped[int] = mapped_column(Integer, server_default="1")
|
||||
invited_by_user_id: Mapped[Optional[int]] = mapped_column(BigInteger, ForeignKey("parents.user_id", ondelete="SET NULL"))
|
||||
joined_at: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=text("CURRENT_TIMESTAMP"))
|
||||
removed_at: Mapped[Optional[datetime]] = mapped_column(DateTime)
|
||||
created_at: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=text("CURRENT_TIMESTAMP"))
|
||||
updated_at: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=text("CURRENT_TIMESTAMP"), onupdate=datetime.utcnow)
|
||||
|
||||
|
||||
class DeviceFamilyInvitation(Base):
|
||||
__tablename__ = "device_family_invitations"
|
||||
__table_args__ = (
|
||||
UniqueConstraint("invite_token", name="uq_device_family_invite_token"),
|
||||
Index("idx_device_family_invites_device_status", "device_id", "status"),
|
||||
Index("idx_device_family_invites_owner_status", "owner_user_id", "status"),
|
||||
Index("idx_device_family_invites_expires_at", "expires_at"),
|
||||
)
|
||||
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
invite_token: Mapped[str] = mapped_column(String(36), nullable=False)
|
||||
device_id: Mapped[str] = mapped_column(String(64), ForeignKey("device_auth.device_id"), nullable=False)
|
||||
owner_user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("parents.user_id"), nullable=False)
|
||||
status: Mapped[int] = mapped_column(Integer, server_default="1")
|
||||
expires_at: Mapped[datetime] = mapped_column(DateTime, nullable=False)
|
||||
accepted_by_user_id: Mapped[Optional[int]] = mapped_column(BigInteger, ForeignKey("parents.user_id", ondelete="SET NULL"))
|
||||
accepted_at: Mapped[Optional[datetime]] = mapped_column(DateTime)
|
||||
created_at: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=text("CURRENT_TIMESTAMP"))
|
||||
updated_at: Mapped[Optional[datetime]] = mapped_column(DateTime, server_default=text("CURRENT_TIMESTAMP"), onupdate=datetime.utcnow)
|
||||
|
||||
|
||||
class DeviceBindSession(Base):
|
||||
__tablename__ = "device_bind_sessions"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
bind_token: Mapped[str] = mapped_column(String(36), unique=True, nullable=False)
|
||||
device_id: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
initiator_user_id: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
target_child_id: Mapped[Optional[int]] = mapped_column(Integer)
|
||||
initiator_user_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
||||
target_child_id: Mapped[Optional[int]] = mapped_column(BigInteger)
|
||||
challenge_code_hash: Mapped[Optional[str]] = mapped_column(String(64))
|
||||
challenge_set_at: Mapped[Optional[datetime]] = mapped_column(DateTime)
|
||||
expires_at: Mapped[datetime] = mapped_column(DateTime, nullable=False)
|
||||
@@ -253,11 +294,11 @@ class DeviceBindSession(Base):
|
||||
class DeviceBindHistory(Base):
|
||||
__tablename__ = "device_bind_history"
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
device_id: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
child_id: Mapped[Optional[int]] = mapped_column(Integer)
|
||||
bound_by_user_id: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
unbound_by_user_id: Mapped[Optional[int]] = mapped_column(Integer)
|
||||
child_id: Mapped[Optional[int]] = mapped_column(BigInteger)
|
||||
bound_by_user_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
||||
unbound_by_user_id: Mapped[Optional[int]] = mapped_column(BigInteger)
|
||||
bind_source: Mapped[int] = mapped_column(Integer, server_default="1")
|
||||
bound_at: Mapped[datetime] = mapped_column(DateTime, nullable=False)
|
||||
unbound_at: Mapped[Optional[datetime]] = mapped_column(DateTime)
|
||||
@@ -271,6 +312,8 @@ class DeviceSetting(Base):
|
||||
setting_id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||||
device_id: Mapped[str] = mapped_column(String(64), unique=True, nullable=False)
|
||||
sleep_mode: Mapped[int] = mapped_column(Integer, server_default="0")
|
||||
manual_sleep_mode: Mapped[int] = mapped_column(Integer, nullable=False, server_default="0")
|
||||
schedule_suppressed_until: Mapped[Optional[datetime]] = mapped_column(DateTime)
|
||||
disable_time_start: Mapped[Optional[time]] = mapped_column(Time)
|
||||
disable_time_end: Mapped[Optional[time]] = mapped_column(Time)
|
||||
timezone: Mapped[str] = mapped_column(String(32), server_default=text("'Asia/Shanghai'"))
|
||||
|
||||
Reference in New Issue
Block a user