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
This commit is contained in:
David Bomba 2018-06-07 20:08:34 +10:00 committed by GitHub
parent 4434477c5d
commit a9f2d0d855
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 814 additions and 287 deletions

View File

@ -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

View File

@ -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);

View File

@ -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 {

View File

@ -67,4 +67,5 @@ class BaseController extends Controller
exit;
}
}

View File

@ -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 = [

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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 = [

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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('/');
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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()) {

View File

@ -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));
},
],
[

View File

@ -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) . '<span '.Utils::getEntityRowClass($model).'/>';
if(Auth::user()->can('view', [ENTITY_CLIENT, $model]))
return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id) . '<span '.Utils::getEntityRowClass($model).'/>';
},
],
[
'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]);
},
],
[

View File

@ -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]);
},
],
];

View File

@ -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]);
},
],
[

View File

@ -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]);
},
],
];

View File

@ -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;
},

View File

@ -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]);
},
],
[

View File

@ -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]);
},
],
];

View File

@ -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]) ;
},
],
];

View File

@ -19,21 +19,22 @@ class ProposalSnippetDatatable extends EntityDatatable
function ($model) {
$icon = '<i class="fa fa-' . $model->icon . '"></i>&nbsp;&nbsp;';
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]);
},
],
];

View File

@ -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]);
},
],
];

View File

@ -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]);
},
],
];

View File

@ -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]);
},
],
[

View File

@ -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);
},
],
];

View File

@ -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);
},
],

View File

@ -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()

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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 ? '' : '<input type="checkbox" name="ids[]" value="' . $model->public_id
. '" ' . Utils::getEntityRowClass($model) . '>';
@ -65,7 +65,7 @@ class DatatableService
$hasAction = false;
$str = '<center style="min-width:100px">';
$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 .= '<button type="button" class="btn btn-sm btn-danger tr-status">'.trans('texts.deleted').'</button>';

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -0,0 +1,114 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Migrations\Migration;
use App\Models\User;
class AddJsonPermissions extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function ($table) {
$table->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,
];
}

View File

@ -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,

View File

@ -60,6 +60,7 @@
</div>
@endif
@endforeach
@if((!$product && Auth::user()->can('create', ENTITY_PRODUCT)) || ($product && Auth::user()->can('edit',[ENTITY_PRODUCT, $product])))
<center class="buttons">
{!! 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
</center>
@endif
{!! Former::close() !!}
<script type="text/javascript">

View File

@ -469,12 +469,12 @@
</script>
@if(Auth::user()->canCreateOrEdit(ENTITY_CLIENT))
<center class="buttons">
{!! 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')) !!}
</center>
@endif
{!! Former::close() !!}
</div>
@stop

View File

@ -50,12 +50,12 @@
</div>
</div>
@if(Auth::user()->canCreateOrEdit(ENTITY_CREDIT, $credit))
<center class="buttons">
{!! 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')) !!}
</center>
@endif
{!! Former::close() !!}
<script type="text/javascript">

View File

@ -15,7 +15,7 @@
<script type="text/javascript">
@if (Auth::user()->hasPermission('view_all'))
@if (Auth::user()->hasPermission('admin'))
function loadChart(data) {
var ctx = document.getElementById('chart-canvas').getContext('2d');
if (window.myChart) {
@ -219,7 +219,7 @@
@else
<div class="col-md-10">
@endif
@if (Auth::user()->hasPermission('view_all'))
@if (Auth::user()->hasPermission('admin'))
<div class="pull-right">
@if (count($currencies) > 1)
<div id="currency-btn-group" class="btn-group" role="group" style="border: 1px solid #ccc;">
@ -370,7 +370,7 @@
</div>
</div>
@if (Auth::user()->hasPermission('view_all'))
@if (Auth::user()->hasPermission('admin'))
<div class="row">
<div class="col-md-12">
<div id="progress-div" class="progress">
@ -441,7 +441,7 @@
@foreach ($payments as $payment)
<tr>
<td>{!! \App\Models\Invoice::calcLink($payment) !!}</td>
@can('viewByOwner', [ENTITY_CLIENT, $payment->client_user_id])
@can('view', [ENTITY_CLIENT, $payment])
<td>{!! link_to('/clients/'.$payment->client_public_id, trim($payment->client_name) ?: (trim($payment->first_name . ' ' . $payment->last_name) ?: $payment->email)) !!}</td>
@else
<td>{{ trim($payment->client_name) ?: (trim($payment->first_name . ' ' . $payment->last_name) ?: $payment->email) }}</td>
@ -478,7 +478,7 @@
@if ($invoice->invoice_type_id == INVOICE_TYPE_STANDARD)
<tr>
<td>{!! \App\Models\Invoice::calcLink($invoice) !!}</td>
@can('viewByOwner', [ENTITY_CLIENT, $invoice->client_user_id])
@can('view', [ENTITY_CLIENT, $invoice])
<td>{!! link_to('/clients/'.$invoice->client_public_id, trim($invoice->client_name) ?: (trim($invoice->first_name . ' ' . $invoice->last_name) ?: $invoice->email)) !!}</td>
@else
<td>{{ trim($invoice->client_name) ?: (trim($invoice->first_name . ' ' . $invoice->last_name) ?: $invoice->email) }}</td>
@ -513,7 +513,7 @@
@if ($invoice->invoice_type_id == INVOICE_TYPE_STANDARD)
<tr>
<td>{!! \App\Models\Invoice::calcLink($invoice) !!}</td>
@can('viewByOwner', [ENTITY_CLIENT, $invoice->client_user_id])
@can('view', [ENTITY_CLIENT, $invoice])
<td>{!! link_to('/clients/'.$invoice->client_public_id, trim($invoice->client_name) ?: (trim($invoice->first_name . ' ' . $invoice->last_name) ?: $invoice->email)) !!}</td>
@else
<td>{{ trim($invoice->client_name) ?: (trim($invoice->first_name . ' ' . $invoice->last_name) ?: $invoice->email) }}</td>

View File

@ -0,0 +1 @@
you do not have permission to view this resource

View File

@ -411,7 +411,7 @@
])
@endforeach
@endif
@if (Auth::user()->hasPermission('view_all'))
@if (Auth::user()->hasPermission('view_reports'))
@include('partials.navigation_option', ['option' => 'reports'])
@endif
@include('partials.navigation_option', ['option' => 'settings'])

View File

@ -138,7 +138,9 @@
<div class="form-group" style="margin-bottom: 8px">
<div class="col-lg-8 col-sm-8 col-lg-offset-4 col-sm-offset-4">
@can('create', $invoice->client)
<a id="createClientLink" class="pointer" data-bind="click: $root.showClientForm, html: $root.clientLinkText"></a>
@endcan
<span data-bind="visible: $root.invoice().client().public_id() > 0" style="display:none">|
<a data-bind="attr: {href: '{{ url('/clients') }}/' + $root.invoice().client().public_id()}" target="_blank">{{ trans('texts.view_client') }}</a>
</span>
@ -1026,11 +1028,13 @@
});
// If no clients exists show the client form when clicking on the client select input
@can('create', $invoice->client);
if (clients.length === 0) {
$('.client_select input.form-control').on('click', function() {
model.showClientForm();
});
}
@endcan
$('#invoice_footer, #terms, #public_notes, #invoice_number, #invoice_date, #due_date, #partial_due_date, #start_date, #po_number, #discount, #currency_id, #invoice_design_id, #recurring, #is_amount_discount, #partial, #custom_text_value1, #custom_text_value2').change(function() {
$('#downloadPdfButton').attr('disabled', true);
@ -1341,8 +1345,13 @@
return false;
}
if (!isSaveValid()) {
model.showClientForm();
return false;
@if(Auth::user()->can('create', ENTITY_CLIENT))
model.showClientForm();
return false;
@else
showPermissionErrorModal();
@endif
}
@if ($account->auto_email_invoice)
@ -1436,8 +1445,14 @@
function submitAction(value) {
if (!isSaveValid()) {
model.showClientForm();
return false;
@if(Auth::user()->can('create', ENTITY_CLIENT))
model.showClientForm();
return false;
@else
showPermissionErrorModal();
@endif
}
$('#action').val(value);
@ -1725,6 +1740,10 @@
refreshPDF(true);
}
function showPermissionErrorModal() {
swal({!! json_encode(trans('texts.create_client')) !!});
}
</script>
@if ($account->hasFeature(FEATURE_DOCUMENTS) && $account->invoice_embed_documents)
@foreach ($invoice->documents as $document)

View File

@ -111,7 +111,7 @@
</div>
</div>
@if (Auth::user()->canCreateOrEdit(ENTITY_PAYMENT, $payment))
<center class="buttons">
{!! 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
</center>
@endif
@include('partials/refund_payment')

View File

@ -61,7 +61,7 @@
</div>
</div>
@if(Auth::user()->canCreateOrEdit(ENTITY_PROJECT)))
<center class="buttons">
{!! 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
</center>
@endif
{!! Former::close() !!}

View File

@ -55,6 +55,7 @@
</div>
</div>
@if(Auth::user()->canCreateOrEdit(ENTITY_PROPOSAL, $proposal))
<center class="buttons">
{!! Button::normal(trans('texts.cancel'))
->appendIcon(Icon::create('remove-circle'))
@ -81,6 +82,7 @@
@endif
</center>
@endif
{!! Former::close() !!}

View File

@ -30,7 +30,7 @@
<script type="text/javascript">
@if (Auth::user()->hasPermission('view_all'))
@if (Auth::user()->hasPermission('view_reports'))
function loadChart(data) {
var ctx = document.getElementById('chart-canvas').getContext('2d');
if (window.myChart) {
@ -239,7 +239,7 @@
<div class="row">
<div class="col-md-12">
@if (Auth::user()->hasPermission('view_all'))
@if (Auth::user()->hasPermission('view_reports'))
<div id="progress-div" class="progress">
<div class="progress-bar progress-bar-striped active" role="progressbar"
aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"></div>

View File

@ -38,7 +38,7 @@
@stop
@section('top-right')
@if (config('services.postmark') && auth()->user()->hasPermission('view_all') && auth()->user()->hasPermission('view_all'))
@if (config('services.postmark') && auth()->user()->hasPermission('view_reports'))
{!! Button::normal(trans('texts.emails'))
->asLinkTo(url('/reports/emails'))
->appendIcon(Icon::create('envelope')) !!}

View File

@ -13,9 +13,6 @@
@if ($user)
{!! Former::populate($user) !!}
{{ Former::populateField('is_admin', intval($user->is_admin)) }}
{{ Former::populateField('permissions[create_all]', intval($user->hasPermission('create'))) }}
{{ Former::populateField('permissions[view_all]', intval($user->hasPermission('view_all'))) }}
{{ Former::populateField('permissions[edit_all]', intval($user->hasPermission('edit_all'))) }}
@endif
<div style="display:none">
@ -55,24 +52,35 @@
->value(1)
->text(trans('texts.administrator'))
->help(trans('texts.administrator_help')) !!}
{!! Former::checkbox('permissions[create_all]')
->value('create_all')
->label('&nbsp;')
->id('permissions_create_all')
->text(trans('texts.user_create_all'))
->help(trans('texts.create_all_help')) !!}
{!! Former::checkbox('permissions[view_all]')
->value('view_all')
->label('&nbsp;')
->id('permissions_view_all')
->text(trans('texts.user_view_all'))
->help(trans('texts.view_all_help')) !!}
{!! Former::checkbox('permissions[edit_all]')
->value('edit_all')
->label('&nbsp;')
->id('permissions_edit_all')
->text(trans('texts.user_edit_all'))
->help(trans('texts.edit_all_help')) !!}
@foreach (json_decode(PERMISSION_ENTITIES,1) as $permissionEntity)
<?php
if($user)
$permissions = json_decode($user->permissions,1);
else
$permissions = [];
?>
{!! Former::checkboxes('permissions[]')
->label(ucfirst($permissionEntity))
->checkboxes([
trans('texts.create') => ['id'=> 'create_' . $permissionEntity,
'name' => 'permissions[create_' . $permissionEntity . ']',
'value' => 'create_' . $permissionEntity . '',
'checked' => is_array($permissions) && in_array('create_' . $permissionEntity, $permissions, FALSE) ? true : false],
trans('texts.view') => ['id'=> 'view_' . $permissionEntity,
'name' => 'permissions[view_' . $permissionEntity . ']',
'value' => 'view_' . $permissionEntity . '',
'checked' => is_array($permissions) && in_array('view_' . $permissionEntity, $permissions, FALSE) ? true : false],
trans('texts.edit') => ['id'=> 'edit_' . $permissionEntity,
'name' => 'permissions[edit_' . $permissionEntity . ']',
'value' => 'edit_' . $permissionEntity . '',
'checked' => is_array($permissions) && in_array('edit_' . $permissionEntity, $permissions, FALSE) ? true : false],
]) !!}
@endforeach
</div>
</div>
@ -97,6 +105,8 @@
@stop
@section('onReady')
//start legacy
$('#first_name').focus();
$('#is_admin, #permissions_view_all').change(fixCheckboxes);
function fixCheckboxes(){
@ -109,4 +119,41 @@
if(!viewChecked)$('#permissions_edit_all').prop('checked',false)
}
fixCheckboxes();
//end legacy
/*
*
* Iterate over all permission checkboxes and ensure VIEW/EDIT
* combinations are enabled/disabled depending on VIEW state.
*
*/
$("input[type='checkbox'][id^='view_']").each(function() {
var entity = $(this).attr('id').split("_")[1].replace("]",""); //get entity name
$('#edit_' + entity).prop('disabled', !$('#view_' + entity).is(':checked')); //set state of edit checkbox
});
/*
*
* Checks state of View/Edit checkbox, will enable/disable check/uncheck
* dependent on state of VIEW permission.
*
*/
$("input[type='checkbox'][id^='view_']").change(function(){
var entity = $(this).attr('id').split("_")[1].replace("]",""); //get entity name
$('#edit_' + entity).prop('disabled', !$('#view_' + entity).is(':checked')); //set state of edit checkbox
if(!$('#view_' + entity).is(':checked')) {
$('#edit_' + entity).prop('checked', false); //remove checkbox value from edit dependant on View state.
}
});
@stop

View File

@ -202,12 +202,12 @@
</script>
@if(Auth::user()->canCreateOrEdit(ENTITY_VENDOR))
<center class="buttons">
{!! 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')) !!}
</center>
@endif
{!! Former::close() !!}
</div>
@stop

View File

@ -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');

View File

@ -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

View File

@ -0,0 +1,291 @@
<?php
use Faker\Factory;
use Codeception\Util\Fixtures;
class PermissionsCest
{
/**
* @var \Faker\Generator
*/
private $faker;
private $entityArray;
public function _before(FunctionalTester $I)
{
$this->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);
}
}