diff --git a/VERSION.txt b/VERSION.txt index e92da973fed6..02cc04aa1bc4 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.5.60 \ No newline at end of file +5.5.61 \ No newline at end of file diff --git a/app/Console/Commands/CheckData.php b/app/Console/Commands/CheckData.php index 7ffba27472b4..1b3857ff72a9 100644 --- a/app/Console/Commands/CheckData.php +++ b/app/Console/Commands/CheckData.php @@ -448,13 +448,24 @@ class CheckData extends Command //check contact exists! if($contact_class::where('company_id', $entity->company_id)->where($client_vendor_key,$entity->{$client_vendor_key})->exists()) { - $invitation = new $entity_obj(); - $invitation->company_id = $entity->company_id; - $invitation->user_id = $entity->user_id; - $invitation->{$entity_key} = $entity->id; - $invitation->{$contact_id} = $contact_class::where('company_id', $entity->company_id)->where($client_vendor_key,$entity->{$client_vendor_key})->first()->id; - $invitation->key = Str::random(config('ninja.key_length')); - $this->logMessage("Add invitation for {$entity_key} - {$entity->id}"); + + $contact = $contact_class::where('company_id', $entity->company_id)->where($client_vendor_key,$entity->{$client_vendor_key})->first(); + + //double check if an archived invite exists + if($contact && $entity->invitations()->withTrashed()->where($contact_id, $contact->id)->count() != 0) { + $i = $entity->invitations()->withTrashed()->where($contact_id, $contact->id)->first(); + $i->restore(); + $this->logMessage("Found a valid contact and invitation restoring for {$entity_key} - {$entity->id}"); + } + else { + $invitation = new $entity_obj(); + $invitation->company_id = $entity->company_id; + $invitation->user_id = $entity->user_id; + $invitation->{$entity_key} = $entity->id; + $invitation->{$contact_id} = $contact->id; + $invitation->key = Str::random(config('ninja.key_length')); + $this->logMessage("Add invitation for {$entity_key} - {$entity->id}"); + } } else $this->logMessage("No contact present, so cannot add invitation for {$entity_key} - {$entity->id}"); diff --git a/app/Http/Controllers/ActivityController.php b/app/Http/Controllers/ActivityController.php index 12ce6c4f50c6..fea2a3d4e695 100644 --- a/app/Http/Controllers/ActivityController.php +++ b/app/Http/Controllers/ActivityController.php @@ -87,13 +87,15 @@ class ActivityController extends BaseController { $default_activities = $request->has('rows') ? $request->input('rows') : 50; - $activities = Activity::orderBy('created_at', 'DESC')->company() + $activities = Activity::orderBy('created_at', 'DESC') + ->company() ->take($default_activities); if ($request->has('react')) { if(!auth()->user()->isAdmin()) - return response()->json(['data' => []], 200); + $activities->where('user_id', auth()->user()->id); + // return response()->json(['data' => []], 200); $system = ctrans('texts.system'); diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php index 76e85b80ce6b..73903e1a8373 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); } }, @@ -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/app/Http/Middleware/Cors.php b/app/Http/Middleware/Cors.php index d0346e48277c..f5cb51145651 100644 --- a/app/Http/Middleware/Cors.php +++ b/app/Http/Middleware/Cors.php @@ -16,7 +16,7 @@ class Cors // ALLOW OPTIONS METHOD $headers = [ 'Access-Control-Allow-Methods'=> 'POST, GET, OPTIONS, PUT, DELETE', - 'Access-Control-Allow-Headers'=> 'X-API-PASSWORD-BASE64,X-API-COMPANY-KEY,X-CLIENT-VERSION,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', + 'Access-Control-Allow-Headers'=> 'X-API-PASSWORD-BASE64,X-API-COMPANY-KEY,X-CLIENT-VERSION,X-API-SECRET,X-API-TOKEN,X-API-PASSWORD,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Disposition,Range,X-CSRF-TOKEN,X-XSRF-TOKEN,X-LIVEWIRE', ]; return Response::make('OK', 200, $headers); @@ -26,8 +26,8 @@ class Cors $response->headers->set('Access-Control-Allow-Origin', '*'); $response->headers->set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); - $response->headers->set('Access-Control-Allow-Headers', 'X-API-PASSWORD-BASE64,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'); - $response->headers->set('Access-Control-Expose-Headers', 'X-APP-VERSION,X-MINIMUM-CLIENT-VERSION'); + $response->headers->set('Access-Control-Allow-Headers', 'X-API-PASSWORD-BASE64,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,Content-Disposition,Range,X-CSRF-TOKEN,X-XSRF-TOKEN,X-LIVEWIRE'); + $response->headers->set('Access-Control-Expose-Headers', 'X-APP-VERSION,X-MINIMUM-CLIENT-VERSION,Content-Disposition'); $response->headers->set('X-APP-VERSION', config('ninja.app_version')); $response->headers->set('X-MINIMUM-CLIENT-VERSION', config('ninja.minimum_client_version')); 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); diff --git a/app/Models/BaseModel.php b/app/Models/BaseModel.php index 0573f1864890..d95e051757c2 100644 --- a/app/Models/BaseModel.php +++ b/app/Models/BaseModel.php @@ -174,7 +174,7 @@ class BaseModel extends Model return $this ->withTrashed() - ->company() + // ->company() ->where('id', $this->decodePrimaryKey($value))->firstOrFail(); } diff --git a/app/Models/ClientContact.php b/app/Models/ClientContact.php index 887607bd1400..264e303403fb 100644 --- a/app/Models/ClientContact.php +++ b/app/Models/ClientContact.php @@ -240,7 +240,7 @@ class ClientContact extends Authenticatable implements HasLocalePreference { return $this ->withTrashed() - ->company() + // ->company() ->where('id', $this->decodePrimaryKey($value))->firstOrFail(); } diff --git a/app/Models/User.php b/app/Models/User.php index 63e94b633b67..28529ad75922 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -358,18 +358,21 @@ class User extends Authenticatable implements MustVerifyEmail public function hasPermission($permission) : bool { $parts = explode('_', $permission); - $all_permission = ''; + $all_permission = false; if (count($parts) > 1) { $all_permission = $parts[0].'_all'; } -//empty $all_permissions leads to stripos returning true; - return $this->isOwner() || $this->isAdmin() || - (is_int(stripos($this->token()->cu->permissions, $all_permission))) || - (is_int(stripos($this->token()->cu->permissions, $permission))); + (stripos($all_permission, $this->token()->cu->permissions) !== false) || + (stripos($permission, $this->token()->cu->permissions) !== false); + + // return $this->isOwner() || + // $this->isAdmin() || + // (is_int(stripos($this->token()->cu->permissions, $all_permission))) || + // (is_int(stripos($this->token()->cu->permissions, $permission))); } 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/app/Policies/EntityPolicy.php b/app/Policies/EntityPolicy.php index 99ca027916e3..ac5155c7c97c 100644 --- a/app/Policies/EntityPolicy.php +++ b/app/Policies/EntityPolicy.php @@ -47,7 +47,7 @@ class EntityPolicy public function edit(User $user, $entity) : bool { return ($user->isAdmin() && $entity->company_id == $user->companyId()) - || ($user->hasPermission('edit_'.strtolower(\Illuminate\Support\Str::snake(class_basename($entity)))) && $entity->company_id == $user->companyId()) + || ($user->hasPermission('edit_'.\Illuminate\Support\Str::snake(class_basename($entity))) && $entity->company_id == $user->companyId()) || ($user->hasPermission('edit_all') && $entity->company_id == $user->companyId()) || ($user->owns($entity) && $entity->company_id == $user->companyId()) || ($user->assigned($entity) && $entity->company_id == $user->companyId()); @@ -64,7 +64,7 @@ class EntityPolicy public function view(User $user, $entity) : bool { return ($user->isAdmin() && $entity->company_id == $user->companyId()) - || ($user->hasPermission('view_'.strtolower(\Illuminate\Support\Str::snake(class_basename($entity)))) && $entity->company_id == $user->companyId()) + || ($user->hasPermission('view_'.\Illuminate\Support\Str::snake(class_basename($entity))) && $entity->company_id == $user->companyId()) || ($user->hasPermission('view_all') && $entity->company_id == $user->companyId()) || ($user->owns($entity) && $entity->company_id == $user->companyId()) || ($user->assigned($entity) && $entity->company_id == $user->companyId()); diff --git a/app/Services/Subscription/SubscriptionService.php b/app/Services/Subscription/SubscriptionService.php index 3c59d33fdfbc..cb9e0e5a38fc 100644 --- a/app/Services/Subscription/SubscriptionService.php +++ b/app/Services/Subscription/SubscriptionService.php @@ -98,7 +98,7 @@ class SubscriptionService ->save(); //update the invoice and attach to the recurring invoice!!!!! - $invoice = Invoice::find($payment_hash->fee_invoice_id); + $invoice = Invoice::withTrashed()->find($payment_hash->fee_invoice_id); $invoice->recurring_id = $recurring_invoice->id; $invoice->is_proforma = false; $invoice->save(); 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/config/ninja.php b/config/ninja.php index ea66940ea2d4..d6f71c5cb730 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -14,8 +14,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => '5.5.60', - 'app_tag' => '5.5.60', + 'app_version' => '5.5.61', + 'app_tag' => '5.5.61', 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', ''), 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(); + // }); } /** 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)