Skip to content

Commit 39e2e60

Browse files
Lee0zJakubKermeszmigroo
authored
#169 - ability to edit and delete opinions for administrator (#201)
* Create event * Add button url * Fix url * Secure backend from unauthorised changes * logic for admin to delete comments * lint * pencil is not displayed for admin * cleaned update opinion method on backend * Fix unnecessary commits and cs * Fix DataImporter.php * Added policies * Added validation and fixed policy * change policy to bool * Change policy logic * fix updating opinion * Fix policy --------- Co-authored-by: JakubKermes <jakubker22@gmail.com> Co-authored-by: zmigroo <patrykzmigro@gmail.com>
1 parent 911b999 commit 39e2e60

File tree

7 files changed

+37
-14
lines changed

7 files changed

+37
-14
lines changed

app/Http/Controllers/CityOpinionController.php

+4-9
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,19 @@
66

77
use App\Http\Requests\CityOpinionRequest;
88
use App\Models\CityOpinion;
9-
use Illuminate\Support\Facades\Auth;
109

1110
class CityOpinionController extends Controller
1211
{
1312
public function store(CityOpinionRequest $request): void
1413
{
15-
$opinion = $request->only(["rating", "content", "city_id"]);
16-
$opinion["user_id"] = Auth::id();
17-
18-
CityOpinion::query()->create($opinion);
14+
$request->user()
15+
->cityOpinions()
16+
->create($request->validated());
1917
}
2018

2119
public function update(CityOpinionRequest $request, CityOpinion $cityOpinion): void
2220
{
23-
$opinion = $request->only(["rating", "content", "city_id"]);
24-
$opinion["user_id"] = Auth::id();
25-
26-
$cityOpinion->update($opinion);
21+
$cityOpinion->update($request->validated());
2722
}
2823

2924
public function destroy(CityOpinion $cityOpinion): void

app/Importers/DataImporter.php

+1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ protected function deleteMissingProviders(string $providerName, array $existingC
9090
->whereNotIn("city_id", $existingCityProviders)
9191
->whereNot("created_by", "admin")
9292
->get();
93+
9394
$cityProvidersToDelete->each(fn($cityProvider) => $cityProvider->delete());
9495
}
9596

app/Policies/CityOpinionPolicy.php

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Policies;
6+
7+
use App\Models\CityOpinion;
8+
use App\Models\User;
9+
10+
class CityOpinionPolicy
11+
{
12+
public function update(User $user, CityOpinion $cityOpinion): bool
13+
{
14+
return $cityOpinion->user_id === $user->id;
15+
}
16+
17+
public function delete(User $user, CityOpinion $cityOpinion): bool
18+
{
19+
return $cityOpinion->user_id === $user->id || $user->hasRole("admin");
20+
}
21+
}

app/Providers/AppServiceProvider.php

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

55
namespace App\Providers;
66

7+
use App\Models\CityOpinion;
8+
use App\Policies\CityOpinionPolicy;
79
use Illuminate\Http\Resources\Json\JsonResource;
10+
use Illuminate\Support\Facades\Gate;
811
use Illuminate\Support\ServiceProvider;
912
use Laravel\Sanctum\PersonalAccessToken;
1013
use Laravel\Sanctum\Sanctum;
@@ -28,6 +31,7 @@ public function register(): void
2831
public function boot(): void
2932
{
3033
JsonResource::withoutWrapping();
34+
Gate::policy(CityOpinion::class, CityOpinionPolicy::class);
3135
Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
3236
}
3337
}

resources/js/Pages/City/Index.vue

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import InfoPopup from '@/Shared/Components/InfoPopup.vue'
1616
import Opinion from '@/Shared/Components/Opinion.vue'
1717
1818
const toast = useToast()
19-
2019
const page = usePage()
2120
const isAuth = computed(() => page.props.auth.isAuth)
2221

resources/js/Shared/Components/Opinion.vue

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import DeleteModal from './DeleteModal.vue'
88
import { useToast } from 'vue-toastification'
99
import ErrorMessage from './ErrorMessage.vue'
1010
11+
const isAdmin = computed(() => page.props.auth.isAdmin)
1112
const toast = useToast()
1213
const page = usePage()
1314
const user = computed(() => page.props.auth.user)
@@ -103,8 +104,8 @@ const emptyRatingError = ref('')
103104
{{ opinion.content }}
104105
</div>
105106

106-
<div v-if="user.id === props.opinion.user.id" class="mt-1 flex justify-end">
107-
<button class="flex px-1 hover:drop-shadow" @click="toggleUpdateOpinionDialog">
107+
<div v-if="user.id === props.opinion.user.id || isAdmin" class="mt-1 flex justify-end">
108+
<button v-if="user.id === props.opinion.user.id" class="flex px-1 hover:drop-shadow" @click="toggleUpdateOpinionDialog">
108109
<PencilIcon class="h-5 w-5 text-blumilk-500 hover:drop-shadow sm:h-4 sm:w-4" />
109110
</button>
110111
<button class="flex px-1 hover:drop-shadow" @click="toggleDeleteOpinionDialog">

routes/web.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@
3333
Route::get("/favorite-cities", [FavoritesController::class, "index"]);
3434

3535
Route::post("/opinions", [CityOpinionController::class, "store"]);
36-
Route::patch("/opinions/{cityOpinion}", [CityOpinionController::class, "update"]);
37-
Route::delete("/opinions/{cityOpinion}", [CityOpinionController::class, "destroy"]);
36+
Route::patch("/opinions/{cityOpinion}", [CityOpinionController::class, "update"])
37+
->middleware("can:update,cityOpinion");
38+
Route::delete("/opinions/{cityOpinion}", [CityOpinionController::class, "destroy"])
39+
->middleware("can:delete,cityOpinion");
3840

3941
Route::middleware(["role:admin"])->group(function (): void {
4042
Route::get("/admin/importers", [ImportInfoController::class, "index"]);

0 commit comments

Comments
 (0)