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
6 changes: 5 additions & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ module.exports = {
plugins: ["@typescript-eslint"],
rules: {
"vue/multi-word-component-names": "off",
// Typescript does this for us
"vue/component-api-style": ["warn", ["script-setup"]],
"vue/component-name-in-template-casing": ["error", "PascalCase"],
"vue/define-props-declaration": ["error", "type-based"],
"vue/no-undef-components": "error",
"vue/no-useless-mustaches": "error",
},
};
4 changes: 3 additions & 1 deletion app/Http/Controllers/CRUDController.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ public function index(Request $request)
}
}

$items = $query->paginate()->withQueryString();
$filteredQuery = collect($request->query())
->intersectByKeys(['sort_by' => '', 'sort_dir' => '', 'query' => '', 'filter_by' => '']);
$items = $query->paginate()->appends($filteredQuery->toArray());

$with = $this->with();

Expand Down
9 changes: 6 additions & 3 deletions app/Http/Controllers/EventController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ public function show(Request $request, Event $event)

$canJoin = $isEnrolled && $user->can('join', $event);

$hasJoined = $event->enrollments()->where('participant_id', $user->usertype_id)->exists();

return Inertia::render('Event', [
'event' => $event->load(['users', 'event_day', 'enrollments']),
'isEnrolled' => $isEnrolled,
'hasJoined' => $hasJoined,
'canJoin' => $canJoin,
]);
}
Expand All @@ -39,7 +42,7 @@ public function join(Request $request, Event $event)

// FIXME: when attempting to join multiple times in a row, only the first attempt triggers the banner.
if ($user->cannot('join', $event)) {
return redirect()->back()->dangerBanner('Não pode inscrever-se neste evento.');
return redirect()->back()->dangerBanner('Não podes inscrever-te neste evento');
}

$edition = $request->input('edition');
Expand All @@ -51,11 +54,11 @@ public function join(Request $request, Event $event)
$currentEnrollment = $user->usertype->enrollments()->where('edition_id', $edition->id)->first(); // we can safely get only the first one because there should only be one.

if ($currentEnrollment === null) {
return redirect()->route('home')->dangerBanner('Não está atualmente inscrito em nenhuma edição. Deve fazê-lo antes de tentar inscrever-se num evento.');
return redirect()->route('home')->dangerBanner('Não estás inscrito nesta edição!');
}

$currentEnrollment->events()->attach($event);

return redirect()->back()->banner("Inscrição no evento '$event->name' realizada com sucesso!");
return redirect()->route('profile.show')->banner('Inscrição realizada com sucesso!');
}
}
10 changes: 7 additions & 3 deletions app/Http/Controllers/QuestCRUDController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

use App\Models\Company;
use App\Models\Edition;
use App\Models\Event;
use App\Models\Quest;
use App\Models\Stand;

class QuestCRUDController extends CRUDController
{
Expand All @@ -15,15 +17,16 @@ class QuestCRUDController extends CRUDController
protected array $rules = [
'name' => 'required|string',
'category' => 'required|string|in:company,talk,workshop,milestone,teambuiling',
'requirement' => 'required|regex:/^(company;[0-9]+)$/',
'requirement' => 'required|regex:/^((stand|event);[0-9]+)$/',
'edition_id' => 'required|exists:editions,id',
];

protected function with(): array
{
return [
'editions' => Edition::all(),
'companies' => Company::with('user')->get(),
'stands' => Stand::all(),
'events' => Event::all(),
];
}

Expand All @@ -34,7 +37,8 @@ protected function created(array $new): ?array
$requirement = explode(';', $new['requirement']);

$requirement_type = match ($requirement[0]) {
'company' => Company::class,
'stand' => Stand::class,
'event' => Event::class,
default => null,
};
$requirement_id = $requirement[1];
Expand Down
28 changes: 28 additions & 0 deletions app/Http/Controllers/QuestController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace App\Http\Controllers;

use App\Models\Participant;
use App\Models\Quest;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;

class QuestController extends Controller
{
public function give(Request $request, Quest $quest)
{
$request->validate([
'quest_code' => 'required|exists:participants,quest_code',
]);

$edition = $request->input('edition');
$participant = Participant::firstWhere('quest_code', $request->get('quest_code'));
$enrollment = $participant->enrollments()->where('edition_id', $edition?->id)->first();

Gate::authorize('give', [$quest, $enrollment]);

$enrollment->quests()->attach($quest);

return redirect()->back()->banner('Quest atribuída com sucesso!');
}
}
38 changes: 16 additions & 22 deletions app/Http/Controllers/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,47 @@

namespace App\Http\Controllers;

use App\Models\Event;
use App\Models\Slot;
use App\Models\Edition;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
use Laravel\Fortify\Features;
use Laravel\Jetstream\Http\Controllers\Inertia\UserProfileController;

class UserController extends UserProfileController
{
/**
* Show the general profile settings screen.
*
* @return \Inertia\Response
*/
public function show(Request $request)
{
$this->validateTwoFactorAuthenticationState($request);

$user = $request->user();

/** @var Edition */
$edition = $request->edition;

if ($edition === null) {
return response('No edition found', 500);
}

$tickets = Event::all();
$slots = Slot::all();

if ($user->isParticipant()) {
$currentEnrollment = $user->usertype->enrollments()->where('edition_id', $edition->id)->first(); // we can safely get only the first one because there should only be one.

if ($currentEnrollment !== null) {
$joinedEvents = $currentEnrollment->events()->get();

$tickets = $tickets->map(function ($event) use ($joinedEvents) {
$event->joined = $joinedEvents->contains($event);

return $event;
});

$slots = Slot::all();
}
$slots = $edition
->slots()
->withCount(['quests as completed_count' => function ($query) {
$query->whereRelation('slots', 'id', DB::raw('slots.id'));
}])
->get();
$tickets = $edition
->events()
->addSelect([
DB::raw('exists(select * from "enrollment_event" where "enrollment_event"."event_id" = "events"."id" and "enrollment_event"."enrollment_id" = '.$currentEnrollment->id.') as "joined"'),
DB::raw('"events".*'),
])
->get();
}

return Inertia::render('Profile/Show', [
'confirmsTwoFactorAuthentication' => Features::optionEnabled(Features::twoFactorAuthentication(), 'confirm'),
'tickets' => $tickets,
'slots' => $slots,
]);
Expand Down
5 changes: 5 additions & 0 deletions app/Models/Edition.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ public function quests(): HasMany
return $this->hasMany(Quest::class);
}

public function slots(): HasManyThrough
{
return $this->hasManyDeep(Slot::class, [Quest::class, 'quest_slot'])->distinct();
}

public function speakers(): HasManyThrough
{
return $this->hasManyDeep(User::class, [EventDay::class, Event::class, 'event_user'])
Expand Down
23 changes: 23 additions & 0 deletions app/Providers/AuthServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
// use Illuminate\Support\Facades\Gate;

use App\Models\Edition;
use App\Models\Enrollment;
use App\Models\Event;
use App\Models\Participant;
use App\Models\Quest;
use App\Models\Stand;
use App\Models\User;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
Expand Down Expand Up @@ -45,5 +49,24 @@ public function boot(): void
$event->enrollments()->count() < $event->capacity // event must not be full
)
));

Gate::define('give', fn (User $user, Quest $quest, Enrollment $enrollment) => (
$enrollment->quests()->where('quest_id', $quest->id)->doesntExist() && // participant must not have the quest
( // either
(
$user->isAdmin() && // user is admin and either
(
$quest->requirement_type === Event::class &&
$enrollment->events()->where('event_id', $quest->requirement_id)->exists()
) || // requirement is an event the user has joined
$quest->requirement_type === Stand::class // or requirement is a stand
) ||
(
$user->isCompany() &&
$quest->requirement_type === Stand::class &&
$quest->requirement->sponsor->company->is($user->usertype)
) // or the user is a company and the requirement is a stand from the same company
)
));
}
}
19 changes: 19 additions & 0 deletions database/factories/AdminFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,32 @@

namespace Database\Factories;

use App\Models\Admin;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Admin>
*/
class AdminFactory extends Factory
{
public function configure(): static
{
return $this->afterMaking(function (Admin $admin) {
if ($admin->user_id !== 0) {
return;
}

$admin->user()->associate(User::factory()->create([
'usertype_id' => -1,
'usertype_type' => Admin::class,
]));
})->afterCreating(function (Admin $admin) {
$admin->user->usertype_id = $admin->id;
$admin->user->save();
});
}

/**
* Define the model's default state.
*
Expand Down
19 changes: 19 additions & 0 deletions database/factories/CompanyFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,33 @@

namespace Database\Factories;

use App\Models\Company;
use App\Models\SocialMedia;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Company>
*/
class CompanyFactory extends Factory
{
public function configure(): static
{
return $this->afterMaking(function (Company $company) {
if ($company->user_id !== 0) {
return;
}

$company->user()->associate(User::factory()->create([
'usertype_id' => -1,
'usertype_type' => Company::class,
]));
})->afterCreating(function (Company $company) {
$company->user->usertype_id = $company->id;
$company->user->save();
});
}

/**
* Define the model's default state.
*
Expand Down
26 changes: 26 additions & 0 deletions database/factories/EnrollmentFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Database\Factories;

use App\Models\Edition;
use App\Models\Participant;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Enrollment>
*/
class EnrollmentFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'edition_id' => Edition::factory(),
'participant_id' => Participant::factory(),
];
}
}
19 changes: 19 additions & 0 deletions database/factories/ParticipantFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,33 @@

namespace Database\Factories;

use App\Models\Participant;
use App\Models\SocialMedia;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Participant>
*/
class ParticipantFactory extends Factory
{
public function configure(): static
{
return $this->afterMaking(function (Participant $participant) {
if ($participant->user_id !== 0) {
return;
}

$participant->user()->associate(User::factory()->create([
'usertype_id' => -1,
'usertype_type' => Participant::class,
]));
})->afterCreating(function (Participant $participant) {
$participant->user->usertype_id = $participant->id;
$participant->user->save();
});
}

/**
* Define the model's default state.
*
Expand Down
Loading