diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index abefe0b5f7..755932691d 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -137,8 +137,6 @@ class AccountController extends BaseController if ($section == ACCOUNT_COMPANY_DETAILS) { return self::showCompanyDetails(); - } elseif ($section == ACCOUNT_USER_DETAILS) { - return self::showUserDetails(); } elseif ($section == ACCOUNT_LOCALIZATION) { return self::showLocalization(); } elseif ($section == ACCOUNT_PAYMENTS) { @@ -232,7 +230,7 @@ class AccountController extends BaseController return View::make('accounts.details', $data); } - private function showUserDetails() + public function showUserDetails() { $oauthLoginUrls = []; foreach (AuthService::$providers as $provider) { @@ -467,8 +465,6 @@ class AccountController extends BaseController { if ($section === ACCOUNT_COMPANY_DETAILS) { return AccountController::saveDetails(); - } elseif ($section === ACCOUNT_USER_DETAILS) { - return AccountController::saveUserDetails(); } elseif ($section === ACCOUNT_LOCALIZATION) { return AccountController::saveLocalization(); } elseif ($section === ACCOUNT_NOTIFICATIONS) { @@ -839,7 +835,7 @@ class AccountController extends BaseController return Redirect::to('settings/'.ACCOUNT_COMPANY_DETAILS); } - private function saveUserDetails() + public function saveUserDetails() { $user = Auth::user(); $rules = ['email' => 'email|required|unique:users,email,'.$user->id.',id']; diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php index ee7f62686f..5124097636 100644 --- a/app/Http/Controllers/BaseController.php +++ b/app/Http/Controllers/BaseController.php @@ -1,10 +1,14 @@ layout = View::make($this->layout); } } - - /* - public function __construct() - { - $this->beforeFilter('csrf', array('on' => array('post', 'delete', 'put'))); + + protected function checkViewPermission($object, &$response = null){ + if(!$object->canView()){ + $response = response('Unauthorized.', 401); + return false; + } + return true; + } + + protected function checkEditPermission($object, &$response = null){ + if(!$object->canEdit()){ + $response = response('Unauthorized.', 401); + return false; + } + return true; + } + + protected function checkCreatePermission(&$response = null){ + if(!call_user_func(array($this->model, 'canCreate'))){ + $response = response('Unauthorized.', 401); + return false; + } + return true; + } + + protected function checkUpdatePermission($input, &$response = null){ + $creating = empty($input['public_id']) || $input['public_id'] == '-1'; + + if($creating){ + return $this->checkCreatePermission($response); + } + else{ + $object = call_user_func(array($this->model, 'scope'), $input['public_id'])->firstOrFail(); + return $this->checkEditPermission($object, $response); + } } - */ } diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php index 163d75f622..7e1c01de9e 100644 --- a/app/Http/Controllers/ClientController.php +++ b/app/Http/Controllers/ClientController.php @@ -20,6 +20,9 @@ use App\Models\Size; use App\Models\PaymentTerm; use App\Models\Industry; use App\Models\Currency; +use App\Models\Payment; +use App\Models\Credit; +use App\Models\Expense; use App\Models\Country; use App\Models\Task; use App\Ninja\Repositories\ClientRepository; @@ -32,6 +35,7 @@ class ClientController extends BaseController { protected $clientService; protected $clientRepo; + protected $model = 'App\Models\Client'; public function __construct(ClientRepository $clientRepo, ClientService $clientService) { @@ -77,7 +81,13 @@ class ClientController extends BaseController */ public function store(CreateClientRequest $request) { - $client = $this->clientService->save($request->input()); + $data = $request->input(); + + if(!$this->checkUpdatePermission($data, $response)){ + return $response; + } + + $client = $this->clientService->save($data); Session::flash('message', trans('texts.created_client')); @@ -93,22 +103,36 @@ class ClientController extends BaseController public function show($publicId) { $client = Client::withTrashed()->scope($publicId)->with('contacts', 'size', 'industry')->firstOrFail(); + + if(!$this->checkViewPermission($client, $response)){ + return $response; + } + Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT); - $actionLinks = [ - ['label' => trans('texts.new_task'), 'url' => '/tasks/create/'.$client->public_id] - ]; - - if (Utils::isPro()) { - array_push($actionLinks, ['label' => trans('texts.new_quote'), 'url' => '/quotes/create/'.$client->public_id]); + $actionLinks = []; + if(Task::canCreate()){ + $actionLinks[] = ['label' => trans('texts.new_task'), 'url' => '/tasks/create/'.$client->public_id]; + } + if (Utils::isPro() && Invoice::canCreate()) { + $actionLinks[] = ['label' => trans('texts.new_quote'), 'url' => '/quotes/create/'.$client->public_id]; + } + + if(!empty($actionLinks)){ + $actionLinks[] = \DropdownButton::DIVIDER; + } + + if(Payment::canCreate()){ + $actionLinks[] = ['label' => trans('texts.enter_payment'), 'url' => '/payments/create/'.$client->public_id]; + } + + if(Credit::canCreate()){ + $actionLinks[] = ['label' => trans('texts.enter_credit'), 'url' => '/credits/create/'.$client->public_id]; + } + + if(Expense::canCreate()){ + $actionLinks[] = ['label' => trans('texts.enter_expense'), 'url' => '/expenses/create/0/'.$client->public_id]; } - - array_push($actionLinks, - \DropdownButton::DIVIDER, - ['label' => trans('texts.enter_payment'), 'url' => '/payments/create/'.$client->public_id], - ['label' => trans('texts.enter_credit'), 'url' => '/credits/create/'.$client->public_id], - ['label' => trans('texts.enter_expense'), 'url' => '/expenses/create/0/'.$client->public_id] - ); $data = array( 'actionLinks' => $actionLinks, @@ -132,6 +156,10 @@ class ClientController extends BaseController */ public function create() { + if(!$this->checkCreatePermission($response)){ + return $response; + } + 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"]); } @@ -157,6 +185,11 @@ class ClientController extends BaseController public function edit($publicId) { $client = Client::scope($publicId)->with('contacts')->firstOrFail(); + + if(!$this->checkEditPermission($client, $response)){ + return $response; + } + $data = [ 'client' => $client, 'method' => 'PUT', @@ -199,7 +232,13 @@ class ClientController extends BaseController */ public function update(UpdateClientRequest $request) { - $client = $this->clientService->save($request->input()); + $data = $request->input(); + + if(!$this->checkUpdatePermission($data, $response)){ + return $response; + } + + $client = $this->clientService->save($data); Session::flash('message', trans('texts.updated_client')); diff --git a/app/Http/Controllers/CreditController.php b/app/Http/Controllers/CreditController.php index 5a4b3011ad..26085c3d6b 100644 --- a/app/Http/Controllers/CreditController.php +++ b/app/Http/Controllers/CreditController.php @@ -17,10 +17,11 @@ class CreditController extends BaseController { protected $creditRepo; protected $creditService; + protected $model = 'App\Models\Credit'; public function __construct(CreditRepository $creditRepo, CreditService $creditService) { - //parent::__construct(); + // parent::__construct(); $this->creditRepo = $creditRepo; $this->creditService = $creditService; @@ -56,6 +57,10 @@ class CreditController extends BaseController public function create($clientPublicId = 0) { + if(!$this->checkCreatePermission($response)){ + return $response; + } + $data = array( 'clientPublicId' => Input::old('client') ? Input::old('client') : $clientPublicId, //'invoicePublicId' => Input::old('invoice') ? Input::old('invoice') : $invoicePublicId, @@ -72,6 +77,11 @@ class CreditController extends BaseController public function edit($publicId) { $credit = Credit::scope($publicId)->firstOrFail(); + + if(!$this->checkEditPermission($credit, $response)){ + return $response; + } + $credit->credit_date = Utils::fromSqlDate($credit->credit_date); $data = array( diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index 1e26fd4a71..fb42733162 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -63,9 +63,15 @@ class DashboardController extends BaseController ->get(); $activities = Activity::where('activities.account_id', '=', Auth::user()->account_id) + ->where('activities.activity_type_id', '>', 0); + + if(!Auth::user()->hasPermission('view_all')){ + $user_id = Auth::user()->id; + $activities = $activities->where('activities.user_id', '=', $user_id); + } + + $activities = $activities->orderBy('activities.created_at', 'desc') ->with('client.contacts', 'user', 'invoice', 'payment', 'credit', 'account') - ->where('activity_type_id', '>', 0) - ->orderBy('created_at', 'desc') ->take(50) ->get(); @@ -81,8 +87,14 @@ class DashboardController extends BaseController ->where('invoices.is_deleted', '=', false) ->where('invoices.deleted_at', '=', null) ->where('contacts.is_primary', '=', true) - ->where('invoices.due_date', '<', date('Y-m-d')) - ->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'is_quote']) + ->where('invoices.due_date', '<', date('Y-m-d')); + + if(!Auth::user()->hasPermission('view_all')){ + $user_id = Auth::user()->id; + $pastDue = $pastDue->where('invoices.user_id', '=', $user_id); + } + + $pastDue = $pastDue->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'is_quote']) ->orderBy('invoices.due_date', 'asc') ->take(50) ->get(); @@ -100,9 +112,15 @@ class DashboardController extends BaseController ->where('invoices.is_deleted', '=', false) ->where('contacts.is_primary', '=', true) ->where('invoices.due_date', '>=', date('Y-m-d')) - ->orderBy('invoices.due_date', 'asc') - ->take(50) - ->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'is_quote']) + ->orderBy('invoices.due_date', 'asc'); + + if(!Auth::user()->hasPermission('view_all')){ + $user_id = Auth::user()->id; + $upcoming = $upcoming->where('invoices.user_id', '=', $user_id); + } + + $upcoming = $upcoming->take(50) + ->select(['invoices.due_date', 'invoices.balance', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id', 'is_quote']) ->get(); $payments = DB::table('payments') @@ -114,8 +132,14 @@ class DashboardController extends BaseController ->where('invoices.is_deleted', '=', false) ->where('clients.is_deleted', '=', false) ->where('contacts.deleted_at', '=', null) - ->where('contacts.is_primary', '=', true) - ->select(['payments.payment_date', 'payments.amount', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id']) + ->where('contacts.is_primary', '=', true); + + if(!Auth::user()->hasPermission('view_all')){ + $user_id = Auth::user()->id; + $payments = $payments->where('payments.user_id', '=', $user_id); + } + + $payments = $payments->select(['payments.payment_date', 'payments.amount', 'invoices.public_id', 'invoices.invoice_number', 'clients.name as client_name', 'contacts.email', 'contacts.first_name', 'contacts.last_name', 'clients.currency_id', 'clients.public_id as client_public_id', 'clients.user_id as client_user_id']) ->orderBy('payments.payment_date', 'desc') ->take(50) ->get(); diff --git a/app/Http/Controllers/ExpenseController.php b/app/Http/Controllers/ExpenseController.php index 2d4294d540..eb9fa0c437 100644 --- a/app/Http/Controllers/ExpenseController.php +++ b/app/Http/Controllers/ExpenseController.php @@ -25,10 +25,11 @@ class ExpenseController extends BaseController // Expenses protected $expenseRepo; protected $expenseService; + protected $model = 'App\Models\Expense'; public function __construct(ExpenseRepository $expenseRepo, ExpenseService $expenseService) { - //parent::__construct(); + // parent::__construct(); $this->expenseRepo = $expenseRepo; $this->expenseService = $expenseService; @@ -70,6 +71,10 @@ class ExpenseController extends BaseController public function create($vendorPublicId = null, $clientPublicId = null) { + if(!$this->checkCreatePermission($response)){ + return $response; + } + if($vendorPublicId != 0) { $vendor = Vendor::scope($vendorPublicId)->with('vendorcontacts')->firstOrFail(); } else { @@ -95,6 +100,11 @@ class ExpenseController extends BaseController public function edit($publicId) { $expense = Expense::scope($publicId)->firstOrFail(); + + if(!$this->checkEditPermission($expense, $response)){ + return $response; + } + $expense->expense_date = Utils::fromSqlDate($expense->expense_date); $actions = []; diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index fbbdc7c08e..8c31cce798 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -34,10 +34,11 @@ class InvoiceController extends BaseController protected $clientRepo; protected $invoiceService; protected $recurringInvoiceService; + protected $model = 'App\Models\Invoice'; public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService, RecurringInvoiceService $recurringInvoiceService) { - //parent::__construct(); + // parent::__construct(); $this->mailer = $mailer; $this->invoiceRepo = $invoiceRepo; @@ -90,6 +91,11 @@ class InvoiceController extends BaseController ->with('invitations', 'account.country', 'client.contacts', 'client.country', 'invoice_items') ->withTrashed() ->firstOrFail(); + + if(!$this->checkEditPermission($invoice, $response)){ + return $response; + } + $entityType = $invoice->getEntityType(); $contactIds = DB::table('invitations') @@ -206,7 +212,11 @@ class InvoiceController extends BaseController public function create($clientPublicId = 0, $isRecurring = false) { - $account = Auth::user()->account; + if(!$this->checkCreatePermission($response)){ + return $response; + } + + $account = Auth::user()->account; $entityType = $isRecurring ? ENTITY_RECURRING_INVOICE : ENTITY_INVOICE; $clientId = null; @@ -335,10 +345,16 @@ class InvoiceController extends BaseController */ public function store(SaveInvoiceWithClientRequest $request) { + $data = $request->input(); + + if(!$this->checkUpdatePermission($data, $response)){ + return $response; + } + $action = Input::get('action'); $entityType = Input::get('entityType'); - $invoice = $this->invoiceService->save($request->input()); + $invoice = $this->invoiceService->save($data, true); $entityType = $invoice->getEntityType(); $message = trans("texts.created_{$entityType}"); @@ -369,10 +385,16 @@ class InvoiceController extends BaseController */ public function update(SaveInvoiceWithClientRequest $request) { + $data = $request->input(); + + if(!$this->checkUpdatePermission($data, $response)){ + return $response; + } + $action = Input::get('action'); $entityType = Input::get('entityType'); - $invoice = $this->invoiceService->save($request->input()); + $invoice = $this->invoiceService->save($data, true); $entityType = $invoice->getEntityType(); $message = trans("texts.updated_{$entityType}"); Session::flash('message', $message); diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php index 24c4005f1d..7e675d023f 100644 --- a/app/Http/Controllers/PaymentController.php +++ b/app/Http/Controllers/PaymentController.php @@ -30,9 +30,11 @@ use App\Http\Requests\UpdatePaymentRequest; class PaymentController extends BaseController { + protected $model = 'App\Models\Payment'; + public function __construct(PaymentRepository $paymentRepo, InvoiceRepository $invoiceRepo, AccountRepository $accountRepo, ContactMailer $contactMailer, PaymentService $paymentService) { - //parent::__construct(); + // parent::__construct(); $this->paymentRepo = $paymentRepo; $this->invoiceRepo = $invoiceRepo; @@ -66,6 +68,10 @@ class PaymentController extends BaseController public function create($clientPublicId = 0, $invoicePublicId = 0) { + if(!$this->checkCreatePermission($response)){ + return $response; + } + $invoices = Invoice::scope() ->where('is_recurring', '=', false) ->where('is_quote', '=', false) @@ -92,6 +98,11 @@ class PaymentController extends BaseController public function edit($publicId) { $payment = Payment::scope($publicId)->firstOrFail(); + + if(!$this->checkEditPermission($payment, $response)){ + return $response; + } + $payment->payment_date = Utils::fromSqlDate($payment->payment_date); $data = array( @@ -573,6 +584,11 @@ class PaymentController extends BaseController public function store(CreatePaymentRequest $request) { $input = $request->input(); + + if(!$this->checkUpdatePermission($input, $response)){ + return $response; + } + $input['invoice_id'] = Invoice::getPrivateId($input['invoice']); $input['client_id'] = Client::getPrivateId($input['client']); $payment = $this->paymentRepo->save($input); @@ -590,6 +606,11 @@ class PaymentController extends BaseController public function update(UpdatePaymentRequest $request) { $input = $request->input(); + + if(!$this->checkUpdatePermission($input, $response)){ + return $response; + } + $payment = $this->paymentRepo->save($input); Session::flash('message', trans('texts.updated_payment')); diff --git a/app/Http/Controllers/QuoteController.php b/app/Http/Controllers/QuoteController.php index 882acb039e..7777c5a9d0 100644 --- a/app/Http/Controllers/QuoteController.php +++ b/app/Http/Controllers/QuoteController.php @@ -33,10 +33,11 @@ class QuoteController extends BaseController protected $invoiceRepo; protected $clientRepo; protected $invoiceService; + protected $model = 'App\Models\Invoice'; public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService) { - //parent::__construct(); + // parent::__construct(); $this->mailer = $mailer; $this->invoiceRepo = $invoiceRepo; @@ -78,6 +79,10 @@ class QuoteController extends BaseController public function create($clientPublicId = 0) { + if(!$this->checkCreatePermission($response)){ + return $response; + } + if (!Utils::isPro()) { return Redirect::to('/invoices/create'); } diff --git a/app/Http/Controllers/TaskController.php b/app/Http/Controllers/TaskController.php index e09ed50b4b..46178f09dd 100644 --- a/app/Http/Controllers/TaskController.php +++ b/app/Http/Controllers/TaskController.php @@ -22,10 +22,11 @@ class TaskController extends BaseController { protected $taskRepo; protected $taskService; + protected $model = 'App\Models\Task'; public function __construct(TaskRepository $taskRepo, InvoiceRepository $invoiceRepo, TaskService $taskService) { - //parent::__construct(); + // parent::__construct(); $this->taskRepo = $taskRepo; $this->invoiceRepo = $invoiceRepo; @@ -84,6 +85,9 @@ class TaskController extends BaseController */ public function create($clientPublicId = 0) { + if(!$this->checkCreatePermission($response)){ + return $response; + } $this->checkTimezone(); $data = [ @@ -113,6 +117,10 @@ class TaskController extends BaseController $task = Task::scope($publicId)->with('client', 'invoice')->withTrashed()->firstOrFail(); + if(!$this->checkEditPermission($task, $response)){ + return $response; + } + $actions = []; if ($task->invoice) { $actions[] = ['url' => URL::to("invoices/{$task->invoice->public_id}/edit"), 'label' => trans("texts.view_invoice")]; @@ -175,6 +183,12 @@ class TaskController extends BaseController private function save($publicId = null) { $action = Input::get('action'); + + $input = $request->input(); + + if(!$this->checkUpdatePermission($input, $response)){ + return $response; + } if (in_array($action, ['archive', 'delete', 'restore'])) { return self::bulk(); diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index ee3f9d6554..0e5a8dd70d 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -192,6 +192,8 @@ class UserController extends BaseController $user->last_name = trim(Input::get('last_name')); $user->username = trim(Input::get('email')); $user->email = trim(Input::get('email')); + $user->is_admin = boolval(Input::get('is_admin')); + $user->permissions = Input::get('permissions'); } else { $lastUser = User::withTrashed()->where('account_id', '=', Auth::user()->account_id) ->orderBy('public_id', 'DESC')->first(); @@ -202,10 +204,12 @@ class UserController extends BaseController $user->last_name = trim(Input::get('last_name')); $user->username = trim(Input::get('email')); $user->email = trim(Input::get('email')); + $user->is_admin = boolval(Input::get('is_admin')); $user->registered = true; $user->password = str_random(RANDOM_KEY_LENGTH); $user->confirmation_code = str_random(RANDOM_KEY_LENGTH); $user->public_id = $lastUser->public_id + 1; + $user->permissions = Input::get('permissions'); } $user->save(); diff --git a/app/Http/Controllers/VendorController.php b/app/Http/Controllers/VendorController.php index 5d25f29215..989246f824 100644 --- a/app/Http/Controllers/VendorController.php +++ b/app/Http/Controllers/VendorController.php @@ -30,6 +30,7 @@ class VendorController extends BaseController { protected $vendorService; protected $vendorRepo; + protected $model = 'App\Models\Vendor'; public function __construct(VendorRepository $vendorRepo, VendorService $vendorService) { @@ -76,7 +77,13 @@ class VendorController extends BaseController */ public function store(CreateVendorRequest $request) { - $vendor = $this->vendorService->save($request->input()); + $data = $request->input(); + + if(!$this->checkUpdatePermission($data, $response)){ + return $response; + } + + $vendor = $this->vendorService->save($data); Session::flash('message', trans('texts.created_vendor')); @@ -92,6 +99,11 @@ class VendorController extends BaseController public function show($publicId) { $vendor = Vendor::withTrashed()->scope($publicId)->with('vendorcontacts', 'size', 'industry')->firstOrFail(); + + if(!$this->checkViewPermission($vendor, $response)){ + return $response; + } + Utils::trackViewed($vendor->getDisplayName(), 'vendor'); $actionLinks = [ @@ -119,6 +131,10 @@ class VendorController extends BaseController */ public function create() { + if(!$this->checkCreatePermission($response)){ + return $response; + } + if (Vendor::scope()->count() > Auth::user()->getMaxNumVendors()) { return View::make('error', ['hideHeader' => true, 'error' => "Sorry, you've exceeded the limit of ".Auth::user()->getMaxNumVendors()." vendors"]); } @@ -144,6 +160,11 @@ class VendorController extends BaseController public function edit($publicId) { $vendor = Vendor::scope($publicId)->with('vendorcontacts')->firstOrFail(); + + if(!$this->checkEditPermission($vendor, $response)){ + return $response; + } + $data = [ 'vendor' => $vendor, 'method' => 'PUT', @@ -180,7 +201,13 @@ class VendorController extends BaseController */ public function update(UpdateVendorRequest $request) { - $vendor = $this->vendorService->save($request->input()); + $data = $request->input(); + + if(!$this->checkUpdatePermission($data, $response)){ + return $response; + } + + $vendor = $this->vendorService->save($data); Session::flash('message', trans('texts.updated_vendor')); diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 72ffce9c8b..1142338b20 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -28,6 +28,7 @@ class Kernel extends HttpKernel { protected $routeMiddleware = [ 'auth' => 'App\Http\Middleware\Authenticate', 'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth', + 'permissions.required' => 'App\Http\Middleware\PermissionsRequired', 'guest' => 'App\Http\Middleware\RedirectIfAuthenticated', 'api' => 'App\Http\Middleware\ApiCheck', ]; diff --git a/app/Http/Middleware/PermissionsRequired.php b/app/Http/Middleware/PermissionsRequired.php new file mode 100644 index 0000000000..af0e0015a3 --- /dev/null +++ b/app/Http/Middleware/PermissionsRequired.php @@ -0,0 +1,57 @@ + [action => permission] + */ + static protected $actions = []; + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @return mixed + */ + public function handle($request, Closure $next, $guard = 'user') + { + // Get the current route. + $route = $request->route(); + + // Get the current route actions. + $actions = $route->getAction(); + + // Check if we have any permissions to check the user has. + if ($permissions = !empty($actions['permissions']) ? $actions['permissions'] : null) + { + if(!Auth::user($guard)->hasPermission($permissions, !empty($actions['permissions_require_all']))){ + return response('Unauthorized.', 401); + } + } + + // Check controller permissions + $action = explode('@', $request->route()->getActionName()); + if(isset(static::$actions[$action[0]]) && isset(static::$actions[$action[0]][$action[1]])) { + $controller_permissions = static::$actions[$action[0]][$action[1]]; + if(!Auth::user($guard)->hasPermission($controller_permissions)){ + return response('Unauthorized.', 401); + } + } + + return $next($request); + } + + /** + * add a controller's action permission + * + * @param \App\Http\Controllers\Controller $controller + * @param array $permissions + */ + public static function addPermission(\App\Http\Controllers\Controller $controller, $permissions) + { + static::$actions[get_class($controller)] = $permissions; + } +} diff --git a/app/Http/routes.php b/app/Http/routes.php index 0c9aef7c1a..55f65e99a4 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -104,62 +104,9 @@ Route::group(['middleware' => 'auth:user'], function() { Route::get('view_archive/{entity_type}/{visible}', 'AccountController@setTrashVisible'); Route::get('hide_message', 'HomeController@hideMessage'); Route::get('force_inline_pdf', 'UserController@forcePDFJS'); - - Route::get('api/users', array('as'=>'api.users', 'uses'=>'UserController@getDatatable')); - Route::resource('users', 'UserController'); - Route::post('users/bulk', 'UserController@bulk'); - Route::get('send_confirmation/{user_id}', 'UserController@sendConfirmation'); - Route::get('start_trial', 'AccountController@startTrial'); - Route::get('restore_user/{user_id}', 'UserController@restoreUser'); - Route::post('users/change_password', 'UserController@changePassword'); - Route::get('/switch_account/{user_id}', 'UserController@switchAccount'); - Route::get('/unlink_account/{user_account_id}/{user_id}', 'UserController@unlinkAccount'); - Route::get('/manage_companies', 'UserController@manageCompanies'); - - Route::get('api/tokens', array('as'=>'api.tokens', 'uses'=>'TokenController@getDatatable')); - Route::resource('tokens', 'TokenController'); - Route::post('tokens/bulk', 'TokenController@bulk'); - - Route::get('api/products', array('as'=>'api.products', 'uses'=>'ProductController@getDatatable')); - Route::resource('products', 'ProductController'); - Route::post('products/bulk', 'ProductController@bulk'); - - Route::get('api/tax_rates', array('as'=>'api.tax_rates', 'uses'=>'TaxRateController@getDatatable')); - Route::resource('tax_rates', 'TaxRateController'); - Route::post('tax_rates/bulk', 'TaxRateController@bulk'); - - Route::get('company/{section}/{subSection?}', 'AccountController@redirectLegacy'); - Route::get('settings/data_visualizations', 'ReportController@d3'); - Route::get('settings/charts_and_reports', 'ReportController@showReports'); - Route::post('settings/charts_and_reports', 'ReportController@showReports'); - - Route::post('settings/cancel_account', 'AccountController@cancelAccount'); - Route::post('settings/company_details', 'AccountController@updateDetails'); - Route::get('settings/{section?}', 'AccountController@showSection'); - Route::post('settings/{section?}', 'AccountController@doSection'); - - //Route::get('api/payment_terms', array('as'=>'api.payment_terms', 'uses'=>'PaymentTermController@getDatatable')); - //Route::resource('payment_terms', 'PaymentTermController'); - //Route::post('payment_terms/bulk', 'PaymentTermController@bulk'); - - Route::get('account/getSearchData', array('as' => 'getSearchData', 'uses' => 'AccountController@getSearchData')); - Route::post('user/setTheme', 'UserController@setTheme'); - Route::post('remove_logo', 'AccountController@removeLogo'); - Route::post('account/go_pro', 'AccountController@enableProPlan'); - - Route::post('/export', 'ExportController@doExport'); - Route::post('/import', 'ImportController@doImport'); - Route::post('/import_csv', 'ImportController@doImportCSV'); - - Route::resource('gateways', 'AccountGatewayController'); - Route::get('api/gateways', array('as'=>'api.gateways', 'uses'=>'AccountGatewayController@getDatatable')); - Route::post('account_gateways/bulk', 'AccountGatewayController@bulk'); - - Route::resource('bank_accounts', 'BankAccountController'); - Route::get('api/bank_accounts', array('as'=>'api.bank_accounts', 'uses'=>'BankAccountController@getDatatable')); - Route::post('bank_accounts/bulk', 'BankAccountController@bulk'); - Route::post('bank_accounts/validate', 'BankAccountController@validateAccount'); - Route::post('bank_accounts/import_expenses/{bank_id}', 'BankAccountController@importExpenses'); + + Route::get('settings/user_details', 'AccountController@showUserDetails'); + Route::post('settings/user_details', 'AccountController@saveUserDetails'); Route::resource('clients', 'ClientController'); Route::get('api/clients', array('as'=>'api.clients', 'uses'=>'ClientController@getDatatable')); @@ -222,6 +169,67 @@ Route::group(['middleware' => 'auth:user'], function() { Route::post('expenses/bulk', 'ExpenseController@bulk'); }); +Route::group([ + 'middleware' => ['auth:user', 'permissions.required'], + 'permissions' => 'admin', +], function() { + Route::get('api/users', array('as'=>'api.users', 'uses'=>'UserController@getDatatable')); + Route::resource('users', 'UserController'); + Route::post('users/bulk', 'UserController@bulk'); + Route::get('send_confirmation/{user_id}', 'UserController@sendConfirmation'); + Route::get('start_trial', 'AccountController@startTrial'); + Route::get('restore_user/{user_id}', 'UserController@restoreUser'); + Route::post('users/change_password', 'UserController@changePassword'); + Route::get('/switch_account/{user_id}', 'UserController@switchAccount'); + Route::get('/unlink_account/{user_account_id}/{user_id}', 'UserController@unlinkAccount'); + Route::get('/manage_companies', 'UserController@manageCompanies'); + + Route::get('api/tokens', array('as'=>'api.tokens', 'uses'=>'TokenController@getDatatable')); + Route::resource('tokens', 'TokenController'); + Route::post('tokens/bulk', 'TokenController@bulk'); + + Route::get('api/products', array('as'=>'api.products', 'uses'=>'ProductController@getDatatable')); + Route::resource('products', 'ProductController'); + Route::post('products/bulk', 'ProductController@bulk'); + + Route::get('api/tax_rates', array('as'=>'api.tax_rates', 'uses'=>'TaxRateController@getDatatable')); + Route::resource('tax_rates', 'TaxRateController'); + Route::post('tax_rates/bulk', 'TaxRateController@bulk'); + + Route::get('company/{section}/{subSection?}', 'AccountController@redirectLegacy'); + Route::get('settings/data_visualizations', 'ReportController@d3'); + Route::get('settings/charts_and_reports', 'ReportController@showReports'); + Route::post('settings/charts_and_reports', 'ReportController@showReports'); + + Route::post('settings/cancel_account', 'AccountController@cancelAccount'); + Route::post('settings/company_details', 'AccountController@updateDetails'); + Route::get('settings/{section?}', 'AccountController@showSection'); + Route::post('settings/{section?}', 'AccountController@doSection'); + + //Route::get('api/payment_terms', array('as'=>'api.payment_terms', 'uses'=>'PaymentTermController@getDatatable')); + //Route::resource('payment_terms', 'PaymentTermController'); + //Route::post('payment_terms/bulk', 'PaymentTermController@bulk'); + + Route::get('account/getSearchData', array('as' => 'getSearchData', 'uses' => 'AccountController@getSearchData')); + Route::post('user/setTheme', 'UserController@setTheme'); + Route::post('remove_logo', 'AccountController@removeLogo'); + Route::post('account/go_pro', 'AccountController@enableProPlan'); + + Route::post('/export', 'ExportController@doExport'); + Route::post('/import', 'ImportController@doImport'); + Route::post('/import_csv', 'ImportController@doImportCSV'); + + Route::resource('gateways', 'AccountGatewayController'); + Route::get('api/gateways', array('as'=>'api.gateways', 'uses'=>'AccountGatewayController@getDatatable')); + Route::post('account_gateways/bulk', 'AccountGatewayController@bulk'); + + Route::resource('bank_accounts', 'BankAccountController'); + Route::get('api/bank_accounts', array('as'=>'api.bank_accounts', 'uses'=>'BankAccountController@getDatatable')); + Route::post('bank_accounts/bulk', 'BankAccountController@bulk'); + Route::post('bank_accounts/validate', 'BankAccountController@validateAccount'); + Route::post('bank_accounts/import_expenses/{bank_id}', 'BankAccountController@importExpenses'); +}); + // Route groups for API Route::group(['middleware' => 'api', 'prefix' => 'api/v1'], function() { @@ -604,6 +612,7 @@ if (!defined('CONTACT_EMAIL')) { define('USER_STATE_PENDING', 'pending'); define('USER_STATE_DISABLED', 'disabled'); define('USER_STATE_ADMIN', 'admin'); + define('USER_STATE_OWNER', 'owner'); define('API_SERIALIZER_ARRAY', 'array'); define('API_SERIALIZER_JSON', 'json'); diff --git a/app/Libraries/Utils.php b/app/Libraries/Utils.php index fcb210b0d7..cfcc97c001 100644 --- a/app/Libraries/Utils.php +++ b/app/Libraries/Utils.php @@ -118,6 +118,21 @@ class Utils return Auth::check() && Auth::user()->isPro(); } + public static function isAdmin() + { + return Auth::check() && Auth::user()->is_admin; + } + + public static function hasPermission($permission, $requireAll = false) + { + return Auth::check() && Auth::user()->hasPermission($permission, $requireAll); + } + + public static function hasAllPermissions($permission) + { + return Auth::check() && Auth::user()->hasPermissions($permission); + } + public static function isTrial() { return Auth::check() && Auth::user()->isTrial(); diff --git a/app/Models/EntityModel.php b/app/Models/EntityModel.php index b57eded2fb..aa6544e52f 100644 --- a/app/Models/EntityModel.php +++ b/app/Models/EntityModel.php @@ -113,4 +113,56 @@ class EntityModel extends Eloquent $name = $parts[count($parts)-1]; return strtolower($name) . '_id'; } + + public static function canCreate() { + return Auth::user()->hasPermission('create_all'); + } + + public function canEdit() { + return static::canEditItem($this); + } + + public static function canEditItem($item) { + return Auth::user()->hasPermission('edit_all') || (isset($item->user_id) && Auth::user()->id == $item->user_id); + } + + public static function canEditItemById($item_id) { + if(Auth::user()->hasPermission('edit_all')) { + return true; + } + + return static::whereId($item_id)->first()->user_id == Auth::user()->id; + } + + public static function canEditItemByOwner($user_id) { + if(Auth::user()->hasPermission('edit_all')) { + return true; + } + + return Auth::user()->id == $user_id; + } + + public function canView() { + return static::canViewItem($this); + } + + public static function canViewItem($item) { + return Auth::user()->hasPermission('view_all') || (isset($item->user_id) && Auth::user()->id == $item->user_id); + } + + public static function canViewItemById($item_id) { + if(Auth::user()->hasPermission('view_all')) { + return true; + } + + return static::whereId($item_id)->first()->user_id == Auth::user()->id; + } + + public static function canViewItemByOwner($user_id) { + if(Auth::user()->hasPermission('view_all')) { + return true; + } + + return Auth::user()->id == $user_id; + } } diff --git a/app/Models/Product.php b/app/Models/Product.php index 6f03676618..4098c67063 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -1,5 +1,6 @@ belongsTo('App\Models\TaxRate'); } + + public function canEdit() { + return Auth::user()->hasPermission('admin'); + } } diff --git a/app/Models/TaxRate.php b/app/Models/TaxRate.php index 7adf6f768b..15c39a7572 100644 --- a/app/Models/TaxRate.php +++ b/app/Models/TaxRate.php @@ -16,4 +16,8 @@ class TaxRate extends EntityModel { return ENTITY_TAX_RATE; } + + public function canEdit() { + return Auth::user()->hasPermission('admin'); + } } diff --git a/app/Models/User.php b/app/Models/User.php index 9f66f0d2af..1b2ae7815a 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -14,7 +14,12 @@ use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract; use Illuminate\Database\Eloquent\SoftDeletes; class User extends Model implements AuthenticatableContract, CanResetPasswordContract { - + public static $all_permissions = array( + 'create_all' => 0b0001, + 'view_all' => 0b0010, + 'edit_all' => 0b0100, + ); + use Authenticatable, CanResetPassword; /** @@ -253,7 +258,69 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon && $this->email != $this->getOriginal('email') && $this->getOriginal('confirmed'); } + + + + /** + * 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){ + $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 = array(); + 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 boolean True to require all permissions, false to require only one + * @return boolean + */ + public function hasPermission($permission, $requireAll = false){ + if ($this->is_admin) { + return true; + } else if(is_string($permission)){ + return !empty($this->permissions[$permission]); + } else if(is_array($permission)) { + if($requireAll){ + return count(array_diff($permission, $this->permissions)) == 0; + } else { + return count(array_intersect($permission, $this->permissions)) > 0; + } + } + + return false; + } } User::updating(function ($user) { diff --git a/app/Ninja/Repositories/ClientRepository.php b/app/Ninja/Repositories/ClientRepository.php index 2e8ce31b5c..9df81663a5 100644 --- a/app/Ninja/Repositories/ClientRepository.php +++ b/app/Ninja/Repositories/ClientRepository.php @@ -46,7 +46,8 @@ class ClientRepository extends BaseRepository 'clients.work_phone', 'contacts.email', 'clients.deleted_at', - 'clients.is_deleted' + 'clients.is_deleted', + 'clients.user_id' ); if (!\Session::get('show_trash:client')) { diff --git a/app/Ninja/Repositories/CreditRepository.php b/app/Ninja/Repositories/CreditRepository.php index 1c33cb19e4..9803b4628a 100644 --- a/app/Ninja/Repositories/CreditRepository.php +++ b/app/Ninja/Repositories/CreditRepository.php @@ -29,6 +29,7 @@ class CreditRepository extends BaseRepository 'credits.public_id', 'clients.name as client_name', 'clients.public_id as client_public_id', + 'clients.user_id as client_user_id', 'credits.amount', 'credits.balance', 'credits.credit_date', @@ -37,7 +38,8 @@ class CreditRepository extends BaseRepository 'contacts.email', 'credits.private_notes', 'credits.deleted_at', - 'credits.is_deleted' + 'credits.is_deleted', + 'credits.user_id' ); if ($clientPublicId) { diff --git a/app/Ninja/Repositories/ExpenseRepository.php b/app/Ninja/Repositories/ExpenseRepository.php index cfd312622a..49988435e5 100644 --- a/app/Ninja/Repositories/ExpenseRepository.php +++ b/app/Ninja/Repositories/ExpenseRepository.php @@ -40,7 +40,8 @@ class ExpenseRepository extends BaseRepository 'expenses.public_id', 'expenses.deleted_at', 'expenses.should_be_invoiced', - 'expenses.created_at' + 'expenses.created_at', + 'expenses.user_id' ); return $query; @@ -80,11 +81,15 @@ class ExpenseRepository extends BaseRepository 'expenses.vendor_id', 'expenses.expense_currency_id', 'expenses.invoice_currency_id', + 'expenses.user_id', 'invoices.public_id as invoice_public_id', + 'invoices.user_id as invoice_user_id', 'vendors.name as vendor_name', 'vendors.public_id as vendor_public_id', + 'vendors.user_id as vendor_user_id', 'clients.name as client_name', 'clients.public_id as client_public_id', + 'clients.user_id as client_user_id', 'contacts.first_name', 'contacts.email', 'contacts.last_name', diff --git a/app/Ninja/Repositories/InvoiceRepository.php b/app/Ninja/Repositories/InvoiceRepository.php index f028acdf93..67c0bab310 100644 --- a/app/Ninja/Repositories/InvoiceRepository.php +++ b/app/Ninja/Repositories/InvoiceRepository.php @@ -49,6 +49,7 @@ class InvoiceRepository extends BaseRepository DB::raw('COALESCE(clients.currency_id, accounts.currency_id) currency_id'), DB::raw('COALESCE(clients.country_id, accounts.country_id) country_id'), 'clients.public_id as client_public_id', + 'clients.user_id as client_user_id', 'invoice_number', 'invoice_status_id', 'clients.name as client_name', @@ -65,7 +66,8 @@ class InvoiceRepository extends BaseRepository 'invoices.quote_invoice_id', 'invoices.deleted_at', 'invoices.is_deleted', - 'invoices.partial' + 'invoices.partial', + 'invoices.user_id' ); if (!\Session::get('show_trash:'.$entityType)) { @@ -189,7 +191,7 @@ class InvoiceRepository extends BaseRepository ->make(); } - public function save($data) + public function save($data, $checkSubPermissions = false) { $account = \Auth::user()->account; $publicId = isset($data['public_id']) ? $data['public_id'] : false; @@ -405,29 +407,40 @@ class InvoiceRepository extends BaseRepository $task = false; if (isset($item['task_public_id']) && $item['task_public_id']) { $task = Task::scope($item['task_public_id'])->where('invoice_id', '=', null)->firstOrFail(); - $task->invoice_id = $invoice->id; - $task->client_id = $invoice->client_id; - $task->save(); + if(!$checkSubPermissions || $task->canEdit()){ + $task->invoice_id = $invoice->id; + $task->client_id = $invoice->client_id; + $task->save(); + } } $expense = false; if (isset($item['expense_public_id']) && $item['expense_public_id']) { $expense = Expense::scope($item['expense_public_id'])->where('invoice_id', '=', null)->firstOrFail(); - $expense->invoice_id = $invoice->id; - $expense->client_id = $invoice->client_id; - $expense->save(); + if(!$checkSubPermissions || $expense->canEdit()){ + $expense->invoice_id = $invoice->id; + $expense->client_id = $invoice->client_id; + $expense->save(); + } } if ($productKey = trim($item['product_key'])) { if (\Auth::user()->account->update_products && ! strtotime($productKey)) { $product = Product::findProductByKey($productKey); if (!$product) { - $product = Product::createNew(); - $product->product_key = trim($item['product_key']); + if(!$checkSubPermissions || Product::canCreate()){ + $product = Product::createNew(); + $product->product_key = trim($item['product_key']); + } + else{ + $product = null; + } + } + if($product && (!$checkSubPermissions || $product->canEdit())){ + $product->notes = ($task || $expense) ? '' : $item['notes']; + $product->cost = $expense ? 0 : $item['cost']; + $product->save(); } - $product->notes = ($task || $expense) ? '' : $item['notes']; - $product->cost = $expense ? 0 : $item['cost']; - $product->save(); } } diff --git a/app/Ninja/Repositories/PaymentRepository.php b/app/Ninja/Repositories/PaymentRepository.php index 15f5007251..a027cb62ae 100644 --- a/app/Ninja/Repositories/PaymentRepository.php +++ b/app/Ninja/Repositories/PaymentRepository.php @@ -36,9 +36,11 @@ class PaymentRepository extends BaseRepository 'payments.transaction_reference', 'clients.name as client_name', 'clients.public_id as client_public_id', + 'clients.user_id as client_user_id', 'payments.amount', 'payments.payment_date', 'invoices.public_id as invoice_public_id', + 'invoices.user_id as invoice_user_id', 'invoices.invoice_number', 'contacts.first_name', 'contacts.last_name', @@ -47,6 +49,7 @@ class PaymentRepository extends BaseRepository 'payments.account_gateway_id', 'payments.deleted_at', 'payments.is_deleted', + 'payments.user_id', 'invoices.is_deleted as invoice_is_deleted', 'gateways.name as gateway_name' ); diff --git a/app/Ninja/Repositories/TaskRepository.php b/app/Ninja/Repositories/TaskRepository.php index 47a052378f..a7655a8abd 100644 --- a/app/Ninja/Repositories/TaskRepository.php +++ b/app/Ninja/Repositories/TaskRepository.php @@ -27,6 +27,7 @@ class TaskRepository 'tasks.public_id', 'clients.name as client_name', 'clients.public_id as client_public_id', + 'clients.user_id as client_user_id', 'contacts.first_name', 'contacts.email', 'contacts.last_name', @@ -36,9 +37,11 @@ class TaskRepository 'tasks.deleted_at', 'invoices.invoice_number', 'invoices.public_id as invoice_public_id', + 'invoices.user_id as invoice_user_id', 'tasks.is_running', 'tasks.time_log', - 'tasks.created_at' + 'tasks.created_at', + 'tasks.user_id' ); if ($clientPublicId) { diff --git a/app/Ninja/Repositories/UserRepository.php b/app/Ninja/Repositories/UserRepository.php index 5675a161a6..ca5878b0c1 100644 --- a/app/Ninja/Repositories/UserRepository.php +++ b/app/Ninja/Repositories/UserRepository.php @@ -22,7 +22,7 @@ class UserRepository extends BaseRepository $query->where('users.deleted_at', '=', null); } - $query->select('users.public_id', 'users.first_name', 'users.last_name', 'users.email', 'users.confirmed', 'users.public_id', 'users.deleted_at'); + $query->select('users.public_id', 'users.first_name', 'users.last_name', 'users.email', 'users.confirmed', 'users.public_id', 'users.deleted_at', 'users.is_admin', 'users.permissions'); return $query; } @@ -34,5 +34,4 @@ class UserRepository extends BaseRepository return $user; } - } diff --git a/app/Ninja/Repositories/VendorRepository.php b/app/Ninja/Repositories/VendorRepository.php index 81fc8fc7f4..df885f62e1 100644 --- a/app/Ninja/Repositories/VendorRepository.php +++ b/app/Ninja/Repositories/VendorRepository.php @@ -42,7 +42,8 @@ class VendorRepository extends BaseRepository 'vendors.city', 'vendor_contacts.email', 'vendors.deleted_at', - 'vendors.is_deleted' + 'vendors.is_deleted', + 'vendors.user_id' ); if (!\Session::get('show_trash:vendor')) { diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index e5fcf4540f..3cd6910987 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -8,6 +8,9 @@ use Form; use URL; use Request; use Validator; +use App\Models\Credit; +use App\Models\Invoice; +use App\Models\Vendor; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { @@ -46,31 +49,38 @@ class AppServiceProvider extends ServiceProvider { $class = ( Request::is($types) || Request::is('*'.$type.'*')) && !Request::is('*settings*') ? ' active' : ''; $str = ''; + $str .= ''; return $str; }); diff --git a/app/Services/BaseService.php b/app/Services/BaseService.php index ca1944d4e5..b68b06482a 100644 --- a/app/Services/BaseService.php +++ b/app/Services/BaseService.php @@ -14,14 +14,16 @@ class BaseService public function bulk($ids, $action) { - if ( ! $ids) { + if ( ! $ids ) { return 0; } $entities = $this->getRepo()->findByPublicIdsWithTrashed($ids); foreach ($entities as $entity) { - $this->getRepo()->$action($entity); + if($entity->canEdit()){ + $this->getRepo()->$action($entity); + } } return count($entities); diff --git a/app/Services/ClientService.php b/app/Services/ClientService.php index 21242da54a..662fc8eab9 100644 --- a/app/Services/ClientService.php +++ b/app/Services/ClientService.php @@ -4,6 +4,12 @@ use Utils; use URL; use Auth; use App\Services\BaseService; +use App\Models\Client; +use App\Models\Invoice; +use App\Models\Credit; +use App\Models\Expense; +use App\Models\Payment; +use App\Models\Task; use App\Ninja\Repositories\ClientRepository; use App\Ninja\Repositories\NinjaRepository; @@ -37,6 +43,10 @@ class ClientService extends BaseService { $query = $this->clientRepo->find($search); + if(!Utils::hasPermission('view_all')){ + $query->where('clients.user_id', '=', Auth::user()->id); + } + return $this->createDatatable(ENTITY_CLIENT, $query); } @@ -89,19 +99,33 @@ class ClientService extends BaseService trans('texts.edit_client'), function ($model) { return URL::to("clients/{$model->public_id}/edit"); + }, + function ($model) { + return Client::canEditItem($model); + } + ], + [ + '--divider--', function(){return false;}, + function ($model) { + return Client::canEditItem($model) && (Task::canCreate() || Invoice::canCreate()); } ], - [], [ trans('texts.new_task'), function ($model) { return URL::to("tasks/create/{$model->public_id}"); + }, + function ($model) { + return Task::canCreate(); } ], [ trans('texts.new_invoice'), function ($model) { return URL::to("invoices/create/{$model->public_id}"); + }, + function ($model) { + return Invoice::canCreate(); } ], [ @@ -110,26 +134,40 @@ class ClientService extends BaseService return URL::to("quotes/create/{$model->public_id}"); }, function ($model) { - return Auth::user()->isPro(); + return Auth::user()->isPro() && Invoice::canCreate(); + } + ], + [ + '--divider--', function(){return false;}, + function ($model) { + return (Task::canCreate() || Invoice::canCreate()) && (Payment::canCreate() || Credit::canCreate() || Expense::canCreate()); } ], - [], [ trans('texts.enter_payment'), function ($model) { return URL::to("payments/create/{$model->public_id}"); + }, + function ($model) { + return Payment::canCreate(); } ], [ trans('texts.enter_credit'), function ($model) { return URL::to("credits/create/{$model->public_id}"); + }, + function ($model) { + return Credit::canCreate(); } ], [ trans('texts.enter_expense'), function ($model) { return URL::to("expenses/create/0/{$model->public_id}"); + }, + function ($model) { + return Expense::canCreate(); } ] ]; diff --git a/app/Services/CreditService.php b/app/Services/CreditService.php index 70c2d13048..2a130c5517 100644 --- a/app/Services/CreditService.php +++ b/app/Services/CreditService.php @@ -3,6 +3,8 @@ use Utils; use URL; use App\Services\BaseService; +use App\Models\Client; +use App\Models\Payment; use App\Ninja\Repositories\CreditRepository; @@ -30,6 +32,10 @@ class CreditService extends BaseService public function getDatatable($clientPublicId, $search) { $query = $this->creditRepo->find($clientPublicId, $search); + + if(!Utils::hasPermission('view_all')){ + $query->where('expenses.user_id', '=', Auth::user()->id); + } return $this->createDatatable(ENTITY_CREDIT, $query, !$clientPublicId); } @@ -40,6 +46,10 @@ class CreditService extends BaseService [ 'client_name', function ($model) { + if(!Client::canViewItemByOwner($model->client_user_id)){ + return Utils::getClientDisplayName($model); + } + return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : ''; }, ! $hideClient @@ -78,6 +88,9 @@ class CreditService extends BaseService trans('texts.apply_credit'), function ($model) { return URL::to("payments/create/{$model->client_public_id}") . '?paymentTypeId=1'; + }, + function ($model) { + return Payment::canCreate(); } ] ]; diff --git a/app/Services/DatatableService.php b/app/Services/DatatableService.php index 285efe717a..2f9af2856c 100644 --- a/app/Services/DatatableService.php +++ b/app/Services/DatatableService.php @@ -3,6 +3,7 @@ use HtmlString; use Utils; use Datatable; +use Auth; class DatatableService { @@ -13,7 +14,9 @@ class DatatableService if ($actions && $showCheckbox) { $table->addColumn('checkbox', function ($model) { - return ''; }); } @@ -45,6 +48,8 @@ class DatatableService $hasAction = false; $str = '
'; + $can_edit = Auth::user()->hasPermission('edit_all') || (isset($model->user_id) && Auth::user()->id == $model->user_id); + if (property_exists($model, 'is_deleted') && $model->is_deleted) { $str .= ''; } elseif ($model->deleted_at && $model->deleted_at !== '0000-00-00') { @@ -70,9 +75,15 @@ class DatatableService } list($value, $url, $visible) = $action; if ($visible($model)) { - $str .= "
  • {$value}
  • "; - $lastIsDivider = false; - $hasAction = true; + if($value == '--divider--'){ + $str .= "
  • "; + $lastIsDivider = true; + } + else { + $str .= "
  • {$value}
  • "; + $hasAction = true; + $lastIsDivider = false; + } } } elseif ( ! $lastIsDivider) { $str .= "
  • "; @@ -84,20 +95,20 @@ class DatatableService return ''; } - if ( ! $lastIsDivider) { + if ( $can_edit && ! $lastIsDivider) { $str .= "
  • "; } - if ($entityType != ENTITY_USER || $model->public_id) { + if (($entityType != ENTITY_USER || $model->public_id) && $can_edit) { $str .= "
  • public_id})\">" . trans("texts.archive_{$entityType}") . "
  • "; } - } else { + } else if($can_edit) { $str .= "
  • public_id})\">" . trans("texts.restore_{$entityType}") . "
  • "; } - if (property_exists($model, 'is_deleted') && !$model->is_deleted) { + if (property_exists($model, 'is_deleted') && !$model->is_deleted && $can_edit) { $str .= "
  • public_id})\">" . trans("texts.delete_{$entityType}") . "
  • "; } diff --git a/app/Services/ExpenseService.php b/app/Services/ExpenseService.php index 9f094240d0..2fc2afbc84 100644 --- a/app/Services/ExpenseService.php +++ b/app/Services/ExpenseService.php @@ -1,10 +1,13 @@ expenseRepo->find($search); + if(!Utils::hasPermission('view_all')){ + $query->where('expenses.user_id', '=', Auth::user()->id); + } + return $this->createDatatable(ENTITY_EXPENSE, $query); } @@ -63,6 +70,10 @@ class ExpenseService extends BaseService function ($model) { if ($model->vendor_public_id) { + if(!Vendor::canViewItemByOwner($model->vendor_user_id)){ + return $model->vendor_name; + } + return link_to("vendors/{$model->vendor_public_id}", $model->vendor_name)->toHtml(); } else { return ''; @@ -74,6 +85,10 @@ class ExpenseService extends BaseService function ($model) { if ($model->client_public_id) { + if(!Client::canViewItemByOwner($model->client_user_id)){ + return Utils::getClientDisplayName($model); + } + return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml(); } else { return ''; @@ -83,6 +98,10 @@ class ExpenseService extends BaseService [ 'expense_date', function ($model) { + if(!Expense::canEditItemByOwner($model->user_id)){ + return Utils::fromSqlDate($model->expense_date); + } + return link_to("expenses/{$model->public_id}/edit", Utils::fromSqlDate($model->expense_date))->toHtml(); } ], @@ -151,6 +170,9 @@ class ExpenseService extends BaseService trans('texts.edit_expense'), function ($model) { return URL::to("expenses/{$model->public_id}/edit") ; + }, + function ($model) { + return Expense::canEditItem($model); } ], [ @@ -159,7 +181,7 @@ class ExpenseService extends BaseService return URL::to("/invoices/{$model->invoice_public_id}/edit"); }, function ($model) { - return $model->invoice_public_id; + return $model->invoice_public_id && Invoice::canEditItemByOwner($model->invoice_user_id); } ], [ @@ -168,7 +190,7 @@ class ExpenseService extends BaseService return "javascript:invoiceEntity({$model->public_id})"; }, function ($model) { - return ! $model->invoice_id && (!$model->deleted_at || $model->deleted_at == '0000-00-00'); + return ! $model->invoice_id && (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Invoice::canCreate(); } ], ]; diff --git a/app/Services/InvoiceService.php b/app/Services/InvoiceService.php index 522c1a5dff..c7c0be72ac 100644 --- a/app/Services/InvoiceService.php +++ b/app/Services/InvoiceService.php @@ -8,6 +8,9 @@ use App\Ninja\Repositories\InvoiceRepository; use App\Ninja\Repositories\ClientRepository; use App\Events\QuoteInvitationWasApproved; use App\Models\Invitation; +use App\Models\Invoice; +use App\Models\Client; +use App\Models\Payment; class InvoiceService extends BaseService { @@ -27,14 +30,26 @@ class InvoiceService extends BaseService return $this->invoiceRepo; } - public function save($data) + public function save($data, $checkSubPermissions = false) { if (isset($data['client'])) { - $client = $this->clientRepo->save($data['client']); - $data['client_id'] = $client->id; + $can_save_client = !$checkSubPermissions; + if(!$can_save_client){ + if(empty($data['client']['public_id']) || $data['client']['public_id']=='-1'){ + $can_save_client = Client::canCreate(); + } + else{ + $can_save_client = Client::wherePublicId($data['client']['public_id'])->first()->canEdit(); + } + } + + if($can_save_client){ + $client = $this->clientRepo->save($data['client']); + $data['client_id'] = $client->id; + } } - $invoice = $this->invoiceRepo->save($data); + $invoice = $this->invoiceRepo->save($data, $checkSubPermissions); $client = $invoice->client; $client->load('contacts'); @@ -109,6 +124,10 @@ class InvoiceService extends BaseService $query = $this->invoiceRepo->getInvoices($accountId, $clientPublicId, $entityType, $search) ->where('invoices.is_quote', '=', $entityType == ENTITY_QUOTE ? true : false); + if(!Utils::hasPermission('view_all')){ + $query->where('invoices.user_id', '=', Auth::user()->id); + } + return $this->createDatatable($entityType, $query, !$clientPublicId); } @@ -118,12 +137,19 @@ class InvoiceService extends BaseService [ 'invoice_number', function ($model) use ($entityType) { + if(!Invoice::canEditItem($model)){ + return $model->invoice_number; + } + return link_to("{$entityType}s/{$model->public_id}/edit", $model->invoice_number, ['class' => Utils::getEntityRowClass($model)])->toHtml(); } ], [ 'client_name', function ($model) { + if(!Client::canViewItemByOwner($model->client_user_id)){ + return Utils::getClientDisplayName($model); + } return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml(); }, ! $hideClient @@ -174,12 +200,18 @@ class InvoiceService extends BaseService trans("texts.edit_{$entityType}"), function ($model) use ($entityType) { return URL::to("{$entityType}s/{$model->public_id}/edit"); + }, + function ($model) { + return Invoice::canEditItem($model); } ], [ trans("texts.clone_{$entityType}"), function ($model) use ($entityType) { return URL::to("{$entityType}s/{$model->public_id}/clone"); + }, + function ($model) { + return Invoice::canCreate(); } ], [ @@ -188,14 +220,19 @@ class InvoiceService extends BaseService return URL::to("{$entityType}s/{$entityType}_history/{$model->public_id}"); } ], - [], + [ + '--divider--', function(){return false;}, + function ($model) { + return Invoice::canEditItem($model) || Payment::canCreate(); + } + ], [ trans("texts.mark_sent"), function ($model) { return "javascript:markEntity({$model->public_id})"; }, function ($model) { - return $model->invoice_status_id < INVOICE_STATUS_SENT; + return $model->invoice_status_id < INVOICE_STATUS_SENT && Invoice::canEditItem($model); } ], [ @@ -204,7 +241,7 @@ class InvoiceService extends BaseService return URL::to("payments/create/{$model->client_public_id}/{$model->public_id}"); }, function ($model) use ($entityType) { - return $entityType == ENTITY_INVOICE && $model->balance > 0; + return $entityType == ENTITY_INVOICE && $model->balance > 0 && Payment::canCreate(); } ], [ @@ -213,7 +250,7 @@ class InvoiceService extends BaseService return URL::to("quotes/{$model->quote_id}/edit"); }, function ($model) use ($entityType) { - return $entityType == ENTITY_INVOICE && $model->quote_id; + return $entityType == ENTITY_INVOICE && $model->quote_id && Invoice::canEditItem($model); } ], [ @@ -222,7 +259,7 @@ class InvoiceService extends BaseService return URL::to("invoices/{$model->quote_invoice_id}/edit"); }, function ($model) use ($entityType) { - return $entityType == ENTITY_QUOTE && $model->quote_invoice_id; + return $entityType == ENTITY_QUOTE && $model->quote_invoice_id && Invoice::canEditItem($model); } ], [ @@ -231,7 +268,7 @@ class InvoiceService extends BaseService return "javascript:convertEntity({$model->public_id})"; }, function ($model) use ($entityType) { - return $entityType == ENTITY_QUOTE && ! $model->quote_invoice_id; + return $entityType == ENTITY_QUOTE && ! $model->quote_invoice_id && Invoice::canEditItem($model); } ] ]; diff --git a/app/Services/PaymentService.php b/app/Services/PaymentService.php index 83429f5b20..3bf26d8ba2 100644 --- a/app/Services/PaymentService.php +++ b/app/Services/PaymentService.php @@ -1,6 +1,7 @@ paymentRepo->find($clientPublicId, $search); + if(!Utils::hasPermission('view_all')){ + $query->where('payments.user_id', '=', Auth::user()->id); + } + return $this->createDatatable(ENTITY_PAYMENT, $query, !$clientPublicId); } @@ -295,12 +302,20 @@ class PaymentService extends BaseService [ 'invoice_number', function ($model) { + if(!Invoice::canEditItemByOwner($model->invoice_user_id)){ + 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(!Client::canViewItemByOwner($model->client_user_id)){ + return Utils::getClientDisplayName($model); + } + return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : ''; }, ! $hideClient @@ -339,6 +354,9 @@ class PaymentService extends BaseService trans('texts.edit_payment'), function ($model) { return URL::to("payments/{$model->public_id}/edit"); + }, + function ($model) { + return Payment::canEditItem($model); } ] ]; diff --git a/app/Services/RecurringInvoiceService.php b/app/Services/RecurringInvoiceService.php index bd23d2a5e0..2786ccfc68 100644 --- a/app/Services/RecurringInvoiceService.php +++ b/app/Services/RecurringInvoiceService.php @@ -1,7 +1,9 @@ invoiceRepo->getRecurringInvoices($accountId, $clientPublicId, $search); + if(!Utils::hasPermission('view_all')){ + $query->where('invoices.user_id', '=', Auth::user()->id); + } + return $this->createDatatable(ENTITY_RECURRING_INVOICE, $query, !$clientPublicId); } @@ -66,6 +72,9 @@ class RecurringInvoiceService extends BaseService trans('texts.edit_invoice'), function ($model) { return URL::to("invoices/{$model->public_id}/edit"); + }, + function ($model) { + return Invoice::canEditItem($model); } ] ]; diff --git a/app/Services/TaskService.php b/app/Services/TaskService.php index 59f8fd95fe..70e7e22c7c 100644 --- a/app/Services/TaskService.php +++ b/app/Services/TaskService.php @@ -1,8 +1,11 @@ taskRepo->find($clientPublicId, $search); + if(!Utils::hasPermission('view_all')){ + $query->where('tasks.user_id', '=', Auth::user()->id); + } + return $this->createDatatable(ENTITY_TASK, $query, !$clientPublicId); } @@ -42,6 +49,10 @@ class TaskService extends BaseService [ 'client_name', function ($model) { + if(!Client::canViewItemByOwner($model->client_user_id)){ + return Utils::getClientDisplayName($model); + } + return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : ''; }, ! $hideClient @@ -82,7 +93,7 @@ class TaskService extends BaseService return URL::to('tasks/'.$model->public_id.'/edit'); }, function ($model) { - return !$model->deleted_at || $model->deleted_at == '0000-00-00'; + return (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Task::canEditItem($model); } ], [ @@ -91,7 +102,7 @@ class TaskService extends BaseService return URL::to("/invoices/{$model->invoice_public_id}/edit"); }, function ($model) { - return $model->invoice_number; + return $model->invoice_number && Invoice::canEditItemByOwner($model->invoice_user_id); } ], [ @@ -100,7 +111,7 @@ class TaskService extends BaseService return "javascript:stopTask({$model->public_id})"; }, function ($model) { - return $model->is_running; + return $model->is_running && Task::canEditItem($model); } ], [ @@ -109,7 +120,7 @@ class TaskService extends BaseService return "javascript:invoiceEntity({$model->public_id})"; }, function ($model) { - return ! $model->invoice_number && (!$model->deleted_at || $model->deleted_at == '0000-00-00'); + return ! $model->invoice_number && (!$model->deleted_at || $model->deleted_at == '0000-00-00') && Invoice::canCreate(); } ] ]; diff --git a/app/Services/UserService.php b/app/Services/UserService.php index fcc0220036..8e31b4c30d 100644 --- a/app/Services/UserService.php +++ b/app/Services/UserService.php @@ -53,11 +53,15 @@ class UserService extends BaseService 'confirmed', function ($model) { if (!$model->public_id) { - return self::getStatusLabel(USER_STATE_ADMIN); + return self::getStatusLabel(USER_STATE_OWNER); } elseif ($model->deleted_at) { return self::getStatusLabel(USER_STATE_DISABLED); } elseif ($model->confirmed) { - return self::getStatusLabel(USER_STATE_ACTIVE); + if($model->is_admin){ + return self::getStatusLabel(USER_STATE_ADMIN); + } else { + return self::getStatusLabel(USER_STATE_ACTIVE); + } } else { return self::getStatusLabel(USER_STATE_PENDING); } @@ -96,17 +100,20 @@ class UserService extends BaseService $class = 'default'; switch ($state) { case USER_STATE_PENDING: - $class = 'info'; + $class = 'default'; break; case USER_STATE_ACTIVE: - $class = 'primary'; + $class = 'info'; break; case USER_STATE_DISABLED: $class = 'warning'; break; - case USER_STATE_ADMIN: + case USER_STATE_OWNER: $class = 'success'; break; + case USER_STATE_ADMIN: + $class = 'primary'; + break; } return "

    $label

    "; } diff --git a/app/Services/VendorService.php b/app/Services/VendorService.php index cd2dcf8d18..6f9b4420d7 100644 --- a/app/Services/VendorService.php +++ b/app/Services/VendorService.php @@ -3,6 +3,8 @@ use Utils; use URL; use Auth; +use App\Models\Vendor; +use App\Models\Expense; use App\Services\BaseService; use App\Ninja\Repositories\VendorRepository; use App\Ninja\Repositories\NinjaRepository; @@ -36,6 +38,10 @@ class VendorService extends BaseService public function getDatatable($search) { $query = $this->vendorRepo->find($search); + + if(!Utils::hasPermission('view_all')){ + $query->where('vendors.user_id', '=', Auth::user()->id); + } return $this->createDatatable(ENTITY_VENDOR, $query); } @@ -83,13 +89,25 @@ class VendorService extends BaseService trans('texts.edit_vendor'), function ($model) { return URL::to("vendors/{$model->public_id}/edit"); + }, + function ($model) { + return Vendor::canEditItem($model); } ], - [], + [ + '--divider--', function(){return false;}, + function ($model) { + return Vendor::canEditItem($model) && Expense::canCreate(); + } + + ], [ trans('texts.enter_expense'), function ($model) { return URL::to("expenses/create/{$model->public_id}"); + }, + function ($model) { + return Expense::canCreate(); } ] ]; diff --git a/database/migrations/2016_03_14_066181_add_user_permissions.php b/database/migrations/2016_03_14_066181_add_user_permissions.php new file mode 100644 index 0000000000..2cdd599482 --- /dev/null +++ b/database/migrations/2016_03_14_066181_add_user_permissions.php @@ -0,0 +1,33 @@ +boolean('is_admin')->default(true); + $table->unsignedInteger('permissions')->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function($table) { + $table->dropColumn('is_admin'); + $table->dropColumn('permissions'); + }); + } +} diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index e40467673c..1afab6f998 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -1065,6 +1065,14 @@ $LANG = array( 'cost' => 'Cost', 'create_invoice_for_sample' => 'Note: create your first invoice to see a preview here.', + // User Permissions + 'owner' => 'Owner', + 'administrator' => 'Administrator', + 'administrator_help' => 'Allow user to manage users, change settings, and view and modify all data', + 'user_create_all' => 'Create clients, invoices, etc.', + 'user_view_all' => 'View all clients, invoices, etc.', + 'user_edit_all' => 'Edit all clients, invoices, etc.', + ); return $LANG; diff --git a/resources/views/accounts/user_details.blade.php b/resources/views/accounts/user_details.blade.php index 57bfdb8eb5..c9426a8b3b 100644 --- a/resources/views/accounts/user_details.blade.php +++ b/resources/views/accounts/user_details.blade.php @@ -21,7 +21,9 @@ {{ Former::populateField('referral_code', true) }} @endif - @include('accounts.nav', ['selected' => ACCOUNT_USER_DETAILS]) + @if (Utils::isAdmin()) + @include('accounts.nav', ['selected' => ACCOUNT_USER_DETAILS]) + @endif
    diff --git a/resources/views/clients/show.blade.php b/resources/views/clients/show.blade.php index ee7ac115df..3166f9b800 100644 --- a/resources/views/clients/show.blade.php +++ b/resources/views/clients/show.blade.php @@ -43,8 +43,11 @@ @endif @if ($client->trashed()) - {!! Button::primary(trans('texts.restore_client'))->withAttributes(['onclick' => 'onRestoreClick()']) !!} + @if ($client->canEdit()) + {!! Button::primary(trans('texts.restore_client'))->withAttributes(['onclick' => 'onRestoreClick()']) !!} + @endif @else + @if ($client->canEdit()) {!! DropdownButton::normal(trans('texts.edit_client')) ->withAttributes(['class'=>'normalDropDown']) ->withContents([ @@ -52,10 +55,12 @@ ['label' => trans('texts.delete_client'), 'url' => "javascript:onDeleteClick()"], ] )->split() !!} - - {!! DropdownButton::primary(trans('texts.new_invoice')) - ->withAttributes(['class'=>'primaryDropDown']) - ->withContents($actionLinks)->split() !!} + @endif + @if (\App\Models\Invoice::canCreate()) + {!! DropdownButton::primary(trans('texts.new_invoice')) + ->withAttributes(['class'=>'primaryDropDown']) + ->withContents($actionLinks)->split() !!} + @endif @endif {!! Former::close() !!} diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php index d36c8334cc..ad8b8c4e09 100644 --- a/resources/views/dashboard.blade.php +++ b/resources/views/dashboard.blade.php @@ -116,7 +116,11 @@ @foreach ($payments as $payment) {!! \App\Models\Invoice::calcLink($payment) !!} - {!! link_to('/clients/'.$payment->client_public_id, trim($payment->client_name) ?: (trim($payment->first_name . ' ' . $payment->last_name) ?: $payment->email)) !!} + @if (\App\Models\Client::canViewItemByOwner($payment->client_user_id)) + {!! link_to('/clients/'.$payment->client_public_id, trim($payment->client_name) ?: (trim($payment->first_name . ' ' . $payment->last_name) ?: $payment->email)) !!} + @else + {{ trim($payment->client_name) ?: (trim($payment->first_name . ' ' . $payment->last_name) ?: $payment->email) }} + @endif {{ Utils::fromSqlDate($payment->payment_date) }} {{ Utils::formatMoney($payment->amount, $payment->currency_id ?: ($account->currency_id ?: DEFAULT_CURRENCY)) }} @@ -149,7 +153,11 @@ @if (!$invoice->is_quote) {!! \App\Models\Invoice::calcLink($invoice) !!} - {!! link_to('/clients/'.$invoice->client_public_id, trim($invoice->client_name) ?: (trim($invoice->first_name . ' ' . $invoice->last_name) ?: $invoice->email)) !!} + @if (\App\Models\Client::canViewItemByOwner($payment->client_user_id)) + {!! link_to('/clients/'.$payment->client_public_id, trim($payment->client_name) ?: (trim($payment->first_name . ' ' . $payment->last_name) ?: $payment->email)) !!} + @else + {{ trim($payment->client_name) ?: (trim($payment->first_name . ' ' . $payment->last_name) ?: $payment->email) }} + @endif {{ Utils::fromSqlDate($invoice->due_date) }} {{ Utils::formatMoney($invoice->balance, $invoice->currency_id ?: ($account->currency_id ?: DEFAULT_CURRENCY)) }} @@ -160,7 +168,7 @@
    -
    +

    @@ -180,7 +188,11 @@ @if (!$invoice->is_quote) {!! \App\Models\Invoice::calcLink($invoice) !!} - {!! link_to('/clients/'.$invoice->client_public_id, trim($invoice->client_name) ?: (trim($invoice->first_name . ' ' . $invoice->last_name) ?: $invoice->email)) !!} + @if (\App\Models\Client::canViewItemByOwner($payment->client_user_id)) + {!! link_to('/clients/'.$payment->client_public_id, trim($payment->client_name) ?: (trim($payment->first_name . ' ' . $payment->last_name) ?: $payment->email)) !!} + @else + {{ trim($payment->client_name) ?: (trim($payment->first_name . ' ' . $payment->last_name) ?: $payment->email) }} + @endif {{ Utils::fromSqlDate($invoice->due_date) }} {{ Utils::formatMoney($invoice->balance, $invoice->currency_id ?: ($account->currency_id ?: DEFAULT_CURRENCY)) }} diff --git a/resources/views/header.blade.php b/resources/views/header.blade.php index 9cf35b09a7..3ce364da64 100644 --- a/resources/views/header.blade.php +++ b/resources/views/header.blade.php @@ -473,11 +473,13 @@ 'selected' => true, ]) @endif -
  • - @if (count(session(SESSION_USER_ACCOUNTS)) > 1) -
  • {!! link_to('/manage_companies', trans('texts.manage_companies')) !!}
  • - @elseif (!session(SESSION_USER_ACCOUNTS) || count(session(SESSION_USER_ACCOUNTS)) < 5) -
  • {!! link_to('/login?new_company=true', trans('texts.add_company')) !!}
  • +
  • + @if (Utils::isAdmin()) + @if (count(session(SESSION_USER_ACCOUNTS)) > 1) +
  • {!! link_to('/manage_companies', trans('texts.manage_companies')) !!}
  • + @elseif (!session(SESSION_USER_ACCOUNTS) || count(session(SESSION_USER_ACCOUNTS)) < 5) +
  • {!! link_to('/login?new_company=true', trans('texts.add_company')) !!}
  • + @endif @endif
  • {!! link_to('#', trans('texts.logout'), array('onclick'=>'logout()')) !!}
  • @@ -487,15 +489,21 @@ diff --git a/resources/views/invoices/edit.blade.php b/resources/views/invoices/edit.blade.php index 5fa93dd3c8..c3c21fd5f5 100644 --- a/resources/views/invoices/edit.blade.php +++ b/resources/views/invoices/edit.blade.php @@ -63,8 +63,13 @@

    - {{ trans('texts.edit_client') }} | - {!! link_to('/clients/'.$invoice->client->public_id, trans('texts.view_client'), ['target' => '_blank']) !!} + + @if($invoice->client->canView()) + @if ($invoice->client->canEdit()) + {{ trans('texts.edit_client') }} | + @endif + {!! link_to('/clients/'.$invoice->client->public_id, trans('texts.view_client'), ['target' => '_blank']) !!} + @endif

    diff --git a/resources/views/list.blade.php b/resources/views/list.blade.php index 6e567bf3de..92f7d22cbd 100644 --- a/resources/views/list.blade.php +++ b/resources/views/list.blade.php @@ -9,12 +9,14 @@ {!! Former::text('public_id') !!}
    - @if ($entityType == ENTITY_TASK) - {!! Button::primary(trans('texts.invoice'))->withAttributes(['class'=>'invoice', 'onclick' =>'submitForm("invoice")'])->appendIcon(Icon::create('check')) !!} - @endif - @if ($entityType == ENTITY_EXPENSE) - {!! Button::primary(trans('texts.invoice'))->withAttributes(['class'=>'invoice', 'onclick' =>'submitForm("invoice")'])->appendIcon(Icon::create('check')) !!} - @endif + @if (\App\Models\Invoice::canCreate()) + @if ($entityType == ENTITY_TASK) + {!! Button::primary(trans('texts.invoice'))->withAttributes(['class'=>'invoice', 'onclick' =>'submitForm("invoice")'])->appendIcon(Icon::create('check')) !!} + @endif + @if ($entityType == ENTITY_EXPENSE) + {!! Button::primary(trans('texts.invoice'))->withAttributes(['class'=>'invoice', 'onclick' =>'submitForm("invoice")'])->appendIcon(Icon::create('check')) !!} + @endif + @endif {!! DropdownButton::normal(trans('texts.archive'))->withContents([ ['label' => trans('texts.archive_'.$entityType), 'url' => 'javascript:submitForm("archive")'], @@ -38,7 +40,9 @@ {!! Button::normal(trans('texts.credits'))->asLinkTo(URL::to('/credits'))->appendIcon(Icon::create('list')) !!} @endif - {!! Button::primary(trans("texts.new_$entityType"))->asLinkTo(URL::to("/{$entityType}s/create"))->appendIcon(Icon::create('plus-sign')) !!} + @if (Auth::user()->hasPermission('create_all')) + {!! Button::primary(trans("texts.new_$entityType"))->asLinkTo(URL::to("/{$entityType}s/create"))->appendIcon(Icon::create('plus-sign')) !!} + @endif
    diff --git a/resources/views/user_account.blade.php b/resources/views/user_account.blade.php index 9ab41f845b..9be002ada0 100644 --- a/resources/views/user_account.blade.php +++ b/resources/views/user_account.blade.php @@ -1,8 +1,12 @@
  • - @if (isset($user_id) && $user_id != Auth::user()->id) - - @else - + @if (Utils::isAdmin()) + @if (isset($user_id) && $user_id != Auth::user()->id) + + @else + + @endif + @else + @endif @if (file_exists($logo_path)) @@ -23,7 +27,6 @@ @if (isset($selected) && $selected) @endif -
  • \ No newline at end of file diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php index 71efd2fee6..3e77e91442 100644 --- a/resources/views/users/edit.blade.php +++ b/resources/views/users/edit.blade.php @@ -23,7 +23,26 @@ {!! Former::text('first_name') !!} {!! Former::text('last_name') !!} {!! Former::text('email') !!} - + {!! Former::checkbox('is_admin') + ->label(' ') + ->text(trans('texts.administrator')) + ->help(trans('texts.administrator_help')) !!} + {!! Former::checkbox('permissions[create_all]') + ->value('create_all') + ->label(' ') + ->id('permissions_create_all') + ->text(trans('texts.user_create_all')) !!} + {!! Former::checkbox('permissions[view_all]') + ->value('view_all') + ->label(' ') + ->id('permissions_view_all') + ->text(trans('texts.user_view_all')) !!} + {!! Former::checkbox('permissions[edit_all]') + ->value('edit_all') + ->label(' ') + ->id('permissions_edit_all') + ->text(trans('texts.user_edit_all')) !!} +
    @@ -38,4 +57,14 @@ @section('onReady') $('#first_name').focus(); + $('#is_admin, #permissions_view_all').change(fixCheckboxes); + function fixCheckboxes(){ + var adminChecked = $('#is_admin').is(':checked'); + var viewChecked = $('#permissions_view_all').is(':checked'); + + $('#permissions_view_all').prop('disabled', adminChecked); + $('#permissions_create_all').prop('disabled', adminChecked); + $('#permissions_edit_all').prop('disabled', adminChecked || !viewChecked); + } + fixCheckboxes(); @stop \ No newline at end of file