From fe2ad3edd8cbc5ed5d56d2a44ebc1f2a1e64132d Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 23 Jan 2023 07:41:27 +1100 Subject: [PATCH 01/16] Fixes for multidb Task Scheduler --- app/Jobs/Ninja/TaskScheduler.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/app/Jobs/Ninja/TaskScheduler.php b/app/Jobs/Ninja/TaskScheduler.php index 69862f8877c2..f4a6104d1a07 100644 --- a/app/Jobs/Ninja/TaskScheduler.php +++ b/app/Jobs/Ninja/TaskScheduler.php @@ -42,6 +42,23 @@ class TaskScheduler implements ShouldQueue */ public function handle() { + + if (! config('ninja.db.multi_db_enabled')) { + + Scheduler::with('company') + ->where('is_paused', false) + ->where('is_deleted', false) + ->whereNotNull('next_run') + ->where('next_run', '<=', now()) + ->cursor() + ->each(function ($scheduler) { + $this->doJob($scheduler); + }); + + + return; + } + foreach (MultiDB::$dbs as $db) { MultiDB::setDB($db); From 526a26868ac53260554e2c29392d78aa0089a07f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 23 Jan 2023 08:15:40 +1100 Subject: [PATCH 02/16] Fixes for schema --- .../2014_10_13_000000_create_users_table.php | 24 +++++----- ...40557_add_is_public_to_documents_table.php | 8 ++-- ...31_change_custom_surcharge_column_type.php | 48 +++++++++---------- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/database/migrations/2014_10_13_000000_create_users_table.php b/database/migrations/2014_10_13_000000_create_users_table.php index 59de4b5047b4..bf25b3891e35 100644 --- a/database/migrations/2014_10_13_000000_create_users_table.php +++ b/database/migrations/2014_10_13_000000_create_users_table.php @@ -476,10 +476,10 @@ return new class extends Migration { $t->string('custom_value4')->nullable(); $t->datetime('next_send_date')->nullable(); - $t->string('custom_surcharge1')->nullable(); - $t->string('custom_surcharge2')->nullable(); - $t->string('custom_surcharge3')->nullable(); - $t->string('custom_surcharge4')->nullable(); + $t->decimal('custom_surcharge1', 20, 6)->nullable(); + $t->decimal('custom_surcharge2', 20, 6)->nullable(); + $t->decimal('custom_surcharge3', 20, 6)->nullable(); + $t->decimal('custom_surcharge4', 20, 6)->nullable(); $t->boolean('custom_surcharge_tax1')->default(false); $t->boolean('custom_surcharge_tax2')->default(false); $t->boolean('custom_surcharge_tax3')->default(false); @@ -554,10 +554,10 @@ return new class extends Migration { $t->string('custom_value4')->nullable(); $t->datetime('next_send_date')->nullable(); - $t->string('custom_surcharge1')->nullable(); - $t->string('custom_surcharge2')->nullable(); - $t->string('custom_surcharge3')->nullable(); - $t->string('custom_surcharge4')->nullable(); + $t->decimal('custom_surcharge1', 20, 6)->nullable(); + $t->decimal('custom_surcharge2', 20, 6)->nullable(); + $t->decimal('custom_surcharge3', 20, 6)->nullable(); + $t->decimal('custom_surcharge4', 20, 6)->nullable(); $t->boolean('custom_surcharge_tax1')->default(false); $t->boolean('custom_surcharge_tax2')->default(false); $t->boolean('custom_surcharge_tax3')->default(false); @@ -791,10 +791,10 @@ return new class extends Migration { $t->string('custom_value3')->nullable(); $t->string('custom_value4')->nullable(); - $t->string('custom_surcharge1')->nullable(); - $t->string('custom_surcharge2')->nullable(); - $t->string('custom_surcharge3')->nullable(); - $t->string('custom_surcharge4')->nullable(); + $t->decimal('custom_surcharge1', 20, 6)->nullable(); + $t->decimal('custom_surcharge2', 20, 6)->nullable(); + $t->decimal('custom_surcharge3', 20, 6)->nullable(); + $t->decimal('custom_surcharge4', 20, 6)->nullable(); $t->boolean('custom_surcharge_tax1')->default(false); $t->boolean('custom_surcharge_tax2')->default(false); $t->boolean('custom_surcharge_tax3')->default(false); diff --git a/database/migrations/2020_08_18_140557_add_is_public_to_documents_table.php b/database/migrations/2020_08_18_140557_add_is_public_to_documents_table.php index 8628c31217b3..5944297e60d4 100644 --- a/database/migrations/2020_08_18_140557_add_is_public_to_documents_table.php +++ b/database/migrations/2020_08_18_140557_add_is_public_to_documents_table.php @@ -59,10 +59,10 @@ return new class extends Migration { $table->boolean('auto_bill_enabled')->default(0); $table->unsignedInteger('design_id')->nullable(); $table->boolean('uses_inclusive_taxes')->default(0); - $table->string('custom_surcharge1')->nullable(); - $table->string('custom_surcharge2')->nullable(); - $table->string('custom_surcharge3')->nullable(); - $table->string('custom_surcharge4')->nullable(); + $table->decimal('custom_surcharge1', 20, 6)->nullable(); + $table->decimal('custom_surcharge2', 20, 6)->nullable(); + $table->decimal('custom_surcharge3', 20, 6)->nullable(); + $table->decimal('custom_surcharge4', 20, 6)->nullable(); $table->boolean('custom_surcharge_tax1')->default(false); $table->boolean('custom_surcharge_tax2')->default(false); $table->boolean('custom_surcharge_tax3')->default(false); diff --git a/database/migrations/2021_01_17_040331_change_custom_surcharge_column_type.php b/database/migrations/2021_01_17_040331_change_custom_surcharge_column_type.php index cf00db8af5e3..538a3ddf9e5f 100644 --- a/database/migrations/2021_01_17_040331_change_custom_surcharge_column_type.php +++ b/database/migrations/2021_01_17_040331_change_custom_surcharge_column_type.php @@ -12,33 +12,33 @@ return new class extends Migration { */ public function up() { - Schema::table('invoices', function (Blueprint $table) { - $table->decimal('custom_surcharge1', 20, 6)->change(); - $table->decimal('custom_surcharge2', 20, 6)->change(); - $table->decimal('custom_surcharge3', 20, 6)->change(); - $table->decimal('custom_surcharge4', 20, 6)->change(); - }); + // Schema::table('invoices', function (Blueprint $table) { + // $table->decimal('custom_surcharge1', 20, 6)->change(); + // $table->decimal('custom_surcharge2', 20, 6)->change(); + // $table->decimal('custom_surcharge3', 20, 6)->change(); + // $table->decimal('custom_surcharge4', 20, 6)->change(); + // }); - Schema::table('recurring_invoices', function (Blueprint $table) { - $table->decimal('custom_surcharge1', 20, 6)->change(); - $table->decimal('custom_surcharge2', 20, 6)->change(); - $table->decimal('custom_surcharge3', 20, 6)->change(); - $table->decimal('custom_surcharge4', 20, 6)->change(); - }); + // Schema::table('recurring_invoices', function (Blueprint $table) { + // $table->decimal('custom_surcharge1', 20, 6)->change(); + // $table->decimal('custom_surcharge2', 20, 6)->change(); + // $table->decimal('custom_surcharge3', 20, 6)->change(); + // $table->decimal('custom_surcharge4', 20, 6)->change(); + // }); - Schema::table('quotes', function (Blueprint $table) { - $table->decimal('custom_surcharge1', 20, 6)->change(); - $table->decimal('custom_surcharge2', 20, 6)->change(); - $table->decimal('custom_surcharge3', 20, 6)->change(); - $table->decimal('custom_surcharge4', 20, 6)->change(); - }); + // Schema::table('quotes', function (Blueprint $table) { + // $table->decimal('custom_surcharge1', 20, 6)->change(); + // $table->decimal('custom_surcharge2', 20, 6)->change(); + // $table->decimal('custom_surcharge3', 20, 6)->change(); + // $table->decimal('custom_surcharge4', 20, 6)->change(); + // }); - Schema::table('credits', function (Blueprint $table) { - $table->decimal('custom_surcharge1', 20, 6)->change(); - $table->decimal('custom_surcharge2', 20, 6)->change(); - $table->decimal('custom_surcharge3', 20, 6)->change(); - $table->decimal('custom_surcharge4', 20, 6)->change(); - }); + // Schema::table('credits', function (Blueprint $table) { + // $table->decimal('custom_surcharge1', 20, 6)->change(); + // $table->decimal('custom_surcharge2', 20, 6)->change(); + // $table->decimal('custom_surcharge3', 20, 6)->change(); + // $table->decimal('custom_surcharge4', 20, 6)->change(); + // }); } /** From 5e012aa52072a007f0f148339a5f3c35593aafe3 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 23 Jan 2023 08:25:43 +1100 Subject: [PATCH 03/16] Setup permissions for Bank Transactions --- app/Http/Controllers/BaseController.php | 4 ++-- app/Policies/BankTransactionPolicy.php | 2 +- tests/Unit/PermissionsTest.php | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php index 76e85b80ce6b..7eb00f722853 100644 --- a/app/Http/Controllers/BaseController.php +++ b/app/Http/Controllers/BaseController.php @@ -450,7 +450,7 @@ class BaseController extends Controller 'company.bank_transactions'=> function ($query) use ($updated_at, $user) { $query->where('updated_at', '>=', $updated_at); - if (! $user->isAdmin()) { + if (! $user->hasPermission('view_bank_transaction')) { $query->where('bank_transactions.user_id', $user->id); } }, @@ -796,7 +796,7 @@ class BaseController extends Controller 'company.bank_transactions'=> function ($query) use ($created_at, $user) { $query->where('created_at', '>=', $created_at); - if (! $user->isAdmin()) { + if (! $user->hasPermission('bank_transactions')) { $query->where('bank_transactions.user_id', $user->id); } }, diff --git a/app/Policies/BankTransactionPolicy.php b/app/Policies/BankTransactionPolicy.php index 00b57861aa6d..9819e0768bc6 100644 --- a/app/Policies/BankTransactionPolicy.php +++ b/app/Policies/BankTransactionPolicy.php @@ -26,6 +26,6 @@ class BankTransactionPolicy extends EntityPolicy */ public function create(User $user) : bool { - return $user->isAdmin(); + return $user->isAdmin() || $user->hasPermission('create_invoice') || $user->hasPermission('create_all'); } } diff --git a/tests/Unit/PermissionsTest.php b/tests/Unit/PermissionsTest.php index 91fa3e9854a0..71a64962a1ee 100644 --- a/tests/Unit/PermissionsTest.php +++ b/tests/Unit/PermissionsTest.php @@ -13,10 +13,12 @@ namespace Tests\Unit; use App\Factory\CompanyUserFactory; use App\Models\Account; +use App\Models\Client; use App\Models\Company; use App\Models\CompanyToken; use App\Models\CompanyUser; use App\Models\Invoice; +use App\Models\RecurringInvoice; use App\Models\User; use Illuminate\Foundation\Testing\DatabaseTransactions; use Tests\MockAccountData; @@ -77,6 +79,21 @@ class PermissionsTest extends TestCase } + public function testPermissionResolution() + { + $class = 'view'.lcfirst(class_basename(\Illuminate\Support\Str::snake(Invoice::class))); + + $this->assertEquals('view_invoice', $class); + + $class = 'view'.lcfirst(class_basename(\Illuminate\Support\Str::snake(Client::class))); + $this->assertEquals('view_client', $class); + + + $class = 'view'.lcfirst(class_basename(\Illuminate\Support\Str::snake(RecurringInvoice::class))); + $this->assertEquals('view_recurring_invoice', $class); + + } + public function testExactPermissions() { From 9ee5c2bace10e550d16a965c9db6dabf4f35fdf4 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 23 Jan 2023 08:29:39 +1100 Subject: [PATCH 04/16] Tests for permissions --- tests/Unit/PermissionsTest.php | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/tests/Unit/PermissionsTest.php b/tests/Unit/PermissionsTest.php index 71a64962a1ee..0b4de1d48844 100644 --- a/tests/Unit/PermissionsTest.php +++ b/tests/Unit/PermissionsTest.php @@ -88,10 +88,40 @@ class PermissionsTest extends TestCase $class = 'view'.lcfirst(class_basename(\Illuminate\Support\Str::snake(Client::class))); $this->assertEquals('view_client', $class); - $class = 'view'.lcfirst(class_basename(\Illuminate\Support\Str::snake(RecurringInvoice::class))); $this->assertEquals('view_recurring_invoice', $class); + $class = 'view'.lcfirst(class_basename(\Illuminate\Support\Str::snake(App\Models\Product::class))); + $this->assertEquals('view_product', $class); + + $class = 'view'.lcfirst(class_basename(\Illuminate\Support\Str::snake(App\Models\Payment::class))); + $this->assertEquals('view_payment', $class); + + $class = 'view'.lcfirst(class_basename(\Illuminate\Support\Str::snake(App\Models\Quote::class))); + $this->assertEquals('view_quote', $class); + + $class = 'view'.lcfirst(class_basename(\Illuminate\Support\Str::snake(App\Models\Credit::class))); + $this->assertEquals('view_credit', $class); + + $class = 'view'.lcfirst(class_basename(\Illuminate\Support\Str::snake(App\Models\Project::class))); + $this->assertEquals('view_project', $class); + + $class = 'view'.lcfirst(class_basename(\Illuminate\Support\Str::snake(App\Models\Task::class))); + $this->assertEquals('view_task', $class); + + $class = 'view'.lcfirst(class_basename(\Illuminate\Support\Str::snake(App\Models\Vendor::class))); + $this->assertEquals('view_vendor', $class); + + $class = 'view'.lcfirst(class_basename(\Illuminate\Support\Str::snake(App\Models\PurchaseOrder::class))); + $this->assertEquals('view_purchase_order', $class); + + $class = 'view'.lcfirst(class_basename(\Illuminate\Support\Str::snake(App\Models\Expense::class))); + $this->assertEquals('view_expense', $class); + + $class = 'view'.lcfirst(class_basename(\Illuminate\Support\Str::snake(App\Models\BankTransaction::class))); + $this->assertEquals('view_bank_transaction', $class); + + } public function testExactPermissions() From f217ea2441a9b4b375ad18d4a66044d7274d2ea5 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 23 Jan 2023 08:32:41 +1100 Subject: [PATCH 05/16] Tests for permissions --- tests/Unit/PermissionsTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/Unit/PermissionsTest.php b/tests/Unit/PermissionsTest.php index 0b4de1d48844..a4853bc965cb 100644 --- a/tests/Unit/PermissionsTest.php +++ b/tests/Unit/PermissionsTest.php @@ -121,6 +121,9 @@ class PermissionsTest extends TestCase $class = 'view'.lcfirst(class_basename(\Illuminate\Support\Str::snake(App\Models\BankTransaction::class))); $this->assertEquals('view_bank_transaction', $class); + $this->assertEquals('invoice', \Illuminate\Support\Str::snake(class_basename(Invoice::class))); + + $this->assertEquals('recurring_invoice', \Illuminate\Support\Str::snake(class_basename(RecurringInvoice::class))); } From e2ef82b26662f3c0de9d6be108e4dc64335ff73e Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 23 Jan 2023 09:31:40 +1100 Subject: [PATCH 06/16] Fixes for content-disposition in CORS --- app/Http/Controllers/BaseController.php | 2 +- config/cors.php | 2 +- resources/views/portal/ninja2020/layout/clean.blade.php | 9 +++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php index 7eb00f722853..73903e1a8373 100644 --- a/app/Http/Controllers/BaseController.php +++ b/app/Http/Controllers/BaseController.php @@ -861,7 +861,7 @@ class BaseController extends Controller /**/ // 10-01-2022 need to ensure we snake case properly here to ensure permissions work as expected // 28-03-2022 this is definitely correct here, do not append _ to the view, it resolved correctly when snake cased - if (auth()->user() && ! auth()->user()->hasPermission('view'.lcfirst(class_basename(Str::snake($this->entity_type))))) { + if (auth()->user() && ! auth()->user()->hasPermission('view_'.Str::snake(class_basename($this->entity_type)))) { //06-10-2022 - some entities do not have assigned_user_id - this becomes an issue when we have a large company and low permission users if(in_array($this->entity_type, [User::class])){ $query->where('id', auth()->user()->id); diff --git a/config/cors.php b/config/cors.php index d90557c1a441..fdb09ab1d89f 100644 --- a/config/cors.php +++ b/config/cors.php @@ -23,7 +23,7 @@ return [ 'allowed_origins_patterns' => [], - 'allowed_headers' => ['X-API-COMPANY-KEY,X-API-SECRET,X-API-TOKEN,X-API-PASSWORD,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,X-CSRF-TOKEN,X-XSRF-TOKEN,X-LIVEWIRE'], + 'allowed_headers' => ['X-API-COMPANY-KEY,X-API-SECRET,X-API-TOKEN,X-API-PASSWORD,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Disposition,Content-Type,Range,X-CSRF-TOKEN,X-XSRF-TOKEN,X-LIVEWIRE'], 'exposed_headers' => ['X-APP-VERSION,X-MINIMUM-CLIENT-VERSION,X-CSRF-TOKEN,X-XSRF-TOKEN,X-LIVEWIRE'], diff --git a/resources/views/portal/ninja2020/layout/clean.blade.php b/resources/views/portal/ninja2020/layout/clean.blade.php index 083045a7985a..17ee40e4947f 100644 --- a/resources/views/portal/ninja2020/layout/clean.blade.php +++ b/resources/views/portal/ninja2020/layout/clean.blade.php @@ -2,6 +2,15 @@ + @if(App\Utils\Ninja::isHosted()) + + + + @endif @if (isset($company) && $company->matomo_url && $company->matomo_id)