Manage technologies through the API, with SVG logos
/api/v1/technologies is a full CRUD with the panel's own rules: name and slug are plain strings, the prose is translatable, `radar_ring: null` takes one off the radar, and TechnologyPolicy still refuses to delete one a project, member or call uses. The MCP server picks the tools up from openapi.yaml on its own. A logo is an SVG, so POST /v1/media now accepts one — sanitized with enshrined/svg-sanitize (scripts, event handlers and remote references removed), and served by Caddy under a Content-Security-Policy that would stop a script regardless. `for` (pages or technologies) says what an upload is for, which picks the directory the panel uses for it and the permission it takes. Creating a technology without a category answered 500: the column's default never reached the model, so the response read a null enum. The controller now states the default, as the panel does. Beside a file, the MCP upload tool no longer demands the JSON body's `url`: the body then carries the upload's other fields, such as `for`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
27
README.md
27
README.md
@@ -401,17 +401,24 @@ tabla es derivada, así que reconstruirla siempre es seguro.
|
||||
### Subir por la API
|
||||
|
||||
`POST /api/v1/media` es el campo de subida de una ficha, sin la ficha: guarda la
|
||||
imagen donde el panel pone las de las páginas y contesta con el `path` que se
|
||||
manda como `featured_image`. Existe para el [MCP](#servidor-mcp), que sin él
|
||||
imagen donde el panel pone las de ese tipo de ficha y contesta con el `path` que
|
||||
se manda como `featured_image` de una página o `logo` de una tecnología. `for`
|
||||
dice para qué es (`pages`, por defecto, o `technologies`), y con ello la carpeta
|
||||
y el permiso que hace falta. Existe para el [MCP](#servidor-mcp), que sin él
|
||||
podía crear una página pero nunca ponerle una foto. Pasa por `Media::for()`,
|
||||
así que se procesa, se sirve y se poda igual que una subida desde el panel.
|
||||
|
||||
Dos formas de entrada, una por petición: **multipart** con `file`, o **JSON**
|
||||
con una `url` que la API descarga ella misma. Solo JPEG, PNG, WebP, GIF y AVIF,
|
||||
decidido por los bytes y no por el nombre ni el tipo declarado. **Sin SVG**: el
|
||||
panel lo acepta de quien lo administra, pero esto también descarga de URLs
|
||||
arbitrarias, y un SVG es un documento que puede llevar script servido desde
|
||||
este dominio. 20 MB como mucho (`MEDIA_UPLOAD_MAX_KB`).
|
||||
con una `url` que la API descarga ella misma. JPEG, PNG, WebP, GIF, AVIF y SVG,
|
||||
decidido por los bytes y no por el nombre ni el tipo declarado. 20 MB como mucho
|
||||
(`MEDIA_UPLOAD_MAX_KB`).
|
||||
|
||||
**El SVG entra, pero nunca tal cual**: es lo que es un logo, y también un
|
||||
documento que puede llevar script servido desde este dominio. Pasa antes por
|
||||
[`enshrined/svg-sanitize`](https://github.com/darylldoyle/svg-sanitizer), que
|
||||
quita scripts, manejadores de eventos y referencias a cualquier cosa fuera del
|
||||
fichero; y Caddy sirve los `/storage/*.svg` con una `Content-Security-Policy`
|
||||
que pararía un script igualmente si se colara.
|
||||
|
||||
**La URL es la parte delicada**, porque la petición la hace este servidor desde
|
||||
dentro de la red del stack: sin control, sería una forma de pedirle
|
||||
@@ -424,8 +431,8 @@ cambie entre la comprobación y la petición no cuele otra, **no sigue
|
||||
redirecciones** y deja de leer al pasar del límite, diga lo que diga
|
||||
`Content-Length`.
|
||||
|
||||
El permiso es escribir páginas (`pages.create` o `pages.update`), no ninguno de
|
||||
`media.*`: esos siempre describieron cuidar ficheros que ya existen, y
|
||||
El permiso es escribir el tipo de ficha de `for` (`pages.create` o
|
||||
`pages.update`, `technologies.create` o…), no ninguno de `media.*`: esos siempre describieron cuidar ficheros que ya existen, y
|
||||
`MediaPolicy::create` sigue siendo `false` para que el panel no gane un botón de
|
||||
«nuevo fichero» suelto.
|
||||
|
||||
@@ -1256,6 +1263,8 @@ POST /api/v1/pages/{page}/restore
|
||||
GET /api/v1/users PATCH para roles, is_active, locale
|
||||
GET /api/v1/roles solo lectura
|
||||
GET /api/v1/roles/catalogue catálogo de permisos agrupado
|
||||
/api/v1/technologies CRUD completo; filtros: category,
|
||||
radar_ring (none = fuera del radar), search
|
||||
POST /api/v1/media subir una imagen (fichero o URL)
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user