mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge pull request #5022 from turbo124/v5-develop
Fixes for user management
This commit is contained in:
commit
609cb1ee8d
163
app/Console/Commands/CreateAccount.php
Normal file
163
app/Console/Commands/CreateAccount.php
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\DataMapper\CompanySettings;
|
||||||
|
use App\DataMapper\FeesAndLimits;
|
||||||
|
use App\Events\Invoice\InvoiceWasCreated;
|
||||||
|
use App\Factory\InvoiceFactory;
|
||||||
|
use App\Factory\InvoiceItemFactory;
|
||||||
|
use App\Helpers\Invoice\InvoiceSum;
|
||||||
|
use App\Jobs\Company\CreateCompanyPaymentTerms;
|
||||||
|
use App\Jobs\Company\CreateCompanyTaskStatuses;
|
||||||
|
use App\Jobs\Util\VersionCheck;
|
||||||
|
use App\Models\Account;
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\ClientContact;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\CompanyGateway;
|
||||||
|
use App\Models\CompanyToken;
|
||||||
|
use App\Models\Country;
|
||||||
|
use App\Models\Credit;
|
||||||
|
use App\Models\Expense;
|
||||||
|
use App\Models\Product;
|
||||||
|
use App\Models\Project;
|
||||||
|
use App\Models\Quote;
|
||||||
|
use App\Models\Task;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\Vendor;
|
||||||
|
use App\Models\VendorContact;
|
||||||
|
use App\Repositories\InvoiceRepository;
|
||||||
|
use App\Utils\Ninja;
|
||||||
|
use App\Utils\Traits\GeneratesCounter;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Faker\Factory;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class CreateAccount extends Command
|
||||||
|
{
|
||||||
|
use MakesHash, GeneratesCounter;
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Create Single Account';
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'ninja:create-account {--email=} {--password=}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new command instance.
|
||||||
|
*
|
||||||
|
* @param InvoiceRepository $invoice_repo
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$this->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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -623,8 +623,8 @@ class UserController extends BaseController
|
|||||||
* Detach an existing user to a company.
|
* Detach an existing user to a company.
|
||||||
*
|
*
|
||||||
* @OA\Post(
|
* @OA\Post(
|
||||||
* path="/api/v1/users/{user}/reconfirm",
|
* path="/api/v1/users/{user}/invite",
|
||||||
* operationId="reconfirmUser",
|
* operationId="inviteUser",
|
||||||
* tags={"users"},
|
* tags={"users"},
|
||||||
* summary="Reconfirm an existing user to a company",
|
* summary="Reconfirm an existing user to a company",
|
||||||
* description="Reconfirm an existing user from a company",
|
* description="Reconfirm an existing user from a company",
|
||||||
@ -666,18 +666,10 @@ class UserController extends BaseController
|
|||||||
* @param User $user
|
* @param User $user
|
||||||
* @return \Illuminate\Http\JsonResponse
|
* @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;
|
$user->service()->invite($user->company());
|
||||||
$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);
|
|
||||||
|
|
||||||
return response()->json(['message' => ctrans('texts.confirmation_resent')], 200);
|
return response()->json(['message' => ctrans('texts.confirmation_resent')], 200);
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ class PasswordProtection
|
|||||||
'errors' => new stdClass,
|
'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
|
//user is attempting to reauth with OAuth - check the token value
|
||||||
//todo expand this to include all OAuth providers
|
//todo expand this to include all OAuth providers
|
||||||
@ -53,7 +53,7 @@ class PasswordProtection
|
|||||||
|
|
||||||
/* Cannot allow duplicates! */
|
/* Cannot allow duplicates! */
|
||||||
if ($existing_user = MultiDB::hasUser($query)) {
|
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);
|
return $next($request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,10 +74,10 @@ class PasswordProtection
|
|||||||
return response()->json($error, 403);
|
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::pull(auth()->user()->hashed_id.'_logged_in');
|
||||||
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);
|
return $next($request);
|
||||||
|
|
||||||
|
@ -46,24 +46,10 @@ class SendVerificationNotification implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle($event)
|
public function handle($event)
|
||||||
{
|
{
|
||||||
|
|
||||||
MultiDB::setDB($event->company->db);
|
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ use App\Jobs\Mail\NinjaMailerObject;
|
|||||||
use App\Mail\Admin\ResetPasswordObject;
|
use App\Mail\Admin\ResetPasswordObject;
|
||||||
use App\Models\Presenters\UserPresenter;
|
use App\Models\Presenters\UserPresenter;
|
||||||
use App\Notifications\ResetPasswordNotification;
|
use App\Notifications\ResetPasswordNotification;
|
||||||
|
use App\Services\User\UserService;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use App\Utils\Traits\UserSessionAttributes;
|
use App\Utils\Traits\UserSessionAttributes;
|
||||||
use App\Utils\Traits\UserSettings;
|
use App\Utils\Traits\UserSettings;
|
||||||
@ -398,4 +399,9 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||||||
|
|
||||||
//$this->notify(new ResetPasswordNotification($token));
|
//$this->notify(new ResetPasswordNotification($token));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function service()
|
||||||
|
{
|
||||||
|
return new UserService($this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
52
app/Services/User/UserService.php
Normal file
52
app/Services/User/UserService.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Services\User;
|
||||||
|
|
||||||
|
use App\Jobs\Mail\NinjaMailer;
|
||||||
|
use App\Jobs\Mail\NinjaMailerJob;
|
||||||
|
use App\Jobs\Mail\NinjaMailerObject;
|
||||||
|
use App\Mail\Admin\VerifyUserObject;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Utils\Ninja;
|
||||||
|
|
||||||
|
class UserService
|
||||||
|
{
|
||||||
|
|
||||||
|
public $user;
|
||||||
|
|
||||||
|
public function __construct(User $user)
|
||||||
|
{
|
||||||
|
$this->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;
|
||||||
|
}
|
||||||
|
}
|
@ -60,6 +60,7 @@ class UserTransformer extends EntityTransformer
|
|||||||
'oauth_provider_id' => (string) $user->oauth_provider_id,
|
'oauth_provider_id' => (string) $user->oauth_provider_id,
|
||||||
'last_confirmed_email_address' => (string) $user->last_confirmed_email_address ?: '',
|
'last_confirmed_email_address' => (string) $user->last_confirmed_email_address ?: '',
|
||||||
'google_2fa_secret' => (bool) $user->google_2fa_secret,
|
'google_2fa_secret' => (bool) $user->google_2fa_secret,
|
||||||
|
'has_password' => (bool) $user->has_password,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class AddHasPasswordFieldToUserTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->boolean('has_password')->default(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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::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('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::resource('webhooks', 'WebhookController');
|
||||||
Route::post('webhooks/bulk', 'WebhookController@bulk')->name('webhooks.bulk');
|
Route::post('webhooks/bulk', 'WebhookController@bulk')->name('webhooks.bulk');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user