2019-03-28 22:34:58 +01:00
< ? php
2019-05-11 05:32:07 +02:00
/**
2020-09-06 11:38:10 +02:00
* Invoice Ninja ( https :// invoiceninja . com ) .
2019-05-11 05:32:07 +02:00
*
* @ link https :// github . com / invoiceninja / invoiceninja source repository
*
2024-04-12 06:15:41 +02:00
* @ copyright Copyright ( c ) 2024. Invoice Ninja LLC ( https :// invoiceninja . com )
2019-05-11 05:32:07 +02:00
*
2021-06-16 08:58:16 +02:00
* @ license https :// www . elastic . co / licensing / elastic - license
2019-05-11 05:32:07 +02:00
*/
2019-03-28 22:34:58 +01:00
namespace App\Http\Controllers ;
2024-05-12 12:23:17 +02:00
use App\Models\User ;
use App\Utils\Ninja ;
2023-04-26 15:17:49 +02:00
use App\Models\Client ;
use App\Models\Design ;
2024-05-12 12:23:17 +02:00
use App\Utils\Statics ;
use App\Models\Account ;
2023-04-26 15:17:49 +02:00
use App\Models\TaxRate ;
use App\Models\Webhook ;
2024-05-12 12:23:17 +02:00
use App\Models\Scheduler ;
use App\Models\TaskStatus ;
use App\Models\PaymentTerm ;
2023-04-26 15:17:49 +02:00
use Illuminate\Support\Str ;
use League\Fractal\Manager ;
2024-05-12 12:23:17 +02:00
use App\Models\GroupSetting ;
use Illuminate\Http\Response ;
use App\Models\CompanyGateway ;
use App\Utils\Traits\AppSetup ;
use App\Models\BankIntegration ;
use App\Models\BankTransaction ;
use App\Models\ExpenseCategory ;
2023-04-26 15:17:49 +02:00
use League\Fractal\Resource\Item ;
2024-05-12 12:23:17 +02:00
use App\Models\BankTransactionRule ;
use Illuminate\Support\Facades\Auth ;
use App\Transformers\ArraySerializer ;
2024-07-11 09:15:24 +02:00
use Illuminate\Support\Facades\Schema as DbSchema ;
2024-05-12 12:23:17 +02:00
use App\Transformers\EntityTransformer ;
use League\Fractal\Resource\Collection ;
use Illuminate\Database\Eloquent\Builder ;
2024-06-07 03:21:50 +02:00
use InvoiceNinja\EInvoice\Decoder\Schema ;
2023-04-26 15:17:49 +02:00
use League\Fractal\Serializer\JsonApiSerializer ;
2024-05-12 12:23:17 +02:00
use League\Fractal\Pagination\IlluminatePaginatorAdapter ;
use Illuminate\Contracts\Container\BindingResolutionException ;
2019-03-28 22:34:58 +01:00
2019-06-24 02:13:53 +02:00
/**
2020-09-06 11:38:10 +02:00
* Class BaseController .
2023-04-26 23:46:59 +02:00
* @ method static Illuminate\Database\Eloquent\Builder exclude ( $columns )
2019-06-24 02:13:53 +02:00
*/
2019-03-28 22:34:58 +01:00
class BaseController extends Controller
{
2020-03-21 06:37:30 +01:00
use AppSetup ;
2022-06-21 11:57:17 +02:00
2019-06-24 02:13:53 +02:00
/**
* Passed from the parent when we need to force
2019-12-30 22:59:12 +01:00
* includes internally rather than externally via
2019-09-11 02:37:53 +02:00
* the $_REQUEST 'include' variable .
2019-12-30 22:59:12 +01:00
*
2019-06-24 02:13:53 +02:00
* @ var array
*/
2023-01-25 02:58:24 +01:00
public $forced_includes = [];
2019-06-24 02:13:53 +02:00
2019-06-25 07:08:07 +02:00
/**
* Passed from the parent when we need to force
2020-09-06 11:38:10 +02:00
* the key of the response object .
2019-06-25 07:08:07 +02:00
* @ var string
*/
2023-01-25 02:58:24 +01:00
public $forced_index = 'data' ;
2019-06-25 07:08:07 +02:00
2023-02-20 10:56:01 +01:00
/**
* The calling controller Model Type
*/
2023-02-20 08:46:26 +01:00
protected $entity_type ;
2023-02-20 10:56:01 +01:00
/**
* The calling controller Transformer type
*
*/
2023-02-20 08:46:26 +01:00
protected $entity_transformer ;
2023-02-20 10:56:01 +01:00
/**
* The serializer in use with Fractal
*
*/
2023-02-20 08:46:26 +01:00
protected $serializer ;
2023-02-20 09:52:50 +01:00
/* Grouped permissions when we want to hide columns for particular permission groups*/
2024-01-14 05:05:00 +01:00
2023-02-20 09:52:50 +01:00
private array $client_exclusion_fields = [ 'balance' , 'paid_to_date' , 'credit_balance' , 'client_hash' ];
private array $client_excludable_permissions = [ 'view_client' ];
private array $client_excludable_overrides = [ 'edit_client' , 'edit_all' , 'view_invoice' , 'view_all' , 'edit_invoice' ];
2024-01-14 05:05:00 +01:00
2023-02-20 09:52:50 +01:00
/* Grouped permissions when we want to hide columns for particular permission groups*/
2019-06-24 02:13:53 +02:00
/**
2020-09-06 11:38:10 +02:00
* Fractal manager .
2023-02-20 10:56:01 +01:00
* @ var Manager $manager
2019-06-24 02:13:53 +02:00
*/
2023-01-25 02:58:24 +01:00
protected Manager $manager ;
2019-06-24 02:13:53 +02:00
2023-02-20 10:56:01 +01:00
/**
* An array of includes to be loaded by default .
*/
2020-07-26 10:30:55 +02:00
private $first_load = [
'account' ,
2020-10-26 01:58:08 +01:00
'user.company_user' ,
'token.company_user' ,
2020-07-26 10:30:55 +02:00
'company.activities' ,
2020-10-20 02:53:54 +02:00
'company.designs.company' ,
2020-10-25 21:56:02 +01:00
'company.task_statuses' ,
'company.expense_categories' ,
2020-10-20 02:53:54 +02:00
'company.documents' ,
2020-12-26 09:03:24 +01:00
'company.users.company_user' ,
2020-10-26 01:58:08 +01:00
'company.clients.contacts.company' ,
2020-08-12 01:04:39 +02:00
'company.clients.gateway_tokens' ,
2020-09-19 04:05:54 +02:00
'company.clients.documents' ,
2020-10-20 02:53:54 +02:00
'company.company_gateways.gateway' ,
'company.credits.invitations.contact' ,
'company.credits.invitations.company' ,
'company.credits.documents' ,
'company.expenses.documents' ,
2021-01-19 21:22:14 +01:00
'company.groups.documents' ,
2020-07-26 10:30:55 +02:00
'company.invoices.invitations.contact' ,
'company.invoices.invitations.company' ,
2022-06-24 07:54:34 +02:00
'company.purchase_orders.invitations' ,
2020-07-26 10:30:55 +02:00
'company.invoices.documents' ,
2020-10-20 02:53:54 +02:00
'company.products' ,
'company.products.documents' ,
'company.payments.paymentables' ,
'company.payments.documents' ,
2022-06-14 14:18:20 +02:00
'company.purchase_orders.documents' ,
2020-10-20 02:53:54 +02:00
'company.payment_terms.company' ,
'company.projects.documents' ,
2021-08-29 12:34:53 +02:00
'company.recurring_expenses' ,
2020-09-19 04:05:54 +02:00
'company.recurring_invoices' ,
'company.recurring_invoices.invitations.contact' ,
'company.recurring_invoices.invitations.company' ,
'company.recurring_invoices.documents' ,
2020-07-26 10:30:55 +02:00
'company.quotes.invitations.contact' ,
'company.quotes.invitations.company' ,
'company.quotes.documents' ,
2020-10-18 09:46:10 +02:00
'company.tasks.documents' ,
2024-02-18 06:19:09 +01:00
// 'company.tasks.project',
2021-03-29 12:58:03 +02:00
'company.subscriptions' ,
2020-10-20 02:53:54 +02:00
'company.tax_rates' ,
2020-09-06 11:38:10 +02:00
'company.tokens_hashed' ,
2020-10-26 01:58:08 +01:00
'company.vendors.contacts.company' ,
'company.vendors.documents' ,
2020-10-20 02:53:54 +02:00
'company.webhooks' ,
2021-03-30 00:32:33 +02:00
'company.system_logs' ,
2022-09-07 07:09:53 +02:00
'company.bank_integrations' ,
2022-09-14 06:33:05 +02:00
'company.bank_transactions' ,
2022-11-21 22:42:53 +01:00
'company.bank_transaction_rules' ,
2023-01-16 22:37:15 +01:00
'company.task_schedulers' ,
2020-07-26 10:30:55 +02:00
];
2023-02-20 10:56:01 +01:00
/**
* An array of includes to be loaded by default
* when the company is large .
*/
2020-07-26 10:30:55 +02:00
private $mini_load = [
2022-06-21 11:57:17 +02:00
'account' ,
'user.company_user' ,
'token' ,
'company.activities' ,
'company.tax_rates' ,
'company.documents' ,
'company.company_gateways.gateway' ,
'company.users.company_user' ,
'company.task_statuses' ,
'company.payment_terms' ,
'company.groups' ,
'company.designs.company' ,
'company.expense_categories' ,
'company.subscriptions' ,
2022-09-07 07:09:53 +02:00
'company.bank_integrations' ,
2022-11-21 22:42:53 +01:00
'company.bank_transaction_rules' ,
2023-01-16 22:37:15 +01:00
'company.task_schedulers' ,
2022-06-21 11:57:17 +02:00
];
2024-01-14 05:05:00 +01:00
2023-02-20 10:56:01 +01:00
/**
* __construct
*
* @ return void
*/
2019-12-30 22:59:12 +01:00
public function __construct ()
2019-03-28 22:34:58 +01:00
{
$this -> manager = new Manager ();
2019-06-24 02:13:53 +02:00
}
2024-01-14 05:05:00 +01:00
2023-02-20 10:56:01 +01:00
/**
* Initializes the Manager and transforms
* the required includes
*
* @ return void
*/
2019-06-24 02:13:53 +02:00
private function buildManager ()
{
2019-06-24 13:05:47 +02:00
$include = '' ;
2019-06-24 02:13:53 +02:00
2020-03-21 06:37:30 +01:00
if ( request () -> has ( 'first_load' ) && request () -> input ( 'first_load' ) == 'true' ) {
2020-09-06 11:38:10 +02:00
$include = implode ( ',' , array_merge ( $this -> forced_includes , $this -> getRequestIncludes ([])));
2020-03-21 06:37:30 +01:00
} elseif ( request () -> input ( 'include' ) !== null ) {
2020-09-06 11:38:10 +02:00
$include = array_merge ( $this -> forced_includes , explode ( ',' , request () -> input ( 'include' )));
$include = implode ( ',' , $include );
2019-12-30 22:59:12 +01:00
} elseif ( count ( $this -> forced_includes ) >= 1 ) {
2020-09-06 11:38:10 +02:00
$include = implode ( ',' , $this -> forced_includes );
2019-06-24 13:05:47 +02:00
}
2019-06-24 02:13:53 +02:00
2023-01-25 02:58:24 +01:00
// $include = $this->filterIncludes($include);
2019-06-24 02:13:53 +02:00
$this -> manager -> parseIncludes ( $include );
2020-09-06 11:38:10 +02:00
2019-03-28 22:34:58 +01:00
$this -> serializer = request () -> input ( 'serializer' ) ? : EntityTransformer :: API_SERIALIZER_ARRAY ;
2019-12-30 22:59:12 +01:00
if ( $this -> serializer === EntityTransformer :: API_SERIALIZER_JSON ) {
2019-03-28 22:34:58 +01:00
$this -> manager -> setSerializer ( new JsonApiSerializer ());
2019-12-30 22:59:12 +01:00
} else {
2019-03-28 22:34:58 +01:00
$this -> manager -> setSerializer ( new ArraySerializer ());
2019-06-24 02:13:53 +02:00
}
2019-03-28 22:34:58 +01:00
}
2019-03-30 10:30:41 +01:00
/**
2023-02-20 10:56:01 +01:00
* Catch all fallback route .
2019-03-30 10:30:41 +01:00
*/
public function notFound ()
{
2021-01-24 23:24:13 +01:00
return response () -> json ([ 'message' => ctrans ( 'texts.api_404' )], 404 )
2020-06-21 23:30:25 +02:00
-> header ( 'X-API-VERSION' , config ( 'ninja.minimum_client_version' ))
2019-12-29 23:06:42 +01:00
-> header ( 'X-APP-VERSION' , config ( 'ninja.app_version' ));
2019-03-30 10:30:41 +01:00
}
2023-01-25 02:58:24 +01:00
/**
* Filters the includes to ensure the
2023-02-16 02:36:09 +01:00
* end user has the correct permissions to
2023-01-25 02:58:24 +01:00
* view the includes
2023-02-16 02:36:09 +01:00
*
2023-02-20 08:46:26 +01:00
* @ param string $includes The includes for the object
2023-01-25 02:58:24 +01:00
* @ return string The filtered array of includes
*/
2023-04-26 15:03:32 +02:00
// private function filterIncludes(string $includes): string
// {
// $permissions_array = [
// 'payments' => 'view_payment',
// 'client' => 'view_client',
// 'clients' => 'view_client',
// 'vendor' => 'view_vendor',
// 'vendors' => 'view_vendors',
// 'expense' => 'view_expense',
// 'expenses' => 'view_expense',
// ];
// $collection = collect(explode(",", $includes));
// $filtered_includes = $collection->filter(function ($include) use ($permissions_array) {
// return auth()->user()->hasPermission($permissions_array[$include]);
// });
// return $filtered_includes->implode(",");
// }
2023-01-25 02:58:24 +01:00
2020-04-04 12:32:42 +02:00
/**
2020-09-06 11:38:10 +02:00
* 404 for the client portal .
2024-06-16 00:30:25 +02:00
* @ return Response | \Illuminate\Http\JsonResponse 404 response
2020-04-04 12:32:42 +02:00
*/
2019-07-17 00:59:09 +02:00
public function notFoundClient ()
{
2022-06-15 07:20:00 +02:00
abort ( 404 , 'Page not found in the client portal.' );
}
public function notFoundVendor ()
{
abort ( 404 , 'Page not found in the vendor portal.' );
2019-07-17 00:59:09 +02:00
}
2020-04-04 12:32:42 +02:00
/**
2020-09-06 11:38:10 +02:00
* API Error response .
2023-02-20 10:56:01 +01:00
*
2024-04-24 01:21:00 +02:00
* @ param string | array $message The return error message
2023-02-20 10:56:01 +01:00
* @ param int $httpErrorCode 404 / 401 / 403 etc
2024-06-16 00:30:25 +02:00
* @ return Response | \Illuminate\Http\JsonResponse The JSON response
2020-10-28 11:10:49 +01:00
* @ throws BindingResolutionException
2020-04-04 12:32:42 +02:00
*/
protected function errorResponse ( $message , $httpErrorCode = 400 )
2019-03-28 22:34:58 +01:00
{
2020-04-04 12:32:42 +02:00
$error [ 'error' ] = $message ;
2020-02-10 10:53:02 +01:00
2019-03-28 22:34:58 +01:00
$error = json_encode ( $error , JSON_PRETTY_PRINT );
2020-02-10 10:53:02 +01:00
2019-03-28 22:34:58 +01:00
$headers = self :: getApiHeaders ();
return response () -> make ( $error , $httpErrorCode , $headers );
}
2023-01-25 00:43:18 +01:00
/**
* Refresh API response with latest cahnges
2023-02-20 10:56:01 +01:00
*
* @ param Builder $query
2024-06-16 00:30:25 +02:00
* @ return Response | \Illuminate\Http\JsonResponse
2023-01-25 00:43:18 +01:00
*/
2020-07-10 01:28:09 +02:00
protected function refreshResponse ( $query )
{
2023-04-26 15:17:49 +02:00
/** @var \App\Models\User $user */
2021-01-29 13:05:03 +01:00
$user = auth () -> user ();
2021-05-19 10:38:51 +02:00
$this -> manager -> parseIncludes ( $this -> first_load );
2020-07-24 11:39:43 +02:00
$this -> serializer = request () -> input ( 'serializer' ) ? : EntityTransformer :: API_SERIALIZER_ARRAY ;
if ( $this -> serializer === EntityTransformer :: API_SERIALIZER_JSON ) {
$this -> manager -> setSerializer ( new JsonApiSerializer ());
} else {
$this -> manager -> setSerializer ( new ArraySerializer ());
}
2020-07-10 01:28:09 +02:00
2020-07-26 07:12:40 +02:00
$transformer = new $this -> entity_transformer ( $this -> serializer );
2023-01-21 06:52:24 +01:00
2020-07-10 01:28:09 +02:00
$updated_at = request () -> has ( 'updated_at' ) ? request () -> input ( 'updated_at' ) : 0 ;
2020-08-02 08:31:55 +02:00
2023-01-30 02:59:47 +01:00
if ( $user -> getCompany () -> is_large && $updated_at == 0 ) {
2022-06-21 11:57:17 +02:00
$updated_at = time ();
2021-08-17 12:49:31 +02:00
}
2020-07-10 01:28:09 +02:00
$updated_at = date ( 'Y-m-d H:i:s' , $updated_at );
$query -> with (
2020-11-25 15:19:52 +01:00
[
2023-01-25 02:58:24 +01:00
'company' => function ( $query ) {
2022-06-21 11:57:17 +02:00
$query -> whereNotNull ( 'updated_at' ) -> with ( 'documents' , 'users' );
},
'company.clients' => function ( $query ) use ( $updated_at , $user ) {
$query -> where ( 'clients.updated_at' , '>=' , $updated_at ) -> with ( 'contacts.company' , 'gateway_tokens' , 'documents' );
if ( ! $user -> hasPermission ( 'view_client' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'clients.user_id' , $user -> id ) -> orWhere ( 'clients.assigned_user_id' , $user -> id );
2023-02-16 02:36:09 +01:00
});
2022-06-21 11:57:17 +02:00
}
2023-02-20 09:52:50 +01:00
if ( $user -> hasExcludedPermissions ( $this -> client_excludable_permissions , $this -> client_excludable_overrides )) {
$query -> exclude ( $this -> client_exclusion_fields );
}
2022-06-21 11:57:17 +02:00
},
'company.company_gateways' => function ( $query ) use ( $user ) {
$query -> whereNotNull ( 'updated_at' ) -> with ( 'gateway' );
if ( ! $user -> isAdmin ()) {
$query -> where ( 'company_gateways.user_id' , $user -> id );
}
},
2024-01-14 05:05:00 +01:00
'company.credits' => function ( $query ) use ( $updated_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'updated_at' , '>=' , $updated_at ) -> with ( 'invitations' , 'documents' );
if ( ! $user -> hasPermission ( 'view_credit' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'credits.user_id' , $user -> id ) -> orWhere ( 'credits.assigned_user_id' , $user -> id );
2023-02-16 02:36:09 +01:00
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.designs' => function ( $query ) use ( $updated_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'updated_at' , '>=' , $updated_at ) -> with ( 'company' );
if ( ! $user -> isAdmin ()) {
$query -> where ( 'designs.user_id' , $user -> id );
}
},
2024-01-14 05:05:00 +01:00
'company.documents' => function ( $query ) use ( $updated_at ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'updated_at' , '>=' , $updated_at );
},
2024-01-14 05:05:00 +01:00
'company.expenses' => function ( $query ) use ( $updated_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'updated_at' , '>=' , $updated_at ) -> with ( 'documents' );
if ( ! $user -> hasPermission ( 'view_expense' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'expenses.user_id' , $user -> id ) -> orWhere ( 'expenses.assigned_user_id' , $user -> id );
2023-02-16 02:36:09 +01:00
});
2022-06-21 11:57:17 +02:00
}
},
2023-01-25 02:58:24 +01:00
'company.groups' => function ( $query ) {
2022-06-21 11:57:17 +02:00
$query -> whereNotNull ( 'updated_at' ) -> with ( 'documents' );
},
2024-01-14 05:05:00 +01:00
'company.invoices' => function ( $query ) use ( $updated_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'updated_at' , '>=' , $updated_at ) -> with ( 'invitations' , 'documents' );
if ( ! $user -> hasPermission ( 'view_invoice' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'invoices.user_id' , $user -> id ) -> orWhere ( 'invoices.assigned_user_id' , $user -> id );
2023-02-16 02:36:09 +01:00
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.payments' => function ( $query ) use ( $updated_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'updated_at' , '>=' , $updated_at ) -> with ( 'paymentables' , 'documents' );
if ( ! $user -> hasPermission ( 'view_payment' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'payments.user_id' , $user -> id ) -> orWhere ( 'payments.assigned_user_id' , $user -> id );
2023-02-16 02:36:09 +01:00
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.payment_terms' => function ( $query ) use ( $user ) {
2022-06-21 11:57:17 +02:00
$query -> whereNotNull ( 'updated_at' );
if ( ! $user -> isAdmin ()) {
$query -> where ( 'payment_terms.user_id' , $user -> id );
}
},
'company.products' => function ( $query ) use ( $updated_at , $user ) {
$query -> where ( 'updated_at' , '>=' , $updated_at ) -> with ( 'documents' );
if ( ! $user -> hasPermission ( 'view_product' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 10:49:34 +02:00
$query -> where ( 'products.user_id' , $user -> id ) -> orWhere ( 'products.assigned_user_id' , $user -> id );
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.projects' => function ( $query ) use ( $updated_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'updated_at' , '>=' , $updated_at ) -> with ( 'documents' );
if ( ! $user -> hasPermission ( 'view_project' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'projects.user_id' , $user -> id ) -> orWhere ( 'projects.assigned_user_id' , $user -> id );
2023-02-16 02:36:09 +01:00
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.purchase_orders' => function ( $query ) use ( $updated_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'updated_at' , '>=' , $updated_at ) -> with ( 'documents' );
if ( ! $user -> hasPermission ( 'view_purchase_order' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'purchase_orders.user_id' , $user -> id ) -> orWhere ( 'purchase_orders.assigned_user_id' , $user -> id );
2023-02-16 02:36:09 +01:00
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.quotes' => function ( $query ) use ( $updated_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'updated_at' , '>=' , $updated_at ) -> with ( 'invitations' , 'documents' );
if ( ! $user -> hasPermission ( 'view_quote' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'quotes.user_id' , $user -> id ) -> orWhere ( 'quotes.assigned_user_id' , $user -> id );
2023-02-16 02:36:09 +01:00
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.recurring_invoices' => function ( $query ) use ( $updated_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'updated_at' , '>=' , $updated_at ) -> with ( 'invitations' , 'documents' , 'client.gateway_tokens' , 'client.group_settings' , 'client.company' );
if ( ! $user -> hasPermission ( 'view_recurring_invoice' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'recurring_invoices.user_id' , $user -> id ) -> orWhere ( 'recurring_invoices.assigned_user_id' , $user -> id );
2023-02-16 02:36:09 +01:00
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.recurring_expenses' => function ( $query ) use ( $updated_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'updated_at' , '>=' , $updated_at ) -> with ( 'documents' );
if ( ! $user -> hasPermission ( 'view_recurring_expense' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'recurring_expenses.user_id' , $user -> id ) -> orWhere ( 'recurring_expenses.assigned_user_id' , $user -> id );
2023-02-16 02:36:09 +01:00
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.tasks' => function ( $query ) use ( $updated_at , $user ) {
2024-06-14 09:09:44 +02:00
$query -> where ( 'updated_at' , '>=' , $updated_at ) -> with ( 'project' , 'documents' );
2022-06-21 11:57:17 +02:00
if ( ! $user -> hasPermission ( 'view_task' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'tasks.user_id' , $user -> id ) -> orWhere ( 'tasks.assigned_user_id' , $user -> id );
2023-02-16 02:36:09 +01:00
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.tax_rates' => function ( $query ) {
2022-06-21 11:57:17 +02:00
$query -> whereNotNull ( 'updated_at' );
},
2024-01-14 05:05:00 +01:00
'company.vendors' => function ( $query ) use ( $updated_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'updated_at' , '>=' , $updated_at ) -> with ( 'contacts' , 'documents' );
if ( ! $user -> hasPermission ( 'view_vendor' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'vendors.user_id' , $user -> id ) -> orWhere ( 'vendors.assigned_user_id' , $user -> id );
2023-02-16 02:36:09 +01:00
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.expense_categories' => function ( $query ) {
2022-06-21 11:57:17 +02:00
$query -> whereNotNull ( 'updated_at' );
},
2024-01-14 05:05:00 +01:00
'company.task_statuses' => function ( $query ) {
2022-06-21 11:57:17 +02:00
$query -> whereNotNull ( 'updated_at' );
},
2024-01-14 05:05:00 +01:00
'company.activities' => function ( $query ) use ( $user ) {
2022-06-21 11:57:17 +02:00
if ( ! $user -> isAdmin ()) {
$query -> where ( 'activities.user_id' , $user -> id );
}
},
2024-01-14 05:05:00 +01:00
'company.subscriptions' => function ( $query ) use ( $user ) {
2022-06-21 11:57:17 +02:00
$query -> whereNotNull ( 'updated_at' );
if ( ! $user -> isAdmin ()) {
$query -> where ( 'subscriptions.user_id' , $user -> id );
}
},
2024-01-14 05:05:00 +01:00
'company.bank_integrations' => function ( $query ) use ( $user ) {
2022-09-07 07:09:53 +02:00
$query -> whereNotNull ( 'updated_at' );
2023-01-25 01:28:23 +01:00
//scopes down permissions for users with no permissions
2023-01-25 00:43:18 +01:00
if ( ! $user -> hasPermission ( 'view_bank_transaction' )) {
2022-09-07 07:09:53 +02:00
$query -> where ( 'bank_integrations.user_id' , $user -> id );
}
2023-01-25 00:43:18 +01:00
2023-01-25 01:28:23 +01:00
//allows us to return integrations for users who can create bank transactions
2023-02-16 02:36:09 +01:00
if ( ! $user -> isSuperUser () && $user -> hasIntersectPermissions ([ 'create_bank_transaction' , 'edit_bank_transaction' , 'view_bank_transaction' ])) {
2023-01-25 00:43:18 +01:00
$query -> exclude ([ " balance " ]);
}
2022-09-07 07:09:53 +02:00
},
2024-01-14 05:05:00 +01:00
'company.bank_transactions' => function ( $query ) use ( $updated_at , $user ) {
2022-09-14 08:48:56 +02:00
$query -> where ( 'updated_at' , '>=' , $updated_at );
2022-09-14 06:33:05 +02:00
2023-01-22 22:25:43 +01:00
if ( ! $user -> hasPermission ( 'view_bank_transaction' )) {
2022-09-14 06:33:05 +02:00
$query -> where ( 'bank_transactions.user_id' , $user -> id );
}
},
2024-01-14 05:05:00 +01:00
'company.bank_transaction_rules' => function ( $query ) {
2023-08-06 07:24:13 +02:00
$query -> whereNotNull ( 'updated_at' );
2022-11-21 22:42:53 +01:00
},
2024-01-14 05:05:00 +01:00
'company.task_schedulers' => function ( $query ) {
2023-08-06 07:24:13 +02:00
$query -> whereNotNull ( 'updated_at' );
2023-01-16 22:31:07 +01:00
},
2022-06-21 11:57:17 +02:00
]
2020-07-10 01:28:09 +02:00
);
2020-11-13 10:09:20 +01:00
if ( $query instanceof Builder ) {
2022-10-27 02:28:09 +02:00
$limit = $this -> resolveQueryLimit ();
2020-07-24 11:39:43 +02:00
$paginator = $query -> paginate ( $limit );
2023-02-20 08:46:26 +01:00
2023-11-24 00:23:40 +01:00
/** @phpstan-ignore-next-line */
$query = $paginator -> getCollection (); // @phpstan-ignore-line
2024-01-14 05:05:00 +01:00
2020-07-24 11:39:43 +02:00
$resource = new Collection ( $query , $transformer , $this -> entity_type );
2023-02-20 08:46:26 +01:00
2020-07-24 11:39:43 +02:00
$resource -> setPaginator ( new IlluminatePaginatorAdapter ( $paginator ));
}
2024-01-14 05:05:00 +01:00
2023-04-26 15:03:32 +02:00
// else {
// $resource = new Collection($query, $transformer, $this->entity_type);
// }
2020-07-24 11:39:43 +02:00
return $this -> response ( $this -> manager -> createData ( $resource ) -> toArray ());
2020-07-10 01:28:09 +02:00
}
2024-01-14 05:05:00 +01:00
2023-02-20 08:46:26 +01:00
/**
* Returns the per page limit for the query .
*
* @ return int
*/
private function resolveQueryLimit () : int
2022-10-27 02:28:09 +02:00
{
2023-02-16 02:36:09 +01:00
if ( request () -> has ( 'per_page' )) {
2023-02-23 08:36:56 +01:00
return min ( abs (( int ) request () -> input ( 'per_page' , 20 )), 5000 );
2023-02-16 02:36:09 +01:00
}
2022-10-27 02:28:09 +02:00
return 20 ;
}
2024-01-14 05:05:00 +01:00
2023-02-20 10:56:01 +01:00
/**
* Mini Load Query
*
2023-04-26 15:03:32 +02:00
* @ param Builder $query
2023-04-26 15:17:49 +02:00
*
2023-02-20 10:56:01 +01:00
*/
2021-05-14 09:38:16 +02:00
protected function miniLoadResponse ( $query )
{
2023-04-26 15:17:49 +02:00
/** @var \App\Models\User $user */
2022-06-21 11:57:17 +02:00
$user = auth () -> user ();
2021-05-14 09:38:16 +02:00
$this -> serializer = request () -> input ( 'serializer' ) ? : EntityTransformer :: API_SERIALIZER_ARRAY ;
if ( $this -> serializer === EntityTransformer :: API_SERIALIZER_JSON ) {
$this -> manager -> setSerializer ( new JsonApiSerializer ());
} else {
$this -> manager -> setSerializer ( new ArraySerializer ());
}
$transformer = new $this -> entity_transformer ( $this -> serializer );
$created_at = request () -> has ( 'created_at' ) ? request () -> input ( 'created_at' ) : 0 ;
$created_at = date ( 'Y-m-d H:i:s' , $created_at );
$query -> with (
[
2023-01-25 02:58:24 +01:00
'company' => function ( $query ) {
2022-06-21 11:57:17 +02:00
$query -> whereNotNull ( 'created_at' ) -> with ( 'documents' , 'users' );
},
2024-01-14 05:05:00 +01:00
'company.designs' => function ( $query ) use ( $created_at ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at ) -> with ( 'company' );
},
2024-01-14 05:05:00 +01:00
'company.documents' => function ( $query ) use ( $created_at ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at );
},
2024-01-14 05:05:00 +01:00
'company.groups' => function ( $query ) use ( $created_at ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at ) -> with ( 'documents' );
},
2024-01-14 05:05:00 +01:00
'company.payment_terms' => function ( $query ) use ( $created_at ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at );
},
2024-01-14 05:05:00 +01:00
'company.tax_rates' => function ( $query ) {
2022-06-21 11:57:17 +02:00
$query -> whereNotNull ( 'created_at' );
},
2024-01-14 05:05:00 +01:00
'company.activities' => function ( $query ) use ( $user ) {
2022-06-21 11:57:17 +02:00
if ( ! $user -> isAdmin ()) {
$query -> where ( 'activities.user_id' , $user -> id );
}
},
2024-01-14 05:05:00 +01:00
'company.bank_integrations' => function ( $query ) use ( $user ) {
2023-01-25 00:43:18 +01:00
if ( ! $user -> hasPermission ( 'view_bank_transaction' )) {
2022-09-07 07:09:53 +02:00
$query -> where ( 'bank_integrations.user_id' , $user -> id );
}
2023-01-25 00:43:18 +01:00
2023-02-16 02:36:09 +01:00
if ( ! $user -> isSuperUser () && $user -> hasIntersectPermissions ([ 'create_bank_transaction' , 'edit_bank_transaction' , 'view_bank_transaction' ])) {
2023-01-25 00:43:18 +01:00
$query -> exclude ([ " balance " ]);
}
2022-09-07 07:09:53 +02:00
},
2024-01-14 05:05:00 +01:00
'company.bank_transaction_rules' => function ( $query ) use ( $user ) {
2023-08-05 01:22:02 +02:00
if ( ! $user -> isAdmin () && ! $user -> hasIntersectPermissions ([ 'create_bank_transaction' , 'edit_bank_transaction' , 'view_bank_transaction' ])) {
2022-11-21 22:42:53 +01:00
$query -> where ( 'bank_transaction_rules.user_id' , $user -> id );
}
},
2024-01-14 05:05:00 +01:00
'company.task_schedulers' => function ( $query ) use ( $user ) {
2023-01-16 22:31:07 +01:00
if ( ! $user -> isAdmin ()) {
$query -> where ( 'schedulers.user_id' , $user -> id );
}
},
2022-06-21 11:57:17 +02:00
]
2021-05-14 09:38:16 +02:00
);
if ( $query instanceof Builder ) {
2022-10-27 02:28:09 +02:00
$limit = $this -> resolveQueryLimit ();
2021-05-14 09:38:16 +02:00
$paginator = $query -> paginate ( $limit );
2023-04-26 15:17:49 +02:00
2023-08-07 06:50:08 +02:00
/** @phpstan-ignore-next-line **/
2023-11-24 00:23:40 +01:00
$query = $paginator -> getCollection (); // @phpstan-ignore-line
2021-05-14 09:38:16 +02:00
$resource = new Collection ( $query , $transformer , $this -> entity_type );
$resource -> setPaginator ( new IlluminatePaginatorAdapter ( $paginator ));
}
2023-04-26 15:03:32 +02:00
// else {
// $resource = new Collection($query, $transformer, $this->entity_type);
// }
2021-05-14 09:38:16 +02:00
return $this -> response ( $this -> manager -> createData ( $resource ) -> toArray ());
}
2023-02-20 10:56:01 +01:00
/**
* Passes back the miniloaded data response
*
2024-07-14 13:28:54 +02:00
* @ param mixed $query
2023-04-26 15:17:49 +02:00
*
2023-02-20 10:56:01 +01:00
*/
2021-04-29 00:44:40 +02:00
protected function timeConstrainedResponse ( $query )
{
2023-04-26 15:17:49 +02:00
/** @var \App\Models\User $user */
2021-04-29 00:44:40 +02:00
$user = auth () -> user ();
2023-01-30 07:08:21 +01:00
if ( $user -> getCompany () -> is_large ) {
2022-06-21 11:57:17 +02:00
$this -> manager -> parseIncludes ( $this -> mini_load );
return $this -> miniLoadResponse ( $query );
} else {
$this -> manager -> parseIncludes ( $this -> first_load );
2021-05-14 09:38:16 +02:00
}
2021-04-29 00:44:40 +02:00
$this -> serializer = request () -> input ( 'serializer' ) ? : EntityTransformer :: API_SERIALIZER_ARRAY ;
if ( $this -> serializer === EntityTransformer :: API_SERIALIZER_JSON ) {
$this -> manager -> setSerializer ( new JsonApiSerializer ());
} else {
$this -> manager -> setSerializer ( new ArraySerializer ());
}
$transformer = new $this -> entity_transformer ( $this -> serializer );
$created_at = request () -> has ( 'created_at' ) ? request () -> input ( 'created_at' ) : 0 ;
$created_at = date ( 'Y-m-d H:i:s' , $created_at );
$query -> with (
[
2023-01-25 02:58:24 +01:00
'company' => function ( $query ) {
2022-06-21 11:57:17 +02:00
$query -> whereNotNull ( 'created_at' ) -> with ( 'documents' , 'users' );
},
'company.clients' => function ( $query ) use ( $created_at , $user ) {
$query -> where ( 'clients.created_at' , '>=' , $created_at ) -> with ( 'contacts.company' , 'gateway_tokens' , 'documents' );
if ( ! $user -> hasPermission ( 'view_client' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'clients.user_id' , $user -> id ) -> orWhere ( 'clients.assigned_user_id' , $user -> id );
});
2022-06-21 11:57:17 +02:00
}
2024-01-14 05:05:00 +01:00
2023-02-20 09:52:50 +01:00
if ( $user -> hasExcludedPermissions ( $this -> client_excludable_permissions , $this -> client_excludable_overrides )) {
2023-02-20 08:46:26 +01:00
$query -> exclude ( $this -> client_exclusion_fields );
}
2022-06-21 11:57:17 +02:00
},
'company.company_gateways' => function ( $query ) use ( $user ) {
$query -> whereNotNull ( 'created_at' ) -> with ( 'gateway' );
if ( ! $user -> isAdmin ()) {
$query -> where ( 'company_gateways.user_id' , $user -> id );
}
},
2024-01-14 05:05:00 +01:00
'company.credits' => function ( $query ) use ( $created_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at ) -> with ( 'invitations' , 'documents' );
if ( ! $user -> hasPermission ( 'view_credit' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'credits.user_id' , $user -> id ) -> orWhere ( 'credits.assigned_user_id' , $user -> id );
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.documents' => function ( $query ) use ( $created_at ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at );
},
2024-01-14 05:05:00 +01:00
'company.expenses' => function ( $query ) use ( $created_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at ) -> with ( 'documents' );
if ( ! $user -> hasPermission ( 'view_expense' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'expenses.user_id' , $user -> id ) -> orWhere ( 'expenses.assigned_user_id' , $user -> id );
});
2022-06-21 11:57:17 +02:00
}
},
2023-01-25 02:58:24 +01:00
'company.groups' => function ( $query ) use ( $created_at ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at ) -> with ( 'documents' );
},
2024-01-14 05:05:00 +01:00
'company.invoices' => function ( $query ) use ( $created_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at ) -> with ( 'invitations' , 'documents' );
if ( ! $user -> hasPermission ( 'view_invoice' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'invoices.user_id' , $user -> id ) -> orWhere ( 'invoices.assigned_user_id' , $user -> id );
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.payments' => function ( $query ) use ( $created_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at ) -> with ( 'paymentables' , 'documents' );
if ( ! $user -> hasPermission ( 'view_payment' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'payments.user_id' , $user -> id ) -> orWhere ( 'payments.assigned_user_id' , $user -> id );
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.payment_terms' => function ( $query ) use ( $created_at ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at );
},
'company.products' => function ( $query ) use ( $created_at , $user ) {
$query -> where ( 'created_at' , '>=' , $created_at ) -> with ( 'documents' );
if ( ! $user -> hasPermission ( 'view_product' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'products.user_id' , $user -> id ) -> orWhere ( 'products.assigned_user_id' , $user -> id );
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.projects' => function ( $query ) use ( $created_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at ) -> with ( 'documents' );
if ( ! $user -> hasPermission ( 'view_project' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'projects.user_id' , $user -> id ) -> orWhere ( 'projects.assigned_user_id' , $user -> id );
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.purchase_orders' => function ( $query ) use ( $created_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at ) -> with ( 'documents' );
if ( ! $user -> hasPermission ( 'view_purchase_order' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'purchase_orders.user_id' , $user -> id ) -> orWhere ( 'purchase_orders.assigned_user_id' , $user -> id );
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.quotes' => function ( $query ) use ( $created_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at ) -> with ( 'invitations' , 'documents' );
if ( ! $user -> hasPermission ( 'view_quote' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'quotes.user_id' , $user -> id ) -> orWhere ( 'quotes.assigned_user_id' , $user -> id );
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.recurring_invoices' => function ( $query ) use ( $created_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at ) -> with ( 'invitations' , 'documents' , 'client.gateway_tokens' , 'client.group_settings' , 'client.company' );
if ( ! $user -> hasPermission ( 'view_recurring_invoice' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'recurring_invoices.user_id' , $user -> id ) -> orWhere ( 'recurring_invoices.assigned_user_id' , $user -> id );
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.tasks' => function ( $query ) use ( $created_at , $user ) {
2024-06-14 09:09:44 +02:00
$query -> where ( 'created_at' , '>=' , $created_at ) -> with ( 'project.documents' , 'documents' );
2022-06-21 11:57:17 +02:00
if ( ! $user -> hasPermission ( 'view_task' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'tasks.user_id' , $user -> id ) -> orWhere ( 'tasks.assigned_user_id' , $user -> id );
});
2022-06-21 11:57:17 +02:00
}
},
2023-01-25 02:58:24 +01:00
'company.tax_rates' => function ( $query ) use ( $created_at ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at );
},
2024-01-14 05:05:00 +01:00
'company.vendors' => function ( $query ) use ( $created_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at ) -> with ( 'contacts' , 'documents' );
if ( ! $user -> hasPermission ( 'view_vendor' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'vendors.user_id' , $user -> id ) -> orWhere ( 'vendors.assigned_user_id' , $user -> id );
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.expense_categories' => function ( $query ) {
2022-06-21 11:57:17 +02:00
$query -> whereNotNull ( 'created_at' );
},
2024-01-14 05:05:00 +01:00
'company.task_statuses' => function ( $query ) use ( $created_at ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at );
},
2024-01-14 05:05:00 +01:00
'company.activities' => function ( $query ) use ( $user ) {
2022-06-21 11:57:17 +02:00
if ( ! $user -> isAdmin ()) {
$query -> where ( 'activities.user_id' , $user -> id );
}
},
2024-01-14 05:05:00 +01:00
'company.webhooks' => function ( $query ) use ( $user ) {
2022-06-21 11:57:17 +02:00
if ( ! $user -> isAdmin ()) {
$query -> where ( 'webhooks.user_id' , $user -> id );
}
},
2024-01-14 05:05:00 +01:00
'company.tokens' => function ( $query ) use ( $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'company_tokens.user_id' , $user -> id );
},
'company.system_logs' ,
2024-01-14 05:05:00 +01:00
'company.subscriptions' => function ( $query ) use ( $created_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at );
if ( ! $user -> isAdmin ()) {
$query -> where ( 'subscriptions.user_id' , $user -> id );
}
},
2024-01-14 05:05:00 +01:00
'company.recurring_expenses' => function ( $query ) use ( $created_at , $user ) {
2022-06-21 11:57:17 +02:00
$query -> where ( 'created_at' , '>=' , $created_at ) -> with ( 'documents' );
if ( ! $user -> hasPermission ( 'view_recurring_expense' )) {
2023-02-16 02:36:09 +01:00
$query -> whereNested ( function ( $query ) use ( $user ) {
2022-08-27 11:43:01 +02:00
$query -> where ( 'recurring_expenses.user_id' , $user -> id ) -> orWhere ( 'recurring_expenses.assigned_user_id' , $user -> id );
});
2022-06-21 11:57:17 +02:00
}
},
2024-01-14 05:05:00 +01:00
'company.bank_integrations' => function ( $query ) use ( $created_at , $user ) {
2022-09-07 07:09:53 +02:00
$query -> where ( 'created_at' , '>=' , $created_at );
2023-01-25 00:43:18 +01:00
if ( ! $user -> hasPermission ( 'view_bank_transaction' )) {
2022-09-07 07:09:53 +02:00
$query -> where ( 'bank_integrations.user_id' , $user -> id );
}
2023-01-25 00:43:18 +01:00
2023-02-16 02:36:09 +01:00
if ( ! $user -> isSuperUser () && $user -> hasIntersectPermissions ([ 'create_bank_transaction' , 'edit_bank_transaction' , 'view_bank_transaction' ])) {
2023-01-25 00:43:18 +01:00
$query -> exclude ([ " balance " ]);
}
2022-09-07 07:09:53 +02:00
},
2024-01-14 05:05:00 +01:00
'company.bank_transactions' => function ( $query ) use ( $created_at , $user ) {
2022-09-14 06:33:05 +02:00
$query -> where ( 'created_at' , '>=' , $created_at );
2023-01-31 12:21:23 +01:00
if ( ! $user -> hasPermission ( 'bank_transaction' )) {
2022-09-14 06:33:05 +02:00
$query -> where ( 'bank_transactions.user_id' , $user -> id );
}
},
2024-01-14 05:05:00 +01:00
'company.task_schedulers' => function ( $query ) use ( $created_at , $user ) {
2023-01-16 22:31:07 +01:00
$query -> where ( 'created_at' , '>=' , $created_at );
if ( ! $user -> isAdmin ()) {
$query -> where ( 'schedulers.user_id' , $user -> id );
}
},
2022-06-21 11:57:17 +02:00
]
2021-04-29 00:44:40 +02:00
);
if ( $query instanceof Builder ) {
2022-10-27 02:28:09 +02:00
$limit = $this -> resolveQueryLimit ();
2021-04-29 00:44:40 +02:00
$paginator = $query -> paginate ( $limit );
2023-04-26 15:17:49 +02:00
2023-08-07 06:50:08 +02:00
/** @phpstan-ignore-next-line **/
2023-11-24 00:23:40 +01:00
$query = $paginator -> getCollection (); // @phpstan-ignore-line
2021-04-29 00:44:40 +02:00
$resource = new Collection ( $query , $transformer , $this -> entity_type );
$resource -> setPaginator ( new IlluminatePaginatorAdapter ( $paginator ));
2023-10-26 04:57:44 +02:00
}
2024-01-14 05:05:00 +01:00
2024-07-14 13:28:54 +02:00
return $this -> response ( $this -> manager -> createData ( $resource ) -> toArray ()); //@phpstan-ignore-line
2021-04-29 00:44:40 +02:00
}
2024-01-14 05:05:00 +01:00
2023-02-20 10:56:01 +01:00
/**
* List response
2023-04-26 15:17:49 +02:00
*
2023-04-27 00:05:57 +02:00
* @ param Builder $query
2023-02-20 10:56:01 +01:00
*/
2023-04-26 16:16:07 +02:00
protected function listResponse ( Builder $query )
2019-03-28 22:34:58 +01:00
{
2019-06-24 02:13:53 +02:00
$this -> buildManager ();
2020-11-13 10:09:20 +01:00
$transformer = new $this -> entity_transformer ( request () -> input ( 'serializer' ));
2019-03-28 22:34:58 +01:00
$includes = $transformer -> getDefaultIncludes ();
2019-12-29 23:06:42 +01:00
2019-03-28 22:34:58 +01:00
$includes = $this -> getRequestIncludes ( $includes );
$query -> with ( $includes );
2023-03-24 02:12:12 +01:00
$user = Auth :: user ();
if ( $user && ! $user -> hasPermission ( 'view_' . Str :: snake ( class_basename ( $this -> entity_type )))) {
2023-02-16 02:36:09 +01:00
if ( in_array ( $this -> entity_type , [ User :: class ])) {
2023-03-24 02:12:12 +01:00
$query -> where ( 'id' , $user -> id );
2023-02-16 02:36:09 +01:00
} elseif ( in_array ( $this -> entity_type , [ BankTransactionRule :: class , CompanyGateway :: class , TaxRate :: class , BankIntegration :: class , Scheduler :: class , BankTransaction :: class , Webhook :: class , ExpenseCategory :: class ])) { //table without assigned_user_id
2023-03-24 02:12:12 +01:00
if ( $this -> entity_type == BankIntegration :: class && ! $user -> isSuperUser () && $user -> hasIntersectPermissions ([ 'create_bank_transaction' , 'edit_bank_transaction' , 'view_bank_transaction' ])) {
2023-02-16 02:36:09 +01:00
$query -> exclude ([ " balance " ]);
} //allows us to selective display bank integrations back to the user if they can view / create bank transactions but without the bank balance being present in the response
2023-10-26 04:57:44 +02:00
elseif ( $this -> entity_type == TaxRate :: class && $user -> hasIntersectPermissions ([ 'create_invoice' , 'edit_invoice' , 'create_quote' , 'edit_quote' , 'create_purchase_order' , 'edit_purchase_order' ])) {
2023-07-27 03:14:59 +02:00
// need to show tax rates if the user has the ability to create documents.
2023-11-30 07:59:17 +01:00
} elseif ( $this -> entity_type == ExpenseCategory :: class && $user -> hasPermission ( 'create_expense' )) {
2023-11-27 12:20:58 +01:00
// need to show expense categories if the user has the ability to create expenses.
2023-11-30 07:59:17 +01:00
} else {
2023-03-24 02:12:12 +01:00
$query -> where ( 'user_id' , '=' , $user -> id );
2023-02-16 02:36:09 +01:00
}
} elseif ( in_array ( $this -> entity_type , [ Design :: class , GroupSetting :: class , PaymentTerm :: class , TaskStatus :: class ])) {
2023-02-15 11:11:34 +01:00
// nlog($this->entity_type);
2023-02-16 02:36:09 +01:00
} else {
2024-08-22 08:45:06 +02:00
$query -> where ( function ( $q ) use ( $user ) { //grouping these together improves query performance significantly)
2024-06-30 09:37:44 +02:00
$q -> where ( 'user_id' , '=' , $user -> id ) -> orWhere ( 'assigned_user_id' , $user -> id );
});
2023-02-16 02:36:09 +01:00
}
2020-11-25 15:19:52 +01:00
}
2024-01-14 05:05:00 +01:00
2023-03-24 02:12:12 +01:00
if ( $this -> entity_type == Client :: class && $user -> hasExcludedPermissions ( $this -> client_excludable_permissions , $this -> client_excludable_overrides )) {
2023-02-20 09:52:50 +01:00
$query -> exclude ( $this -> client_exclusion_fields );
}
2023-01-20 23:23:56 +01:00
2020-11-25 15:19:52 +01:00
if ( request () -> has ( 'updated_at' ) && request () -> input ( 'updated_at' ) > 0 ) {
2020-11-13 10:09:20 +01:00
$query -> where ( 'updated_at' , '>=' , date ( 'Y-m-d H:i:s' , intval ( request () -> input ( 'updated_at' ))));
2020-11-25 15:19:52 +01:00
}
2020-02-28 13:11:56 +01:00
2020-11-25 15:19:52 +01:00
if ( $this -> serializer && $this -> serializer != EntityTransformer :: API_SERIALIZER_JSON ) {
2020-11-13 10:09:20 +01:00
$this -> entity_type = null ;
2020-11-25 15:19:52 +01:00
}
2019-03-28 22:34:58 +01:00
2020-11-13 10:09:20 +01:00
if ( $query instanceof Builder ) {
2022-10-27 02:28:09 +02:00
$limit = $this -> resolveQueryLimit ();
2019-03-28 22:34:58 +01:00
$paginator = $query -> paginate ( $limit );
2023-11-24 00:23:40 +01:00
$query = $paginator -> getCollection (); // @phpstan-ignore-line
2020-11-13 10:09:20 +01:00
$resource = new Collection ( $query , $transformer , $this -> entity_type );
2019-03-28 22:34:58 +01:00
$resource -> setPaginator ( new IlluminatePaginatorAdapter ( $paginator ));
}
2020-11-13 10:09:20 +01:00
return $this -> response ( $this -> manager -> createData ( $resource ) -> toArray ());
2019-03-28 22:34:58 +01:00
}
2024-01-14 05:05:00 +01:00
2023-02-20 10:56:01 +01:00
/**
* Sorts the response by keys
*
* @ param mixed $response
2024-06-16 00:30:25 +02:00
* @ return Response | \Illuminate\Http\JsonResponse
2023-02-20 10:56:01 +01:00
*/
2019-03-28 22:34:58 +01:00
protected function response ( $response )
{
2019-06-25 07:08:07 +02:00
$index = request () -> input ( 'index' ) ? : $this -> forced_index ;
2019-03-28 22:34:58 +01:00
if ( $index == 'none' ) {
unset ( $response [ 'meta' ]);
} else {
$meta = isset ( $response [ 'meta' ]) ? $response [ 'meta' ] : null ;
$response = [
$index => $response ,
];
if ( $meta ) {
$response [ 'meta' ] = $meta ;
unset ( $response [ $index ][ 'meta' ]);
}
2019-09-18 08:02:05 +02:00
2019-12-30 22:59:12 +01:00
if ( request () -> include_static ) {
2023-04-27 00:05:57 +02:00
/** @var \App\Models\User $user */
$user = auth () -> user ();
2024-05-12 12:23:17 +02:00
$response_data = Statics :: company ( $user -> getCompany () -> getLocale ());
2024-06-14 09:09:44 +02:00
if ( request () -> has ( 'einvoice' )) {
2024-05-12 12:23:17 +02:00
2024-08-22 08:45:06 +02:00
if ( class_exists ( Schema :: class )) {
2024-06-16 02:33:18 +02:00
$ro = new Schema ();
$response_data [ 'einvoice_schema' ] = $ro ( 'Peppol' );
}
2024-05-12 12:23:17 +02:00
}
$response [ 'static' ] = $response_data ;
2024-06-14 09:09:44 +02:00
2019-12-30 22:59:12 +01:00
}
2019-03-28 22:34:58 +01:00
}
2020-09-06 11:38:10 +02:00
2019-09-23 13:29:30 +02:00
ksort ( $response );
2019-03-28 22:34:58 +01:00
$response = json_encode ( $response , JSON_PRETTY_PRINT );
2020-02-10 10:53:02 +01:00
2019-03-28 22:34:58 +01:00
$headers = self :: getApiHeaders ();
2020-09-06 11:38:10 +02:00
2019-03-28 22:34:58 +01:00
return response () -> make ( $response , 200 , $headers );
}
2024-01-14 05:05:00 +01:00
2023-02-20 10:56:01 +01:00
/**
* Item Response
*
* @ param mixed $item
2024-06-16 00:30:25 +02:00
* @ return Response | \Illuminate\Http\JsonResponse
2023-02-20 10:56:01 +01:00
*/
2019-03-28 22:34:58 +01:00
protected function itemResponse ( $item )
{
2019-06-24 02:13:53 +02:00
$this -> buildManager ();
2019-03-28 22:34:58 +01:00
2020-11-13 10:09:20 +01:00
$transformer = new $this -> entity_transformer ( request () -> input ( 'serializer' ));
2019-03-28 22:34:58 +01:00
2020-11-25 15:19:52 +01:00
if ( $this -> serializer && $this -> serializer != EntityTransformer :: API_SERIALIZER_JSON ) {
2020-11-13 10:09:20 +01:00
$this -> entity_type = null ;
2020-11-25 15:19:52 +01:00
}
2021-03-29 12:58:03 +02:00
2020-11-13 11:42:06 +01:00
$resource = new Item ( $item , $transformer , $this -> entity_type );
2019-03-28 22:34:58 +01:00
2024-06-17 02:14:04 +02:00
/** @var ?\App\Models\User $user */
2023-04-27 00:05:57 +02:00
$user = auth () -> user ();
if ( $user && request () -> include_static ) {
$data [ 'static' ] = Statics :: company ( $user -> getCompany () -> getLocale ());
2020-11-25 15:19:52 +01:00
}
2020-09-06 11:38:10 +02:00
2020-11-13 10:09:20 +01:00
return $this -> response ( $this -> manager -> createData ( $resource ) -> toArray ());
2019-03-28 22:34:58 +01:00
}
2024-01-14 05:05:00 +01:00
2023-02-20 10:56:01 +01:00
/**
* Returns the API headers .
*
* @ return array
*/
public static function getApiHeaders () : array
2019-03-28 22:34:58 +01:00
{
return [
2022-06-21 11:57:17 +02:00
'Content-Type' => 'application/json' ,
'X-Api-Version' => config ( 'ninja.minimum_client_version' ),
'X-App-Version' => config ( 'ninja.app_version' ),
2019-03-28 22:34:58 +01:00
];
}
2024-01-14 05:05:00 +01:00
2023-02-20 10:56:01 +01:00
/**
* Returns the parsed relationship includes
*
* @ param mixed $data
* @ return array
*/
protected function getRequestIncludes ( $data ) : array
2019-03-28 22:34:58 +01:00
{
2020-09-06 11:38:10 +02:00
/*
2020-02-10 10:53:02 +01:00
* Thresholds for displaying large account on first load
*/
2020-03-21 06:37:30 +01:00
if ( request () -> has ( 'first_load' ) && request () -> input ( 'first_load' ) == 'true' ) {
2024-01-14 05:05:00 +01:00
2023-04-27 00:05:57 +02:00
/** @var \App\Models\User $user */
$user = auth () -> user ();
if ( $user -> getCompany () -> is_large && request () -> missing ( 'updated_at' )) {
2020-07-26 10:30:55 +02:00
$data = $this -> mini_load ;
2020-03-21 06:37:30 +01:00
} else {
2020-07-26 10:30:55 +02:00
$data = $this -> first_load ;
2020-03-21 06:37:30 +01:00
}
} else {
2023-08-21 11:31:25 +02:00
$included = request () -> input ( 'include' , '' );
2020-03-21 06:37:30 +01:00
$included = explode ( ',' , $included );
foreach ( $included as $include ) {
if ( $include == 'clients' ) {
$data [] = 'clients.contacts' ;
} elseif ( $include ) {
$data [] = $include ;
}
}
2019-03-28 22:34:58 +01:00
}
return $data ;
}
2024-01-14 05:05:00 +01:00
2023-02-20 10:56:01 +01:00
/**
* Main entrypoint for the default / route .
*
* @ return mixed
*/
2020-02-13 12:27:42 +01:00
public function flutterRoute ()
{
2024-01-14 05:05:00 +01:00
2024-07-11 09:15:24 +02:00
if (( bool ) $this -> checkAppSetup () !== false && DbSchema :: hasTable ( 'accounts' ) && $account = Account :: first ()) {
2024-01-14 05:05:00 +01:00
2023-04-27 00:05:57 +02:00
/** @var \App\Models\Account $account */
2023-02-07 13:03:05 +01:00
//always redirect invoicing.co to invoicing.co
2023-11-24 00:23:40 +01:00
if ( Ninja :: isHosted () && ! in_array ( request () -> getSchemeAndHttpHost (), [ 'https://staging.invoicing.co' , 'https://invoicing.co' , 'https://demo.invoicing.co' , 'https://invoiceninja.net' , config ( 'ninja.app_url' )])) {
return redirect () -> secure ( config ( 'ninja.app_url' ));
2023-02-16 02:36:09 +01:00
}
2023-02-07 13:03:05 +01:00
2020-09-06 11:38:10 +02:00
if ( config ( 'ninja.require_https' ) && ! request () -> isSecure ()) {
return redirect () -> secure ( request () -> getRequestUri ());
}
2020-06-28 05:47:13 +02:00
2021-10-19 11:35:06 +02:00
/* Clean up URLs and remove query parameters from the URL*/
2022-06-21 11:57:17 +02:00
if ( request () -> has ( 'login' ) && request () -> input ( 'login' ) == 'true' ) {
return redirect ( '/' ) -> with ([ 'login' => 'true' ]);
}
2021-10-19 11:35:06 +02:00
2022-06-23 10:47:44 +02:00
if ( request () -> has ( 'signup' ) && request () -> input ( 'signup' ) == 'true' ) {
return redirect ( '/' ) -> with ([ 'signup' => 'true' ]);
}
2021-10-19 11:35:06 +02:00
2022-09-06 11:18:05 +02:00
// 06-09-2022 - parse the path if loaded in a subdirectory for canvaskit resolution
2022-09-02 12:53:32 +02:00
$canvas_path_array = parse_url ( config ( 'ninja.app_url' ));
$canvas_path = ( array_key_exists ( 'path' , $canvas_path_array )) ? $canvas_path_array [ 'path' ] : '' ;
2023-02-16 02:36:09 +01:00
$canvas_path = rtrim ( str_replace ( " index.php " , " " , $canvas_path ), '/' );
2024-01-14 05:05:00 +01:00
2020-03-26 04:23:57 +01:00
$data = [];
2020-03-18 10:40:15 +01:00
2021-08-09 00:59:28 +02:00
//pass report errors bool to front end
$data [ 'report_errors' ] = Ninja :: isSelfHost () ? $account -> report_errors : true ;
2021-08-09 00:44:51 +02:00
2023-01-14 21:46:23 +01:00
//pass whitelabel bool to front end
$data [ 'white_label' ] = Ninja :: isSelfHost () ? $account -> isPaid () : false ;
2021-08-09 00:59:28 +02:00
//pass referral code to front end
2023-11-02 01:16:14 +01:00
$data [ 'rc' ] = request () -> has ( 'rc' ) && is_string ( request () -> input ( 'rc' )) ? request () -> input ( 'rc' ) : '' ;
$data [ 'build' ] = request () -> has ( 'build' ) && is_string ( request () -> input ( 'build' )) ? request () -> input ( 'build' ) : '' ;
$data [ 'login' ] = request () -> has ( 'login' ) && is_string ( request () -> input ( 'input' )) ? request () -> input ( 'login' ) : 'false' ;
$data [ 'signup' ] = request () -> has ( 'signup' ) && is_string ( request () -> input ( 'signup' )) ? request () -> input ( 'signup' ) : 'false' ;
2022-09-02 12:53:32 +02:00
$data [ 'canvas_path' ] = $canvas_path ;
2022-06-21 11:57:17 +02:00
if ( request () -> session () -> has ( 'login' )) {
$data [ 'login' ] = 'true' ;
}
2021-10-19 11:35:06 +02:00
2023-02-16 02:36:09 +01:00
if ( request () -> session () -> has ( 'signup' )) {
2022-06-23 10:47:44 +02:00
$data [ 'signup' ] = 'true' ;
}
2021-10-19 11:35:06 +02:00
2021-09-15 02:15:14 +02:00
$data [ 'user_agent' ] = request () -> server ( 'HTTP_USER_AGENT' );
2021-08-20 11:04:16 +02:00
$data [ 'path' ] = $this -> setBuild ();
2021-08-09 00:44:51 +02:00
2022-06-21 11:57:17 +02:00
if ( Ninja :: isSelfHost () && $account -> set_react_as_default_ap ) {
2022-05-27 05:10:32 +02:00
return response () -> view ( 'react.index' , $data ) -> header ( 'X-Frame-Options' , 'SAMEORIGIN' , false );
2022-06-21 11:57:17 +02:00
} else {
2022-05-27 05:10:32 +02:00
return response () -> view ( 'index.index' , $data ) -> header ( 'X-Frame-Options' , 'SAMEORIGIN' , false );
2022-06-21 11:57:17 +02:00
}
2020-03-25 09:36:47 +01:00
}
2020-03-26 04:23:57 +01:00
return redirect ( '/setup' );
2020-02-13 12:27:42 +01:00
}
2024-01-14 05:05:00 +01:00
2023-02-20 10:56:01 +01:00
/**
* Sets the Flutter build to serve
*
2023-04-26 15:03:32 +02:00
* @ return string
2023-02-20 10:56:01 +01:00
*/
2023-04-26 15:03:32 +02:00
private function setBuild () : string
2021-08-20 11:04:16 +02:00
{
$build = '' ;
2022-06-21 11:57:17 +02:00
if ( request () -> has ( 'build' )) {
2021-08-20 11:14:27 +02:00
$build = request () -> input ( 'build' );
2022-06-21 11:57:17 +02:00
} elseif ( Ninja :: isHosted ()) {
2021-09-26 10:44:41 +02:00
return 'main.dart.js' ;
}
2021-08-20 11:04:16 +02:00
switch ( $build ) {
case 'wasm' :
2021-08-20 11:25:07 +02:00
return 'main.wasm.dart.js' ;
2021-08-20 11:04:16 +02:00
case 'foss' :
2021-08-20 11:25:07 +02:00
return 'main.foss.dart.js' ;
2021-08-20 11:04:16 +02:00
case 'last' :
2021-08-20 11:25:07 +02:00
return 'main.last.dart.js' ;
2021-08-20 11:04:16 +02:00
case 'next' :
2022-06-21 11:57:17 +02:00
return 'main.next.dart.js' ;
2021-08-25 11:41:03 +02:00
case 'profile' :
2022-06-21 11:57:17 +02:00
return 'main.profile.dart.js' ;
2021-08-20 11:04:16 +02:00
default :
2021-09-26 10:44:41 +02:00
return 'main.foss.dart.js' ;
2021-08-20 11:04:16 +02:00
}
}
2024-01-14 05:05:00 +01:00
2023-02-20 10:56:01 +01:00
/**
* Checks in a account has a required feature
*
* @ param mixed $feature
* @ return bool
*/
2021-03-07 11:14:53 +01:00
public function checkFeature ( $feature )
{
2022-06-21 11:57:17 +02:00
if ( auth () -> user () -> account -> hasFeature ( $feature )) {
return true ;
}
2021-03-07 11:14:53 +01:00
2022-06-21 11:57:17 +02:00
return false ;
2021-03-07 11:14:53 +01:00
}
2024-01-14 05:05:00 +01:00
2023-02-20 10:56:01 +01:00
/**
* Feature failure response
*
* @ return mixed
*/
2021-03-07 11:14:53 +01:00
public function featureFailure ()
{
2022-06-21 11:57:17 +02:00
return response () -> json ([ 'message' => 'Upgrade to a paid plan for this feature.' ], 403 );
2021-03-07 11:14:53 +01:00
}
2019-12-30 22:59:12 +01:00
}