Make permissions matrix reusable
This commit is contained in:
parent
fc119ecd98
commit
c66a1991d8
9 changed files with 132 additions and 88 deletions
|
@ -284,9 +284,22 @@ App::get('/console/databases/collection')
|
|||
])
|
||||
;
|
||||
|
||||
$permissions = new View(__DIR__ . '/../../views/console/comps/permissions-matrix.phtml');
|
||||
$permissions
|
||||
->setParam('method', 'databases.getCollection')
|
||||
->setParam('events', 'load,databases.updateCollection')
|
||||
->setParam('data', 'project-collection')
|
||||
->setParam('params', [
|
||||
'collection-id' => '{{router.params.id}}',
|
||||
'database-id' => '{{router.params.databaseId}}'
|
||||
]);
|
||||
|
||||
$page = new View(__DIR__ . '/../../views/console/databases/collection.phtml');
|
||||
|
||||
$page->setParam('logs', $logs);
|
||||
$page
|
||||
->setParam('permissions', $permissions)
|
||||
->setParam('logs', $logs)
|
||||
;
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME . ' - Database Collection')
|
||||
|
|
102
app/views/console/comps/permissions-matrix.phtml
Normal file
102
app/views/console/comps/permissions-matrix.phtml
Normal file
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
|
||||
use Utopia\Database\Database;
|
||||
|
||||
$method = $this->getParam('method', '');
|
||||
$params = $this->getParam('params', []);
|
||||
$events = $this->getParam('events', '');
|
||||
$data = $this->getParam('data', '');
|
||||
$permissions = $this->getParam('permissions', Database::PERMISSIONS);
|
||||
|
||||
$escapedPermissions = \array_map(function ($perm) {
|
||||
// Alpine won't bind to a parameter named delete :/
|
||||
if ($perm == 'delete') {
|
||||
return 'xdelete';
|
||||
}
|
||||
return $perm;
|
||||
}, $permissions);
|
||||
|
||||
?>
|
||||
<div
|
||||
<?php if ($method): ?>
|
||||
data-method="<?php echo $method; ?>"
|
||||
<?php endif; ?>
|
||||
<?php foreach ($params as $key => $value): ?>
|
||||
data-param-<?php echo $key; ?>="<?php echo $value; ?>"
|
||||
<?php endforeach; ?>
|
||||
data-scope="sdk"
|
||||
data-event="load<?php if (!empty($events)) echo ',' . $events; ?>"
|
||||
data-name="<?php echo $data; ?>"
|
||||
class="permissions-matrix margin-bottom-large"
|
||||
x-data="permissionsMatrix">
|
||||
|
||||
<input
|
||||
type="hidden"
|
||||
name="permissions"
|
||||
data-cast-from="csv"
|
||||
data-cast-to="array"
|
||||
data-ls-bind="{{<?php echo $data ?>.$permissions}}"
|
||||
:value="rawPermissions"/>
|
||||
|
||||
<table data-ls-attrs="x-init=load({{<?php echo $data ?>.$permissions}})">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Role</th>
|
||||
<?php foreach ($permissions as $permission): ?>
|
||||
<th><?php echo \ucfirst($permission); ?></th>
|
||||
<?php endforeach; ?>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template x-for="(permission, index) in permissions">
|
||||
<tr>
|
||||
<td>
|
||||
<p x-text="permission.role"></p>
|
||||
</td>
|
||||
<?php foreach ($escapedPermissions as $permission): ?>
|
||||
<td>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="<?php echo $permission ?>"
|
||||
x-model="permission.<?php echo $permission; ?>"
|
||||
@click="updatePermission(index)"/>
|
||||
</td>
|
||||
<?php endforeach; ?>
|
||||
<td>
|
||||
<span class="action" @click="removePermission(index)">
|
||||
<i class="icon-trash"></i>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
<tr x-data="permissionsRow"
|
||||
@addrow.window="addPermission(role,<?php echo \implode(',', $escapedPermissions) ?>)">
|
||||
<td>
|
||||
<datalist id="types">
|
||||
<option value="user:">
|
||||
<option value="team:">
|
||||
<option value="users">
|
||||
<option value="guests">
|
||||
<option value="any">
|
||||
</datalist>
|
||||
|
||||
<input required id="role" form="permissions" type="text" name="role" x-model="role" list="types"/>
|
||||
</td>
|
||||
<?php foreach ($escapedPermissions as $permission): ?>
|
||||
<td>
|
||||
<input type="checkbox" name="<?php echo $permission ?>" x-model="<?php echo $permission; ?>"/>
|
||||
</td>
|
||||
<?php endforeach; ?>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<button type="button" class="btn btn-primary margin-top-small" @click="$dispatch('addrow')">Add</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
$logs = $this->getParam('logs', null);
|
||||
$permissions = $this->getParam('permissions', null);
|
||||
|
||||
?>
|
||||
<div
|
||||
|
@ -547,82 +548,7 @@ $logs = $this->getParam('logs', null);
|
|||
|
||||
<hr class="margin-top-small" />
|
||||
|
||||
<div class="permissions-matrix margin-bottom-large" x-data="permissionsMatrix">
|
||||
|
||||
<input type="hidden" name="permissions" data-cast-from="csv" data-cast-to="array" data-ls-bind="{{project-collection.$permissions}}" :value="rawPermissions"/>
|
||||
|
||||
<table data-ls-attrs="x-init=load({{project-collection.$permissions}})">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Role</th>
|
||||
<th>Read</th>
|
||||
<th>Create</th>
|
||||
<th>Update</th>
|
||||
<th>Delete</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template x-for="(permission, index) in permissions">
|
||||
<tr>
|
||||
<td>
|
||||
<p x-text="permission.role"></p>
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="read" x-model="permission.read" @click="updatePermission(index)"/>
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="create" x-model="permission.create" @click="updatePermission(index)"/>
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="update" x-model="permission.update" @click="updatePermission(index)"/>
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="delete" x-model="permission.xdelete" @click="updatePermission(index)"/>
|
||||
</td>
|
||||
<td>
|
||||
<span class="action" @click="removePermission(index)">
|
||||
<i class="icon-trash"></i>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
<tr x-data="permissionsRow" x-on:addrow.window="addPermission(role,read,create,update,xdelete)">
|
||||
<td>
|
||||
<datalist id="types">
|
||||
<option value="user:">
|
||||
<option value="team:">
|
||||
<option value="users">
|
||||
<option value="guests">
|
||||
<option value="any">
|
||||
</datalist>
|
||||
|
||||
<input required id="role" form="permissions" type="text" name="role" x-model="role" list="types" />
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="read" x-model="read" />
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="create" x-model="create"/>
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="update" x-model="update" />
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="delete" x-model="xdelete" />
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<button type="button" class="btn btn-primary margin-top-small" @click="$dispatch('addrow')">Add</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<?php echo $permissions->render(); ?>
|
||||
|
||||
<hr class="margin-top-no" />
|
||||
|
||||
|
|
3
public/dist/scripts/app-all.js
vendored
3
public/dist/scripts/app-all.js
vendored
|
@ -4043,7 +4043,8 @@ this.action=action;},showModal(modal){document.documentElement.classList.add("mo
|
|||
if(this.hasSubSubResource){event+=`.${this.subSubType}.${this.subSubResource ? this.subSubResource : '*'}`;}
|
||||
if(this.action){event+=`.${this.action}`;}
|
||||
if(this.attribute){event+=`.${this.attribute}`;}
|
||||
this.events.add(event);this.reset();},removeEvent(value){this.events.delete(value);}}));});})(window);(function(window){document.addEventListener('alpine:init',()=>{Alpine.data('permissionsMatrix',()=>({permissions:[],rawPermissions:[],load(permissions){this.rawPermissions=permissions;permissions.map(p=>{let{type,role}=this.parsePermission(p);type=this.parseInputPermission(type);let index=-1;let existing=this.permissions.find((p,idx)=>{if(p.role===role){index=idx;return true;}})
|
||||
this.events.add(event);this.reset();},removeEvent(value){this.events.delete(value);}}));});})(window);(function(window){document.addEventListener('alpine:init',()=>{Alpine.data('permissionsMatrix',()=>({permissions:[],rawPermissions:[],load(permissions){if(permissions===undefined){return;}
|
||||
this.rawPermissions=permissions;permissions.map(p=>{let{type,role}=this.parsePermission(p);type=this.parseInputPermission(type);let index=-1;let existing=this.permissions.find((p,idx)=>{if(p.role===role){index=idx;return true;}})
|
||||
if(existing===undefined){this.permissions.push({role,[type]:true,});}
|
||||
if(index!==-1){existing[type]=true;this.permissions[index]=existing;}});},addPermission(role,read,create,update,xdelete){if(!document.getElementById('role').reportValidity())return;if(read)this.rawPermissions.push(`read(${role})`);if(create)this.rawPermissions.push(`create(${role})`);if(update)this.rawPermissions.push(`update(${role})`);if(xdelete)this.rawPermissions.push(`delete(${role})`);this.permissions.push({role,read,create,update,xdelete});this.reset();},updatePermission(index){setTimeout(()=>{const permission=this.permissions[index];for(const key of Object.keys(permission)){if(key==='role'){continue;}
|
||||
const parsedKey=this.parseOutputPermission(key);if(permission[key]){if(!this.rawPermissions.includes(`${parsedKey}(${permission.role})`)){this.rawPermissions.push(`${parsedKey}(${permission.role})`);}}else{this.rawPermissions=this.rawPermissions.filter(p=>{return!p.includes(`${parsedKey}(${permission.role})`);});}}});},removePermission(index){let row=this.permissions.splice(index,1);if(row.length===1){this.rawPermissions=this.rawPermissions.filter(p=>!p.includes(row[0].role));}},parsePermission(permission){let parts=permission.split('(');let type=parts[0];let role=parts[1].replace(')','').replace(' ','');return{type,role};},parseInputPermission(key){if(key==='delete'){return'xdelete';}
|
||||
|
|
3
public/dist/scripts/app.js
vendored
3
public/dist/scripts/app.js
vendored
|
@ -708,7 +708,8 @@ this.action=action;},showModal(modal){document.documentElement.classList.add("mo
|
|||
if(this.hasSubSubResource){event+=`.${this.subSubType}.${this.subSubResource ? this.subSubResource : '*'}`;}
|
||||
if(this.action){event+=`.${this.action}`;}
|
||||
if(this.attribute){event+=`.${this.attribute}`;}
|
||||
this.events.add(event);this.reset();},removeEvent(value){this.events.delete(value);}}));});})(window);(function(window){document.addEventListener('alpine:init',()=>{Alpine.data('permissionsMatrix',()=>({permissions:[],rawPermissions:[],load(permissions){this.rawPermissions=permissions;permissions.map(p=>{let{type,role}=this.parsePermission(p);type=this.parseInputPermission(type);let index=-1;let existing=this.permissions.find((p,idx)=>{if(p.role===role){index=idx;return true;}})
|
||||
this.events.add(event);this.reset();},removeEvent(value){this.events.delete(value);}}));});})(window);(function(window){document.addEventListener('alpine:init',()=>{Alpine.data('permissionsMatrix',()=>({permissions:[],rawPermissions:[],load(permissions){if(permissions===undefined){return;}
|
||||
this.rawPermissions=permissions;permissions.map(p=>{let{type,role}=this.parsePermission(p);type=this.parseInputPermission(type);let index=-1;let existing=this.permissions.find((p,idx)=>{if(p.role===role){index=idx;return true;}})
|
||||
if(existing===undefined){this.permissions.push({role,[type]:true,});}
|
||||
if(index!==-1){existing[type]=true;this.permissions[index]=existing;}});},addPermission(role,read,create,update,xdelete){if(!document.getElementById('role').reportValidity())return;if(read)this.rawPermissions.push(`read(${role})`);if(create)this.rawPermissions.push(`create(${role})`);if(update)this.rawPermissions.push(`update(${role})`);if(xdelete)this.rawPermissions.push(`delete(${role})`);this.permissions.push({role,read,create,update,xdelete});this.reset();},updatePermission(index){setTimeout(()=>{const permission=this.permissions[index];for(const key of Object.keys(permission)){if(key==='role'){continue;}
|
||||
const parsedKey=this.parseOutputPermission(key);if(permission[key]){if(!this.rawPermissions.includes(`${parsedKey}(${permission.role})`)){this.rawPermissions.push(`${parsedKey}(${permission.role})`);}}else{this.rawPermissions=this.rawPermissions.filter(p=>{return!p.includes(`${parsedKey}(${permission.role})`);});}}});},removePermission(index){let row=this.permissions.splice(index,1);if(row.length===1){this.rawPermissions=this.rawPermissions.filter(p=>!p.includes(row[0].role));}},parsePermission(permission){let parts=permission.split('(');let type=parts[0];let role=parts[1].replace(')','').replace(' ','');return{type,role};},parseInputPermission(key){if(key==='delete'){return'xdelete';}
|
||||
|
|
2
public/dist/styles/default-ltr.css
vendored
2
public/dist/styles/default-ltr.css
vendored
File diff suppressed because one or more lines are too long
2
public/dist/styles/default-rtl.css
vendored
2
public/dist/styles/default-rtl.css
vendored
File diff suppressed because one or more lines are too long
|
@ -4,6 +4,10 @@
|
|||
permissions: [],
|
||||
rawPermissions: [],
|
||||
load(permissions) {
|
||||
if (permissions === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.rawPermissions = permissions;
|
||||
|
||||
permissions.map(p => {
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
.permissions-matrix {
|
||||
th:first-child {
|
||||
th:first-child, td:first-child {
|
||||
width: 100px;
|
||||
}
|
||||
th:not(:first-child):not(:last-child) {
|
||||
width: 30px;
|
||||
th:not(:first-child):not(:last-child), td:not(:first-child):not(:last-child) {
|
||||
width: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
th:last-child {
|
||||
th:last-child, td:last-child {
|
||||
width: 20px;
|
||||
}
|
||||
td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
td:not(:first-child) {
|
||||
text-align: center;
|
||||
}
|
||||
input, p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue