v0.9.39 bugs fixes
This commit is contained in:
@@ -10,7 +10,7 @@
|
|||||||
PROJECT_NAME=jama
|
PROJECT_NAME=jama
|
||||||
|
|
||||||
# Image version to run (set by build.sh, or use 'latest')
|
# 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
|
# App port — the host port Docker maps to the container
|
||||||
PORT=3000
|
PORT=3000
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jama-backend",
|
"name": "jama-backend",
|
||||||
"version": "0.9.38",
|
"version": "0.9.40",
|
||||||
"description": "TeamChat backend server",
|
"description": "TeamChat backend server",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -43,6 +43,24 @@ function adminMiddleware(req, res, next) {
|
|||||||
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) {
|
function generateToken(userId) {
|
||||||
return jwt.sign({ id: userId }, JWT_SECRET, { expiresIn: '30d' });
|
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 };
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const { getDb } = require('../models/db');
|
const { getDb } = require('../models/db');
|
||||||
const { authMiddleware, adminMiddleware } = require('../middleware/auth');
|
const { authMiddleware, adminMiddleware, teamManagerMiddleware } = require('../middleware/auth');
|
||||||
|
|
||||||
module.exports = function(io) {
|
module.exports = function(io) {
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ router.get('/me', authMiddleware, (req, res) => {
|
|||||||
|
|
||||||
// ── MULTI-GROUP DMs — must come before /:id ───────────────────────────────────
|
// ── 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 db = getDb();
|
||||||
const dms = db.prepare(`
|
const dms = db.prepare(`
|
||||||
SELECT mgd.*,
|
SELECT mgd.*,
|
||||||
@@ -166,7 +166,7 @@ router.delete('/multigroup/:id', authMiddleware, adminMiddleware, (req, res) =>
|
|||||||
|
|
||||||
// ── USER GROUPS ───────────────────────────────────────────────────────────────
|
// ── USER GROUPS ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
router.get('/', authMiddleware, adminMiddleware, (req, res) => {
|
router.get('/', authMiddleware, teamManagerMiddleware, (req, res) => {
|
||||||
const db = getDb();
|
const db = getDb();
|
||||||
const groups = db.prepare(`
|
const groups = db.prepare(`
|
||||||
SELECT ug.*,
|
SELECT ug.*,
|
||||||
@@ -176,7 +176,7 @@ router.get('/', authMiddleware, adminMiddleware, (req, res) => {
|
|||||||
res.json({ groups });
|
res.json({ groups });
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/:id', authMiddleware, adminMiddleware, (req, res) => {
|
router.get('/:id', authMiddleware, teamManagerMiddleware, (req, res) => {
|
||||||
const db = getDb();
|
const db = getDb();
|
||||||
const group = db.prepare('SELECT * FROM user_groups WHERE id = ?').get(req.params.id);
|
const group = db.prepare('SELECT * FROM user_groups WHERE id = ?').get(req.params.id);
|
||||||
if (!group) return res.status(404).json({ error: 'Not found' });
|
if (!group) return res.status(404).json({ error: 'Not found' });
|
||||||
@@ -252,11 +252,9 @@ router.patch('/:id', authMiddleware, adminMiddleware, (req, res) => {
|
|||||||
for (const uid of currentSet) {
|
for (const uid of currentSet) {
|
||||||
if (!newIds.has(uid)) {
|
if (!newIds.has(uid)) {
|
||||||
db.prepare('DELETE FROM user_group_members WHERE user_group_id = ? AND user_id = ?').run(ug.id, 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);
|
// For managed DMs, membership is controlled solely by the user group — always remove
|
||||||
if (!stillHasAccess) {
|
removeUser(db, ug.dm_group_id, uid, req.user.id);
|
||||||
removeUser(db, ug.dm_group_id, uid, req.user.id);
|
removedUids.push(uid);
|
||||||
removedUids.push(uid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
build.sh
2
build.sh
@@ -13,7 +13,7 @@
|
|||||||
# ─────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
VERSION="${1:-0.9.38}"
|
VERSION="${1:-0.9.40}"
|
||||||
ACTION="${2:-}"
|
ACTION="${2:-}"
|
||||||
REGISTRY="${REGISTRY:-}"
|
REGISTRY="${REGISTRY:-}"
|
||||||
IMAGE_NAME="jama"
|
IMAGE_NAME="jama"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jama-frontend",
|
"name": "jama-frontend",
|
||||||
"version": "0.9.38",
|
"version": "0.9.40",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
Reference in New Issue
Block a user