Skip to content

Instantly share code, notes, and snippets.

@jerodfritz
Last active October 9, 2023 14:21
Show Gist options
  • Save jerodfritz/bfcea3b33bc39e533cd39f4ef788eb69 to your computer and use it in GitHub Desktop.
Save jerodfritz/bfcea3b33bc39e533cd39f4ef788eb69 to your computer and use it in GitHub Desktop.
Strapi isOwners.js policy
'use strict';
/**
* `isOwners` policy that allows for many owners and a private field == false individual querying or sharing with multiple users as readonly
*/
const _ = require('lodash');
let compareIDs = (a, b) => {
return a.toString() === b.toString();
}
var pluralize = require('pluralize')
module.exports = async (ctx, next) => {
try {
let errMsg = "You are not allowed to perform this action.";
if (!ctx.state.user) {
ctx.state.user = {
id: undefined,
role: {
type: undefined
}
}
}
const {
id,
role,
} = ctx.state.user;
if (role.type !== 'root') {
// [find, count] Only query entities that owned by the current user or findone if private==false
if (
//GraphQL Query
ctx.request.method == "POST" && ctx.request.url.startsWith("/graphql") ||
// REST Get
ctx.request.method === 'GET'
) {
// Remove everything about owner in the query eg. owner.id_in, owner.id, owner etc.
// Remove everything about readonly in the query eg. readonly.id_in, readonly.id, readonly etc.
for (let key in ctx.query) {
if (key.includes("owners") || key.includes("readonly")) {
delete ctx.query[key];
}
}
if (_.has(ctx, 'params.id') || _.has(ctx, 'params._where.id') || _.has(ctx, 'query.id')) {
// allow to pull single binder if private is false
ctx.query = Object.assign({
_where: {
_or: [{
'owners_in': id
}, {
'readonly': id
}, {
'private': false
}]
}
}, ctx.query);
} else {
// Reset owners to current user
ctx.query = Object.assign({
_where: {
_or: [{
'owners_in': id
}, {
'readonly': id
}]
}
}, ctx.query);
}
//console.log("GRAPHQL PARAMS", JSON.stringify(ctx.params));
//console.log("GRAPHQL QUERRY", JSON.stringify(ctx.query));
}
// [update, delete] Check owner of an existing entity
if ((ctx.request.method === 'DELETE' || ctx.request.method === 'PUT') && typeof ctx.params !== "undefined" && ctx.params !== null && typeof ctx.params.id !== "undefined" && ctx.params.id !== null && ctx.params.id !== '') {
// Extract model name from request path eg. /messages/15
let path = ctx.request.path;
var modelName = path.split("/");
if (Array.isArray(modelName) === false || modelName.length < 2 || modelName[1] === '') {
//console.log("isOwners: ctx.request.path", ctx.request.path, modelName)
return ctx.unauthorized(`isOwners: Invalid request ${ctx.request.path}`);
}
// Get existing entity and check for ownership
let existingEntity = await strapi.query(pluralize.singular(modelName[1])).findOne({
id: ctx.params.id
});
if (typeof existingEntity === "undefined" || existingEntity === null) {
return ctx.notFound('Not Found');
}
let isAnOwner = _.find(existingEntity.owners, {
id: id.toString()
});
if (!isAnOwner) {
return ctx.unauthorized(`${errMsg} [2]`);
}
// append owner to current owners
let owners = [id.toString()];
owners = _.uniqWith(_.union(owners, existingEntity.owners.map(item => item.id)), compareIDs);
ctx.request.body.owners = owners;
}
// [create] Set owner for a new entity
if (!ctx.request.url.startsWith("/graphql") && ctx.request.method === 'POST') {
ctx.request.body.owners = [id.toString()];
}
await next();
}
} catch (error) {
strapi.plugins.sentry.services.sentry.sendError(error);
console.log("error", error);
return ctx.unauthorized(error);
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment