-
Notifications
You must be signed in to change notification settings - Fork 10.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[NEW] Granular permissions for settings #8942
Changes from 26 commits
eed869a
28b769b
8523456
c87a30d
48b1076
daccad8
00e4bb5
9b71b62
293ad73
8f59f1c
8d923c2
a7fdc87
f007231
47d8749
c706dd4
f26246b
cd336fe
c7d7145
4108b7a
02c0160
71beed0
642e3b3
d302fb5
2a0627b
d75b360
200902d
b138793
b2e901a
b94cb37
5c73a9e
a1a0153
e8e8704
a39f732
5397e75
cdbf318
57d8f3e
d59d490
d5a931c
6e778c3
ddd5606
b80e1ec
34d51a4
9a18fcc
a55afb4
93a0464
59e2aab
8419341
7870cd6
d238b7a
f2e8ada
0858217
b09fd79
bb2af49
3808a30
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#!/bin/bash | ||
tmpPath=tests/end-to-end/temporary_staged_test | ||
stopfile=`find ${tmpPath} -type f | head -1` | ||
echo 'Last stop at:' $stopfile | ||
[ -z "$RETRY_TESTS" ] && RETRY_TESTS=1 | ||
stopfile=`find ${tmpPath} -type f | head -1` | ||
array=(`find tests/end-to-end/*/*.js -type f`) | ||
|
||
for j in ${!array[@]}; do | ||
file=${array[$j]} | ||
[[ ${stopfile##*/} == ${file##*/} ]] && [[ $stopfile != $file ]] && break | ||
done | ||
|
||
rm -rf $tmpPath | ||
mkdir -p $tmpPath | ||
for file in ${array[@]:$j}; do | ||
failed=1 | ||
for i in `seq 1 $RETRY_TESTS`; do | ||
echo '-------------- '$i' try ---------------' | ||
set -x | ||
cp $file $tmpPath | ||
CHIMP_PATH=$tmpPath npm run chimp-path | ||
failed=$? | ||
set +x | ||
if [ $failed -eq 0 ]; then | ||
break | ||
fi | ||
done | ||
if [ $failed -ne 0 ]; then | ||
exit 1 | ||
fi | ||
rm $tmpPath/${file##*/} | ||
done |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
#!/bin/bash | ||
tmpPath=tests/end-to-end/temporary_staged_test | ||
rm -rf $tmpPath | ||
mkdir -p $tmpPath | ||
[ -z "$RETRY_TESTS" ] && RETRY_TESTS=1 | ||
for file in tests/end-to-end/*/*.js; do | ||
failed=1 | ||
for i in `seq 1 $RETRY_TESTS`; do | ||
echo '-------------- '$i' try ---------------' | ||
set -x | ||
cp $file $tmpPath | ||
CHIMP_PATH=$tmpPath npm run chimp-path | ||
failed=$? | ||
set +x | ||
if [ $failed -eq 0 ]; then | ||
break | ||
fi | ||
done | ||
if [ $failed -ne 0 ]; then | ||
exit 1 | ||
fi | ||
rm $tmpPath/${file##*/} | ||
done | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,77 @@ | ||
<template name="permissionsTable"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Created a template for the table as both permission tables follow the same scheme. |
||
<table border="1" class="permission-grid secondary-background-color"> | ||
<thead class="content-background-color"> | ||
<tr> | ||
<th class="border-component-color"> </th> | ||
{{#each role in allRoles}} | ||
<th class="border-component-color" title="{{role.description}}"> | ||
<a href="{{pathFor "admin-permissions-edit" name=role._id}}"> | ||
{{role._id}} | ||
<i class="icon-edit"></i> | ||
</a> | ||
</th> | ||
{{/each}} | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{{#each permission in permissions}} | ||
<tr class="admin-table-row"> | ||
<td class="permission-name border-component-color" | ||
title="{{permissionDescription permission}}">{{permissionName permission}}<br>[{{permission._id}}] | ||
</td> | ||
{{#each role in allRoles}} | ||
<td class="border-component-color"> | ||
<input type="checkbox" name="perm[{{role._id}}][{{permission._id}}]" class="role-permission" | ||
value="1" checked="{{granted permission.roles role}}" data-role="{{role._id}}" | ||
data-permission="{{permission._id}}"> | ||
</td> | ||
{{/each}} | ||
</tr> | ||
{{/each}} | ||
</tbody> | ||
</table> | ||
</template> | ||
<template name="permissions"> | ||
<div class="permissions-manager"> | ||
{{#if hasPermission}} | ||
<a href="{{pathFor "admin-permissions-new"}}" class="button primary new-role">{{_ "New_role"}}</a> | ||
<table border="1" class="permission-grid secondary-background-color"> | ||
<thead class="content-background-color"> | ||
<tr> | ||
<th class="border-component-color"> </th> | ||
{{#each role}} | ||
<th class="border-component-color" title="{{description}}"> | ||
<a href="{{pathFor "admin-permissions-edit" name=_id}}"> | ||
{{_id}} | ||
<i class="icon-edit"></i> | ||
</a> | ||
</th> | ||
{{/each}} | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{{#each permission}} | ||
<tr class="admin-table-row"> | ||
<td class="permission-name border-component-color" title="{{_ permissionDescription}}">{{_ permissionName}}<br>[{{_id}}]</td> | ||
{{#each role}} | ||
<td class="border-component-color"> | ||
<input type="checkbox" name="perm[{{_id}}][{{../_id}}]" class="role-permission" value="1" checked="{{granted ../roles}}" data-role="{{_id}}" data-permission="{{../_id}}"> | ||
</td> | ||
{{/each}} | ||
</tr> | ||
{{/each}} | ||
</tbody> | ||
</table> | ||
{{else}} | ||
{{_ "Not_authorized"}} | ||
{{/if}} | ||
</div> | ||
<section class="page-settings"> | ||
<div class="permissions-manager"> | ||
{{#if hasPermission}} | ||
<a href="{{pathFor "admin-permissions-new"}}" class="button primary new-role">{{_ "New_role"}}</a> | ||
<div class="rocket-form"> | ||
<div class="section"> | ||
{{> permissionsTable permissions=permissions allRoles=roles collection='Chat'}} | ||
</div> | ||
</div> | ||
{{/if}} | ||
{{#if hasSettingPermission}} | ||
<div class="rocket-form"> | ||
<div class="section {{#unless settingPermissionExpanded}}section-collapsed{{/unless}}"> | ||
<div class="section-title"> | ||
<div class="section-title-text"> | ||
{{_ "Setting_permissions"}}</div> | ||
<div class="section-title-right"> | ||
<button class="button primary js-toggle-setting-permissions"><span> | ||
{{#if settingPermissionExpanded }} | ||
{{_ "Collapse"}} | ||
{{else}} | ||
{{_ "Expand"}} | ||
{{/if}} | ||
</span> | ||
</button> | ||
</div> | ||
</div> | ||
<div class="section-content border-component-color"> | ||
{{#if settingPermissionExpanded }} | ||
{{> permissionsTable permissions=settingPermissions allRoles=roles collection='Setting'}} | ||
{{else}} | ||
{{_ "Not_authorized"}} | ||
{{/if}} | ||
</div> | ||
</div> | ||
</div> | ||
{{/if}} | ||
{{#if hasNoPermission}} | ||
{{_ "Not_authorized"}} | ||
{{/if}} | ||
</div> | ||
</section> | ||
</template> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,129 @@ | ||
/* globals ChatPermissions */ | ||
import { permissionLevel } from '../../lib/rocketchat'; | ||
|
||
const whereNotSetting = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
$where: function() { | ||
return this.level !== permissionLevel.SETTING; | ||
}.toString(), | ||
}; | ||
|
||
Template.permissions.helpers({ | ||
role() { | ||
roles() { | ||
return Template.instance().roles.get(); | ||
}, | ||
|
||
permission() { | ||
return ChatPermissions.find({}, { | ||
sort: { | ||
_id: 1, | ||
permissions() { | ||
return ChatPermissions.find(whereNotSetting, // the $where seems to have no effect - filtered as workaround after fetch() | ||
{ | ||
sort: { | ||
_id: 1, | ||
}, | ||
}).fetch() | ||
.filter((setting) => !setting.level); | ||
}, | ||
|
||
settingPermissions() { | ||
return ChatPermissions.find({ | ||
level: permissionLevel.SETTING, | ||
}, | ||
{ | ||
sort: { // sorting seems not to be copied from the publication, we need to request it explicitly in find() | ||
group: 1, | ||
section: 1, | ||
}, | ||
}); | ||
}).fetch() | ||
.filter((setting) => setting.group); // group permissions are assigned implicitly, we can hide them. $exists: {group:false} not supported by Minimongo | ||
}, | ||
|
||
hasPermission() { | ||
return RocketChat.authz.hasAllPermission('access-permissions'); | ||
}, | ||
|
||
hasSettingPermission() { | ||
return RocketChat.authz.hasAllPermission('access-setting-permissions'); | ||
}, | ||
|
||
hasNoPermission() { | ||
return !RocketChat.authz.hasAtLeastOnePermission(['access-permissions', 'access-setting-permissions']); | ||
}, | ||
|
||
granted(roles) { | ||
settingPermissionExpanded() { | ||
return Template.instance().settingPermissionsExpanded.get(); | ||
}, | ||
}); | ||
|
||
Template.permissions.events({ | ||
'click .js-toggle-setting-permissions'(event, instance) { | ||
instance.settingPermissionsExpanded.set(!instance.settingPermissionsExpanded.get()); | ||
}, | ||
}); | ||
|
||
Template.permissions.onCreated(function() { | ||
this.settingPermissionsExpanded = new ReactiveVar(false); | ||
this.roles = new ReactiveVar([]); | ||
|
||
Tracker.autorun(() => { | ||
this.roles.set(RocketChat.models.Roles.find().fetch()); | ||
}); | ||
}); | ||
|
||
Template.permissionsTable.helpers({ | ||
granted(roles, role) { | ||
if (roles) { | ||
if (roles.indexOf(this._id) !== -1) { | ||
if (roles.indexOf(role._id) !== -1) { | ||
return 'checked'; | ||
} | ||
} | ||
}, | ||
|
||
permissionName() { | ||
return `${ this._id }`; | ||
permissionName(permission) { | ||
if (permission.level === permissionLevel.SETTING) { | ||
let path = ''; | ||
if (permission.group) { | ||
path = `${ t(permission.group) } > `; | ||
} | ||
if (permission.section) { | ||
path = `${ path }${ t(permission.section) } > `; | ||
} | ||
path = `${ path }${ t(permission.settingId) }`; | ||
return path; | ||
} else { | ||
return t(permission._id); | ||
} | ||
}, | ||
|
||
permissionDescription() { | ||
return `${ this._id }_description`; | ||
permissionDescription(permission) { | ||
return t(`${ permission._id }_description`); | ||
}, | ||
|
||
hasPermission() { | ||
return RocketChat.authz.hasAllPermission('access-permissions'); | ||
}, | ||
}); | ||
|
||
Template.permissions.events({ | ||
Template.permissionsTable.events({ | ||
'click .role-permission'(e, instance) { | ||
const permission = e.currentTarget.getAttribute('data-permission'); | ||
const role = e.currentTarget.getAttribute('data-role'); | ||
|
||
if (instance.permissionByRole[permission].indexOf(role) === -1) { | ||
if (!instance.permissionByRole[permission] // the permissino has this role not assigned at all (undefined) | ||
|| instance.permissionByRole[permission].indexOf(role) === -1) { | ||
return Meteor.call('authorization:addPermissionToRole', permission, role); | ||
} else { | ||
return Meteor.call('authorization:removeRoleFromPermission', permission, role); | ||
} | ||
}, | ||
}); | ||
|
||
Template.permissions.onCreated(function() { | ||
this.roles = new ReactiveVar([]); | ||
Template.permissionsTable.onCreated(function() { | ||
this.permissionByRole = {}; | ||
this.actions = { | ||
added: {}, | ||
removed: {}, | ||
}; | ||
|
||
Tracker.autorun(() => { | ||
this.roles.set(RocketChat.models.Roles.find().fetch()); | ||
}); | ||
|
||
Tracker.autorun(() => { | ||
ChatPermissions.find().observeChanges({ | ||
const observer = { | ||
added: (id, fields) => { | ||
this.permissionByRole[id] = fields.roles; | ||
}, | ||
|
@@ -70,6 +133,14 @@ Template.permissions.onCreated(function() { | |
removed: (id) => { | ||
delete this.permissionByRole[id]; | ||
}, | ||
}); | ||
}; | ||
if (this.data.collection === 'Chat') { | ||
ChatPermissions.find(whereNotSetting).observeChanges(observer); | ||
} | ||
|
||
if (this.data.collection === 'Setting') { | ||
ChatPermissions.find({ level: permissionLevel.SETTING }).observeChanges(observer); | ||
} | ||
}); | ||
}); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,5 @@ | ||
RocketChat.authz = {}; | ||
|
||
export const permissionLevel = { | ||
SETTING: 'setting', | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this change in testing should be in a different PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course it could be. I left it in here since it makes it easier to validate the tests added ;-)
But of course, this is useful even without the actual feature