Add permission settings model and related functionality
All checks were successful
farmcontrol/farmcontrol-ws/pipeline/head This commit looks good
All checks were successful
farmcontrol/farmcontrol-ws/pipeline/head This commit looks good
- Introduced a new permission settings schema and model to manage user permissions effectively. - Updated user schema to include a reference to permission settings, allowing for dynamic permission management. - Enhanced the editObject function to conditionally recalculate permissions based on the new recalculate parameter. - Added utility functions for applying and retrieving permission settings, improving permission handling across the application.
This commit is contained in:
parent
7e8879164a
commit
3742839737
@ -425,7 +425,8 @@ export const editObject = async ({
|
|||||||
ownerType = undefined,
|
ownerType = undefined,
|
||||||
populate = [],
|
populate = [],
|
||||||
auditLog = true,
|
auditLog = true,
|
||||||
notify = true
|
notify = true,
|
||||||
|
recalculate = true
|
||||||
}) => {
|
}) => {
|
||||||
try {
|
try {
|
||||||
// Determine parentType from model name
|
// Determine parentType from model name
|
||||||
@ -494,7 +495,7 @@ export const editObject = async ({
|
|||||||
populate
|
populate
|
||||||
});
|
});
|
||||||
|
|
||||||
if (model.recalculate) {
|
if (model.recalculate && recalculate == true) {
|
||||||
logger.debug(`Recalculating ${model.modelName}`);
|
logger.debug(`Recalculating ${model.modelName}`);
|
||||||
await model.recalculate(newExpandedObject, owner, ownerType);
|
await model.recalculate(newExpandedObject, owner, ownerType);
|
||||||
}
|
}
|
||||||
|
|||||||
38
src/database/permissions.js
Normal file
38
src/database/permissions.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
export const applyPermissionSettingsList = (settingsList = []) => {
|
||||||
|
const permissions = {};
|
||||||
|
|
||||||
|
for (const setting of settingsList) {
|
||||||
|
const matrix = setting?.permissions;
|
||||||
|
if (!matrix || typeof matrix !== 'object' || Array.isArray(matrix)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [modelName, actions] of Object.entries(matrix)) {
|
||||||
|
if (!actions || typeof actions !== 'object' || Array.isArray(actions)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!permissions[modelName]) {
|
||||||
|
permissions[modelName] = {};
|
||||||
|
}
|
||||||
|
for (const [actionName, value] of Object.entries(actions)) {
|
||||||
|
if (value === true || value === false) {
|
||||||
|
permissions[modelName][actionName] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Object.keys(permissions[modelName]).length === 0) {
|
||||||
|
delete permissions[modelName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return permissions;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPermissionSettingsId = (value) => {
|
||||||
|
if (!value) return null;
|
||||||
|
if (typeof value === 'string') return value;
|
||||||
|
if (value._id) {
|
||||||
|
return value._id._id || value._id;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
59
src/database/schemas/management/permissionsettings.schema.js
Normal file
59
src/database/schemas/management/permissionsettings.schema.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import mongoose from 'mongoose';
|
||||||
|
import { generateId } from '../../utils.js';
|
||||||
|
import { getPermissionSettingsId } from '../../permissions.js';
|
||||||
|
|
||||||
|
const { Schema } = mongoose;
|
||||||
|
|
||||||
|
const permissionSettingsSchema = new Schema(
|
||||||
|
{
|
||||||
|
_reference: { type: String, default: () => generateId()() },
|
||||||
|
name: { type: String, required: true },
|
||||||
|
permissions: { type: Schema.Types.Mixed, required: false, default: () => ({}) },
|
||||||
|
},
|
||||||
|
{ timestamps: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
permissionSettingsSchema.index({ name: 'text' });
|
||||||
|
|
||||||
|
permissionSettingsSchema.virtual('id').get(function () {
|
||||||
|
return this._id;
|
||||||
|
});
|
||||||
|
|
||||||
|
permissionSettingsSchema.set('toJSON', { virtuals: true });
|
||||||
|
|
||||||
|
permissionSettingsSchema.statics.recalculate = async function (permissionSettings, user) {
|
||||||
|
const permissionSettingsId = getPermissionSettingsId(permissionSettings);
|
||||||
|
if (!permissionSettingsId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userModel = mongoose.model('user');
|
||||||
|
const users = await userModel
|
||||||
|
.find({ permissionSettings: permissionSettingsId })
|
||||||
|
.lean();
|
||||||
|
|
||||||
|
const stillExists = await this.exists({ _id: permissionSettingsId });
|
||||||
|
if (!stillExists) {
|
||||||
|
await userModel.updateMany(
|
||||||
|
{ permissionSettings: permissionSettingsId },
|
||||||
|
{ $pull: { permissionSettings: permissionSettingsId } }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const assignedUser of users) {
|
||||||
|
const nextUser = stillExists
|
||||||
|
? assignedUser
|
||||||
|
: {
|
||||||
|
...assignedUser,
|
||||||
|
permissionSettings: (assignedUser.permissionSettings || []).filter(
|
||||||
|
(item) => String(getPermissionSettingsId(item)) !== String(permissionSettingsId)
|
||||||
|
),
|
||||||
|
};
|
||||||
|
await userModel.recalculate(nextUser, user);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const permissionSettingsModel = mongoose.model(
|
||||||
|
'permissionSettings',
|
||||||
|
permissionSettingsSchema
|
||||||
|
);
|
||||||
@ -1,5 +1,8 @@
|
|||||||
import mongoose from 'mongoose';
|
import mongoose from 'mongoose';
|
||||||
import { generateId } from '../../utils.js';
|
import { generateId } from '../../utils.js';
|
||||||
|
import { applyPermissionSettingsList, getPermissionSettingsId } from '../../permissions.js';
|
||||||
|
|
||||||
|
const { Schema } = mongoose;
|
||||||
|
|
||||||
const userSchema = new mongoose.Schema(
|
const userSchema = new mongoose.Schema(
|
||||||
{
|
{
|
||||||
@ -11,6 +14,10 @@ const userSchema = new mongoose.Schema(
|
|||||||
email: { required: true, type: String },
|
email: { required: true, type: String },
|
||||||
profileImage: { type: mongoose.SchemaTypes.ObjectId, ref: 'file', required: false },
|
profileImage: { type: mongoose.SchemaTypes.ObjectId, ref: 'file', required: false },
|
||||||
appPasswordHash: { type: String, required: false, select: false },
|
appPasswordHash: { type: String, required: false, select: false },
|
||||||
|
permissionSettings: [
|
||||||
|
{ type: Schema.Types.ObjectId, ref: 'permissionSettings', required: false },
|
||||||
|
],
|
||||||
|
permissions: { type: Schema.Types.Mixed, required: false, default: () => ({}) },
|
||||||
},
|
},
|
||||||
{ timestamps: true }
|
{ timestamps: true }
|
||||||
);
|
);
|
||||||
@ -23,4 +30,40 @@ userSchema.virtual('id').get(function () {
|
|||||||
|
|
||||||
userSchema.set('toJSON', { virtuals: true });
|
userSchema.set('toJSON', { virtuals: true });
|
||||||
|
|
||||||
|
const resolvePermissionSettings = async (user) => {
|
||||||
|
const permissionSettingsModel = mongoose.model('permissionSettings');
|
||||||
|
const items = user?.permissionSettings || [];
|
||||||
|
const ids = items.map(getPermissionSettingsId).filter(Boolean);
|
||||||
|
if (ids.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const docs = await permissionSettingsModel
|
||||||
|
.find({ _id: { $in: ids } })
|
||||||
|
.lean();
|
||||||
|
const docsById = new Map(docs.map((doc) => [String(doc._id), doc]));
|
||||||
|
|
||||||
|
return ids.map((id) => docsById.get(String(id))).filter(Boolean);
|
||||||
|
};
|
||||||
|
|
||||||
|
userSchema.statics.recalculate = async function (user, actingUser) {
|
||||||
|
const userId = user?._id || user;
|
||||||
|
if (!userId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const settings = await resolvePermissionSettings(user);
|
||||||
|
const permissions = applyPermissionSettingsList(settings);
|
||||||
|
const { editObject } = await import('../../database.js');
|
||||||
|
|
||||||
|
await editObject({
|
||||||
|
model: this,
|
||||||
|
id: userId,
|
||||||
|
updateData: { permissions },
|
||||||
|
user: actingUser,
|
||||||
|
populate: ['profileImage', 'permissionSettings'],
|
||||||
|
recalculate: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const userModel = mongoose.model('user', userSchema);
|
export const userModel = mongoose.model('user', userSchema);
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import { stockLocationModel } from './inventory/stocklocation.schema.js';
|
|||||||
import { stockTransferModel } from './inventory/stocktransfer.schema.js';
|
import { stockTransferModel } from './inventory/stocktransfer.schema.js';
|
||||||
import { auditLogModel } from './management/auditlog.schema.js';
|
import { auditLogModel } from './management/auditlog.schema.js';
|
||||||
import { userModel } from './management/user.schema.js';
|
import { userModel } from './management/user.schema.js';
|
||||||
|
import { permissionSettingsModel } from './management/permissionsettings.schema.js';
|
||||||
import { appPasswordModel } from './management/apppassword.schema.js';
|
import { appPasswordModel } from './management/apppassword.schema.js';
|
||||||
import { noteTypeModel } from './management/notetype.schema.js';
|
import { noteTypeModel } from './management/notetype.schema.js';
|
||||||
import { noteModel } from './misc/note.schema.js';
|
import { noteModel } from './misc/note.schema.js';
|
||||||
@ -212,6 +213,13 @@ export const models = {
|
|||||||
referenceField: '_reference',
|
referenceField: '_reference',
|
||||||
label: 'User',
|
label: 'User',
|
||||||
},
|
},
|
||||||
|
PMS: {
|
||||||
|
model: permissionSettingsModel,
|
||||||
|
idField: '_id',
|
||||||
|
type: 'permissionSettings',
|
||||||
|
referenceField: '_reference',
|
||||||
|
label: 'Permission Settings',
|
||||||
|
},
|
||||||
APP: {
|
APP: {
|
||||||
model: appPasswordModel,
|
model: appPasswordModel,
|
||||||
idField: '_id',
|
idField: '_id',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user