Skip to content
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ CLAUDE.md

.vercel
prompts/


/playground/**
/playground/
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace HiEvents\Http\Actions\Admin\FailedJobs;

use HiEvents\DomainObjects\Enums\Role;
use HiEvents\Http\Actions\BaseAction;
use HiEvents\Services\Application\Handlers\Admin\DeleteFailedJobHandler;
use Illuminate\Http\JsonResponse;

class DeleteAllFailedJobsAction extends BaseAction
{
public function __construct(
private readonly DeleteFailedJobHandler $handler,
) {
}

public function __invoke(): JsonResponse
{
$this->minimumAllowedRole(Role::SUPERADMIN);

$count = $this->handler->deleteAll();

return $this->jsonResponse([
'message' => __('Deleted :count failed jobs', ['count' => $count]),
'deleted_count' => $count,
]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace HiEvents\Http\Actions\Admin\FailedJobs;

use HiEvents\DomainObjects\Enums\Role;
use HiEvents\Http\Actions\BaseAction;
use HiEvents\Services\Application\Handlers\Admin\DeleteFailedJobHandler;
use Illuminate\Http\JsonResponse;

class DeleteFailedJobAction extends BaseAction
{
public function __construct(
private readonly DeleteFailedJobHandler $handler,
) {
}

public function __invoke(int $jobId): JsonResponse
{
$this->minimumAllowedRole(Role::SUPERADMIN);

$deleted = $this->handler->handle($jobId);

if (!$deleted) {
return $this->errorResponse(__('Failed job not found'), 404);
}

return $this->deletedResponse();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

namespace HiEvents\Http\Actions\Admin\FailedJobs;

use HiEvents\DomainObjects\Enums\Role;
use HiEvents\Http\Actions\BaseAction;
use HiEvents\Http\Resources\Admin\AdminFailedJobResource;
use HiEvents\Services\Application\Handlers\Admin\DTO\GetAllFailedJobsDTO;
use HiEvents\Services\Application\Handlers\Admin\GetAllFailedJobsHandler;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class GetAllFailedJobsAction extends BaseAction
{
public function __construct(
private readonly GetAllFailedJobsHandler $handler,
) {
}

public function __invoke(Request $request): JsonResponse
{
$this->minimumAllowedRole(Role::SUPERADMIN);

$jobs = $this->handler->handle(new GetAllFailedJobsDTO(
perPage: min((int)$request->query('per_page', 20), 100),
search: $request->query('search'),
queue: $request->query('queue'),
sortBy: $request->query('sort_by', 'failed_at'),
sortDirection: $request->query('sort_direction', 'desc'),
));

return $this->resourceResponse(
resource: AdminFailedJobResource::class,
data: $jobs
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace HiEvents\Http\Actions\Admin\FailedJobs;

use HiEvents\DomainObjects\Enums\Role;
use HiEvents\Http\Actions\BaseAction;
use HiEvents\Services\Application\Handlers\Admin\RetryFailedJobHandler;
use Illuminate\Http\JsonResponse;

class RetryAllFailedJobsAction extends BaseAction
{
public function __construct(
private readonly RetryFailedJobHandler $handler,
) {
}

public function __invoke(): JsonResponse
{
$this->minimumAllowedRole(Role::SUPERADMIN);

$count = $this->handler->retryAll();

return $this->jsonResponse([
'message' => __('Queued :count jobs for retry', ['count' => $count]),
'retry_count' => $count,
]);
}
}
33 changes: 33 additions & 0 deletions backend/app/Http/Actions/Admin/FailedJobs/RetryFailedJobAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace HiEvents\Http\Actions\Admin\FailedJobs;

use HiEvents\DomainObjects\Enums\Role;
use HiEvents\Http\Actions\BaseAction;
use HiEvents\Services\Application\Handlers\Admin\RetryFailedJobHandler;
use Illuminate\Http\JsonResponse;

class RetryFailedJobAction extends BaseAction
{
public function __construct(
private readonly RetryFailedJobHandler $handler,
) {
}

public function __invoke(int $jobId): JsonResponse
{
$this->minimumAllowedRole(Role::SUPERADMIN);

$retried = $this->handler->handle($jobId);

if (!$retried) {
return $this->errorResponse(__('Failed job not found'), 404);
}

return $this->jsonResponse([
'message' => __('Job queued for retry'),
]);
}
}
40 changes: 40 additions & 0 deletions backend/app/Http/Actions/Admin/Messages/GetAllMessagesAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace HiEvents\Http\Actions\Admin\Messages;

use HiEvents\DomainObjects\Enums\Role;
use HiEvents\Http\Actions\BaseAction;
use HiEvents\Http\Resources\Admin\AdminMessageResource;
use HiEvents\Services\Application\Handlers\Admin\DTO\GetAllMessagesForAdminDTO;
use HiEvents\Services\Application\Handlers\Admin\GetAllMessagesForAdminHandler;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class GetAllMessagesAction extends BaseAction
{
public function __construct(
private readonly GetAllMessagesForAdminHandler $handler,
) {
}

public function __invoke(Request $request): JsonResponse
{
$this->minimumAllowedRole(Role::SUPERADMIN);

$messages = $this->handler->handle(new GetAllMessagesForAdminDTO(
perPage: min((int)$request->query('per_page', 20), 100),
search: $request->query('search'),
status: $request->query('status'),
type: $request->query('type'),
sortBy: $request->query('sort_by', 'created_at'),
sortDirection: $request->query('sort_direction', 'desc'),
));

return $this->resourceResponse(
resource: AdminMessageResource::class,
data: $messages
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace HiEvents\Http\Actions\Admin\Stats;

use HiEvents\DomainObjects\Enums\Role;
use HiEvents\Http\Actions\BaseAction;
use HiEvents\Services\Application\Handlers\Admin\DTO\GetAdminDashboardDataDTO;
use HiEvents\Services\Application\Handlers\Admin\GetAdminDashboardDataHandler;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class GetAdminDashboardDataAction extends BaseAction
{
public function __construct(
private readonly GetAdminDashboardDataHandler $handler,
) {
}

public function __invoke(Request $request): JsonResponse
{
$this->minimumAllowedRole(Role::SUPERADMIN);

$data = $this->handler->handle(new GetAdminDashboardDataDTO(
days: min((int)$request->query('days', 14), 90),
limit: min((int)$request->query('limit', 10), 50),
));

return $this->jsonResponse($data->toArray());
}
}
36 changes: 36 additions & 0 deletions backend/app/Http/Resources/Admin/AdminFailedJobResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace HiEvents\Http\Resources\Admin;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class AdminFailedJobResource extends JsonResource
{
public function toArray(Request $request): array
{
$payload = json_decode($this->payload, true);
$jobName = $payload['displayName'] ?? 'Unknown';

return [
'id' => $this->id,
'uuid' => $this->uuid,
'connection' => $this->connection,
'queue' => $this->queue,
'job_name' => class_basename($jobName),
'job_name_full' => $jobName,
'payload' => $this->payload,
'exception_summary' => $this->getExceptionSummary(),
'exception' => $this->exception,
'failed_at' => $this->failed_at,
];
}

private function getExceptionSummary(): string
{
$lines = explode("\n", $this->exception);
return $lines[0] ?? 'Unknown error';
}
}
29 changes: 29 additions & 0 deletions backend/app/Http/Resources/Admin/AdminMessageResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace HiEvents\Http\Resources\Admin;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class AdminMessageResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'event_id' => $this->event_id,
'event_title' => $this->event_title,
'account_name' => $this->account_name,
'subject' => $this->subject,
'message' => $this->message,
'type' => $this->type,
'status' => $this->status,
'recipients_count' => (int)$this->recipients_count,
'sent_by' => trim(($this->sent_by_first_name ?? '') . ' ' . ($this->sent_by_last_name ?? '')),
'sent_at' => $this->sent_at,
'created_at' => $this->created_at,
];
}
}
15 changes: 15 additions & 0 deletions backend/app/Models/FailedJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace HiEvents\Models;

class FailedJob extends BaseModel
{
protected $table = 'failed_jobs';

public $timestamps = false;

protected function getCastMap(): array
{
return [];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace HiEvents\Services\Application\Handlers\Admin\DTO;

use HiEvents\DataTransferObjects\BaseDataObject;

class AdminDashboardResponseDTO extends BaseDataObject
{
public function __construct(
public readonly array $popular_events,
public readonly array $most_viewed_events,
public readonly array $top_organizers,
public readonly array $recent_accounts,
public readonly float $recent_revenue,
public readonly int $recent_orders_count,
public readonly float $recent_orders_total,
public readonly int $recent_signups_count,
) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace HiEvents\Services\Application\Handlers\Admin\DTO;

use HiEvents\DataTransferObjects\BaseDataObject;

class GetAdminDashboardDataDTO extends BaseDataObject
{
public function __construct(
public readonly int $days = 14,
public readonly int $limit = 10,
) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace HiEvents\Services\Application\Handlers\Admin\DTO;

use HiEvents\DataTransferObjects\BaseDataObject;

class GetAllFailedJobsDTO extends BaseDataObject
{
public function __construct(
public readonly int $perPage = 20,
public readonly ?string $search = null,
public readonly ?string $queue = null,
public readonly ?string $sortBy = 'failed_at',
public readonly ?string $sortDirection = 'desc',
) {
}
}
Loading
Loading