Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Google account relation by detaching it from user model #155

Merged
merged 6 commits into from
Sep 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion app/src/Controller/Profile/ProfileController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use App\Database\Currency;
use App\Database\GoogleAccount;
use App\Repository\CurrencyRepository;
use App\Repository\GoogleAccountRepository;
use App\Request\CheckNickNameRequest;
use App\Request\Profile\UpdateBasicRequest;
use App\Request\Profile\UpdateLocaleRequest;
Expand All @@ -33,6 +34,7 @@ public function __construct(
protected ResponseWrapper $response,
protected CurrencyRepository $currencyRepository,
protected UserOptionsService $userOptionsService,
protected GoogleAccountRepository $googleAccountRepository,
) {
parent::__construct($auth);
}
Expand Down Expand Up @@ -121,9 +123,11 @@ public function updateLocale(UpdateLocaleRequest $request): ResponseInterface
#[Route(route: '/profile/social', name: 'profile.social', methods: 'GET', group: 'auth')]
public function socialAccounts(): ResponseInterface
{
$googleAccount = $this->googleAccountRepository->findByUser($this->user);

return $this->response->json([
'data' => [
'google' => $this->user->googleAccount instanceof GoogleAccount
'google' => $googleAccount instanceof GoogleAccount
],
]);
}
Expand Down
4 changes: 2 additions & 2 deletions app/src/Database/GoogleAccount.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
namespace App\Database;

use App\Database\Typecast\EncryptedTypecast;
use App\Repository\ChargeRepository;
use App\Repository\GoogleAccountRepository;
use Cycle\Annotated\Annotation as ORM;
use Cycle\ORM\Entity\Behavior;
use Cycle\ORM\Parser\Typecast;

#[ORM\Entity(repository: ChargeRepository::class, typecast: [
#[ORM\Entity(repository: GoogleAccountRepository::class, typecast: [
Typecast::class,
EncryptedTypecast::class,
])]
Expand Down
3 changes: 0 additions & 3 deletions app/src/Database/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,6 @@ class User implements PasswordContainerInterface
#[ORM\Relation\BelongsTo(target: Currency::class, innerKey: 'default_currency_code', cascade: true, load: 'eager')]
private Currency $defaultCurrency;

#[ORM\Relation\HasOne(target: GoogleAccount::class, outerKey: 'user_id', nullable: true, cascade: true)]
public GoogleAccount|null $googleAccount = null;

#[ORM\Column(type: 'json', name: 'options', typecast: JsonTypecast::RULE)]
public array $options = [];

Expand Down
11 changes: 11 additions & 0 deletions app/src/Repository/GoogleAccountRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,22 @@

namespace App\Repository;

use App\Database\User;
use Cycle\ORM\Select\Repository;

/**
* @extends Repository<\App\Database\GoogleAccount>
*/
class GoogleAccountRepository extends Repository
{
/**
* @param \App\Database\User $user
* @return object|null
*/
public function findByUser(User $user): object|null
{
return $this->findOne([
'user_id' => $user->id,
]);
}
}
25 changes: 18 additions & 7 deletions app/src/Service/Auth/AuthService.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
namespace App\Service\Auth;

use App\Database\Currency;
use App\Database\GoogleAccount;
use App\Database\User;
use App\Repository\CurrencyRepository;
use App\Repository\UserRepository;
use App\Security\PasswordContainerInterface;
use App\Service\GoogleAccountService;
use App\Service\UserOptionsService;
use App\Service\UserService;
use Psr\Http\Message\ServerRequestInterface;
Expand All @@ -35,6 +37,7 @@ public function __construct(
protected UserOptionsService $userOptionsService,
protected CurrencyRepository $currencyRepository,
protected RefreshTokenService $refreshTokenService,
protected GoogleAccountService $googleAccountService,
protected EmailConfirmationService $emailConfirmationService,
) {
}
Expand Down Expand Up @@ -135,13 +138,6 @@ protected function createUser(User $user, string $locale = null): User

$this->userOptionsService->setLocale($user, $locale ?? $this->translator->getLocale());

if (($googleAccount = $user->googleAccount) !== null) {
// insert user first
$user->googleAccount = null;
$this->storeUser($user);
$user->googleAccount = $googleAccount;
}

$this->storeUser($user);

if (! $user->isEmailConfirmed) {
Expand All @@ -166,6 +162,21 @@ protected function storeUser(User $user): User
}
}

protected function storeGoogleAccount(GoogleAccount $googleAccount): GoogleAccount
{
try {
return $this->googleAccountService->store($googleAccount);
} catch (\Throwable $exception) {
$this->logger->error('Error while storing googleAccount', [
'error' => get_class($exception),
'message' => $exception->getMessage(),
'code' => $exception->getCode(),
]);

throw new \RuntimeException($exception->getMessage(), (int) $exception->getCode(), $exception);
}
}

protected function initiateEmailConfirmation(User $user): void
{
try {
Expand Down
38 changes: 22 additions & 16 deletions app/src/Service/Auth/GoogleAuthService.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
use App\Database\GoogleAccount;
use App\Database\User;
use App\Repository\CurrencyRepository;
use App\Repository\GoogleAccountRepository;
use App\Repository\UserRepository;
use App\Service\Auth\Exception\InvalidTokenException;
use App\Service\GoogleAccountService;
use App\Service\PhotoStorageService;
use App\Service\UserOptionsService;
use App\Service\UserService;
Expand All @@ -36,7 +38,9 @@ public function __construct(
protected CurrencyRepository $currencyRepository,
protected PhotoStorageService $photoStorageService,
protected RefreshTokenService $refreshTokenService,
protected GoogleAccountService $googleAccountService,
protected EmailConfirmationService $emailConfirmationService,
protected readonly GoogleAccountRepository $googleAccountRepository,
) {
parent::__construct(
$this->auth,
Expand All @@ -48,6 +52,7 @@ public function __construct(
$this->userOptionsService,
$this->currencyRepository,
$this->refreshTokenService,
$this->googleAccountService,
$this->emailConfirmationService,
);
}
Expand Down Expand Up @@ -126,36 +131,37 @@ public function loginOrRegister(string $idToken): Authentication
throw new InvalidTokenException($this->say('google_auth_account_not_verified'));
}

if (
$user instanceof User &&
$user->googleAccount !== null &&
$user->googleAccount->accountId !== (string) ($data['sub'] ?? '')
) {
$this->logger->error('Unable to attach Google Account to existing user, Google account ID is already attached and different from actual.', [
'data' => json_encode($data),
]);
if ($user instanceof User) {
$googleAccount = $this->googleAccountRepository->findByUser($user);

throw new InvalidTokenException($this->say('google_auth_email_already_claimed'));
}
if ($googleAccount instanceof GoogleAccount && $googleAccount->accountId !== (string) ($data['sub'] ?? '')) {
$this->logger->error('Unable to attach Google Account to existing user, Google account ID is already attached and different from actual.', [
'data' => json_encode($data),
]);

if ($user instanceof User) {
if ($user->googleAccount instanceof GoogleAccount) {
throw new InvalidTokenException($this->say('google_auth_email_already_claimed'));
}

if ($googleAccount instanceof GoogleAccount) {
// Update existing Google Account data
$user->googleAccount->setData($data);
$googleAccount->setData($data);
} else {
// attach existing user to the new Google Account
$user->googleAccount = $this->makeGoogleAccount($data);
$googleAccount = $this->makeGoogleAccount($user, $data);

if ($user->photo === null) {
$this->photoStorageService->queueDownloadProfilePhoto((int) $user->id, $data['picture']);
}
}

$this->storeUser($user);
$this->storeGoogleAccount($googleAccount);
} else {
// new user
$user = $this->makeUser($data);
$user = $this->createUser($user);
$googleAccount = $this->makeGoogleAccount($user, $data);
$this->storeGoogleAccount($googleAccount);
$this->photoStorageService->queueDownloadProfilePhoto((int) $user->id, $data['picture']);
}

Expand All @@ -171,14 +177,14 @@ protected function makeUser(array $data): User
$user->email = $data['email'] ?? null;
$user->defaultCurrencyCode = Currency::DEFAULT_CURRENCY_CODE;
$user->isEmailConfirmed = (bool) ($data['email_verified'] ?? false);
$user->googleAccount = $this->makeGoogleAccount($data);

return $user;
}

protected function makeGoogleAccount(array $data): GoogleAccount
protected function makeGoogleAccount(User $user, array $data): GoogleAccount
{
$account = new GoogleAccount();
$account->userId = (int) $user->id;
$account->accountId = $data['sub'] ?? null;
$account->pictureUrl = $data['picture'] ?? null;
$account->setData($data);
Expand Down
24 changes: 24 additions & 0 deletions app/src/Service/GoogleAccountService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace App\Service;

use App\Database\GoogleAccount;
use Cycle\ORM\EntityManagerInterface;

class GoogleAccountService
{
public function __construct(
private readonly EntityManagerInterface $tr,
) {
}

public function store(GoogleAccount $googleAccount): GoogleAccount
{
$this->tr->persist($googleAccount);
$this->tr->run();

return $googleAccount;
}
}
Loading