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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ prompts/
/plans

.claude/worktrees/
.claude/scheduled_tasks.lock
tmp_translate/
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ cd docker/development
- **ALWAYS** wrap all translatable strings in `__()` helper
- Domain Objects are auto-generated via `php artisan generate-domain-objects` - never edit manually
- **Always** create unit tests for new features in `backend/tests/Unit/`
- **NEVER leave dead code.** Code that has no production callers — unused methods, unused DTO fields, unused constants, columns that are written but never read, classes only called from tests — must be deleted, not left "for future use". This applies to both backend and frontend. If you add a method speculatively, wire it to a real caller in the same change or remove it. The same rule applies after refactors: if something becomes unreferenced, it goes. Confirm with grep before claiming a method or class is reachable.
- **DON'T** add comments unless absolutely necessary
- **ALWAYS** sanitize user-provided content with `HtmlPurifierService` before storing, especially content rendered as HTML

Expand Down
11 changes: 11 additions & 0 deletions backend/app/DomainObjects/Enums/LocationType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace HiEvents\DomainObjects\Enums;

enum LocationType
{
use BaseEnum;

case IN_PERSON;
case ONLINE;
}
39 changes: 31 additions & 8 deletions backend/app/DomainObjects/EventDomainObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
use Illuminate\Support\Collection;
use Illuminate\Support\Str;

class EventDomainObject extends Generated\EventDomainObjectAbstract implements IsSortable, IsFilterable
class EventDomainObject extends Generated\EventDomainObjectAbstract implements IsFilterable, IsSortable
{
private ?Collection $products = null;

Expand Down Expand Up @@ -44,6 +44,8 @@ class EventDomainObject extends Generated\EventDomainObjectAbstract implements I

private ?AccountDomainObject $account = null;

private ?EventLocationDomainObject $eventLocation = null;

public static function getAllowedFilterFields(): array
{
return [
Expand Down Expand Up @@ -96,6 +98,7 @@ public function getProducts(): ?Collection
public function setQuestions(?Collection $questions): EventDomainObject
{
$this->questions = $questions;

return $this;
}

Expand All @@ -112,6 +115,7 @@ public function getSlug(): string
public function setImages(?Collection $images): EventDomainObject
{
$this->images = $images;

return $this;
}

Expand All @@ -128,6 +132,7 @@ public function getEventSettings(): ?EventSettingDomainObject
public function setEventSettings(?EventSettingDomainObject $settings): EventDomainObject
{
$this->settings = $settings;

return $this;
}

Expand All @@ -151,6 +156,7 @@ public function getAccount(): ?AccountDomainObject
public function setAccount(?AccountDomainObject $account): self
{
$this->account = $account;

return $this;
}

Expand All @@ -175,6 +181,7 @@ public function getDescriptionPreview(): string
public function setEventOccurrences(?Collection $eventOccurrences): self
{
$this->eventOccurrences = $eventOccurrences;

return $this;
}

Expand All @@ -190,7 +197,7 @@ public function getStartDate(): ?string
}

return $this->eventOccurrences->min(
fn(EventOccurrenceDomainObject $o) => $o->getStartDate()
fn (EventOccurrenceDomainObject $o) => $o->getStartDate()
);
}

Expand All @@ -201,17 +208,17 @@ public function getEndDate(): ?string
}

$withEndDates = $this->eventOccurrences->filter(
fn(EventOccurrenceDomainObject $o) => $o->getEndDate() !== null
fn (EventOccurrenceDomainObject $o) => $o->getEndDate() !== null
);

if ($withEndDates->isEmpty()) {
return $this->eventOccurrences->max(
fn(EventOccurrenceDomainObject $o) => $o->getStartDate()
fn (EventOccurrenceDomainObject $o) => $o->getStartDate()
);
}

return $withEndDates->max(
fn(EventOccurrenceDomainObject $o) => $o->getEndDate()
fn (EventOccurrenceDomainObject $o) => $o->getEndDate()
);
}

Expand All @@ -224,9 +231,9 @@ public function getNextOccurrenceStartDate(): ?string
$now = Carbon::now();

$nextOccurrence = $this->eventOccurrences
->filter(fn(EventOccurrenceDomainObject $o) => $o->getStatus() === EventOccurrenceStatus::ACTIVE->name)
->filter(fn(EventOccurrenceDomainObject $o) => Carbon::parse($o->getStartDate(), 'UTC')->isFuture())
->sortBy(fn(EventOccurrenceDomainObject $o) => $o->getStartDate())
->filter(fn (EventOccurrenceDomainObject $o) => $o->getStatus() === EventOccurrenceStatus::ACTIVE->name)
->filter(fn (EventOccurrenceDomainObject $o) => Carbon::parse($o->getStartDate(), 'UTC')->isFuture())
->sortBy(fn (EventOccurrenceDomainObject $o) => $o->getStartDate())
->first();

return $nextOccurrence?->getStartDate();
Expand Down Expand Up @@ -347,12 +354,14 @@ public function getEventStatistics(): ?EventStatisticDomainObject
public function setEventStatistics(?EventStatisticDomainObject $eventStatistics): self
{
$this->eventStatistics = $eventStatistics;

return $this;
}

public function setProductCategories(?Collection $productCategories): EventDomainObject
{
$this->productCategories = $productCategories;

return $this;
}

Expand All @@ -369,6 +378,7 @@ public function getWebhooks(): ?Collection
public function setWebhooks(?Collection $webhooks): EventDomainObject
{
$this->webhooks = $webhooks;

return $this;
}

Expand All @@ -380,6 +390,19 @@ public function getAffiliates(): ?Collection
public function setAffiliates(?Collection $affiliates): EventDomainObject
{
$this->affiliates = $affiliates;

return $this;
}

public function getEventLocation(): ?EventLocationDomainObject
{
return $this->eventLocation;
}

public function setEventLocation(?EventLocationDomainObject $eventLocation): self
{
$this->eventLocation = $eventLocation;

return $this;
}
}
24 changes: 24 additions & 0 deletions backend/app/DomainObjects/EventLocationDomainObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace HiEvents\DomainObjects;

use HiEvents\DomainObjects\Generated\EventLocationDomainObjectAbstract;

class EventLocationDomainObject extends EventLocationDomainObjectAbstract
{
private ?LocationDomainObject $location = null;

public function getLocation(): ?LocationDomainObject
{
return $this->location;
}

public function setLocation(?LocationDomainObject $location): self
{
$this->location = $location;

return $this;
}
}
23 changes: 22 additions & 1 deletion backend/app/DomainObjects/EventOccurrenceDomainObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use HiEvents\DomainObjects\Status\EventOccurrenceStatus;
use Illuminate\Support\Collection;

class EventOccurrenceDomainObject extends EventOccurrenceDomainObjectAbstract implements IsSortable, IsFilterable
class EventOccurrenceDomainObject extends EventOccurrenceDomainObjectAbstract implements IsFilterable, IsSortable
{
private ?EventDomainObject $event = null;

Expand All @@ -24,6 +24,8 @@ class EventOccurrenceDomainObject extends EventOccurrenceDomainObjectAbstract im

private ?EventOccurrenceStatisticDomainObject $eventOccurrenceStatistics = null;

private ?EventLocationDomainObject $eventLocation = null;

public static function getAllowedFilterFields(): array
{
return [
Expand Down Expand Up @@ -57,6 +59,7 @@ public static function getDefaultSortDirection(): string
public function setEvent(?EventDomainObject $event): self
{
$this->event = $event;

return $this;
}

Expand All @@ -68,6 +71,7 @@ public function getEvent(): ?EventDomainObject
public function setOrderItems(?Collection $orderItems): self
{
$this->orderItems = $orderItems;

return $this;
}

Expand All @@ -79,6 +83,7 @@ public function getOrderItems(): ?Collection
public function setAttendees(?Collection $attendees): self
{
$this->attendees = $attendees;

return $this;
}

Expand All @@ -90,6 +95,7 @@ public function getAttendees(): ?Collection
public function setCheckInLists(?Collection $checkInLists): self
{
$this->checkInLists = $checkInLists;

return $this;
}

Expand All @@ -101,6 +107,7 @@ public function getCheckInLists(): ?Collection
public function setPriceOverrides(?Collection $priceOverrides): self
{
$this->priceOverrides = $priceOverrides;

return $this;
}

Expand All @@ -112,6 +119,7 @@ public function getPriceOverrides(): ?Collection
public function setEventOccurrenceStatistics(?EventOccurrenceStatisticDomainObject $statistics): self
{
$this->eventOccurrenceStatistics = $statistics;

return $this;
}

Expand All @@ -138,6 +146,7 @@ public function isSoldOut(): bool
public function isPast(): bool
{
$endDate = $this->getEndDate() ?? $this->getStartDate();

return Carbon::parse($endDate, 'UTC')->isPast();
}

Expand All @@ -154,4 +163,16 @@ public function getAvailableCapacity(): ?int

return max(0, $this->getCapacity() - $this->getUsedCapacity());
}

public function setEventLocation(?EventLocationDomainObject $eventLocation): self
{
$this->eventLocation = $eventLocation;

return $this;
}

public function getEventLocation(): ?EventLocationDomainObject
{
return $this->eventLocation;
}
}
22 changes: 0 additions & 22 deletions backend/app/DomainObjects/EventSettingDomainObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@

namespace HiEvents\DomainObjects;

use HiEvents\DataTransferObjects\AddressDTO;
use HiEvents\Helper\AddressHelper;

class EventSettingDomainObject extends Generated\EventSettingDomainObjectAbstract
{
/**
* @return string
* @todo This should not be here.
*/
public function getGetEmailFooterHtml(): string
Expand All @@ -23,22 +19,4 @@ public function getGetEmailFooterHtml(): string
</div>
HTML;
}

public function getAddressString(): string
{
return AddressHelper::formatAddress($this->getLocationDetails());
}

public function getAddress(): AddressDTO
{
return new AddressDTO(
venue_name: $this->getLocationDetails()['venue_name'] ?? null,
address_line_1: $this->getLocationDetails()['address_line_1'] ?? null,
address_line_2: $this->getLocationDetails()['address_line_2'] ?? null,
city: $this->getLocationDetails()['city'] ?? null,
state_or_region: $this->getLocationDetails()['state_or_region'] ?? null,
zip_or_postal_code: $this->getLocationDetails()['zip_or_postal_code'] ?? null,
country: $this->getLocationDetails()['country'] ?? null,
);
}
}
28 changes: 14 additions & 14 deletions backend/app/DomainObjects/Generated/EventDomainObjectAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ abstract class EventDomainObjectAbstract extends \HiEvents\DomainObjects\Abstrac
final public const ACCOUNT_ID = 'account_id';
final public const USER_ID = 'user_id';
final public const ORGANIZER_ID = 'organizer_id';
final public const EVENT_LOCATION_ID = 'event_location_id';
final public const TITLE = 'title';
final public const DESCRIPTION = 'description';
final public const STATUS = 'status';
final public const LOCATION_DETAILS = 'location_details';
final public const CURRENCY = 'currency';
final public const TIMEZONE = 'timezone';
final public const ATTRIBUTES = 'attributes';
Expand All @@ -35,10 +35,10 @@ abstract class EventDomainObjectAbstract extends \HiEvents\DomainObjects\Abstrac
protected int $account_id;
protected int $user_id;
protected ?int $organizer_id = null;
protected ?int $event_location_id = null;
protected string $title;
protected ?string $description = null;
protected ?string $status = null;
protected array|string|null $location_details = null;
protected string $currency = 'USD';
protected ?string $timezone = null;
protected array|string|null $attributes = null;
Expand All @@ -59,10 +59,10 @@ public function toArray(): array
'account_id' => $this->account_id ?? null,
'user_id' => $this->user_id ?? null,
'organizer_id' => $this->organizer_id ?? null,
'event_location_id' => $this->event_location_id ?? null,
'title' => $this->title ?? null,
'description' => $this->description ?? null,
'status' => $this->status ?? null,
'location_details' => $this->location_details ?? null,
'currency' => $this->currency ?? null,
'timezone' => $this->timezone ?? null,
'attributes' => $this->attributes ?? null,
Expand Down Expand Up @@ -122,6 +122,17 @@ public function getOrganizerId(): ?int
return $this->organizer_id;
}

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

public function getEventLocationId(): ?int
{
return $this->event_location_id;
}

public function setTitle(string $title): self
{
$this->title = $title;
Expand Down Expand Up @@ -155,17 +166,6 @@ public function getStatus(): ?string
return $this->status;
}

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

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

public function setCurrency(string $currency): self
{
$this->currency = $currency;
Expand Down
Loading
Loading