diff --git a/app/Console/Commands/CreateAccount.php b/app/Console/Commands/CreateAccount.php new file mode 100644 index 000000000000..053b7661400b --- /dev/null +++ b/app/Console/Commands/CreateAccount.php @@ -0,0 +1,163 @@ +info(date('r').' Create Single Account...'); + + $this->warmCache(); + + $this->createAccount(); + + } + + private function createAccount() + { + + $account = Account::factory()->create(); + $company = Company::factory()->create([ + 'account_id' => $account->id, + ]); + + $account->default_company_id = $company->id; + $account->save(); + + $email = $this->option('email') ?? 'admin@example.com'; + $password = $this->option('password') ?? 'changeme!'; + + $user = User::factory()->create([ + 'account_id' => $account->id, + 'email' => $email, + 'password' => Hash::make($password), + 'confirmation_code' => $this->createDbHash(config('database.default')), + 'email_verified_at' => now(), + ]); + + $company_token = new CompanyToken; + $company_token->user_id = $user->id; + $company_token->company_id = $company->id; + $company_token->account_id = $account->id; + $company_token->name = 'User Token'; + $company_token->token = Str::random(64); + $company_token->is_system = true; + + $company_token->save(); + + $user->companies()->attach($company->id, [ + 'account_id' => $account->id, + 'is_owner' => 1, + 'is_admin' => 1, + 'is_locked' => 0, + 'notifications' => CompanySettings::notificationDefaults(), + 'settings' => null, + ]); + + CreateCompanyPaymentTerms::dispatchNow($company, $user); + CreateCompanyTaskStatuses::dispatchNow($company, $user); + VersionCheck::dispatchNow(); + + } + + private function warmCache() + { + /* Warm up the cache !*/ + $cached_tables = config('ninja.cached_tables'); + + foreach ($cached_tables as $name => $class) { + if (! Cache::has($name)) { + // check that the table exists in case the migration is pending + if (! Schema::hasTable((new $class())->getTable())) { + continue; + } + if ($name == 'payment_terms') { + $orderBy = 'num_days'; + } elseif ($name == 'fonts') { + $orderBy = 'sort_order'; + } elseif (in_array($name, ['currencies', 'industries', 'languages', 'countries', 'banks'])) { + $orderBy = 'name'; + } else { + $orderBy = 'id'; + } + $tableData = $class::orderBy($orderBy)->get(); + if ($tableData->count()) { + Cache::forever($name, $tableData); + } + } + } + } + +} diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 5a00afa0ce4b..ff320634ea20 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -623,8 +623,8 @@ class UserController extends BaseController * Detach an existing user to a company. * * @OA\Post( - * path="/api/v1/users/{user}/reconfirm", - * operationId="reconfirmUser", + * path="/api/v1/users/{user}/invite", + * operationId="inviteUser", * tags={"users"}, * summary="Reconfirm an existing user to a company", * description="Reconfirm an existing user from a company", @@ -666,18 +666,10 @@ class UserController extends BaseController * @param User $user * @return \Illuminate\Http\JsonResponse */ - public function reconfirm(ReconfirmUserRequest $request, User $user) + public function invite(ReconfirmUserRequest $request, User $user) { - $user->confirmation_code = $this->createDbHash($user->company()->db); - $user->save(); - $nmo = new NinjaMailerObject; - $nmo->mailable = new NinjaMailer((new VerifyUserObject($user, $user->company()))->build()); - $nmo->company = $user->company(); - $nmo->to_user = $user; - $nmo->settings = $user->company->settings; - - NinjaMailerJob::dispatch($nmo); + $user->service()->invite($user->company()); return response()->json(['message' => ctrans('texts.confirmation_resent')], 200); diff --git a/app/Http/Middleware/PasswordProtection.php b/app/Http/Middleware/PasswordProtection.php index 1df11b733400..20535de73d7b 100644 --- a/app/Http/Middleware/PasswordProtection.php +++ b/app/Http/Middleware/PasswordProtection.php @@ -36,7 +36,7 @@ class PasswordProtection 'errors' => new stdClass, ]; - if($request->header('X-API-OAUTH-PASSWORD')){ + if( $request->header('X-API-OAUTH-PASSWORD') && strlen($request->header('X-API-OAUTH-PASSWORD')) >=1 ){ //user is attempting to reauth with OAuth - check the token value //todo expand this to include all OAuth providers @@ -53,7 +53,7 @@ class PasswordProtection /* Cannot allow duplicates! */ if ($existing_user = MultiDB::hasUser($query)) { - Cache::add(auth()->user()->email.'_logged_in', Str::random(64), now()->addMinutes(30)); + Cache::add(auth()->user()->hashed_id.'_logged_in', Str::random(64), now()->addMinutes(30)); return $next($request); } } @@ -74,10 +74,10 @@ class PasswordProtection return response()->json($error, 403); } - } elseif (Cache::get(auth()->user()->email.'_logged_in')) { + } elseif (Cache::get(auth()->user()->hashed_id.'_logged_in')) { - Cache::pull(auth()->user()->email.'_logged_in'); - Cache::add(auth()->user()->email.'_logged_in', Str::random(64), now()->addMinutes(30)); + Cache::pull(auth()->user()->hashed_id.'_logged_in'); + Cache::add(auth()->user()->hashed_id.'_logged_in', Str::random(64), now()->addMinutes(30)); return $next($request); diff --git a/app/Listeners/SendVerificationNotification.php b/app/Listeners/SendVerificationNotification.php index 1c396454dd1c..a8d4836bbfcf 100644 --- a/app/Listeners/SendVerificationNotification.php +++ b/app/Listeners/SendVerificationNotification.php @@ -46,24 +46,10 @@ class SendVerificationNotification implements ShouldQueue */ public function handle($event) { + MultiDB::setDB($event->company->db); - try { + $event->user->service()->invite($event->company); - $nmo = new NinjaMailerObject; - $nmo->mailable = new NinjaMailer((new VerifyUserObject($event->user, $event->company))->build()); - $nmo->company = $event->company; - $nmo->to_user = $event->user; - $nmo->settings = $event->company->settings; - - NinjaMailerJob::dispatch($nmo); - - // $event->user->notify(new VerifyUser($event->user, $event->company)); - - Ninja::registerNinjaUser($event->user); - - } catch (Exception $e) { - nlog("I couldn't send the email " . $e->getMessage()); - } } } diff --git a/app/Models/User.php b/app/Models/User.php index 52582d0a95ee..f9fb94e5b59f 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -17,6 +17,7 @@ use App\Jobs\Mail\NinjaMailerObject; use App\Mail\Admin\ResetPasswordObject; use App\Models\Presenters\UserPresenter; use App\Notifications\ResetPasswordNotification; +use App\Services\User\UserService; use App\Utils\Traits\MakesHash; use App\Utils\Traits\UserSessionAttributes; use App\Utils\Traits\UserSettings; @@ -398,4 +399,9 @@ class User extends Authenticatable implements MustVerifyEmail //$this->notify(new ResetPasswordNotification($token)); } + + public function service() + { + return new UserService($this); + } } diff --git a/app/Services/User/UserService.php b/app/Services/User/UserService.php new file mode 100644 index 000000000000..a085574ff18f --- /dev/null +++ b/app/Services/User/UserService.php @@ -0,0 +1,52 @@ +user = $user; + } + + public function invite($company) + { + try { + + $nmo = new NinjaMailerObject; + $nmo->mailable = new NinjaMailer((new VerifyUserObject($this->user, $company))->build()); + $nmo->company = $company; + $nmo->to_user = $this->user; + $nmo->settings = $company->settings; + + NinjaMailerJob::dispatch($nmo); + + Ninja::registerNinjaUser($this->user); + + } catch (\Exception $e) { + nlog("I couldn't send the verification email " . $e->getMessage()); + } + + return $this->user; + } +} diff --git a/app/Transformers/UserTransformer.php b/app/Transformers/UserTransformer.php index bd3632ab69b7..6c550feff39a 100644 --- a/app/Transformers/UserTransformer.php +++ b/app/Transformers/UserTransformer.php @@ -60,6 +60,7 @@ class UserTransformer extends EntityTransformer 'oauth_provider_id' => (string) $user->oauth_provider_id, 'last_confirmed_email_address' => (string) $user->last_confirmed_email_address ?: '', 'google_2fa_secret' => (bool) $user->google_2fa_secret, + 'has_password' => (bool) $user->has_password, ]; } diff --git a/database/migrations/2021_03_03_230941_add_has_password_field_to_user_table.php b/database/migrations/2021_03_03_230941_add_has_password_field_to_user_table.php new file mode 100644 index 000000000000..92f3821c8d6a --- /dev/null +++ b/database/migrations/2021_03_03_230941_add_has_password_field_to_user_table.php @@ -0,0 +1,30 @@ +boolean('has_password')->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + } +} diff --git a/routes/api.php b/routes/api.php index 244683169dfa..45d6d5683b4e 100644 --- a/routes/api.php +++ b/routes/api.php @@ -164,7 +164,7 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a Route::delete('users/{user}/detach_from_company', 'UserController@detach')->middleware('password_protected'); Route::post('users/bulk', 'UserController@bulk')->name('users.bulk')->middleware('password_protected'); - Route::post('/user/{user}/reconfirm', 'UserController@reconfirm')->middleware('password_protected'); + Route::post('/users/{user}/invite', 'UserController@invite')->middleware('password_protected'); Route::resource('webhooks', 'WebhookController'); Route::post('webhooks/bulk', 'WebhookController@bulk')->name('webhooks.bulk');