forked from lunanting/cangku
356 lines
10 KiB
JavaScript
356 lines
10 KiB
JavaScript
const database = require('../config/database');
|
|
const { ROLES, SIDEBAR_PAGES, SIDEBAR_PAGE_MAP } = require('../constants/sidebarPages');
|
|
const SETTINGS_PAGE_KEY = 'settings';
|
|
const PLANNING_UPLOAD_PAGE_KEY = 'planning_upload';
|
|
|
|
function getDefaultRoleAllowed(pageKey, role) {
|
|
return Boolean(SIDEBAR_PAGE_MAP[pageKey]?.defaultRoles?.[role]);
|
|
}
|
|
|
|
function getDefaultDepartmentAllowed(pageKey) {
|
|
return Boolean(SIDEBAR_PAGE_MAP[pageKey]?.departmentDefaultAllowed);
|
|
}
|
|
|
|
function shouldRepairExistingPermission(pageKey, role, allowed) {
|
|
if (pageKey === SETTINGS_PAGE_KEY && role === 'admin') {
|
|
return !(allowed === 1 || allowed === true);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
async function ensureSidebarRolePermissions() {
|
|
for (const page of SIDEBAR_PAGES) {
|
|
for (const role of ROLES) {
|
|
const existing = await database.local.query(
|
|
'SELECT id, page_name, allowed FROM permissions WHERE page_key = ? AND role = ? LIMIT 1',
|
|
[page.pageKey, role]
|
|
);
|
|
|
|
if (existing.length > 0) {
|
|
const shouldRepairAllowed = shouldRepairExistingPermission(page.pageKey, role, existing[0].allowed);
|
|
const shouldRepairPageName = existing[0].page_name !== page.pageName;
|
|
|
|
if (shouldRepairAllowed || shouldRepairPageName) {
|
|
await database.local.query(
|
|
'UPDATE permissions SET page_name = ?, allowed = ? WHERE id = ?',
|
|
[
|
|
page.pageName,
|
|
shouldRepairAllowed ? (getDefaultRoleAllowed(page.pageKey, role) ? 1 : 0) : existing[0].allowed,
|
|
existing[0].id,
|
|
]
|
|
);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
await database.local.insert('permissions', {
|
|
page_key: page.pageKey,
|
|
page_name: page.pageName,
|
|
role,
|
|
allowed: getDefaultRoleAllowed(page.pageKey, role) ? 1 : 0,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
async function getSidebarRolePermissions() {
|
|
const rows = await database.local.query(
|
|
`SELECT page_key as pageKey, page_name as pageName, role, allowed
|
|
FROM permissions
|
|
WHERE page_key IN (${SIDEBAR_PAGES.map(() => '?').join(', ')})`,
|
|
SIDEBAR_PAGES.map((item) => item.pageKey)
|
|
);
|
|
|
|
return rows;
|
|
}
|
|
|
|
async function ensureDepartmentPagePermissions() {
|
|
const departments = await database.local.query('SELECT id FROM departments');
|
|
|
|
for (const department of departments) {
|
|
const rows = await database.local.query(
|
|
`SELECT id, page_key as pageKey, page_name as pageName
|
|
FROM department_page_permissions
|
|
WHERE department_id = ?`,
|
|
[department.id]
|
|
);
|
|
|
|
const rowMap = rows.reduce((acc, row) => {
|
|
acc[row.pageKey] = row;
|
|
return acc;
|
|
}, {});
|
|
|
|
for (const page of SIDEBAR_PAGES) {
|
|
const existing = rowMap[page.pageKey];
|
|
if (existing) {
|
|
if (existing.pageName !== page.pageName) {
|
|
await database.local.query(
|
|
`UPDATE department_page_permissions
|
|
SET page_name = ?
|
|
WHERE id = ?`,
|
|
[page.pageName, existing.id]
|
|
);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
await database.local.insert('department_page_permissions', {
|
|
department_id: department.id,
|
|
page_key: page.pageKey,
|
|
page_name: page.pageName,
|
|
allowed: getDefaultDepartmentAllowed(page.pageKey) ? 1 : 0,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
async function getDepartmentPagePermissions(departmentId) {
|
|
const rows = await database.local.query(
|
|
`SELECT page_key as pageKey, allowed
|
|
FROM department_page_permissions
|
|
WHERE department_id = ?`,
|
|
[departmentId]
|
|
);
|
|
|
|
const rowMap = rows.reduce((acc, row) => {
|
|
acc[row.pageKey] = row.allowed === 1 || row.allowed === true;
|
|
return acc;
|
|
}, {});
|
|
|
|
return SIDEBAR_PAGES.map((page) => ({
|
|
pageKey: page.pageKey,
|
|
pageName: page.pageName,
|
|
path: page.path,
|
|
category: page.category,
|
|
allowed: rowMap[page.pageKey] === undefined ? getDefaultDepartmentAllowed(page.pageKey) : rowMap[page.pageKey],
|
|
}));
|
|
}
|
|
|
|
async function saveDepartmentPagePermissions(departmentId, pagePermissions = []) {
|
|
const normalized = SIDEBAR_PAGES.map((page) => {
|
|
const incoming = pagePermissions.find((item) => item.pageKey === page.pageKey);
|
|
return {
|
|
pageKey: page.pageKey,
|
|
pageName: page.pageName,
|
|
allowed: incoming?.allowed !== undefined ? Boolean(incoming.allowed) : getDefaultDepartmentAllowed(page.pageKey),
|
|
};
|
|
});
|
|
|
|
await database.local.query('DELETE FROM department_page_permissions WHERE department_id = ?', [departmentId]);
|
|
|
|
for (const permission of normalized) {
|
|
await database.local.insert('department_page_permissions', {
|
|
department_id: departmentId,
|
|
page_key: permission.pageKey,
|
|
page_name: permission.pageName,
|
|
allowed: permission.allowed ? 1 : 0,
|
|
});
|
|
}
|
|
|
|
return getDepartmentPagePermissions(departmentId);
|
|
}
|
|
|
|
async function getUserPageOverrideRows(userId) {
|
|
return database.local.query(
|
|
`SELECT page_key as pageKey, allowed
|
|
FROM user_page_permissions
|
|
WHERE user_id = ?`,
|
|
[userId]
|
|
);
|
|
}
|
|
|
|
async function getBaseAllowedPageKeysForUser(user) {
|
|
if (!user) {
|
|
return [];
|
|
}
|
|
|
|
if (user.role === 'admin') {
|
|
return SIDEBAR_PAGES.map((page) => page.pageKey);
|
|
}
|
|
|
|
const roleRows = await database.local.query(
|
|
`SELECT page_key as pageKey, allowed
|
|
FROM permissions
|
|
WHERE role = ?
|
|
AND page_key IN (${SIDEBAR_PAGES.map(() => '?').join(', ')})`,
|
|
[user.role, ...SIDEBAR_PAGES.map((item) => item.pageKey)]
|
|
);
|
|
|
|
const roleAllowed = new Set(
|
|
SIDEBAR_PAGES.filter((page) => {
|
|
const row = roleRows.find((item) => item.pageKey === page.pageKey);
|
|
if (!row) {
|
|
return getDefaultRoleAllowed(page.pageKey, user.role);
|
|
}
|
|
return row.allowed === 1 || row.allowed === true;
|
|
}).map((page) => page.pageKey)
|
|
);
|
|
|
|
if (!user.department_id) {
|
|
if (user.role === 'admin') {
|
|
return Array.from(roleAllowed);
|
|
}
|
|
|
|
return Array.from(roleAllowed).filter((pageKey) => pageKey !== PLANNING_UPLOAD_PAGE_KEY);
|
|
}
|
|
|
|
const departmentRows = await database.local.query(
|
|
`SELECT page_key as pageKey, allowed
|
|
FROM department_page_permissions
|
|
WHERE department_id = ?`,
|
|
[user.department_id]
|
|
);
|
|
|
|
if (departmentRows.length === 0) {
|
|
return Array.from(roleAllowed).filter((pageKey) => getDefaultDepartmentAllowed(pageKey));
|
|
}
|
|
|
|
const departmentRowMap = departmentRows.reduce((acc, row) => {
|
|
acc[row.pageKey] = row.allowed === 1 || row.allowed === true;
|
|
return acc;
|
|
}, {});
|
|
|
|
const departmentAllowed = new Set(
|
|
SIDEBAR_PAGES
|
|
.filter((page) => departmentRowMap[page.pageKey] === undefined ? getDefaultDepartmentAllowed(page.pageKey) : departmentRowMap[page.pageKey])
|
|
.map((page) => page.pageKey)
|
|
);
|
|
|
|
let pageKeys = Array.from(roleAllowed).filter((pageKey) => departmentAllowed.has(pageKey));
|
|
|
|
return pageKeys;
|
|
}
|
|
|
|
async function getAllowedPageKeysForUser(user) {
|
|
const basePageKeys = await getBaseAllowedPageKeysForUser(user);
|
|
if (!user || user.role === 'admin') {
|
|
return basePageKeys;
|
|
}
|
|
|
|
const overrideRows = await getUserPageOverrideRows(user.id);
|
|
const userAllowed = overrideRows
|
|
.filter((row) => row.allowed === 1 || row.allowed === true)
|
|
.map((row) => row.pageKey);
|
|
|
|
return Array.from(new Set([...basePageKeys, ...userAllowed]));
|
|
}
|
|
|
|
async function getUserPagePermissions(userId) {
|
|
const users = await database.local.query(
|
|
`SELECT id, username, name, role, department_id
|
|
FROM users
|
|
WHERE id = ?
|
|
LIMIT 1`,
|
|
[userId]
|
|
);
|
|
const user = users[0];
|
|
if (!user) {
|
|
return null;
|
|
}
|
|
|
|
const [basePageKeys, overrideRows] = await Promise.all([
|
|
getBaseAllowedPageKeysForUser(user),
|
|
getUserPageOverrideRows(userId),
|
|
]);
|
|
const baseAllowed = new Set(basePageKeys);
|
|
const overrideMap = overrideRows.reduce((acc, row) => {
|
|
acc[row.pageKey] = row.allowed === 1 || row.allowed === true;
|
|
return acc;
|
|
}, {});
|
|
|
|
return {
|
|
user,
|
|
permissions: SIDEBAR_PAGES.map((page) => {
|
|
const userAllowed = overrideMap[page.pageKey] === true;
|
|
return {
|
|
pageKey: page.pageKey,
|
|
pageName: page.pageName,
|
|
path: page.path,
|
|
category: page.category,
|
|
baseAllowed: baseAllowed.has(page.pageKey),
|
|
userAllowed,
|
|
effectiveAllowed: baseAllowed.has(page.pageKey) || userAllowed,
|
|
};
|
|
}),
|
|
};
|
|
}
|
|
|
|
async function saveUserPagePermissions(userId, pagePermissions = []) {
|
|
const pageMap = new Map(SIDEBAR_PAGES.map((page) => [page.pageKey, page]));
|
|
const normalized = pagePermissions
|
|
.filter((item) => item?.allowed === true && pageMap.has(item.pageKey))
|
|
.map((item) => {
|
|
const page = pageMap.get(item.pageKey);
|
|
return {
|
|
pageKey: page.pageKey,
|
|
pageName: page.pageName,
|
|
};
|
|
});
|
|
|
|
const deduped = Array.from(
|
|
normalized.reduce((acc, item) => acc.set(item.pageKey, item), new Map()).values()
|
|
);
|
|
|
|
await database.local.query('DELETE FROM user_page_permissions WHERE user_id = ?', [userId]);
|
|
|
|
for (const permission of deduped) {
|
|
await database.local.insert('user_page_permissions', {
|
|
user_id: userId,
|
|
page_key: permission.pageKey,
|
|
page_name: permission.pageName,
|
|
allowed: 1,
|
|
});
|
|
}
|
|
|
|
return getUserPagePermissions(userId);
|
|
}
|
|
|
|
async function getResolvedUserWithPageAccess(userId) {
|
|
const rows = await database.local.query(
|
|
`SELECT
|
|
u.id,
|
|
u.username,
|
|
u.name,
|
|
u.email,
|
|
u.role,
|
|
u.status,
|
|
u.department_id,
|
|
u.avatar_url,
|
|
u.auth_source,
|
|
d.name as departmentName
|
|
FROM users u
|
|
LEFT JOIN departments d ON u.department_id = d.id
|
|
WHERE u.id = ?
|
|
LIMIT 1`,
|
|
[userId]
|
|
);
|
|
|
|
const user = rows[0];
|
|
if (!user) {
|
|
return null;
|
|
}
|
|
|
|
const allowedPageKeys = await getAllowedPageKeysForUser(user);
|
|
|
|
return {
|
|
...user,
|
|
picture: user.avatar_url || '',
|
|
departmentId: user.department_id || null,
|
|
allowedPageKeys,
|
|
};
|
|
}
|
|
|
|
module.exports = {
|
|
SIDEBAR_PAGES,
|
|
ensureSidebarRolePermissions,
|
|
ensureDepartmentPagePermissions,
|
|
getAllowedPageKeysForUser,
|
|
getDepartmentPagePermissions,
|
|
getResolvedUserWithPageAccess,
|
|
getSidebarRolePermissions,
|
|
getUserPagePermissions,
|
|
saveDepartmentPagePermissions,
|
|
saveUserPagePermissions,
|
|
};
|