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
26 changes: 26 additions & 0 deletions app/Http/Controllers/V1/SuggestionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,21 @@
use App\Http\Requests\SuggestionRequest;
use App\Models\Suggestion;
use App\Models\Trip;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;

class SuggestionController extends Controller
{
/**
* Store a newly created resource in storage.
*
* @throws AuthorizationException
*/
public function store(Trip $trip, SuggestionRequest $suggestionRequest): RedirectResponse
{
Gate::authorize('view', $trip);
$suggestion = [
'description' => $suggestionRequest['description'],
'user_id' => auth()->id(),
Expand All @@ -28,8 +33,14 @@ public function store(Trip $trip, SuggestionRequest $suggestionRequest): Redirec
return redirect()->route('trips.show', ['trip' => $trip]);
}

/**
* This can and should be moved to its own controller
*
* @throws AuthorizationException
*/
public function vote(Suggestion $suggestion, Request $request): RedirectResponse
{
Gate::authorize('view', $suggestion->trip);
$validated = $request->validate([
'type' => 'required|in:up,down',
]);
Expand All @@ -41,4 +52,19 @@ public function vote(Suggestion $suggestion, Request $request): RedirectResponse

return redirect()->back();
}

/**
* @throws AuthorizationException
*/
public function status(Suggestion $suggestion, Request $request): RedirectResponse
{
Gate::authorize('update', $suggestion->trip);
$validated = $request->validate([
'type' => 'required|in:approved,rejected',
]);

$suggestion->update(['status' => $validated['type']]);

return redirect()->back();
}
}
9 changes: 9 additions & 0 deletions app/Http/Controllers/V1/TripController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use App\Http\Requests\TripRequest;
use App\Models\Trip;
use App\Models\User;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Gate;
Expand Down Expand Up @@ -58,9 +59,12 @@ public function store(TripRequest $tripRequest): RedirectResponse

/**
* Display the specified resource.
*
* @throws AuthorizationException
*/
public function show(Trip $trip): View
{
Gate::authorize('view', $trip);
$data = $trip->load([
'suggestions' => function ($query) {
$query->withCount([
Expand All @@ -72,13 +76,16 @@ public function show(Trip $trip): View
},
]);
},
'users:name',
]);

return view('trips.show', compact('data'));
}

/**
* Show the form for editing the specified resource.
*
* @throws AuthorizationException
*/
public function edit(Trip $trip): View
{
Expand All @@ -94,6 +101,8 @@ public function edit(Trip $trip): View

/**
* Update the specified resource in storage.
*
* @throws AuthorizationException
*/
public function update(TripRequest $tripRequest, Trip $trip): RedirectResponse
{
Expand Down
11 changes: 11 additions & 0 deletions app/Policies/TripPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ public function viewAny(User $user): bool
*/
public function view(User $user, Trip $trip): bool
{
// if i own the trip, im allowed
if ($user->id === $trip->owner_id) {
return true;
}

// if im part of the trip, i should also be allowed
if ($trip->users->contains(auth()->id())) {
return true;
}

// else i have no business here
return false;
}

Expand Down
43 changes: 33 additions & 10 deletions resources/views/trips/show.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,33 @@ class="inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent

<div class="flex flex-col gap-y-3 mt-3">
@foreach($data->suggestions as $suggestion)
<div class="p-2 border-gray-500 border rounded hover:bg-gray-100 flex gap-2">
<div

@class([
'p-2 flex border-gray-500 border rounded hover:bg-gray-100 flex gap-2' => is_null($suggestion->status),
'p-2 flex gap-2 border-green-500 border rounded bg-green-100 hover:bg-green-300 font-bold shadow-lg shadow-green-500/50 text-green-950' => $suggestion->status == 'approved',
'p-2 flex gap-2 border-red-500 border rounded bg-red-50 font-italic line-through opacity-50 shadow-lg shadow-red-500/50 text-red-950' => $suggestion->status == 'rejected'
])
>
<div class="flex gap-x-2">
<a href="{{ route('suggestions.vote', $suggestion) }}?type=up">
<a
@if(is_null($suggestion->status))
href="{{ route('suggestions.vote', $suggestion) }}?type=up"
@endif
>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 18.75 7.5-7.5 7.5 7.5" />
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 7.5-7.5 7.5 7.5" />
<path stroke-linecap="round" stroke-linejoin="round" d="M6.633 10.25c.806 0 1.533-.446 2.031-1.08a9.041 9.041 0 0 1 2.861-2.4c.723-.384 1.35-.956 1.653-1.715a4.498 4.498 0 0 0 .322-1.672V2.75a.75.75 0 0 1 .75-.75 2.25 2.25 0 0 1 2.25 2.25c0 1.152-.26 2.243-.723 3.218-.266.558.107 1.282.725 1.282m0 0h3.126c1.026 0 1.945.694 2.054 1.715.045.422.068.85.068 1.285a11.95 11.95 0 0 1-2.649 7.521c-.388.482-.987.729-1.605.729H13.48c-.483 0-.964-.078-1.423-.23l-3.114-1.04a4.501 4.501 0 0 0-1.423-.23H5.904m10.598-9.75H14.25M5.904 18.5c.083.205.173.405.27.602.197.4-.078.898-.523.898h-.908c-.889 0-1.713-.518-1.972-1.368a12 12 0 0 1-.521-3.507c0-1.553.295-3.036.831-4.398C3.387 9.953 4.167 9.5 5 9.5h1.053c.472 0 .745.556.5.96a8.958 8.958 0 0 0-1.302 4.665c0 1.194.232 2.333.654 3.375Z" />
</svg>

</a>
<span>{{ $suggestion->up_votes_count }}</span>
<a href="{{ route('suggestions.vote', $suggestion) }}?type=down">
<span> {{ $suggestion->up_votes_count }}</span>
<a
@if(is_null($suggestion->status))
href="{{ route('suggestions.vote', $suggestion) }}?type=down"
@endif
>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 5.25 7.5 7.5 7.5-7.5m-15 6 7.5 7.5 7.5-7.5" />
<path stroke-linecap="round" stroke-linejoin="round" d="M7.498 15.25H4.372c-1.026 0-1.945-.694-2.054-1.715a12.137 12.137 0 0 1-.068-1.285c0-2.848.992-5.464 2.649-7.521C5.287 4.247 5.886 4 6.504 4h4.016a4.5 4.5 0 0 1 1.423.23l3.114 1.04a4.5 4.5 0 0 0 1.423.23h1.294M7.498 15.25c.618 0 .991.724.725 1.282A7.471 7.471 0 0 0 7.5 19.75 2.25 2.25 0 0 0 9.75 22a.75.75 0 0 0 .75-.75v-.633c0-.573.11-1.14.322-1.672.304-.76.93-1.33 1.653-1.715a9.04 9.04 0 0 0 2.86-2.4c.498-.634 1.226-1.08 2.032-1.08h.384m-10.253 1.5H9.7m8.075-9.75c.01.05.027.1.05.148.593 1.2.925 2.55.925 3.977 0 1.487-.36 2.89-.999 4.125m.023-8.25c-.076-.365.183-.75.575-.75h.908c.889 0 1.713.518 1.972 1.368.339 1.11.521 2.287.521 3.507 0 1.553-.295 3.036-.831 4.398-.306.774-1.086 1.227-1.918 1.227h-1.053c-.472 0-.745-.556-.5-.96a8.95 8.95 0 0 0 .303-.54" />
</svg>
</a>
<span>{{ $suggestion->down_votes_count }}</span>
Expand All @@ -92,12 +107,20 @@ class="inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent
{{ $suggestion->description }}
</p>
@can('update', $data)
<div>
<div class="flex gap-x-3">
<span>
Approve
<a href="{{ route('suggestions.status', $suggestion) }}?type=approved">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12c0 1.268-.63 2.39-1.593 3.068a3.745 3.745 0 0 1-1.043 3.296 3.745 3.745 0 0 1-3.296 1.043A3.745 3.745 0 0 1 12 21c-1.268 0-2.39-.63-3.068-1.593a3.746 3.746 0 0 1-3.296-1.043 3.745 3.745 0 0 1-1.043-3.296A3.745 3.745 0 0 1 3 12c0-1.268.63-2.39 1.593-3.068a3.745 3.745 0 0 1 1.043-3.296 3.746 3.746 0 0 1 3.296-1.043A3.746 3.746 0 0 1 12 3c1.268 0 2.39.63 3.068 1.593a3.746 3.746 0 0 1 3.296 1.043 3.746 3.746 0 0 1 1.043 3.296A3.745 3.745 0 0 1 21 12Z" />
</svg>
</a>
</span>
<span>
Reject
<a href="{{ route('suggestions.status', $suggestion) }}?type=rejected">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
<path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
</svg>
</a>
</span>
</div>
@endcan
Expand Down
1 change: 1 addition & 0 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
Route::resource('trips', TripController::class)->except(['destroy']);
Route::resource('trips.suggestions', SuggestionController::class)->only(['store']);
Route::get('/suggestions/{suggestion}/vote', [SuggestionController::class, 'vote'])->name('suggestions.vote');
Route::get('/suggestions/{suggestion}/status', [SuggestionController::class, 'status'])->name('suggestions.status');
});

require __DIR__.'/auth.php';