Skip to content

Commit 2aa2bf8

Browse files
authored
Merge pull request #84 from HiEventsDev/develop
Add ability to duplicate events
2 parents 1f0bf47 + e38747f commit 2aa2bf8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1781
-541
lines changed

backend/app/DataTransferObjects/BaseDTO.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
namespace HiEvents\DataTransferObjects;
44

5+
use HiEvents\DataTransferObjects\Attributes\CollectionOf;
56
use Illuminate\Support\Collection;
67
use ReflectionClass;
78
use ReflectionProperty;
89
use RuntimeException;
910
use Throwable;
10-
use HiEvents\DataTransferObjects\Attributes\CollectionOf;
1111

1212
abstract class BaseDTO
1313
{

backend/app/DomainObjects/EventDomainObject.php

+14
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ class EventDomainObject extends Generated\EventDomainObjectAbstract implements I
1919

2020
private ?Collection $images = null;
2121

22+
private ?Collection $promoCodes = null;
23+
2224
private ?EventSettingDomainObject $settings = null;
2325

2426
private ?OrganizerDomainObject $organizer = null;
@@ -190,4 +192,16 @@ public function getLifecycleStatus(): string
190192

191193
return EventLifecycleStatus::ENDED->name;
192194
}
195+
196+
public function getPromoCodes(): ?Collection
197+
{
198+
return $this->promoCodes;
199+
}
200+
201+
public function setPromoCodes(?Collection $promoCodes): self
202+
{
203+
$this->promoCodes = $promoCodes;
204+
205+
return $this;
206+
}
193207
}

backend/app/Http/Actions/Events/DuplicateEventAction.php

+31-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,41 @@
22

33
namespace HiEvents\Http\Actions\Events;
44

5+
use HiEvents\DomainObjects\EventDomainObject;
56
use HiEvents\Http\Actions\BaseAction;
7+
use HiEvents\Http\Request\Event\DuplicateEventRequest;
8+
use HiEvents\Resources\Event\EventResource;
9+
use HiEvents\Services\Domain\Event\DTO\DuplicateEventDataDTO;
10+
use HiEvents\Services\Handlers\Event\DuplicateEventHandler;
11+
use Illuminate\Http\JsonResponse;
12+
use Throwable;
613

714
class DuplicateEventAction extends BaseAction
815
{
9-
public function __invoke(): void
16+
public function __construct(private readonly DuplicateEventHandler $handler)
1017
{
11-
// todo
18+
}
19+
20+
/**
21+
* @throws Throwable
22+
*/
23+
public function __invoke(int $eventId, DuplicateEventRequest $request): JsonResponse
24+
{
25+
$this->isActionAuthorized($eventId, EventDomainObject::class);
26+
27+
$event = $this->handler->handle(new DuplicateEventDataDTO(
28+
eventId: $eventId,
29+
accountId: $this->getAuthenticatedAccountId(),
30+
title: $request->validated('title'),
31+
startDate: $request->validated('start_date'),
32+
duplicateTickets: $request->validated('duplicate_tickets'),
33+
duplicateQuestions: $request->validated('duplicate_questions'),
34+
duplicateSettings: $request->validated('duplicate_settings'),
35+
duplicatePromoCodes: $request->validated('duplicate_promo_codes'),
36+
description: $request->validated('description'),
37+
endDate: $request->validated('end_date'),
38+
));
39+
40+
return $this->resourceResponse(EventResource::class, $event);
1241
}
1342
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace HiEvents\Http\Request\Event;
4+
5+
use HiEvents\Http\Request\BaseRequest;
6+
use HiEvents\Validators\EventRules;
7+
8+
class DuplicateEventRequest extends BaseRequest
9+
{
10+
use EventRules;
11+
12+
public function rules(): array
13+
{
14+
$eventValidations = $this->minimalRules();
15+
16+
$duplicateValidations = [
17+
'duplicate_tickets' => ['boolean', 'required'],
18+
'duplicate_questions' => ['boolean', 'required'],
19+
'duplicate_settings' => ['boolean', 'required'],
20+
'duplicate_promo_codes' => ['boolean', 'required'],
21+
];
22+
23+
return array_merge($eventValidations, $duplicateValidations);
24+
}
25+
26+
public function messages(): array
27+
{
28+
return $this->eventMessages();
29+
}
30+
}

backend/app/Http/Request/EventSettings/UpdateEventSettingsRequest.php

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
class UpdateEventSettingsRequest extends BaseRequest
1212
{
13+
// @todo these should all be required for the update request. They should only be nullable for the PATCH request
1314
public function rules(): array
1415
{
1516
return [

backend/app/Http/Request/Ticket/UpsertTicketRequest.php

+5-9
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
namespace HiEvents\Http\Request\Ticket;
66

7-
use Illuminate\Validation\Rule;
87
use HiEvents\DomainObjects\Enums\TicketType;
98
use HiEvents\Http\Request\BaseRequest;
109
use HiEvents\Validators\Rules\RulesHelper;
10+
use Illuminate\Validation\Rule;
1111

1212
class UpsertTicketRequest extends BaseRequest
1313
{
@@ -20,16 +20,12 @@ public function rules(): array
2020
'sale_start_date' => 'date|nullable',
2121
'sale_end_date' => 'date|nullable|after:sale_start_date',
2222
'max_per_order' => 'integer|nullable',
23-
'price' => array_merge(RulesHelper::MONEY, [
24-
'required_without:prices',
25-
Rule::requiredIf($this->input('type') !== TicketType::TIERED->name),
26-
]),
27-
'prices' => 'required_without:price|array|required_if:type,' . TicketType::TIERED->name,
28-
'prices.*.price' => RulesHelper::MONEY,
29-
'prices.*.label' => ['nullable', ...RulesHelper::STRING],
23+
'prices' => ['required', 'array'],
24+
'prices.*.price' => [...RulesHelper::MONEY, 'required'],
25+
'prices.*.label' => ['nullable', ...RulesHelper::STRING, 'required_if:type,' . TicketType::TIERED->name],
3026
'prices.*.sale_start_date' => ['date', 'nullable', 'after:sale_start_date'],
3127
'prices.*.sale_end_date' => 'date|nullable|after:prices.*.sale_start_date',
32-
'prices.*.initial_quantity_available' => 'integer|nullable',
28+
'prices.*.initial_quantity_available' => ['integer', 'nullable', 'min:0'],
3329
'prices.*.is_hidden' => ['boolean'],
3430
'description' => 'string|nullable',
3531
'min_per_order' => 'integer|nullable',

backend/app/Models/Event.php

+5
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ public function event_settings(): HasOne
3939
return $this->hasOne(EventSetting::class);
4040
}
4141

42+
public function promo_codes(): HasMany
43+
{
44+
return $this->hasMany(PromoCode::class);
45+
}
46+
4247
public static function boot()
4348
{
4449
parent::boot();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
<?php
2+
3+
namespace HiEvents\Services\Domain\Event;
4+
5+
use HiEvents\DomainObjects\Enums\HomepageBackgroundType;
6+
use HiEvents\DomainObjects\EventDomainObject;
7+
use HiEvents\DomainObjects\EventSettingDomainObject;
8+
use HiEvents\DomainObjects\OrganizerDomainObject;
9+
use HiEvents\Exceptions\OrganizerNotFoundException;
10+
use HiEvents\Helper\DateHelper;
11+
use HiEvents\Helper\IdHelper;
12+
use HiEvents\Repository\Interfaces\EventRepositoryInterface;
13+
use HiEvents\Repository\Interfaces\EventSettingsRepositoryInterface;
14+
use HiEvents\Repository\Interfaces\EventStatisticRepositoryInterface;
15+
use HiEvents\Repository\Interfaces\OrganizerRepositoryInterface;
16+
use Illuminate\Database\DatabaseManager;
17+
use Throwable;
18+
19+
class CreateEventService
20+
{
21+
public function __construct(
22+
private readonly EventRepositoryInterface $eventRepository,
23+
private readonly EventSettingsRepositoryInterface $eventSettingsRepository,
24+
private readonly OrganizerRepositoryInterface $organizerRepository,
25+
private readonly DatabaseManager $databaseManager,
26+
private readonly EventStatisticRepositoryInterface $eventStatisticsRepository,
27+
)
28+
{
29+
}
30+
31+
/**
32+
* @throws Throwable
33+
*/
34+
public function createEvent(
35+
EventDomainObject $eventData,
36+
EventSettingDomainObject $eventSettings = null
37+
): EventDomainObject
38+
{
39+
$this->databaseManager->beginTransaction();
40+
41+
$organizer = $this->getOrganizer(
42+
organizerId: $eventData->getOrganizerId(),
43+
accountId: $eventData->getAccountId()
44+
);
45+
46+
$event = $this->handleEventCreate($eventData);
47+
48+
$this->createEventSettings(
49+
eventSettings: $eventSettings,
50+
event: $event,
51+
organizer: $organizer
52+
);
53+
54+
$this->createEventStatistics($event);
55+
56+
$this->databaseManager->commit();
57+
58+
return $event;
59+
}
60+
61+
/**
62+
* @throws OrganizerNotFoundException
63+
*/
64+
private function getOrganizer(int $organizerId, int $accountId): OrganizerDomainObject
65+
{
66+
$organizer = $this->organizerRepository->findFirstWhere([
67+
'id' => $organizerId,
68+
'account_id' => $accountId,
69+
]);
70+
71+
if ($organizer === null) {
72+
throw new OrganizerNotFoundException(
73+
__('Organizer :id not found', ['id' => $organizerId])
74+
);
75+
}
76+
77+
return $organizer;
78+
}
79+
80+
private function handleEventCreate(EventDomainObject $eventData): EventDomainObject
81+
{
82+
return $this->eventRepository->create([
83+
'title' => $eventData->getTitle(),
84+
'organizer_id' => $eventData->getOrganizerId(),
85+
'start_date' => DateHelper::convertToUTC($eventData->getStartDate(), $eventData->getTimezone()),
86+
'end_date' => $eventData->getEndDate()
87+
? DateHelper::convertToUTC($eventData->getEndDate(), $eventData->getTimezone())
88+
: null,
89+
'description' => $eventData->getDescription(),
90+
'timezone' => $eventData->getTimezone(),
91+
'currency' => $eventData->getCurrency(),
92+
'location_details' => $eventData->getLocationDetails(),
93+
'account_id' => $eventData->getAccountId(),
94+
'user_id' => $eventData->getUserId(),
95+
'status' => $eventData->getStatus(),
96+
'short_id' => IdHelper::randomPrefixedId(IdHelper::EVENT_PREFIX),
97+
'attributes' => $eventData->getAttributes(),
98+
]);
99+
}
100+
101+
private function createEventStatistics(EventDomainObject $event): void
102+
{
103+
$this->eventStatisticsRepository->create([
104+
'event_id' => $event->getId(),
105+
'tickets_sold' => 0,
106+
'sales_total_gross' => 0,
107+
'sales_total_before_additions' => 0,
108+
'total_tax' => 0,
109+
'total_fee' => 0,
110+
'orders_created' => 0,
111+
]);
112+
}
113+
114+
private function createEventSettings(
115+
?EventSettingDomainObject $eventSettings,
116+
EventDomainObject $event,
117+
OrganizerDomainObject $organizer
118+
): void
119+
{
120+
if ($eventSettings !== null) {
121+
$eventSettings->setEventId($event->getId());
122+
$eventSettingsArray = $eventSettings->toArray();
123+
124+
unset($eventSettingsArray['id']);
125+
126+
$this->eventSettingsRepository->create($eventSettingsArray);
127+
128+
return;
129+
}
130+
131+
$this->eventSettingsRepository->create([
132+
'event_id' => $event->getId(),
133+
'homepage_background_color' => '#ffffff',
134+
'homepage_primary_text_color' => '#000000',
135+
'homepage_primary_color' => '#7b5db8',
136+
'homepage_secondary_text_color' => '#ffffff',
137+
'homepage_secondary_color' => '#7b5eb9',
138+
'homepage_background_type' => HomepageBackgroundType::COLOR->name,
139+
'homepage_body_background_color' => '#7a5eb9',
140+
'continue_button_text' => __('Continue'),
141+
'support_email' => $organizer->getEmail(),
142+
]);
143+
}
144+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace HiEvents\Services\Domain\Event\DTO;
4+
5+
use HiEvents\DataTransferObjects\BaseDTO;
6+
7+
class DuplicateEventDataDTO extends BaseDTO
8+
{
9+
public function __construct(
10+
public int $eventId,
11+
public int $accountId,
12+
public string $title,
13+
public string $startDate,
14+
public bool $duplicateTickets = true,
15+
public bool $duplicateQuestions = true,
16+
public bool $duplicateSettings = true,
17+
public bool $duplicatePromoCodes = true,
18+
public ?string $description = null,
19+
public ?string $endDate = null,
20+
)
21+
{
22+
}
23+
}

0 commit comments

Comments
 (0)