mirror of
https://github.com/grocy/grocy.git
synced 2025-10-12 16:44:55 +00:00
[WIP] Implemented basic permissions (#960)
* Add permissions to Database & add "User"-classes * Add UI & API for Permissions, protect "User"-(Api)-Controller with new permissions. * Add some permissions. * Add permission localization * Add error handling. * Error pages: only redirect on 404 * ExceptionController: return JSON-Response on api-routes * Rename PRODUCT_ADD to PRODUCT_PURCHASE * Move translation to new file * Fix checkboxes stay selected on reload. * Remove configurable User-implementation * Remove MASTER_DATA_READ * Disable buttons the user isn't allowed to use. * Add default permissions for new users * When migration to permissions, everyone starts as ADMIN * Permission-Localization: add to transifex & LocalizationService * Review Co-authored-by: Bernd Bestel <bernd@berrnd.de>
This commit is contained in:
committed by
GitHub
parent
f28697e5b4
commit
b7d1b21f1d
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Controllers\Users\User;
|
||||
use \Grocy\Services\DatabaseService;
|
||||
use \Grocy\Services\ApplicationService;
|
||||
use \Grocy\Services\LocalizationService;
|
||||
@@ -66,6 +67,11 @@ class BaseController
|
||||
}
|
||||
$this->View->set('featureFlags', $constants);
|
||||
|
||||
if (GROCY_AUTHENTICATED)
|
||||
{
|
||||
$this->View->set('permissions', User::PermissionList());
|
||||
}
|
||||
|
||||
return $this->View->render($response, $page, $data);
|
||||
}
|
||||
|
||||
|
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Controllers\Users\User;
|
||||
|
||||
class BatteriesApiController extends BaseApiController
|
||||
{
|
||||
public function __construct(\DI\Container $container)
|
||||
@@ -11,7 +13,9 @@ class BatteriesApiController extends BaseApiController
|
||||
|
||||
public function TrackChargeCycle(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
User::checkPermission($request, User::PERMISSION_BATTERY_TRACK_CHARGE_CYCLE);
|
||||
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -49,7 +53,9 @@ class BatteriesApiController extends BaseApiController
|
||||
|
||||
public function UndoChargeCycle(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
User::checkPermission($request, User::PERMISSION_BATTERY_UNDO_TRACK_CHARGE_CYCLE);
|
||||
|
||||
try
|
||||
{
|
||||
$this->ApiResponse($response, $this->getBatteriesService()->UndoChargeCycle($args['chargeCycleId']));
|
||||
return $this->EmptyApiResponse($response);
|
||||
|
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Controllers\Users\User;
|
||||
|
||||
class ChoresApiController extends BaseApiController
|
||||
{
|
||||
public function __construct(\DI\Container $container)
|
||||
@@ -15,7 +17,9 @@ class ChoresApiController extends BaseApiController
|
||||
|
||||
try
|
||||
{
|
||||
$trackedTime = date('Y-m-d H:i:s');
|
||||
User::checkPermission($request, User::PERMISSION_CHORE_TRACK);
|
||||
|
||||
$trackedTime = date('Y-m-d H:i:s');
|
||||
if (array_key_exists('tracked_time', $requestBody) && (IsIsoDateTime($requestBody['tracked_time']) || IsIsoDate($requestBody['tracked_time'])))
|
||||
{
|
||||
$trackedTime = $requestBody['tracked_time'];
|
||||
@@ -26,6 +30,8 @@ class ChoresApiController extends BaseApiController
|
||||
{
|
||||
$doneBy = $requestBody['done_by'];
|
||||
}
|
||||
if($doneBy != GROCY_USER_ID)
|
||||
User::checkPermission($request, User::PERMISSION_CHORE_TRACK_OTHERS);
|
||||
|
||||
$choreExecutionId = $this->getChoresService()->TrackChore($args['choreId'], $trackedTime, $doneBy);
|
||||
return $this->ApiResponse($response, $this->getDatabase()->chores_log($choreExecutionId));
|
||||
@@ -57,7 +63,9 @@ class ChoresApiController extends BaseApiController
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->ApiResponse($response, $this->getChoresService()->UndoChoreExecution($args['executionId']));
|
||||
User::checkPermission($request, User::PERMISSION_CHORE_UNDO);
|
||||
|
||||
$this->ApiResponse($response, $this->getChoresService()->UndoChoreExecution($args['executionId']));
|
||||
return $this->EmptyApiResponse($response);
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
@@ -70,7 +78,9 @@ class ChoresApiController extends BaseApiController
|
||||
{
|
||||
try
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
User::checkPermission($request, User::PERMISSION_CHORE_EDIT);
|
||||
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
$choreId = null;
|
||||
if (array_key_exists('chore_id', $requestBody) && !empty($requestBody['chore_id']) && is_numeric($requestBody['chore_id']))
|
||||
|
69
controllers/ExceptionController.php
Normal file
69
controllers/ExceptionController.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Slim\Exception\HttpException;
|
||||
use Slim\Exception\HttpForbiddenException;
|
||||
use Slim\Exception\HttpNotFoundException;
|
||||
use Throwable;
|
||||
|
||||
class ExceptionController extends BaseApiController
|
||||
{
|
||||
/**
|
||||
* @var \Slim\App
|
||||
*/
|
||||
private $app;
|
||||
|
||||
public function __construct(\Slim\App $app, \DI\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequestInterface $request,
|
||||
Throwable $exception,
|
||||
bool $displayErrorDetails,
|
||||
bool $logErrors,
|
||||
bool $logErrorDetails,
|
||||
?LoggerInterface $logger = null)
|
||||
{
|
||||
$response = $this->app->getResponseFactory()->createResponse();
|
||||
|
||||
$isApiRoute = string_starts_with($request->getUri()->getPath(), '/api/');
|
||||
if ($isApiRoute) {
|
||||
$status = 500;
|
||||
if ($exception instanceof HttpException) {
|
||||
$status = $exception->getCode();
|
||||
}
|
||||
$data = [
|
||||
'error_message' => $exception->getMessage(),
|
||||
];
|
||||
if ($displayErrorDetails) {
|
||||
$data['error_details'] = [
|
||||
'stack_trace' => $exception->getTraceAsString(),
|
||||
'file' => $exception->getFile(),
|
||||
'line' => $exception->getLine(),
|
||||
];
|
||||
}
|
||||
return $this->ApiResponse($response->withStatus($status), $data);
|
||||
}
|
||||
if ($exception instanceof HttpNotFoundException) {
|
||||
return $this->renderPage($response->withStatus(404), 'errors/404', [
|
||||
'exception' => $exception
|
||||
]);
|
||||
}
|
||||
if ($exception instanceof HttpForbiddenException) {
|
||||
return $this->renderPage($response->withStatus(403), 'errors/403', [
|
||||
'exception' => $exception
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->renderPage($response->withStatus(500), 'errors/500', [
|
||||
'exception' => $exception
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Controllers\Users\User;
|
||||
use \Grocy\Services\FilesService;
|
||||
|
||||
class FilesApiController extends BaseApiController
|
||||
@@ -15,7 +16,9 @@ class FilesApiController extends BaseApiController
|
||||
{
|
||||
try
|
||||
{
|
||||
if (IsValidFileName(base64_decode($args['fileName'])))
|
||||
User::checkPermission($request, User::PERMISSION_UPLOAD_FILE);
|
||||
|
||||
if (IsValidFileName(base64_decode($args['fileName'])))
|
||||
{
|
||||
$fileName = base64_decode($args['fileName']);
|
||||
}
|
||||
@@ -97,7 +100,9 @@ class FilesApiController extends BaseApiController
|
||||
{
|
||||
try
|
||||
{
|
||||
if (IsValidFileName(base64_decode($args['fileName'])))
|
||||
User::checkPermission($request, User::PERMISSION_DELETE_FILE);
|
||||
|
||||
if (IsValidFileName(base64_decode($args['fileName'])))
|
||||
{
|
||||
$fileName = base64_decode($args['fileName']);
|
||||
}
|
||||
|
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Controllers\Users\User;
|
||||
|
||||
class GenericEntityApiController extends BaseApiController
|
||||
{
|
||||
public function __construct(\DI\Container $container)
|
||||
@@ -11,7 +13,7 @@ class GenericEntityApiController extends BaseApiController
|
||||
|
||||
public function GetObjects(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$objects = $this->getDatabase()->{$args['entity']}();
|
||||
$objects = $this->getDatabase()->{$args['entity']}();
|
||||
$allUserfields = $this->getUserfieldsService()->GetAllValues($args['entity']);
|
||||
|
||||
foreach ($objects as $object)
|
||||
@@ -41,7 +43,7 @@ class GenericEntityApiController extends BaseApiController
|
||||
|
||||
public function GetObject(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
if ($this->IsValidEntity($args['entity']) && !$this->IsEntityWithPreventedListing($args['entity']))
|
||||
if ($this->IsValidEntity($args['entity']) && !$this->IsEntityWithPreventedListing($args['entity']))
|
||||
{
|
||||
$userfields = $this->getUserfieldsService()->GetValues($args['entity'], $args['objectId']);
|
||||
if (count($userfields) === 0)
|
||||
@@ -66,7 +68,9 @@ class GenericEntityApiController extends BaseApiController
|
||||
|
||||
public function AddObject(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
if ($this->IsValidEntity($args['entity']))
|
||||
User::checkPermission($request, User::PERMISSION_MASTER_DATA_EDIT);
|
||||
|
||||
if ($this->IsValidEntity($args['entity']))
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
@@ -97,7 +101,9 @@ class GenericEntityApiController extends BaseApiController
|
||||
|
||||
public function EditObject(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
if ($this->IsValidEntity($args['entity']))
|
||||
User::checkPermission($request, User::PERMISSION_MASTER_DATA_EDIT);
|
||||
|
||||
if ($this->IsValidEntity($args['entity']))
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
@@ -126,7 +132,9 @@ class GenericEntityApiController extends BaseApiController
|
||||
|
||||
public function DeleteObject(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
if ($this->IsValidEntity($args['entity']))
|
||||
User::checkPermission($request, User::PERMISSION_MASTER_DATA_EDIT);
|
||||
|
||||
if ($this->IsValidEntity($args['entity']))
|
||||
{
|
||||
$row = $this->getDatabase()->{$args['entity']}($args['objectId']);
|
||||
$row->delete();
|
||||
@@ -141,7 +149,8 @@ class GenericEntityApiController extends BaseApiController
|
||||
|
||||
public function SearchObjects(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
if ($this->IsValidEntity($args['entity']) && !$this->IsEntityWithPreventedListing($args['entity']))
|
||||
|
||||
if ($this->IsValidEntity($args['entity']) && !$this->IsEntityWithPreventedListing($args['entity']))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -160,7 +169,7 @@ class GenericEntityApiController extends BaseApiController
|
||||
|
||||
public function GetUserfields(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
return $this->ApiResponse($response, $this->getUserfieldsService()->GetValues($args['entity'], $args['objectId']));
|
||||
}
|
||||
@@ -172,7 +181,9 @@ class GenericEntityApiController extends BaseApiController
|
||||
|
||||
public function SetUserfields(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
User::checkPermission($request, User::PERMISSION_MASTER_DATA_EDIT);
|
||||
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
try
|
||||
{
|
||||
|
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Controllers\Users\User;
|
||||
|
||||
class RecipesApiController extends BaseApiController
|
||||
{
|
||||
public function __construct(\DI\Container $container)
|
||||
@@ -11,7 +13,9 @@ class RecipesApiController extends BaseApiController
|
||||
|
||||
public function AddNotFulfilledProductsToShoppingList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
User::checkPermission($request, User::PERMISSION_SHOPPINGLIST_ITEMS_ADD);
|
||||
|
||||
$requestBody = $request->getParsedBody();
|
||||
$excludedProductIds = null;
|
||||
|
||||
if ($requestBody !== null && array_key_exists('excludedProductIds', $requestBody))
|
||||
@@ -25,7 +29,9 @@ class RecipesApiController extends BaseApiController
|
||||
|
||||
public function ConsumeRecipe(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
User::checkPermission($request, User::PERMISSION_PRODUCT_CONSUME);
|
||||
|
||||
try
|
||||
{
|
||||
$this->getRecipesService()->ConsumeRecipe($args['recipeId']);
|
||||
return $this->EmptyApiResponse($response);
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Controllers\Users\User;
|
||||
use \Grocy\Services\StockService;
|
||||
|
||||
class StockApiController extends BaseApiController
|
||||
@@ -62,7 +63,9 @@ class StockApiController extends BaseApiController
|
||||
|
||||
public function AddProduct(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
User::checkPermission($request, User::PERMISSION_PRODUCT_PURCHASE);
|
||||
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -136,7 +139,9 @@ class StockApiController extends BaseApiController
|
||||
|
||||
public function EditStockEntry(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
User::checkPermission($request, User::PERMISSION_STOCK_EDIT);
|
||||
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -185,7 +190,9 @@ class StockApiController extends BaseApiController
|
||||
|
||||
public function TransferProduct(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
User::checkPermission($request, User::PERMISSION_STOCK_TRANSFER);
|
||||
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -239,7 +246,9 @@ class StockApiController extends BaseApiController
|
||||
|
||||
public function ConsumeProduct(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
User::checkPermission($request, User::PERMISSION_PRODUCT_CONSUME);
|
||||
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
$result = null;
|
||||
|
||||
@@ -310,7 +319,9 @@ class StockApiController extends BaseApiController
|
||||
|
||||
public function InventoryProduct(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
User::checkPermission($request, User::PERMISSION_STOCK_CORRECTION);
|
||||
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -372,7 +383,9 @@ class StockApiController extends BaseApiController
|
||||
|
||||
public function OpenProduct(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
User::checkPermission($request, User::PERMISSION_PRODUCT_OPEN);
|
||||
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -439,7 +452,9 @@ class StockApiController extends BaseApiController
|
||||
|
||||
public function AddMissingProductsToShoppingList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
User::checkPermission($request, User::PERMISSION_SHOPPINGLIST_ITEMS_ADD);
|
||||
|
||||
try
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
@@ -460,7 +475,9 @@ class StockApiController extends BaseApiController
|
||||
|
||||
public function ClearShoppingList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
User::checkPermission($request, User::PERMISSION_SHOPPINGLIST_ITEMS_DELETE);
|
||||
|
||||
try
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
@@ -482,7 +499,9 @@ class StockApiController extends BaseApiController
|
||||
|
||||
public function AddProductToShoppingList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
User::checkPermission($request, User::PERMISSION_SHOPPINGLIST_ITEMS_ADD);
|
||||
|
||||
try
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
@@ -523,7 +542,9 @@ class StockApiController extends BaseApiController
|
||||
|
||||
public function RemoveProductFromShoppingList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
User::checkPermission($request, User::PERMISSION_SHOPPINGLIST_ITEMS_DELETE);
|
||||
|
||||
try
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
@@ -559,7 +580,9 @@ class StockApiController extends BaseApiController
|
||||
|
||||
public function ExternalBarcodeLookup(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
User::checkPermission($request, User::PERMISSION_MASTER_DATA_EDIT);
|
||||
|
||||
try
|
||||
{
|
||||
$addFoundProduct = false;
|
||||
if (isset($request->getQueryParams()['add']) && ($request->getQueryParams()['add'] === 'true' || $request->getQueryParams()['add'] === 1))
|
||||
@@ -577,7 +600,9 @@ class StockApiController extends BaseApiController
|
||||
|
||||
public function UndoBooking(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
User::checkPermission($request, User::PERMISSION_STOCK_CORRECTION);
|
||||
|
||||
try
|
||||
{
|
||||
$this->ApiResponse($response, $this->getStockService()->UndoBooking($args['bookingId']));
|
||||
return $this->EmptyApiResponse($response);
|
||||
@@ -590,7 +615,9 @@ class StockApiController extends BaseApiController
|
||||
|
||||
public function UndoTransaction(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
User::checkPermission($request, User::PERMISSION_STOCK_CORRECTION);
|
||||
|
||||
try
|
||||
{
|
||||
$this->ApiResponse($response, $this->getStockService()->UndoTransaction($args['transactionId']));
|
||||
return $this->EmptyApiResponse($response);
|
||||
|
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Controllers\Users\User;
|
||||
|
||||
class TasksApiController extends BaseApiController
|
||||
{
|
||||
public function __construct(\DI\Container $container)
|
||||
@@ -16,7 +18,9 @@ class TasksApiController extends BaseApiController
|
||||
|
||||
public function MarkTaskAsCompleted(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$requestBody = $request->getParsedBody();
|
||||
User::checkPermission($request, User::PERMISSION_TASKS_MARK_COMPLETED);
|
||||
|
||||
$requestBody = $request->getParsedBody();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -37,7 +41,9 @@ class TasksApiController extends BaseApiController
|
||||
|
||||
public function UndoTask(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
User::checkPermission($request, User::PERMISSION_TASKS_UNDO);
|
||||
|
||||
try
|
||||
{
|
||||
$this->getTasksService()->UndoTask($args['taskId']);
|
||||
return $this->EmptyApiResponse($response);
|
||||
|
15
controllers/Users/PermissionMissingException.php
Normal file
15
controllers/Users/PermissionMissingException.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers\Users;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Slim\Exception\HttpForbiddenException;
|
||||
use Throwable;
|
||||
|
||||
class PermissionMissingException extends HttpForbiddenException
|
||||
{
|
||||
public function __construct(ServerRequestInterface $request, string $permission, ?Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($request, 'Permission missing: ' . $permission, $previous);
|
||||
}
|
||||
}
|
91
controllers/Users/User.php
Normal file
91
controllers/Users/User.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers\Users;
|
||||
|
||||
use Grocy\Services\DatabaseService;
|
||||
use LessQL\Result;
|
||||
|
||||
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';
|
||||
const PERMISSION_BATTERY_UNDO_TRACK_CHARGE_CYCLE = 'BATTERY_UNDO_TRACK_CHARGE_CYCLE';
|
||||
const PERMISSION_BATTERY_TRACK_CHARGE_CYCLE = 'BATTERY_TRACK_CHARGE_CYCLE';
|
||||
const PERMISSION_CHORE_TRACK = 'CHORE_TRACK';
|
||||
const PERMISSION_CHORE_TRACK_OTHERS = 'CHORE_TRACK_OTHERS';
|
||||
const PERMISSION_CHORE_EDIT = 'CHORE_EDIT';
|
||||
const PERMISSION_CHORE_UNDO = 'CHORE_UNDO';
|
||||
const PERMISSION_UPLOAD_FILE = 'UPLOAD_FILE';
|
||||
const PERMISSION_DELETE_FILE = 'DELETE_FILE';
|
||||
const PERMISSION_MASTER_DATA_EDIT = 'MASTER_DATA_EDIT';
|
||||
const PERMISSION_TASKS_UNDO = 'TASKS_UNDO';
|
||||
const PERMISSION_TASKS_MARK_COMPLETED = 'TASKS_MARK_COMPLETED';
|
||||
const PERMISSION_STOCK_TRANSFER = 'STOCK_TRANSFER';
|
||||
const PERMISSION_STOCK_EDIT = 'STOCK_EDIT';
|
||||
const PERMISSION_PRODUCT_CONSUME = 'PRODUCT_CONSUME';
|
||||
const PERMISSION_STOCK_CORRECTION = 'STOCK_CORRECTION';
|
||||
const PERMISSION_PRODUCT_OPEN = 'PRODUCT_OPEN';
|
||||
const PERMISSION_SHOPPINGLIST_ITEMS_ADD = 'SHOPPINGLIST_ITEMS_ADD';
|
||||
const PERMISSION_SHOPPINGLIST_ITEMS_DELETE = 'SHOPPINGLIST_ITEMS_DELETE';
|
||||
const PERMISSION_PRODUCT_PURCHASE = 'PRODUCT_PURCHASE';
|
||||
|
||||
/**
|
||||
* @var \LessQL\Database|null
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->db = DatabaseService::getInstance()->GetDbConnection();
|
||||
|
||||
}
|
||||
|
||||
protected function getPermissions(): Result
|
||||
{
|
||||
return $this->db->user_permissions_resolved()->where('user_id', GROCY_USER_ID);
|
||||
}
|
||||
|
||||
public function hasPermission(string $permission): bool
|
||||
{
|
||||
// global $PERMISSION_CACHE;
|
||||
// if(isset($PERMISSION_CACHE[$permission]))
|
||||
// return $PERMISSION_CACHE[$permission];
|
||||
return $this->getPermissions()->where('permission_name', $permission)->fetch() !== null;
|
||||
}
|
||||
|
||||
public static function checkPermission($request, string ...$permissions): void
|
||||
{
|
||||
$user = new User();
|
||||
foreach ($permissions as $permission) {
|
||||
if (!$user->hasPermission($permission)) {
|
||||
throw new PermissionMissingException($request, $permission);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function getPermissionList()
|
||||
{
|
||||
return $this->db->uihelper_user_permissions()->where('user_id', GROCY_USER_ID);
|
||||
}
|
||||
|
||||
public static function hasPermissions(string ...$permissions)
|
||||
{
|
||||
$user = new User();
|
||||
foreach ($permissions as $permission) {
|
||||
if (!$user->hasPermission($permission)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function PermissionList()
|
||||
{
|
||||
$user = new User();
|
||||
return $user->getPermissionList();
|
||||
}
|
||||
}
|
@@ -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, 'userpermissions', [
|
||||
'user' => $this->getDatabase()->users($args['userId']),
|
||||
'permissions' => $this->getDatabase()->uihelper_user_permissions()
|
||||
->where('parent IS NULL')->where('user_id', $args['userId']),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user