Feature: foto de perfil para funcionarios y urlFoto en /auth/me
Qué se hizo
Los funcionarios ahora pueden tener foto de perfil, igual que los estudiantes, para cargarla desde "Mi perfil". Además, GET /auth/me devuelve la ruta de la foto propia, de estudiantes y de funcionarios, para que el frontend la muestre en la barra superior sin pedir el perfil aparte.
Por qué
La columna foto existía solo en la tabla estudiantes, así que un funcionario no tenía dónde guardar la suya. Y para mostrar la foto en la barra superior, el frontend tenía que hacer un pedido extra al perfil; ahora le alcanza con /auth/me, que ya pide al entrar.
Cambios
-
proyecto_schema.sql: columnafoto VARCHAR(255)enfuncionarios, con el constraintchk_funcionario_foto_extension(solo jpg/jpeg/png), igual queestudiantes.foto. -
PUT /funcionarios/{id}/foto(nuevo, multipart, campofoto): lo puede usar el propio funcionario o alguien conEDITAR_FUNCIONARIO. -
GET /funcionarios/{id}/foto(nuevo): el propio funcionario o alguien conVER_FUNCIONARIOS. -
Mismas reglas que la foto de estudiante:
- jpg/jpeg/png de hasta 5 MB;
- no se borra el archivo anterior (criterio de "nunca borrado físico");
- si falla el guardado en la base, se borra el archivo recién subido.
- Las fotos van a la misma carpeta
fotos/{id}que las de estudiantes. Los ids salen de la tablausuarios, compartida entre estudiantes y funcionarios, así que nunca chocan. -
urlFotonuevo enFuncionarioResponseDTOy enGET /auth/me(/estudiantes/{id}/fotoo/funcionarios/{id}/foto;nullsi no tiene foto).
Tests
-
FuncionarioServiceTest: subir foto (éxito, limpieza si falla el guardado, 404) y ver foto (éxito, sin foto cargada). -
AuthServiceTest:urlFotoen/auth/mepara funcionario y estudiante, con y sin foto. -
FuncionarioMapperTest(nuevo): armado deurlFoto. -
FuncionarioFotoSecurityTest(nuevo): reglas de@PreAuthorizecon@EnableMethodSecurityreal (el propio funcionario, otro sin permiso y otro con permiso). -
./mvnw test: pasan los 793 tests.
Cómo probar
- Aplicar la migración de abajo y levantar el backend.
- Como funcionario:
PUT /funcionarios/{miId}/fotocon un png → 200, y la respuesta traeurlFoto. -
GET /auth/me→ traeurlFoto;GET /funcionarios/{miId}/foto→ devuelve la imagen. - Como funcionario sin permisos: subir o ver la foto de otro funcionario → 403.
- Subir un archivo
.gifo de más de 5 MB → 400.
🗄️ Cambios en la base de datos: SÍ, obligatorios
Con ddl-auto=validate, el backend no arranca contra una base que no tenga la columna nueva. Cada uno tiene que correr esto una vez en su base local antes de levantar esta versión, y también hay que correrlo en el deploy:
ALTER TABLE proyecto.funcionarios ADD COLUMN IF NOT EXISTS foto VARCHAR(255);
ALTER TABLE proyecto.funcionarios ADD CONSTRAINT chk_funcionario_foto_extension
CHECK (foto IS NULL OR foto ~* '\.(jpg|jpeg|png)$');
Con el contenedor de docker compose: guardar el SQL en un archivo y correr
docker exec -i sienep-db psql -U sienep -d sienep < migracion-foto-funcionario.sql
o pegarlo en pgAdmin. Quien cree la base desde cero con proyecto_schema.sql no tiene que hacer nada, porque ya está incluido.
dev, la base queda idéntica a una creada desde cero con el esquema nuevo, y el backend arranca.
Compatibilidad
No choca con los otros MRs abiertos. Es independiente del MR de solicitudes de instancia: si se mergean los dos, hay que correr las dos migraciones, en cualquier orden.