first commit
This commit is contained in:
855
API文档.md
855
API文档.md
@@ -1,855 +0,0 @@
|
||||
# Sycamore_whisper API 文档
|
||||
|
||||
**
|
||||
|
||||
## 一、基础信息
|
||||
|
||||
| 项目 | 内容 |
|
||||
| ---------- | ------------------------------------------------------------ |
|
||||
| 响应格式 | 所有 API 响应均为 JSON 格式(除非特殊说明) |
|
||||
| 成功状态码 | 通常为 200(请求成功)或 201(资源创建成功) |
|
||||
| 权限说明 | 管理接口需在请求头中携带 Authorization: Bearer {ADMIN_TOKEN} 进行身份验证 |
|
||||
|
||||
## 二、通用说明
|
||||
|
||||
1. 错误响应均会附带明确错误信息,帮助定位问题;
|
||||
|
||||
2. 图片上传大小限制为 10MB,支持常见图片格式(png, jpg, jpeg, gif, webp);
|
||||
3. 分页接口默认按 “ID 降序” 排列数据,未指定页码时默认返回第 1 页;
|
||||
4. 涉及 “帖子 ID”“评论 ID”“举报 ID” 的接口,若 ID 不存在则返回 404 错误。
|
||||
|
||||
## 三、公共接口(无需管理员权限)
|
||||
|
||||
### 3.1 提交帖子
|
||||
|
||||
- **URL**: /post
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **功能描述**: 提交新帖子内容,是否需要审核取决于当前系统审核模式
|
||||
|
||||
- **请求体(JSON)**:
|
||||
|
||||
```
|
||||
{
|
||||
"content": "帖子内容"
|
||||
}
|
||||
```
|
||||
|
||||
- **成功响应(201 Created)**:
|
||||
|
||||
```
|
||||
{
|
||||
"id": 1, // 新创建帖子的ID
|
||||
"status": "Pending" // 状态:Pending(待审核)/ Pass(直接通过,无需审核)
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**:
|
||||
|
||||
- - 400 Bad Request:帖子内容为空
|
||||
|
||||
- - 403 Forbidden:内容包含违规关键词
|
||||
|
||||
### 3.2 帖子点赞 / 点踩
|
||||
|
||||
#### 3.2.1 帖子点赞
|
||||
|
||||
- **URL**: /up
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **功能描述**: 给指定 ID 的帖子点赞
|
||||
|
||||
- **请求体(JSON)**:
|
||||
|
||||
```
|
||||
{
|
||||
"id": 1 // 帖子ID(必填)
|
||||
}
|
||||
```
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"status": "OK"
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**:
|
||||
|
||||
- - 400 Bad Request:缺少帖子 ID
|
||||
|
||||
- - 404 Not Found:帖子不存在
|
||||
|
||||
#### 3.2.2 帖子点踩
|
||||
|
||||
- **URL**: /down
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **请求体、成功响应、错误响应**:与 “帖子点赞” 接口完全一致
|
||||
|
||||
### 3.3 发布评论
|
||||
|
||||
- **URL**: /comment
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **功能描述**: 给帖子添加顶级评论,或回复已有评论
|
||||
|
||||
- **请求体(JSON)**:
|
||||
|
||||
```
|
||||
{
|
||||
"content": "评论内容",
|
||||
"submission_id": 1, // 关联的帖子ID
|
||||
"parent_comment_id": 0, // 父评论ID:0=顶级评论,非0=回复指定评论
|
||||
"nickname": "匿名用户" // 用户名
|
||||
}
|
||||
```
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"id": 1, // 新创建评论的ID
|
||||
"status": "Pass"
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**:
|
||||
|
||||
- - 400 Bad Request:缺少 content/submission_id/parent_comment_id,或 parent_comment_id 指向不存在的评论
|
||||
|
||||
- - 403 Forbidden:评论内容包含违规关键词
|
||||
|
||||
- - 404 Not Found:关联的帖子不存在
|
||||
|
||||
### 3.4 图片上传与访问
|
||||
|
||||
#### 3.4.1 上传图片
|
||||
|
||||
- **URL**: /upload_pic
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **请求体格式**: multipart/form-data,需包含名为file的图片文件
|
||||
|
||||
- **功能描述**: 上传图片至服务器,返回图片访问 URL
|
||||
|
||||
- **成功响应(201 Created)**:
|
||||
|
||||
```
|
||||
{
|
||||
"status": "OK",
|
||||
"url": "/img/230615_abcd1.png" // 图片访问URL
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**:
|
||||
|
||||
- - 400 Bad Request:未上传文件、文件格式不支持(非图片)、文件大小超过 10MB
|
||||
|
||||
#### 3.4.2 访问图片
|
||||
|
||||
- **URL**: /img/{filename} ({filename} 替换为图片文件名,如 230615_abcd1.png)
|
||||
|
||||
- **请求方法**: GET
|
||||
|
||||
- **功能描述**: 通过文件名直接访问图片
|
||||
|
||||
- **成功响应(200 OK)**: 返回图片文件(如 PNG/JPG 格式)
|
||||
|
||||
- **错误响应**: 403 Forbidden:访问的文件格式不允许(非图片文件)
|
||||
|
||||
### 3.5 举报与状态查询
|
||||
|
||||
#### 3.5.1 提交举报
|
||||
|
||||
- **URL**: /report
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **功能描述**: 举报违规帖子,需提供举报标题和具体理由
|
||||
|
||||
- **请求体(JSON)**:
|
||||
|
||||
```
|
||||
{
|
||||
"id": 1, // 被举报帖子的ID(必填)
|
||||
"title": "举报标题(必填,如“帖子包含广告”)",
|
||||
"content": "举报内容(必填,详细说明违规点)"
|
||||
}
|
||||
```
|
||||
|
||||
- **成功响应(201 Created)**:
|
||||
|
||||
```
|
||||
{
|
||||
"id": 1, // 举报记录的ID
|
||||
"status": "OK"
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**:
|
||||
|
||||
- - 400 Bad Request:缺少 id/title/content
|
||||
|
||||
- - 404 Not Found:被举报的帖子不存在
|
||||
|
||||
#### 3.5.2 获取帖子状态
|
||||
|
||||
- **URL**: /get/post_state
|
||||
|
||||
- **请求方法**: GET
|
||||
|
||||
- **请求参数(Query)**: id=1(帖子 ID,必填)
|
||||
|
||||
- **功能描述**: 查询指定帖子的审核状态
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"status": "Approved" | "Rejected" | "Pending" | "Deleted or Not Found"
|
||||
// Approved=已通过,Rejected=已拒绝,Pending=待审核,Deleted or Not Found=已删除或不存在
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**: 400 Bad Request:缺少帖子 ID
|
||||
|
||||
#### 3.5.3 获取举报状态
|
||||
|
||||
- **URL**: /get/report_state
|
||||
|
||||
- **请求方法**: GET
|
||||
|
||||
- **请求参数(Query)**: id=1(举报 ID,必填)
|
||||
|
||||
- **功能描述**: 查询指定举报的处理状态
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"status": "Approved" | "Rejected" | "Pending" | "Deleted or Not Found"
|
||||
// Approved=举报通过(帖子已处理),Rejected=举报驳回,Pending=待处理,Deleted or Not Found=举报记录已删除或不存在
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**: 400 Bad Request:缺少举报 ID
|
||||
|
||||
### 3.6 帖子详情与列表
|
||||
|
||||
#### 3.6.1 获取帖子详情
|
||||
|
||||
- **URL**: /get/post_info
|
||||
|
||||
- **请求方法**: GET
|
||||
|
||||
- **请求参数(Query)**: id=1(帖子 ID,必填)
|
||||
|
||||
- **功能描述**: 查询已通过审核的帖子详情(含点赞 / 点踩数)
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"id": 1,
|
||||
"content": "帖子内容",
|
||||
"upvotes": 10, // 点赞数
|
||||
"downvotes": 2 // 点踩数
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**:
|
||||
|
||||
- - 400 Bad Request:缺少帖子 ID
|
||||
|
||||
- - 404 Not Found:帖子不存在或未通过审核
|
||||
|
||||
#### 3.6.2 获取帖子评论
|
||||
|
||||
- **URL**: /get/comment
|
||||
|
||||
- **请求方法**: GET
|
||||
|
||||
- **请求参数(Query)**: id=1(帖子 ID,必填)
|
||||
|
||||
- **功能描述**: 查询指定帖子的所有评论
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"nickname": "用户名",
|
||||
"content": "评论内容",
|
||||
"parent_comment_id": 0 // 0=顶级评论,非0=回复评论
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
- **错误响应**:
|
||||
|
||||
- - 400 Bad Request:缺少帖子 ID
|
||||
|
||||
- - 404 Not Found:帖子不存在或未通过审核
|
||||
|
||||
#### 3.6.3 分页获取帖子列表
|
||||
|
||||
- **URL**: /get/10_info
|
||||
|
||||
- **请求方法**: GET
|
||||
|
||||
- **请求参数(Query)**: page=1(页码,可选,默认 1)
|
||||
|
||||
- **功能描述**: 分页返回已通过审核的帖子,每页 10 条,按 ID 降序排列
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"content": "帖子内容",
|
||||
"upvotes": 10,
|
||||
"downvotes": 2
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### 3.7 其他公共接口
|
||||
|
||||
#### 3.7.1 获取统计信息
|
||||
|
||||
- **URL**: /get/statics
|
||||
|
||||
- **请求方法**: GET
|
||||
|
||||
- **功能描述**: 查询系统总数据统计(帖子、评论、图片数量)
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"posts": 100, // 总帖子数
|
||||
"comments": 500, // 总评论数
|
||||
"images": 50 // 总图片数
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.7.2 测试接口
|
||||
|
||||
- **URL**: /test
|
||||
|
||||
- **请求方法**: GET / POST
|
||||
|
||||
- **功能描述**: 验证 API 服务是否正常运行
|
||||
|
||||
- **成功响应(200 OK)**: API OK!!!(文本格式)
|
||||
|
||||
#### 3.7.3 获取 API 信息
|
||||
|
||||
- **URL**: /get/api_info
|
||||
|
||||
- **请求方法**: GET
|
||||
|
||||
- **功能描述**: 获取 API 版本、开发者等信息
|
||||
|
||||
- **成功响应(200 OK)**: 返回包含 API 信息的 HTML 页面
|
||||
|
||||
#### 3.7.4 茶壶彩蛋
|
||||
|
||||
- **URL**: /get/teapot
|
||||
|
||||
- **请求方法**: GET
|
||||
|
||||
- **响应**: 418 I'm a teapot
|
||||
|
||||
## 四、管理接口
|
||||
|
||||
### 4.1 审核模式管理
|
||||
|
||||
#### 4.1.1 切换审核模式
|
||||
|
||||
- **URL**: /admin/need_audit
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **功能描述**: 开启 / 关闭帖子审核模式(开启后新帖子需审核才能通过)
|
||||
|
||||
- **请求体(JSON)**:
|
||||
|
||||
```
|
||||
{
|
||||
"need_audit": true | false // true=开启审核,false=关闭审核(必填)
|
||||
}
|
||||
```
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"status": "OK"
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**:
|
||||
|
||||
- - 400 Bad Request:缺少 need_audit 参数,或参数不是布尔值
|
||||
|
||||
- - 401 Unauthorized / 403 Forbidden:管理员权限验证失败
|
||||
|
||||
#### 4.1.2 获取当前审核模式
|
||||
|
||||
- **URL**: /admin/get/need_audit
|
||||
|
||||
- **请求方法**: GET
|
||||
|
||||
- **功能描述**: 查询当前系统的帖子审核模式
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"status": true | false // true=开启审核,false=关闭审核
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**: 401/403:管理员权限验证失败
|
||||
|
||||
### 4.2 帖子管理
|
||||
|
||||
#### 4.2.1 审核通过帖子
|
||||
|
||||
- **URL**: /admin/approve
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **功能描述**: 将待审核的帖子标记为 “已通过”
|
||||
|
||||
- **请求体(JSON)**:
|
||||
|
||||
```
|
||||
{
|
||||
"id": 1 // 待审核帖子的ID(必填)
|
||||
}
|
||||
```
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"status": "OK"
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**: 401/403:权限失败;400:缺少 ID;404:帖子不存在
|
||||
|
||||
#### 4.2.2 拒绝帖子
|
||||
|
||||
- **URL**: /admin/disapprove
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **请求体、成功响应、错误响应**:与 “审核通过帖子” 接口一致
|
||||
|
||||
#### 4.2.3 重新审核帖子
|
||||
|
||||
- **URL**: /admin/reaudit
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **功能描述**: 将已通过审核的帖子重新标记为 “待审核”
|
||||
|
||||
- **请求体、成功响应、错误响应**:与 “审核通过帖子” 接口一致
|
||||
|
||||
#### 4.2.4 删除帖子
|
||||
|
||||
- **URL**: /admin/del_post
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **功能描述**: 永久删除指定帖子
|
||||
|
||||
- **请求体(JSON)**:
|
||||
|
||||
```
|
||||
{
|
||||
"id": 1 // 帖子ID(必填)
|
||||
}
|
||||
```
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"status": "OK"
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**: 401/403:权限失败;400:缺少 ID;404:帖子不存在
|
||||
|
||||
#### 4.2.5 修改帖子
|
||||
|
||||
- **URL**: /admin/modify_post
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **功能描述**: 修改指定帖子的内容
|
||||
|
||||
- **请求体(JSON)**:
|
||||
|
||||
```
|
||||
{
|
||||
"id": 1, // 帖子ID(必填)
|
||||
"content": "新的帖子内容(必填)"
|
||||
}
|
||||
```
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"status": "OK"
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**: 401/403:权限失败;400:缺少 ID 或 content;404:帖子不存在
|
||||
|
||||
### 4.3 评论与图片管理
|
||||
|
||||
#### 4.3.1 删除评论
|
||||
|
||||
- **URL**: /admin/del_comment
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **功能描述**: 永久删除指定评论
|
||||
|
||||
- **请求体(JSON)**:
|
||||
|
||||
```
|
||||
{
|
||||
"id": 1 // 评论ID(必填)
|
||||
}
|
||||
```
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"status": "OK"
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**: 401/403:权限失败;400:缺少 ID;404:评论不存在
|
||||
|
||||
#### 4.3.2 修改评论
|
||||
|
||||
- **URL**: /admin/modify_comment
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **功能描述**: 修改指定评论的内容、用户名或父评论 ID
|
||||
|
||||
- **请求体(JSON)**:
|
||||
|
||||
```
|
||||
{
|
||||
"id": 1, // 评论ID(必填)
|
||||
"content": "新评论内容(必填)",
|
||||
"parent_comment_id": 0, // 新的父评论ID(必填)
|
||||
"nickname": "新用户名(必填)"
|
||||
}
|
||||
```
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"status": "OK"
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**: 401/403:权限失败;400:缺少必填字段;404:评论或父评论不存在
|
||||
|
||||
#### 4.3.3 删除图片
|
||||
|
||||
- **URL**: /admin/del_pic
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **功能描述**: 永久删除服务器上的指定图片
|
||||
|
||||
- **请求体(JSON)**:
|
||||
|
||||
```
|
||||
{
|
||||
"filename": "230615_abcd1.png" // 图片文件名(必填)
|
||||
}
|
||||
```
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"status": "OK"
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**: 401/403:权限失败;400:缺少 filename;404:图片不存在
|
||||
|
||||
### 4.4 举报管理
|
||||
|
||||
#### 4.4.1 批准举报
|
||||
|
||||
- **URL**: /admin/approve_report
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **功能描述**: 批准用户提交的举报,系统将自动删除被举报的违规帖子
|
||||
|
||||
- **请求体(JSON)**:
|
||||
|
||||
```
|
||||
{
|
||||
"id": 1 // 举报记录的ID(必填)
|
||||
}
|
||||
```
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"status": "OK"
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**:
|
||||
|
||||
- - 401/403:管理员权限验证失败
|
||||
|
||||
- - 400 Bad Request:缺少举报 ID
|
||||
|
||||
- - 404 Not Found:举报记录不存在或已处理
|
||||
|
||||
#### 4.4.2 拒绝举报
|
||||
|
||||
- **URL**: /admin/reject_report
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **功能描述**: 驳回用户提交的举报,被举报帖子将保持原有状态
|
||||
|
||||
- **请求体(JSON)**:
|
||||
|
||||
```
|
||||
{
|
||||
"id": 1 // 举报记录的ID(必填)
|
||||
}
|
||||
```
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"status": "OK"
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**: 与 “批准举报” 接口完全一致
|
||||
|
||||
### 4.5 数据备份与恢复
|
||||
|
||||
#### 4.5.1 创建备份
|
||||
|
||||
- **URL**: /admin/get/backup
|
||||
|
||||
- **请求方法**: GET
|
||||
|
||||
- **功能描述**: 自动备份系统数据库(含帖子、评论、举报数据)和所有上传图片,生成 ZIP 格式压缩包供下载
|
||||
|
||||
- **成功响应(200 OK)**: 返回 ZIP 格式的备份文件(文件名为 “backup_YYYYMMDD_HHMMSS.zip”,如 “backup_20240520_143025.zip”)
|
||||
|
||||
- **错误响应**: 401/403:管理员权限验证失败
|
||||
|
||||
#### 4.5.2 恢复备份
|
||||
|
||||
- **URL**: /admin/recover
|
||||
|
||||
- **请求方法**: POST
|
||||
|
||||
- **请求体格式**: multipart/form-data,需包含名为backup_file的 ZIP 备份文件
|
||||
|
||||
- **功能描述**: 从备份文件恢复系统数据(覆盖现有数据库和图片,操作不可逆,建议提前二次备份)
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"status": "OK"
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**:
|
||||
|
||||
- - 401/403:管理员权限验证失败
|
||||
|
||||
- - 400 Bad Request:未上传文件、文件不是 ZIP 格式或备份文件损坏
|
||||
|
||||
- - 500 Internal Server Error:恢复过程中出现数据错误
|
||||
|
||||
### 4.6 管理端数据查询
|
||||
|
||||
#### 4.6.1 获取待审核帖子
|
||||
|
||||
- **URL**: /admin/get/pending_posts
|
||||
|
||||
- **请求方法**: GET
|
||||
|
||||
- **功能描述**: 查询系统中所有状态为 “待审核” 的帖子列表(含未通过普通用户查询的待审核内容)
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"content": "待审核的帖子内容",
|
||||
"create_time": "2024-05-20 14:20:30", // 帖子创建时间
|
||||
"upvotes": 0,
|
||||
"downvotes": 0
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
- **错误响应**: 401/403:管理员权限验证失败
|
||||
|
||||
#### 4.6.2 获取已拒绝帖子
|
||||
|
||||
- **URL**: /admin/get/reject_posts
|
||||
|
||||
- **请求方法**: GET
|
||||
|
||||
- **功能描述**: 查询系统中所有状态为 “已拒绝” 的帖子列表
|
||||
|
||||
- **成功响应(200 OK)**: 格式与 “获取待审核帖子” 一致,仅包含 “已拒绝” 状态的帖子
|
||||
|
||||
- **错误响应**: 401/403:管理员权限验证失败
|
||||
|
||||
#### 4.6.3 获取图片链接列表
|
||||
|
||||
- **URL**: /admin/get/pic_links
|
||||
|
||||
- **请求方法**: GET
|
||||
|
||||
- **请求参数(Query)**: page=1(页码,可选,默认 1,每页返回 20 条图片链接)
|
||||
|
||||
- **功能描述**: 查询系统中所有已上传图片的访问 URL 和文件名
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
[
|
||||
"/img/251012_nfXWz.png",
|
||||
"/img/251012_JrTrD.png",
|
||||
"/img/251012_sk7ll.png",
|
||||
"/img/251012_8efux.png",
|
||||
"/img/251012_zK8fz.jpg",
|
||||
"/img/251012_B0nkO.jpg",
|
||||
"/img/251012_nNV3o.png"
|
||||
]
|
||||
```
|
||||
|
||||
- **错误响应**: 401/403:管理员权限验证失败
|
||||
|
||||
#### 4.6.4 获取待处理举报
|
||||
|
||||
- **URL**: /admin/get/pending_reports
|
||||
|
||||
- **请求方法**: GET
|
||||
|
||||
- **功能描述**: 查询系统中所有状态为 “待处理” 的举报记录列表
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
[
|
||||
{
|
||||
"id": 1, // 举报ID
|
||||
"reported_post_id": 2, // 被举报帖子ID
|
||||
"reported_post_content": "被举报的帖子内容", // 被举报帖子内容(便于审核)
|
||||
"title": "举报标题",
|
||||
"content": "举报详细内容",
|
||||
"submit_time": "2024-05-20 15:00:45" // 举报提交时间
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
- **错误响应**: 401/403:管理员权限验证失败
|
||||
|
||||
### 4.7 管理员工具接口
|
||||
|
||||
#### 4.7.1 管理员测试接口
|
||||
|
||||
- **URL**: /admin/test
|
||||
|
||||
- **请求方法**: GET / POST
|
||||
|
||||
- **功能描述**: 验证管理员权限接口是否正常运行(需携带管理员 Token)
|
||||
|
||||
- **成功响应(200 OK)**: Admin API OK!!!(文本格式)
|
||||
|
||||
- **错误响应**: 401/403:管理员权限验证失败
|
||||
|
||||
#### 4.7.2 获取管理员视角的帖子详情
|
||||
|
||||
- **URL**: /admin/get/post_info
|
||||
|
||||
- **请求方法**: GET
|
||||
|
||||
- **请求参数(Query)**: id=1(帖子 ID,必填)
|
||||
|
||||
- **功能描述**: 查看指定帖子的完整信息(含创建时间、更新时间、审核状态,不受 “未通过审核” 限制)
|
||||
|
||||
- **成功响应(200 OK)**:
|
||||
|
||||
```
|
||||
{
|
||||
"id": 1,
|
||||
"content": "帖子内容",
|
||||
"status": "Pending", // 帖子状态:Approved/Rejected/Pending
|
||||
"create_time": "2024-05-20 14:20:30",
|
||||
"update_time": "2024-05-20 14:20:30", // 最后更新时间(如审核时间、修改时间)
|
||||
"upvotes": 10,
|
||||
"downvotes": 2
|
||||
}
|
||||
```
|
||||
|
||||
- **错误响应**:
|
||||
|
||||
- - 401/403:管理员权限验证失败
|
||||
|
||||
- - 400 Bad Request:缺少帖子 ID
|
||||
|
||||
- - 404 Not Found:帖子不存在
|
||||
|
||||
## 五、附录
|
||||
|
||||
### 5.1 常见状态码说明
|
||||
|
||||
| 状态码 | 含义 | 适用场景 |
|
||||
| ------------------------- | -------------- | ------------------------------------------------------ |
|
||||
| 200 OK | 请求成功 | 点赞、获取数据、修改内容等操作成功 |
|
||||
| 201 Created | 资源创建成功 | 提交帖子、上传图片、提交举报等创建新资源的操作 |
|
||||
| 400 Bad Request | 请求参数错误 | 缺少必填字段、参数格式错误(如非布尔值、非数字 ID) |
|
||||
| 401 Unauthorized | 未授权 | 访问管理接口未携带管理员 Token |
|
||||
| 403 Forbidden | 权限拒绝 | 携带无效 Token、内容含违规关键词、访问不允许的文件格式 |
|
||||
| 404 Not Found | 资源不存在 | 帖子 ID / 评论 ID / 举报 ID / 图片文件名不存在 |
|
||||
| 418 I'm a teapot | 彩蛋状态码 | 访问/get/teapot接口 |
|
||||
| 500 Internal Server Error | 服务器内部错误 | 备份恢复失败、数据库异常等系统级错误 |
|
||||
21
LICENSE.txt
Normal file
21
LICENSE.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024-2025 libm
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
218
api_server.py
218
api_server.py
@@ -90,30 +90,29 @@ def set_config(key, value):
|
||||
|
||||
|
||||
# === 变量 ===
|
||||
BANNED_KEYWORDS = [
|
||||
"傻逼", "煞笔", "傻叉", "脑残", "狗东西",
|
||||
"操你妈", "你妈的", "滚", "神经病", "贱人", "杂种", "王八蛋",
|
||||
"臭婊子", "蠢货", "白痴", "妈的",
|
||||
"约吗", "开房", "一夜情", "裸聊", "床照",
|
||||
"小电影", "嫖娼", "成人网", "🈷吗",
|
||||
"毒品", "枪支", "赌博", "六合彩", "博彩", "赌球",
|
||||
"诈骗", "洗钱", "开票", "假证", "网监",
|
||||
"习近平", "毛泽东", "共产党", "台湾独立", "台独", "法轮功",
|
||||
"反动", "民主运动", "六四", "政变",
|
||||
"割腕", "跳楼"
|
||||
DEFAULT_BANNED_KEYWORDS = [
|
||||
"傻逼"
|
||||
]
|
||||
|
||||
ADMIN_TOKEN = "I_Love_SFLS_128936^"
|
||||
# === 延迟初始化配置 ===
|
||||
DEFAULT_ADMIN_TOKEN = "Sycamore_whisper"
|
||||
DEFAULT_UPLOAD_FOLDER = "img"
|
||||
DEFAULT_ALLOWED_EXTENSIONS = {"png", "jpg", "jpeg", "gif", "webp"}
|
||||
DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024 # 10 MB
|
||||
|
||||
UPLOAD_FOLDER = "img"
|
||||
ALLOWED_EXTENSIONS = {"png", "jpg", "jpeg", "gif", "webp"}
|
||||
MAX_FILE_SIZE = 10 * 1024 * 1024 # 10 MB
|
||||
CONFIG = {}
|
||||
INIT = False
|
||||
NEED_AUDIT = False
|
||||
|
||||
if not os.path.exists(UPLOAD_FOLDER):
|
||||
os.makedirs(UPLOAD_FOLDER)
|
||||
# 运行时使用的变量,初始为默认值
|
||||
ADMIN_TOKEN = DEFAULT_ADMIN_TOKEN
|
||||
UPLOAD_FOLDER = DEFAULT_UPLOAD_FOLDER
|
||||
ALLOWED_EXTENSIONS = set(DEFAULT_ALLOWED_EXTENSIONS)
|
||||
MAX_FILE_SIZE = DEFAULT_MAX_FILE_SIZE
|
||||
BANNED_KEYWORDS = list(DEFAULT_BANNED_KEYWORDS)
|
||||
|
||||
DB_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'instance', 'database.db')
|
||||
IMG_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'img')
|
||||
IMG_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), UPLOAD_FOLDER)
|
||||
BACKUP_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'backups')
|
||||
os.makedirs(BACKUP_FOLDER, exist_ok=True)
|
||||
|
||||
@@ -122,6 +121,140 @@ ALLOWED_BACKUP_EXTENSIONS = {'zip'}
|
||||
def allowed_backup_file(filename):
|
||||
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_BACKUP_EXTENSIONS
|
||||
|
||||
def apply_config_to_globals():
|
||||
global ADMIN_TOKEN, UPLOAD_FOLDER, ALLOWED_EXTENSIONS, MAX_FILE_SIZE, IMG_FOLDER, BANNED_KEYWORDS
|
||||
ADMIN_TOKEN = CONFIG.get('ADMIN_TOKEN', DEFAULT_ADMIN_TOKEN)
|
||||
UPLOAD_FOLDER = CONFIG.get('UPLOAD_FOLDER', DEFAULT_UPLOAD_FOLDER)
|
||||
ALLOWED_EXTENSIONS = set(CONFIG.get('ALLOWED_EXTENSIONS', DEFAULT_ALLOWED_EXTENSIONS))
|
||||
MAX_FILE_SIZE = int(CONFIG.get('MAX_FILE_SIZE', DEFAULT_MAX_FILE_SIZE))
|
||||
BANNED_KEYWORDS = list(CONFIG.get('BANNED_KEYWORDS', DEFAULT_BANNED_KEYWORDS))
|
||||
IMG_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), UPLOAD_FOLDER)
|
||||
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
|
||||
|
||||
def load_config():
|
||||
global CONFIG, INIT
|
||||
try:
|
||||
import importlib, sys
|
||||
importlib.invalidate_caches()
|
||||
if 'config' in sys.modules:
|
||||
cfg = importlib.reload(sys.modules['config'])
|
||||
else:
|
||||
cfg = importlib.import_module('config')
|
||||
CONFIG = {
|
||||
'ADMIN_TOKEN': getattr(cfg, 'ADMIN_TOKEN'),
|
||||
'UPLOAD_FOLDER': getattr(cfg, 'UPLOAD_FOLDER'),
|
||||
'ALLOWED_EXTENSIONS': set(getattr(cfg, 'ALLOWED_EXTENSIONS')),
|
||||
'MAX_FILE_SIZE': int(getattr(cfg, 'MAX_FILE_SIZE')),
|
||||
'BANNED_KEYWORDS': list(getattr(cfg, 'BANNED_KEYWORDS', DEFAULT_BANNED_KEYWORDS)),
|
||||
}
|
||||
INIT = True
|
||||
apply_config_to_globals()
|
||||
except Exception:
|
||||
INIT = False
|
||||
CONFIG = {}
|
||||
|
||||
# 启动时尝试加载配置
|
||||
load_config()
|
||||
|
||||
# 全部接口在初始化完成前返回 503(仅 /init 允许)
|
||||
@app.before_request
|
||||
def gate_uninitialized():
|
||||
if request.path == '/init':
|
||||
return None
|
||||
global INIT
|
||||
# 若未初始化,尝试动态加载配置(兼容多进程/热重载场景)
|
||||
if not INIT:
|
||||
try:
|
||||
load_config()
|
||||
except Exception:
|
||||
pass
|
||||
if not INIT:
|
||||
return jsonify({"status": "Fail", "reason": "Uninitialized"}), 503
|
||||
|
||||
def write_config_py(token, upload_folder, allowed_exts, max_file_size, banned_keywords=None):
|
||||
# 归一化扩展名为小写且唯一
|
||||
exts = sorted(set(str(e).strip().lower() for e in allowed_exts if str(e).strip()))
|
||||
# 归一化敏感词为去空格的字符串列表
|
||||
banned = banned_keywords if banned_keywords is not None else DEFAULT_BANNED_KEYWORDS
|
||||
banned = [str(w).strip() for w in banned if str(w).strip()]
|
||||
content = (
|
||||
"# Auto-generated by /init\n"
|
||||
f"ADMIN_TOKEN = {repr(token)}\n"
|
||||
f"UPLOAD_FOLDER = {repr(upload_folder)}\n"
|
||||
f"ALLOWED_EXTENSIONS = {repr(exts)}\n"
|
||||
f"MAX_FILE_SIZE = {int(max_file_size)}\n"
|
||||
f"BANNED_KEYWORDS = {repr(banned)}\n"
|
||||
)
|
||||
config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config.py')
|
||||
with open(config_path, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
@app.route('/init', methods=['POST'])
|
||||
def init_service():
|
||||
global INIT
|
||||
if INIT:
|
||||
return jsonify({"status": "Fail", "reason": "Already initialized"}), 403
|
||||
data = request.get_json() or {}
|
||||
required = ["ADMIN_TOKEN", "UPLOAD_FOLDER", "ALLOWED_EXTENSIONS", "MAX_FILE_SIZE"]
|
||||
missing = [k for k in required if k not in data]
|
||||
if missing:
|
||||
return jsonify({"status": "Fail", "reason": f"Missing fields: {', '.join(missing)}"}), 400
|
||||
|
||||
token = str(data["ADMIN_TOKEN"])
|
||||
upload_folder = str(data["UPLOAD_FOLDER"]).strip()
|
||||
# 接受 list 或 逗号字符串
|
||||
exts = data["ALLOWED_EXTENSIONS"]
|
||||
if isinstance(exts, str):
|
||||
allowed_exts = [x.strip() for x in exts.split(',')]
|
||||
elif isinstance(exts, list):
|
||||
allowed_exts = exts
|
||||
else:
|
||||
return jsonify({"status": "Fail", "reason": "ALLOWED_EXTENSIONS must be list or comma string"}), 400
|
||||
|
||||
try:
|
||||
max_file_size = int(data["MAX_FILE_SIZE"])
|
||||
except Exception:
|
||||
return jsonify({"status": "Fail", "reason": "MAX_FILE_SIZE must be int"}), 400
|
||||
|
||||
# 可选的 BANNED_KEYWORDS
|
||||
bk = data.get("BANNED_KEYWORDS", DEFAULT_BANNED_KEYWORDS)
|
||||
if isinstance(bk, str):
|
||||
banned_keywords = [x.strip() for x in bk.split(',') if x.strip()]
|
||||
elif isinstance(bk, list):
|
||||
banned_keywords = [str(x).strip() for x in bk if str(x).strip()]
|
||||
else:
|
||||
return jsonify({"status": "Fail", "reason": "BANNED_KEYWORDS must be list or comma string"}), 400
|
||||
|
||||
try:
|
||||
write_config_py(token, upload_folder, allowed_exts, max_file_size, banned_keywords)
|
||||
load_config()
|
||||
initialize_database()
|
||||
try:
|
||||
global NEED_AUDIT
|
||||
NEED_AUDIT = get_config("need_audit", "false").lower() == "true"
|
||||
except Exception:
|
||||
NEED_AUDIT = False
|
||||
return jsonify({"status": "OK"}), 200
|
||||
except Exception as e:
|
||||
return jsonify({"status": "Fail", "reason": str(e)}), 500
|
||||
|
||||
|
||||
# 在服务收到请求且已配置后,确保数据库表创建并加载审核状态
|
||||
@app.before_request
|
||||
def ensure_db_and_audit():
|
||||
global NEED_AUDIT
|
||||
if not getattr(ensure_db_and_audit, "_has_run", False) and INIT:
|
||||
try:
|
||||
initialize_database()
|
||||
try:
|
||||
NEED_AUDIT = get_config("need_audit", "false").lower() == "true"
|
||||
except Exception:
|
||||
NEED_AUDIT = False
|
||||
except Exception:
|
||||
pass
|
||||
finally:
|
||||
setattr(ensure_db_and_audit, "_has_run", True)
|
||||
|
||||
|
||||
# === 管理端文章状态修改工具函数 ===
|
||||
def admin_change_status(submission_id, from_status, to_status):
|
||||
@@ -291,7 +424,7 @@ def serve_image(filename):
|
||||
if not allowed_file(filename):
|
||||
return 'Request not allowed', 403 # 后缀不允许
|
||||
# 返回图片
|
||||
return send_from_directory('img', filename)
|
||||
return send_from_directory(UPLOAD_FOLDER, filename)
|
||||
|
||||
|
||||
@app.route('/report', methods=['POST'])
|
||||
@@ -473,10 +606,6 @@ def return_418():
|
||||
def return_200():
|
||||
return 'API OK!!!', 200
|
||||
|
||||
@app.route('/get/api_info', methods=['GET'])
|
||||
def get_api_info():
|
||||
return '<a>Sycamore_whisper API v1.0.0</a> Made with ❤️ By <a href="https://leonxie.cn">Leonxie</a>', 200
|
||||
|
||||
@app.route('/admin/need_audit', methods=['POST'])
|
||||
@require_admin
|
||||
def toggle_audit():
|
||||
@@ -499,6 +628,36 @@ def get_need_audit():
|
||||
global NEED_AUDIT
|
||||
return jsonify({"status": NEED_AUDIT}), 200
|
||||
|
||||
# 动态敏感词配置
|
||||
@app.route('/admin/get/banned_keywords', methods=['GET'])
|
||||
@require_admin
|
||||
def get_banned_keywords():
|
||||
return jsonify({"keywords": BANNED_KEYWORDS}), 200
|
||||
|
||||
@app.route('/admin/banned_keywords', methods=['POST'])
|
||||
@require_admin
|
||||
def set_banned_keywords():
|
||||
data = request.get_json() or {}
|
||||
keywords = data.get("BANNED_KEYWORDS", data.get("banned_keywords"))
|
||||
if keywords is None:
|
||||
return jsonify({"status": "Fail", "reason": "BANNED_KEYWORDS not found"}), 400
|
||||
if isinstance(keywords, str):
|
||||
new_keywords = [x.strip() for x in keywords.split(',') if x.strip()]
|
||||
elif isinstance(keywords, list):
|
||||
new_keywords = [str(x).strip() for x in keywords if str(x).strip()]
|
||||
else:
|
||||
return jsonify({"status": "Fail", "reason": "BANNED_KEYWORDS must be list or comma string"}), 400
|
||||
|
||||
global BANNED_KEYWORDS
|
||||
BANNED_KEYWORDS = new_keywords
|
||||
try:
|
||||
# 重写配置文件,确保重启后仍生效
|
||||
write_config_py(ADMIN_TOKEN, UPLOAD_FOLDER, list(ALLOWED_EXTENSIONS), MAX_FILE_SIZE, BANNED_KEYWORDS)
|
||||
load_config()
|
||||
return jsonify({"status": "OK"}), 200
|
||||
except Exception as e:
|
||||
return jsonify({"status": "Fail", "reason": str(e)}), 500
|
||||
|
||||
@app.route('/admin/approve', methods=['POST'])
|
||||
@require_admin
|
||||
def admin_approve():
|
||||
@@ -634,7 +793,7 @@ def admin_del_pic():
|
||||
return jsonify({"status": "Fail", "reason": "filename not found"}), 400
|
||||
|
||||
filename = data["filename"]
|
||||
file_path = os.path.join(os.getcwd(), "img", filename)
|
||||
file_path = os.path.join(os.getcwd(), UPLOAD_FOLDER, filename)
|
||||
|
||||
if not os.path.isfile(file_path):
|
||||
return jsonify({"status": "Fail", "reason": "file not found"}), 404
|
||||
@@ -832,12 +991,12 @@ def admin_get_pic_links():
|
||||
page = 1
|
||||
|
||||
per_page = 20
|
||||
if not os.path.exists('img'):
|
||||
if not os.path.exists(UPLOAD_FOLDER):
|
||||
return jsonify([]), 200
|
||||
|
||||
all_files = sorted(
|
||||
[f for f in os.listdir('img') if os.path.isfile(os.path.join('img', f))],
|
||||
key=lambda x: os.path.getmtime(os.path.join('img', x)),
|
||||
[f for f in os.listdir(UPLOAD_FOLDER) if os.path.isfile(os.path.join(UPLOAD_FOLDER, f))],
|
||||
key=lambda x: os.path.getmtime(os.path.join(UPLOAD_FOLDER, x)),
|
||||
reverse=True
|
||||
)
|
||||
|
||||
@@ -881,7 +1040,4 @@ def initialize_database():
|
||||
|
||||
# === 启动 ===
|
||||
if __name__ == '__main__':
|
||||
with app.app_context():
|
||||
initialize_database()
|
||||
NEED_AUDIT = get_config("need_audit", "false").lower() == "true"
|
||||
app.run(host='0.0.0.0', port=5000)
|
||||
app.run(host='127.0.0.1', port=5000) # 监听IP&端口,建议监听127.0.0.1并配置反向代理
|
||||
|
||||
Reference in New Issue
Block a user