feat(ops): add object storage management and site-mapping CSV import/export
Ship the Ops backstage 对象存储 page (browse / upload / move / delete / folder ops) backed by a new object-storage service + handler, with the shared storage client extended with List/Stat/Copy/Usage/DownloadURL so both MinIO and Aliyun providers cover the new surface. Add ForcePathStyle to the object-storage config and treat r2/s3/custom_s3 as external providers so Cloudflare R2 and other S3-compatibles can share the MinIO client path without spinning up the bundled MinIO. Also add CSV import/export + template download to the site-domain mappings page, raise gin MaxMultipartMemory to 8 MiB for the new multipart endpoints, register Ops swagger routes, and extend the descriptions-parity test to cover the ops router. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -303,6 +303,17 @@ func queryParameterNames(route gin.RouteInfo) []string {
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.Contains(path, "/ops/site-domain-mappings"):
|
||||
add("page", "size", "keyword", "is_active")
|
||||
case strings.Contains(path, "/ops/object-storage/objects/detail") ||
|
||||
strings.Contains(path, "/ops/object-storage/objects/url") ||
|
||||
strings.Contains(path, "/ops/object-storage/objects/download-url") ||
|
||||
strings.Contains(path, "/ops/object-storage/objects/download"):
|
||||
add("key")
|
||||
case strings.Contains(path, "/ops/object-storage/objects"):
|
||||
add("prefix", "keyword", "continuation_token", "start_after", "recursive", "size", "key")
|
||||
case strings.Contains(path, "/ops/object-storage/folders"):
|
||||
add("prefix")
|
||||
case strings.Contains(path, "/workspace/ai-point-usage"):
|
||||
add("page", "page_size")
|
||||
case strings.Contains(path, "/tenant/articles"):
|
||||
@@ -357,13 +368,13 @@ func queryParameter(name string) map[string]any {
|
||||
|
||||
func schemaForQueryParameter(name string) map[string]any {
|
||||
switch name {
|
||||
case "page", "page_size", "limit", "offset", "days", "period_days":
|
||||
case "page", "page_size", "limit", "offset", "days", "period_days", "size":
|
||||
return map[string]any{"type": "integer"}
|
||||
case "brand_id", "keyword_id", "question_id", "template_id", "kol_prompt_id", "prompt_rule_id", "group_id", "folder_id", "if_sync_version":
|
||||
return map[string]any{"type": "integer", "format": "int64"}
|
||||
case "force":
|
||||
return map[string]any{"type": "string", "enum": []string{"1"}}
|
||||
case "ungrouped", "undo":
|
||||
case "ungrouped", "undo", "recursive", "is_active":
|
||||
return map[string]any{"type": "string", "enum": []string{"true", "false"}}
|
||||
case "created_from", "created_to", "date_from", "date_to", "business_date":
|
||||
return map[string]any{"type": "string", "format": "date"}
|
||||
@@ -403,6 +414,9 @@ func isMultipartRoute(route gin.RouteInfo) bool {
|
||||
}
|
||||
path := route.Path
|
||||
return path == "/api/tenant/images" ||
|
||||
path == "/api/ops/site-domain-mappings/import" ||
|
||||
path == "/api/ops/object-storage/objects/upload" ||
|
||||
path == "/api/ops/desktop-client/releases/upload" ||
|
||||
path == "/api/tenant/knowledge/items/file" ||
|
||||
path == "/api/tenant/kol/manage/profile/avatar" ||
|
||||
path == "/api/tenant/articles/:id/images"
|
||||
|
||||
Reference in New Issue
Block a user