feat: add invite rewards and redeem codes

This commit is contained in:
zl-q
2026-05-21 16:26:58 +08:00
parent d712645754
commit 673f8fed30
67 changed files with 3813 additions and 265 deletions
@@ -42,27 +42,79 @@ def upgrade() -> None:
sa.Column("total_latency_ms", sa.Integer(), nullable=True),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("last_activity_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("anonymized_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False),
sa.Column(
"anonymized_at",
sa.DateTime(timezone=True),
server_default=sa.text("now()"),
nullable=False,
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index("ix_anonymous_session_snapshots_anonymous_id", "anonymous_session_snapshots", ["anonymous_id"])
op.create_index("ix_anonymous_session_snapshots_created_at", "anonymous_session_snapshots", ["created_at"])
op.create_index("ix_anonymous_session_snapshots_question_type", "anonymous_session_snapshots", ["question_type"])
op.create_index(
"ix_anonymous_session_snapshots_anonymous_id",
"anonymous_session_snapshots",
["anonymous_id"],
)
op.create_index(
"ix_anonymous_session_snapshots_created_at",
"anonymous_session_snapshots",
["created_at"],
)
op.create_index(
"ix_anonymous_session_snapshots_question_type",
"anonymous_session_snapshots",
["question_type"],
)
_enable_service_role_all_rls("anonymous_session_snapshots")
op.create_table(
"user_feedback",
sa.Column("id", postgresql.UUID(as_uuid=True), server_default=sa.text("gen_random_uuid()"), nullable=False),
sa.Column(
"id",
postgresql.UUID(as_uuid=True),
server_default=sa.text("gen_random_uuid()"),
nullable=False,
),
sa.Column("user_id", postgresql.UUID(as_uuid=True), nullable=True),
sa.Column("feedback_type", sa.String(length=20), server_default=sa.text("'other'"), nullable=False),
sa.Column(
"feedback_type",
sa.String(length=20),
server_default=sa.text("'other'"),
nullable=False,
),
sa.Column("content", sa.Text(), nullable=False),
sa.Column("images", postgresql.JSONB(astext_type=sa.Text()), server_default=sa.text("'[]'::jsonb"), nullable=False),
sa.Column("device_info", postgresql.JSONB(astext_type=sa.Text()), server_default=sa.text("'{}'::jsonb"), nullable=False),
sa.Column(
"images",
postgresql.JSONB(astext_type=sa.Text()),
server_default=sa.text("'[]'::jsonb"),
nullable=False,
),
sa.Column(
"device_info",
postgresql.JSONB(astext_type=sa.Text()),
server_default=sa.text("'{}'::jsonb"),
nullable=False,
),
sa.Column("app_version", sa.String(length=20), nullable=False),
sa.Column("os_version", sa.String(length=50), nullable=False),
sa.Column("status", sa.String(length=20), server_default=sa.text("'pending'"), nullable=False),
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False),
sa.Column(
"status",
sa.String(length=20),
server_default=sa.text("'pending'"),
nullable=False,
),
sa.Column(
"created_at",
sa.DateTime(timezone=True),
server_default=sa.text("now()"),
nullable=False,
),
sa.Column(
"updated_at",
sa.DateTime(timezone=True),
server_default=sa.text("now()"),
nullable=False,
),
sa.ForeignKeyConstraint(["user_id"], ["auth.users.id"], ondelete="SET NULL"),
sa.PrimaryKeyConstraint("id"),
)
@@ -70,12 +122,22 @@ def upgrade() -> None:
op.create_index("ix_user_feedback_created_at", "user_feedback", ["created_at"])
op.create_index("ix_user_feedback_status", "user_feedback", ["status"])
op.execute("COMMENT ON TABLE user_feedback IS '用户反馈表'")
op.execute("COMMENT ON COLUMN user_feedback.user_id IS '用户ID,NULL表示匿名(勾选不上传我的个人信息)'")
op.execute("COMMENT ON COLUMN user_feedback.feedback_type IS '反馈类型: bug/suggestion/other'")
op.execute(
"COMMENT ON COLUMN user_feedback.user_id IS '用户ID,NULL表示匿名(勾选不上传我的个人信息)'"
)
op.execute(
"COMMENT ON COLUMN user_feedback.feedback_type IS '反馈类型: bug/suggestion/other'"
)
op.execute("COMMENT ON COLUMN user_feedback.content IS '反馈内容,最多500字'")
op.execute("COMMENT ON COLUMN user_feedback.images IS '图片Storage路径列表,最多3张'")
op.execute("COMMENT ON COLUMN user_feedback.device_info IS '设备信息JSON,匿名时照样采集(不涉及隐私)'")
op.execute("COMMENT ON COLUMN user_feedback.status IS '处理状态: pending/processed'")
op.execute(
"COMMENT ON COLUMN user_feedback.images IS '图片Storage路径列表,最多3张'"
)
op.execute(
"COMMENT ON COLUMN user_feedback.device_info IS '设备信息JSON,匿名时照样采集(不涉及隐私)'"
)
op.execute(
"COMMENT ON COLUMN user_feedback.status IS '处理状态: pending/processed'"
)
_enable_service_role_all_rls("user_feedback")
@@ -89,7 +151,9 @@ def downgrade() -> None:
def _enable_service_role_all_rls(table_name: str) -> None:
op.execute(f"ALTER TABLE {table_name} ENABLE ROW LEVEL SECURITY")
op.execute(f"CREATE POLICY service_role_all_{table_name} ON {table_name} FOR ALL TO service_role USING (true) WITH CHECK (true)")
op.execute(
f"CREATE POLICY service_role_all_{table_name} ON {table_name} FOR ALL TO service_role USING (true) WITH CHECK (true)"
)
def _drop_service_role_all_rls(table_name: str) -> None: