07. 资源上传与站点配置¶
1. 通用上传(JWT)¶
POST /api/upload/file¶
multipart/form-data 字段:
file:文件file_type:avatar/other/ 自定义
返回示例:
{
"code": 200,
"message": "上传成功",
"data": {
"file_name": "avatar.jpg",
"file_size": 53211,
"file_type": "avatar",
"minio_path": "uploads/avatar/2026/04/xxx.jpg",
"file_url": "https://...",
"thumbnail_url": "https://..."
}
}
2. 操作证上传与查询(JWT)¶
POST /api/upload/operator-certificate¶
multipart/form-data 字段:
callsign(可选)file(可选,multipart 兼容路径)- 或直传完成后:
object_key+upload_token+file_name
推荐流程:POST /api/storage/presign-put(file_type=operator_cert)→ PUT 直传 → 本接口提交 object_key 和 upload_token。
说明:
callsign仅表示“申请中的新呼号”,不会在用户提交时直接写入users.callsign。- 只有管理员审批通过后,新呼号才会真正生效。
- 如果提交的
callsign已被其他用户占用,接口返回409。 - 操作证上限 20MB;支持图片与 PDF。
返回示例:
{
"code": 200,
"message": "操作证信息已提交,请等待管理员审核",
"data": {
"id": 99,
"callsign": "BG7NEW",
"file_name": "cert.pdf",
"file_size": 124312,
"upload_time": "2026-04-05 16:11:00"
}
}
GET /api/operator-certificate¶
返回 active_cert(已通过)和 pending_cert(待审/拒绝最近一条)。
两类证书对象都会返回 callsign 字段,表示该证书对应的呼号。
3. 站点 Logo/Favicon(Admin)¶
POST /api/upload/logo¶
multipart/form-data:file
POST /api/upload/favicon¶
multipart/form-data:file
配置中保存的是 object key;读取公开配置时由后端解析为可访问 URL。
3.1 通用存储与直传(JWT)¶
POST /api/storage/presign-put¶
申请直传凭证。body:
{
"file_type": "assets",
"file_name": "package.zip",
"size": 1048576,
"content_type": "application/zip"
}
file_type 支持 assets | client_resource | firmware | operator_cert。其中 assets、client_resource、firmware 仅管理员可申请,operator_cert 绑定当前用户。object key 仅由服务端生成。
返回示例(MinIO):
{
"code": 200,
"data": {
"mode": "s3",
"upload_url": "https://minio.example/...",
"method": "PUT",
"headers": { "Content-Type": "application/zip" },
"object_key": "staging/assets/1/2026/07/xxx.zip",
"upload_token": "signed-upload-grant",
"expires_at": "2026-07-14T12:00:00Z",
"max_size": 104857600,
"content_type": "application/zip"
}
}
local 驱动下 mode 为 local,upload_url 指向 PUT /api/storage/put?token=...&key=...(token 鉴权,无需 JWT)。
上传内容先进入 staging;complete 会校验申请人、类型、实际大小和有效期,再提升为新的不可变 final key。未完成且超过 24 小时的 staging 对象会自动清理。
PUT /api/storage/put¶
local 驱动专用直传入口;校验 query 中的 token 与 key 后写入存储。
4. 资源中心(Admin)¶
管理端¶
GET /api/assets(管理员列表,参数parent_id)POST /api/assets/folderPOST /api/assets/upload(multipart/form-data:parent_id+file+name+remark,兼容代理上传)POST /api/assets/complete(直传完成后落库)PUT /api/assets/:idPUT /api/assets/:id/movePOST /api/assets/:id/replaceDELETE /api/assets/:id
直传完整流程:presign-put → 浏览器 PUT 到 upload_url → POST /api/assets/complete:
{
"parent_id": 12,
"name": "客户端安装包",
"remark": "",
"object_key": "staging/assets/1/2026/07/xxx.zip",
"upload_token": "signed-upload-grant"
}
示例:创建文件夹
{ "name": "客户端安装包", "parent_id": null, "remark": "发布目录" }
示例:移动资源
{ "target_parent_id": 12 }
前台公开下载¶
GET /api/assets/treeGET /api/assets/folder/:idGET /api/assets/:id/download
下载链接返回示例:
{
"code": 200,
"message": "获取成功",
"data": {
"name": "draarl-client.exe",
"size": 51200321,
"mime_type": "application/octet-stream",
"download_url": "https://...presigned..."
}
}
4.1 固件上传(Admin)¶
POST /api/firmware:multipart/form-data(兼容代理上传)POST /api/firmware/complete:直传完成后落库,服务端重算 SHA-256
complete body 示例:
{
"dev_model": 1,
"version": "1.2.3",
"changelog": "修复连接",
"object_key": "staging/firmware/1/2026/07/xxx.bin",
"upload_token": "signed-upload-grant",
"file_name": "firmware.bin"
}
固件仍使用独立表和 OTA API。新上传对象提升为
firmware/<dev-model>/<version>/<sha256>/<file-name>;旧记录和旧对象路径保持可读。
4.2 客户端资源上传(Admin)¶
通用客户端资源使用 file_type=client_resource 申请直传。complete 路径为
POST /api/client-resources/:resource_id/releases/:release_id/artifacts/complete,
请求必须携带至少一个明确的 platform/arch target。完整生命周期、manifest
和按需下载接口见 客户端资源分发。
5. 站点配置接口¶
公开读取¶
GET /api/config/public
返回示例:
{
"code": 200,
"message": "获取成功",
"data": {
"icp": { "icp": "粤ICP备xxxx号" },
"systemInfo": { "name": "DraARL", "logo_url": "https://...", "favicon_url": "https://..." },
"sso_enabled": true,
"sso_name": "Keycloak"
}
}
已登录读取¶
GET /api/config/category/:category
管理员配置(Admin)¶
PUT /api/configPUT /api/config/icpPUT /api/config/systemPUT /api/config/aprsGET /api/config/allGET /api/config/systemGET /api/config/aprsGET /api/config/aprs/logsDELETE /api/config/logoDELETE /api/config/faviconGET /api/config/smtpPUT /api/config/smtp
SMTP 更新请求示例:
{
"host": "smtp.qq.com",
"port": 465,
"use_ssl": true,
"insecure_skip_verify": false,
"sender_name": "DraARL",
"sender_email": "noreply@example.com",
"password": "授权码"
}