'use strict'; const _ = require('lodash'); const { subject: asSubject } = require('@casl/ability'); const { permittedFieldsOf } = require('@casl/ability/extra'); const { sanitizeEntity, contentTypes: { constants }, } = require('strapi-utils'); const { buildStrapiQuery, buildCaslQuery } = require('./query-builers'); module.exports = ({ ability, action, model }) => ({ ability, action, model, get isAllowed() { return this.ability.can(action, model); }, toSubject(target, subjectType = model) { return asSubject(subjectType, target); }, pickPermittedFieldsOf(data, options = {}) { return this.sanitize(data, { ...options, isOutput: false }); }, getQuery(queryAction = action) { if (_.isUndefined(queryAction)) { throw new Error('Action must be defined to build a permission query'); } return buildStrapiQuery(buildCaslQuery(ability, queryAction, model)); }, queryFrom(query = {}, action) { const permissionQuery = this.getQuery(action); return { ...query, _where: query._where ? _.concat(permissionQuery, query._where) : [permissionQuery], }; }, sanitize(data, options = {}) { const { subject = this.toSubject(data), action: actionOverride = action, withPrivate = true, isOutput = true, } = options; if (_.isArray(data)) { return data.map(entity => this.sanitize(entity, { action, withPrivate, isOutput })); } const permittedFields = permittedFieldsOf(ability, actionOverride, subject); const hasAtLeastOneRegisteredField = _.some( _.flatMap(ability.rulesFor(actionOverride, subject), 'fields') ); const shouldIncludeAllFields = _.isEmpty(permittedFields) && !hasAtLeastOneRegisteredField; const sanitizedEntity = sanitizeEntity(data, { model: strapi.getModel(model), includeFields: shouldIncludeAllFields ? null : permittedFields, withPrivate, isOutput, }); return _.omit(sanitizedEntity, [ `${constants.CREATED_BY_ATTRIBUTE}.roles`, `${constants.UPDATED_BY_ATTRIBUTE}.roles`, ]); }, });