const { BadRequest, Forbidden } = require('@feathersjs/errors');
const { resolveScope } = require('./util/resolveScope');

const getScope = async (context) => {
	const { scopeName, scopeId } = await resolveScope(context);
	if (scopeName === undefined || scopeId === undefined) {
		throw new BadRequest('Cannot find scope name or scopeId.');
	}
	return { scopeName, scopeId };
};

const getPermissionService = (app, scopeName) => {
	const permissionServicePath = `/${scopeName}/:scopeId/userPermissions`;
	const permissionService = app.service(permissionServicePath);
	if (permissionService === undefined) {
		throw new BadRequest(`There is no userPermission service for the scope '${scopeName}'.`);
	}
	return permissionService;
};

/**
 * Retrieve permissions of a user in a given scope
 * @param {FeathersApp} app Feathers app object
 * @param {ObjectId|String} userId A userId as ObjectId or String
 * @param {Object} scope A scope in the format {id, name}
 * @example
 * await getScopePermissions(app, new ObjectId(), {name: 'teams', id: new ObjectId()}) ==> []
 * await getScopePermissions(app, aRealUserId, {name: 'teams', id: aTeamId}) ==> [
 * 	'FILE_CREATE',
 * 	'TEAM_EDIT',
 * ]
 */
const getScopePermissions = async (app, userId, scope) => {
	const permissionService = getPermissionService(app, scope.name);
	return permissionService.get(userId, {
		route: {
			scopeId: scope.id,
		},
	});
};

/**
 * Resolves the context if the (authenticated) user has the required permissions inside the scope.
 * @param {Array<Permission>} requiredPermissions an array of strings identifying permissions in the scope
 * @requires auth.hooks.authenticate('jwt')
 */
const checkScopePermissions = (requiredPermissions) => async (context) => {
	const { scopeName, scopeId } = await getScope(context);
	const { userId } = context.params.account;
	const userPermissions = await getScopePermissions(context.app, userId, { id: scopeId, name: scopeName });

	if (requiredPermissions.every((permission) => userPermissions.includes(permission))) {
		return context;
	}
	throw new Forbidden(`Missing one of the required permissions ${requiredPermissions}.`, {
		userId, scopeName, scopeId, requiredPermissions,
	});
};

module.exports = {
	getScopePermissions,
	checkScopePermissions,
};

@@ -116,16 +116,238 @@
 ope');%0A%0A
+/**%0A * Returns the name and id for the scope of the requested resource%0A * @param %7BContext%7D context Feathers hook context%0A * @returns %7BObject%7D %7B scopeName, scopeId %7D%0A * @throws %7BBadRequest%7D if the scope cannot be found%0A */%0A
 const ge
@@ -595,16 +595,310 @@
  %7D;%0A%7D;%0A%0A
+/**%0A * Returns the service instance of the user permission service for the given scope%0A * @param %7BFeathersApp%7D app Feathers app object%0A * @param %7BString%7D scopeName scope name%0A * @returns %7BService%7D permissionService%0A * @throws %7BBadRequest%7D if no user permission service exists for the scope%0A */%0A
 const ge
@@ -1925,16 +1925,36 @@
 **%0A * Re
+turns a hook that re
 solves t
@@ -2190,16 +2190,236 @@
 ('jwt')%0A
+ * @returns %7BFunction%7D Hook function: (context) =%3E context%0A * @throws %7BBadRequest%7D if the scope cannot be found or has no user permission service%0A * @throws %7BForbidden%7D if the user does not have the required permissions%0A
  */%0Acons

Update inline docs