name = $name; $user->email = strtolower($email); $user->password = Hash::make($password); $user->timezone = $timezone; $user->week_start = $weekStart; if ($verifyEmail) { $user->email_verified_at = Carbon::now(); } $user->save(); $this->createDefaultOrganizationForUser( $user, $currency, $numberFormat, $currencyFormat, $dateFormat, $intervalFormat, $timeFormat, ); return $user; } /** * Create a user without a password (e.g. provisioned via SSO). Such users * can only authenticate through a linked identity provider. */ public function createPasswordlessUser( string $name, string $email, string $timezone, Weekday $weekStart, ?string $currency, bool $verifyEmail = false ): User { $user = new User; $user->name = $name; $user->email = strtolower($email); $user->password = null; $user->timezone = $timezone; $user->week_start = $weekStart; if ($verifyEmail) { $user->email_verified_at = Carbon::now(); } $user->save(); $this->createDefaultOrganizationForUser($user, $currency); return $user; } private function createDefaultOrganizationForUser( User $user, ?string $currency, ?NumberFormat $numberFormat = null, ?CurrencyFormat $currencyFormat = null, ?DateFormat $dateFormat = null, ?IntervalFormat $intervalFormat = null, ?TimeFormat $timeFormat = null, ): void { $organizations = app(InvitationService::class)->processAcceptedInvitations($user); if ($organizations->isEmpty()) { $organization = app(OrganizationService::class)->createOrganization( $this->getOrganizationNameForUserName($user->name), $user, true, $currency, $numberFormat, $currencyFormat, $dateFormat, $intervalFormat, $timeFormat, ); $this->switchCurrentOrganization($user, $organization); } } /** * This does NOT change the member id. * This should only be used in if you want to change a member to a placeholder! */ public function assignOrganizationEntitiesToDifferentUser(Organization $organization, User $fromUser, User $toUser): void { // Time entries TimeEntry::query() ->whereBelongsTo($organization, 'organization') ->whereBelongsTo($fromUser, 'user') ->update([ 'user_id' => $toUser->getKey(), ]); // Project members ProjectMember::query() ->whereBelongsToOrganization($organization) ->whereBelongsTo($fromUser, 'user') ->update([ 'user_id' => $toUser->getKey(), ]); } public function makeSureUserHasAtLeastOneOrganization(User $user): void { if ($user->organizations()->count() > 0) { return; } // Create a new organization $organization = app(OrganizationService::class)->createOrganization( $this->getOrganizationNameForUserName($user->name), $user, true ); $this->switchCurrentOrganization($user, $organization); AfterCreateOrganization::dispatch($organization); } public function switchCurrentOrganization(User $user, Organization $organization): void { $user->currentOrganization()->associate($organization); $user->save(); } public function getOrganizationNameForUserName(string $username): string { return explode(' ', $username, 2)[0]."'s Organization"; } public function makeSureUserHasCurrentOrganization(User $user): void { if ($user->current_team_id !== null) { return; } $organization = $user->organizations()->first(); if ($organization !== null) { $user->currentOrganization()->associate($organization); $user->save(); } } /** * Change the ownership of an organization to a new user. * The previous owner will be demoted to an admin. */ public function changeOwnership(Organization $organization, User $newOwner): void { $organization->update([ 'user_id' => $newOwner->getKey(), ]); /** @var Member|null $userMembership */ $userMembership = Member::query() ->whereBelongsTo($organization, 'organization') ->whereBelongsTo($newOwner, 'user') ->first(); if ($userMembership === null) { throw new \InvalidArgumentException('User is not a member of the organization'); } $userMembership->role = Role::Owner->value; $userMembership->save(); $oldOwners = Member::query() ->whereBelongsTo($organization, 'organization') ->where('role', '=', Role::Owner->value) ->where('user_id', '!=', $newOwner->getKey()) ->get(); foreach ($oldOwners as $oldOwner) { $oldOwner->role = Role::Admin->value; $oldOwner->save(); } } public function deleteProfilePhoto(User $user): void { if ($user->profile_photo_path === null) { return; } Storage::disk(config('filesystems.public'))->delete($user->profile_photo_path); $user->profile_photo_path = null; $user->save(); } }