This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pulse-signage",
|
||||
"version": "1.4.1",
|
||||
"version": "1.4.2",
|
||||
"private": false,
|
||||
"description": "Pulse Signage application with MySQL and media uploads",
|
||||
"repository": {
|
||||
|
||||
@@ -95,6 +95,79 @@ async function addUserAuditColumns(pool, tableName) {
|
||||
await addForeignKeyIfMissing(pool, tableName, 'modified_by', `fk_${tableName}_modified_by`, 'users', 'id', 'SET NULL');
|
||||
}
|
||||
|
||||
async function hasSingleColumnUniqueIndex(pool, tableName, columnName) {
|
||||
const [rows] = await pool.query(
|
||||
`SELECT INDEX_NAME, COUNT(*) AS column_count
|
||||
FROM information_schema.statistics
|
||||
WHERE table_schema = DATABASE()
|
||||
AND table_name = ?
|
||||
AND non_unique = 0
|
||||
AND column_name = ?
|
||||
GROUP BY INDEX_NAME`,
|
||||
[tableName, columnName]
|
||||
);
|
||||
|
||||
return (rows || []).some(function (row) {
|
||||
return Number(row.column_count) === 1;
|
||||
});
|
||||
}
|
||||
|
||||
async function addUniqueIndexIfMissing(pool, tableName, columnName, indexName) {
|
||||
const hasUniqueIndex = await hasSingleColumnUniqueIndex(pool, tableName, columnName);
|
||||
if (hasUniqueIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
await pool.query(`ALTER TABLE \`${tableName}\` ADD UNIQUE KEY \`${indexName}\` (\`${columnName}\`)`);
|
||||
}
|
||||
|
||||
async function dedupePermissionRows(pool) {
|
||||
const [rows] = await pool.query('SELECT id, permission_key FROM permissions ORDER BY id ASC');
|
||||
const canonicalIdByKey = new Map();
|
||||
const duplicateRowsByKey = new Map();
|
||||
|
||||
for (const row of rows || []) {
|
||||
const permissionKey = getPermissionKey(row);
|
||||
const permissionId = Number(row.id);
|
||||
if (!permissionKey || !Number.isInteger(permissionId) || permissionId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!canonicalIdByKey.has(permissionKey)) {
|
||||
canonicalIdByKey.set(permissionKey, permissionId);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!duplicateRowsByKey.has(permissionKey)) {
|
||||
duplicateRowsByKey.set(permissionKey, []);
|
||||
}
|
||||
duplicateRowsByKey.get(permissionKey).push(permissionId);
|
||||
}
|
||||
|
||||
if (!duplicateRowsByKey.size) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const [permissionKey, duplicateIds] of duplicateRowsByKey.entries()) {
|
||||
const canonicalId = canonicalIdByKey.get(permissionKey);
|
||||
for (const duplicateId of duplicateIds) {
|
||||
await pool.query(
|
||||
'UPDATE IGNORE role_permissions SET permission_id = ? WHERE permission_id = ?',
|
||||
[canonicalId, duplicateId]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const duplicateIds = [];
|
||||
for (const duplicateList of duplicateRowsByKey.values()) {
|
||||
duplicateIds.push.apply(duplicateIds, duplicateList);
|
||||
}
|
||||
|
||||
if (duplicateIds.length) {
|
||||
await pool.query('DELETE FROM permissions WHERE id IN (?)', [duplicateIds]);
|
||||
}
|
||||
}
|
||||
|
||||
async function pruneStaleOnboardingDevices(pool) {
|
||||
await pool.query(
|
||||
`DELETE FROM player_onboarding_devices
|
||||
@@ -541,6 +614,8 @@ async function ensureSchema(pool) {
|
||||
await addColumnIfMissing(pool, 'permissions', 'modified_at', 'TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');
|
||||
await addUserAuditColumns(pool, 'permissions');
|
||||
await dropColumnIfPresent(pool, 'permissions', 'perm_key');
|
||||
await dedupePermissionRows(pool);
|
||||
await addUniqueIndexIfMissing(pool, 'permissions', 'permission_key', 'uq_permissions_permission_key');
|
||||
|
||||
await pool.query(`
|
||||
CREATE TABLE IF NOT EXISTS role_permissions (
|
||||
|
||||
Reference in New Issue
Block a user