Add user permission support

This commit is contained in:
Joshua Dwire 2016-03-15 19:08:00 -04:00
parent 25b0957a7f
commit 0148d06205
45 changed files with 719 additions and 159 deletions

View File

@ -137,8 +137,6 @@ class AccountController extends BaseController
if ($section == ACCOUNT_COMPANY_DETAILS) { if ($section == ACCOUNT_COMPANY_DETAILS) {
return self::showCompanyDetails(); return self::showCompanyDetails();
} elseif ($section == ACCOUNT_USER_DETAILS) {
return self::showUserDetails();
} elseif ($section == ACCOUNT_LOCALIZATION) { } elseif ($section == ACCOUNT_LOCALIZATION) {
return self::showLocalization(); return self::showLocalization();
} elseif ($section == ACCOUNT_PAYMENTS) { } elseif ($section == ACCOUNT_PAYMENTS) {
@ -232,7 +230,7 @@ class AccountController extends BaseController
return View::make('accounts.details', $data); return View::make('accounts.details', $data);
} }
private function showUserDetails() public function showUserDetails()
{ {
$oauthLoginUrls = []; $oauthLoginUrls = [];
foreach (AuthService::$providers as $provider) { foreach (AuthService::$providers as $provider) {
@ -467,8 +465,6 @@ class AccountController extends BaseController
{ {
if ($section === ACCOUNT_COMPANY_DETAILS) { if ($section === ACCOUNT_COMPANY_DETAILS) {
return AccountController::saveDetails(); return AccountController::saveDetails();
} elseif ($section === ACCOUNT_USER_DETAILS) {
return AccountController::saveUserDetails();
} elseif ($section === ACCOUNT_LOCALIZATION) { } elseif ($section === ACCOUNT_LOCALIZATION) {
return AccountController::saveLocalization(); return AccountController::saveLocalization();
} elseif ($section === ACCOUNT_NOTIFICATIONS) { } elseif ($section === ACCOUNT_NOTIFICATIONS) {
@ -839,7 +835,7 @@ class AccountController extends BaseController
return Redirect::to('settings/'.ACCOUNT_COMPANY_DETAILS); return Redirect::to('settings/'.ACCOUNT_COMPANY_DETAILS);
} }
private function saveUserDetails() public function saveUserDetails()
{ {
$user = Auth::user(); $user = Auth::user();
$rules = ['email' => 'email|required|unique:users,email,'.$user->id.',id']; $rules = ['email' => 'email|required|unique:users,email,'.$user->id.',id'];

View File

@ -1,11 +1,15 @@
<?php namespace App\Http\Controllers; <?php namespace App\Http\Controllers;
use App\Http\Middleware\PermissionsRequired;
use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Foundation\Bus\DispatchesJobs;
use Auth;
class BaseController extends Controller class BaseController extends Controller
{ {
use DispatchesJobs; use DispatchesJobs;
protected $model = 'App\Models\EntityModel';
/** /**
* Setup the layout used by the controller. * Setup the layout used by the controller.
* *
@ -18,10 +22,39 @@ class BaseController extends Controller
} }
} }
/* protected function checkViewPermission($object, &$response = null){
public function __construct() if(!$object->canView()){
{ $response = response('Unauthorized.', 401);
$this->beforeFilter('csrf', array('on' => array('post', 'delete', 'put'))); 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);
}
} }
*/
} }

View File

@ -20,6 +20,9 @@ use App\Models\Size;
use App\Models\PaymentTerm; use App\Models\PaymentTerm;
use App\Models\Industry; use App\Models\Industry;
use App\Models\Currency; use App\Models\Currency;
use App\Models\Payment;
use App\Models\Credit;
use App\Models\Expense;
use App\Models\Country; use App\Models\Country;
use App\Models\Task; use App\Models\Task;
use App\Ninja\Repositories\ClientRepository; use App\Ninja\Repositories\ClientRepository;
@ -32,6 +35,7 @@ class ClientController extends BaseController
{ {
protected $clientService; protected $clientService;
protected $clientRepo; protected $clientRepo;
protected $model = 'App\Models\Client';
public function __construct(ClientRepository $clientRepo, ClientService $clientService) public function __construct(ClientRepository $clientRepo, ClientService $clientService)
{ {
@ -77,7 +81,13 @@ class ClientController extends BaseController
*/ */
public function store(CreateClientRequest $request) 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')); Session::flash('message', trans('texts.created_client'));
@ -93,22 +103,36 @@ class ClientController extends BaseController
public function show($publicId) public function show($publicId)
{ {
$client = Client::withTrashed()->scope($publicId)->with('contacts', 'size', 'industry')->firstOrFail(); $client = Client::withTrashed()->scope($publicId)->with('contacts', 'size', 'industry')->firstOrFail();
Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT);
$actionLinks = [ if(!$this->checkViewPermission($client, $response)){
['label' => trans('texts.new_task'), 'url' => '/tasks/create/'.$client->public_id] return $response;
];
if (Utils::isPro()) {
array_push($actionLinks, ['label' => trans('texts.new_quote'), 'url' => '/quotes/create/'.$client->public_id]);
} }
array_push($actionLinks, Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT);
\DropdownButton::DIVIDER,
['label' => trans('texts.enter_payment'), 'url' => '/payments/create/'.$client->public_id], $actionLinks = [];
['label' => trans('texts.enter_credit'), 'url' => '/credits/create/'.$client->public_id], if(Task::canCreate()){
['label' => trans('texts.enter_expense'), 'url' => '/expenses/create/0/'.$client->public_id] $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];
}
$data = array( $data = array(
'actionLinks' => $actionLinks, 'actionLinks' => $actionLinks,
@ -132,6 +156,10 @@ class ClientController extends BaseController
*/ */
public function create() public function create()
{ {
if(!$this->checkCreatePermission($response)){
return $response;
}
if (Client::scope()->withTrashed()->count() > Auth::user()->getMaxNumClients()) { 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"]); 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) public function edit($publicId)
{ {
$client = Client::scope($publicId)->with('contacts')->firstOrFail(); $client = Client::scope($publicId)->with('contacts')->firstOrFail();
if(!$this->checkEditPermission($client, $response)){
return $response;
}
$data = [ $data = [
'client' => $client, 'client' => $client,
'method' => 'PUT', 'method' => 'PUT',
@ -199,7 +232,13 @@ class ClientController extends BaseController
*/ */
public function update(UpdateClientRequest $request) 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')); Session::flash('message', trans('texts.updated_client'));

View File

@ -17,10 +17,11 @@ class CreditController extends BaseController
{ {
protected $creditRepo; protected $creditRepo;
protected $creditService; protected $creditService;
protected $model = 'App\Models\Credit';
public function __construct(CreditRepository $creditRepo, CreditService $creditService) public function __construct(CreditRepository $creditRepo, CreditService $creditService)
{ {
//parent::__construct(); // parent::__construct();
$this->creditRepo = $creditRepo; $this->creditRepo = $creditRepo;
$this->creditService = $creditService; $this->creditService = $creditService;
@ -56,6 +57,10 @@ class CreditController extends BaseController
public function create($clientPublicId = 0) public function create($clientPublicId = 0)
{ {
if(!$this->checkCreatePermission($response)){
return $response;
}
$data = array( $data = array(
'clientPublicId' => Input::old('client') ? Input::old('client') : $clientPublicId, 'clientPublicId' => Input::old('client') ? Input::old('client') : $clientPublicId,
//'invoicePublicId' => Input::old('invoice') ? Input::old('invoice') : $invoicePublicId, //'invoicePublicId' => Input::old('invoice') ? Input::old('invoice') : $invoicePublicId,
@ -72,6 +77,11 @@ class CreditController extends BaseController
public function edit($publicId) public function edit($publicId)
{ {
$credit = Credit::scope($publicId)->firstOrFail(); $credit = Credit::scope($publicId)->firstOrFail();
if(!$this->checkEditPermission($credit, $response)){
return $response;
}
$credit->credit_date = Utils::fromSqlDate($credit->credit_date); $credit->credit_date = Utils::fromSqlDate($credit->credit_date);
$data = array( $data = array(

View File

@ -25,10 +25,11 @@ class ExpenseController extends BaseController
// Expenses // Expenses
protected $expenseRepo; protected $expenseRepo;
protected $expenseService; protected $expenseService;
protected $model = 'App\Models\Expense';
public function __construct(ExpenseRepository $expenseRepo, ExpenseService $expenseService) public function __construct(ExpenseRepository $expenseRepo, ExpenseService $expenseService)
{ {
//parent::__construct(); // parent::__construct();
$this->expenseRepo = $expenseRepo; $this->expenseRepo = $expenseRepo;
$this->expenseService = $expenseService; $this->expenseService = $expenseService;
@ -70,6 +71,10 @@ class ExpenseController extends BaseController
public function create($vendorPublicId = null, $clientPublicId = null) public function create($vendorPublicId = null, $clientPublicId = null)
{ {
if(!$this->checkCreatePermission($response)){
return $response;
}
if($vendorPublicId != 0) { if($vendorPublicId != 0) {
$vendor = Vendor::scope($vendorPublicId)->with('vendorcontacts')->firstOrFail(); $vendor = Vendor::scope($vendorPublicId)->with('vendorcontacts')->firstOrFail();
} else { } else {
@ -95,6 +100,11 @@ class ExpenseController extends BaseController
public function edit($publicId) public function edit($publicId)
{ {
$expense = Expense::scope($publicId)->firstOrFail(); $expense = Expense::scope($publicId)->firstOrFail();
if(!$this->checkEditPermission($expense, $response)){
return $response;
}
$expense->expense_date = Utils::fromSqlDate($expense->expense_date); $expense->expense_date = Utils::fromSqlDate($expense->expense_date);
$actions = []; $actions = [];

View File

@ -34,10 +34,11 @@ class InvoiceController extends BaseController
protected $clientRepo; protected $clientRepo;
protected $invoiceService; protected $invoiceService;
protected $recurringInvoiceService; protected $recurringInvoiceService;
protected $model = 'App\Models\Invoice';
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService, RecurringInvoiceService $recurringInvoiceService) public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService, RecurringInvoiceService $recurringInvoiceService)
{ {
//parent::__construct(); // parent::__construct();
$this->mailer = $mailer; $this->mailer = $mailer;
$this->invoiceRepo = $invoiceRepo; $this->invoiceRepo = $invoiceRepo;
@ -90,6 +91,11 @@ class InvoiceController extends BaseController
->with('invitations', 'account.country', 'client.contacts', 'client.country', 'invoice_items') ->with('invitations', 'account.country', 'client.contacts', 'client.country', 'invoice_items')
->withTrashed() ->withTrashed()
->firstOrFail(); ->firstOrFail();
if(!$this->checkEditPermission($invoice, $response)){
return $response;
}
$entityType = $invoice->getEntityType(); $entityType = $invoice->getEntityType();
$contactIds = DB::table('invitations') $contactIds = DB::table('invitations')
@ -206,6 +212,10 @@ class InvoiceController extends BaseController
public function create($clientPublicId = 0, $isRecurring = false) public function create($clientPublicId = 0, $isRecurring = false)
{ {
if(!$this->checkCreatePermission($response)){
return $response;
}
$account = Auth::user()->account; $account = Auth::user()->account;
$entityType = $isRecurring ? ENTITY_RECURRING_INVOICE : ENTITY_INVOICE; $entityType = $isRecurring ? ENTITY_RECURRING_INVOICE : ENTITY_INVOICE;
$clientId = null; $clientId = null;

View File

@ -30,9 +30,11 @@ use App\Http\Requests\UpdatePaymentRequest;
class PaymentController extends BaseController class PaymentController extends BaseController
{ {
protected $model = 'App\Models\Payment';
public function __construct(PaymentRepository $paymentRepo, InvoiceRepository $invoiceRepo, AccountRepository $accountRepo, ContactMailer $contactMailer, PaymentService $paymentService) public function __construct(PaymentRepository $paymentRepo, InvoiceRepository $invoiceRepo, AccountRepository $accountRepo, ContactMailer $contactMailer, PaymentService $paymentService)
{ {
//parent::__construct(); // parent::__construct();
$this->paymentRepo = $paymentRepo; $this->paymentRepo = $paymentRepo;
$this->invoiceRepo = $invoiceRepo; $this->invoiceRepo = $invoiceRepo;
@ -66,6 +68,10 @@ class PaymentController extends BaseController
public function create($clientPublicId = 0, $invoicePublicId = 0) public function create($clientPublicId = 0, $invoicePublicId = 0)
{ {
if(!$this->checkCreatePermission($response)){
return $response;
}
$invoices = Invoice::scope() $invoices = Invoice::scope()
->where('is_recurring', '=', false) ->where('is_recurring', '=', false)
->where('is_quote', '=', false) ->where('is_quote', '=', false)
@ -92,6 +98,11 @@ class PaymentController extends BaseController
public function edit($publicId) public function edit($publicId)
{ {
$payment = Payment::scope($publicId)->firstOrFail(); $payment = Payment::scope($publicId)->firstOrFail();
if(!$this->checkEditPermission($payment, $response)){
return $response;
}
$payment->payment_date = Utils::fromSqlDate($payment->payment_date); $payment->payment_date = Utils::fromSqlDate($payment->payment_date);
$data = array( $data = array(

View File

@ -33,10 +33,11 @@ class QuoteController extends BaseController
protected $invoiceRepo; protected $invoiceRepo;
protected $clientRepo; protected $clientRepo;
protected $invoiceService; protected $invoiceService;
protected $model = 'App\Models\Invoice';
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService) public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService)
{ {
//parent::__construct(); // parent::__construct();
$this->mailer = $mailer; $this->mailer = $mailer;
$this->invoiceRepo = $invoiceRepo; $this->invoiceRepo = $invoiceRepo;
@ -78,6 +79,10 @@ class QuoteController extends BaseController
public function create($clientPublicId = 0) public function create($clientPublicId = 0)
{ {
if(!$this->checkCreatePermission($response)){
return $response;
}
if (!Utils::isPro()) { if (!Utils::isPro()) {
return Redirect::to('/invoices/create'); return Redirect::to('/invoices/create');
} }

View File

@ -22,10 +22,11 @@ class TaskController extends BaseController
{ {
protected $taskRepo; protected $taskRepo;
protected $taskService; protected $taskService;
protected $model = 'App\Models\Task';
public function __construct(TaskRepository $taskRepo, InvoiceRepository $invoiceRepo, TaskService $taskService) public function __construct(TaskRepository $taskRepo, InvoiceRepository $invoiceRepo, TaskService $taskService)
{ {
//parent::__construct(); // parent::__construct();
$this->taskRepo = $taskRepo; $this->taskRepo = $taskRepo;
$this->invoiceRepo = $invoiceRepo; $this->invoiceRepo = $invoiceRepo;
@ -67,6 +68,10 @@ class TaskController extends BaseController
*/ */
public function store() public function store()
{ {
if(!$this->checkCreatePermission($response)){
return $response;
}
return $this->save(); return $this->save();
} }
@ -84,6 +89,9 @@ class TaskController extends BaseController
*/ */
public function create($clientPublicId = 0) public function create($clientPublicId = 0)
{ {
if(!$this->checkCreatePermission($response)){
return $response;
}
$this->checkTimezone(); $this->checkTimezone();
$data = [ $data = [
@ -113,6 +121,10 @@ class TaskController extends BaseController
$task = Task::scope($publicId)->with('client', 'invoice')->withTrashed()->firstOrFail(); $task = Task::scope($publicId)->with('client', 'invoice')->withTrashed()->firstOrFail();
if(!$this->checkEditPermission($task, $response)){
return $response;
}
$actions = []; $actions = [];
if ($task->invoice) { if ($task->invoice) {
$actions[] = ['url' => URL::to("invoices/{$task->invoice->public_id}/edit"), 'label' => trans("texts.view_invoice")]; $actions[] = ['url' => URL::to("invoices/{$task->invoice->public_id}/edit"), 'label' => trans("texts.view_invoice")];

View File

@ -192,6 +192,8 @@ class UserController extends BaseController
$user->last_name = trim(Input::get('last_name')); $user->last_name = trim(Input::get('last_name'));
$user->username = trim(Input::get('email')); $user->username = trim(Input::get('email'));
$user->email = trim(Input::get('email')); $user->email = trim(Input::get('email'));
$user->is_admin = boolval(Input::get('is_admin'));
$user->permissions = Input::get('permissions');
} else { } else {
$lastUser = User::withTrashed()->where('account_id', '=', Auth::user()->account_id) $lastUser = User::withTrashed()->where('account_id', '=', Auth::user()->account_id)
->orderBy('public_id', 'DESC')->first(); ->orderBy('public_id', 'DESC')->first();
@ -202,10 +204,12 @@ class UserController extends BaseController
$user->last_name = trim(Input::get('last_name')); $user->last_name = trim(Input::get('last_name'));
$user->username = trim(Input::get('email')); $user->username = trim(Input::get('email'));
$user->email = trim(Input::get('email')); $user->email = trim(Input::get('email'));
$user->is_admin = boolval(Input::get('is_admin'));
$user->registered = true; $user->registered = true;
$user->password = str_random(RANDOM_KEY_LENGTH); $user->password = str_random(RANDOM_KEY_LENGTH);
$user->confirmation_code = str_random(RANDOM_KEY_LENGTH); $user->confirmation_code = str_random(RANDOM_KEY_LENGTH);
$user->public_id = $lastUser->public_id + 1; $user->public_id = $lastUser->public_id + 1;
$user->permissions = Input::get('permissions');
} }
$user->save(); $user->save();

View File

@ -30,6 +30,7 @@ class VendorController extends BaseController
{ {
protected $vendorService; protected $vendorService;
protected $vendorRepo; protected $vendorRepo;
protected $model = 'App\Models\Vendor';
public function __construct(VendorRepository $vendorRepo, VendorService $vendorService) public function __construct(VendorRepository $vendorRepo, VendorService $vendorService)
{ {
@ -92,6 +93,11 @@ class VendorController extends BaseController
public function show($publicId) public function show($publicId)
{ {
$vendor = Vendor::withTrashed()->scope($publicId)->with('vendorcontacts', 'size', 'industry')->firstOrFail(); $vendor = Vendor::withTrashed()->scope($publicId)->with('vendorcontacts', 'size', 'industry')->firstOrFail();
if(!$this->checkViewPermission($vendor, $response)){
return $response;
}
Utils::trackViewed($vendor->getDisplayName(), 'vendor'); Utils::trackViewed($vendor->getDisplayName(), 'vendor');
$actionLinks = [ $actionLinks = [
@ -119,6 +125,10 @@ class VendorController extends BaseController
*/ */
public function create() public function create()
{ {
if(!$this->checkCreatePermission($response)){
return $response;
}
if (Vendor::scope()->count() > Auth::user()->getMaxNumVendors()) { 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"]); return View::make('error', ['hideHeader' => true, 'error' => "Sorry, you've exceeded the limit of ".Auth::user()->getMaxNumVendors()." vendors"]);
} }
@ -144,6 +154,11 @@ class VendorController extends BaseController
public function edit($publicId) public function edit($publicId)
{ {
$vendor = Vendor::scope($publicId)->with('vendorcontacts')->firstOrFail(); $vendor = Vendor::scope($publicId)->with('vendorcontacts')->firstOrFail();
if(!$this->checkEditPermission($vendor, $response)){
return $response;
}
$data = [ $data = [
'vendor' => $vendor, 'vendor' => $vendor,
'method' => 'PUT', 'method' => 'PUT',

View File

@ -28,6 +28,7 @@ class Kernel extends HttpKernel {
protected $routeMiddleware = [ protected $routeMiddleware = [
'auth' => 'App\Http\Middleware\Authenticate', 'auth' => 'App\Http\Middleware\Authenticate',
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth', 'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
'permissions.required' => 'App\Http\Middleware\PermissionsRequired',
'guest' => 'App\Http\Middleware\RedirectIfAuthenticated', 'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
'api' => 'App\Http\Middleware\ApiCheck', 'api' => 'App\Http\Middleware\ApiCheck',
]; ];

View File

@ -0,0 +1,57 @@
<?php namespace App\Http\Middleware;
use Closure;
use Auth;
class PermissionsRequired {
/**
* @var array of controller => [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;
}
}

View File

@ -105,20 +105,8 @@ Route::group(['middleware' => 'auth:user'], function() {
Route::get('hide_message', 'HomeController@hideMessage'); Route::get('hide_message', 'HomeController@hideMessage');
Route::get('force_inline_pdf', 'UserController@forcePDFJS'); Route::get('force_inline_pdf', 'UserController@forcePDFJS');
Route::get('api/users', array('as'=>'api.users', 'uses'=>'UserController@getDatatable')); Route::get('settings/user_details', 'AccountController@showUserDetails');
Route::resource('users', 'UserController'); Route::post('settings/user_details', 'AccountController@saveUserDetails');
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::get('api/products', array('as'=>'api.products', 'uses'=>'ProductController@getDatatable'));
Route::resource('products', 'ProductController'); Route::resource('products', 'ProductController');
@ -128,39 +116,6 @@ Route::group(['middleware' => 'auth:user'], function() {
Route::resource('tax_rates', 'TaxRateController'); Route::resource('tax_rates', 'TaxRateController');
Route::post('tax_rates/bulk', 'TaxRateController@bulk'); 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::resource('clients', 'ClientController'); Route::resource('clients', 'ClientController');
Route::get('api/clients', array('as'=>'api.clients', 'uses'=>'ClientController@getDatatable')); Route::get('api/clients', array('as'=>'api.clients', 'uses'=>'ClientController@getDatatable'));
Route::get('api/activities/{client_id?}', array('as'=>'api.activities', 'uses'=>'ActivityController@getDatatable')); Route::get('api/activities/{client_id?}', array('as'=>'api.activities', 'uses'=>'ActivityController@getDatatable'));
@ -222,6 +177,59 @@ Route::group(['middleware' => 'auth:user'], function() {
Route::post('expenses/bulk', 'ExpenseController@bulk'); 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('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 groups for API
Route::group(['middleware' => 'api', 'prefix' => 'api/v1'], function() Route::group(['middleware' => 'api', 'prefix' => 'api/v1'], function()
{ {
@ -604,6 +612,7 @@ if (!defined('CONTACT_EMAIL')) {
define('USER_STATE_PENDING', 'pending'); define('USER_STATE_PENDING', 'pending');
define('USER_STATE_DISABLED', 'disabled'); define('USER_STATE_DISABLED', 'disabled');
define('USER_STATE_ADMIN', 'admin'); define('USER_STATE_ADMIN', 'admin');
define('USER_STATE_OWNER', 'owner');
define('API_SERIALIZER_ARRAY', 'array'); define('API_SERIALIZER_ARRAY', 'array');
define('API_SERIALIZER_JSON', 'json'); define('API_SERIALIZER_JSON', 'json');

View File

@ -118,6 +118,21 @@ class Utils
return Auth::check() && Auth::user()->isPro(); 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() public static function isTrial()
{ {
return Auth::check() && Auth::user()->isTrial(); return Auth::check() && Auth::user()->isTrial();

View File

@ -113,4 +113,40 @@ class EntityModel extends Eloquent
$name = $parts[count($parts)-1]; $name = $parts[count($parts)-1];
return strtolower($name) . '_id'; 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 function canView() {
return static::canEdit($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;
}
} }

View File

@ -21,4 +21,8 @@ class Product extends EntityModel
{ {
return $this->belongsTo('App\Models\TaxRate'); return $this->belongsTo('App\Models\TaxRate');
} }
public function canEdit() {
return Auth::user()->hasPermission('admin');
}
} }

View File

@ -16,4 +16,8 @@ class TaxRate extends EntityModel
{ {
return ENTITY_TAX_RATE; return ENTITY_TAX_RATE;
} }
public function canEdit() {
return Auth::user()->hasPermission('admin');
}
} }

View File

@ -14,6 +14,11 @@ use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Model implements AuthenticatableContract, CanResetPasswordContract { class User extends Model implements AuthenticatableContract, CanResetPasswordContract {
public static $all_permissions = array(
'create_all' => 0b0001,
'view_all' => 0b0010,
'edit_all' => 0b0100,
);
use Authenticatable, CanResetPassword; use Authenticatable, CanResetPassword;
@ -254,6 +259,68 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
&& $this->getOriginal('confirmed'); && $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) { User::updating(function ($user) {

View File

@ -46,7 +46,8 @@ class ClientRepository extends BaseRepository
'clients.work_phone', 'clients.work_phone',
'contacts.email', 'contacts.email',
'clients.deleted_at', 'clients.deleted_at',
'clients.is_deleted' 'clients.is_deleted',
'clients.user_id'
); );
if (!\Session::get('show_trash:client')) { if (!\Session::get('show_trash:client')) {

View File

@ -37,7 +37,8 @@ class CreditRepository extends BaseRepository
'contacts.email', 'contacts.email',
'credits.private_notes', 'credits.private_notes',
'credits.deleted_at', 'credits.deleted_at',
'credits.is_deleted' 'credits.is_deleted',
'credits.user_id'
); );
if ($clientPublicId) { if ($clientPublicId) {

View File

@ -40,7 +40,8 @@ class ExpenseRepository extends BaseRepository
'expenses.public_id', 'expenses.public_id',
'expenses.deleted_at', 'expenses.deleted_at',
'expenses.should_be_invoiced', 'expenses.should_be_invoiced',
'expenses.created_at' 'expenses.created_at',
'expenses.user_id'
); );
return $query; return $query;

View File

@ -65,7 +65,8 @@ class InvoiceRepository extends BaseRepository
'invoices.quote_invoice_id', 'invoices.quote_invoice_id',
'invoices.deleted_at', 'invoices.deleted_at',
'invoices.is_deleted', 'invoices.is_deleted',
'invoices.partial' 'invoices.partial',
'invoices.user_id'
); );
if (!\Session::get('show_trash:'.$entityType)) { if (!\Session::get('show_trash:'.$entityType)) {

View File

@ -47,6 +47,7 @@ class PaymentRepository extends BaseRepository
'payments.account_gateway_id', 'payments.account_gateway_id',
'payments.deleted_at', 'payments.deleted_at',
'payments.is_deleted', 'payments.is_deleted',
'payments.user_id',
'invoices.is_deleted as invoice_is_deleted', 'invoices.is_deleted as invoice_is_deleted',
'gateways.name as gateway_name' 'gateways.name as gateway_name'
); );

View File

@ -38,7 +38,8 @@ class TaskRepository
'invoices.public_id as invoice_public_id', 'invoices.public_id as invoice_public_id',
'tasks.is_running', 'tasks.is_running',
'tasks.time_log', 'tasks.time_log',
'tasks.created_at' 'tasks.created_at',
'tasks.user_id'
); );
if ($clientPublicId) { if ($clientPublicId) {

View File

@ -22,7 +22,7 @@ class UserRepository extends BaseRepository
$query->where('users.deleted_at', '=', null); $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; return $query;
} }
@ -34,5 +34,4 @@ class UserRepository extends BaseRepository
return $user; return $user;
} }
} }

View File

@ -42,7 +42,8 @@ class VendorRepository extends BaseRepository
'vendors.city', 'vendors.city',
'vendor_contacts.email', 'vendor_contacts.email',
'vendors.deleted_at', 'vendors.deleted_at',
'vendors.is_deleted' 'vendors.is_deleted',
'vendors.user_id'
); );
if (!\Session::get('show_trash:vendor')) { if (!\Session::get('show_trash:vendor')) {

View File

@ -8,6 +8,9 @@ use Form;
use URL; use URL;
use Request; use Request;
use Validator; use Validator;
use App\Models\Credit;
use App\Models\Invoice;
use App\Models\Vendor;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider { class AppServiceProvider extends ServiceProvider {
@ -46,31 +49,38 @@ class AppServiceProvider extends ServiceProvider {
$class = ( Request::is($types) || Request::is('*'.$type.'*')) && !Request::is('*settings*') ? ' active' : ''; $class = ( Request::is($types) || Request::is('*'.$type.'*')) && !Request::is('*settings*') ? ' active' : '';
$str = '<li class="dropdown '.$class.'"> $str = '<li class="dropdown '.$class.'">
<a href="'.URL::to($types).'" class="dropdown-toggle">'.trans("texts.$types").'</a> <a href="'.URL::to($types).'" class="dropdown-toggle">'.trans("texts.$types").'</a>';
<ul class="dropdown-menu" id="menu1">
<li><a href="'.URL::to($types.'/create').'">'.trans("texts.new_$type").'</a></li>'; $items = [];
if(Auth::user()->hasPermission('create_all')){
$items[] = '<li><a href="'.URL::to($types.'/create').'">'.trans("texts.new_$type").'</a></li>';
}
if ($type == ENTITY_INVOICE) { if ($type == ENTITY_INVOICE) {
$str .= '<li class="divider"></li> if(!empty($items))$items[] = '<li class="divider"></li>';
<li><a href="'.URL::to('recurring_invoices').'">'.trans("texts.recurring_invoices").'</a></li> $items[] = '<li><a href="'.URL::to('recurring_invoices').'">'.trans("texts.recurring_invoices").'</a></li>';
<li><a href="'.URL::to('recurring_invoices/create').'">'.trans("texts.new_recurring_invoice").'</a></li>'; if(Invoice::canCreate())$items[] = '<li><a href="'.URL::to('recurring_invoices/create').'">'.trans("texts.new_recurring_invoice").'</a></li>';
if (Auth::user()->isPro()) { if (Auth::user()->isPro()) {
$str .= '<li class="divider"></li> $items[] = '<li class="divider"></li>';
<li><a href="'.URL::to('quotes').'">'.trans("texts.quotes").'</a></li> $items[] = '<li><a href="'.URL::to('quotes').'">'.trans("texts.quotes").'</a></li>';
<li><a href="'.URL::to('quotes/create').'">'.trans("texts.new_quote").'</a></li>'; if(Invoice::canCreate())$items[] = '<li><a href="'.URL::to('quotes/create').'">'.trans("texts.new_quote").'</a></li>';
} }
} else if ($type == ENTITY_CLIENT) { } else if ($type == ENTITY_CLIENT) {
$str .= '<li class="divider"></li> if(!empty($items))$items[] = '<li class="divider"></li>';
<li><a href="'.URL::to('credits').'">'.trans("texts.credits").'</a></li> $items[] = '<li><a href="'.URL::to('credits').'">'.trans("texts.credits").'</a></li>';
<li><a href="'.URL::to('credits/create').'">'.trans("texts.new_credit").'</a></li>'; if(Credit::canCreate())$items[] = '<li><a href="'.URL::to('credits/create').'">'.trans("texts.new_credit").'</a></li>';
} else if ($type == ENTITY_EXPENSE) { } else if ($type == ENTITY_EXPENSE) {
$str .= '<li class="divider"></li> if(!empty($items))$items[] = '<li class="divider"></li>';
<li><a href="'.URL::to('vendors').'">'.trans("texts.vendors").'</a></li> $items[] = '<li><a href="'.URL::to('vendors').'">'.trans("texts.vendors").'</a></li>';
<li><a href="'.URL::to('vendors/create').'">'.trans("texts.new_vendor").'</a></li>'; if(Vendor::canCreate())$items[] = '<li><a href="'.URL::to('vendors/create').'">'.trans("texts.new_vendor").'</a></li>';
} }
$str .= '</ul> if(!empty($items)){
</li>'; $str.= '<ul class="dropdown-menu" id="menu1">'.implode($items).'</ul>';
}
$str .= '</li>';
return $str; return $str;
}); });

View File

@ -4,6 +4,12 @@ use Utils;
use URL; use URL;
use Auth; use Auth;
use App\Services\BaseService; 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\ClientRepository;
use App\Ninja\Repositories\NinjaRepository; use App\Ninja\Repositories\NinjaRepository;
@ -37,6 +43,10 @@ class ClientService extends BaseService
{ {
$query = $this->clientRepo->find($search); $query = $this->clientRepo->find($search);
if(!Utils::hasPermission('view_all')){
$query->where('clients.user_id', '=', Auth::user()->id);
}
return $this->createDatatable(ENTITY_CLIENT, $query); return $this->createDatatable(ENTITY_CLIENT, $query);
} }
@ -89,19 +99,33 @@ class ClientService extends BaseService
trans('texts.edit_client'), trans('texts.edit_client'),
function ($model) { function ($model) {
return URL::to("clients/{$model->public_id}/edit"); 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'), trans('texts.new_task'),
function ($model) { function ($model) {
return URL::to("tasks/create/{$model->public_id}"); return URL::to("tasks/create/{$model->public_id}");
},
function ($model) {
return Task::canCreate();
} }
], ],
[ [
trans('texts.new_invoice'), trans('texts.new_invoice'),
function ($model) { function ($model) {
return URL::to("invoices/create/{$model->public_id}"); 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}"); return URL::to("quotes/create/{$model->public_id}");
}, },
function ($model) { 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'), trans('texts.enter_payment'),
function ($model) { function ($model) {
return URL::to("payments/create/{$model->public_id}"); return URL::to("payments/create/{$model->public_id}");
},
function ($model) {
return Payment::canCreate();
} }
], ],
[ [
trans('texts.enter_credit'), trans('texts.enter_credit'),
function ($model) { function ($model) {
return URL::to("credits/create/{$model->public_id}"); return URL::to("credits/create/{$model->public_id}");
},
function ($model) {
return Credit::canCreate();
} }
], ],
[ [
trans('texts.enter_expense'), trans('texts.enter_expense'),
function ($model) { function ($model) {
return URL::to("expenses/create/0/{$model->public_id}"); return URL::to("expenses/create/0/{$model->public_id}");
},
function ($model) {
return Expense::canCreate();
} }
] ]
]; ];

View File

@ -3,6 +3,7 @@
use HtmlString; use HtmlString;
use Utils; use Utils;
use Datatable; use Datatable;
use Auth;
class DatatableService class DatatableService
{ {
@ -45,6 +46,8 @@ class DatatableService
$hasAction = false; $hasAction = false;
$str = '<center style="min-width:100px">'; $str = '<center style="min-width:100px">';
$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) { 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>'; $str .= '<button type="button" class="btn btn-sm btn-danger tr-status">'.trans('texts.deleted').'</button>';
} elseif ($model->deleted_at && $model->deleted_at !== '0000-00-00') { } elseif ($model->deleted_at && $model->deleted_at !== '0000-00-00') {
@ -70,9 +73,15 @@ class DatatableService
} }
list($value, $url, $visible) = $action; list($value, $url, $visible) = $action;
if ($visible($model)) { if ($visible($model)) {
if($value == '--divider--'){
$str .= "<li class=\"divider\"></li>";
$lastIsDivider = true;
}
else {
$str .= "<li><a href=\"{$url($model)}\">{$value}</a></li>"; $str .= "<li><a href=\"{$url($model)}\">{$value}</a></li>";
$lastIsDivider = false;
$hasAction = true; $hasAction = true;
$lastIsDivider = false;
}
} }
} elseif ( ! $lastIsDivider) { } elseif ( ! $lastIsDivider) {
$str .= "<li class=\"divider\"></li>"; $str .= "<li class=\"divider\"></li>";
@ -84,20 +93,20 @@ class DatatableService
return ''; return '';
} }
if ( ! $lastIsDivider) { if ( $can_edit && ! $lastIsDivider) {
$str .= "<li class=\"divider\"></li>"; $str .= "<li class=\"divider\"></li>";
} }
if ($entityType != ENTITY_USER || $model->public_id) { if (($entityType != ENTITY_USER || $model->public_id) && $can_edit) {
$str .= "<li><a href=\"javascript:archiveEntity({$model->public_id})\">" $str .= "<li><a href=\"javascript:archiveEntity({$model->public_id})\">"
. trans("texts.archive_{$entityType}") . "</a></li>"; . trans("texts.archive_{$entityType}") . "</a></li>";
} }
} else { } else if($can_edit) {
$str .= "<li><a href=\"javascript:restoreEntity({$model->public_id})\">" $str .= "<li><a href=\"javascript:restoreEntity({$model->public_id})\">"
. trans("texts.restore_{$entityType}") . "</a></li>"; . trans("texts.restore_{$entityType}") . "</a></li>";
} }
if (property_exists($model, 'is_deleted') && !$model->is_deleted) { if (property_exists($model, 'is_deleted') && !$model->is_deleted && $can_edit) {
$str .= "<li><a href=\"javascript:deleteEntity({$model->public_id})\">" $str .= "<li><a href=\"javascript:deleteEntity({$model->public_id})\">"
. trans("texts.delete_{$entityType}") . "</a></li>"; . trans("texts.delete_{$entityType}") . "</a></li>";
} }

View File

@ -1,10 +1,13 @@
<?php namespace App\Services; <?php namespace App\Services;
use Auth;
use DB; use DB;
use Utils; use Utils;
use URL; use URL;
use App\Services\BaseService; use App\Services\BaseService;
use App\Ninja\Repositories\ExpenseRepository; use App\Ninja\Repositories\ExpenseRepository;
use App\Models\Expense;
use App\Models\Invoice;
use App\Models\Client; use App\Models\Client;
use App\Models\Vendor; use App\Models\Vendor;
@ -42,6 +45,10 @@ class ExpenseService extends BaseService
{ {
$query = $this->expenseRepo->find($search); $query = $this->expenseRepo->find($search);
if(!Utils::hasPermission('view_all')){
$query->where('expenses.user_id', '=', Auth::user()->id);
}
return $this->createDatatable(ENTITY_EXPENSE, $query); return $this->createDatatable(ENTITY_EXPENSE, $query);
} }
@ -151,6 +158,9 @@ class ExpenseService extends BaseService
trans('texts.edit_expense'), trans('texts.edit_expense'),
function ($model) { function ($model) {
return URL::to("expenses/{$model->public_id}/edit") ; return URL::to("expenses/{$model->public_id}/edit") ;
},
function ($model) {
return Expense::canEditItem($model);
} }
], ],
[ [
@ -159,7 +169,7 @@ class ExpenseService extends BaseService
return URL::to("/invoices/{$model->invoice_public_id}/edit"); return URL::to("/invoices/{$model->invoice_public_id}/edit");
}, },
function ($model) { function ($model) {
return $model->invoice_public_id; return $model->invoice_public_id && Invoice::canEditItemById($model->invoice_public_id);
} }
], ],
[ [
@ -168,7 +178,7 @@ class ExpenseService extends BaseService
return "javascript:invoiceEntity({$model->public_id})"; return "javascript:invoiceEntity({$model->public_id})";
}, },
function ($model) { 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();
} }
], ],
]; ];

View File

@ -8,6 +8,8 @@ use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Repositories\ClientRepository; use App\Ninja\Repositories\ClientRepository;
use App\Events\QuoteInvitationWasApproved; use App\Events\QuoteInvitationWasApproved;
use App\Models\Invitation; use App\Models\Invitation;
use App\Models\Invoice;
use App\Models\Payment;
class InvoiceService extends BaseService class InvoiceService extends BaseService
{ {
@ -109,6 +111,10 @@ class InvoiceService extends BaseService
$query = $this->invoiceRepo->getInvoices($accountId, $clientPublicId, $entityType, $search) $query = $this->invoiceRepo->getInvoices($accountId, $clientPublicId, $entityType, $search)
->where('invoices.is_quote', '=', $entityType == ENTITY_QUOTE ? true : false); ->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); return $this->createDatatable($entityType, $query, !$clientPublicId);
} }
@ -174,12 +180,18 @@ class InvoiceService extends BaseService
trans("texts.edit_{$entityType}"), trans("texts.edit_{$entityType}"),
function ($model) use ($entityType) { function ($model) use ($entityType) {
return URL::to("{$entityType}s/{$model->public_id}/edit"); return URL::to("{$entityType}s/{$model->public_id}/edit");
},
function ($model) {
return Invoice::canEditItem($model);
} }
], ],
[ [
trans("texts.clone_{$entityType}"), trans("texts.clone_{$entityType}"),
function ($model) use ($entityType) { function ($model) use ($entityType) {
return URL::to("{$entityType}s/{$model->public_id}/clone"); return URL::to("{$entityType}s/{$model->public_id}/clone");
},
function ($model) {
return Invoice::canCreate();
} }
], ],
[ [
@ -188,14 +200,19 @@ class InvoiceService extends BaseService
return URL::to("{$entityType}s/{$entityType}_history/{$model->public_id}"); 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"), trans("texts.mark_sent"),
function ($model) { function ($model) {
return "javascript:markEntity({$model->public_id})"; return "javascript:markEntity({$model->public_id})";
}, },
function ($model) { function ($model) {
return $model->invoice_status_id < INVOICE_STATUS_SENT; return $model->invoice_status_id < INVOICE_STATUS_SENT && Invoice::canEditItem($model);
} }
], ],
[ [
@ -204,7 +221,7 @@ class InvoiceService extends BaseService
return URL::to("payments/create/{$model->client_public_id}/{$model->public_id}"); return URL::to("payments/create/{$model->client_public_id}/{$model->public_id}");
}, },
function ($model) use ($entityType) { function ($model) use ($entityType) {
return $entityType == ENTITY_INVOICE && $model->balance > 0; return $entityType == ENTITY_INVOICE && $model->balance > 0 && Payment::canCreate();
} }
], ],
[ [
@ -213,7 +230,7 @@ class InvoiceService extends BaseService
return URL::to("quotes/{$model->quote_id}/edit"); return URL::to("quotes/{$model->quote_id}/edit");
}, },
function ($model) use ($entityType) { function ($model) use ($entityType) {
return $entityType == ENTITY_INVOICE && $model->quote_id; return $entityType == ENTITY_INVOICE && $model->quote_id && Invoice::canEditItem($model);
} }
], ],
[ [
@ -222,7 +239,7 @@ class InvoiceService extends BaseService
return URL::to("invoices/{$model->quote_invoice_id}/edit"); return URL::to("invoices/{$model->quote_invoice_id}/edit");
}, },
function ($model) use ($entityType) { 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 +248,7 @@ class InvoiceService extends BaseService
return "javascript:convertEntity({$model->public_id})"; return "javascript:convertEntity({$model->public_id})";
}, },
function ($model) use ($entityType) { function ($model) use ($entityType) {
return $entityType == ENTITY_QUOTE && ! $model->quote_invoice_id; return $entityType == ENTITY_QUOTE && ! $model->quote_invoice_id && Invoice::canEditItem($model);
} }
] ]
]; ];

View File

@ -1,6 +1,7 @@
<?php namespace App\Services; <?php namespace App\Services;
use Utils; use Utils;
use Auth;
use URL; use URL;
use DateTime; use DateTime;
use Event; use Event;
@ -286,6 +287,10 @@ class PaymentService extends BaseService
{ {
$query = $this->paymentRepo->find($clientPublicId, $search); $query = $this->paymentRepo->find($clientPublicId, $search);
if(!Utils::hasPermission('view_all')){
$query->where('payments.user_id', '=', Auth::user()->id);
}
return $this->createDatatable(ENTITY_PAYMENT, $query, !$clientPublicId); return $this->createDatatable(ENTITY_PAYMENT, $query, !$clientPublicId);
} }
@ -339,6 +344,9 @@ class PaymentService extends BaseService
trans('texts.edit_payment'), trans('texts.edit_payment'),
function ($model) { function ($model) {
return URL::to("payments/{$model->public_id}/edit"); return URL::to("payments/{$model->public_id}/edit");
},
function ($model) {
return Payment::canEditItem($model);
} }
] ]
]; ];

View File

@ -1,7 +1,9 @@
<?php namespace App\Services; <?php namespace App\Services;
use URL; use URL;
use Auth;
use Utils; use Utils;
use App\Models\Invoice;
use App\Ninja\Repositories\InvoiceRepository; use App\Ninja\Repositories\InvoiceRepository;
class RecurringInvoiceService extends BaseService class RecurringInvoiceService extends BaseService
@ -19,6 +21,10 @@ class RecurringInvoiceService extends BaseService
{ {
$query = $this->invoiceRepo->getRecurringInvoices($accountId, $clientPublicId, $search); $query = $this->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); return $this->createDatatable(ENTITY_RECURRING_INVOICE, $query, !$clientPublicId);
} }
@ -66,6 +72,9 @@ class RecurringInvoiceService extends BaseService
trans('texts.edit_invoice'), trans('texts.edit_invoice'),
function ($model) { function ($model) {
return URL::to("invoices/{$model->public_id}/edit"); return URL::to("invoices/{$model->public_id}/edit");
},
function ($model) {
return Invoice::canEditItem($model);
} }
] ]
]; ];

View File

@ -1,8 +1,10 @@
<?php namespace App\Services; <?php namespace App\Services;
use Auth;
use URL; use URL;
use Utils; use Utils;
use App\Models\Task; use App\Models\Task;
use App\Models\Invoice;
use App\Ninja\Repositories\TaskRepository; use App\Ninja\Repositories\TaskRepository;
use App\Services\BaseService; use App\Services\BaseService;
@ -33,6 +35,10 @@ class TaskService extends BaseService
{ {
$query = $this->taskRepo->find($clientPublicId, $search); $query = $this->taskRepo->find($clientPublicId, $search);
if(!Utils::hasPermission('view_all')){
$query->where('tasks.user_id', '=', Auth::user()->id);
}
return $this->createDatatable(ENTITY_TASK, $query, !$clientPublicId); return $this->createDatatable(ENTITY_TASK, $query, !$clientPublicId);
} }
@ -82,7 +88,7 @@ class TaskService extends BaseService
return URL::to('tasks/'.$model->public_id.'/edit'); return URL::to('tasks/'.$model->public_id.'/edit');
}, },
function ($model) { 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 +97,7 @@ class TaskService extends BaseService
return URL::to("/invoices/{$model->invoice_public_id}/edit"); return URL::to("/invoices/{$model->invoice_public_id}/edit");
}, },
function ($model) { function ($model) {
return $model->invoice_number; return $model->invoice_number && Invoice::canEditItemById($model->invoice_number);
} }
], ],
[ [
@ -100,7 +106,7 @@ class TaskService extends BaseService
return "javascript:stopTask({$model->public_id})"; return "javascript:stopTask({$model->public_id})";
}, },
function ($model) { function ($model) {
return $model->is_running; return $model->is_running && Task::canEditItem($model);
} }
], ],
[ [
@ -109,7 +115,7 @@ class TaskService extends BaseService
return "javascript:invoiceEntity({$model->public_id})"; return "javascript:invoiceEntity({$model->public_id})";
}, },
function ($model) { 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();
} }
] ]
]; ];

View File

@ -53,11 +53,15 @@ class UserService extends BaseService
'confirmed', 'confirmed',
function ($model) { function ($model) {
if (!$model->public_id) { if (!$model->public_id) {
return self::getStatusLabel(USER_STATE_ADMIN); return self::getStatusLabel(USER_STATE_OWNER);
} elseif ($model->deleted_at) { } elseif ($model->deleted_at) {
return self::getStatusLabel(USER_STATE_DISABLED); return self::getStatusLabel(USER_STATE_DISABLED);
} elseif ($model->confirmed) { } elseif ($model->confirmed) {
if($model->is_admin){
return self::getStatusLabel(USER_STATE_ADMIN);
} else {
return self::getStatusLabel(USER_STATE_ACTIVE); return self::getStatusLabel(USER_STATE_ACTIVE);
}
} else { } else {
return self::getStatusLabel(USER_STATE_PENDING); return self::getStatusLabel(USER_STATE_PENDING);
} }
@ -96,17 +100,20 @@ class UserService extends BaseService
$class = 'default'; $class = 'default';
switch ($state) { switch ($state) {
case USER_STATE_PENDING: case USER_STATE_PENDING:
$class = 'info'; $class = 'default';
break; break;
case USER_STATE_ACTIVE: case USER_STATE_ACTIVE:
$class = 'primary'; $class = 'info';
break; break;
case USER_STATE_DISABLED: case USER_STATE_DISABLED:
$class = 'warning'; $class = 'warning';
break; break;
case USER_STATE_ADMIN: case USER_STATE_OWNER:
$class = 'success'; $class = 'success';
break; break;
case USER_STATE_ADMIN:
$class = 'primary';
break;
} }
return "<h4><div class=\"label label-{$class}\">$label</div></h4>"; return "<h4><div class=\"label label-{$class}\">$label</div></h4>";
} }

View File

@ -3,6 +3,8 @@
use Utils; use Utils;
use URL; use URL;
use Auth; use Auth;
use App\Models\Vendor;
use App\Models\Expense;
use App\Services\BaseService; use App\Services\BaseService;
use App\Ninja\Repositories\VendorRepository; use App\Ninja\Repositories\VendorRepository;
use App\Ninja\Repositories\NinjaRepository; use App\Ninja\Repositories\NinjaRepository;
@ -83,13 +85,25 @@ class VendorService extends BaseService
trans('texts.edit_vendor'), trans('texts.edit_vendor'),
function ($model) { function ($model) {
return URL::to("vendors/{$model->public_id}/edit"); 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'), trans('texts.enter_expense'),
function ($model) { function ($model) {
return URL::to("expenses/create/{$model->public_id}"); return URL::to("expenses/create/{$model->public_id}");
},
function ($model) {
return Expense::canCreate();
} }
] ]
]; ];

View File

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

View File

@ -1063,6 +1063,14 @@ $LANG = array(
'invalid_expiry' => 'The expiration date is not valid.', 'invalid_expiry' => 'The expiration date is not valid.',
'invalid_cvv' => 'The CVV is not valid.', 'invalid_cvv' => 'The CVV is not valid.',
// 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; return $LANG;

View File

@ -21,7 +21,9 @@
{{ Former::populateField('referral_code', true) }} {{ Former::populateField('referral_code', true) }}
@endif @endif
@if (Utils::isAdmin())
@include('accounts.nav', ['selected' => ACCOUNT_USER_DETAILS]) @include('accounts.nav', ['selected' => ACCOUNT_USER_DETAILS])
@endif
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">

View File

@ -43,8 +43,11 @@
@endif @endif
@if ($client->trashed()) @if ($client->trashed())
@if ($client->canEdit())
{!! Button::primary(trans('texts.restore_client'))->withAttributes(['onclick' => 'onRestoreClick()']) !!} {!! Button::primary(trans('texts.restore_client'))->withAttributes(['onclick' => 'onRestoreClick()']) !!}
@endif
@else @else
@if ($client->canEdit())
{!! DropdownButton::normal(trans('texts.edit_client')) {!! DropdownButton::normal(trans('texts.edit_client'))
->withAttributes(['class'=>'normalDropDown']) ->withAttributes(['class'=>'normalDropDown'])
->withContents([ ->withContents([
@ -52,11 +55,13 @@
['label' => trans('texts.delete_client'), 'url' => "javascript:onDeleteClick()"], ['label' => trans('texts.delete_client'), 'url' => "javascript:onDeleteClick()"],
] ]
)->split() !!} )->split() !!}
@endif
@if (\App\Models\Invoice::canCreate())
{!! DropdownButton::primary(trans('texts.new_invoice')) {!! DropdownButton::primary(trans('texts.new_invoice'))
->withAttributes(['class'=>'primaryDropDown']) ->withAttributes(['class'=>'primaryDropDown'])
->withContents($actionLinks)->split() !!} ->withContents($actionLinks)->split() !!}
@endif @endif
@endif
{!! Former::close() !!} {!! Former::close() !!}
</div> </div>

View File

@ -473,11 +473,13 @@
]) ])
@endif @endif
<li class="divider"></li> <li class="divider"></li>
@if (Utils::isAdmin())
@if (count(session(SESSION_USER_ACCOUNTS)) > 1) @if (count(session(SESSION_USER_ACCOUNTS)) > 1)
<li>{!! link_to('/manage_companies', trans('texts.manage_companies')) !!}</li> <li>{!! link_to('/manage_companies', trans('texts.manage_companies')) !!}</li>
@elseif (!session(SESSION_USER_ACCOUNTS) || count(session(SESSION_USER_ACCOUNTS)) < 5) @elseif (!session(SESSION_USER_ACCOUNTS) || count(session(SESSION_USER_ACCOUNTS)) < 5)
<li>{!! link_to('/login?new_company=true', trans('texts.add_company')) !!}</li> <li>{!! link_to('/login?new_company=true', trans('texts.add_company')) !!}</li>
@endif @endif
@endif
<li>{!! link_to('#', trans('texts.logout'), array('onclick'=>'logout()')) !!}</li> <li>{!! link_to('#', trans('texts.logout'), array('onclick'=>'logout()')) !!}</li>
</ul> </ul>
</div> </div>
@ -490,10 +492,14 @@
<span class="glyphicon glyphicon-cog" title="{{ trans('texts.settings') }}"/> <span class="glyphicon glyphicon-cog" title="{{ trans('texts.settings') }}"/>
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
@if (Utils::isAdmin())
@foreach (\App\Models\Account::$basicSettings as $setting) @foreach (\App\Models\Account::$basicSettings as $setting)
<li>{!! link_to('settings/' . $setting, uctrans("texts.{$setting}")) !!}</li> <li>{!! link_to('settings/' . $setting, uctrans("texts.{$setting}")) !!}</li>
@endforeach @endforeach
<li><a href="{{ url('settings/' . ACCOUNT_INVOICE_SETTINGS) }}">{!! uctrans('texts.advanced_settings') . Utils::getProLabel(ACCOUNT_ADVANCED_SETTINGS) !!}</a></li> <li><a href="{{ url('settings/' . ACCOUNT_INVOICE_SETTINGS) }}">{!! uctrans('texts.advanced_settings') . Utils::getProLabel(ACCOUNT_ADVANCED_SETTINGS) !!}</a></li>
@else
<li>{!! link_to('settings/user_details', uctrans("texts.user_details")) !!}</li>
@endif
</ul> </ul>
</li> </li>
</ul> </ul>

View File

@ -38,7 +38,9 @@
{!! Button::normal(trans('texts.credits'))->asLinkTo(URL::to('/credits'))->appendIcon(Icon::create('list')) !!} {!! Button::normal(trans('texts.credits'))->asLinkTo(URL::to('/credits'))->appendIcon(Icon::create('list')) !!}
@endif @endif
@if (Auth::user()->hasPermission('create_all'))
{!! Button::primary(trans("texts.new_$entityType"))->asLinkTo(URL::to("/{$entityType}s/create"))->appendIcon(Icon::create('plus-sign')) !!} {!! Button::primary(trans("texts.new_$entityType"))->asLinkTo(URL::to("/{$entityType}s/create"))->appendIcon(Icon::create('plus-sign')) !!}
@endif
</div> </div>

View File

@ -1,9 +1,13 @@
<li style="margin-top: 4px; margin-bottom: 4px; min-width: 220px; cursor: pointer"> <li style="margin-top: 4px; margin-bottom: 4px; min-width: 220px; cursor: pointer">
@if (Utils::isAdmin())
@if (isset($user_id) && $user_id != Auth::user()->id) @if (isset($user_id) && $user_id != Auth::user()->id)
<a href="{{ URL::to("/switch_account/{$user_id}") }}"> <a href="{{ URL::to("/switch_account/{$user_id}") }}">
@else @else
<a href="{{ URL::to("/settings/company_details") }}"> <a href="{{ URL::to("/settings/company_details") }}">
@endif @endif
@else
<a href="{{ URL::to("/settings/user_details") }}">
@endif
@if (file_exists($logo_path)) @if (file_exists($logo_path))
<div class="pull-left" style="height: 40px; margin-right: 16px;"> <div class="pull-left" style="height: 40px; margin-right: 16px;">
@ -23,7 +27,6 @@
@if (isset($selected) && $selected) @if (isset($selected) && $selected)
</b> </b>
@endif @endif
</a> </a>
</li> </li>

View File

@ -23,6 +23,25 @@
{!! Former::text('first_name') !!} {!! Former::text('first_name') !!}
{!! Former::text('last_name') !!} {!! Former::text('last_name') !!}
{!! Former::text('email') !!} {!! Former::text('email') !!}
{!! Former::checkbox('is_admin')
->label('&nbsp;')
->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')) !!}
{!! Former::checkbox('permissions[view_all]')
->value('view_all')
->label('&nbsp;')
->id('permissions_view_all')
->text(trans('texts.user_view_all')) !!}
{!! Former::checkbox('permissions[edit_all]')
->value('edit_all')
->label('&nbsp;')
->id('permissions_edit_all')
->text(trans('texts.user_edit_all')) !!}
</div> </div>
</div> </div>
@ -38,4 +57,14 @@
@section('onReady') @section('onReady')
$('#first_name').focus(); $('#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 @stop