Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial webhook action implementation #1755

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
132 changes: 132 additions & 0 deletions app/TransactionRules/Actions/NotifyWebhook.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?php
/**
* NotifyWebhook.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);

namespace FireflyIII\TransactionRules\Actions;

use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
use FireflyIII\Transformers\TransactionTransformer;

use Illuminate\Support\Collection;
use Log;

use League\Fractal\Manager;
use League\Fractal\Serializer\JsonApiSerializer;
use League\Fractal\Resource\Collection as FractalCollection;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Psr7\Request;

use Symfony\Component\HttpFoundation\ParameterBag;



/**
* Class NotifyWebhook.
*/
class NotifyWebhook implements ActionInterface
{
/** @var RuleAction The rule action */
private $action;

/**
* TriggerInterface constructor.
*
* @param RuleAction $action
*/
public function __construct(RuleAction $action)
{
$this->action = $action;
}

/**
* Notify webhook at X about the event
*
* @param TransactionJournal $journal
*
* @return bool
*/
public function act(TransactionJournal $journal): bool
{
$url = $this->action->action_value;

if (\filter_var($url, FILTER_VALIDATE_URL) === false) {
Log::debug(sprintf('RuleAction NotifyWebhook invalid url "%s"', $this->action->action_value));
return false;
}

// collect transactions using the journal collector
$collector = app(TransactionCollectorInterface::class);
$collector->setUser(auth()->user());
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
// filter on specific journals.
$collector->setJournals(new Collection([$journal]));

// add filter to remove transactions:
$transactionType = $journal->transactionType->type;
if ($transactionType === TransactionType::WITHDRAWAL) {
$collector->addFilter(PositiveAmountFilter::class);
}
if (!($transactionType === TransactionType::WITHDRAWAL)) {
$collector->addFilter(NegativeAmountFilter::class);
}

$transactions = $collector->getTransactions();
$resource = new FractalCollection($transactions, new TransactionTransformer(new ParameterBag()), 'transactions');

$manager = new Manager();
$baseUrl = route('index') . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));

$body = $manager->createData($resource)->toArray();

try {
Log::debug(sprintf('RuleAction NotifyWebhook posting to "%s"...', $this->action->action_value));
$client = new Client();
$response = $client->request('POST', $this->action->action_value, ['json' => $body]);
if ($response->getStatusCode() !== 200) {
Log::debug(sprintf('RuleAction NotifyWebhook posted to "%s" - Webhook received a non 200 response.', $this->action->action_value));
return false;
}
Log::debug(sprintf('RuleAction NotifyWebhook posted to "%s" journal id "%d".', $this->action->action_value, $journal->id));
return true;
} catch (ClientException $exception) {
if ($exception->getResponse()->getStatusCode() !== 410) {
Log::debug(sprintf('RuleAction NotifyWebhook posted to "%s" - Webhook received a %d status code in response.', $this->action->action_value, $exception->getResponse()->getStatusCode()));
return false;
//throw new WebHookFailedException($exception->getMessage(), $exception->getCode(), $exception);
}
} catch (GuzzleException $exception) {
Log::debug(sprintf('RuleAction NotifyWebhook posted to "%s" - Failed: %s', $this->action->action_value, $exception->getMessage()));
return false;
//throw new WebHookFailedException($exception->getMessage(), $exception->getCode(), $exception);
}

Log::debug(sprintf('RuleAction NotifyWebhook posted to "%s" - Webhook failed in posting', $this->action->action_value));
return false;
}
}
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"davejamesmiller/laravel-breadcrumbs": "5.*",
"doctrine/dbal": "2.*",
"fideloper/proxy": "4.*",
"guzzlehttp/guzzle": "~6.0",
"laravel/framework": "5.7.*",
"laravel/passport": "^7.0",
"laravelcollective/html": "5.7.*",
Expand Down
2 changes: 1 addition & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions config/firefly.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
use FireflyIII\TransactionRules\Actions\ConvertToTransfer;
use FireflyIII\TransactionRules\Actions\ConvertToWithdrawal;
use FireflyIII\TransactionRules\Actions\LinkToBill;
use FireflyIII\TransactionRules\Actions\NotifyWebhook;
use FireflyIII\TransactionRules\Actions\PrependDescription;
use FireflyIII\TransactionRules\Actions\PrependNotes;
use FireflyIII\TransactionRules\Actions\RemoveAllTags;
Expand Down Expand Up @@ -373,6 +374,7 @@
'convert_withdrawal' => ConvertToWithdrawal::class,
'convert_deposit' => ConvertToDeposit::class,
'convert_transfer' => ConvertToTransfer::class,
'notify_webhook' => NotifyWebhook::class,
],
'rule-actions-text' => [
'set_category',
Expand All @@ -383,6 +385,7 @@
'set_description',
'append_description',
'prepend_description',
'notify_webhook',
],
'test-triggers' => [
'limit' => 10,
Expand Down
2 changes: 2 additions & 0 deletions resources/lang/en_US/firefly.php
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,8 @@
'rule_action_convert_withdrawal' => 'Convert the transaction to a withdrawal to ":action_value"',
'rule_action_convert_transfer_choice' => 'Convert the transaction to a transfer',
'rule_action_convert_transfer' => 'Convert the transaction to a transfer with ":action_value"',
'rule_action_notify_webhook_choice' => 'Notify about event to webhook..',
'rule_action_notify_webhook' => 'Notify about event to webhook ":action_value"',

'rules_have_read_warning' => 'Have you read the warning?',
'apply_rule_warning' => 'Warning: running a rule(group) on a large selection of transactions could take ages, and it could time-out. If it does, the rule(group) will only be applied to an unknown subset of your transactions. This might leave your financial administration in tatters. Please be careful.',
Expand Down