609 lines
18 KiB
Python
609 lines
18 KiB
Python
from datetime import datetime
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
class AdminLoginRequest(BaseModel):
|
|
account: str = Field(min_length=1, max_length=100)
|
|
password: str = Field(min_length=1, max_length=200)
|
|
|
|
|
|
class AdminUserOut(BaseModel):
|
|
id: int
|
|
nickname: str
|
|
phone: str | None = None
|
|
email: str | None = None
|
|
role: str
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class AdminLoginResponse(BaseModel):
|
|
access_token: str
|
|
refresh_token: str
|
|
token_type: str = "bearer"
|
|
user: AdminUserOut
|
|
|
|
|
|
class AdminSpotListItem(BaseModel):
|
|
id: int
|
|
title: str
|
|
city: str
|
|
audit_status: str
|
|
reject_reason: str | None = None
|
|
creator_id: int
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class AdminSpotImageItem(BaseModel):
|
|
id: int
|
|
image_url: str
|
|
is_cover: bool
|
|
sort_order: int
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class AdminSpotDetailItem(BaseModel):
|
|
id: int
|
|
title: str
|
|
city: str
|
|
longitude: float | None = None
|
|
latitude: float | None = None
|
|
description: str | None = None
|
|
transport: str | None = None
|
|
best_time: str | None = None
|
|
difficulty: str | None = None
|
|
is_free: bool
|
|
price_min: float | None = None
|
|
price_max: float | None = None
|
|
audit_status: str
|
|
reject_reason: str | None = None
|
|
creator_id: int
|
|
tag_ids: list[int] = []
|
|
image_urls: list[str] = []
|
|
images: list[AdminSpotImageItem] = []
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class AdminSpotCreateRequest(BaseModel):
|
|
title: str = Field(min_length=1, max_length=200)
|
|
city: str = Field(min_length=1, max_length=100)
|
|
longitude: float
|
|
latitude: float
|
|
description: str | None = None
|
|
transport: str | None = None
|
|
best_time: str | None = Field(default=None, max_length=200)
|
|
difficulty: str | None = None
|
|
is_free: bool = True
|
|
price_min: float | None = None
|
|
price_max: float | None = None
|
|
audit_status: str = Field(default="pending", pattern="^(pending|approved|rejected|deleted)$")
|
|
reject_reason: str | None = Field(default=None, max_length=500)
|
|
creator_id: int
|
|
image_urls: list[str] = []
|
|
tag_ids: list[int] = []
|
|
|
|
|
|
class AdminSpotUpdateRequest(BaseModel):
|
|
title: str | None = Field(default=None, min_length=1, max_length=200)
|
|
city: str | None = Field(default=None, min_length=1, max_length=100)
|
|
longitude: float | None = None
|
|
latitude: float | None = None
|
|
description: str | None = None
|
|
transport: str | None = None
|
|
best_time: str | None = Field(default=None, max_length=200)
|
|
difficulty: str | None = None
|
|
is_free: bool | None = None
|
|
price_min: float | None = None
|
|
price_max: float | None = None
|
|
audit_status: str | None = Field(default=None, pattern="^(pending|approved|rejected|deleted)$")
|
|
reject_reason: str | None = Field(default=None, max_length=500)
|
|
creator_id: int | None = None
|
|
image_urls: list[str] | None = None
|
|
tag_ids: list[int] | None = None
|
|
|
|
|
|
class AdminSpotAuditRequest(BaseModel):
|
|
audit_status: str = Field(pattern="^(pending|approved|rejected|deleted)$")
|
|
reject_reason: str | None = Field(default=None, max_length=500)
|
|
|
|
|
|
class AdminBatchAuditRequest(BaseModel):
|
|
ids: list[int] = Field(min_length=1)
|
|
audit_status: str = Field(pattern="^(pending|approved|rejected|deleted)$")
|
|
reject_reason: str | None = Field(default=None, max_length=500)
|
|
|
|
|
|
class AdminDashboardStats(BaseModel):
|
|
spots_total: int
|
|
spots_pending: int
|
|
spots_approved: int
|
|
spots_rejected: int
|
|
users_total: int
|
|
events_total: int
|
|
shooting_total: int
|
|
|
|
|
|
class AdminEventListItem(BaseModel):
|
|
id: int
|
|
title: str
|
|
city: str
|
|
status: str
|
|
audit_status: str
|
|
reject_reason: str | None = None
|
|
creator_id: int
|
|
registration_count: int
|
|
max_participants: int
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class AdminEventRegistrationItem(BaseModel):
|
|
id: int
|
|
event_id: int
|
|
user_id: int
|
|
user_nickname: str
|
|
status: str
|
|
created_at: datetime | None = None
|
|
|
|
|
|
class AdminEventPhotoItem(BaseModel):
|
|
id: int
|
|
event_id: int
|
|
uploader_id: int
|
|
uploader_nickname: str
|
|
image_url: str
|
|
caption: str | None = None
|
|
spot_id: int | None = None
|
|
created_at: datetime | None = None
|
|
|
|
|
|
class AdminEventPhotoInput(BaseModel):
|
|
uploader_id: int
|
|
image_url: str = Field(min_length=1, max_length=500)
|
|
caption: str | None = Field(default=None, max_length=200)
|
|
spot_id: int | None = None
|
|
|
|
|
|
class AdminEventDetailItem(BaseModel):
|
|
id: int
|
|
title: str
|
|
city: str
|
|
description: str | None = None
|
|
cover_url: str | None = None
|
|
location_name: str | None = None
|
|
start_time: datetime | None = None
|
|
end_time: datetime | None = None
|
|
max_participants: int
|
|
spot_id: int | None = None
|
|
status: str
|
|
audit_status: str
|
|
reject_reason: str | None = None
|
|
registration_count: int
|
|
creator_id: int
|
|
registration_user_ids: list[int] = []
|
|
photos: list[AdminEventPhotoItem] = []
|
|
registrations: list[AdminEventRegistrationItem] = []
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class AdminEventCreateRequest(BaseModel):
|
|
creator_id: int
|
|
title: str = Field(min_length=1, max_length=200)
|
|
city: str = Field(min_length=1, max_length=100)
|
|
description: str | None = None
|
|
cover_url: str | None = Field(default=None, max_length=500)
|
|
location_name: str | None = Field(default=None, max_length=200)
|
|
start_time: datetime | None = None
|
|
end_time: datetime | None = None
|
|
max_participants: int = Field(default=0, ge=0)
|
|
spot_id: int | None = None
|
|
status: str = Field(default="upcoming", pattern="^(upcoming|ongoing|ended|cancelled)$")
|
|
audit_status: str = Field(default="pending", pattern="^(pending|approved|rejected|deleted)$")
|
|
reject_reason: str | None = Field(default=None, max_length=500)
|
|
registration_user_ids: list[int] = []
|
|
photos: list[AdminEventPhotoInput] = []
|
|
|
|
|
|
class AdminEventUpdateRequest(BaseModel):
|
|
creator_id: int | None = None
|
|
title: str | None = Field(default=None, min_length=1, max_length=200)
|
|
city: str | None = Field(default=None, min_length=1, max_length=100)
|
|
description: str | None = None
|
|
cover_url: str | None = Field(default=None, max_length=500)
|
|
location_name: str | None = Field(default=None, max_length=200)
|
|
start_time: datetime | None = None
|
|
end_time: datetime | None = None
|
|
max_participants: int | None = Field(default=None, ge=0)
|
|
spot_id: int | None = None
|
|
status: str | None = Field(default=None, pattern="^(upcoming|ongoing|ended|cancelled)$")
|
|
audit_status: str | None = Field(default=None, pattern="^(pending|approved|rejected|deleted)$")
|
|
reject_reason: str | None = Field(default=None, max_length=500)
|
|
registration_user_ids: list[int] | None = None
|
|
photos: list[AdminEventPhotoInput] | None = None
|
|
|
|
|
|
class AdminEventRegistrationCreateRequest(BaseModel):
|
|
user_id: int
|
|
status: str = Field(default="registered", pattern="^(registered|cancelled)$")
|
|
|
|
|
|
class AdminEventRegistrationUpdateRequest(BaseModel):
|
|
status: str = Field(pattern="^(registered|cancelled)$")
|
|
|
|
|
|
class AdminEventPhotoCreateRequest(BaseModel):
|
|
uploader_id: int
|
|
image_url: str = Field(min_length=1, max_length=500)
|
|
caption: str | None = Field(default=None, max_length=200)
|
|
spot_id: int | None = None
|
|
|
|
|
|
class AdminEventPhotoUpdateRequest(BaseModel):
|
|
uploader_id: int | None = None
|
|
image_url: str | None = Field(default=None, min_length=1, max_length=500)
|
|
caption: str | None = Field(default=None, max_length=200)
|
|
spot_id: int | None = None
|
|
|
|
|
|
class AdminShootingListItem(BaseModel):
|
|
id: int
|
|
title: str
|
|
city: str
|
|
status: str
|
|
audit_status: str
|
|
reject_reason: str | None = None
|
|
creator_id: int
|
|
role_needed: str
|
|
max_applicants: int
|
|
is_free: bool
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class AdminShootingApplicationItem(BaseModel):
|
|
id: int
|
|
request_id: int
|
|
applicant_id: int
|
|
applicant_nickname: str
|
|
message: str | None = None
|
|
status: str
|
|
created_at: datetime | None = None
|
|
|
|
|
|
class AdminShootingDetailItem(BaseModel):
|
|
id: int
|
|
title: str
|
|
city: str
|
|
description: str | None = None
|
|
style: str | None = None
|
|
shoot_date: datetime | None = None
|
|
is_free: bool
|
|
budget_min: float | None = None
|
|
budget_max: float | None = None
|
|
role_needed: str
|
|
max_applicants: int
|
|
contact_info: str | None = None
|
|
spot_id: int | None = None
|
|
status: str
|
|
audit_status: str
|
|
reject_reason: str | None = None
|
|
creator_id: int
|
|
applications: list[AdminShootingApplicationItem] = []
|
|
application_user_ids: list[int] = []
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class AdminShootingApplicationInput(BaseModel):
|
|
applicant_id: int
|
|
message: str | None = None
|
|
status: str = Field(default="pending", pattern="^(pending|accepted|rejected|cancelled)$")
|
|
|
|
|
|
class AdminShootingCreateRequest(BaseModel):
|
|
creator_id: int
|
|
title: str = Field(min_length=1, max_length=200)
|
|
city: str = Field(min_length=1, max_length=100)
|
|
description: str | None = None
|
|
style: str | None = Field(default=None, max_length=100)
|
|
shoot_date: datetime | None = None
|
|
is_free: bool = False
|
|
budget_min: float | None = None
|
|
budget_max: float | None = None
|
|
role_needed: str = Field(default="photographer", pattern="^(photographer|cosplayer|both)$")
|
|
max_applicants: int = Field(default=1, ge=1, le=100)
|
|
contact_info: str | None = Field(default=None, max_length=200)
|
|
spot_id: int | None = None
|
|
status: str = Field(default="open", pattern="^(open|matched|closed|cancelled)$")
|
|
audit_status: str = Field(default="pending", pattern="^(pending|approved|rejected|deleted)$")
|
|
reject_reason: str | None = Field(default=None, max_length=500)
|
|
applications: list[AdminShootingApplicationInput] = []
|
|
|
|
|
|
class AdminShootingUpdateRequest(BaseModel):
|
|
creator_id: int | None = None
|
|
title: str | None = Field(default=None, min_length=1, max_length=200)
|
|
city: str | None = Field(default=None, min_length=1, max_length=100)
|
|
description: str | None = None
|
|
style: str | None = Field(default=None, max_length=100)
|
|
shoot_date: datetime | None = None
|
|
is_free: bool | None = None
|
|
budget_min: float | None = None
|
|
budget_max: float | None = None
|
|
role_needed: str | None = Field(default=None, pattern="^(photographer|cosplayer|both)$")
|
|
max_applicants: int | None = Field(default=None, ge=1, le=100)
|
|
contact_info: str | None = Field(default=None, max_length=200)
|
|
spot_id: int | None = None
|
|
status: str | None = Field(default=None, pattern="^(open|matched|closed|cancelled)$")
|
|
audit_status: str | None = Field(default=None, pattern="^(pending|approved|rejected|deleted)$")
|
|
reject_reason: str | None = Field(default=None, max_length=500)
|
|
applications: list[AdminShootingApplicationInput] | None = None
|
|
|
|
|
|
class AdminShootingApplicationCreateRequest(BaseModel):
|
|
applicant_id: int
|
|
message: str | None = None
|
|
status: str = Field(default="pending", pattern="^(pending|accepted|rejected|cancelled)$")
|
|
|
|
|
|
class AdminShootingApplicationUpdateRequest(BaseModel):
|
|
message: str | None = None
|
|
status: str = Field(pattern="^(pending|accepted|rejected|cancelled)$")
|
|
|
|
|
|
class AdminAuditRequest(BaseModel):
|
|
audit_status: str = Field(pattern="^(pending|approved|rejected|deleted)$")
|
|
reject_reason: str | None = Field(default=None, max_length=500)
|
|
|
|
|
|
class AdminModuleCrudCoverage(BaseModel):
|
|
create: bool
|
|
read: bool
|
|
update: bool
|
|
delete: bool
|
|
|
|
|
|
class AdminModuleDesignItem(BaseModel):
|
|
module_key: str
|
|
module_name: str
|
|
models: list[str]
|
|
api_endpoint_prefixes: list[str]
|
|
coverage: AdminModuleCrudCoverage
|
|
status: str
|
|
notes: str
|
|
|
|
|
|
class AdminModuleDesignResponse(BaseModel):
|
|
total_modules: int
|
|
full_covered: int
|
|
partial_covered: int
|
|
missing_covered: int
|
|
items: list[AdminModuleDesignItem]
|
|
|
|
|
|
class AdminUserListItem(BaseModel):
|
|
id: int
|
|
nickname: str
|
|
phone: str | None = None
|
|
email: str | None = None
|
|
city: str | None = None
|
|
identity: str | None = None
|
|
role: str
|
|
is_active: bool
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class AdminUserCreateRequest(BaseModel):
|
|
nickname: str = Field(min_length=1, max_length=50)
|
|
password: str = Field(min_length=6, max_length=200)
|
|
phone: str | None = Field(default=None, max_length=20)
|
|
email: str | None = Field(default=None, max_length=255)
|
|
city: str | None = Field(default=None, max_length=100)
|
|
identity: str = Field(default="both", pattern="^(photographer|cosplayer|both)$")
|
|
role: str = Field(default="user", pattern="^(user|moderator|admin)$")
|
|
is_active: bool = True
|
|
|
|
|
|
class AdminUserUpdateRequest(BaseModel):
|
|
nickname: str | None = Field(default=None, min_length=1, max_length=50)
|
|
phone: str | None = Field(default=None, max_length=20)
|
|
email: str | None = Field(default=None, max_length=255)
|
|
city: str | None = Field(default=None, max_length=100)
|
|
identity: str | None = Field(default=None, pattern="^(photographer|cosplayer|both)$")
|
|
role: str | None = Field(default=None, pattern="^(user|moderator|admin)$")
|
|
is_active: bool | None = None
|
|
password: str | None = Field(default=None, min_length=6, max_length=200)
|
|
|
|
|
|
class AdminMembershipPlanItem(BaseModel):
|
|
id: int
|
|
name: str
|
|
description: str | None = None
|
|
duration_days: int
|
|
price: float
|
|
benefits: str | None = None
|
|
extra_uploads: int
|
|
extra_top_count: int
|
|
is_active: bool
|
|
sort_order: int
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class AdminMembershipPlanCreateRequest(BaseModel):
|
|
name: str = Field(min_length=1, max_length=100)
|
|
description: str | None = None
|
|
duration_days: int = Field(ge=1, le=3650)
|
|
price: float = Field(ge=0)
|
|
benefits: str | None = None
|
|
extra_uploads: int = Field(default=0, ge=0)
|
|
extra_top_count: int = Field(default=0, ge=0)
|
|
is_active: bool = True
|
|
sort_order: int = 0
|
|
|
|
|
|
class AdminMembershipPlanUpdateRequest(BaseModel):
|
|
name: str | None = Field(default=None, min_length=1, max_length=100)
|
|
description: str | None = None
|
|
duration_days: int | None = Field(default=None, ge=1, le=3650)
|
|
price: float | None = Field(default=None, ge=0)
|
|
benefits: str | None = None
|
|
extra_uploads: int | None = Field(default=None, ge=0)
|
|
extra_top_count: int | None = Field(default=None, ge=0)
|
|
is_active: bool | None = None
|
|
sort_order: int | None = None
|
|
|
|
|
|
class AdminUserMembershipItem(BaseModel):
|
|
id: int
|
|
user_id: int
|
|
user_nickname: str
|
|
plan_id: int
|
|
plan_name: str
|
|
start_date: datetime
|
|
end_date: datetime
|
|
is_active: bool
|
|
|
|
|
|
class AdminUserMembershipCreateRequest(BaseModel):
|
|
user_id: int
|
|
plan_id: int
|
|
start_date: datetime
|
|
end_date: datetime
|
|
is_active: bool = True
|
|
|
|
|
|
class AdminUserMembershipUpdateRequest(BaseModel):
|
|
plan_id: int | None = None
|
|
start_date: datetime | None = None
|
|
end_date: datetime | None = None
|
|
is_active: bool | None = None
|
|
|
|
|
|
class AdminPointLedgerItem(BaseModel):
|
|
id: int
|
|
user_id: int
|
|
user_nickname: str
|
|
change: int
|
|
balance: int
|
|
reason: str
|
|
ref_type: str | None = None
|
|
ref_id: int | None = None
|
|
rolled_back: bool = False
|
|
created_at: datetime
|
|
|
|
|
|
class AdminPointAdjustRequest(BaseModel):
|
|
user_id: int
|
|
change: int = Field(ne=0)
|
|
reason: str = Field(min_length=1, max_length=200)
|
|
ref_type: str | None = Field(default=None, max_length=50)
|
|
ref_id: int | None = None
|
|
|
|
|
|
class AdminNotificationItem(BaseModel):
|
|
id: int
|
|
user_id: int
|
|
user_nickname: str
|
|
type: str
|
|
title: str
|
|
content: str | None = None
|
|
ref_type: str | None = None
|
|
ref_id: int | None = None
|
|
is_read: bool
|
|
created_at: datetime
|
|
|
|
|
|
class AdminNotificationCreateRequest(BaseModel):
|
|
user_id: int
|
|
type: str = Field(min_length=1, max_length=50)
|
|
title: str = Field(min_length=1, max_length=200)
|
|
content: str | None = None
|
|
ref_type: str | None = Field(default=None, max_length=50)
|
|
ref_id: int | None = None
|
|
|
|
|
|
class AdminNotificationUpdateRequest(BaseModel):
|
|
title: str | None = Field(default=None, min_length=1, max_length=200)
|
|
content: str | None = None
|
|
is_read: bool | None = None
|
|
|
|
|
|
class AdminAuditLogItem(BaseModel):
|
|
id: int
|
|
operator_id: int
|
|
operator_nickname: str
|
|
action: str
|
|
target_type: str
|
|
target_id: int | None = None
|
|
detail: str | None = None
|
|
created_at: datetime
|
|
|
|
|
|
class AdminAuditLogCreateRequest(BaseModel):
|
|
action: str = Field(min_length=1, max_length=100)
|
|
target_type: str = Field(min_length=1, max_length=50)
|
|
target_id: int | None = None
|
|
detail: str | None = None
|
|
|
|
|
|
class AdminReportItem(BaseModel):
|
|
id: int
|
|
reporter_id: int
|
|
reporter_nickname: str
|
|
target_type: str
|
|
target_id: int
|
|
reason: str
|
|
status: str
|
|
handler_id: int | None = None
|
|
handler_nickname: str | None = None
|
|
conclusion: str | None = None
|
|
created_at: datetime
|
|
resolved_at: datetime | None = None
|
|
|
|
|
|
class AdminReportUpdateRequest(BaseModel):
|
|
status: str | None = Field(default=None, pattern="^(pending|processing|resolved|rejected)$")
|
|
handler_id: int | None = None
|
|
conclusion: str | None = None
|
|
|
|
|
|
class AdminSystemConfigItem(BaseModel):
|
|
id: int
|
|
config_key: str
|
|
category: str
|
|
title: str
|
|
config_json: str
|
|
description: str | None = None
|
|
is_active: bool
|
|
sort_order: int
|
|
updated_by: int | None = None
|
|
updated_at: datetime | None = None
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class AdminSystemConfigCreateRequest(BaseModel):
|
|
config_key: str = Field(min_length=1, max_length=100)
|
|
category: str = Field(min_length=1, max_length=50)
|
|
title: str = Field(min_length=1, max_length=200)
|
|
config_json: str = Field(min_length=2)
|
|
description: str | None = None
|
|
is_active: bool = True
|
|
sort_order: int = 0
|
|
|
|
|
|
class AdminSystemConfigUpdateRequest(BaseModel):
|
|
category: str | None = Field(default=None, min_length=1, max_length=50)
|
|
title: str | None = Field(default=None, min_length=1, max_length=200)
|
|
config_json: str | None = Field(default=None, min_length=2)
|
|
description: str | None = None
|
|
is_active: bool | None = None
|
|
sort_order: int | None = None
|