diff --git a/.env.example b/.env.example index b384930432cc..9f8319b00738 100644 --- a/.env.example +++ b/.env.example @@ -55,5 +55,7 @@ PHANTOMJS_PDF_GENERATION=true PHANTOMJS_KEY='a-demo-key-with-low-quota-per-ip-address' PHANTOMJS_SECRET=secret +UPDATE_SECRET= + COMPOSER_AUTH='{"github-oauth": {"github.com": "${{ secrets.GITHUB_TOKEN }}"}}' SENTRY_LARAVEL_DSN=https://cc7e8e2c678041689e53e409b7dba236@sentry.invoicing.co/5 \ No newline at end of file diff --git a/app/Http/Controllers/SetupController.php b/app/Http/Controllers/SetupController.php index 9d975aaebc17..b1e2a1b41838 100644 --- a/app/Http/Controllers/SetupController.php +++ b/app/Http/Controllers/SetupController.php @@ -12,7 +12,6 @@ namespace App\Http\Controllers; -use \Illuminate\Support\Facades\DB; use App\Http\Requests\Setup\CheckDatabaseRequest; use App\Http\Requests\Setup\CheckMailRequest; use App\Http\Requests\Setup\StoreSetupRequest; @@ -20,6 +19,7 @@ use App\Jobs\Account\CreateAccount; use App\Jobs\Util\VersionCheck; use App\Models\Account; use App\Utils\CurlUtils; +use App\Utils\Ninja; use App\Utils\SystemHealth; use App\Utils\Traits\AppSetup; use Beganovich\Snappdf\Snappdf; @@ -29,10 +29,12 @@ use Illuminate\Contracts\Routing\ResponseFactory; use Illuminate\Http\JsonResponse; use Illuminate\Http\Response; use Illuminate\Support\Facades\Artisan; +use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\Request; use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Storage; -use Illuminate\Support\Facades\File; +use \Illuminate\Support\Facades\DB; /** * Class SetupController. @@ -267,4 +269,29 @@ class SetupController extends Controller return response([], 500); } } + + public function update() + { + + if( Ninja::isNinja() || !request()->has('secret') || (request()->input('secret') != config('ninja.update_secret')) ) + return redirect('/'); + + $cacheCompiled = base_path('bootstrap/cache/compiled.php'); + if (file_exists($cacheCompiled)) { unlink ($cacheCompiled); } + $cacheServices = base_path('bootstrap/cache/services.php'); + if (file_exists($cacheServices)) { unlink ($cacheServices); } + + Artisan::call('clear-compiled'); + Artisan::call('cache:clear'); + Artisan::call('debugbar:clear'); + Artisan::call('route:clear'); + Artisan::call('view:clear'); + Artisan::call('config:clear'); + Cache::flush(); + Artisan::call('migrate', ['--force' => true]); + Artisan::call('db:seed', ['--force' => true]); + + return redirect('/?clear_cache=true'); + + } } diff --git a/app/Http/Controllers/Traits/VerifiesUserEmail.php b/app/Http/Controllers/Traits/VerifiesUserEmail.php index c9309f2780c6..74232e3fc722 100644 --- a/app/Http/Controllers/Traits/VerifiesUserEmail.php +++ b/app/Http/Controllers/Traits/VerifiesUserEmail.php @@ -13,6 +13,7 @@ namespace App\Http\Controllers\Traits; use App\Models\User; +use App\Utils\Traits\MakesHash; use App\Utils\Traits\UserSessionAttributes; use Illuminate\Http\RedirectResponse; use Illuminate\Support\Facades\Hash; @@ -23,6 +24,7 @@ use Illuminate\Support\Facades\Hash; trait VerifiesUserEmail { use UserSessionAttributes; + use MakesHash; /** * @return RedirectResponse @@ -37,14 +39,14 @@ trait VerifiesUserEmail return $this->render('auth.confirmed', ['root' => 'themes', 'message' => ctrans('texts.wrong_confirmation')]); } - if (is_null($user->password) || empty($user->password)) { - return $this->render('auth.confirmation_with_password', ['root' => 'themes']); - } - $user->email_verified_at = now(); $user->confirmation_code = null; $user->save(); + if (is_null($user->password) || empty($user->password) || Hash::check('', $user->password)) { + return $this->render('auth.confirmation_with_password', ['root' => 'themes', 'user_id' => $user->hashed_id]); + } + return $this->render('auth.confirmed', [ 'root' => 'themes', 'message' => ctrans('texts.security_confirmation'), @@ -53,16 +55,13 @@ trait VerifiesUserEmail public function confirmWithPassword() { - $user = User::where('confirmation_code', request()->confirmation_code)->first(); - - if (! $user) { - return $this->render('auth.confirmed', ['root' => 'themes', 'message' => ctrans('texts.wrong_confirmation')]); - } + $user = User::where('id', $this->decodePrimaryKey(request()->user_id))->firstOrFail(); request()->validate([ - 'password' => ['required', 'min:6', 'confirmed'], + 'password' => ['required', 'min:6'], ]); + $user->password = Hash::make(request()->password); $user->email_verified_at = now(); diff --git a/app/Services/Subscription/SubscriptionService.php b/app/Services/Subscription/SubscriptionService.php index 4178cbfba3f3..dfcb3a9b3014 100644 --- a/app/Services/Subscription/SubscriptionService.php +++ b/app/Services/Subscription/SubscriptionService.php @@ -127,7 +127,7 @@ class SubscriptionService ]; $response = $this->triggerWebhook($context); - + nlog($response); return $response; } @@ -269,11 +269,23 @@ class SubscriptionService //scan for any notification we are required to send } + /** + * Get the single charge products for the + * subscription + * + * @return ?Product Collection + */ public function products() { return Product::whereIn('id', $this->transformKeys(explode(",", $this->subscription->product_ids)))->get(); } + /** + * Get the recurring products for the + * subscription + * + * @return ?Product Collection + */ public function recurring_products() { return Product::whereIn('id', $this->transformKeys(explode(",", $this->subscription->recurring_product_ids)))->get(); diff --git a/config/ninja.php b/config/ninja.php index 95f8a0df3753..f3702aad3497 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -38,7 +38,7 @@ return [ 'sentry_dsn' => env('SENTRY_LARAVEL_DSN', 'https://9b4e15e575214354a7d666489783904a@sentry.invoicing.co/6'), 'environment' => env('NINJA_ENVIRONMENT', 'selfhost'), // 'hosted', 'development', 'selfhost', 'reseller' 'preconfigured_install' => env('PRECONFIGURED_INSTALL',false), - + 'update_secret' => env('UPDATE_SECRET', false), // Settings used by invoiceninja.com 'terms_of_service_url' => [ 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 f43a1a0a9ede..c14b37cde2cd 100644 --- a/database/migrations/2014_10_13_000000_create_users_table.php +++ b/database/migrations/2014_10_13_000000_create_users_table.php @@ -623,7 +623,7 @@ class CreateUsersTable extends Migration $t->unsignedInteger('vendor_id')->nullable(); $t->unsignedInteger('status_id')->index(); - $t->text('number')->nullable(); + $t->string('number')->nullable(); $t->float('discount')->default(0); $t->boolean('is_amount_discount')->default(false); @@ -672,6 +672,7 @@ class CreateUsersTable extends Migration $t->softDeletes('deleted_at', 6); $t->index(['company_id', 'deleted_at']); + $t->unique(['company_id', 'number']); $t->foreign('client_id')->references('id')->on('clients')->onDelete('cascade')->onUpdate('cascade'); $t->foreign('company_id')->references('id')->on('companies')->onDelete('cascade')->onUpdate('cascade'); $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade'); @@ -960,7 +961,7 @@ class CreateUsersTable extends Migration $t->unsignedInteger('exchange_currency_id'); $t->index(['company_id', 'deleted_at']); - + $t->unique(['company_id', 'number']); $t->foreign('company_id')->references('id')->on('companies')->onDelete('cascade')->onUpdate('cascade'); $t->foreign('client_id')->references('id')->on('clients')->onDelete('cascade')->onUpdate('cascade'); $t->foreign('client_contact_id')->references('id')->on('client_contacts')->onDelete('cascade')->onUpdate('cascade'); diff --git a/database/migrations/2020_09_22_205113_id_number_fields_for_missing_entities.php b/database/migrations/2020_09_22_205113_id_number_fields_for_missing_entities.php index 231d12c97953..302ecba4b8b7 100644 --- a/database/migrations/2020_09_22_205113_id_number_fields_for_missing_entities.php +++ b/database/migrations/2020_09_22_205113_id_number_fields_for_missing_entities.php @@ -25,15 +25,18 @@ class IdNumberFieldsForMissingEntities extends Migration { Schema::table('expenses', function (Blueprint $table) { $table->string('number')->nullable(); + $table->unique(['company_id', 'number']); }); Schema::table('tasks', function (Blueprint $table) { $table->string('number')->nullable(); + $table->unique(['company_id', 'number']); }); Schema::table('vendors', function (Blueprint $table) { $table->text('vendor_hash')->nullable(); $table->text('public_notes')->nullable(); + $table->unique(['company_id', 'number']); }); Schema::table('vendor_contacts', function (Blueprint $table) { diff --git a/database/migrations/2020_10_12_204517_project_number_column.php b/database/migrations/2020_10_12_204517_project_number_column.php index 4ccb631fd987..8ec1672df99e 100644 --- a/database/migrations/2020_10_12_204517_project_number_column.php +++ b/database/migrations/2020_10_12_204517_project_number_column.php @@ -24,6 +24,7 @@ class ProjectNumberColumn extends Migration { Schema::table('projects', function ($table) { $table->string('number')->nullable(); + $table->unique(['company_id', 'number']); }); Schema::table('expenses', function ($t) { diff --git a/database/migrations/2021_01_25_095351_add_number_field_to_clients_and_vendors.php b/database/migrations/2021_01_25_095351_add_number_field_to_clients_and_vendors.php index e79c33a405c6..3a95f1cd3291 100644 --- a/database/migrations/2021_01_25_095351_add_number_field_to_clients_and_vendors.php +++ b/database/migrations/2021_01_25_095351_add_number_field_to_clients_and_vendors.php @@ -23,10 +23,13 @@ class AddNumberFieldToClientsAndVendors extends Migration Schema::table('clients', function (Blueprint $table) { $table->string('id_number')->nullable(); + $table->unique(['company_id', 'number']); }); Schema::table('vendors', function (Blueprint $table) { $table->string('id_number')->nullable(); + $table->unique(['company_id', 'number']); + }); } diff --git a/database/migrations/2021_03_19_221024_add_unique_constraints_on_all_entities.php b/database/migrations/2021_03_19_221024_add_unique_constraints_on_all_entities.php index 8f68e23e89df..8ccbb6532086 100644 --- a/database/migrations/2021_03_19_221024_add_unique_constraints_on_all_entities.php +++ b/database/migrations/2021_03_19_221024_add_unique_constraints_on_all_entities.php @@ -13,38 +13,7 @@ class AddUniqueConstraintsOnAllEntities extends Migration */ public function up() { - Schema::table('expenses', function (Blueprint $table) { - $table->unique(['company_id', 'number']); - }); - Schema::table('tasks', function (Blueprint $table) { - $table->unique(['company_id', 'number']); - }); - - Schema::table('vendors', function (Blueprint $table) { - $table->unique(['company_id', 'number']); - }); - - Schema::table('payments', function (Blueprint $table) { - $table->unique(['company_id', 'number']); - }); - - Schema::table('projects', function (Blueprint $table) { - $table->unique(['company_id', 'number']); - }); - - Schema::table('clients', function (Blueprint $table) { - $table->unique(['company_id', 'number']); - }); - - Schema::table('recurring_invoices', function (Blueprint $table) { - $table->string('number')->change(); - $table->unique(['company_id', 'number']); - }); - - Schema::table('recurring_invoice_invitations', function (Blueprint $table) { - $table->unique(['client_contact_id', 'recurring_invoice_id'],'recur_invoice_client_unique'); - }); } diff --git a/resources/views/themes/ninja2020/auth/confirmation_with_password.blade.php b/resources/views/themes/ninja2020/auth/confirmation_with_password.blade.php index 5ff7dfc7c39d..ee02e834ee61 100644 --- a/resources/views/themes/ninja2020/auth/confirmation_with_password.blade.php +++ b/resources/views/themes/ninja2020/auth/confirmation_with_password.blade.php @@ -11,6 +11,7 @@
@csrf +
middleware('guest'); Route::get('setup', 'SetupController@index')->middleware('guest'); Route::post('setup', 'SetupController@doSetup')->middleware('guest'); +Route::get('update', 'SetupController@update')->middleware('guest'); Route::post('setup/check_db', 'SetupController@checkDB')->middleware('guest'); Route::post('setup/check_mail', 'SetupController@checkMail')->middleware('guest');