Description
During working on the Workstreams we had to check permissions based on allowRule
and denyRule
as was described in this comment #315 (comment). And it was implemented during the challenge in workManagementForTemplate permission middleware.
As we are going to have more and more places where we would have to restrict permissions based on various set of rules and to avoid issues like this one #332 I've moved the logic for checking permissions into general util methods:
matchPermissionRule
hasPermission
hasPermissionForProject
See implementation: https://github.com/topcoder-platform/tc-project-service/blob/dev-next/src/util.js#L596-L748
For proof of concept I've refactored two methods for testing permissions using these general methods:
The most general method is hasPermissionForProject: (permission, user, projectId)
:
projectId
is project id we should check permission foruser
is the user we should check permissions for, usually we would use the current user from the request objectuser = req.authUser
permission
I suggest to be able to define the permission
in two ways:
-
Full when permission is defined with
allowRule
anddenyRule
:{ allowRule: { projectRoles: [], topcoderRoles: [] }, denyRule: { projectRoles: [], topcoderRoles: [] } }
-
Simplified if we don't need
denyRule
we can deifne directly the inner part ofallowRule
without explicit propertyallowRule
:{ projectRoles: [], topcoderRoles: [] }
This simplified permission is equal to a full permission:
{ allowRule: { projectRoles: [], topcoderRoles: [] } }
I guess this should cover most of our needs for permissions checking. And after some time we can refactor exitent code to use these methods instead of reimplementing this logic, for example many of these methods could be rewritten reusing the general methods.
Also, we can create constants with predefined reusable permissions, see example, same like we started to do in Connect app. Eventually, we should end up having the same or similar set of rules in Connect app and Project Service.
So far what I see can be done to improve them:
- Create some way to check that the user is a member of the project with any member role. For now we would have to list all the user roles in
projectRoles
which is too wordy, also when adding a new role we would have to update all permission rules. So far I see two possible ways:- Add new property like
isProjectMember
so the rule would look like:The big disadvantage I see, is that it may be misleading as it could feel that we have to add both propeties{ isProjectMember: true, topcoderRoles: [] }
isProjectMember
andprojectRoles
to check if user is a member and has a particular role. - Another way - is somehow use
projectRoles
property to define all roles at once. Possible ways:projectRoles = []
- empty array, feels like areally bad ideaprojectRoles = true
- booleantrue
is nice, the only small disadvantage I see, the wordtrue
doesn't exmplains what it meansprojectRoels = 'any'
- stringany
, is good that it explains what does it mean, but it feels a little bit "hardcoded". We can introduce a new constantANY = 'any'
, but then we would be required to always import this constant which feels not that comfortable.- Maybe you have any other idea.
- Add new property like
- Optimize method hasPermissionForProject so in case there is not rule to check
projectRoles
we don't have to retrieveprojectMembers
from the DB, to make it faster in such case. - cover these methods with extensive unit tests
- Validate all input params to make sure developer run these methods with the combinations which make sense and provide detailed errors otherwise, in particular but not limited:
- use
Joi
to validate possible shapes ofpermission
to provide detailed feedback to the developer about possible method misusing. - if there is any rule with
projectRoles
we should throw error ifprojectMembers
orprojectId
is not defined.projectMembers
may be still an empty array or evennull
.
- use
- Write wiki documentation on how to use these methods with examples.
@vikasrohit Let me know what you think. If you see any ways we can adjust these methods to cover more cases or to be more comfortable or reliable.