Skip to content

Commit

Permalink
♻️ rewrite webhook settings in vue; api improvements
Browse files Browse the repository at this point in the history
fixes #2888
fixes #2889
  • Loading branch information
MrKrisKrisu committed Jan 14, 2025
1 parent f73ae81 commit 1870405
Show file tree
Hide file tree
Showing 13 changed files with 163 additions and 159 deletions.
63 changes: 21 additions & 42 deletions app/Http/Controllers/API/v1/WebhookController.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class WebhookController extends Controller
* path="/webhooks",
* operationId="getWebhooks",
* tags={"Webhooks"},
* summary="Get webhooks for current user and current application",
* description="Returns all webhooks which are created for the current user and which the current authorized applicaton has access to.",
* summary="Get webhooks for current user.",
* description="Returns all webhooks which are created for the current user.",
* @OA\Response(
* response=200,
* description="successful operation",
Expand All @@ -37,12 +37,8 @@ class WebhookController extends Controller
* }
* )
*/
public function getWebhooks(Request $request): AnonymousResourceCollection {
$clientId = $request->user()->token()->client->id;
$webhooks = Webhook::where('oauth_client_id', '=', $clientId)
->where('user_id', '=', $request->user()->id)
->get();
return WebhookResource::collection($webhooks);
public function index(): AnonymousResourceCollection {
return WebhookResource::collection(Webhook::where('user_id', auth()->id())->get());
}

/**
Expand All @@ -51,7 +47,7 @@ public function getWebhooks(Request $request): AnonymousResourceCollection {
* operationId="getSingleWebhook",
* tags={"Webhooks"},
* summary="Get single webhook",
* description="Returns a single webhook Object, if user and application is authorized to see it",
* description="Returns a single webhook Object, if user is authorized to see it",
* @OA\Parameter (
* name="id",
* in="path",
Expand All @@ -74,19 +70,11 @@ public function getWebhooks(Request $request): AnonymousResourceCollection {
* {"passport": {}}, {"token": {}}
* }
* )
*
* Show single webhook
*
* @param int $webhookId
*
* @return WebhookResource|JsonResponse
*/
public function getWebhook(Request $request, int $webhookId): WebhookResource|JsonResponse {
$clientId = $request->user()->token()->client->id;
$webhook = Webhook::where('oauth_client_id', '=', $clientId)
->where('user_id', '=', $request->user()->id)
->where('id', '=', $webhookId)
->first();
public function show(int $webhookId): WebhookResource|JsonResponse {
$webhook = Webhook::where('user_id', auth()->id())
->where('id', '=', $webhookId)
->first();
if ($webhook == null) {
return $this->sendError('No webhook found for this id.');
}
Expand All @@ -98,7 +86,7 @@ public function getWebhook(Request $request, int $webhookId): WebhookResource|Js
* path="/webhooks/{id}",
* operationId="deleteWebhook",
* tags={"Webhooks"},
* summary="Delete a webhook if the user and application are authorized to do",
* summary="Delete a webhook if the user is authorized to do",
* description="",
* @OA\Parameter (
* name="id",
Expand All @@ -107,30 +95,21 @@ public function getWebhook(Request $request, int $webhookId): WebhookResource|Js
* example=1337,
* @OA\Schema(type="integer")
* ),
* @OA\Response(
* response=200,
* description="successful operation",
* @OA\JsonContent(
* ref="#/components/schemas/SuccessResponse"
* )
* ),
* @OA\Response(response=400, description="Bad request"),
* @OA\Response(response=404, description="No webhook found for this id"),
* @OA\Response(response=403, description="User or application not authorized to delete this webhook"),
* security={
* {"passport": {}}, {"token": {}}
* }
* @OA\Response(response=204, description="Webhook deleted."),
* @OA\Response(response=400, description="Bad request"),
* @OA\Response(response=404, description="No webhook found for this id"),
* @OA\Response(response=403, description="User or application not authorized to delete this webhook"),
* security={
* {"passport": {}}, {"token": {}}
* }
* )
*
* @param int $webhookId
*
* @return JsonResponse
*/
public function deleteWebhook(Request $request, int $webhookId): JsonResponse {
public function destroy(int $webhookId): JsonResponse {
try {
$webhook = Webhook::findOrFail($webhookId);
WebhookBackend::deleteWebhook($webhook, $request->user()->token()->client);
return $this->sendResponse();
$this->authorize('delete', $webhook);
$webhook->delete();
return response()->json(null, 204);
} catch (AuthorizationException) {
return $this->sendError('You are not allowed to delete this webhook', 403);
} catch (ModelNotFoundException) {
Expand Down
19 changes: 0 additions & 19 deletions app/Http/Controllers/Backend/WebhookController.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,25 +56,6 @@ public static function createWebhook(
return $webhook;
}

/**
* Deletes a webhook
*
* @throws AuthorizationException
*/
public static function deleteWebhook(
Webhook $webhook,
OAuthClient|null $client
): bool {
Gate::authorize("delete", $webhook);
// Checking if the client is allowed to delete here,
// because I found no way of doing that in the policy.
if ($client != null && $client->id != $webhook->client->id) {
throw new AuthorizationException();
}
$webhook->delete();
return true;
}

public static function sendStatusWebhook(Status $status, WebhookEventEnum $event): void {
self::dispatchWebhook($status->user, $event, [
'status' => new StatusResource($status)
Expand Down
6 changes: 0 additions & 6 deletions app/Http/Controllers/Frontend/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,6 @@ public function renderToken(): Renderable {
]);
}

public function renderWebhooks(): Renderable {
return view('settings.webhooks', [
'webhooks' => WebhookController::index(user: auth()->user()),
]);
}

/**
* Approve a follow request
*
Expand Down
24 changes: 0 additions & 24 deletions app/Http/Controllers/Frontend/WebhookController.php

This file was deleted.

23 changes: 23 additions & 0 deletions app/Http/Resources/WebhookEventResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace App\Http\Resources;

use App\Enum\WebhookEvent;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class WebhookEventResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param Request $request
*
* @return array
*/
public function toArray($request): array {
return [
'type' => $this->event->value,
];
}
}
9 changes: 4 additions & 5 deletions app/Http/Resources/WebhookResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ class WebhookResource extends JsonResource
public function toArray($request): array {
return [
'id' => $this->id,
'clientId' => $this->oauth_client_id,
'userId' => $this->user_id,
'clientId' => $this->oauth_client_id, // TODO: should be removed
'client' => new ClientResource($this->client),
'userId' => $this->user_id, // TODO: should be removed and replaced with user object
'url' => $this->url,
'createdAt' => $this->created_at->toIso8601String(),
'events' => array_map(function($event) {
return WebhookEvent::from($event)->name();
}, $this->events),
'events' => WebhookEventResource::collection($this->events),
];
}
}
3 changes: 2 additions & 1 deletion lang/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -826,5 +826,6 @@
"trip-info.user": "User",
"trip-info.origin": "Abfahrtsort",
"trip-info.destination": "Zielort",
"requested-timestamp": "Abfragezeitpunkt"
"requested-timestamp": "Abfragezeitpunkt",
"successfully-deleted": "Erfolgreich gelöscht"
}
3 changes: 2 additions & 1 deletion lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -826,5 +826,6 @@
"trip-info.user": "User",
"trip-info.origin": "Origin",
"trip-info.destination": "Destination",
"requested-timestamp": "Requested timestamp"
"requested-timestamp": "Requested timestamp",
"successfully-deleted": "Successfully deleted"
}
10 changes: 10 additions & 0 deletions resources/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import TripCreationForm from "../vue/components/TripCreation/TripCreationForm.vu
import {createPinia} from 'pinia'
import piniaPluginPersistedsState from 'pinia-plugin-persistedstate'
import FriendCheckinSettings from "../vue/components/Settings/FriendCheckinSettings.vue";
import WebhookSettings from "../vue/components/Settings/Webhooks.vue";

window.notyf = new Notyf({
duration: 5000,
Expand Down Expand Up @@ -59,6 +60,8 @@ document.addEventListener("DOMContentLoaded", function () {
fallbackLang = "de";
}

// TODO: As we add more vue components here, we should consider embedding them in a better way

const i18nOptions = {
fallbackLang: fallbackLang,
fallbackMissingTranslations: true,
Expand Down Expand Up @@ -117,7 +120,14 @@ document.addEventListener("DOMContentLoaded", function () {
app7.use(i18nVue, i18nOptions);
app7.use(pinia);
app7.mount("#settings-friend-checkin");
}

if (document.getElementById("settings-webhooks")) {
const app8 = createApp({});
app8.component("Webhooks", WebhookSettings);
app8.use(i18nVue, i18nOptions);
app8.use(pinia);
app8.mount("#settings-webhooks");
}
});

Expand Down
55 changes: 2 additions & 53 deletions resources/views/settings/webhooks.blade.php
Original file line number Diff line number Diff line change
@@ -1,59 +1,8 @@
@php
use Carbon\Carbon;
use App\Enum\WebhookEvent;
@endphp
@extends('layouts.settings')
@section('title', __('settings.title-webhooks'))

@section('content')
<div class="row justify-content-center">
<div class="col-md-8 col-lg-7">
<div class="card mb-3">
<div class="card-header">{{ __('settings.title-webhooks') }}</div>
<div class="card-body table-responsive px-0">
<p class="mx-4">
{{ __('settings.webhook-description') }}
</p>
@if(count($webhooks) == 0)
<p class="text-danger mx-4">{{__('settings.no-webhooks')}}</p>
@else
<table class="table">
<thead>
<tr>
<th>{{ __('settings.client-name') }}</th>
<th>{{ __('settings.created') }}</th>
<th>{{ __('settings.webhook-event-notifications-description') }}</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach($webhooks as $webhook)
<tr>
<td>{{ $webhook->client->name }}</td>
<td>{{ Carbon::parse($webhook->created_at)->isoFormat(__('datetime-format')) }}</td>
<td>
<ul>
@foreach($webhook->events()->get() as $event)
<li>{{ __('settings.webhook_event.' . $event->event->value) }}</li>
@endforeach
</ul>
</td>
<td>
<form method="post" action="{{ route('delwebhook') }}">
@csrf
<input type="hidden" name="webhookId" value="{{$webhook->id}}"/>
<button class="btn btn-block btn-danger mx-0">
<i class="fas fa-trash"></i>
</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
@endif
</div>
</div>
</div>
<div id="settings-webhooks">
<Webhooks></Webhooks>
</div>
@endsection
Loading

0 comments on commit 1870405

Please sign in to comment.