mirror of
https://github.com/grocy/grocy.git
synced 2026-04-06 21:06:15 +02:00
Add UI & API for Permissions, protect "User"-(Api)-Controller with new permissions.
This commit is contained in:
parent
f6c76b6e20
commit
359baa794a
|
|
@ -5,6 +5,10 @@ namespace Grocy\Controllers\Users;
|
|||
abstract class User
|
||||
{
|
||||
const PERMISSION_ADMIN = 'ADMIN';
|
||||
const PERMISSION_CREATE_USER = 'CREATE_USER';
|
||||
const PERMISSION_EDIT_USER = 'EDIT_USER';
|
||||
const PERMISSION_READ_USER = 'READ_USER';
|
||||
const PERMISSION_EDIT_SELF = 'EDIT_SELF';
|
||||
|
||||
public abstract function hasPermission(string $permission): bool;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Controllers\Users\User;
|
||||
|
||||
class UsersApiController extends BaseApiController
|
||||
{
|
||||
public function __construct(\DI\Container $container)
|
||||
|
|
@ -11,7 +13,8 @@ class UsersApiController extends BaseApiController
|
|||
|
||||
public function GetUsers(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
User::checkPermission($request, User::PERMISSION_READ_USER);
|
||||
try
|
||||
{
|
||||
return $this->ApiResponse($response, $this->getUsersService()->GetUsersAsDto());
|
||||
}
|
||||
|
|
@ -23,6 +26,7 @@ class UsersApiController extends BaseApiController
|
|||
|
||||
public function CreateUser(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
User::checkPermission($request, User::PERMISSION_CREATE_USER);
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
try
|
||||
|
|
@ -43,7 +47,8 @@ class UsersApiController extends BaseApiController
|
|||
|
||||
public function DeleteUser(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
User::checkPermission($request, User::PERMISSION_EDIT_USER);
|
||||
try
|
||||
{
|
||||
$this->getUsersService()->DeleteUser($args['userId']);
|
||||
return $this->EmptyApiResponse($response);
|
||||
|
|
@ -56,7 +61,12 @@ class UsersApiController extends BaseApiController
|
|||
|
||||
public function EditUser(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
if ($args['userId'] == GROCY_USER_ID) {
|
||||
User::checkPermission($request, User::PERMISSION_EDIT_SELF);
|
||||
} else {
|
||||
User::checkPermission($request, User::PERMISSION_EDIT_USER);
|
||||
}
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -108,4 +118,66 @@ class UsersApiController extends BaseApiController
|
|||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function AddPermission(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try {
|
||||
User::checkPermission($request, User::PERMISSION_ADMIN);
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
$this->getDatabase()->user_permissions()->createRow(array(
|
||||
'user_id' => $args['userId'],
|
||||
'permission_id' => $requestBody['permission_id'],
|
||||
))->save();
|
||||
return $this->EmptyApiResponse($response);
|
||||
} catch (\Slim\Exception\HttpSpecializedException $ex) {
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage(), $ex->getCode());
|
||||
} catch (\Exception $ex) {
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function ListPermissions(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try {
|
||||
User::checkPermission($request, User::PERMISSION_ADMIN);
|
||||
|
||||
return $this->ApiResponse($response,
|
||||
$this->getDatabase()->user_permissions()->where($args['userId'])
|
||||
);
|
||||
} catch (\Slim\Exception\HttpSpecializedException $ex) {
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage(), $ex->getCode());
|
||||
} catch (\Exception $ex) {
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function SetPermissions(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try {
|
||||
User::checkPermission($request, User::PERMISSION_ADMIN);
|
||||
$requestBody = $request->getParsedBody();
|
||||
$db = $this->getDatabase();
|
||||
$db->user_permissions()
|
||||
->where('user_id', $args['userId'])
|
||||
->delete();
|
||||
|
||||
$perms = [];
|
||||
|
||||
foreach ($requestBody['permissions'] as $perm_id) {
|
||||
$perms[] = array(
|
||||
'user_id' => $args['userId'],
|
||||
'permission_id' => $perm_id
|
||||
);
|
||||
}
|
||||
|
||||
$db->insert('user_permissions', $perms, 'batch');
|
||||
|
||||
return $this->EmptyApiResponse($response);
|
||||
} catch (\Slim\Exception\HttpSpecializedException $ex) {
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage(), $ex->getCode());
|
||||
} catch (\Exception $ex) {
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@
|
|||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Controllers\Users\User;
|
||||
|
||||
class UsersController extends BaseController
|
||||
{
|
||||
public function UsersList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
return $this->renderPage($response, 'users', [
|
||||
User::checkPermission($request, User::PERMISSION_READ_USER);
|
||||
return $this->renderPage($response, 'users', [
|
||||
'users' => $this->getDatabase()->users()->orderBy('username')
|
||||
]);
|
||||
}
|
||||
|
|
@ -15,16 +18,30 @@ class UsersController extends BaseController
|
|||
{
|
||||
if ($args['userId'] == 'new')
|
||||
{
|
||||
return $this->renderPage($response, 'userform', [
|
||||
User::checkPermission($request, User::PERMISSION_CREATE_USER);
|
||||
return $this->renderPage($response, 'userform', [
|
||||
'mode' => 'create'
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->renderPage($response, 'userform', [
|
||||
if($args['userId'] == GROCY_USER_ID)
|
||||
User::checkPermission($request, User::PERMISSION_EDIT_SELF);
|
||||
else User::checkPermission($request, User::PERMISSION_EDIT_USER);
|
||||
return $this->renderPage($response, 'userform', [
|
||||
'user' => $this->getDatabase()->users($args['userId']),
|
||||
'mode' => 'edit'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function PermissionList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
User::checkPermission($request, User::PERMISSION_READ_USER);
|
||||
return $this->renderPage($response, 'permissions', [
|
||||
'user' => $this->getDatabase()->users($args['userId']),
|
||||
'permissions' => $this->getDatabase()->uihelper_permission()
|
||||
->where('parent IS NULL')->where('user_id', $args['userId']),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,4 +58,15 @@ SELECT ph.id AS id,
|
|||
) AS has_permission,
|
||||
ph.parent AS parent
|
||||
FROM users u,
|
||||
permission_hierarchy ph;
|
||||
permission_hierarchy ph;
|
||||
|
||||
|
||||
INSERT INTO permission_hierarchy(name, parent)
|
||||
VALUES ('CREATE_USER', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN'));
|
||||
|
||||
INSERT INTO permission_hierarchy(name, parent)
|
||||
VALUES ('EDIT_USER', last_insert_rowid());
|
||||
|
||||
INSERT INTO permission_hierarchy(name, parent)
|
||||
VALUES ('READ_USER', last_insert_rowid()),
|
||||
('EDIT_SELF', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN'));
|
||||
41
public/viewjs/permissions.js
Normal file
41
public/viewjs/permissions.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
$('input.permission-cb').click(
|
||||
function () {
|
||||
check_hierachy(this.checked, this.name);
|
||||
}
|
||||
);
|
||||
|
||||
function check_hierachy(checked, name) {
|
||||
var disabled = checked;
|
||||
$('#permission-sub-' + name).find('input.permission-cb')
|
||||
.prop('checked', disabled)
|
||||
.attr('disabled', disabled);
|
||||
}
|
||||
|
||||
$('#permission-save').click(
|
||||
function () {
|
||||
var permission_list = $('input.permission-cb')
|
||||
.filter(function () {
|
||||
return $(this).prop('checked') && !$(this).attr('disabled');
|
||||
}).map(function () {
|
||||
return $(this).data('perm-id');
|
||||
}).toArray();
|
||||
Grocy.Api.Put('users/' + edited_user_id + '/permissions', {
|
||||
'permissions': permission_list,
|
||||
}, function (result) {
|
||||
toastr.success(__t("Permissions saved!"));
|
||||
}, function (xhr) {
|
||||
toastr.error(__t(JSON.parse(xhr.response).error_message));
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
if (edited_user_id == Grocy.UserId) {
|
||||
$('input.permission-cb[name=ADMIN]').click(function () {
|
||||
if (!this.checked) {
|
||||
if (!confirm(__t('Are you sure you want to stop being an ADMIN?'))) {
|
||||
this.checked = true;
|
||||
check_hierachy(this.checked, this.name);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
11
routes.php
11
routes.php
|
|
@ -34,7 +34,10 @@ $app->group('', function(RouteCollectorProxy $group)
|
|||
$group->get('/users', '\Grocy\Controllers\UsersController:UsersList');
|
||||
$group->get('/user/{userId}', '\Grocy\Controllers\UsersController:UserEditForm');
|
||||
|
||||
// Stock routes
|
||||
$group->get('/user/permissions/{userId}', '\Grocy\Controllers\UsersController:PermissionList');
|
||||
|
||||
|
||||
// Stock routes
|
||||
if (GROCY_FEATURE_FLAG_STOCK)
|
||||
{
|
||||
$group->get('/stockoverview', '\Grocy\Controllers\StockController:Overview');
|
||||
|
|
@ -169,7 +172,11 @@ $app->group('/api', function(RouteCollectorProxy $group)
|
|||
$group->put('/users/{userId}', '\Grocy\Controllers\UsersApiController:EditUser');
|
||||
$group->delete('/users/{userId}', '\Grocy\Controllers\UsersApiController:DeleteUser');
|
||||
|
||||
// User
|
||||
$group->get('/users/{userId}/permissions', '\Grocy\Controllers\UsersApiController:ListPermissions');
|
||||
$group->post('/users/{userId}/permissions', '\Grocy\Controllers\UsersApiController:AddPermission');
|
||||
$group->put('/users/{userId}/permissions', '\Grocy\Controllers\UsersApiController:SetPermissions');
|
||||
|
||||
// User
|
||||
$group->get('/user/settings', '\Grocy\Controllers\UsersApiController:GetUserSettings');
|
||||
$group->get('/user/settings/{settingKey}', '\Grocy\Controllers\UsersApiController:GetUserSetting');
|
||||
$group->put('/user/settings/{settingKey}', '\Grocy\Controllers\UsersApiController:SetUserSetting');
|
||||
|
|
|
|||
15
views/components/permission_select.blade.php
Normal file
15
views/components/permission_select.blade.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<label>
|
||||
<input type="checkbox" name="{{ $perm->permission_name }}" class="permission-cb" data-perm-id="{{ $perm->permission_id }}" @if($perm->has_permission) checked @endif>
|
||||
{{ $__t($perm->permission_name) }}
|
||||
</label>
|
||||
<div id="permission-sub-{{ $perm->permission_name }}">
|
||||
<ul>
|
||||
@foreach($perm->uihelper_permissionList(array('user_id' => $user->id))->via('parent') as $p)
|
||||
<li>
|
||||
@include('components.permission_select', array(
|
||||
'perm' => $p
|
||||
))
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
33
views/permissions.blade.php
Normal file
33
views/permissions.blade.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
@extends('layout.default')
|
||||
|
||||
@section('title', $__t('Permissions of %s', GetUserDisplayName($user)))
|
||||
@section('activeNav', '')
|
||||
@section('viewJsName', 'permissions')
|
||||
@push('pageScripts')
|
||||
<script>
|
||||
var edited_user_id = {{ $user->id }};
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h2 class="title">@yield('title')</h2>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div>
|
||||
<ul>
|
||||
@foreach($permissions as $perm)
|
||||
<li>
|
||||
@include('components.permission_select', array(
|
||||
'permission' => $perm
|
||||
))
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
<button id="permission-save" class="btn btn-success" type="submit">{{ $__t('Save') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -47,6 +47,9 @@
|
|||
<a class="btn btn-info btn-sm" href="{{ $U('/user/') }}{{ $user->id }}">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<a class="btn btn-info btn-sm" href="{{ $U('/user/permissions/') }}{{ $user->id }}">
|
||||
<i class="fas fa-lock"></i>
|
||||
</a>
|
||||
<a class="btn btn-danger btn-sm user-delete-button @if($user->id == GROCY_USER_ID) disabled @endif" href="#" data-user-id="{{ $user->id }}" data-user-username="{{ $user->username }}">
|
||||
<i class="fas fa-trash"></i>
|
||||
</a>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user