926215297e
Rediseno completo del modulo Notas (era lista inline, sin popup, sin compartir):
- Tarjetas con resumen del contenido en vez de lista vertical; la primera tarjeta siempre es
un "+" para crear.
- Crear y editar se hacen en un DetailPopup (antes: textarea fijo arriba + edicion inline por
tarjeta).
- Nueva tabla note_shares (migracion 019): compartir una nota con otro usuario ya registrado,
siempre de solo lectura -- el dueño sigue siendo el unico que edita/borra/comparte (mismo
patron que project_members pero sin rol ni invitacion por correo, ya que acá no hace falta).
Quien recibe la nota la ve con "Compartida por {nombre}", sin ningun control de edicion.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
56 lines
2.3 KiB
JavaScript
56 lines
2.3 KiB
JavaScript
import * as repo from './repository.js';
|
|
import * as usersRepo from '../users/repository.js';
|
|
import { HttpError } from '../../utils/http.js';
|
|
import { logAudit } from '../../utils/audit.js';
|
|
|
|
// Siempre privadas para editar/borrar/compartir: cada quien solo toca sus propias notas, sin
|
|
// importar el rol. Una nota de otro usuario responde 404 (no 403) para no revelar que existe.
|
|
async function getOwnNoteOr404(id, currentUser) {
|
|
const note = await repo.findById(id);
|
|
if (!note || note.user_id !== currentUser.id) throw new HttpError(404, 'Nota no encontrada');
|
|
return note;
|
|
}
|
|
|
|
export const listNotes = (currentUser) => repo.findVisibleToUser(currentUser.id);
|
|
|
|
export async function createNote(content, currentUser) {
|
|
const trimmed = (content || '').trim();
|
|
if (!trimmed) throw new HttpError(400, 'El contenido es obligatorio');
|
|
return repo.create(currentUser.id, trimmed);
|
|
}
|
|
|
|
export async function updateNote(id, content, currentUser) {
|
|
await getOwnNoteOr404(id, currentUser);
|
|
const trimmed = (content || '').trim();
|
|
if (!trimmed) throw new HttpError(400, 'El contenido es obligatorio');
|
|
return repo.update(id, trimmed);
|
|
}
|
|
|
|
export async function removeNote(id, currentUser) {
|
|
await getOwnNoteOr404(id, currentUser);
|
|
await repo.remove(id);
|
|
}
|
|
|
|
export async function listNoteShares(id, currentUser) {
|
|
await getOwnNoteOr404(id, currentUser);
|
|
return repo.listShares(id);
|
|
}
|
|
|
|
export async function shareNote(id, targetUserId, currentUser) {
|
|
await getOwnNoteOr404(id, currentUser);
|
|
if (!targetUserId) throw new HttpError(400, 'Indica un usuario');
|
|
if (targetUserId === currentUser.id) throw new HttpError(400, 'No puedes compartir una nota contigo mismo');
|
|
const targetUser = await usersRepo.findById(targetUserId);
|
|
if (!targetUser) throw new HttpError(404, 'Usuario no encontrado');
|
|
const shares = await repo.addShare(id, targetUserId);
|
|
await logAudit({ userId: currentUser.id, action: 'share', entityType: 'note', entityId: id, detail: { userId: targetUserId } });
|
|
return shares;
|
|
}
|
|
|
|
export async function unshareNote(id, targetUserId, currentUser) {
|
|
await getOwnNoteOr404(id, currentUser);
|
|
const shares = await repo.removeShare(id, targetUserId);
|
|
await logAudit({ userId: currentUser.id, action: 'unshare', entityType: 'note', entityId: id, detail: { userId: targetUserId } });
|
|
return shares;
|
|
}
|