From a9f2d0d855eae7d5539b7ca5341ff6ffffb8736c Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 7 Jun 2018 20:08:34 +1000 Subject: [PATCH] This PR implements Create/View/Edit permissions based on ENTITY TYPE (ie invoice/expense/client). (#2150) * migration for new permissions schema * update permissions across data tables * refactor migrations to prevent duplicate attribute * update permissions in views * Product Permissions * permissions via controllers * Refactor to use Laravel authorization gate * Doc Blocks for EntityPolicy * check permissions conditional on create new client * Bug Fixes * Data table permissions * working on UI * settings UI/UX finalised * Datatable permissions * remove legacy permissions * permission fix for viewing client * remove all instances of viewByOwner * refactor after PR * Bug fix for Functional test and implementation of Functional tests for Permissions * fix for tests --- .travis.yml | 1 + app/Constants.php | 20 ++ app/Http/Controllers/BaseAPIController.php | 2 +- app/Http/Controllers/BaseController.php | 1 + app/Http/Controllers/ClientController.php | 8 +- app/Http/Controllers/CreditController.php | 2 +- .../Controllers/DashboardApiController.php | 2 +- app/Http/Controllers/DashboardController.php | 2 +- app/Http/Controllers/InvoiceController.php | 4 +- app/Http/Controllers/ProductController.php | 7 +- app/Http/Controllers/ProjectController.php | 2 +- app/Http/Controllers/ProposalController.php | 3 +- app/Http/Controllers/ReportController.php | 2 +- app/Http/Controllers/UserController.php | 11 +- app/Jobs/ExportReportResults.php | 2 +- app/Jobs/LoadPostmarkStats.php | 2 +- app/Jobs/RunReport.php | 2 +- app/Models/EntityModel.php | 2 +- app/Models/User.php | 71 ++--- app/Ninja/Datatables/ClientDatatable.php | 16 +- app/Ninja/Datatables/CreditDatatable.php | 26 +- .../Datatables/ExpenseCategoryDatatable.php | 8 +- app/Ninja/Datatables/ExpenseDatatable.php | 31 +- app/Ninja/Datatables/InvoiceDatatable.php | 30 +- app/Ninja/Datatables/PaymentDatatable.php | 21 +- app/Ninja/Datatables/ProjectDatatable.php | 16 +- .../Datatables/ProposalCategoryDatatable.php | 8 +- app/Ninja/Datatables/ProposalDatatable.php | 27 +- .../Datatables/ProposalSnippetDatatable.php | 15 +- .../Datatables/ProposalTemplateDatatable.php | 15 +- .../Datatables/RecurringExpenseDatatable.php | 21 +- .../Datatables/RecurringInvoiceDatatable.php | 2 +- app/Ninja/Datatables/TaskDatatable.php | 34 +- app/Ninja/Datatables/VendorDatatable.php | 4 +- app/Ninja/Repositories/AccountRepository.php | 2 +- app/Policies/DocumentPolicy.php | 2 +- app/Policies/EntityPolicy.php | 55 +++- app/Services/CreditService.php | 2 +- app/Services/DatatableService.php | 6 +- app/Services/ExpenseService.php | 6 +- app/Services/InvoiceService.php | 2 +- app/Services/PaymentService.php | 2 +- app/Services/ProductService.php | 2 +- app/Services/RecurringExpenseService.php | 2 +- app/Services/RecurringInvoiceService.php | 2 +- app/Services/TaskService.php | 2 +- app/Services/VendorService.php | 2 +- ...2018_05_19_095124_add_json_permissions.php | 114 +++++++ database/seeds/UserTableSeeder.php | 15 + resources/views/accounts/product.blade.php | 3 +- resources/views/clients/edit.blade.php | 4 +- resources/views/credits/edit.blade.php | 4 +- resources/views/dashboard.blade.php | 12 +- resources/views/errors/400.blade.php | 1 + resources/views/header.blade.php | 2 +- resources/views/invoices/edit.blade.php | 27 +- resources/views/payments/edit.blade.php | 3 +- resources/views/projects/edit.blade.php | 3 +- resources/views/proposals/edit.blade.php | 2 + resources/views/reports/emails.blade.php | 4 +- .../views/reports/report_builder.blade.php | 2 +- resources/views/users/edit.blade.php | 89 ++++-- resources/views/vendors/edit.blade.php | 4 +- tests/_support/FunctionalTester.php | 2 +- tests/functional.suite.yml | 12 +- tests/functional/PermissionsCest.php | 291 ++++++++++++++++++ 66 files changed, 814 insertions(+), 287 deletions(-) create mode 100644 database/migrations/2018_05_19_095124_add_json_permissions.php create mode 100644 resources/views/errors/400.blade.php create mode 100644 tests/functional/PermissionsCest.php diff --git a/.travis.yml b/.travis.yml index d0438c98764a..4cbed2ad822d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -87,6 +87,7 @@ script: - php ./vendor/codeception/codeception/codecept run --debug acceptance GatewayFeesCest.php - php ./vendor/codeception/codeception/codecept run --debug acceptance DiscountCest.php - php ./vendor/codeception/codeception/codecept run --debug acceptance AllPagesCept.php + - php ./vendor/codeception/codeception/codecept run --debug functional PermissionsCest.php #- sed -i 's/NINJA_DEV=true/NINJA_PROD=true/g' .env #- php ./vendor/codeception/codeception/codecept run acceptance GoProCest.php diff --git a/app/Constants.php b/app/Constants.php index 2f2b272f36a1..5af2094118ba 100644 --- a/app/Constants.php +++ b/app/Constants.php @@ -48,6 +48,25 @@ if (! defined('APP_NAME')) { define('ENTITY_PROPOSAL_CATEGORY', 'proposal_category'); define('ENTITY_PROPOSAL_INVITATION', 'proposal_invitation'); + $permissionEntities = [ + ENTITY_PROPOSAL, + ENTITY_EXPENSE, + ENTITY_PROJECT, + ENTITY_VENDOR, + ENTITY_PRODUCT, + ENTITY_TASK, + ENTITY_QUOTE, + ENTITY_CREDIT, + ENTITY_PAYMENT, + ENTITY_CONTACT, + ENTITY_INVOICE, + ENTITY_CLIENT, + ENTITY_RECURRING_INVOICE, + 'reports', + ]; + + define('PERMISSION_ENTITIES', json_encode($permissionEntities)); + define('INVOICE_TYPE_STANDARD', 1); define('INVOICE_TYPE_QUOTE', 2); @@ -408,6 +427,7 @@ if (! defined('APP_NAME')) { define('NEW_VERSION_AVAILABLE', 'NEW_VERSION_AVAILABLE'); define('TEST_USERNAME', env('TEST_USERNAME', 'user@example.com')); + define('TEST_PERMISSIONS_USERNAME', env('TEST_PERMISSIONS_USERNAME', 'permissions@example.com')); define('TEST_PASSWORD', 'password'); define('API_SECRET', 'API_SECRET'); define('DEFAULT_API_PAGE_SIZE', 15); diff --git a/app/Http/Controllers/BaseAPIController.php b/app/Http/Controllers/BaseAPIController.php index 45fe4d0de3e4..bc467488f881 100644 --- a/app/Http/Controllers/BaseAPIController.php +++ b/app/Http/Controllers/BaseAPIController.php @@ -112,7 +112,7 @@ class BaseAPIController extends Controller $query->whereHas('client', $filter); } - if (! Utils::hasPermission('view_all')) { + if (! Utils::hasPermission('admin')) { if ($this->entityType == ENTITY_USER) { $query->where('id', '=', Auth::user()->id); } else { diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php index 535062515c77..24c64f6334e0 100644 --- a/app/Http/Controllers/BaseController.php +++ b/app/Http/Controllers/BaseController.php @@ -67,4 +67,5 @@ class BaseController extends Controller exit; } + } diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php index d19923f26e6e..92a1febc0cc5 100644 --- a/app/Http/Controllers/ClientController.php +++ b/app/Http/Controllers/ClientController.php @@ -58,7 +58,7 @@ class ClientController extends BaseController public function getDatatable() { $search = Input::get('sSearch'); - $userId = Auth::user()->filterId(); + $userId = Auth::user()->filterIdByEntity(ENTITY_CLIENT); return $this->clientService->getDatatable($search, $userId); } @@ -86,10 +86,13 @@ class ClientController extends BaseController */ public function show(ClientRequest $request) { + $client = $request->entity(); $user = Auth::user(); $account = $user->account; + //$user->can('view', [ENTITY_CLIENT, $client]); + $actionLinks = []; if ($user->can('create', ENTITY_INVOICE)) { $actionLinks[] = ['label' => trans('texts.new_invoice'), 'url' => URL::to('/invoices/create/'.$client->public_id)]; @@ -147,6 +150,8 @@ class ClientController extends BaseController */ public function create(ClientRequest $request) { + //Auth::user()->can('create', ENTITY_CLIENT); + if (Client::scope()->withTrashed()->count() > Auth::user()->getMaxNumClients()) { return View::make('error', ['hideHeader' => true, 'error' => "Sorry, you've exceeded the limit of ".Auth::user()->getMaxNumClients().' clients']); } @@ -172,6 +177,7 @@ class ClientController extends BaseController */ public function edit(ClientRequest $request) { + $client = $request->entity(); $data = [ diff --git a/app/Http/Controllers/CreditController.php b/app/Http/Controllers/CreditController.php index 187741c3dc2a..ac5ada2dee42 100644 --- a/app/Http/Controllers/CreditController.php +++ b/app/Http/Controllers/CreditController.php @@ -68,7 +68,7 @@ class CreditController extends BaseController { $credit = Credit::withTrashed()->scope($publicId)->firstOrFail(); - $this->authorize('edit', $credit); + $this->authorize('view', $credit); $credit->credit_date = Utils::fromSqlDate($credit->credit_date); diff --git a/app/Http/Controllers/DashboardApiController.php b/app/Http/Controllers/DashboardApiController.php index 894a2e3593a9..e77a1409a070 100644 --- a/app/Http/Controllers/DashboardApiController.php +++ b/app/Http/Controllers/DashboardApiController.php @@ -18,7 +18,7 @@ class DashboardApiController extends BaseAPIController public function index() { $user = Auth::user(); - $viewAll = $user->hasPermission('view_all'); + $viewAll = $user->hasPermission('view_reports'); $userId = $user->id; $accountId = $user->account->id; $defaultCurrency = $user->account->currency_id; diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index d69b9f150c5d..49e99747b5ed 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -25,7 +25,7 @@ class DashboardController extends BaseController public function index() { $user = Auth::user(); - $viewAll = $user->hasPermission('view_all'); + $viewAll = $user->hasPermission('view_reports'); $userId = $user->id; $account = $user->account; $accountId = $account->id; diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index cfde36f324f7..572c0584e5a5 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -140,7 +140,7 @@ class InvoiceController extends BaseController $lastSent = ($invoice->is_recurring && $invoice->last_sent_date) ? $invoice->recurring_invoices->last() : null; - if (! Auth::user()->hasPermission('view_all')) { + if (! Auth::user()->hasPermission('view_client')) { $clients = $clients->where('clients.user_id', '=', Auth::user()->id); } @@ -211,7 +211,7 @@ class InvoiceController extends BaseController $invoice->loadFromRequest(); $clients = Client::scope()->with('contacts', 'country')->orderBy('name'); - if (! Auth::user()->hasPermission('view_all')) { + if (! Auth::user()->hasPermission('view_client')) { $clients = $clients->where('clients.user_id', '=', Auth::user()->id); } diff --git a/app/Http/Controllers/ProductController.php b/app/Http/Controllers/ProductController.php index b877ed961202..53bbd949abf3 100644 --- a/app/Http/Controllers/ProductController.php +++ b/app/Http/Controllers/ProductController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers; +use App\Http\Requests\CreateProductRequest; use App\Http\Requests\ProductRequest; use App\Models\Product; use App\Models\TaxRate; @@ -9,6 +10,7 @@ use App\Ninja\Datatables\ProductDatatable; use App\Ninja\Repositories\ProductRepository; use App\Services\ProductService; use Auth; +use Illuminate\Auth\Access\AuthorizationException; use Input; use Redirect; use Session; @@ -84,6 +86,8 @@ class ProductController extends BaseController */ public function edit(ProductRequest $request, $publicId, $clone = false) { + Auth::user()->can('view', [ENTITY_PRODUCT, $request->entity()]); + $account = Auth::user()->account; $product = Product::scope($publicId)->withTrashed()->firstOrFail(); @@ -114,8 +118,9 @@ class ProductController extends BaseController /** * @return \Illuminate\Contracts\View\View */ - public function create() + public function create(CreateProductRequest $request) { + $account = Auth::user()->account; $data = [ diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php index 35922197d1ad..c7739d3b9919 100644 --- a/app/Http/Controllers/ProjectController.php +++ b/app/Http/Controllers/ProjectController.php @@ -45,7 +45,7 @@ class ProjectController extends BaseController public function getDatatable($expensePublicId = null) { $search = Input::get('sSearch'); - $userId = Auth::user()->filterId(); + $userId = Auth::user()->filterIdByEntity(ENTITY_PROJECT); return $this->projectService->getDatatable($search, $userId); } diff --git a/app/Http/Controllers/ProposalController.php b/app/Http/Controllers/ProposalController.php index a3f2a3f59b1e..1c93ad6482ed 100644 --- a/app/Http/Controllers/ProposalController.php +++ b/app/Http/Controllers/ProposalController.php @@ -51,7 +51,8 @@ class ProposalController extends BaseController public function getDatatable($expensePublicId = null) { $search = Input::get('sSearch'); - $userId = Auth::user()->filterId(); + //$userId = Auth::user()->filterId(); + $userId = Auth::user()->filterIdByEntity(ENTITY_PROPOSAL); return $this->proposalService->getDatatable($search, $userId); } diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php index 6ec9b04e2219..af22fbd1df16 100644 --- a/app/Http/Controllers/ReportController.php +++ b/app/Http/Controllers/ReportController.php @@ -54,7 +54,7 @@ class ReportController extends BaseController */ public function showReports() { - if (! Auth::user()->hasPermission('view_all')) { + if (! Auth::user()->hasPermission('view_reports')) { return redirect('/'); } diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index dee90742961b..a42221b54371 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -162,6 +162,7 @@ class UserController extends BaseController */ public function save($userPublicId = false) { + if (! Auth::user()->hasFeature(FEATURE_USERS)) { return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT); } @@ -204,7 +205,7 @@ class UserController extends BaseController $user->email = trim(Input::get('email')); if (Auth::user()->hasFeature(FEATURE_USER_PERMISSIONS)) { $user->is_admin = boolval(Input::get('is_admin')); - $user->permissions = Input::get('permissions'); + $user->permissions = self::formatUserPermissions(Input::get('permissions')); } } else { $lastUser = User::withTrashed()->where('account_id', '=', Auth::user()->account_id) @@ -222,7 +223,7 @@ class UserController extends BaseController $user->public_id = $lastUser->public_id + 1; if (Auth::user()->hasFeature(FEATURE_USER_PERMISSIONS)) { $user->is_admin = boolval(Input::get('is_admin')); - $user->permissions = Input::get('permissions'); + $user->permissions = self::formatUserPermissions(Input::get('permissions')); } } @@ -240,6 +241,12 @@ class UserController extends BaseController return Redirect::to('users/' . $user->public_id . '/edit'); } + private function formatUserPermissions(array $permissions) { + + return json_encode(array_diff(array_values($permissions),[0])); + + } + public function sendConfirmation($userPublicId) { $user = User::where('account_id', '=', Auth::user()->account_id) diff --git a/app/Jobs/ExportReportResults.php b/app/Jobs/ExportReportResults.php index 1608c1094c5b..eacaf6e724a5 100644 --- a/app/Jobs/ExportReportResults.php +++ b/app/Jobs/ExportReportResults.php @@ -23,7 +23,7 @@ class ExportReportResults extends Job */ public function handle() { - if (! $this->user->hasPermission('view_all')) { + if (! $this->user->hasPermission('view_reports')) { return false; } diff --git a/app/Jobs/LoadPostmarkStats.php b/app/Jobs/LoadPostmarkStats.php index f5a508e577b8..14d9e776a807 100644 --- a/app/Jobs/LoadPostmarkStats.php +++ b/app/Jobs/LoadPostmarkStats.php @@ -27,7 +27,7 @@ class LoadPostmarkStats extends Job */ public function handle() { - if (! auth()->user()->hasPermission('view_all')) { + if (! auth()->user()->hasPermission('view_reports')) { return $this->response; } diff --git a/app/Jobs/RunReport.php b/app/Jobs/RunReport.php index 4fa4a56025c1..110a7d267203 100644 --- a/app/Jobs/RunReport.php +++ b/app/Jobs/RunReport.php @@ -25,7 +25,7 @@ class RunReport extends Job */ public function handle() { - if (! $this->user->hasPermission('view_all')) { + if (! $this->user->hasPermission('view_reports')) { return false; } diff --git a/app/Models/EntityModel.php b/app/Models/EntityModel.php index 96bf7c57ad70..c4445d67445a 100644 --- a/app/Models/EntityModel.php +++ b/app/Models/EntityModel.php @@ -179,7 +179,7 @@ class EntityModel extends Eloquent } } - if (Auth::check() && ! Auth::user()->hasPermission('view_all') && method_exists($this, 'getEntityType') && $this->getEntityType() != ENTITY_TAX_RATE) { + if (Auth::check() && method_exists($this, 'getEntityType') && ! Auth::user()->hasPermission('view_' . $this->getEntityType()) && $this->getEntityType() != ENTITY_TAX_RATE) { $query->where(Utils::pluralizeEntityType($this->getEntityType()) . '.user_id', '=', Auth::user()->id); } diff --git a/app/Models/User.php b/app/Models/User.php index 69cf746afd10..3005416361fe 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -331,72 +331,34 @@ class User extends Authenticatable return Utils::isNinjaProd() && $this->email != $this->getOriginal('email'); } - /** - * Set the permissions attribute on the model. - * - * @param mixed $value - * - * @return $this - */ - protected function setPermissionsAttribute($value) - { - if (empty($value)) { - $this->attributes['permissions'] = 0; - } else { - $bitmask = 0; - foreach ($value as $permission) { - if (! $permission) { - continue; - } - $bitmask = $bitmask | static::$all_permissions[$permission]; - } - $this->attributes['permissions'] = $bitmask; - } - - return $this; - } - - /** - * Expands the value of the permissions attribute. - * - * @param mixed $value - * - * @return mixed - */ - protected function getPermissionsAttribute($value) - { - $permissions = []; - foreach (static::$all_permissions as $permission => $bitmask) { - if (($value & $bitmask) == $bitmask) { - $permissions[$permission] = $permission; - } - } - - return $permissions; - } /** * Checks to see if the user has the required permission. * * @param mixed $permission Either a single permission or an array of possible permissions - * @param bool True to require all permissions, false to require only one - * @param mixed $requireAll + * @param mixed $requireAll - True to require all permissions, false to require only one * * @return bool */ + public function hasPermission($permission, $requireAll = false) { if ($this->is_admin) { return true; } elseif (is_string($permission)) { - return ! empty($this->permissions[$permission]); - } elseif (is_array($permission)) { - if ($requireAll) { - return count(array_diff($permission, $this->permissions)) == 0; - } else { - return count(array_intersect($permission, $this->permissions)) > 0; + + if( is_array(json_decode($this->permissions,1)) && in_array($permission, json_decode($this->permissions,1)) ) { + return true; } + + } elseif (is_array($permission)) { + + if ($requireAll) + return count(array_intersect($permission, json_decode($this->permissions,1))) == count( $permission ); + else + return count(array_intersect($permission, json_decode($this->permissions,1))) > 0; + } return false; @@ -416,10 +378,15 @@ class User extends Authenticatable * @return bool|mixed */ public function filterId() - { + { //todo permissions return $this->hasPermission('view_all') ? false : $this->id; } + public function filterIdByEntity($entity) + { + return $this->hasPermission('view_' . $entity) ? false : $this->id; + } + public function caddAddUsers() { if (! Utils::isNinjaProd()) { diff --git a/app/Ninja/Datatables/ClientDatatable.php b/app/Ninja/Datatables/ClientDatatable.php index 4c6263e559b5..b013f753eeee 100644 --- a/app/Ninja/Datatables/ClientDatatable.php +++ b/app/Ninja/Datatables/ClientDatatable.php @@ -67,10 +67,10 @@ class ClientDatatable extends EntityDatatable [ trans('texts.edit_client'), function ($model) { - return URL::to("clients/{$model->public_id}/edit"); - }, - function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_CLIENT, $model->user_id]); + if(Auth::user()->can('edit', [ENTITY_CLIENT, $model])) + return URL::to("clients/{$model->public_id}/edit"); + elseif(Auth::user()->can('view', [ENTITY_CLIENT, $model])) + return URL::to("clients/{$model->public_id}"); }, ], [ @@ -78,9 +78,7 @@ class ClientDatatable extends EntityDatatable return false; }, function ($model) { - $user = Auth::user(); - - return $user->can('editByOwner', [ENTITY_CLIENT, $model->user_id]) && ($user->can('create', ENTITY_TASK) || $user->can('create', ENTITY_INVOICE)); + return Auth::user()->can('edit', [ENTITY_CLIENT, $model]) && (Auth::user()->can('create', ENTITY_TASK) || Auth::user()->can('create', ENTITY_INVOICE)); }, ], [ @@ -115,9 +113,7 @@ class ClientDatatable extends EntityDatatable return false; }, function ($model) { - $user = Auth::user(); - - return ($user->can('create', ENTITY_TASK) || $user->can('create', ENTITY_INVOICE)) && ($user->can('create', ENTITY_PAYMENT) || $user->can('create', ENTITY_CREDIT) || $user->can('create', ENTITY_EXPENSE)); + return (Auth::user()->can('create', ENTITY_TASK) || Auth::user()->can('create', ENTITY_INVOICE)) && (Auth::user()->can('create', ENTITY_PAYMENT) || Auth::user()->can('create', ENTITY_CREDIT) || Auth::user()->can('create', ENTITY_EXPENSE)); }, ], [ diff --git a/app/Ninja/Datatables/CreditDatatable.php b/app/Ninja/Datatables/CreditDatatable.php index 53ff00b58845..b7e036a15c79 100644 --- a/app/Ninja/Datatables/CreditDatatable.php +++ b/app/Ninja/Datatables/CreditDatatable.php @@ -17,46 +17,50 @@ class CreditDatatable extends EntityDatatable [ 'client_name', function ($model) { - if (! Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])) { + if (Auth::user()->can('view', [ENTITY_CLIENT, $model])) + return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : ''; + else return Utils::getClientDisplayName($model); - } - return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : ''; }, ! $this->hideClient, ], [ 'amount', function ($model) { - return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id) . ''; + if(Auth::user()->can('view', [ENTITY_CLIENT, $model])) + return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id) . ''; }, ], [ 'balance', function ($model) { - return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id); + if(Auth::user()->can('view', [ENTITY_CLIENT, $model])) + return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id); }, ], [ 'credit_date', function ($model) { - if (! Auth::user()->can('viewByOwner', [ENTITY_CREDIT, $model->user_id])) { + if (Auth::user()->can('view', [ENTITY_CREDIT, $model])) + return link_to("credits/{$model->public_id}/edit", Utils::fromSqlDate($model->credit_date_sql))->toHtml(); + else return Utils::fromSqlDate($model->credit_date_sql); - } - return link_to("credits/{$model->public_id}/edit", Utils::fromSqlDate($model->credit_date_sql))->toHtml(); }, ], [ 'public_notes', function ($model) { - return e($model->public_notes); + if (Auth::user()->can('view', [ENTITY_CREDIT, $model])) + return e($model->public_notes); }, ], [ 'private_notes', function ($model) { - return e($model->private_notes); + if (Auth::user()->can('view', [ENTITY_CREDIT, $model])) + return e($model->private_notes); }, ], ]; @@ -71,7 +75,7 @@ class CreditDatatable extends EntityDatatable return URL::to("credits/{$model->public_id}/edit"); }, function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_CREDIT, $model->user_id]); + return Auth::user()->can('view', [ENTITY_CREDIT, $model]); }, ], [ diff --git a/app/Ninja/Datatables/ExpenseCategoryDatatable.php b/app/Ninja/Datatables/ExpenseCategoryDatatable.php index f73364066ac6..e3f2f01db1e9 100644 --- a/app/Ninja/Datatables/ExpenseCategoryDatatable.php +++ b/app/Ninja/Datatables/ExpenseCategoryDatatable.php @@ -16,11 +16,11 @@ class ExpenseCategoryDatatable extends EntityDatatable [ 'name', function ($model) { - if (! Auth::user()->can('editByOwner', [ENTITY_EXPENSE_CATEGORY, $model->user_id])) { + if (Auth::user()->can('edit', [ENTITY_EXPENSE_CATEGORY, $model])) + return link_to("expense_categories/{$model->public_id}/edit", $model->category)->toHtml(); + else return $model->category; - } - return link_to("expense_categories/{$model->public_id}/edit", $model->category)->toHtml(); }, ], ]; @@ -35,7 +35,7 @@ class ExpenseCategoryDatatable extends EntityDatatable return URL::to("expense_categories/{$model->public_id}/edit"); }, function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_EXPENSE_CATEGORY, $model->user_id]); + return Auth::user()->can('edit', [ENTITY_EXPENSE_CATEGORY, $model]); }, ], ]; diff --git a/app/Ninja/Datatables/ExpenseDatatable.php b/app/Ninja/Datatables/ExpenseDatatable.php index e489c89a71a5..894c2c5d3973 100644 --- a/app/Ninja/Datatables/ExpenseDatatable.php +++ b/app/Ninja/Datatables/ExpenseDatatable.php @@ -19,11 +19,11 @@ class ExpenseDatatable extends EntityDatatable 'vendor_name', function ($model) { if ($model->vendor_public_id) { - if (! Auth::user()->can('viewByOwner', [ENTITY_VENDOR, $model->vendor_user_id])) { + if (Auth::user()->can('view', [ENTITY_VENDOR, $model])) + return link_to("vendors/{$model->vendor_public_id}", $model->vendor_name)->toHtml(); + else return $model->vendor_name; - } - return link_to("vendors/{$model->vendor_public_id}", $model->vendor_name)->toHtml(); } else { return ''; } @@ -34,11 +34,11 @@ class ExpenseDatatable extends EntityDatatable 'client_name', function ($model) { if ($model->client_public_id) { - if (! Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])) { + if (Auth::user()->can('view', [ENTITY_CLIENT, $model])) + return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml(); + else return Utils::getClientDisplayName($model); - } - return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml(); } else { return ''; } @@ -48,12 +48,11 @@ class ExpenseDatatable extends EntityDatatable [ 'expense_date', function ($model) { - if (! Auth::user()->can('viewByOwner', [ENTITY_EXPENSE, $model->user_id])) { + if (Auth::user()->can('view', [ENTITY_EXPENSE, $model])) + return $this->addNote(link_to("expenses/{$model->public_id}/edit", Utils::fromSqlDate($model->expense_date_sql))->toHtml(), $model->private_notes); + else return Utils::fromSqlDate($model->expense_date_sql); - } - $str = link_to("expenses/{$model->public_id}/edit", Utils::fromSqlDate($model->expense_date_sql))->toHtml(); - return $this->addNote($str, $model->private_notes); }, ], [ @@ -75,11 +74,11 @@ class ExpenseDatatable extends EntityDatatable 'category', function ($model) { $category = $model->category != null ? substr($model->category, 0, 100) : ''; - if (! Auth::user()->can('editByOwner', [ENTITY_EXPENSE_CATEGORY, $model->category_user_id])) { + if (Auth::user()->can('view', [ENTITY_EXPENSE_CATEGORY, $model])) + return $model->category_public_id ? link_to("expense_categories/{$model->category_public_id}/edit", $category)->toHtml() : ''; + else return $category; - } - return $model->category_public_id ? link_to("expense_categories/{$model->category_public_id}/edit", $category)->toHtml() : ''; }, ], [ @@ -106,7 +105,7 @@ class ExpenseDatatable extends EntityDatatable return URL::to("expenses/{$model->public_id}/edit"); }, function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_EXPENSE, $model->user_id]); + return Auth::user()->can('view', [ENTITY_EXPENSE, $model]); }, ], [ @@ -115,7 +114,7 @@ class ExpenseDatatable extends EntityDatatable return URL::to("expenses/{$model->public_id}/clone"); }, function ($model) { - return Auth::user()->can('viewByOwner', [ENTITY_EXPENSE, $model->user_id]) && Auth::user()->can('create', ENTITY_EXPENSE); + return Auth::user()->can('create', ENTITY_EXPENSE); }, ], [ @@ -124,7 +123,7 @@ class ExpenseDatatable extends EntityDatatable return URL::to("/invoices/{$model->invoice_public_id}/edit"); }, function ($model) { - return $model->invoice_public_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->invoice_user_id]); + return $model->invoice_public_id && Auth::user()->can('view', [ENTITY_INVOICE, $model]); }, ], [ diff --git a/app/Ninja/Datatables/InvoiceDatatable.php b/app/Ninja/Datatables/InvoiceDatatable.php index 3cba7faf46ed..31cb025551e7 100644 --- a/app/Ninja/Datatables/InvoiceDatatable.php +++ b/app/Ninja/Datatables/InvoiceDatatable.php @@ -20,22 +20,24 @@ class InvoiceDatatable extends EntityDatatable [ $entityType == ENTITY_INVOICE ? 'invoice_number' : 'quote_number', function ($model) use ($entityType) { - if (! Auth::user()->can('viewByOwner', [ENTITY_INVOICE, $model->user_id])) { - return $model->invoice_number; + if(Auth::user()->can('view', [ENTITY_INVOICE, $model])) { + $str = link_to("{$entityType}s/{$model->public_id}/edit", $model->invoice_number, ['class' => Utils::getEntityRowClass($model)])->toHtml(); + return $this->addNote($str, $model->private_notes); } + else + return $model->invoice_number; + - $str = link_to("{$entityType}s/{$model->public_id}/edit", $model->invoice_number, ['class' => Utils::getEntityRowClass($model)])->toHtml(); - return $this->addNote($str, $model->private_notes); }, ], [ 'client_name', function ($model) { - if (! Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])) { + if(Auth::user()->can('view', [ENTITY_CLIENT, $model])) + return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml(); + else return Utils::getClientDisplayName($model); - } - return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml(); }, ! $this->hideClient, ], @@ -96,7 +98,7 @@ class InvoiceDatatable extends EntityDatatable return URL::to("invoices/{$model->public_id}/clone"); }, function ($model) { - return Auth::user()->can('viewByOwner', [ENTITY_INVOICE, $model->user_id]) && Auth::user()->can('create', ENTITY_INVOICE); + return Auth::user()->can('create', ENTITY_INVOICE); }, ], [ @@ -105,7 +107,7 @@ class InvoiceDatatable extends EntityDatatable return URL::to("quotes/{$model->public_id}/clone"); }, function ($model) { - return Auth::user()->can('viewByOwner', [ENTITY_INVOICE, $model->user_id]) && Auth::user()->can('create', ENTITY_QUOTE); + return Auth::user()->can('create', ENTITY_QUOTE); }, ], [ @@ -128,7 +130,7 @@ class InvoiceDatatable extends EntityDatatable return false; }, function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]) || Auth::user()->can('create', ENTITY_PAYMENT); + return Auth::user()->canCreateOrEdit(ENTITY_INVOICE); }, ], [ @@ -137,7 +139,7 @@ class InvoiceDatatable extends EntityDatatable return "javascript:submitForm_{$entityType}('markSent', {$model->public_id})"; }, function ($model) { - return ! $model->is_public && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); + return ! $model->is_public && Auth::user()->can('edit', [ENTITY_INVOICE, $model]); }, ], [ @@ -146,7 +148,7 @@ class InvoiceDatatable extends EntityDatatable return "javascript:submitForm_{$entityType}('markPaid', {$model->public_id})"; }, function ($model) use ($entityType) { - return $entityType == ENTITY_INVOICE && $model->invoice_status_id != INVOICE_STATUS_PAID && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); + return $entityType == ENTITY_INVOICE && $model->invoice_status_id != INVOICE_STATUS_PAID && Auth::user()->can('edit', [ENTITY_INVOICE, $model]); }, ], [ @@ -164,7 +166,7 @@ class InvoiceDatatable extends EntityDatatable return URL::to("invoices/{$model->quote_invoice_id}/edit"); }, function ($model) use ($entityType) { - return $entityType == ENTITY_QUOTE && $model->quote_invoice_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); + return $entityType == ENTITY_QUOTE && $model->quote_invoice_id && Auth::user()->can('view', [ENTITY_INVOICE, $model]); }, ], [ @@ -182,7 +184,7 @@ class InvoiceDatatable extends EntityDatatable return "javascript:submitForm_quote('convert', {$model->public_id})"; }, function ($model) use ($entityType) { - return $entityType == ENTITY_QUOTE && ! $model->quote_invoice_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); + return $entityType == ENTITY_QUOTE && ! $model->quote_invoice_id && Auth::user()->can('edit', [ENTITY_INVOICE, $model]); }, ], ]; diff --git a/app/Ninja/Datatables/PaymentDatatable.php b/app/Ninja/Datatables/PaymentDatatable.php index b20610cb0d71..91129fe45d71 100644 --- a/app/Ninja/Datatables/PaymentDatatable.php +++ b/app/Ninja/Datatables/PaymentDatatable.php @@ -25,21 +25,22 @@ class PaymentDatatable extends EntityDatatable [ 'invoice_name', function ($model) { - if (! Auth::user()->can('viewByOwner', [ENTITY_INVOICE, $model->invoice_user_id])) { + if (Auth::user()->can('view', [ENTITY_INVOICE, $model->invoice_user_id])) + return link_to("invoices/{$model->invoice_public_id}/edit", $model->invoice_number, ['class' => Utils::getEntityRowClass($model)])->toHtml(); + else return $model->invoice_number; - } - return link_to("invoices/{$model->invoice_public_id}/edit", $model->invoice_number, ['class' => Utils::getEntityRowClass($model)])->toHtml(); - }, + }, ], [ 'client_name', function ($model) { - if (! Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])) { + if(Auth::user()->can('view', [ENTITY_CLIENT, ENTITY_CLIENT])) + return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : ''; + else return Utils::getClientDisplayName($model); - } - return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : ''; + }, ! $this->hideClient, ], @@ -128,7 +129,7 @@ class PaymentDatatable extends EntityDatatable return URL::to("payments/{$model->public_id}/edit"); }, function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_PAYMENT, $model->user_id]); + return Auth::user()->can('view', [ENTITY_PAYMENT, $model]); }, ], [ @@ -137,7 +138,7 @@ class PaymentDatatable extends EntityDatatable return "javascript:submitForm_payment('email', {$model->public_id})"; }, function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_PAYMENT, $model->user_id]); + return Auth::user()->can('edit', [ENTITY_PAYMENT, $model]); }, ], [ @@ -151,7 +152,7 @@ class PaymentDatatable extends EntityDatatable return "javascript:showRefundModal({$model->public_id}, '{$max_refund}', '{$formatted}', '{$symbol}', {$local})"; }, function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_PAYMENT, $model->user_id]) + return Auth::user()->can('edit', [ENTITY_PAYMENT, $model]) && $model->payment_status_id >= PAYMENT_STATUS_COMPLETED && $model->refunded < $model->amount; }, diff --git a/app/Ninja/Datatables/ProjectDatatable.php b/app/Ninja/Datatables/ProjectDatatable.php index 1d12f657436e..e51dfae2892c 100644 --- a/app/Ninja/Datatables/ProjectDatatable.php +++ b/app/Ninja/Datatables/ProjectDatatable.php @@ -17,23 +17,23 @@ class ProjectDatatable extends EntityDatatable [ 'project', function ($model) { - if (! Auth::user()->can('editByOwner', [ENTITY_PROJECT, $model->user_id])) { + if (Auth::user()->can('view', [ENTITY_PROJECT, $model])) + return $this->addNote(link_to("projects/{$model->public_id}", $model->project)->toHtml(), $model->private_notes); + else return $model->project; - } - $str = link_to("projects/{$model->public_id}", $model->project)->toHtml(); - return $this->addNote($str, $model->private_notes); + }, ], [ 'client_name', function ($model) { if ($model->client_public_id) { - if (! Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])) { + if (Auth::user()->can('view', [ENTITY_CLIENT, $model])) + return link_to("clients/{$model->client_public_id}", $model->client_name)->toHtml(); + else return Utils::getClientDisplayName($model); - } - return link_to("clients/{$model->client_public_id}", $model->client_name)->toHtml(); } else { return ''; } @@ -69,7 +69,7 @@ class ProjectDatatable extends EntityDatatable return URL::to("projects/{$model->public_id}/edit"); }, function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_PROJECT, $model->user_id]); + return Auth::user()->can('view', [ENTITY_PROJECT, $model]); }, ], [ diff --git a/app/Ninja/Datatables/ProposalCategoryDatatable.php b/app/Ninja/Datatables/ProposalCategoryDatatable.php index 53d44b8509a8..b0325f4f85f0 100644 --- a/app/Ninja/Datatables/ProposalCategoryDatatable.php +++ b/app/Ninja/Datatables/ProposalCategoryDatatable.php @@ -17,11 +17,11 @@ class ProposalCategoryDatatable extends EntityDatatable [ 'name', function ($model) { - if (! Auth::user()->can('editByOwner', [ENTITY_PROPOSAL_CATEGORY, $model->user_id])) { + if (Auth::user()->can('view', [ENTITY_PROPOSAL_CATEGORY, $model]) ) + return link_to("proposals/categories/{$model->public_id}/edit", $model->name)->toHtml(); + else return $model->name; - } - return link_to("proposals/categories/{$model->public_id}/edit", $model->name)->toHtml(); }, ], ]; @@ -36,7 +36,7 @@ class ProposalCategoryDatatable extends EntityDatatable return URL::to("proposals/categories/{$model->public_id}/edit"); }, function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_PROPOSAL_CATEGORY, $model->user_id]); + return Auth::user()->can('view', [ENTITY_PROPOSAL_CATEGORY, $model]); }, ], ]; diff --git a/app/Ninja/Datatables/ProposalDatatable.php b/app/Ninja/Datatables/ProposalDatatable.php index 596f28f7a430..52f2051ed4b0 100644 --- a/app/Ninja/Datatables/ProposalDatatable.php +++ b/app/Ninja/Datatables/ProposalDatatable.php @@ -17,41 +17,40 @@ class ProposalDatatable extends EntityDatatable [ 'quote', function ($model) { - if (! Auth::user()->can('viewByOwner', [ENTITY_QUOTE, $model->invoice_user_id])) { + if (Auth::user()->can('view', [ENTITY_QUOTE, $model])) + return link_to("quotes/{$model->invoice_public_id}", $model->invoice_number)->toHtml(); + else return $model->invoice_number; - } - return link_to("quotes/{$model->invoice_public_id}", $model->invoice_number)->toHtml(); }, ], [ 'client', function ($model) { - if (! Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])) { + if (Auth::user()->can('view', [ENTITY_CLIENT, $model])) + return link_to("clients/{$model->client_public_id}", $model->client)->toHtml(); + else return $model->client; - } - - return link_to("clients/{$model->client_public_id}", $model->client)->toHtml(); }, ], [ 'template', function ($model) { - if (! Auth::user()->can('viewByOwner', [ENTITY_PROPOSAL_TEMPLATE, $model->template_user_id])) { + if(Auth::user()->can('view', [ENTITY_PROPOSAL_TEMPLATE, $model])) + return link_to("proposals/templates/{$model->template_public_id}/edit", $model->template ?: ' ')->toHtml(); + else return $model->template ?: ' '; - } - return link_to("proposals/templates/{$model->template_public_id}/edit", $model->template ?: ' ')->toHtml(); }, ], [ 'created_at', function ($model) { - if (! Auth::user()->can('viewByOwner', [ENTITY_PROPOSAL, $model->user_id])) { + if (Auth::user()->can('view', [ENTITY_PROPOSAL, $model])) + return link_to("proposals/{$model->public_id}/edit", Utils::timestampToDateString(strtotime($model->created_at)))->toHtml(); + else return Utils::timestampToDateString(strtotime($model->created_at)); - } - return link_to("proposals/{$model->public_id}/edit", Utils::timestampToDateString(strtotime($model->created_at)))->toHtml(); }, ], [ @@ -78,7 +77,7 @@ class ProposalDatatable extends EntityDatatable return URL::to("proposals/{$model->public_id}/edit"); }, function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_PROPOSAL, $model->user_id]); + return Auth::user()->can('view', [ENTITY_PROPOSAL, $model]) ; }, ], ]; diff --git a/app/Ninja/Datatables/ProposalSnippetDatatable.php b/app/Ninja/Datatables/ProposalSnippetDatatable.php index 7e97c2a83140..a512d2c43d17 100644 --- a/app/Ninja/Datatables/ProposalSnippetDatatable.php +++ b/app/Ninja/Datatables/ProposalSnippetDatatable.php @@ -19,21 +19,22 @@ class ProposalSnippetDatatable extends EntityDatatable function ($model) { $icon = '  '; - if (! Auth::user()->can('editByOwner', [ENTITY_PROPOSAL_SNIPPET, $model->user_id])) { + if (Auth::user()->can('view', [ENTITY_PROPOSAL_SNIPPET, $model])) + return $icon . link_to("proposals/snippets/{$model->public_id}/edit", $model->name)->toHtml(); + else return $icon . $model->name; - } - return $icon . link_to("proposals/snippets/{$model->public_id}/edit", $model->name)->toHtml(); + }, ], [ 'category', function ($model) { - if (! Auth::user()->can('editByOwner', [ENTITY_PROPOSAL_CATEGORY, $model->category_user_id])) { + if (Auth::user()->can('view', [ENTITY_PROPOSAL_CATEGORY, $model])) + return link_to("proposals/categories/{$model->category_public_id}/edit", $model->category ?: ' ')->toHtml(); + else return $model->category; - } - return link_to("proposals/categories/{$model->category_public_id}/edit", $model->category ?: ' ')->toHtml(); }, ], [ @@ -60,7 +61,7 @@ class ProposalSnippetDatatable extends EntityDatatable return URL::to("proposals/snippets/{$model->public_id}/edit"); }, function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_PROPOSAL_SNIPPET, $model->user_id]); + return Auth::user()->can('view', [ENTITY_PROPOSAL_SNIPPET, $model]); }, ], ]; diff --git a/app/Ninja/Datatables/ProposalTemplateDatatable.php b/app/Ninja/Datatables/ProposalTemplateDatatable.php index 9b18798bbd95..fe21398611d1 100644 --- a/app/Ninja/Datatables/ProposalTemplateDatatable.php +++ b/app/Ninja/Datatables/ProposalTemplateDatatable.php @@ -17,13 +17,10 @@ class ProposalTemplateDatatable extends EntityDatatable [ 'name', function ($model) { - if (! Auth::user()->can('editByOwner', [ENTITY_PROPOSAL_TEMPLATE, $model->user_id])) { + if (Auth::user()->can('view', [ENTITY_PROPOSAL_TEMPLATE, $model])) + return link_to("proposals/templates/{$model->public_id}", $model->name)->toHtml(); + else return $model->name; - } - - return link_to("proposals/templates/{$model->public_id}", $model->name)->toHtml(); - //$str = link_to("quotes/{$model->quote_public_id}", $model->quote_number)->toHtml(); - //return $this->addNote($str, $model->private_notes); }, ], [ @@ -50,7 +47,7 @@ class ProposalTemplateDatatable extends EntityDatatable return URL::to("proposals/templates/{$model->public_id}/edit"); }, function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_PROPOSAL_TEMPLATE, $model->user_id]); + return Auth::user()->can('view', [ENTITY_PROPOSAL_TEMPLATE, $model]); }, ], [ @@ -59,7 +56,7 @@ class ProposalTemplateDatatable extends EntityDatatable return URL::to("proposals/templates/{$model->public_id}/clone"); }, function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_PROPOSAL_TEMPLATE, $model->user_id]); + return Auth::user()->can('view', [ENTITY_PROPOSAL_TEMPLATE, $model]); }, ], [ @@ -68,7 +65,7 @@ class ProposalTemplateDatatable extends EntityDatatable return URL::to("proposals/create/0/{$model->public_id}"); }, function ($model) { - return Auth::user()->can('create', [ENTITY_PROPOSAL, $model->user_id]); + return Auth::user()->can('create', [ENTITY_PROPOSAL, $model]); }, ], ]; diff --git a/app/Ninja/Datatables/RecurringExpenseDatatable.php b/app/Ninja/Datatables/RecurringExpenseDatatable.php index 78a6fdb7df8c..00d9369c95c7 100644 --- a/app/Ninja/Datatables/RecurringExpenseDatatable.php +++ b/app/Ninja/Datatables/RecurringExpenseDatatable.php @@ -19,11 +19,11 @@ class RecurringExpenseDatatable extends EntityDatatable 'vendor_name', function ($model) { if ($model->vendor_public_id) { - if (! Auth::user()->can('viewByOwner', [ENTITY_VENDOR, $model->vendor_user_id])) { + if (Auth::user()->can('view', [ENTITY_VENDOR, $model])) + return link_to("vendors/{$model->vendor_public_id}", $model->vendor_name)->toHtml(); + else return $model->vendor_name; - } - return link_to("vendors/{$model->vendor_public_id}", $model->vendor_name)->toHtml(); } else { return ''; } @@ -34,11 +34,12 @@ class RecurringExpenseDatatable extends EntityDatatable 'client_name', function ($model) { if ($model->client_public_id) { - if (! Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])) { + if (Auth::user()->can('view', [ENTITY_CLIENT, $model])) + return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml(); + else return Utils::getClientDisplayName($model); - } - return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml(); + } else { return ''; } @@ -88,11 +89,11 @@ class RecurringExpenseDatatable extends EntityDatatable 'category', function ($model) { $category = $model->category != null ? substr($model->category, 0, 100) : ''; - if (! Auth::user()->can('editByOwner', [ENTITY_EXPENSE_CATEGORY, $model->category_user_id])) { + if (Auth::user()->can('view', [ENTITY_EXPENSE_CATEGORY, $model])) + return $model->category_public_id ? link_to("expense_categories/{$model->category_public_id}/edit", $category)->toHtml() : ''; + else return $category; - } - return $model->category_public_id ? link_to("expense_categories/{$model->category_public_id}/edit", $category)->toHtml() : ''; }, ], [ @@ -113,7 +114,7 @@ class RecurringExpenseDatatable extends EntityDatatable return URL::to("recurring_expenses/{$model->public_id}/edit"); }, function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_RECURRING_EXPENSE, $model->user_id]); + return Auth::user()->can('view', [ENTITY_RECURRING_EXPENSE, $model]); }, ], ]; diff --git a/app/Ninja/Datatables/RecurringInvoiceDatatable.php b/app/Ninja/Datatables/RecurringInvoiceDatatable.php index 2f4555da7ee5..a4e976ef0ab1 100644 --- a/app/Ninja/Datatables/RecurringInvoiceDatatable.php +++ b/app/Ninja/Datatables/RecurringInvoiceDatatable.php @@ -101,7 +101,7 @@ class RecurringInvoiceDatatable extends EntityDatatable return URL::to("invoices/{$model->public_id}/edit"); }, function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); + return Auth::user()->can('view', [ENTITY_INVOICE, $model]); }, ], [ diff --git a/app/Ninja/Datatables/TaskDatatable.php b/app/Ninja/Datatables/TaskDatatable.php index 051e1d2d5bde..9db285bc5e8e 100644 --- a/app/Ninja/Datatables/TaskDatatable.php +++ b/app/Ninja/Datatables/TaskDatatable.php @@ -19,42 +19,42 @@ class TaskDatatable extends EntityDatatable [ 'client_name', function ($model) { - if (! Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])) { + if (Auth::user()->can('view', [ENTITY_CLIENT, $model])) + return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : ''; + else return Utils::getClientDisplayName($model); - } - return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : ''; }, ! $this->hideClient, ], [ 'project', function ($model) { - if (! Auth::user()->can('editByOwner', [ENTITY_PROJECT, $model->project_user_id])) { + if (Auth::user()->can('view', [ENTITY_PROJECT, $model])) + return $model->project_public_id ? link_to("projects/{$model->project_public_id}", $model->project)->toHtml() : ''; + else return $model->project; - } - return $model->project_public_id ? link_to("projects/{$model->project_public_id}", $model->project)->toHtml() : ''; }, ], [ 'date', function ($model) { - if (! Auth::user()->can('viewByOwner', [ENTITY_EXPENSE, $model->user_id])) { + if (Auth::user()->can('view', [ENTITY_EXPENSE, $model])) + return link_to("tasks/{$model->public_id}/edit", Task::calcStartTime($model))->toHtml(); + else return Task::calcStartTime($model); - } - return link_to("tasks/{$model->public_id}/edit", Task::calcStartTime($model))->toHtml(); }, ], [ 'duration', function ($model) { - if (! Auth::user()->can('viewByOwner', [ENTITY_EXPENSE, $model->user_id])) { + if (Auth::user()->can('view', [ENTITY_EXPENSE, $model])) + return link_to("tasks/{$model->public_id}/edit", Utils::formatTime(Task::calcDuration($model)))->toHtml(); + else return Utils::formatTime(Task::calcDuration($model)); - } - return link_to("tasks/{$model->public_id}/edit", Utils::formatTime(Task::calcDuration($model)))->toHtml(); }, ], [ @@ -81,7 +81,7 @@ class TaskDatatable extends EntityDatatable return URL::to('tasks/'.$model->public_id.'/edit'); }, function ($model) { - return (! $model->deleted_at || $model->deleted_at == '0000-00-00') && Auth::user()->can('editByOwner', [ENTITY_TASK, $model->user_id]); + return (! $model->deleted_at || $model->deleted_at == '0000-00-00') && Auth::user()->can('view', [ENTITY_TASK, $model]); }, ], [ @@ -90,7 +90,7 @@ class TaskDatatable extends EntityDatatable return URL::to("/invoices/{$model->invoice_public_id}/edit"); }, function ($model) { - return $model->invoice_number && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->invoice_user_id]); + return $model->invoice_number && Auth::user()->can('view', [ENTITY_TASK, $model]); }, ], [ @@ -99,7 +99,7 @@ class TaskDatatable extends EntityDatatable return "javascript:submitForm_task('resume', {$model->public_id})"; }, function ($model) { - return ! $model->is_running && Auth::user()->can('editByOwner', [ENTITY_TASK, $model->user_id]); + return ! $model->is_running && Auth::user()->can('edit', [ENTITY_TASK, $model]); }, ], [ @@ -108,7 +108,7 @@ class TaskDatatable extends EntityDatatable return "javascript:submitForm_task('stop', {$model->public_id})"; }, function ($model) { - return $model->is_running && Auth::user()->can('editByOwner', [ENTITY_TASK, $model->user_id]); + return $model->is_running && Auth::user()->can('edit', [ENTITY_TASK, $model]); }, ], [ @@ -117,7 +117,7 @@ class TaskDatatable extends EntityDatatable return "javascript:submitForm_task('invoice', {$model->public_id})"; }, function ($model) { - return ! $model->is_running && ! $model->invoice_number && (! $model->deleted_at || $model->deleted_at == '0000-00-00') && Auth::user()->can('create', ENTITY_INVOICE); + return ! $model->is_running && ! $model->invoice_number && (! $model->deleted_at || $model->deleted_at == '0000-00-00') && Auth::user()->canCreateOrEdit(ENTITY_INVOICE); }, ], ]; diff --git a/app/Ninja/Datatables/VendorDatatable.php b/app/Ninja/Datatables/VendorDatatable.php index 8e87b2782fae..3b17847947f7 100644 --- a/app/Ninja/Datatables/VendorDatatable.php +++ b/app/Ninja/Datatables/VendorDatatable.php @@ -57,7 +57,7 @@ class VendorDatatable extends EntityDatatable return URL::to("vendors/{$model->public_id}/edit"); }, function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_VENDOR, $model->user_id]); + return Auth::user()->can('view', [ENTITY_VENDOR, $model]); }, ], [ @@ -65,7 +65,7 @@ class VendorDatatable extends EntityDatatable return false; }, function ($model) { - return Auth::user()->can('editByOwner', [ENTITY_VENDOR, $model->user_id]) && Auth::user()->can('create', ENTITY_EXPENSE); + return Auth::user()->can('edit', [ENTITY_VENDOR, $model]) && Auth::user()->can('create', ENTITY_EXPENSE); }, ], diff --git a/app/Ninja/Repositories/AccountRepository.php b/app/Ninja/Repositories/AccountRepository.php index 5352577bb8dc..f338cfaa5de1 100644 --- a/app/Ninja/Repositories/AccountRepository.php +++ b/app/Ninja/Repositories/AccountRepository.php @@ -176,7 +176,7 @@ class AccountRepository $data[$account->present()->customLabel('client2')] = []; } - if ($user->hasPermission('view_all')) { + if ($user->hasPermission(['view_client', 'view_invoice'], true)) { $clients = Client::scope() ->with('contacts', 'invoices') ->withTrashed() diff --git a/app/Policies/DocumentPolicy.php b/app/Policies/DocumentPolicy.php index 688728e93316..c3424f4ccb65 100644 --- a/app/Policies/DocumentPolicy.php +++ b/app/Policies/DocumentPolicy.php @@ -28,7 +28,7 @@ class DocumentPolicy extends EntityPolicy */ public static function view(User $user, $document) { - if ($user->hasPermission('view_all')) { + if ($user->hasPermission(['view_expense', 'view_invoice'], true)) { return true; } if ($document->expense) { diff --git a/app/Policies/EntityPolicy.php b/app/Policies/EntityPolicy.php index 19e2cf5ac97e..a65249ea3151 100644 --- a/app/Policies/EntityPolicy.php +++ b/app/Policies/EntityPolicy.php @@ -4,6 +4,7 @@ namespace App\Policies; use App\Models\User; use Illuminate\Auth\Access\HandlesAuthorization; +use Illuminate\Support\Facades\Log; /** * Class EntityPolicy. @@ -14,75 +15,97 @@ class EntityPolicy /** * @param User $user - * @param mixed $item + * @param $item - entity name or object * * @return bool */ + public static function create(User $user, $item) { - if (! static::checkModuleEnabled($user, $item)) { + if (! static::checkModuleEnabled($user, $item)) return false; - } - return $user->hasPermission('create_all'); + + $entityType = is_string($item) ? $item : $item->getEntityType(); + return $user->hasPermission('create_' . $entityType); } /** * @param User $user - * @param $item + * @param $item - entity name or object * * @return bool */ + public static function edit(User $user, $item) { - if (! static::checkModuleEnabled($user, $item)) { + if (! static::checkModuleEnabled($user, $item)) return false; - } - return $user->hasPermission('edit_all') || $user->owns($item); + + $entityType = is_string($item) ? $item : $item->getEntityType(); + return $user->hasPermission('edit_' . $entityType) || $user->owns($item); } /** * @param User $user - * @param $item + * @param $item - entity name or object * * @return bool */ + public static function view(User $user, $item) { - if (! static::checkModuleEnabled($user, $item)) { + if (! static::checkModuleEnabled($user, $item)) return false; - } - return $user->hasPermission('view_all') || $user->owns($item); + $entityType = is_string($item) ? $item : $item->getEntityType(); + return $user->hasPermission('view_' . $entityType) || $user->owns($item); } /** * @param User $user * @param $ownerUserId * + * Legacy permissions - retaining these for legacy code however new code + * should use auth()->user()->can('view', $ENTITY_TYPE) + * + * $ENTITY_TYPE can be either the constant ie ENTITY_INVOICE, or the entity $object + * * @return bool */ + public static function viewByOwner(User $user, $ownerUserId) { - return $user->hasPermission('view_all') || $user->id == $ownerUserId; + return $user->id == $ownerUserId; } /** * @param User $user * @param $ownerUserId * + * Legacy permissions - retaining these for legacy code however new code + * should use auth()->user()->can('edit', $ENTITY_TYPE) + * + * $ENTITY_TYPE can be either the constant ie ENTITY_INVOICE, or the entity $object + * * @return bool */ + public static function editByOwner(User $user, $ownerUserId) { - return $user->hasPermission('edit_all') || $user->id == $ownerUserId; + return $user->id == $ownerUserId; } + /** + * @param User $user + * @param $item - entity name or object + * @return bool + */ + private static function checkModuleEnabled(User $user, $item) { $entityType = is_string($item) ? $item : $item->getEntityType(); - - return $user->account->isModuleEnabled($entityType); + return $user->account->isModuleEnabled($entityType); } } diff --git a/app/Services/CreditService.php b/app/Services/CreditService.php index b06a4237bbde..6719daad7202 100644 --- a/app/Services/CreditService.php +++ b/app/Services/CreditService.php @@ -65,7 +65,7 @@ class CreditService extends BaseService $datatable = new CreditDatatable(true, $clientPublicId); $query = $this->creditRepo->find($clientPublicId, $search); - if (! Utils::hasPermission('view_all')) { + if (! Utils::hasPermission('view_credit')) { $query->where('credits.user_id', '=', Auth::user()->id); } diff --git a/app/Services/DatatableService.php b/app/Services/DatatableService.php index d9924f7f5867..5f2de0f44422 100644 --- a/app/Services/DatatableService.php +++ b/app/Services/DatatableService.php @@ -26,8 +26,8 @@ class DatatableService $table = Datatable::query($query); if ($datatable->isBulkEdit) { - $table->addColumn('checkbox', function ($model) { - $can_edit = Auth::user()->hasPermission('edit_all') || (isset($model->user_id) && Auth::user()->id == $model->user_id); + $table->addColumn('checkbox', function ($model) use ($datatable) { + $can_edit = Auth::user()->hasPermission('edit_' . $datatable->entityType) || (isset($model->user_id) && Auth::user()->id == $model->user_id); return ! $can_edit ? '' : ''; @@ -65,7 +65,7 @@ class DatatableService $hasAction = false; $str = '
'; - $can_edit = Auth::user()->hasPermission('edit_all') || (isset($model->user_id) && Auth::user()->id == $model->user_id); + $can_edit = Auth::user()->hasPermission('edit_' . $datatable->entityType) || (isset($model->user_id) && Auth::user()->id == $model->user_id); if (property_exists($model, 'is_deleted') && $model->is_deleted) { $str .= ''; diff --git a/app/Services/ExpenseService.php b/app/Services/ExpenseService.php index 58eec8551075..8f668a3193de 100644 --- a/app/Services/ExpenseService.php +++ b/app/Services/ExpenseService.php @@ -72,7 +72,7 @@ class ExpenseService extends BaseService { $query = $this->expenseRepo->find($search); - if (! Utils::hasPermission('view_all')) { + if (! Utils::hasPermission('view_expense')) { $query->where('expenses.user_id', '=', Auth::user()->id); } @@ -90,7 +90,7 @@ class ExpenseService extends BaseService $query = $this->expenseRepo->findVendor($vendorPublicId); - if (! Utils::hasPermission('view_all')) { + if (! Utils::hasPermission('view_vendor')) { $query->where('expenses.user_id', '=', Auth::user()->id); } @@ -108,7 +108,7 @@ class ExpenseService extends BaseService $query = $this->expenseRepo->findClient($clientPublicId); - if (! Utils::hasPermission('view_all')) { + if (! Utils::hasPermission('view_client')) { $query->where('expenses.user_id', '=', Auth::user()->id); } diff --git a/app/Services/InvoiceService.php b/app/Services/InvoiceService.php index dbaf86574a36..12ce230bb0c6 100644 --- a/app/Services/InvoiceService.php +++ b/app/Services/InvoiceService.php @@ -163,7 +163,7 @@ class InvoiceService extends BaseService $query = $this->invoiceRepo->getInvoices($accountId, $clientPublicId, $entityType, $search) ->where('invoices.invoice_type_id', '=', $entityType == ENTITY_QUOTE ? INVOICE_TYPE_QUOTE : INVOICE_TYPE_STANDARD); - if (! Utils::hasPermission('view_all')) { + if (! Utils::hasPermission('view_invoice')) { $query->where('invoices.user_id', '=', Auth::user()->id); } diff --git a/app/Services/PaymentService.php b/app/Services/PaymentService.php index 0e7ed3de7dc9..41343abbd3be 100644 --- a/app/Services/PaymentService.php +++ b/app/Services/PaymentService.php @@ -174,7 +174,7 @@ class PaymentService extends BaseService $datatable = new PaymentDatatable(true, $clientPublicId); $query = $this->paymentRepo->find($clientPublicId, $search); - if (! Utils::hasPermission('view_all')) { + if (! Utils::hasPermission('view_payment')) { $query->where('payments.user_id', '=', Auth::user()->id); } diff --git a/app/Services/ProductService.php b/app/Services/ProductService.php index 35a49830d77e..afbfe5faeaca 100644 --- a/app/Services/ProductService.php +++ b/app/Services/ProductService.php @@ -50,7 +50,7 @@ class ProductService extends BaseService $datatable = new ProductDatatable(true); $query = $this->productRepo->find($accountId, $search); - if (! Utils::hasPermission('view_all')) { + if (! Utils::hasPermission('view_product')) { $query->where('products.user_id', '=', Auth::user()->id); } diff --git a/app/Services/RecurringExpenseService.php b/app/Services/RecurringExpenseService.php index 8ee8265b8c43..cdc3f32df10c 100644 --- a/app/Services/RecurringExpenseService.php +++ b/app/Services/RecurringExpenseService.php @@ -73,7 +73,7 @@ class RecurringExpenseService extends BaseService { $query = $this->recurringExpenseRepo->find($search); - if (! Utils::hasPermission('view_all')) { + if (! Utils::hasPermission('view_expense')) { $query->where('recurring_expenses.user_id', '=', Auth::user()->id); } diff --git a/app/Services/RecurringInvoiceService.php b/app/Services/RecurringInvoiceService.php index 11d46c332f1d..222a616faba2 100644 --- a/app/Services/RecurringInvoiceService.php +++ b/app/Services/RecurringInvoiceService.php @@ -23,7 +23,7 @@ class RecurringInvoiceService extends BaseService $datatable = new RecurringInvoiceDatatable(true, $clientPublicId); $query = $this->invoiceRepo->getRecurringInvoices($accountId, $clientPublicId, $search); - if (! Utils::hasPermission('view_all')) { + if (! Utils::hasPermission('view_recurring_invoice')) { $query->where('invoices.user_id', '=', Auth::user()->id); } diff --git a/app/Services/TaskService.php b/app/Services/TaskService.php index 585795cc24f6..5187c23c58d5 100644 --- a/app/Services/TaskService.php +++ b/app/Services/TaskService.php @@ -52,7 +52,7 @@ class TaskService extends BaseService $query = $this->taskRepo->find($clientPublicId, $projectPublicId, $search); - if (! Utils::hasPermission('view_all')) { + if (! Utils::hasPermission('view_task')) { $query->where('tasks.user_id', '=', Auth::user()->id); } diff --git a/app/Services/VendorService.php b/app/Services/VendorService.php index 846d4be87ff0..ace003d4ffba 100644 --- a/app/Services/VendorService.php +++ b/app/Services/VendorService.php @@ -70,7 +70,7 @@ class VendorService extends BaseService $datatable = new VendorDatatable(); $query = $this->vendorRepo->find($search); - if (! Utils::hasPermission('view_all')) { + if (! Utils::hasPermission('view_vendor')) { $query->where('vendors.user_id', '=', Auth::user()->id); } diff --git a/database/migrations/2018_05_19_095124_add_json_permissions.php b/database/migrations/2018_05_19_095124_add_json_permissions.php new file mode 100644 index 000000000000..49f192806f73 --- /dev/null +++ b/database/migrations/2018_05_19_095124_add_json_permissions.php @@ -0,0 +1,114 @@ +longtext('permissionsV2'); + }); + $users = User::where('permissions', '!=', 0)->get(); + foreach($users as $user) { + $user->permissionsV2 = self::returnFormattedPermissions($user->permissions); + $user->save(); + } + + + Schema::table('users', function ($table) { + $table->dropColumn('permissions'); + }); + + Schema::table('users', function($table) + { + $table->renameColumn('permissionsV2', 'permissions'); + }); + } + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function ($table) { + $table->dropColumn('permissionsV2'); + }); + } + /** + * Transform permissions + * + * @return json_array + */ + public function returnFormattedPermissions($userPermission) { + $viewPermissionEntities = []; + $editPermissionEntities = []; + $createPermissionEntities = []; + + $permissionEntities = [ + 'proposal', + 'expense', + 'project', + 'vendor', + 'product', + 'task', + 'quote', + 'credit', + 'payment', + 'contact', + 'invoice', + 'client', + 'recurring_invoice', + 'reports', + ]; + foreach($permissionEntities as $entity) { + array_push($viewPermissionEntities, 'view_'.$entity); + array_push($editPermissionEntities, 'edit_'.$entity); + array_push($createPermissionEntities, 'create_'.$entity); + } + $returnPermissions = []; + if(array_key_exists('create_all', self::getPermissions($userPermission))) + $returnPermissions = array_merge($returnPermissions, $createPermissionEntities); + if(array_key_exists('edit_all', self::getPermissions($userPermission))) + $returnPermissions = array_merge($returnPermissions, $editPermissionEntities); + if(array_key_exists('view_all', self::getPermissions($userPermission))) + $returnPermissions = array_merge($returnPermissions, $viewPermissionEntities); + return json_encode($returnPermissions); + } + + + /** + * Expands the value of the permissions attribute. + * + * @param mixed $value + * + * @return mixed + */ + protected function getPermissions($value) + { + $permissions = []; + foreach (static::$all_permissions as $permission => $bitmask) { + if (($value & $bitmask) == $bitmask) { + $permissions[$permission] = $permission; + } + } + + return $permissions; + } + + /** + * @var array + */ + public static $all_permissions = [ + 'create_all' => 0b0001, + 'view_all' => 0b0010, + 'edit_all' => 0b0100, + ]; + +} \ No newline at end of file diff --git a/database/seeds/UserTableSeeder.php b/database/seeds/UserTableSeeder.php index 19e5bd276561..542564904ed1 100644 --- a/database/seeds/UserTableSeeder.php +++ b/database/seeds/UserTableSeeder.php @@ -65,6 +65,21 @@ class UserTableSeeder extends Seeder 'accepted_terms_version' => NINJA_TERMS_VERSION, ]); + $permissionsUser = User::create([ + 'first_name' => $faker->firstName, + 'last_name' => $faker->lastName, + 'email' => TEST_PERMISSIONS_USERNAME, + 'username' => TEST_PERMISSIONS_USERNAME, + 'account_id' => $account->id, + 'password' => Hash::make(TEST_PASSWORD), + 'registered' => true, + 'confirmed' => true, + 'notify_sent' => false, + 'notify_paid' => false, + 'is_admin' => 0, + 'accepted_terms_version' => NINJA_TERMS_VERSION, + ]); + $client = Client::create([ 'user_id' => $user->id, 'account_id' => $account->id, diff --git a/resources/views/accounts/product.blade.php b/resources/views/accounts/product.blade.php index a8ee804045e4..72d253082edf 100644 --- a/resources/views/accounts/product.blade.php +++ b/resources/views/accounts/product.blade.php @@ -60,6 +60,7 @@ @endif @endforeach + @if((!$product && Auth::user()->can('create', ENTITY_PRODUCT)) || ($product && Auth::user()->can('edit',[ENTITY_PRODUCT, $product])))
{!! Button::normal(trans('texts.cancel'))->large()->asLinkTo(HTMLUtils::previousUrl('/products'))->appendIcon(Icon::create('remove-circle')) !!} {!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!} @@ -70,7 +71,7 @@ ->dropup() !!} @endif
- + @endif {!! Former::close() !!} - + @if(Auth::user()->canCreateOrEdit(ENTITY_CLIENT))
{!! Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('/clients/' . ($client ? $client->public_id : '')))->appendIcon(Icon::create('remove-circle')) !!} {!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!}
- + @endif {!! Former::close() !!} @stop diff --git a/resources/views/credits/edit.blade.php b/resources/views/credits/edit.blade.php index 4297cf23070d..7aa5e67dbd0a 100644 --- a/resources/views/credits/edit.blade.php +++ b/resources/views/credits/edit.blade.php @@ -50,12 +50,12 @@ - + @if(Auth::user()->canCreateOrEdit(ENTITY_CREDIT, $credit))
{!! Button::normal(trans('texts.cancel'))->large()->asLinkTo(HTMLUtils::previousUrl('/credits'))->appendIcon(Icon::create('remove-circle')) !!} {!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!}
- + @endif {!! Former::close() !!} @if ($account->hasFeature(FEATURE_DOCUMENTS) && $account->invoice_embed_documents) @foreach ($invoice->documents as $document) diff --git a/resources/views/payments/edit.blade.php b/resources/views/payments/edit.blade.php index 679abda3a0fc..5c606e45b5c9 100644 --- a/resources/views/payments/edit.blade.php +++ b/resources/views/payments/edit.blade.php @@ -111,7 +111,7 @@ - + @if (Auth::user()->canCreateOrEdit(ENTITY_PAYMENT, $payment))
{!! Button::normal(trans('texts.cancel'))->appendIcon(Icon::create('remove-circle'))->asLinkTo(HTMLUtils::previousUrl('/payments'))->large() !!} @if (!$payment || !$payment->is_deleted) @@ -126,6 +126,7 @@ @endif
+ @endif @include('partials/refund_payment') diff --git a/resources/views/projects/edit.blade.php b/resources/views/projects/edit.blade.php index 5353c59e1681..0e369713a446 100644 --- a/resources/views/projects/edit.blade.php +++ b/resources/views/projects/edit.blade.php @@ -61,7 +61,7 @@ - + @if(Auth::user()->canCreateOrEdit(ENTITY_PROJECT)))
{!! Button::normal(trans('texts.cancel'))->large()->asLinkTo(HTMLUtils::previousUrl('/projects'))->appendIcon(Icon::create('remove-circle')) !!} {!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!} @@ -90,6 +90,7 @@ ->large() !!} @endif
+ @endif {!! Former::close() !!} diff --git a/resources/views/proposals/edit.blade.php b/resources/views/proposals/edit.blade.php index 74253396e079..7a1ded95f1a0 100644 --- a/resources/views/proposals/edit.blade.php +++ b/resources/views/proposals/edit.blade.php @@ -55,6 +55,7 @@ + @if(Auth::user()->canCreateOrEdit(ENTITY_PROPOSAL, $proposal))
{!! Button::normal(trans('texts.cancel')) ->appendIcon(Icon::create('remove-circle')) @@ -81,6 +82,7 @@ @endif
+ @endif {!! Former::close() !!} diff --git a/resources/views/reports/emails.blade.php b/resources/views/reports/emails.blade.php index b0b12fa07464..0c3cf728769d 100644 --- a/resources/views/reports/emails.blade.php +++ b/resources/views/reports/emails.blade.php @@ -30,7 +30,7 @@ - + @if(Auth::user()->canCreateOrEdit(ENTITY_VENDOR))
{!! Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('/vendors/' . ($vendor ? $vendor->public_id : '')))->appendIcon(Icon::create('remove-circle')) !!} {!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!}
- + @endif {!! Former::close() !!} @stop diff --git a/tests/_support/FunctionalTester.php b/tests/_support/FunctionalTester.php index 87e4f0234c27..f79720ff584c 100644 --- a/tests/_support/FunctionalTester.php +++ b/tests/_support/FunctionalTester.php @@ -28,7 +28,7 @@ class FunctionalTester extends \Codeception\Actor { //if ($I->loadSessionSnapshot('login')) return; $I->amOnPage('/login'); - $I->fillField(['name' => 'email'], Fixtures::get('username')); + $I->fillField(['name' => 'email'], Fixtures::get('permissions_username')); $I->fillField(['name' => 'password'], Fixtures::get('password')); $I->click('#loginButton'); diff --git a/tests/functional.suite.yml b/tests/functional.suite.yml index ceaf820abe76..48c576c93921 100644 --- a/tests/functional.suite.yml +++ b/tests/functional.suite.yml @@ -9,9 +9,13 @@ modules: enabled: - \Helper\Functional - PhpBrowser: - url: 'http://ninja.test:8000' + url: 'http://www.ninja.test:8000' curl: CURLOPT_RETURNTRANSFER: true - - Laravel5: - environment_file: '.env' - cleanup: false + - Db: + dsn: 'mysql:dbname=ninja;host=127.0.0.1;' + user: 'ninja' + password: 'ninja' + dump: tests/_data/dump.sql + disabled: + - Laravel5 diff --git a/tests/functional/PermissionsCest.php b/tests/functional/PermissionsCest.php new file mode 100644 index 000000000000..d7d631b2826a --- /dev/null +++ b/tests/functional/PermissionsCest.php @@ -0,0 +1,291 @@ +faker = Factory::create(); + $I->checkIfLogin($I); + + $this->entityArray = [ + 'proposal', + 'expense', + 'project', + 'vendor', + 'product', + 'task', + 'quote', + 'credit', + 'payment', + 'contact', + 'invoice', + 'client', + 'recurring_invoice', + 'reports', + ]; + + } + + public function setViewPermissions(FunctionalTester $I) + { + $I->wantTo('create a view only permission user'); + + $permissions = []; + + foreach($this->entityArray as $item) + array_push($permissions, 'view_' . $item); + + $I->updateInDatabase('users', + ['is_admin' => 0, + 'permissions' => json_encode(array_diff(array_values($permissions),[0])) + ], + ['email' => Fixtures::get('permissions_username')] + ); + } + + /* + * Test View Permissions + * + * See 200 response for an individual ENTITY record + * + */ + + + + + public function viewInvoice(FunctionalTester $I) + { + $I->amOnPage('/invoices/1'); + $I->seeResponseCodeIs(200); + } + + public function viewClient(FunctionalTester $I) + { + $I->amOnPage('/clients/1'); + $I->seeResponseCodeIs(200); + } + + public function viewProduct(FunctionalTester $I) + { + $I->amOnPage('/products/1'); + $I->seeResponseCodeIs(200); + } + + public function viewPayment(FunctionalTester $I) + { + $I->amOnPage('/payments/1'); + $I->seeResponseCodeIs(200); + } + + public function viewQuote(FunctionalTester $I) + { + $I->amOnPage('/invoices/1'); + $I->seeResponseCodeIs(200); + } + + public function viewRecurringInvoice(FunctionalTester $I) + { + $I->amOnPage('/recurring_invoices/1'); + $I->seeResponseCodeIs(200); + } + + public function viewCredit(FunctionalTester $I) + { + $I->amOnPage('/credits/1'); + $I->seeResponseCodeIs(200); + } + + public function viewProposal(FunctionalTester $I) + { + $I->amOnPage('/proposals/1'); + $I->seeResponseCodeIs(200); + } + + public function viewProject(FunctionalTester $I) + { + $I->amOnPage('/projects/1'); + $I->seeResponseCodeIs(200); + } + + public function viewTask(FunctionalTester $I) + { + $I->amOnPage('/tasks/1'); + $I->seeResponseCodeIs(200); + } + + public function viewExpense(FunctionalTester $I) + { + $I->amOnPage('/expenses/1'); + $I->seeResponseCodeIs(200); + } + + public function viewVendor(FunctionalTester $I) + { + $I->amOnPage('/vendors/1'); + $I->seeResponseCodeIs(200); + } + + /* + * Test view permissions for lists + */ + + + public function viewInvoices(FunctionalTester $I) + { + $I->amOnPage('/invoices/'); + $I->seeResponseCodeIs(200); + } + + public function viewClients(FunctionalTester $I) + { + $I->amOnPage('/clients/'); + $I->seeResponseCodeIs(200); + } + + public function viewProducts(FunctionalTester $I) + { + $I->amOnPage('/products/'); + $I->seeResponseCodeIs(200); + } + + public function viewPayments(FunctionalTester $I) + { + $I->amOnPage('/payments/'); + $I->seeResponseCodeIs(200); + } + + public function viewQuotes(FunctionalTester $I) + { + $I->amOnPage('/invoices/'); + $I->seeResponseCodeIs(200); + } + + public function viewRecurringInvoices(FunctionalTester $I) + { + $I->amOnPage('/recurring_invoices/'); + $I->seeResponseCodeIs(200); + } + + public function viewCredits(FunctionalTester $I) + { + $I->amOnPage('/credits/'); + $I->seeResponseCodeIs(200); + } + + public function viewProposals(FunctionalTester $I) + { + $I->amOnPage('/proposals/'); + $I->seeResponseCodeIs(200); + } + + public function viewProjects(FunctionalTester $I) + { + $I->amOnPage('/projects/'); + $I->seeResponseCodeIs(200); + } + + public function viewTasks(FunctionalTester $I) + { + $I->amOnPage('/tasks/'); + $I->seeResponseCodeIs(200); + } + + public function viewExpenses(FunctionalTester $I) + { + $I->amOnPage('/expenses/'); + $I->seeResponseCodeIs(200); + } + + public function viewVendors(FunctionalTester $I) + { + $I->amOnPage('/vendors/'); + $I->seeResponseCodeIs(200); + } + + /* + * Test Create permissions when only VIEW enabled + */ + + public function createInvoice(FunctionalTester $I) + { + $I->amOnPage('/invoices/create'); + $I->seeResponseCodeIs(403); + } + + public function createClient(FunctionalTester $I) + { + $I->amOnPage('/clients/create'); + $I->seeResponseCodeIs(403); + } + + public function createProduct(FunctionalTester $I) + { + $I->amOnPage('/products/create'); + $I->seeResponseCodeIs(403); + } + + public function createPayment(FunctionalTester $I) + { + $I->amOnPage('/payments/create'); + $I->seeResponseCodeIs(403); + } + + public function createQuote(FunctionalTester $I) + { + $I->amOnPage('/invoices/create'); + $I->seeResponseCodeIs(403); + } + + public function createRecurringInvoice(FunctionalTester $I) + { + $I->amOnPage('/recurring_invoices/create'); + $I->seeResponseCodeIs(403); + } + + public function createCredit(FunctionalTester $I) + { + $I->amOnPage('/credits/create'); + $I->seeResponseCodeIs(403); + } + + public function createProposal(FunctionalTester $I) + { + $I->amOnPage('/proposals/create'); + $I->seeResponseCodeIs(403); + } + + public function createProject(FunctionalTester $I) + { + $I->amOnPage('/projects/create'); + $I->seeResponseCodeIs(403); + } + + public function createTask(FunctionalTester $I) + { + $I->amOnPage('/tasks/create'); + $I->seeResponseCodeIs(403); + } + + public function createExpense(FunctionalTester $I) + { + $I->amOnPage('/expenses/create'); + $I->seeResponseCodeIs(403); + } + + public function createVendor(FunctionalTester $I) + { + $I->amOnPage('/vendors/create'); + $I->seeResponseCodeIs(403); + } + +} \ No newline at end of file