feat: file_save_disk, file_delete, file_serve, upload_parse, upload_handler, thumbnail_generate (issue 0014 fase 3)
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
---
|
||||
name: file_save_disk
|
||||
kind: function
|
||||
lang: go
|
||||
domain: infra
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "func FileSaveDisk(baseDir string, filename string, data io.Reader) (UploadedFile, error)"
|
||||
description: "Escribe el contenido de un io.Reader a disco en baseDir con un nombre unico (UUID + extension). Crea el directorio si no existe. Retorna UploadedFile con metadata."
|
||||
tags: [file, save, disk, storage, upload, infra]
|
||||
uses_functions: [file_unique_name_go_infra]
|
||||
uses_types: [UploadedFile_go_infra]
|
||||
returns: [UploadedFile_go_infra]
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: [fmt, io, mime, os, path/filepath, strings, time]
|
||||
params:
|
||||
- name: baseDir
|
||||
desc: "directorio destino (se crea si no existe, permisos 0755)"
|
||||
- name: filename
|
||||
desc: "nombre original del archivo (solo se usa para extraer la extension)"
|
||||
- name: data
|
||||
desc: "reader con el contenido binario a escribir"
|
||||
output: "UploadedFile con StoredName (UUID-based), Path completo, Size en bytes, ContentType inferido por extension y CreatedAt (UTC). Error si falla mkdir, create o copy"
|
||||
tested: true
|
||||
tests: ["guarda contenido en baseDir con nombre UUID", "crea baseDir si no existe", "tamano coincide con bytes escritos", "infiere ContentType desde la extension"]
|
||||
test_file_path: "functions/infra/file_save_disk_test.go"
|
||||
file_path: "functions/infra/file_save_disk.go"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```go
|
||||
f, _ := os.Open("./input.png")
|
||||
defer f.Close()
|
||||
uploaded, err := FileSaveDisk("./uploads", "input.png", f)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(uploaded.Path) // ./uploads/{uuid}.png
|
||||
```
|
||||
|
||||
## Notas
|
||||
|
||||
- El nombre original NUNCA se usa como nombre en disco (riesgo path traversal). Solo se preserva como metadata en el campo `Filename` para trazabilidad.
|
||||
- ContentType se infiere de la extension via `mime.TypeByExtension`. Para validacion estricta del tipo real, llamar `FileValidateType` ANTES de guardar y/o sobreescribir el campo.
|
||||
- Si falla el `io.Copy`, el archivo parcial se borra automaticamente.
|
||||
Reference in New Issue
Block a user