(runtime *common.RuntimeContext)
| 184 | } |
| 185 | |
| 186 | func executeFormSubmit(runtime *common.RuntimeContext) error { |
| 187 | fields, attachmentMap, err := parseFormSubmitJSON(runtime) |
| 188 | if err != nil { |
| 189 | return err |
| 190 | } |
| 191 | |
| 192 | // 上传附件并合并到字段中 |
| 193 | if len(attachmentMap) > 0 { |
| 194 | baseToken := runtime.Str("base-token") |
| 195 | fio := runtime.FileIO() |
| 196 | if fio == nil { |
| 197 | return baseMissingFileIOError("file operations require a FileIO provider (needed for attachments in --json)") |
| 198 | } |
| 199 | |
| 200 | // Step 1: 收集所有唯一路径(跨字段去重) |
| 201 | allPaths := collectUniquePaths(attachmentMap) |
| 202 | if len(allPaths) == 0 { |
| 203 | return baseFlagErrorf("attachments in --json contains no valid file paths") |
| 204 | } |
| 205 | |
| 206 | // Step 2: 前置校验所有文件路径安全性与可访问性,同时收集文件大小供上传使用 |
| 207 | sizeMap := make(map[string]int64, len(allPaths)) |
| 208 | for _, filePath := range allPaths { |
| 209 | if _, err := validate.SafeInputPath(filePath); err != nil { |
| 210 | return baseValidationErrorf("unsafe attachment file path: %s: %v", filePath, err) |
| 211 | } |
| 212 | fileInfo, err := fio.Stat(filePath) |
| 213 | if err != nil { |
| 214 | if errors.Is(err, fileio.ErrPathValidation) { |
| 215 | return baseValidationErrorf("unsafe attachment file path: %s: %v", filePath, err) |
| 216 | } |
| 217 | return baseValidationErrorf("attachment file not accessible: %s: %v", filePath, err) |
| 218 | } |
| 219 | if fileInfo.Size() > baseAttachmentUploadMaxFileSize { |
| 220 | return baseValidationErrorf("attachment file %s exceeds 2GB limit", filePath) |
| 221 | } |
| 222 | if !fileInfo.Mode().IsRegular() { |
| 223 | return baseValidationErrorf("attachment file %s is not a regular file", filePath) |
| 224 | } |
| 225 | sizeMap[filePath] = fileInfo.Size() |
| 226 | } |
| 227 | |
| 228 | // Step 3: 并行上传,构建路径 → 附件结果映射 |
| 229 | fmt.Fprintf(runtime.IO().ErrOut, "Uploading %d unique attachment(s)...\n", len(allPaths)) |
| 230 | resultMap, err := uploadAttachmentsParallel(runtime, allPaths, baseFormAttachmentUploadTarget(baseToken, runtime.Str("share-token")), sizeMap) |
| 231 | if err != nil { |
| 232 | return err |
| 233 | } |
| 234 | |
| 235 | // Step 4: 根据共享结果映射,按字段组装单元格 |
| 236 | for fieldName, filePaths := range attachmentMap { |
| 237 | cell := make([]interface{}, 0, len(filePaths)) |
| 238 | for _, p := range filePaths { |
| 239 | if att, ok := resultMap[p]; ok { |
| 240 | cell = append(cell, att) |
| 241 | } |
| 242 | } |
| 243 | fields[fieldName] = cell |
no test coverage detected