Initial project commit
This commit is contained in:
@@ -0,0 +1,608 @@
|
||||
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
|
||||
Reference in New Issue
Block a user