11import store from '../config/store'
22import _ from 'lodash'
33
4- export const checkPermission = ( permission , project , entity ) => {
5- const { projectRoles, topcoderRoles, handler} = permission
6- const currentUser = _ . get ( store . getState ( ) , 'loadUser.user' , { } )
7- const roles = currentUser . roles || [ ]
8-
9- if ( project && projectRoles ) {
10- const currentProjectMember = _ . find ( project . members , m => m . userId === currentUser . userId )
11- if ( currentProjectMember ) {
12- const currentUserRole = currentProjectMember . role
13- if ( projectRoles . includes ( currentUserRole ) ) {
14- return true
15- }
16- }
4+ /**
5+ * Check if user has permission.
6+ * (The main permission method which should be used).
7+ *
8+ * This method uses permission defined in `permission`
9+ * and checks that the logged-in user from Redux Store matches it.
10+ *
11+ * `permission` may be defined in two ways:
12+ * - **Full** way with defined `allowRule` and optional `denyRule`, example:
13+ * ```js
14+ * {
15+ * allowRule: {
16+ * projectRoles: [],
17+ * topcoderRoles: []
18+ * },
19+ * denyRule: {
20+ * projectRoles: [],
21+ * topcoderRoles: []
22+ * }
23+ * }
24+ * ```
25+ * If user matches `denyRule` then the access would be dined even if matches `allowRule`.
26+ * - **Simplified** way may be used if we only want to define `allowRule`.
27+ * We can skip the `allowRule` property and define `allowRule` directly inside `permission` object, example:
28+ * ```js
29+ * {
30+ * projectRoles: [],
31+ * topcoderRoles: []
32+ * }
33+ * ```
34+ * This **simplified** permission is equal to a **full** permission:
35+ * ```js
36+ * {
37+ * allowRule: {
38+ * projectRoles: [],
39+ * topcoderRoles: []
40+ * }
41+ * }
42+ * ```
43+ *
44+ * If we define any rule with `projectRoles` list, we also should provide `project`
45+ * with the list of project members in `project.members`.
46+ *
47+ * @param {Object } permissionRule permission rule
48+ * @param {Array<String> } permissionRule.projectRoles the list of project roles of the user
49+ * @param {Array<String> } permissionRule.topcoderRoles the list of Topcoder roles of the user
50+ * @param {Object } [project] project object - required to check `topcoderRoles`
51+ * @param {Array } project.members list of project members - required to check `topcoderRoles`
52+ *
53+ * @returns {Boolean } true, if has permission
54+ */
55+ export const checkPermission = ( permission , project ) => {
56+ const user = _ . get ( store . getState ( ) , 'loadUser.user' , { } )
57+
58+ const allowRule = permission . allowRule ? permission . allowRule : permission
59+ const denyRule = permission . denyRule ? permission . denyRule : null
60+
61+ const allow = matchPermissionRule ( allowRule , user , project )
62+ const deny = matchPermissionRule ( denyRule , user , project )
63+
64+ return allow && ! deny
65+ }
66+
67+ /**
68+ * Check if user match the permission rule.
69+ * (Helper method, most likely wouldn't be used directly).
70+ *
71+ * This method uses permission rule defined in `permissionRule`
72+ * and checks that the `user` matches it.
73+ *
74+ * If we define a rule with `projectRoles` list, we also should provide `projectMembers`
75+ * - the list of project members.
76+ *
77+ * @param {Object } permissionRule permission rule
78+ * @param {Array<String> } permissionRule.projectRoles the list of project roles of the user
79+ * @param {Array<String> } permissionRule.topcoderRoles the list of Topcoder roles of the user
80+ * @param {Object } user user for whom we check permissions
81+ * @param {Object } user.roles list of user roles
82+ * @param {Object } [project] project object - required to check `topcoderRoles`
83+ * @param {Array } project.members list of project members - required to check `topcoderRoles`
84+ *
85+ * @returns {Boolean } true, if has permission
86+ */
87+ const matchPermissionRule = ( permissionRule , user , project ) => {
88+ let hasProjectRole = false
89+ let hasTopcoderRole = false
90+
91+ // if no rule defined, no access by default
92+ if ( ! permissionRule ) {
93+ return false
1794 }
1895
19- if ( topcoderRoles && roles . some ( role => topcoderRoles . indexOf ( role ) !== - 1 ) ) {
20- return true
96+ // check Project Roles
97+ if ( permissionRule . projectRoles
98+ && permissionRule . projectRoles . length > 0
99+ && project
100+ && project . members
101+ ) {
102+ const userId = ! _ . isNumber ( user . userId ) ? parseInt ( user . userId , 10 ) : user . userId
103+ const member = _ . find ( project . members , { userId } )
104+ hasProjectRole = member && _ . includes ( permissionRule . projectRoles , member . role )
21105 }
22106
23- if ( handler && handler ( currentUser , entity , project ) ) {
24- return true
107+ // check Topcoder Roles
108+ if ( permissionRule . topcoderRoles && permissionRule . topcoderRoles . length > 0 ) {
109+ hasTopcoderRole = _ . intersection (
110+ _ . get ( user , 'roles' , [ ] ) . map ( role => role . toLowerCase ( ) ) ,
111+ permissionRule . topcoderRoles . map ( role => role . toLowerCase ( ) )
112+ ) . length > 0
25113 }
26114
27- return false
28- }
115+ return hasProjectRole || hasTopcoderRole
116+ }
0 commit comments