Modal scroll fix; per-account editor/viewer roles
- Fix account settings modal overflow: add max-height to .modal, make
.modal-body flex/scrollable, widen #acct-settings-modal to 620px
- Add role column to user_accounts (editor|viewer) with migration;
existing assignments promoted to editor
- New isEditorForAccount() in auth middleware for per-account write checks
- Replace global requireEditor with per-account checks in checks.js,
deposits.js, pdf.js, deposit-pdf.js, qbo-import.js
- GET /api/accounts now returns user_role per account
- users.js returns {account_id, role} per assignment; POST/PUT accept
accounts as [{id, role}]
- Frontend: state.accountRole tracks effective role for active account;
applyRoleUI and renderRow use it; user management shows role dropdown
per account assignment
This commit is contained in:
+6
-8
@@ -12,8 +12,7 @@ router.use(requireAuth, requireAdmin);
|
||||
function userWithAccounts(id) {
|
||||
const user = db.prepare('SELECT id, username, role, created_at FROM users WHERE id = ?').get(id);
|
||||
if (!user) return null;
|
||||
user.accounts = db.prepare('SELECT account_id FROM user_accounts WHERE user_id = ?')
|
||||
.all(id).map(r => r.account_id);
|
||||
user.accounts = db.prepare('SELECT account_id, role FROM user_accounts WHERE user_id = ?').all(id);
|
||||
return user;
|
||||
}
|
||||
|
||||
@@ -21,8 +20,7 @@ function userWithAccounts(id) {
|
||||
router.get('/', (req, res) => {
|
||||
const users = db.prepare('SELECT id, username, role, created_at FROM users ORDER BY id ASC').all();
|
||||
users.forEach(u => {
|
||||
u.accounts = db.prepare('SELECT account_id FROM user_accounts WHERE user_id = ?')
|
||||
.all(u.id).map(r => r.account_id);
|
||||
u.accounts = db.prepare('SELECT account_id, role FROM user_accounts WHERE user_id = ?').all(u.id);
|
||||
});
|
||||
res.json(users);
|
||||
});
|
||||
@@ -48,8 +46,8 @@ router.post('/', async (req, res) => {
|
||||
}
|
||||
|
||||
if (role !== 'admin' && Array.isArray(accounts) && accounts.length > 0) {
|
||||
const stmt = db.prepare('INSERT OR IGNORE INTO user_accounts (user_id, account_id) VALUES (?, ?)');
|
||||
accounts.forEach(aid => stmt.run(userId, aid));
|
||||
const stmt = db.prepare('INSERT OR IGNORE INTO user_accounts (user_id, account_id, role) VALUES (?, ?, ?)');
|
||||
accounts.forEach(a => stmt.run(userId, a.id, a.role === 'editor' ? 'editor' : 'viewer'));
|
||||
}
|
||||
|
||||
res.status(201).json(userWithAccounts(userId));
|
||||
@@ -92,8 +90,8 @@ router.put('/:id', async (req, res) => {
|
||||
db.prepare('DELETE FROM user_accounts WHERE user_id = ?').run(req.params.id);
|
||||
const effectiveRole = role || user.role;
|
||||
if (effectiveRole !== 'admin' && accounts.length > 0) {
|
||||
const stmt = db.prepare('INSERT OR IGNORE INTO user_accounts (user_id, account_id) VALUES (?, ?)');
|
||||
accounts.forEach(aid => stmt.run(req.params.id, aid));
|
||||
const stmt = db.prepare('INSERT OR IGNORE INTO user_accounts (user_id, account_id, role) VALUES (?, ?, ?)');
|
||||
accounts.forEach(a => stmt.run(req.params.id, a.id, a.role === 'editor' ? 'editor' : 'viewer'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user