up
This commit is contained in:
@@ -405,6 +405,96 @@ func UpdateEntregableVisibilidad(c *fiber.Ctx) error {
|
||||
return c.JSON(fiber.Map{"ok": true})
|
||||
}
|
||||
|
||||
// ─── Documentos (contratos / órdenes de servicio) ─────────────────────────────
|
||||
|
||||
func GetDocumentos(c *fiber.Ctx) error {
|
||||
id, _ := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
items, err := models.GetDocumentosByProyecto(uint(id))
|
||||
if err != nil {
|
||||
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(items)
|
||||
}
|
||||
|
||||
func UploadDocumento(c *fiber.Ctx) error {
|
||||
proyID, _ := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if _, err := c.MultipartForm(); err != nil {
|
||||
return c.Status(400).JSON(fiber.Map{"error": "Formato multipart requerido"})
|
||||
}
|
||||
nombre := strings.TrimSpace(c.FormValue("nombre"))
|
||||
descripcion := c.FormValue("descripcion")
|
||||
tipo := c.FormValue("tipo", "contrato")
|
||||
|
||||
validTipos := map[string]bool{"contrato": true, "orden_servicio": true, "otro": true}
|
||||
if !validTipos[tipo] {
|
||||
tipo = "otro"
|
||||
}
|
||||
|
||||
file, err := c.FormFile("archivo")
|
||||
if err != nil {
|
||||
return c.Status(400).JSON(fiber.Map{"error": "Archivo requerido"})
|
||||
}
|
||||
if file.Size > 50*1024*1024 {
|
||||
return c.Status(400).JSON(fiber.Map{"error": "Archivo máximo 50MB"})
|
||||
}
|
||||
if nombre == "" {
|
||||
nombre = file.Filename
|
||||
}
|
||||
|
||||
dir := fmt.Sprintf("uploads/proyectos/%d/docs", proyID)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return c.Status(500).JSON(fiber.Map{"error": "Error al crear directorio"})
|
||||
}
|
||||
|
||||
safeFile := safeFilenameProyecto(file.Filename)
|
||||
savePath := filepath.Join(dir, safeFile)
|
||||
if err := c.SaveFile(file, savePath); err != nil {
|
||||
return c.Status(500).JSON(fiber.Map{"error": "Error al guardar archivo"})
|
||||
}
|
||||
|
||||
d := &models.ProyectoDocumento{
|
||||
ProyectoID: uint(proyID),
|
||||
Tipo: tipo,
|
||||
Nombre: nombre,
|
||||
Descripcion: descripcion,
|
||||
Archivo: savePath,
|
||||
OriginalName: file.Filename,
|
||||
TipoMime: mimeFromHeader(file),
|
||||
Tamanio: file.Size,
|
||||
}
|
||||
if err := models.CreateProyectoDocumento(d); err != nil {
|
||||
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.Status(201).JSON(d)
|
||||
}
|
||||
|
||||
func DeleteDocumento(c *fiber.Ctx) error {
|
||||
docID, _ := strconv.ParseUint(c.Params("docID"), 10, 32)
|
||||
item, err := models.GetProyectoDocumentoByID(uint(docID))
|
||||
if err != nil {
|
||||
return c.Status(404).JSON(fiber.Map{"error": "No encontrado"})
|
||||
}
|
||||
_ = os.Remove(item.Archivo)
|
||||
if err := models.DeleteProyectoDocumento(uint(docID)); err != nil {
|
||||
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{"ok": true})
|
||||
}
|
||||
|
||||
func DownloadDocumento(c *fiber.Ctx) error {
|
||||
docID, _ := strconv.ParseUint(c.Params("docID"), 10, 32)
|
||||
item, err := models.GetProyectoDocumentoByID(uint(docID))
|
||||
if err != nil {
|
||||
return c.Status(404).JSON(fiber.Map{"error": "No encontrado"})
|
||||
}
|
||||
clean := filepath.Clean(item.Archivo)
|
||||
if !strings.HasPrefix(clean, "uploads/") {
|
||||
return c.Status(403).JSON(fiber.Map{"error": "Acceso denegado"})
|
||||
}
|
||||
c.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, item.OriginalName))
|
||||
return c.SendFile(clean)
|
||||
}
|
||||
|
||||
// ─── Tickets (admin) ──────────────────────────────────────────────────────────
|
||||
|
||||
func GetTickets(c *fiber.Ctx) error {
|
||||
|
||||
Reference in New Issue
Block a user