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
3 changes: 3 additions & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ 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_EVENT_SPAM_CHECK_ENABLED=false
APP_EVENT_SPAM_CHECK_CONFIDENCE_THRESHOLD=0.7
ANTHROPIC_API_KEY=
APP_STRIPE_CONNECT_ACCOUNT_TYPE=express
APP_PLATFORM_SUPPORT_EMAIL=support@your-website.com
APP_ALLOWED_INTERNAL_WEBHOOK_HOSTS=
Expand Down
20 changes: 20 additions & 0 deletions backend/app/DomainObjects/EventSpamCheckDomainObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace HiEvents\DomainObjects;

class EventSpamCheckDomainObject extends Generated\EventSpamCheckDomainObjectAbstract
{
private ?EventDomainObject $event = null;

public function setEvent(?EventDomainObject $event): self
{
$this->event = $event;

return $this;
}

public function getEvent(): ?EventDomainObject
{
return $this->event;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
<?php

namespace HiEvents\DomainObjects\Generated;

/**
* THIS FILE IS AUTOGENERATED - DO NOT EDIT IT DIRECTLY.
* @package HiEvents\DomainObjects\Generated
*/
abstract class EventSpamCheckDomainObjectAbstract extends \HiEvents\DomainObjects\AbstractDomainObject
{
final public const SINGULAR_NAME = 'event_spam_check';
final public const PLURAL_NAME = 'event_spam_checks';
final public const ID = 'id';
final public const EVENT_ID = 'event_id';
final public const REVIEWED_BY_USER_ID = 'reviewed_by_user_id';
final public const STATUS = 'status';
final public const VERDICT = 'verdict';
final public const CONTENT_HASH = 'content_hash';
final public const CHECKED_AT = 'checked_at';
final public const REVIEWED_AT = 'reviewed_at';
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 $event_id;
protected ?int $reviewed_by_user_id = null;
protected string $status;
protected array|string|null $verdict = null;
protected string $content_hash;
protected string $checked_at;
protected ?string $reviewed_at = 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,
'event_id' => $this->event_id ?? null,
'reviewed_by_user_id' => $this->reviewed_by_user_id ?? null,
'status' => $this->status ?? null,
'verdict' => $this->verdict ?? null,
'content_hash' => $this->content_hash ?? null,
'checked_at' => $this->checked_at ?? null,
'reviewed_at' => $this->reviewed_at ?? 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 setEventId(int $event_id): self
{
$this->event_id = $event_id;
return $this;
}

public function getEventId(): int
{
return $this->event_id;
}

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

public function getReviewedByUserId(): ?int
{
return $this->reviewed_by_user_id;
}

public function setStatus(string $status): self
{
$this->status = $status;
return $this;
}

public function getStatus(): string
{
return $this->status;
}

public function setVerdict(array|string|null $verdict): self
{
$this->verdict = $verdict;
return $this;
}

public function getVerdict(): array|string|null
{
return $this->verdict;
}

public function setContentHash(string $content_hash): self
{
$this->content_hash = $content_hash;
return $this;
}

public function getContentHash(): string
{
return $this->content_hash;
}

public function setCheckedAt(string $checked_at): self
{
$this->checked_at = $checked_at;
return $this;
}

public function getCheckedAt(): string
{
return $this->checked_at;
}

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

public function getReviewedAt(): ?string
{
return $this->reviewed_at;
}

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;
}
}
15 changes: 15 additions & 0 deletions backend/app/DomainObjects/Status/EventSpamCheckStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace HiEvents\DomainObjects\Status;

use HiEvents\DomainObjects\Enums\BaseEnum;

enum EventSpamCheckStatus
{
use BaseEnum;

case FLAGGED;
case CLEAN;
case APPROVED;
case CONFIRMED_SPAM;
}
1 change: 1 addition & 0 deletions backend/app/DomainObjects/Status/EventStatus.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ enum EventStatus
case DRAFT;
case LIVE;
case ARCHIVED;
case PENDING_MANUAL_REVIEW;
}
7 changes: 7 additions & 0 deletions backend/app/Exceptions/EventPendingReviewException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace HiEvents\Exceptions;

use Exception;

class EventPendingReviewException extends Exception {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace HiEvents\Http\Actions\Admin\SpamEvents;

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

class ApproveSpamEventAction extends BaseAction
{
public function __construct(
private readonly ApproveSpamEventHandler $handler,
) {}

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

$this->handler->handle($eventId, $this->getAuthenticatedUser()->getId());

return $this->jsonResponse([
'message' => __('Event approved and published'),
]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace HiEvents\Http\Actions\Admin\SpamEvents;

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

class ConfirmSpamEventAction extends BaseAction
{
public function __construct(
private readonly ConfirmSpamEventHandler $handler,
) {}

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

$this->handler->handle($eventId, $this->getAuthenticatedUser()->getId());

return $this->jsonResponse([
'message' => __('Event confirmed as spam'),
]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace HiEvents\Http\Actions\Admin\SpamEvents;

use HiEvents\DomainObjects\Enums\Role;
use HiEvents\Http\Actions\BaseAction;
use HiEvents\Resources\Admin\AdminSpamEventResource;
use HiEvents\Services\Application\Handlers\Admin\GetAllSpamEventsForAdminHandler;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class GetAllSpamEventsAction extends BaseAction
{
public function __construct(
private readonly GetAllSpamEventsForAdminHandler $handler,
) {}

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

$spamEvents = $this->handler->handle(
search: $request->query('search'),
perPage: min((int) $request->query('per_page', 20), 100),
);

return $this->resourceResponse(
resource: AdminSpamEventResource::class,
data: $spamEvents,
);
}
}
1 change: 1 addition & 0 deletions backend/app/Http/Actions/Events/UpdateEventAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public function __invoke(UpdateEventRequest $request, int $eventId): JsonRespons
'id' => $eventId,
'account_id' => $this->getAuthenticatedAccountId(),
'user_id' => $authorisedUser->getId(),
'description_provided' => $request->exists('description'),
]
)
)
Expand Down
3 changes: 2 additions & 1 deletion backend/app/Http/Actions/Events/UpdateEventStatusAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use HiEvents\DomainObjects\EventDomainObject;
use HiEvents\Exceptions\AccountNotVerifiedException;
use HiEvents\Exceptions\EventPendingReviewException;
use HiEvents\Http\Actions\BaseAction;
use HiEvents\Http\Request\Event\UpdateEventStatusRequest;
use HiEvents\Http\ResponseCodes;
Expand All @@ -28,7 +29,7 @@ public function __invoke(UpdateEventStatusRequest $request, int $eventId): JsonR
'eventId' => $eventId,
'accountId' => $this->getAuthenticatedAccountId(),
]));
} catch (AccountNotVerifiedException $e) {
} catch (AccountNotVerifiedException|EventPendingReviewException $e) {
return $this->errorResponse($e->getMessage(), ResponseCodes::HTTP_UNPROCESSABLE_ENTITY);
}

Expand Down
6 changes: 5 additions & 1 deletion backend/app/Http/Request/Event/UpdateEventStatusRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ class UpdateEventStatusRequest extends BaseRequest
public function rules(): array
{
return [
'status' => ['required', Rule::in(EventStatus::valuesArray())],
'status' => ['required', Rule::in([
EventStatus::DRAFT->name,
EventStatus::LIVE->name,
EventStatus::ARCHIVED->name,
])],
];
}
}
Loading
Loading