mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-05 04:03:26 +00:00
Can now send webhook messages.
This commit is contained in:
30
app/Events/RequestedSendWebhookMessages.php
Normal file
30
app/Events/RequestedSendWebhookMessages.php
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* RequestedSendWebhookMessages.php
|
||||||
|
* Copyright (c) 2020 james@firefly-iii.org
|
||||||
|
*
|
||||||
|
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace FireflyIII\Events;
|
||||||
|
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
|
||||||
|
class RequestedSendWebhookMessages extends Event
|
||||||
|
{
|
||||||
|
use SerializesModels;
|
||||||
|
}
|
@@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
namespace FireflyIII\Generator\Webhook;
|
namespace FireflyIII\Generator\Webhook;
|
||||||
|
|
||||||
|
use FireflyIII\Events\RequestedSendWebhookMessages;
|
||||||
|
use FireflyIII\Events\StoredWebhookMessage;
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Models\Transaction;
|
use FireflyIII\Models\Transaction;
|
||||||
use FireflyIII\Models\TransactionGroup;
|
use FireflyIII\Models\TransactionGroup;
|
||||||
@@ -93,6 +95,7 @@ class WebhookMessageGenerator
|
|||||||
foreach ($this->webhooks as $webhook) {
|
foreach ($this->webhooks as $webhook) {
|
||||||
$this->runWebhook($webhook);
|
$this->runWebhook($webhook);
|
||||||
}
|
}
|
||||||
|
event(new RequestedSendWebhookMessages);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -166,7 +169,7 @@ class WebhookMessageGenerator
|
|||||||
* @param Webhook $webhook
|
* @param Webhook $webhook
|
||||||
* @param array $message
|
* @param array $message
|
||||||
*/
|
*/
|
||||||
private function storeMessage(Webhook $webhook, array $message): void
|
private function storeMessage(Webhook $webhook, array $message): WebhookMessage
|
||||||
{
|
{
|
||||||
$webhookMessage = new WebhookMessage;
|
$webhookMessage = new WebhookMessage;
|
||||||
$webhookMessage->webhook()->associate($webhook);
|
$webhookMessage->webhook()->associate($webhook);
|
||||||
@@ -176,6 +179,8 @@ class WebhookMessageGenerator
|
|||||||
$webhookMessage->message = $message;
|
$webhookMessage->message = $message;
|
||||||
$webhookMessage->logs = null;
|
$webhookMessage->logs = null;
|
||||||
$webhookMessage->save();
|
$webhookMessage->save();
|
||||||
|
|
||||||
|
return $webhookMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -27,7 +27,6 @@ use FireflyIII\Generator\Webhook\WebhookMessageGenerator;
|
|||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use FireflyIII\Models\Webhook;
|
use FireflyIII\Models\Webhook;
|
||||||
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
|
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
|
||||||
use FireflyIII\TransactionRules\Engine\RuleEngine;
|
|
||||||
use FireflyIII\TransactionRules\Engine\RuleEngineInterface;
|
use FireflyIII\TransactionRules\Engine\RuleEngineInterface;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Log;
|
use Log;
|
||||||
@@ -87,8 +86,7 @@ class StoredGroupEventHandler
|
|||||||
$engine->setUser($user);
|
$engine->setUser($user);
|
||||||
$engine->setTransactionGroups(new Collection([$group]));
|
$engine->setTransactionGroups(new Collection([$group]));
|
||||||
$engine->setTrigger(Webhook::TRIGGER_STORE_TRANSACTION);
|
$engine->setTrigger(Webhook::TRIGGER_STORE_TRANSACTION);
|
||||||
|
$engine->generateMessages();
|
||||||
$messages= $engine->generateMessages();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
112
app/Handlers/Events/WebhookEventHandler.php
Normal file
112
app/Handlers/Events/WebhookEventHandler.php
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* WebhookEventHandler.php
|
||||||
|
* Copyright (c) 2020 james@firefly-iii.org
|
||||||
|
*
|
||||||
|
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace FireflyIII\Handlers\Events;
|
||||||
|
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use FireflyIII\Models\WebhookMessage;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Exception\ClientException;
|
||||||
|
use JsonException;
|
||||||
|
use Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class WebhookEventHandler
|
||||||
|
*/
|
||||||
|
class WebhookEventHandler
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function sendWebhookMessages(): void
|
||||||
|
{
|
||||||
|
$max = (int)config('firefly.webhooks.max_attempts');
|
||||||
|
$max = 0 === $max ? 3 : $max;
|
||||||
|
$messages = WebhookMessage::where('sent', 0)
|
||||||
|
->where('attempts', '<=', $max)
|
||||||
|
->get();
|
||||||
|
Log::debug(sprintf('Going to send %d webhook message(s)', $messages->count()));
|
||||||
|
/** @var WebhookMessage $message */
|
||||||
|
foreach ($messages as $message) {
|
||||||
|
$this->sendMessage($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param WebhookMessage $message
|
||||||
|
*/
|
||||||
|
private function sendMessage(WebhookMessage $message): void
|
||||||
|
{
|
||||||
|
Log::debug(sprintf('Trying to send webhook message #%d', $message->id));
|
||||||
|
try {
|
||||||
|
$json = json_encode($message->message, JSON_THROW_ON_ERROR);
|
||||||
|
} catch (JsonException $e) {
|
||||||
|
$message->attempts++;
|
||||||
|
$message->logs[] = sprintf('%s: %s', date('Y-m-d H:i:s'), sprintf('Json error: %s', $e->getMessage()));
|
||||||
|
$message->save();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$user = $message->webhook->user;
|
||||||
|
try {
|
||||||
|
$token = $user->generateAccessToken();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$message->attempts++;
|
||||||
|
$message->logs[] = sprintf('%s: %s', date('Y-m-d H:i:s'), sprintf('Could not generate token: %s', $e->getMessage()));
|
||||||
|
$message->save();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$accessToken = app('preferences')->getForUser($user, 'access_token', $token);
|
||||||
|
$signature = hash_hmac('sha3-256', $json, $accessToken->data, false);
|
||||||
|
$options = [
|
||||||
|
'body' => $json,
|
||||||
|
'headers' => [
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
'Accept' => 'application/json',
|
||||||
|
'Signature' => $signature,
|
||||||
|
'connect_timeout' => 3.14,
|
||||||
|
'User-Agent' => sprintf('FireflyIII/%s', config('firefly.version')),
|
||||||
|
'timeout' => 10,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$client = new Client;
|
||||||
|
$logs = $message->logs ?? [];
|
||||||
|
try {
|
||||||
|
$res = $client->request('GET', $message->webhook->url, $options);
|
||||||
|
$message->sent = true;
|
||||||
|
} catch (ClientException|Exception $e) {
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
Log::error($e->getTraceAsString());
|
||||||
|
$logs[] = sprintf('%s: %s', date('Y-m-d H:i:s'), $e->getMessage());
|
||||||
|
$message->errored = true;
|
||||||
|
$message->sent = false;
|
||||||
|
}
|
||||||
|
$message->attempts++;
|
||||||
|
$message->logs = $logs;
|
||||||
|
$message->save();
|
||||||
|
|
||||||
|
Log::debug(sprintf('Webhook message #%d was sent. Status code %d', $message->id, $res->getStatusCode()));
|
||||||
|
Log::debug(sprintf('Response body: %s', $res->getBody()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -61,6 +61,7 @@ class WebhookMessage extends Model
|
|||||||
'errored' => 'boolean',
|
'errored' => 'boolean',
|
||||||
'uuid' => 'string',
|
'uuid' => 'string',
|
||||||
'message' => 'json',
|
'message' => 'json',
|
||||||
|
'logs' => 'json',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -29,8 +29,10 @@ use FireflyIII\Events\DetectedNewIPAddress;
|
|||||||
use FireflyIII\Events\RegisteredUser;
|
use FireflyIII\Events\RegisteredUser;
|
||||||
use FireflyIII\Events\RequestedNewPassword;
|
use FireflyIII\Events\RequestedNewPassword;
|
||||||
use FireflyIII\Events\RequestedReportOnJournals;
|
use FireflyIII\Events\RequestedReportOnJournals;
|
||||||
|
use FireflyIII\Events\RequestedSendWebhookMessages;
|
||||||
use FireflyIII\Events\RequestedVersionCheckStatus;
|
use FireflyIII\Events\RequestedVersionCheckStatus;
|
||||||
use FireflyIII\Events\StoredTransactionGroup;
|
use FireflyIII\Events\StoredTransactionGroup;
|
||||||
|
use FireflyIII\Events\StoredWebhookMessage;
|
||||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||||
use FireflyIII\Events\UserChangedEmail;
|
use FireflyIII\Events\UserChangedEmail;
|
||||||
use FireflyIII\Handlers\Events\SendEmailVerificationNotification;
|
use FireflyIII\Handlers\Events\SendEmailVerificationNotification;
|
||||||
@@ -112,6 +114,11 @@ class EventServiceProvider extends ServiceProvider
|
|||||||
AccessTokenCreated::class => [
|
AccessTokenCreated::class => [
|
||||||
'FireflyIII\Handlers\Events\APIEventHandler@accessTokenCreated',
|
'FireflyIII\Handlers\Events\APIEventHandler@accessTokenCreated',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// Webhook related event:
|
||||||
|
RequestedSendWebhookMessages::class => [
|
||||||
|
'FireflyIII\Handlers\Events\WebhookEventHandler@sendWebhookMessages',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -823,16 +823,17 @@ return [
|
|||||||
'recurrence_total', 'recurrence_count',
|
'recurrence_total', 'recurrence_count',
|
||||||
],
|
],
|
||||||
'webhooks' => [
|
'webhooks' => [
|
||||||
'triggers' => [
|
'max_attempts' => env('WEBHOOK_MAX_ATTEMPTS', 3),
|
||||||
|
'triggers' => [
|
||||||
100 => 'TRIGGER_STORE_TRANSACTION',
|
100 => 'TRIGGER_STORE_TRANSACTION',
|
||||||
110 => 'TRIGGER_UPDATE_TRANSACTION',
|
110 => 'TRIGGER_UPDATE_TRANSACTION',
|
||||||
120 => 'TRIGGER_DESTROY_TRANSACTION',
|
120 => 'TRIGGER_DESTROY_TRANSACTION',
|
||||||
],
|
],
|
||||||
'responses' => [
|
'responses' => [
|
||||||
200 => 'RESPONSE_TRANSACTIONS',
|
200 => 'RESPONSE_TRANSACTIONS',
|
||||||
210 => 'RESPONSE_ACCOUNTS',
|
210 => 'RESPONSE_ACCOUNTS',
|
||||||
],
|
],
|
||||||
'deliveries' => [
|
'deliveries' => [
|
||||||
300 => 'DELIVERY_JSON',
|
300 => 'DELIVERY_JSON',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@@ -138,6 +138,7 @@ class ChangesForV550 extends Migration
|
|||||||
$table->integer('webhook_id', false, true);
|
$table->integer('webhook_id', false, true);
|
||||||
$table->boolean('sent')->default(false);
|
$table->boolean('sent')->default(false);
|
||||||
$table->boolean('errored')->default(false);
|
$table->boolean('errored')->default(false);
|
||||||
|
$table->unsignedTinyInteger('attempts')->default(0);
|
||||||
$table->string('uuid',64);
|
$table->string('uuid',64);
|
||||||
$table->longText('message');
|
$table->longText('message');
|
||||||
$table->longText('logs')->nullable();
|
$table->longText('logs')->nullable();
|
||||||
|
Reference in New Issue
Block a user