v0.9.39 bugs fixes

This commit is contained in:
2026-03-16 18:29:51 -04:00
parent 5025f0043d
commit de5912c206
6 changed files with 30 additions and 14 deletions

View File

@@ -10,7 +10,7 @@
PROJECT_NAME=jama
# Image version to run (set by build.sh, or use 'latest')
JAMA_VERSION=0.9.38
JAMA_VERSION=0.9.40
# App port — the host port Docker maps to the container
PORT=3000

View File

@@ -1,6 +1,6 @@
{
"name": "jama-backend",
"version": "0.9.38",
"version": "0.9.40",
"description": "TeamChat backend server",
"main": "src/index.js",
"scripts": {

View File

@@ -43,6 +43,24 @@ function adminMiddleware(req, res, next) {
next();
}
// Allows admins OR members of groups designated as Group Managers or Schedule Managers
function teamManagerMiddleware(req, res, next) {
if (req.user?.role === 'admin') return next();
const db = getDb();
const gmSetting = db.prepare("SELECT value FROM settings WHERE key = 'team_group_managers'").get();
const smSetting = db.prepare("SELECT value FROM settings WHERE key = 'team_schedule_managers'").get();
const allowedGroupIds = [
...JSON.parse(gmSetting?.value || '[]'),
...JSON.parse(smSetting?.value || '[]'),
];
if (allowedGroupIds.length === 0) return res.status(403).json({ error: 'Access denied' });
const member = db.prepare(`
SELECT 1 FROM user_group_members WHERE user_id = ? AND user_group_id IN (${allowedGroupIds.map(() => '?').join(',')})
`).get(req.user.id, ...allowedGroupIds);
if (!member) return res.status(403).json({ error: 'Access denied' });
next();
}
function generateToken(userId) {
return jwt.sign({ id: userId }, JWT_SECRET, { expiresIn: '30d' });
}
@@ -70,4 +88,4 @@ function clearActiveSession(userId, device) {
}
}
module.exports = { authMiddleware, adminMiddleware, generateToken, setActiveSession, clearActiveSession, getDeviceClass };
module.exports = { authMiddleware, adminMiddleware, teamManagerMiddleware, generateToken, setActiveSession, clearActiveSession, getDeviceClass };

View File

@@ -1,7 +1,7 @@
const express = require('express');
const router = express.Router();
const { getDb } = require('../models/db');
const { authMiddleware, adminMiddleware } = require('../middleware/auth');
const { authMiddleware, adminMiddleware, teamManagerMiddleware } = require('../middleware/auth');
module.exports = function(io) {
@@ -55,7 +55,7 @@ router.get('/me', authMiddleware, (req, res) => {
// ── MULTI-GROUP DMs — must come before /:id ───────────────────────────────────
router.get('/multigroup', authMiddleware, adminMiddleware, (req, res) => {
router.get('/multigroup', authMiddleware, teamManagerMiddleware, (req, res) => {
const db = getDb();
const dms = db.prepare(`
SELECT mgd.*,
@@ -166,7 +166,7 @@ router.delete('/multigroup/:id', authMiddleware, adminMiddleware, (req, res) =>
// ── USER GROUPS ───────────────────────────────────────────────────────────────
router.get('/', authMiddleware, adminMiddleware, (req, res) => {
router.get('/', authMiddleware, teamManagerMiddleware, (req, res) => {
const db = getDb();
const groups = db.prepare(`
SELECT ug.*,
@@ -176,7 +176,7 @@ router.get('/', authMiddleware, adminMiddleware, (req, res) => {
res.json({ groups });
});
router.get('/:id', authMiddleware, adminMiddleware, (req, res) => {
router.get('/:id', authMiddleware, teamManagerMiddleware, (req, res) => {
const db = getDb();
const group = db.prepare('SELECT * FROM user_groups WHERE id = ?').get(req.params.id);
if (!group) return res.status(404).json({ error: 'Not found' });
@@ -252,13 +252,11 @@ router.patch('/:id', authMiddleware, adminMiddleware, (req, res) => {
for (const uid of currentSet) {
if (!newIds.has(uid)) {
db.prepare('DELETE FROM user_group_members WHERE user_group_id = ? AND user_id = ?').run(ug.id, uid);
const stillHasAccess = db.prepare(`SELECT 1 FROM user_group_members ugm WHERE ugm.user_id = ? AND ugm.user_group_id != ? AND EXISTS (SELECT 1 FROM group_members gm WHERE gm.group_id = ? AND gm.user_id = ?)`).get(uid, ug.id, ug.dm_group_id, uid);
if (!stillHasAccess) {
// For managed DMs, membership is controlled solely by the user group — always remove
removeUser(db, ug.dm_group_id, uid, req.user.id);
removedUids.push(uid);
}
}
}
// For multi-group DMs: add/remove users silently, post group-level notification once
const mgDms = db.prepare('SELECT mgd.id, mgd.dm_group_id FROM multi_group_dm_members mgdm JOIN multi_group_dms mgd ON mgd.id = mgdm.multi_group_dm_id WHERE mgdm.user_group_id = ?').all(ug.id);

View File

@@ -13,7 +13,7 @@
# ─────────────────────────────────────────────────────────────
set -euo pipefail
VERSION="${1:-0.9.38}"
VERSION="${1:-0.9.40}"
ACTION="${2:-}"
REGISTRY="${REGISTRY:-}"
IMAGE_NAME="jama"

View File

@@ -1,6 +1,6 @@
{
"name": "jama-frontend",
"version": "0.9.38",
"version": "0.9.40",
"private": true,
"scripts": {
"dev": "vite",