fix(annotations): address code review findings (1-8, 10)

1. toggleVote wrapped in transaction (race condition fix)
2. FeedbackPanel fetch calls now surface errors via onError/toast
3. Extracted resolveBoard/hasCollectionRole to shared board-access.js
4. AnnotationStore uses monotonic version counter for snapshots
5. PinOverlay uses object pool instead of destroy/recreate on refresh
6. canvasObjects prop memoized with useMemo
7. PinOverlay store subscription cleaned up on unmount
8. Comment content capped at 5000 chars (backend validation)
10. anchor_type validated to 'object' or 'point'
This commit is contained in:
Hiren Kangad
2026-03-10 21:16:08 +05:30
parent 303124f518
commit f7a39a1726
9 changed files with 176 additions and 133 deletions
+27
View File
@@ -0,0 +1,27 @@
const { getBoard, getCollection, getCollectionMember } = require('../db');
function hasCollectionRole(member, minRole) {
if (!member) return false;
const hierarchy = { owner: 3, editor: 2, viewer: 1 };
return (hierarchy[member.role] || 0) >= (hierarchy[minRole] || 0);
}
function resolveBoard(req, res, minRole = 'viewer') {
const board = getBoard(req.params.boardId);
if (!board) { res.status(404).json({ error: 'Board not found' }); return null; }
const collection = getCollection(board.collection_id);
if (!collection) { res.status(404).json({ error: 'Collection not found' }); return null; }
const member = getCollectionMember(board.collection_id, req.user.id);
if (minRole === 'viewer' && collection.is_public) {
return { board, collection, member: member || { role: 'viewer' } };
}
if (!hasCollectionRole(member, minRole)) {
res.status(403).json({ error: `${minRole} access required` });
return null;
}
return { board, collection, member };
}
module.exports = { hasCollectionRole, resolveBoard };