1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 21:22:58 +01:00
invoiceninja/app/Http/Controllers/BaseController.php

1215 lines
48 KiB
PHP
Raw Normal View History

2019-03-28 22:34:58 +01:00
<?php
2019-05-11 05:32:07 +02:00
/**
* Invoice Ninja (https://invoiceninja.com).
2019-05-11 05:32:07 +02:00
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
2023-01-28 23:21:40 +01:00
* @copyright Copyright (c) 2023. 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;
2023-04-19 05:47:47 +02:00
use App\Models\Account;
use App\Models\BankIntegration;
use App\Models\BankTransaction;
use App\Models\BankTransactionRule;
2023-04-26 15:17:49 +02:00
use App\Models\Client;
use App\Models\CompanyGateway;
use App\Models\Design;
use App\Models\ExpenseCategory;
use App\Models\GroupSetting;
use App\Models\PaymentTerm;
use App\Models\Scheduler;
use App\Models\TaskStatus;
use App\Models\TaxRate;
use App\Models\User;
use App\Models\Webhook;
2023-04-19 05:47:47 +02:00
use App\Transformers\ArraySerializer;
use App\Transformers\EntityTransformer;
2023-04-26 15:17:49 +02:00
use App\Utils\Ninja;
use App\Utils\Statics;
use App\Utils\Traits\AppSetup;
use Illuminate\Contracts\Container\BindingResolutionException;
2023-04-19 05:47:47 +02:00
use Illuminate\Database\Eloquent\Builder;
2023-04-26 15:17:49 +02:00
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use League\Fractal\Manager;
2023-04-19 05:47:47 +02:00
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
2023-04-26 15:17:49 +02:00
use League\Fractal\Resource\Collection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
2019-03-28 22:34:58 +01:00
/**
* Class BaseController.
2023-04-26 23:46:59 +02:00
* @method static Illuminate\Database\Eloquent\Builder exclude($columns)
*/
2019-03-28 22:34:58 +01:00
class BaseController extends Controller
{
use AppSetup;
/**
* Passed from the parent when we need to force
* includes internally rather than externally via
2019-09-11 02:37:53 +02:00
* the $_REQUEST 'include' variable.
*
* @var array
*/
public $forced_includes = [];
2019-06-25 07:08:07 +02:00
/**
* Passed from the parent when we need to force
* the key of the response object.
2019-06-25 07:08:07 +02:00
* @var string
*/
public $forced_index = 'data';
2019-06-25 07:08:07 +02:00
/**
* The calling controller Model Type
*/
protected $entity_type;
/**
* The calling controller Transformer type
*
*/
protected $entity_transformer;
/**
* The serializer in use with Fractal
*
*/
protected $serializer;
/* Grouped permissions when we want to hide columns for particular permission groups*/
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'];
/* Grouped permissions when we want to hide columns for particular permission groups*/
/**
* Fractal manager.
* @var Manager $manager
*/
protected Manager $manager;
/**
* 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',
'company.designs.company',
2020-10-25 21:56:02 +01:00
'company.task_statuses',
'company.expense_categories',
'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',
'company.clients.gateway_tokens',
2020-09-19 04:05:54 +02:00
'company.clients.documents',
'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',
'company.products',
'company.products.documents',
'company.payments.paymentables',
'company.payments.documents',
2022-06-14 14:18:20 +02:00
'company.purchase_orders.documents',
'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',
'company.subscriptions',
'company.tax_rates',
'company.tokens_hashed',
2020-10-26 01:58:08 +01:00
'company.vendors.contacts.company',
'company.vendors.documents',
'company.webhooks',
2021-03-30 00:32:33 +02:00
'company.system_logs',
'company.bank_integrations',
'company.bank_transactions',
'company.bank_transaction_rules',
'company.task_schedulers',
2020-07-26 10:30:55 +02: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 = [
'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',
'company.bank_integrations',
'company.bank_transaction_rules',
'company.task_schedulers',
];
/**
* __construct
*
* @return void
*/
public function __construct()
2019-03-28 22:34:58 +01:00
{
$this->manager = new Manager();
}
/**
* Initializes the Manager and transforms
* the required includes
*
* @return void
*/
private function buildManager()
{
2019-06-24 13:05:47 +02:00
$include = '';
if (request()->has('first_load') && request()->input('first_load') == 'true') {
$include = implode(',', array_merge($this->forced_includes, $this->getRequestIncludes([])));
} elseif (request()->input('include') !== null) {
$include = array_merge($this->forced_includes, explode(',', request()->input('include')));
$include = implode(',', $include);
} elseif (count($this->forced_includes) >= 1) {
$include = implode(',', $this->forced_includes);
2019-06-24 13:05:47 +02:00
}
// $include = $this->filterIncludes($include);
$this->manager->parseIncludes($include);
2019-03-28 22:34:58 +01:00
$this->serializer = request()->input('serializer') ?: EntityTransformer::API_SERIALIZER_ARRAY;
if ($this->serializer === EntityTransformer::API_SERIALIZER_JSON) {
2019-03-28 22:34:58 +01:00
$this->manager->setSerializer(new JsonApiSerializer());
} else {
2019-03-28 22:34:58 +01:00
$this->manager->setSerializer(new ArraySerializer());
}
2019-03-28 22:34:58 +01:00
}
/**
* Catch all fallback route.
*/
public function notFound()
{
2021-01-24 23:24:13 +01:00
return response()->json(['message' => ctrans('texts.api_404')], 404)
->header('X-API-VERSION', config('ninja.minimum_client_version'))
->header('X-APP-VERSION', config('ninja.app_version'));
}
/**
* Filters the includes to ensure the
2023-02-16 02:36:09 +01:00
* end user has the correct permissions to
* view the includes
2023-02-16 02:36:09 +01:00
*
* @param string $includes The includes for the object
* @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(",");
// }
/**
* 404 for the client portal.
* @return Response 404 response
*/
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.');
}
/**
* API Error response.
*
* @param string $message The return error message
* @param int $httpErrorCode 404/401/403 etc
* @return Response The JSON response
2020-10-28 11:10:49 +01:00
* @throws BindingResolutionException
*/
protected function errorResponse($message, $httpErrorCode = 400)
2019-03-28 22:34:58 +01:00
{
$error['error'] = $message;
2019-03-28 22:34:58 +01:00
$error = json_encode($error, JSON_PRETTY_PRINT);
2019-03-28 22:34:58 +01:00
$headers = self::getApiHeaders();
return response()->make($error, $httpErrorCode, $headers);
}
/**
* Refresh API response with latest cahnges
*
* @param Builder $query
2023-04-26 15:03:32 +02:00
* @return Response
*/
protected function refreshResponse($query)
{
2023-04-26 15:17:49 +02:00
/** @var \App\Models\User $user */
$user = auth()->user();
$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-26 07:12:40 +02:00
$transformer = new $this->entity_transformer($this->serializer);
2023-01-21 06:52:24 +01:00
$updated_at = request()->has('updated_at') ? request()->input('updated_at') : 0;
if ($user->getCompany()->is_large && $updated_at == 0) {
$updated_at = time();
}
$updated_at = date('Y-m-d H:i:s', $updated_at);
$query->with(
2020-11-25 15:19:52 +01:00
[
'company' => function ($query) {
$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
});
}
if ($user->hasExcludedPermissions($this->client_excludable_permissions, $this->client_excludable_overrides)) {
$query->exclude($this->client_exclusion_fields);
}
},
'company.company_gateways' => function ($query) use ($user) {
$query->whereNotNull('updated_at')->with('gateway');
if (! $user->isAdmin()) {
$query->where('company_gateways.user_id', $user->id);
}
},
'company.credits'=> function ($query) use ($updated_at, $user) {
$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
});
}
},
'company.designs'=> function ($query) use ($updated_at, $user) {
$query->where('updated_at', '>=', $updated_at)->with('company');
if (! $user->isAdmin()) {
$query->where('designs.user_id', $user->id);
}
},
2023-04-25 06:38:43 +02:00
'company.documents'=> function ($query) use ($updated_at) {
$query->where('updated_at', '>=', $updated_at);
},
'company.expenses'=> function ($query) use ($updated_at, $user) {
$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
});
}
},
'company.groups' => function ($query) {
$query->whereNotNull('updated_at')->with('documents');
},
'company.invoices'=> function ($query) use ($updated_at, $user) {
$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
});
}
},
'company.payments'=> function ($query) use ($updated_at, $user) {
$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
});
}
},
'company.payment_terms'=> function ($query) use ($user) {
$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) {
$query->where('products.user_id', $user->id)->orWhere('products.assigned_user_id', $user->id);
});
}
},
'company.projects'=> function ($query) use ($updated_at, $user) {
$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
});
}
},
'company.purchase_orders'=> function ($query) use ($updated_at, $user) {
$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
});
}
},
'company.quotes'=> function ($query) use ($updated_at, $user) {
$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
});
}
},
'company.recurring_invoices'=> function ($query) use ($updated_at, $user) {
$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
});
}
},
'company.recurring_expenses'=> function ($query) use ($updated_at, $user) {
$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
});
}
},
'company.tasks'=> function ($query) use ($updated_at, $user) {
$query->where('updated_at', '>=', $updated_at)->with('documents');
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
});
}
},
'company.tax_rates'=> function ($query) {
$query->whereNotNull('updated_at');
},
'company.vendors'=> function ($query) use ($updated_at, $user) {
$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
});
}
},
'company.expense_categories'=> function ($query) {
$query->whereNotNull('updated_at');
},
'company.task_statuses'=> function ($query) {
$query->whereNotNull('updated_at');
},
'company.activities'=> function ($query) use ($user) {
if (! $user->isAdmin()) {
$query->where('activities.user_id', $user->id);
}
},
'company.subscriptions'=> function ($query) use ($user) {
$query->whereNotNull('updated_at');
if (! $user->isAdmin()) {
$query->where('subscriptions.user_id', $user->id);
}
},
'company.bank_integrations'=> function ($query) use ($user) {
$query->whereNotNull('updated_at');
//scopes down permissions for users with no permissions
if (! $user->hasPermission('view_bank_transaction')) {
$query->where('bank_integrations.user_id', $user->id);
}
//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'])) {
$query->exclude(["balance"]);
}
},
'company.bank_transactions'=> function ($query) use ($updated_at, $user) {
2022-09-14 08:48:56 +02:00
$query->where('updated_at', '>=', $updated_at);
if (! $user->hasPermission('view_bank_transaction')) {
$query->where('bank_transactions.user_id', $user->id);
}
},
2023-08-06 07:24:13 +02:00
'company.bank_transaction_rules'=> function ($query) {
$query->whereNotNull('updated_at');
},
2023-08-06 07:24:13 +02:00
'company.task_schedulers'=> function ($query) {
$query->whereNotNull('updated_at');
2023-01-16 22:31:07 +01:00
},
]
);
2020-11-13 10:09:20 +01:00
if ($query instanceof Builder) {
$limit = $this->resolveQueryLimit();
2020-07-24 11:39:43 +02:00
$paginator = $query->paginate($limit);
2023-08-07 06:50:08 +02:00
/** @phpstan-ignore-next-line **/
$query = $paginator->getCollection();
2020-07-24 11:39:43 +02:00
$resource = new Collection($query, $transformer, $this->entity_type);
2020-07-24 11:39:43 +02:00
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
}
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());
}
/**
* Returns the per page limit for the query.
*
* @return int
*/
private function resolveQueryLimit(): int
{
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
}
return 20;
}
/**
* Mini Load Query
*
2023-04-26 15:03:32 +02:00
* @param Builder $query
2023-04-26 15:17:49 +02: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 */
$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(
[
'company' => function ($query) {
$query->whereNotNull('created_at')->with('documents', 'users');
},
'company.designs'=> function ($query) use ($created_at) {
$query->where('created_at', '>=', $created_at)->with('company');
},
'company.documents'=> function ($query) use ($created_at) {
$query->where('created_at', '>=', $created_at);
},
'company.groups'=> function ($query) use ($created_at) {
$query->where('created_at', '>=', $created_at)->with('documents');
},
'company.payment_terms'=> function ($query) use ($created_at) {
$query->where('created_at', '>=', $created_at);
},
'company.tax_rates'=> function ($query) {
$query->whereNotNull('created_at');
},
'company.activities'=> function ($query) use ($user) {
if (! $user->isAdmin()) {
$query->where('activities.user_id', $user->id);
}
},
'company.bank_integrations'=> function ($query) use ($user) {
if (! $user->hasPermission('view_bank_transaction')) {
$query->where('bank_integrations.user_id', $user->id);
}
2023-02-16 02:36:09 +01:00
if (!$user->isSuperUser() && $user->hasIntersectPermissions(['create_bank_transaction','edit_bank_transaction','view_bank_transaction'])) {
$query->exclude(["balance"]);
}
},
'company.bank_transaction_rules'=> function ($query) use ($user) {
if (! $user->isAdmin() && !$user->hasIntersectPermissions(['create_bank_transaction','edit_bank_transaction','view_bank_transaction'])) {
$query->where('bank_transaction_rules.user_id', $user->id);
}
},
'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);
}
},
]
2021-05-14 09:38:16 +02:00
);
if ($query instanceof Builder) {
$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 **/
2021-05-14 09:38:16 +02:00
$query = $paginator->getCollection();
$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());
}
/**
* Passes back the miniloaded data response
*
2023-03-24 02:12:12 +01:00
* @param Builder $query
2023-04-26 15:17:49 +02: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) {
$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(
[
'company' => function ($query) {
$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);
});
}
if ($user->hasExcludedPermissions($this->client_excludable_permissions, $this->client_excludable_overrides)) {
$query->exclude($this->client_exclusion_fields);
}
},
'company.company_gateways' => function ($query) use ($user) {
$query->whereNotNull('created_at')->with('gateway');
if (! $user->isAdmin()) {
$query->where('company_gateways.user_id', $user->id);
}
},
'company.credits'=> function ($query) use ($created_at, $user) {
$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);
});
}
},
'company.documents'=> function ($query) use ($created_at) {
$query->where('created_at', '>=', $created_at);
},
'company.expenses'=> function ($query) use ($created_at, $user) {
$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);
});
}
},
'company.groups' => function ($query) use ($created_at) {
$query->where('created_at', '>=', $created_at)->with('documents');
},
'company.invoices'=> function ($query) use ($created_at, $user) {
$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);
});
}
},
'company.payments'=> function ($query) use ($created_at, $user) {
$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);
});
}
},
'company.payment_terms'=> function ($query) use ($created_at) {
$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);
});
}
},
'company.projects'=> function ($query) use ($created_at, $user) {
$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);
});
}
},
'company.purchase_orders'=> function ($query) use ($created_at, $user) {
$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);
});
}
},
'company.quotes'=> function ($query) use ($created_at, $user) {
$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);
});
}
},
'company.recurring_invoices'=> function ($query) use ($created_at, $user) {
$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);
});
}
},
'company.tasks'=> function ($query) use ($created_at, $user) {
$query->where('created_at', '>=', $created_at)->with('documents');
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);
});
}
},
'company.tax_rates' => function ($query) use ($created_at) {
$query->where('created_at', '>=', $created_at);
},
'company.vendors'=> function ($query) use ($created_at, $user) {
$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);
});
}
},
'company.expense_categories'=> function ($query) {
$query->whereNotNull('created_at');
},
'company.task_statuses'=> function ($query) use ($created_at) {
$query->where('created_at', '>=', $created_at);
},
'company.activities'=> function ($query) use ($user) {
if (! $user->isAdmin()) {
$query->where('activities.user_id', $user->id);
}
},
'company.webhooks'=> function ($query) use ($user) {
if (! $user->isAdmin()) {
$query->where('webhooks.user_id', $user->id);
}
},
'company.tokens'=> function ($query) use ($user) {
$query->where('company_tokens.user_id', $user->id);
},
'company.system_logs',
'company.subscriptions'=> function ($query) use ($created_at, $user) {
$query->where('created_at', '>=', $created_at);
if (! $user->isAdmin()) {
$query->where('subscriptions.user_id', $user->id);
}
},
'company.recurring_expenses'=> function ($query) use ($created_at, $user) {
$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);
});
}
},
'company.bank_integrations'=> function ($query) use ($created_at, $user) {
$query->where('created_at', '>=', $created_at);
if (! $user->hasPermission('view_bank_transaction')) {
$query->where('bank_integrations.user_id', $user->id);
}
2023-02-16 02:36:09 +01:00
if (!$user->isSuperUser() && $user->hasIntersectPermissions(['create_bank_transaction','edit_bank_transaction','view_bank_transaction'])) {
$query->exclude(["balance"]);
}
},
'company.bank_transactions'=> function ($query) use ($created_at, $user) {
$query->where('created_at', '>=', $created_at);
if (! $user->hasPermission('bank_transaction')) {
$query->where('bank_transactions.user_id', $user->id);
}
},
'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);
}
},
]
2021-04-29 00:44:40 +02:00
);
if ($query instanceof Builder) {
$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 **/
2021-04-29 00:44:40 +02:00
$query = $paginator->getCollection();
2023-04-26 15:17:49 +02:00
2021-04-29 00:44:40 +02:00
$resource = new Collection($query, $transformer, $this->entity_type);
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
2023-04-26 15:17:49 +02:00
}
// else {
// $resource = new Collection($query, $transformer, $this->entity_type);
// }
2021-04-29 00:44:40 +02:00
return $this->response($this->manager->createData($resource)->toArray());
}
/**
* List response
2023-04-26 15:17:49 +02:00
*
2023-04-27 00:05:57 +02:00
* @param Builder $query
*/
2023-04-26 16:16:07 +02:00
protected function listResponse(Builder $query)
2019-03-28 22:34:58 +01: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-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
elseif($this->entity_type == TaxRate::class && $user->hasIntersectPermissions(['create_invoice','edit_invoice','create_quote','edit_quote','create_purchase_order','edit_purchase_order'])){
// need to show tax rates if the user has the ability to create documents.
}
2023-02-16 02:36:09 +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])) {
// nlog($this->entity_type);
2023-02-16 02:36:09 +01:00
} else {
2023-03-24 02:12:12 +01:00
$query->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
}
2023-03-24 02:12:12 +01:00
if ($this->entity_type == Client::class && $user->hasExcludedPermissions($this->client_excludable_permissions, $this->client_excludable_overrides)) {
$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-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) {
$limit = $this->resolveQueryLimit();
2019-03-28 22:34:58 +01:00
$paginator = $query->paginate($limit);
$query = $paginator->getCollection();
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
}
/**
* Sorts the response by keys
*
* @param mixed $response
2023-04-26 15:03:32 +02:00
* @return Response
*/
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
if (request()->include_static) {
2023-04-27 00:05:57 +02:00
/** @var \App\Models\User $user */
$user = auth()->user();
$response['static'] = Statics::company($user->getCompany()->getLocale());
}
2019-03-28 22:34:58 +01:00
}
ksort($response);
2019-03-28 22:34:58 +01:00
$response = json_encode($response, JSON_PRETTY_PRINT);
2019-03-28 22:34:58 +01:00
$headers = self::getApiHeaders();
2019-03-28 22:34:58 +01:00
return response()->make($response, 200, $headers);
}
/**
* Item Response
*
* @param mixed $item
2023-04-26 15:03:32 +02:00
* @return Response
*/
2019-03-28 22:34:58 +01:00
protected function itemResponse($item)
{
$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
}
$resource = new Item($item, $transformer, $this->entity_type);
2019-03-28 22:34:58 +01:00
2023-04-27 00:05:57 +02:00
/** @var \App\Models\User $user */
$user = auth()->user();
if ($user && request()->include_static) {
$data['static'] = Statics::company($user->getCompany()->getLocale());
2020-11-25 15:19:52 +01: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
}
/**
* Returns the API headers.
*
* @return array
*/
public static function getApiHeaders(): array
2019-03-28 22:34:58 +01:00
{
return [
'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
];
}
/**
* Returns the parsed relationship includes
*
* @param mixed $data
* @return array
*/
protected function getRequestIncludes($data): array
2019-03-28 22:34:58 +01:00
{
/*
* Thresholds for displaying large account on first load
*/
if (request()->has('first_load') && request()->input('first_load') == 'true') {
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;
} else {
2020-07-26 10:30:55 +02:00
$data = $this->first_load;
}
} else {
2023-08-21 11:31:25 +02:00
$included = request()->input('include', '');
$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;
}
/**
* Main entrypoint for the default / route.
*
* @return mixed
*/
public function flutterRoute()
{
2023-04-27 00:05:57 +02:00
2020-10-26 01:58:08 +01:00
if ((bool) $this->checkAppSetup() !== false && $account = Account::first()) {
2023-04-27 00:05:57 +02:00
/** @var \App\Models\Account $account */
//always redirect invoicing.co to invoicing.co
2023-03-21 09:56:20 +01:00
if (Ninja::isHosted() && !in_array(request()->getSchemeAndHttpHost(), ['https://staging.invoicing.co', 'https://invoicing.co', 'https://demo.invoicing.co', 'https://invoiceninja.net'])) {
return redirect()->secure('https://invoicing.co');
2023-02-16 02:36:09 +01:00
}
if (config('ninja.require_https') && ! request()->isSecure()) {
return redirect()->secure(request()->getRequestUri());
}
2021-10-19 11:35:06 +02:00
/* Clean up URLs and remove query parameters from the URL*/
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
// 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), '/');
2022-09-02 12:53:32 +02:00
$data = [];
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
$data['rc'] = request()->has('rc') ? request()->input('rc') : '';
2021-08-20 11:04:16 +02:00
$data['build'] = request()->has('build') ? request()->input('build') : '';
$data['login'] = request()->has('login') ? request()->input('login') : 'false';
2022-06-23 10:47:44 +02:00
$data['signup'] = request()->has('signup') ? request()->input('signup') : 'false';
2022-09-02 12:53:32 +02:00
$data['canvas_path'] = $canvas_path;
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
$this->buildCache();
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);
} else {
2022-05-27 05:10:32 +02:00
return response()->view('index.index', $data)->header('X-Frame-Options', 'SAMEORIGIN', false);
}
}
return redirect('/setup');
}
/**
* Sets the Flutter build to serve
*
2023-04-26 15:03:32 +02:00
* @return string
*/
2023-04-26 15:03:32 +02:00
private function setBuild(): string
2021-08-20 11:04:16 +02:00
{
$build = '';
if (request()->has('build')) {
2021-08-20 11:14:27 +02:00
$build = request()->input('build');
} 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':
return 'main.next.dart.js';
2021-08-25 11:41:03 +02:00
case 'profile':
return 'main.profile.dart.js';
case 'html':
return 'main.html.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
}
}
/**
* 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)
{
if (auth()->user()->account->hasFeature($feature)) {
return true;
}
2021-03-07 11:14:53 +01:00
return false;
2021-03-07 11:14:53 +01:00
}
/**
* Feature failure response
*
* @return mixed
*/
2021-03-07 11:14:53 +01:00
public function featureFailure()
{
return response()->json(['message' => 'Upgrade to a paid plan for this feature.'], 403);
2021-03-07 11:14:53 +01:00
}
}