This commit is contained in:
Bernd Bestel 2020-08-29 11:51:49 +02:00
parent 61f6dd4bde
commit 4f31627f8e
No known key found for this signature in database
GPG Key ID: 71BD34C0D4891300
19 changed files with 208 additions and 156 deletions

View File

@ -82,6 +82,11 @@ Setting('DISABLE_BROWSER_BARCODE_CAMERA_SCANNING', false);
# Needs to be a number where Sunday = 0, Monday = 1 and so forth
Setting('MEAL_PLAN_FIRST_DAY_OF_WEEK', '');
# Default permissions for new users
# the array needs to contain the technical/constant names
# see the file controllers/Users/User.php for possible values
Setting('DEFAULT_PERMISSIONS', ['ADMIN']);
# Default user settings
# These settings can be changed per user, here the defaults
@ -172,5 +177,3 @@ Setting('FEATURE_FLAG_CHORES_ASSIGNMENTS', true);
# Feature settings
Setting('FEATURE_SETTING_STOCK_COUNT_OPENED_PRODUCTS_AGAINST_MINIMUM_STOCK_AMOUNT', true); // When set to true opened items will be counted as missing from stock when calculating if a product is below its minimum.
Setting('FEATURE_FLAG_AUTO_TORCH_ON_WITH_CAMERA', true); // Enables the torch automaticaly in every camera barcode scanner.
Setting('DEFAULT_PERMISSIONS', ['ADMIN']);

View File

@ -67,7 +67,10 @@ class BaseController
}
$this->View->set('featureFlags', $constants);
$this->View->set('permissions', User::PermissionList());
if (GROCY_AUTHENTICATED)
{
$this->View->set('permissions', User::PermissionList());
}
return $this->View->render($response, $page, $data);
}

View File

@ -3,7 +3,6 @@
namespace Grocy\Controllers;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Log\LoggerInterface;
use Slim\Exception\HttpException;
@ -44,8 +43,7 @@ class ExceptionController extends BaseApiController
];
if ($displayErrorDetails) {
$data['error_details'] = [
'stack_trace' => $exception->getTrace(),
'previous' => $exception->getPrevious(),
'stack_trace' => $exception->getTraceAsString(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
];
@ -68,4 +66,4 @@ class ExceptionController extends BaseApiController
]);
}
}
}

View File

@ -45,7 +45,7 @@ class User
protected function getPermissions(): Result
{
return $this->db->permission_check()->where('user_id', GROCY_USER_ID);
return $this->db->user_permissions_resolved()->where('user_id', GROCY_USER_ID);
}
public function hasPermission(string $permission): bool
@ -69,7 +69,7 @@ class User
public function getPermissionList()
{
return $this->db->uihelper_permission()->where('user_id', GROCY_USER_ID);
return $this->db->uihelper_user_permissions()->where('user_id', GROCY_USER_ID);
}
public static function hasPermissions(string ...$permissions)
@ -88,7 +88,4 @@ class User
$user = new User();
return $user->getPermissionList();
}
}

View File

@ -38,9 +38,9 @@ class UsersController extends BaseController
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', [
return $this->renderPage($response, 'userpermissions', [
'user' => $this->getDatabase()->users($args['userId']),
'permissions' => $this->getDatabase()->uihelper_permission()
'permissions' => $this->getDatabase()->uihelper_user_permissions()
->where('parent IS NULL')->where('user_id', $args['userId']),
]);
}

View File

@ -1850,20 +1850,44 @@ msgstr ""
msgid "Clear filter"
msgstr ""
msgid "Permissions of %s"
msgid "Permissions for user %s"
msgstr ""
msgid "Are you sure you want to stop being an ADMIN?"
msgstr ""
msgid "Permissions saved!"
msgid "Permissions saved"
msgstr ""
msgid "You are not allowed to view this page!"
msgstr ""
msgid "A server error occured while processing your request. You might found a bug in grocy!"
msgid "You are not allowed to view this page"
msgstr ""
msgid "Page not found"
msgstr ""
msgid "Unauthorized"
msgstr ""
msgid "Error source"
msgstr ""
msgid "Error message"
msgstr ""
msgid "Stack trace"
msgstr ""
msgid "This page does not exists"
msgstr ""
msgid "You will be redirected to the default page in %s seconds"
msgstr ""
msgid "Server error"
msgstr ""
msgid "A server error occured while processing your request"
msgstr ""
msgid "If you think this is a bug, please report it"
msgstr ""

View File

@ -1,100 +1,109 @@
CREATE TABLE user_permissions
(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
permission_id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
UNIQUE (user_id, permission_id)
);
CREATE TABLE permission_hierarchy
(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
name TEXT NOT NULL UNIQUE,
/* if the user has the parent permission,
the user also has the child permission */
parent INTEGER NULL
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
name TEXT NOT NULL UNIQUE,
parent INTEGER NULL -- If the user has the parent permission, the user also has the child permission
);
INSERT INTO permission_hierarchy(name, parent)
VALUES ('ADMIN', NULL);
INSERT INTO user_permissions(permission_id, user_id)
SELECT (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN'), id FROM users;
INSERT INTO permission_hierarchy
(name, parent)
VALUES
('ADMIN', NULL);
INSERT INTO user_permissions
(permission_id, user_id)
SELECT (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN'), id
FROM users;
DROP VIEW IF EXISTS permission_tree;
CREATE VIEW permission_tree
AS
WITH RECURSIVE perm AS (SELECT id AS root, id AS child, name, parent
FROM permission_hierarchy
UNION
SELECT perm.root, ph.id, ph.name, ph.id
FROM permission_hierarchy ph,
perm
WHERE ph.parent = perm.child
WITH RECURSIVE perm AS (
SELECT id AS root, id AS child, name, parent
FROM permission_hierarchy
UNION
SELECT perm.root, ph.id, ph.name, ph.id
FROM permission_hierarchy ph, perm
WHERE ph.parent = perm.child
)
SELECT root AS id, name AS name
FROM perm;
DROP VIEW IF EXISTS permission_check;
CREATE VIEW permission_check
CREATE VIEW user_permissions_resolved
AS
SELECT u.id AS id, -- dummy for LessQL
u.id AS user_id,
pt.name AS permission_name
FROM permission_tree pt,
users u
SELECT
u.id AS id, -- Dummy for LessQL
u.id AS user_id,
pt.name AS permission_name
FROM permission_tree pt, users u
WHERE pt.id IN (SELECT permission_id FROM user_permissions sub_up WHERE sub_up.user_id = u.id);
DROP VIEW IF EXISTS uihelper_permission;
CREATE VIEW uihelper_permission
CREATE VIEW uihelper_user_permissions
AS
SELECT ph.id AS id,
u.id AS user_id,
ph.name AS permission_name,
ph.id AS permission_id,
(ph.name IN
(SELECT pc.permission_name FROM permission_check pc WHERE pc.user_id = u.id)
) AS has_permission,
SELECT
ph.id AS id,
u.id AS user_id,
ph.name AS permission_name,
ph.id AS permission_id,
(ph.name IN (
SELECT pc.permission_name
FROM user_permissions_resolved pc
WHERE pc.user_id = u.id
)
) AS has_permission,
ph.parent AS parent
FROM users u,
permission_hierarchy ph;
FROM users u, 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'));
INSERT INTO permission_hierarchy(name, parent)
INSERT INTO permission_hierarchy
(name, parent)
VALUES
-- Batteries
('BATTERY_UNDO_TRACK_CHARGE_CYCLE', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('BATTERY_TRACK_CHARGE_CYCLE', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
-- Chores
('CHORE_TRACK', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('CHORE_TRACK_OTHERS', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('CHORE_EDIT', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('CHORE_UNDO', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
-- Files
('UPLOAD_FILE', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('DELETE_FILE', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
-- master data
('MASTER_DATA_EDIT', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
-- Tasks
('TASKS_UNDO', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('TASKS_MARK_COMPLETED', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
-- Stock / Products
('STOCK_EDIT', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('STOCK_TRANSFER', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('STOCK_CORRECTION', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('PRODUCT_PURCHASE', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('PRODUCT_CONSUME', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('PRODUCT_OPEN', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
-- shopping list
('SHOPPINGLIST_ITEMS_ADD', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('SHOPPINGLIST_ITEMS_DELETE', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN'));
('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'));
INSERT INTO permission_hierarchy
(name, parent)
VALUES
-- Batteries
('BATTERY_UNDO_TRACK_CHARGE_CYCLE', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('BATTERY_TRACK_CHARGE_CYCLE', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
-- Chores
('CHORE_TRACK', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('CHORE_TRACK_OTHERS', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('CHORE_EDIT', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('CHORE_UNDO', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
-- Files
('UPLOAD_FILE', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('DELETE_FILE', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
-- master data
('MASTER_DATA_EDIT', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
-- Tasks
('TASKS_UNDO', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('TASKS_MARK_COMPLETED', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
-- Stock / Products
('STOCK_EDIT', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('STOCK_TRANSFER', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('STOCK_CORRECTION', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('PRODUCT_PURCHASE', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('PRODUCT_CONSUME', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('PRODUCT_OPEN', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
-- shopping list
('SHOPPINGLIST_ITEMS_ADD', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN')),
('SHOPPINGLIST_ITEMS_DELETE', (SELECT id FROM permission_hierarchy WHERE name = 'ADMIN'));

View File

@ -663,7 +663,7 @@ $.extend(true, $.fn.dataTable.defaults, {
}
});
$(Grocy.Permissions).each(function (index, item)
$(Grocy.UserPermissions).each(function (index, item)
{
if(item.has_permission == 0)
{

View File

@ -19,17 +19,18 @@ $('#permission-save').click(
}).map(function () {
return $(this).data('perm-id');
}).toArray();
Grocy.Api.Put('users/' + edited_user_id + '/permissions', {
Grocy.Api.Put('users/' + Grocy.EditObjectId + '/permissions', {
'permissions': permission_list,
}, function (result) {
toastr.success(__t("Permissions saved!"));
toastr.success(__t("Permissions saved"));
}, function (xhr) {
toastr.error(__t(JSON.parse(xhr.response).error_message));
}
);
}
);
if (edited_user_id == Grocy.UserId) {
if (Grocy.EditObjectId == 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?'))) {

View File

@ -33,9 +33,7 @@ $app->group('', function(RouteCollectorProxy $group)
// User routes
$group->get('/users', '\Grocy\Controllers\UsersController:UsersList');
$group->get('/user/{userId}', '\Grocy\Controllers\UsersController:UserEditForm');
$group->get('/user/permissions/{userId}', '\Grocy\Controllers\UsersController:PermissionList');
$group->get('/user/{userId}/permissions', '\Grocy\Controllers\UsersController:PermissionList');
// Stock routes
if (GROCY_FEATURE_FLAG_STOCK)
@ -171,7 +169,6 @@ $app->group('/api', function(RouteCollectorProxy $group)
$group->post('/users', '\Grocy\Controllers\UsersApiController:CreateUser');
$group->put('/users/{userId}', '\Grocy\Controllers\UsersApiController:EditUser');
$group->delete('/users/{userId}', '\Grocy\Controllers\UsersApiController:DeleteUser');
$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');

View File

@ -4,12 +4,12 @@
</label>
<div id="permission-sub-{{ $perm->permission_name }}">
<ul>
@foreach($perm->uihelper_permissionList(array('user_id' => $user->id))->via('parent') as $p)
@foreach($perm->uihelper_user_permissionsList(array('user_id' => $user->id))->via('parent') as $p)
<li>
@include('components.permission_select', array(
@include('components.userpermission_select', array(
'perm' => $p
))
</li>
@endforeach
</ul>
</div>
</div>

View File

@ -1,11 +1,11 @@
@extends('errors.base')
@section('title', $__t('You are not allowed to view this page!'))
@section('title', $__t('Unauthorized'))
@section('content')
<div class="row">
<div class="col-xs-12 col-md-6 text-center">
<h2 class="title">@yield('title')</h2>
<div class="col">
<div class="alert alert-danger">{{ $__t('You are not allowed to view this page') }}</div>
</div>
</div>
@stop

View File

@ -1,14 +1,13 @@
@extends('errors.base')
@section('title', $__t('Page not found'))
@section('content')
<meta http-equiv="refresh" content="5;url=/">
<meta http-equiv="refresh" content="5;url={{$U('/')}}">
<div class="row">
<div class="col-xs-12 col-md-6">
<h2 class="title">@yield('title')</h2>
<div>
{!! nl2br(e($exception->getTraceAsString())) !!}
</div>
<div class="col">
<div class="alert alert-danger">{{ $__t('This page does not exists') }}</div>
<div>{{ $__t('You will be redirected to the default page in %s seconds', '5') }}</div>
</div>
</div>
@stop

View File

@ -1,3 +1,16 @@
@extends('errors.base')
@section('title', $__t('A server error occured while processing your request. You might found a bug in grocy!'))
@section('title', $__t('Server error'))
@section('content')
<div class="row">
<div class="col">
<div class="alert alert-danger">{{ $__t('A server error occured while processing your request') }}</div>
<div class="alert alert-warning">
{{ $__t('If you think this is a bug, please report it') }}<br>
&rarr; <a target="_blank" href="https://github.com/grocy/grocy/issues">https://github.com/grocy/grocy/issues</a>
</div>
</div>
</div>
@parent
@stop

View File

@ -2,10 +2,18 @@
@section('content')
<div class="row">
<div class="col-xs-12 col-md-6">
<h2 class="title">@yield('title')</h2>
<div class="col">
<div>
{!! nl2br(e($exception->getTraceAsString())) !!}
<h6>{{ $__t('Error source') }}</h6>
<pre><code>{!! $exception->getFile() !!}:{!! $exception->getLine() !!}</code></pre>
</div>
<div>
<h6>{{ $__t('Error message') }}</h6>
<pre><code>{!! $exception->getMessage() !!}</code></pre>
</div>
<div>
<h6>{{ $__t('Stack trace') }}</h6>
<pre><code>{!! $exception->getTraceAsString() !!}</code></pre>
</div>
</div>
</div>

View File

@ -59,11 +59,10 @@
Grocy.GettextPo = {!! $GettextPo !!};
Grocy.FeatureFlags = {!! json_encode($featureFlags) !!};
Grocy.Permissions = {!! json_encode($permissions) !!};
@if (GROCY_AUTHENTICATED)
Grocy.UserSettings = {!! json_encode($userSettings) !!};
Grocy.UserId = {{ GROCY_USER_ID }};
Grocy.UserPermissions = {!! json_encode($permissions) !!};
@else
Grocy.UserSettings = { };
Grocy.UserId = -1;

View File

@ -1,33 +0,0 @@
@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

View File

@ -0,0 +1,34 @@
@extends('layout.default')
@section('title', $__t('Permissions for user %s', GetUserDisplayName($user)))
@section('activeNav', '')
@section('viewJsName', 'userpermissions')
@push('pageScripts')
<script>
Grocy.EditObjectId = {{ $user->id }};
</script>
@endpush
@section('content')
<div class="row">
<div class="col">
<h2 class="title">@yield('title')</h2>
</div>
</div>
<hr>
<div class="row mt-3">
<div class="col">
<ul>
@foreach($permissions as $perm)
<li>
@include('components.userpermission_select', array(
'permission' => $perm
))
</li>
@endforeach
</ul>
<button id="permission-save" class="btn btn-success" type="submit">{{ $__t('Save') }}</button>
</div>
</div>
@endsection

View File

@ -47,7 +47,7 @@
<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 }}">
<a class="btn btn-info btn-sm" href="{{ $U('/user/' . $user->id . '/permissions') }}">
<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 }}">