feat: Implement event management functionality with API endpoints and validation
This commit is contained in:
31
app/Domains/Event/Controllers/AdminApp/EventController.php
Normal file
31
app/Domains/Event/Controllers/AdminApp/EventController.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Event\Controllers\AdminApp;
|
||||
|
||||
use App\Domains\Event\Requests\UpdateEventRequest;
|
||||
use App\Domains\Event\Resources\EventResource;
|
||||
use App\Domains\Event\Services\EventService;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class EventController extends Controller
|
||||
{
|
||||
public function __construct(protected EventService $eventService) {}
|
||||
|
||||
public function show(Request $request): EventResource
|
||||
{
|
||||
return EventResource::make(
|
||||
$this->eventService->activeForTenant($request->user()->tenant()->firstOrFail())
|
||||
);
|
||||
}
|
||||
|
||||
public function update(UpdateEventRequest $request): EventResource
|
||||
{
|
||||
return EventResource::make(
|
||||
$this->eventService->updateActiveForTenant(
|
||||
$request->user()->tenant()->firstOrFail(),
|
||||
$request->validated()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
60
app/Domains/Event/Requests/UpdateEventRequest.php
Normal file
60
app/Domains/Event/Requests/UpdateEventRequest.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Event\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\Validator;
|
||||
|
||||
class UpdateEventRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'title' => ['required', 'string', 'max:255'],
|
||||
'location' => ['required', 'string', 'max:255'],
|
||||
'dates' => ['required', 'array', 'min:1'],
|
||||
'dates.*' => ['required', 'array:date,start_time,end_time'],
|
||||
'dates.*.date' => ['required', 'date_format:Y-m-d', 'distinct'],
|
||||
'dates.*.start_time' => ['required', 'date_format:H:i'],
|
||||
'dates.*.end_time' => ['required', 'date_format:H:i'],
|
||||
'social_media' => ['sometimes', 'array'],
|
||||
'social_media.*' => ['required', 'array:code,url,orden'],
|
||||
'social_media.*.code' => [
|
||||
'required',
|
||||
'string',
|
||||
'distinct',
|
||||
Rule::exists('social_media', 'code'),
|
||||
],
|
||||
'social_media.*.url' => ['required', 'url', 'max:2048'],
|
||||
'social_media.*.orden' => ['sometimes', 'integer', 'min:0', 'distinct'],
|
||||
'contact' => ['sometimes', 'array:whatsapp_url,instagram_url,facebook_url'],
|
||||
'contact.whatsapp_url' => ['nullable', 'url', 'max:2048'],
|
||||
'contact.instagram_url' => ['nullable', 'url', 'max:2048'],
|
||||
'contact.facebook_url' => ['nullable', 'url', 'max:2048'],
|
||||
];
|
||||
}
|
||||
|
||||
/** @return array<int, callable> */
|
||||
public function after(): array
|
||||
{
|
||||
return [
|
||||
function (Validator $validator): void {
|
||||
$input = $this->all();
|
||||
|
||||
if (! array_key_exists('social_media', $input) && ! array_key_exists('contact', $input)) {
|
||||
$validator->errors()->add(
|
||||
'social_media',
|
||||
'The social media field is required.'
|
||||
);
|
||||
}
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
39
app/Domains/Event/Resources/EventResource.php
Normal file
39
app/Domains/Event/Resources/EventResource.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Event\Resources;
|
||||
|
||||
use App\Domains\Event\Models\Event;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
/** @mixin Event */
|
||||
class EventResource extends JsonResource
|
||||
{
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
$socialMedia = $this->tenant->socialMedia->keyBy('code');
|
||||
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'title' => $this->name,
|
||||
'location' => $this->address,
|
||||
'dates' => $this->dates->map(fn ($eventDate): array => [
|
||||
'id' => $eventDate->id,
|
||||
'date' => $eventDate->date->format('Y-m-d'),
|
||||
'start_time' => substr($eventDate->time_start, 0, 5),
|
||||
'end_time' => substr($eventDate->time_end, 0, 5),
|
||||
])->values(),
|
||||
'social_media' => $this->tenant->socialMedia->map(fn ($item): array => [
|
||||
'code' => $item->code,
|
||||
'url' => $item->pivot->url,
|
||||
'orden' => $item->pivot->orden,
|
||||
])->values(),
|
||||
'contact' => [
|
||||
'whatsapp_url' => $socialMedia->get('whatsapp')?->pivot->url,
|
||||
'instagram_url' => $socialMedia->get('instagram')?->pivot->url,
|
||||
'facebook_url' => $socialMedia->get('facebook')?->pivot->url,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
120
app/Domains/Event/Services/EventService.php
Normal file
120
app/Domains/Event/Services/EventService.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Event\Services;
|
||||
|
||||
use App\Domains\Event\Models\Event;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class EventService
|
||||
{
|
||||
private const CONTACT_CODES = [
|
||||
'whatsapp_url' => 'whatsapp',
|
||||
'instagram_url' => 'instagram',
|
||||
'facebook_url' => 'facebook',
|
||||
];
|
||||
|
||||
public function activeForTenant(Tenant $tenant): Event
|
||||
{
|
||||
return $tenant->events()
|
||||
->whereKey($tenant->active_event_id)
|
||||
->with(['dates', 'tenant.socialMedia'])
|
||||
->firstOrFail();
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public function updateActiveForTenant(Tenant $tenant, array $data): Event
|
||||
{
|
||||
return DB::transaction(function () use ($tenant, $data): Event {
|
||||
$tenant = Tenant::query()->whereKey($tenant->getKey())->lockForUpdate()->firstOrFail();
|
||||
$event = $tenant->active_event_id === null
|
||||
? $tenant->events()->create([
|
||||
'name' => $data['title'],
|
||||
'address' => $data['location'],
|
||||
])
|
||||
: $tenant->events()
|
||||
->whereKey($tenant->active_event_id)
|
||||
->lockForUpdate()
|
||||
->firstOrFail();
|
||||
|
||||
$event->update([
|
||||
'name' => $data['title'],
|
||||
'address' => $data['location'],
|
||||
]);
|
||||
|
||||
if ($tenant->active_event_id === null) {
|
||||
$tenant->update(['active_event_id' => $event->id]);
|
||||
}
|
||||
|
||||
$this->syncDates($event, $data['dates']);
|
||||
if (array_key_exists('social_media', $data)) {
|
||||
$this->syncSocialMedia($tenant, $data['social_media']);
|
||||
} else {
|
||||
$this->syncLegacyContact($tenant, $data['contact']);
|
||||
}
|
||||
|
||||
return $event->load(['dates', 'tenant.socialMedia']);
|
||||
});
|
||||
}
|
||||
|
||||
/** @param array<int, array{date: string, start_time: string, end_time: string}> $dates */
|
||||
private function syncDates(Event $event, array $dates): void
|
||||
{
|
||||
$existingDates = $event->dates()->get()->values();
|
||||
|
||||
foreach (array_values($dates) as $index => $date) {
|
||||
$attributes = [
|
||||
'date' => $date['date'],
|
||||
'time_start' => $date['start_time'],
|
||||
'time_end' => $date['end_time'],
|
||||
];
|
||||
|
||||
$existingDate = $existingDates->get($index);
|
||||
|
||||
if ($existingDate) {
|
||||
$existingDate->update($attributes);
|
||||
} else {
|
||||
$event->dates()->create($attributes);
|
||||
}
|
||||
}
|
||||
|
||||
$existingDates->slice(count($dates))->each->delete();
|
||||
$event->unsetRelation('dates');
|
||||
}
|
||||
|
||||
/** @param array<string, string|null> $contact */
|
||||
private function syncLegacyContact(Tenant $tenant, array $contact): void
|
||||
{
|
||||
foreach (self::CONTACT_CODES as $field => $code) {
|
||||
$url = $contact[$field] ?? null;
|
||||
|
||||
if ($url === null || $url === '') {
|
||||
$tenant->socialMedia()->detach($code);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$tenant->socialMedia()->syncWithoutDetaching([
|
||||
$code => ['url' => $url],
|
||||
]);
|
||||
}
|
||||
|
||||
$tenant->unsetRelation('socialMedia');
|
||||
}
|
||||
|
||||
/** @param array<int, array{code: string, url: string, orden?: int}> $socialMedia */
|
||||
private function syncSocialMedia(Tenant $tenant, array $socialMedia): void
|
||||
{
|
||||
$associations = [];
|
||||
|
||||
foreach (array_values($socialMedia) as $index => $item) {
|
||||
$associations[$item['code']] = [
|
||||
'url' => $item['url'],
|
||||
'orden' => $item['orden'] ?? $index,
|
||||
];
|
||||
}
|
||||
|
||||
$tenant->socialMedia()->sync($associations);
|
||||
$tenant->unsetRelation('socialMedia');
|
||||
}
|
||||
}
|
||||
11
app/Domains/Event/routes/adminapp.php
Normal file
11
app/Domains/Event/routes/adminapp.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
use App\Domains\Event\Controllers\AdminApp\EventController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::prefix('v1/adminapp/tenant')
|
||||
->middleware(['auth:sanctum', 'adminapp.tenant'])
|
||||
->group(function (): void {
|
||||
Route::get('event', [EventController::class, 'show']);
|
||||
Route::put('event', [EventController::class, 'update']);
|
||||
});
|
||||
3
app/Domains/Event/routes/api.php
Normal file
3
app/Domains/Event/routes/api.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
require __DIR__.'/adminapp.php';
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Forms\Controllers\AdminApp;
|
||||
|
||||
use App\Domains\Forms\Resources\EventFormResource;
|
||||
use App\Domains\Forms\Services\EventFormService;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class EventFormController extends Controller
|
||||
{
|
||||
public function __construct(protected EventFormService $eventFormService) {}
|
||||
|
||||
public function __invoke(): EventFormResource
|
||||
{
|
||||
return EventFormResource::make(
|
||||
$this->eventFormService->get()
|
||||
);
|
||||
}
|
||||
}
|
||||
19
app/Domains/Forms/Resources/EventFormResource.php
Normal file
19
app/Domains/Forms/Resources/EventFormResource.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Forms\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class EventFormResource extends JsonResource
|
||||
{
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'social_media' => SocialMediaOptionResource::collection(
|
||||
$this->resource['social_media']
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
21
app/Domains/Forms/Resources/SocialMediaOptionResource.php
Normal file
21
app/Domains/Forms/Resources/SocialMediaOptionResource.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Forms\Resources;
|
||||
|
||||
use App\Domains\Tenant\Models\SocialMedia;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
/** @mixin SocialMedia */
|
||||
class SocialMediaOptionResource extends JsonResource
|
||||
{
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'code' => $this->code,
|
||||
'name' => $this->name,
|
||||
'icon' => $this->icon,
|
||||
];
|
||||
}
|
||||
}
|
||||
17
app/Domains/Forms/Services/EventFormService.php
Normal file
17
app/Domains/Forms/Services/EventFormService.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Forms\Services;
|
||||
|
||||
use App\Domains\Tenant\Models\SocialMedia;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
class EventFormService
|
||||
{
|
||||
/** @return array{social_media: Collection<int, SocialMedia>} */
|
||||
public function get(): array
|
||||
{
|
||||
return [
|
||||
'social_media' => SocialMedia::query()->orderBy('id')->get(),
|
||||
];
|
||||
}
|
||||
}
|
||||
10
app/Domains/Forms/routes/adminapp.php
Normal file
10
app/Domains/Forms/routes/adminapp.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
use App\Domains\Forms\Controllers\AdminApp\EventFormController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::prefix('v1/adminapp/forms')
|
||||
->middleware(['auth:sanctum', 'adminapp.tenant'])
|
||||
->group(function (): void {
|
||||
Route::get('event', EventFormController::class);
|
||||
});
|
||||
3
app/Domains/Forms/routes/api.php
Normal file
3
app/Domains/Forms/routes/api.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
require __DIR__.'/adminapp.php';
|
||||
@@ -10,3 +10,5 @@ require __DIR__.'/../app/Domains/Tenant/routes/api.php';
|
||||
require __DIR__.'/../app/Domains/Integration/routes/api.php';
|
||||
require __DIR__.'/../app/Domains/Menu/routes/api.php';
|
||||
require __DIR__.'/../app/Domains/Ticket/routes/api.php';
|
||||
require __DIR__.'/../app/Domains/Event/routes/api.php';
|
||||
require __DIR__.'/../app/Domains/Forms/routes/api.php';
|
||||
|
||||
270
tests/Feature/Event/AdminAppEventControllerTest.php
Normal file
270
tests/Feature/Event/AdminAppEventControllerTest.php
Normal file
@@ -0,0 +1,270 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Event;
|
||||
|
||||
use App\Domains\Auth\Models\User;
|
||||
use App\Domains\Authorization\Enums\RoleCode;
|
||||
use App\Domains\Event\Models\Event;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use App\Domains\Tenant\Models\WebsiteType;
|
||||
use Database\Seeders\AuthorizationSeeder;
|
||||
use Database\Seeders\SocialMediaSeeder;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AdminAppEventControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->seed([AuthorizationSeeder::class, SocialMediaSeeder::class]);
|
||||
WebsiteType::query()->create([
|
||||
'codigo' => 'onticket',
|
||||
'nombre' => 'OnTicket',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_authentication_is_required(): void
|
||||
{
|
||||
$this->getJson('/api/v1/adminapp/tenant/event')->assertUnauthorized();
|
||||
$this->putJson('/api/v1/adminapp/tenant/event', $this->eventPayload())->assertUnauthorized();
|
||||
}
|
||||
|
||||
public function test_an_adminapp_user_can_create_the_active_event_and_contact_information(): void
|
||||
{
|
||||
$tenant = $this->createTenant('acme');
|
||||
Sanctum::actingAs($this->createAdminAppUser($tenant));
|
||||
|
||||
$response = $this->putJson('/api/v1/adminapp/tenant/event', $this->eventPayload())
|
||||
->assertOk()
|
||||
->assertJsonPath('data.title', 'Festival Acme')
|
||||
->assertJsonPath('data.location', 'Predio Ferial, Rosario')
|
||||
->assertJsonPath('data.dates.0.date', '2026-10-09')
|
||||
->assertJsonPath('data.dates.0.start_time', '09:00')
|
||||
->assertJsonPath('data.dates.0.end_time', '18:30')
|
||||
->assertJsonPath('data.contact.whatsapp_url', 'https://wa.me/5493415550101')
|
||||
->assertJsonPath('data.contact.instagram_url', 'https://instagram.com/acme')
|
||||
->assertJsonPath('data.contact.facebook_url', null);
|
||||
|
||||
$eventId = $response->json('data.id');
|
||||
|
||||
$this->assertDatabaseHas('events', [
|
||||
'id' => $eventId,
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'name' => 'Festival Acme',
|
||||
'address' => 'Predio Ferial, Rosario',
|
||||
]);
|
||||
$this->assertSame($eventId, $tenant->fresh()->active_event_id);
|
||||
$this->assertDatabaseHas('event_dates', [
|
||||
'event_id' => $eventId,
|
||||
'date' => '2026-10-09',
|
||||
'time_start' => '09:00:00',
|
||||
'time_end' => '18:30:00',
|
||||
]);
|
||||
$this->assertDatabaseHas('tenant_social_media', [
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'social_media_code' => 'whatsapp',
|
||||
'url' => 'https://wa.me/5493415550101',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_an_adminapp_user_can_read_only_its_tenant_active_event(): void
|
||||
{
|
||||
$tenant = $this->createTenant('acme');
|
||||
$otherTenant = $this->createTenant('other');
|
||||
$this->createActiveEvent($tenant, 'Acme Event');
|
||||
$this->createActiveEvent($otherTenant, 'Other Event');
|
||||
Sanctum::actingAs($this->createAdminAppUser($tenant));
|
||||
|
||||
$this->getJson('/api/v1/adminapp/tenant/event')
|
||||
->assertOk()
|
||||
->assertJsonPath('data.title', 'Acme Event')
|
||||
->assertJsonMissing(['title' => 'Other Event']);
|
||||
}
|
||||
|
||||
public function test_reading_a_tenant_without_an_active_event_returns_not_found(): void
|
||||
{
|
||||
$tenant = $this->createTenant('acme');
|
||||
Sanctum::actingAs($this->createAdminAppUser($tenant));
|
||||
|
||||
$this->getJson('/api/v1/adminapp/tenant/event')->assertNotFound();
|
||||
}
|
||||
|
||||
public function test_updating_reuses_the_active_event_and_synchronizes_dates_and_contact(): void
|
||||
{
|
||||
$tenant = $this->createTenant('acme');
|
||||
$event = $this->createActiveEvent($tenant, 'Old Event');
|
||||
$firstDate = $event->dates()->create([
|
||||
'date' => '2026-10-01',
|
||||
'time_start' => '08:00',
|
||||
'time_end' => '12:00',
|
||||
]);
|
||||
$removedDate = $event->dates()->create([
|
||||
'date' => '2026-10-02',
|
||||
'time_start' => '08:00',
|
||||
'time_end' => '12:00',
|
||||
]);
|
||||
$tenant->socialMedia()->attach('facebook', [
|
||||
'url' => 'https://facebook.com/old',
|
||||
'orden' => 2,
|
||||
]);
|
||||
$tenant->socialMedia()->attach('linkedin', [
|
||||
'url' => 'https://linkedin.com/company/acme',
|
||||
'orden' => 3,
|
||||
]);
|
||||
Sanctum::actingAs($this->createAdminAppUser($tenant));
|
||||
|
||||
$payload = $this->eventPayload();
|
||||
$payload['dates'] = [[
|
||||
'date' => '2026-11-15',
|
||||
'start_time' => '10:00',
|
||||
'end_time' => '20:00',
|
||||
]];
|
||||
|
||||
$this->putJson('/api/v1/adminapp/tenant/event', $payload)
|
||||
->assertOk()
|
||||
->assertJsonPath('data.id', $event->id)
|
||||
->assertJsonPath('data.dates.0.id', $firstDate->id)
|
||||
->assertJsonPath('data.contact.facebook_url', null);
|
||||
|
||||
$this->assertDatabaseHas('event_dates', [
|
||||
'id' => $firstDate->id,
|
||||
'date' => '2026-11-15',
|
||||
]);
|
||||
$this->assertDatabaseMissing('event_dates', ['id' => $removedDate->id]);
|
||||
$this->assertDatabaseMissing('tenant_social_media', [
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'social_media_code' => 'facebook',
|
||||
]);
|
||||
$this->assertDatabaseHas('tenant_social_media', [
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'social_media_code' => 'linkedin',
|
||||
'url' => 'https://linkedin.com/company/acme',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_update_validates_event_dates_and_contact_urls(): void
|
||||
{
|
||||
$tenant = $this->createTenant('acme');
|
||||
Sanctum::actingAs($this->createAdminAppUser($tenant));
|
||||
|
||||
$this->putJson('/api/v1/adminapp/tenant/event', [
|
||||
'title' => '',
|
||||
'location' => '',
|
||||
'dates' => [
|
||||
['date' => '09/10/2026', 'start_time' => '9am', 'end_time' => '18:00'],
|
||||
['date' => '09/10/2026', 'start_time' => '09:00', 'end_time' => '18:00'],
|
||||
],
|
||||
'contact' => [
|
||||
'whatsapp_url' => 'not-a-url',
|
||||
'instagram_url' => null,
|
||||
'facebook_url' => null,
|
||||
],
|
||||
])
|
||||
->assertUnprocessable()
|
||||
->assertJsonValidationErrors([
|
||||
'title',
|
||||
'location',
|
||||
'dates.0.date',
|
||||
'dates.0.start_time',
|
||||
'dates.1.date',
|
||||
'contact.whatsapp_url',
|
||||
]);
|
||||
|
||||
$this->assertDatabaseCount('events', 0);
|
||||
}
|
||||
|
||||
public function test_social_media_accepts_any_registered_code_and_rejects_unknown_codes(): void
|
||||
{
|
||||
$tenant = $this->createTenant('acme');
|
||||
Sanctum::actingAs($this->createAdminAppUser($tenant));
|
||||
$payload = $this->eventPayload();
|
||||
unset($payload['contact']);
|
||||
$payload['social_media'] = [[
|
||||
'code' => 'linkedin',
|
||||
'url' => 'https://linkedin.com/company/acme',
|
||||
'orden' => 5,
|
||||
]];
|
||||
|
||||
$this->putJson('/api/v1/adminapp/tenant/event', $payload)
|
||||
->assertOk()
|
||||
->assertJsonPath('data.social_media.0.code', 'linkedin')
|
||||
->assertJsonPath('data.social_media.0.url', 'https://linkedin.com/company/acme')
|
||||
->assertJsonPath('data.social_media.0.orden', 5);
|
||||
|
||||
$this->assertDatabaseHas('tenant_social_media', [
|
||||
'tenant_code' => $tenant->codigo,
|
||||
'social_media_code' => 'linkedin',
|
||||
'url' => 'https://linkedin.com/company/acme',
|
||||
'orden' => 5,
|
||||
]);
|
||||
|
||||
$payload['social_media'][0]['code'] = 'unknown';
|
||||
|
||||
$this->putJson('/api/v1/adminapp/tenant/event', $payload)
|
||||
->assertUnprocessable()
|
||||
->assertJsonValidationErrors(['social_media.0.code']);
|
||||
}
|
||||
|
||||
public function test_a_customer_cannot_manage_an_event(): void
|
||||
{
|
||||
Sanctum::actingAs(User::factory()->create([
|
||||
'rol_codigo' => RoleCode::User->value,
|
||||
'tenant_codigo' => null,
|
||||
]));
|
||||
|
||||
$this->getJson('/api/v1/adminapp/tenant/event')->assertForbidden();
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
private function eventPayload(): array
|
||||
{
|
||||
return [
|
||||
'title' => 'Festival Acme',
|
||||
'location' => 'Predio Ferial, Rosario',
|
||||
'dates' => [[
|
||||
'date' => '2026-10-09',
|
||||
'start_time' => '09:00',
|
||||
'end_time' => '18:30',
|
||||
]],
|
||||
'contact' => [
|
||||
'whatsapp_url' => 'https://wa.me/5493415550101',
|
||||
'instagram_url' => 'https://instagram.com/acme',
|
||||
'facebook_url' => null,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function createTenant(string $code): Tenant
|
||||
{
|
||||
return Tenant::query()->create([
|
||||
'codigo' => $code,
|
||||
'nombre' => ucfirst($code),
|
||||
'dominio' => "{$code}.test",
|
||||
'website_type_code' => 'onticket',
|
||||
]);
|
||||
}
|
||||
|
||||
private function createAdminAppUser(Tenant $tenant): User
|
||||
{
|
||||
return User::factory()->create([
|
||||
'rol_codigo' => RoleCode::AdminApp->value,
|
||||
'tenant_codigo' => $tenant->codigo,
|
||||
]);
|
||||
}
|
||||
|
||||
private function createActiveEvent(Tenant $tenant, string $name): Event
|
||||
{
|
||||
$event = $tenant->events()->create([
|
||||
'name' => $name,
|
||||
'address' => 'Rosario',
|
||||
]);
|
||||
$tenant->update(['active_event_id' => $event->id]);
|
||||
|
||||
return $event;
|
||||
}
|
||||
}
|
||||
66
tests/Feature/Forms/AdminAppEventFormControllerTest.php
Normal file
66
tests/Feature/Forms/AdminAppEventFormControllerTest.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Forms;
|
||||
|
||||
use App\Domains\Auth\Models\User;
|
||||
use App\Domains\Authorization\Enums\RoleCode;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use App\Domains\Tenant\Models\WebsiteType;
|
||||
use Database\Seeders\AuthorizationSeeder;
|
||||
use Database\Seeders\SocialMediaSeeder;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AdminAppEventFormControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->seed([AuthorizationSeeder::class, SocialMediaSeeder::class]);
|
||||
WebsiteType::query()->create([
|
||||
'codigo' => 'onticket',
|
||||
'nombre' => 'OnTicket',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_authentication_is_required(): void
|
||||
{
|
||||
$this->getJson('/api/v1/adminapp/forms/event')->assertUnauthorized();
|
||||
}
|
||||
|
||||
public function test_an_adminapp_user_can_get_the_event_form(): void
|
||||
{
|
||||
$tenant = Tenant::query()->create([
|
||||
'codigo' => 'acme',
|
||||
'nombre' => 'Acme',
|
||||
'dominio' => 'acme.test',
|
||||
'website_type_code' => 'onticket',
|
||||
]);
|
||||
Sanctum::actingAs(User::factory()->create([
|
||||
'rol_codigo' => RoleCode::AdminApp->value,
|
||||
'tenant_codigo' => $tenant->codigo,
|
||||
]));
|
||||
|
||||
$this->getJson('/api/v1/adminapp/forms/event')
|
||||
->assertOk()
|
||||
->assertJsonCount(4, 'data.social_media')
|
||||
->assertJsonPath('data.social_media.0.code', 'facebook')
|
||||
->assertJsonPath('data.social_media.0.name', 'Facebook')
|
||||
->assertJsonPath('data.social_media.0.icon', 'fa-brands fa-facebook')
|
||||
->assertJsonPath('data.social_media.3.code', 'linkedin');
|
||||
}
|
||||
|
||||
public function test_a_customer_cannot_get_the_event_form(): void
|
||||
{
|
||||
Sanctum::actingAs(User::factory()->create([
|
||||
'rol_codigo' => RoleCode::User->value,
|
||||
'tenant_codigo' => null,
|
||||
]));
|
||||
|
||||
$this->getJson('/api/v1/adminapp/forms/event')->assertForbidden();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user