Skip to content
Open
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
2 changes: 2 additions & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ APP_SAAS_MODE_ENABLED=false
APP_SAAS_STRIPE_APPLICATION_FEE_PERCENT=1.5
APP_HOMEPAGE_VIEWS_UPDATE_BATCH_SIZE=8
APP_DISABLE_REGISTRATION=false
APP_REQUIRE_ACCOUNT_APPROVAL=false
APP_ADMIN_EMAIL=
APP_STRIPE_CONNECT_ACCOUNT_TYPE=express
APP_PLATFORM_SUPPORT_EMAIL=support@your-website.com
APP_ALLOWED_INTERNAL_WEBHOOK_HOSTS=
Expand Down
7 changes: 7 additions & 0 deletions backend/app/DomainObjects/AccountEmailSettingDomainObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace HiEvents\DomainObjects;

class AccountEmailSettingDomainObject extends Generated\AccountEmailSettingDomainObjectAbstract
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ abstract class AccountDomainObjectAbstract extends \HiEvents\DomainObjects\Abstr
final public const SHORT_ID = 'short_id';
final public const STRIPE_CONNECT_SETUP_COMPLETE = 'stripe_connect_setup_complete';
final public const ACCOUNT_VERIFIED_AT = 'account_verified_at';
final public const APPROVED_AT = 'approved_at';
final public const STRIPE_CONNECT_ACCOUNT_TYPE = 'stripe_connect_account_type';
final public const IS_MANUALLY_VERIFIED = 'is_manually_verified';
final public const COUNTRY = 'country';
Expand All @@ -42,6 +43,7 @@ abstract class AccountDomainObjectAbstract extends \HiEvents\DomainObjects\Abstr
protected string $short_id;
protected ?bool $stripe_connect_setup_complete = false;
protected ?string $account_verified_at = null;
protected ?string $approved_at = null;
protected ?string $stripe_connect_account_type = null;
protected bool $is_manually_verified = false;
protected ?string $country = null;
Expand All @@ -63,6 +65,7 @@ public function toArray(): array
'short_id' => $this->short_id ?? null,
'stripe_connect_setup_complete' => $this->stripe_connect_setup_complete ?? null,
'account_verified_at' => $this->account_verified_at ?? null,
'approved_at' => $this->approved_at ?? null,
'stripe_connect_account_type' => $this->stripe_connect_account_type ?? null,
'is_manually_verified' => $this->is_manually_verified ?? null,
'country' => $this->country ?? null,
Expand Down Expand Up @@ -223,6 +226,18 @@ public function getAccountVerifiedAt(): ?string
return $this->account_verified_at;
}


public function setApprovedAt(?string $approved_at): self
{
$this->approved_at = $approved_at;
return $this;
}

public function getApprovedAt(): ?string
{
return $this->approved_at;
}

public function setStripeConnectAccountType(?string $stripe_connect_account_type): self
{
$this->stripe_connect_account_type = $stripe_connect_account_type;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
<?php

namespace HiEvents\DomainObjects\Generated;

/**
* THIS FILE IS AUTOGENERATED - DO NOT EDIT IT DIRECTLY.
* @package HiEvents\DomainObjects\Generated
*/
abstract class AccountEmailSettingDomainObjectAbstract extends \HiEvents\DomainObjects\AbstractDomainObject
{
final public const SINGULAR_NAME = 'account_email_setting';
final public const PLURAL_NAME = 'account_email_settings';
final public const ID = 'id';
final public const ACCOUNT_ID = 'account_id';
final public const SMTP_ENABLED = 'smtp_enabled';
final public const SMTP_HOST = 'smtp_host';
final public const SMTP_PORT = 'smtp_port';
final public const SMTP_ENCRYPTION = 'smtp_encryption';
final public const SMTP_USERNAME = 'smtp_username';
final public const SMTP_PASSWORD = 'smtp_password';
final public const MAIL_FROM_ADDRESS = 'mail_from_address';
final public const MAIL_FROM_NAME = 'mail_from_name';
final public const CREATED_AT = 'created_at';
final public const UPDATED_AT = 'updated_at';
final public const DELETED_AT = 'deleted_at';

protected int $id;
protected int $account_id;
protected bool $smtp_enabled = false;
protected ?string $smtp_host = null;
protected ?int $smtp_port = null;
protected ?string $smtp_encryption = null;
protected ?string $smtp_username = null;
protected ?string $smtp_password = null;
protected ?string $mail_from_address = null;
protected ?string $mail_from_name = null;
protected ?string $created_at = null;
protected ?string $updated_at = null;
protected ?string $deleted_at = null;

public function toArray(): array
{
return [
'id' => $this->id ?? null,
'account_id' => $this->account_id ?? null,
'smtp_enabled' => $this->smtp_enabled ?? null,
'smtp_host' => $this->smtp_host ?? null,
'smtp_port' => $this->smtp_port ?? null,
'smtp_encryption' => $this->smtp_encryption ?? null,
'smtp_username' => $this->smtp_username ?? null,
'smtp_password' => $this->smtp_password ?? null,
'mail_from_address' => $this->mail_from_address ?? null,
'mail_from_name' => $this->mail_from_name ?? null,
'created_at' => $this->created_at ?? null,
'updated_at' => $this->updated_at ?? null,
'deleted_at' => $this->deleted_at ?? null,
];
}

public function setId(int $id): self
{
$this->id = $id;
return $this;
}

public function getId(): int
{
return $this->id;
}

public function setAccountId(int $account_id): self
{
$this->account_id = $account_id;
return $this;
}

public function getAccountId(): int
{
return $this->account_id;
}

public function setSmtpEnabled(bool $smtp_enabled): self
{
$this->smtp_enabled = $smtp_enabled;
return $this;
}

public function getSmtpEnabled(): bool
{
return $this->smtp_enabled;
}

public function setSmtpHost(?string $smtp_host): self
{
$this->smtp_host = $smtp_host;
return $this;
}

public function getSmtpHost(): ?string
{
return $this->smtp_host;
}

public function setSmtpPort(?int $smtp_port): self
{
$this->smtp_port = $smtp_port;
return $this;
}

public function getSmtpPort(): ?int
{
return $this->smtp_port;
}

public function setSmtpEncryption(?string $smtp_encryption): self
{
$this->smtp_encryption = $smtp_encryption;
return $this;
}

public function getSmtpEncryption(): ?string
{
return $this->smtp_encryption;
}

public function setSmtpUsername(?string $smtp_username): self
{
$this->smtp_username = $smtp_username;
return $this;
}

public function getSmtpUsername(): ?string
{
return $this->smtp_username;
}

public function setSmtpPassword(?string $smtp_password): self
{
$this->smtp_password = $smtp_password;
return $this;
}

public function getSmtpPassword(): ?string
{
return $this->smtp_password;
}

public function setMailFromAddress(?string $mail_from_address): self
{
$this->mail_from_address = $mail_from_address;
return $this;
}

public function getMailFromAddress(): ?string
{
return $this->mail_from_address;
}

public function setMailFromName(?string $mail_from_name): self
{
$this->mail_from_name = $mail_from_name;
return $this;
}

public function getMailFromName(): ?string
{
return $this->mail_from_name;
}

public function setCreatedAt(?string $created_at): self
{
$this->created_at = $created_at;
return $this;
}

public function getCreatedAt(): ?string
{
return $this->created_at;
}

public function setUpdatedAt(?string $updated_at): self
{
$this->updated_at = $updated_at;
return $this;
}

public function getUpdatedAt(): ?string
{
return $this->updated_at;
}

public function setDeletedAt(?string $deleted_at): self
{
$this->deleted_at = $deleted_at;
return $this;
}

public function getDeletedAt(): ?string
{
return $this->deleted_at;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

declare(strict_types=1);

namespace HiEvents\Http\Actions\Accounts\Approval;

use HiEvents\Repository\Interfaces\AccountRepositoryInterface;
use HiEvents\Repository\Interfaces\AccountUserRepositoryInterface;
use HiEvents\Repository\Interfaces\UserRepositoryInterface;
use HiEvents\Services\Domain\User\EmailConfirmationService;
use HiEvents\Services\Infrastructure\Encryption\EncryptedPayloadService;
use HiEvents\Services\Infrastructure\Encryption\Exception\DecryptionFailedException;
use HiEvents\Services\Infrastructure\Encryption\Exception\EncryptedPayloadExpiredException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Psr\Log\LoggerInterface;

class ApproveAccountAction extends Controller
{
public function __construct(
private readonly EncryptedPayloadService $encryptedPayloadService,
private readonly AccountRepositoryInterface $accountRepository,
private readonly AccountUserRepositoryInterface $accountUserRepository,
private readonly UserRepositoryInterface $userRepository,
private readonly EmailConfirmationService $emailConfirmationService,
private readonly LoggerInterface $logger,
)
{
}

public function __invoke(Request $request): JsonResponse
{
$token = $request->query('token');

if (!$token) {
return response()->json(['message' => __('Missing approval token.')], 400);
}

try {
$payload = $this->encryptedPayloadService->decryptPayload($token);
} catch (DecryptionFailedException|EncryptedPayloadExpiredException $e) {
$this->logger->warning('Invalid or expired account approval token', [
'error' => $e->getMessage(),
]);
return response()->json([
'message' => __('This approval link is invalid or has expired.'),
], 400);
}

$accountId = $payload['account_id'] ?? null;
if (!$accountId) {
return response()->json(['message' => __('Invalid token payload.')], 400);
}

$account = $this->accountRepository->findById($accountId);
if (!$account) {
return response()->json(['message' => __('Account not found.')], 404);
}

if ($account->getApprovedAt() !== null) {
return response()->json(['message' => __('This account has already been approved.')], 200);
}

// Approve the account
$this->accountRepository->updateWhere(
attributes: ['approved_at' => now()->toDateTimeString()],
where: ['id' => $accountId],
);

$this->logger->info('Account approved by admin', ['account_id' => $accountId]);

// Find the account owner and send them their confirmation email
$accountOwner = $this->accountUserRepository->findFirstWhere([
'account_id' => $accountId,
'is_account_owner' => true,
]);

if ($accountOwner) {
$user = $this->userRepository->findById($accountOwner->getUserId());
$this->emailConfirmationService->sendConfirmation($user, $accountId);
}

return response()->json([
'message' => __('Account approved successfully. The user has been notified.'),
], 200);
}
}
Loading
Loading