v0.12.49 Login Type and Event bug fixes

This commit is contained in:
2026-04-01 09:25:17 -04:00
parent a3a878854e
commit 7031979571
9 changed files with 151 additions and 19 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "rosterchirp-backend",
"version": "0.12.48",
"version": "0.12.49",
"description": "RosterChirp backend server",
"main": "src/index.js",
"scripts": {

View File

@@ -65,7 +65,15 @@ async function canViewEvent(schema, event, userId, isToolManager) {
JOIN user_group_members ugm ON ugm.user_group_id=eug.user_group_id
WHERE eug.event_id=$1 AND ugm.user_id=$2
`, [event.id, userId]);
return !!assigned;
if (assigned) return true;
// Also allow if user has an alias in one of the event's user groups (Guardian Only mode)
const aliasAssigned = await queryOne(schema, `
SELECT 1 FROM event_user_groups eug
JOIN alias_group_members agm ON agm.user_group_id=eug.user_group_id
JOIN guardian_aliases ga ON ga.id=agm.alias_id
WHERE eug.event_id=$1 AND ga.guardian_id=$2
`, [event.id, userId]);
return !!aliasAssigned;
}
async function enrichEvent(schema, event) {
@@ -235,11 +243,21 @@ router.get('/:id', authMiddleware, async (req, res) => {
const itm = await isToolManagerFn(req.schema, req.user);
if (!(await canViewEvent(req.schema, event, req.user.id, itm))) return res.status(403).json({ error: 'Access denied' });
await enrichEvent(req.schema, event);
const isMember = !itm && !!(await queryOne(req.schema, `
SELECT 1 FROM event_user_groups eug
JOIN user_group_members ugm ON ugm.user_group_id=eug.user_group_id
WHERE eug.event_id=$1 AND ugm.user_id=$2
`, [event.id, req.user.id]));
const isMember = !itm && !!(
(await queryOne(req.schema, `
SELECT 1 FROM event_user_groups eug
JOIN user_group_members ugm ON ugm.user_group_id=eug.user_group_id
WHERE eug.event_id=$1 AND ugm.user_id=$2
`, [event.id, req.user.id]))
||
// Guardian Only: user has an alias in one of the event's user groups
(await queryOne(req.schema, `
SELECT 1 FROM event_user_groups eug
JOIN alias_group_members agm ON agm.user_group_id=eug.user_group_id
JOIN guardian_aliases ga ON ga.id=agm.alias_id
WHERE eug.event_id=$1 AND ga.guardian_id=$2
`, [event.id, req.user.id]))
);
if (event.track_availability && (itm || isMember)) {
// User responses
const userAvail = await query(req.schema, `
@@ -253,6 +271,18 @@ router.get('/:id', authMiddleware, async (req, res) => {
`, [req.params.id]);
event.availability = [...userAvail, ...aliasAvail];
// For non-tool-managers: mask notes on entries that don't belong to them or their aliases
if (!itm) {
const myAliasIds = new Set(
(await query(req.schema, 'SELECT id FROM guardian_aliases WHERE guardian_id=$1', [req.user.id])).map(r => r.id)
);
event.availability = event.availability.map(r => {
const isOwn = !r.is_alias && r.user_id === req.user.id;
const isOwnAlias = r.is_alias && myAliasIds.has(r.alias_id);
return (isOwn || isOwnAlias) ? r : { ...r, note: null };
});
}
if (itm) {
const assignedRows = await query(req.schema, `
SELECT DISTINCT u.id AS user_id, u.name, u.first_name, u.last_name, u.display_name

View File

@@ -259,7 +259,7 @@ router.post('/', authMiddleware, teamManagerMiddleware, async (req, res) => {
// PATCH /:id
router.patch('/:id', authMiddleware, teamManagerMiddleware, async (req, res) => {
const { name, memberIds, createDm = false } = req.body;
const { name, memberIds, createDm = false, aliasMemberIds } = req.body;
try {
let ug = await queryOne(req.schema, 'SELECT * FROM user_groups WHERE id=$1', [req.params.id]);
if (!ug) return res.status(404).json({ error: 'Not found' });
@@ -365,6 +365,24 @@ router.patch('/:id', authMiddleware, teamManagerMiddleware, async (req, res) =>
}
}
// Alias member management (Guardian Only mode — players group)
if (Array.isArray(aliasMemberIds)) {
const newAliasIds = new Set(aliasMemberIds.map(Number).filter(Boolean));
const currentAliasSet = new Set(
(await query(req.schema, 'SELECT alias_id FROM alias_group_members WHERE user_group_id=$1', [ug.id])).map(r => r.alias_id)
);
for (const aid of newAliasIds) {
if (!currentAliasSet.has(aid)) {
await exec(req.schema, 'INSERT INTO alias_group_members (user_group_id,alias_id) VALUES ($1,$2) ON CONFLICT DO NOTHING', [ug.id, aid]);
}
}
for (const aid of currentAliasSet) {
if (!newAliasIds.has(aid)) {
await exec(req.schema, 'DELETE FROM alias_group_members WHERE user_group_id=$1 AND alias_id=$2', [ug.id, aid]);
}
}
}
const updated = await queryOne(req.schema, 'SELECT * FROM user_groups WHERE id=$1', [req.params.id]);
res.json({ group: updated });
} catch (e) { res.status(500).json({ error: e.message }); }

View File

@@ -437,6 +437,20 @@ router.post('/me/avatar', authMiddleware, uploadAvatar.single('avatar'), async (
// ── Guardian alias routes (Guardian Only mode) ──────────────────────────────
// List ALL aliases — admin/manager only (for Group Manager alias management)
router.get('/aliases-all', authMiddleware, teamManagerMiddleware, async (req, res) => {
try {
const aliases = await query(req.schema,
`SELECT ga.id, ga.first_name, ga.last_name, ga.guardian_id, ga.avatar, ga.date_of_birth,
u.name AS guardian_name, u.display_name AS guardian_display_name
FROM guardian_aliases ga
JOIN users u ON u.id = ga.guardian_id
ORDER BY ga.first_name, ga.last_name`,
);
res.json({ aliases });
} catch (e) { res.status(500).json({ error: e.message }); }
});
// List current user's aliases
router.get('/me/aliases', authMiddleware, async (req, res) => {
try {