diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php index 9afcc12c7155..86dc368934c1 100644 --- a/app/Http/Controllers/BaseController.php +++ b/app/Http/Controllers/BaseController.php @@ -913,7 +913,6 @@ class BaseController extends Controller * List response * * @param mixed $query - * @return void */ protected function listResponse($query) { @@ -1010,7 +1009,6 @@ class BaseController extends Controller * Item Response * * @param mixed $item - * @return void */ protected function itemResponse($item) { diff --git a/app/Http/Controllers/WebhookController.php b/app/Http/Controllers/WebhookController.php index f77fef636efb..f33c3ea0674b 100644 --- a/app/Http/Controllers/WebhookController.php +++ b/app/Http/Controllers/WebhookController.php @@ -12,19 +12,22 @@ namespace App\Http\Controllers; +use App\Models\Webhook; +use Illuminate\Support\Str; +use Illuminate\Http\Response; use App\Factory\WebhookFactory; use App\Filters\WebhookFilters; -use App\Http\Requests\Webhook\CreateWebhookRequest; -use App\Http\Requests\Webhook\DestroyWebhookRequest; -use App\Http\Requests\Webhook\EditWebhookRequest; -use App\Http\Requests\Webhook\ShowWebhookRequest; -use App\Http\Requests\Webhook\StoreWebhookRequest; -use App\Http\Requests\Webhook\UpdateWebhookRequest; -use App\Models\Webhook; +use App\Utils\Traits\MakesHash; +use App\Jobs\Util\WebhookSingle; use App\Repositories\BaseRepository; use App\Transformers\WebhookTransformer; -use App\Utils\Traits\MakesHash; -use Illuminate\Http\Response; +use App\Http\Requests\Webhook\EditWebhookRequest; +use App\Http\Requests\Webhook\ShowWebhookRequest; +use App\Http\Requests\Webhook\RetryWebhookRequest; +use App\Http\Requests\Webhook\StoreWebhookRequest; +use App\Http\Requests\Webhook\CreateWebhookRequest; +use App\Http\Requests\Webhook\UpdateWebhookRequest; +use App\Http\Requests\Webhook\DestroyWebhookRequest; class WebhookController extends BaseController { @@ -487,4 +490,28 @@ class WebhookController extends BaseController return $this->listResponse(Webhook::withTrashed()->whereIn('id', $this->transformKeys($ids))); } + + public function retry(RetryWebhookRequest $request, Webhook $webhook) + { + match($request->entity) { + 'invoice' => $includes ='client', + 'payment' => $includes ='invoices,client', + 'project' => $includes ='client', + 'purchase_order' => $includes ='vendor', + 'quote' => $includes ='client', + default => $includes = '' + }; + + $class = 'App\Models\\'.ucfirst(Str::camel($request->entity)); + + $entity = $class::withTrashed()->where('id', $this->decodePrimaryKey($request->entity_id))->company()->first(); + + if(!$entity){ + return response()->json(['message' => ctrans('texts.record_not_found')], 400); + } + + WebhookSingle::dispatchSync($webhook->id, $entity, auth()->user()->company()->db, $includes); + + return $this->itemResponse($webhook); + } } diff --git a/app/Http/Requests/Webhook/RetryWebhookRequest.php b/app/Http/Requests/Webhook/RetryWebhookRequest.php new file mode 100644 index 000000000000..5b98c06ab233 --- /dev/null +++ b/app/Http/Requests/Webhook/RetryWebhookRequest.php @@ -0,0 +1,35 @@ +user()->isAdmin(); + } + + public function rules() + { + return [ + 'entity' => 'required|bail|in:client,credit,invoice,product,task,payment,quote,purchase_order,expense,project,vendor', + 'entity_id' => 'required|bail|string', + ]; + } +} diff --git a/app/Jobs/Util/WebhookSingle.php b/app/Jobs/Util/WebhookSingle.php index 84398b00ee1a..ab5bd5af1710 100644 --- a/app/Jobs/Util/WebhookSingle.php +++ b/app/Jobs/Util/WebhookSingle.php @@ -104,8 +104,10 @@ class WebhookSingle implements ShouldQueue $resource = new Item($this->entity, $transformer, $this->entity->getEntityType()); $data = $manager->createData($resource)->toArray(); + + $headers = is_array($subscription->headers) ? $subscription->headers : []; - $this->postData($subscription, $data, $subscription->headers); + $this->postData($subscription, $data, $headers); } private function postData($subscription, $data, $headers = []) diff --git a/lang/en/texts.php b/lang/en/texts.php index 9cf72a3d8cf7..aad041a416b3 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -5026,6 +5026,7 @@ $LANG = array( 'pre_payment_indefinitely' => 'Continue until cancelled', 'notification_payment_emailed' => 'Payment :payment was emailed to :client', 'notification_payment_emailed_subject' => 'Payment :payment was emailed', + 'record_not_found' => 'Record not found', ); diff --git a/routes/api.php b/routes/api.php index daf2db3a84a1..aa90773fe12e 100644 --- a/routes/api.php +++ b/routes/api.php @@ -336,6 +336,7 @@ Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'locale'] Route::resource('webhooks', WebhookController::class); Route::post('webhooks/bulk', [WebhookController::class, 'bulk'])->name('webhooks.bulk'); + Route::post('webhooks/{webhook}/retry', [WebhookController::class, 'retry'])->name('webhooks.retry'); /*Subscription and Webhook routes */ // Route::post('hooks', [SubscriptionController::class, 'subscribe'])->name('hooks.subscribe'); diff --git a/tests/Feature/WebhookAPITest.php b/tests/Feature/WebhookAPITest.php index a2ed5c54f3a3..2d62be234cab 100644 --- a/tests/Feature/WebhookAPITest.php +++ b/tests/Feature/WebhookAPITest.php @@ -11,6 +11,7 @@ namespace Tests\Feature; +use App\Jobs\Util\WebhookSingle; use App\Utils\Traits\MakesHash; use Illuminate\Database\Eloquent\Model; use Illuminate\Foundation\Testing\DatabaseTransactions; @@ -45,6 +46,39 @@ class WebhookAPITest extends TestCase $this->withoutExceptionHandling(); } + public function testWebhookRetry() + { + + $data = [ + 'target_url' => 'http://hook.com', + 'event_id' => 1, //create client + 'format' => 'JSON', + 'headers' => [] + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->postJson("/api/v1/webhooks", $data); + + $response->assertStatus(200); + + $arr = $response->json(); + + $data = [ + 'entity' => 'client', + 'entity_id' => $this->client->hashed_id, + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->postJson("/api/v1/webhooks/".$arr['data']['id']."/retry", $data); + + $response->assertStatus(200); + + } + public function testWebhookGetFilter() { $response = $this->withHeaders([