. */ declare(strict_types=1); namespace FireflyIII\Generator\Webhook; use FireflyIII\Enums\WebhookResponse; use FireflyIII\Enums\WebhookTrigger; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionGroup; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\Webhook; use FireflyIII\Models\WebhookMessage; use FireflyIII\Transformers\AccountTransformer; use FireflyIII\Transformers\TransactionGroupTransformer; use FireflyIII\User; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Collection; use Ramsey\Uuid\Uuid; use Symfony\Component\HttpFoundation\ParameterBag; /** * Class StandardMessageGenerator */ class StandardMessageGenerator implements MessageGeneratorInterface { private Collection $objects; private int $trigger; private User $user; private int $version = 0; private Collection $webhooks; public function __construct() { $this->objects = new Collection(); $this->webhooks = new Collection(); } public function generateMessages(): void { app('log')->debug(__METHOD__); // get the webhooks: if (0 === $this->webhooks->count()) { $this->webhooks = $this->getWebhooks(); } // do some debugging app('log')->debug( sprintf('StandardMessageGenerator will generate messages for %d object(s) and %d webhook(s).', $this->objects->count(), $this->webhooks->count()) ); $this->run(); } public function getVersion(): int { return $this->version; } public function setObjects(Collection $objects): void { $this->objects = $objects; } public function setTrigger(int $trigger): void { $this->trigger = $trigger; } public function setUser(User $user): void { $this->user = $user; } public function setWebhooks(Collection $webhooks): void { $this->webhooks = $webhooks; } private function getWebhooks(): Collection { return $this->user->webhooks()->where('active', true)->where('trigger', $this->trigger)->get(['webhooks.*']); } private function run(): void { app('log')->debug('Now in StandardMessageGenerator::run'); /** @var Webhook $webhook */ foreach ($this->webhooks as $webhook) { $this->runWebhook($webhook); } app('log')->debug('Done with StandardMessageGenerator::run'); } /** * @throws FireflyException * */ private function runWebhook(Webhook $webhook): void { app('log')->debug(sprintf('Now in runWebhook(#%d)', $webhook->id)); /** @var Model $object */ foreach ($this->objects as $object) { $this->generateMessage($webhook, $object); } } /** * @throws FireflyException * */ private function generateMessage(Webhook $webhook, Model $model): void { $class = get_class($model); // Line is ignored because all of Firefly III's Models have an id property. app('log')->debug(sprintf('Now in generateMessage(#%d, %s#%d)', $webhook->id, $class, $model->id)); $uuid = Uuid::uuid4(); $basicMessage = [ 'uuid' => $uuid->toString(), 'user_id' => 0, 'trigger' => WebhookTrigger::from($webhook->trigger)->name, 'response' => WebhookResponse::from($webhook->response)->name, 'url' => $webhook->url, 'version' => sprintf('v%d', $this->getVersion()), 'content' => [], ]; // depends on the model how user_id is set: switch ($class) { default: // Line is ignored because all of Firefly III's Models have an id property. app('log')->error( sprintf('Webhook #%d was given %s#%d to deal with but can\'t extract user ID from it.', $webhook->id, $class, $model->id) ); return; case TransactionGroup::class: // @var TransactionGroup $model $basicMessage['user_id'] = $model->user->id; break; } // then depends on the response what to put in the message: switch ($webhook->response) { default: app('log')->error( sprintf('The response code for webhook #%d is "%d" and the message generator cant handle it. Soft fail.', $webhook->id, $webhook->response) ); return; case WebhookResponse::NONE->value: $basicMessage['content'] = []; break; case WebhookResponse::TRANSACTIONS->value: /** @var TransactionGroup $model */ $transformer = new TransactionGroupTransformer(); try { $basicMessage['content'] = $transformer->transformObject($model); } catch (FireflyException $e) { app('log')->error( sprintf('The transformer could not include the requested transaction group for webhook #%d: %s', $webhook->id, $e->getMessage()) ); app('log')->error($e->getTraceAsString()); return; } break; case WebhookResponse::ACCOUNTS->value: /** @var TransactionGroup $model */ $accounts = $this->collectAccounts($model); foreach ($accounts as $account) { $transformer = new AccountTransformer(); $transformer->setParameters(new ParameterBag()); $basicMessage['content'][] = $transformer->transform($account); } } $this->storeMessage($webhook, $basicMessage); } private function collectAccounts(TransactionGroup $transactionGroup): Collection { $accounts = new Collection(); /** @var TransactionJournal $journal */ foreach ($transactionGroup->transactionJournals as $journal) { /** @var Transaction $transaction */ foreach ($journal->transactions as $transaction) { $accounts->push($transaction->account); } } return $accounts->unique(); } private function storeMessage(Webhook $webhook, array $message): void { $webhookMessage = new WebhookMessage(); $webhookMessage->webhook()->associate($webhook); $webhookMessage->sent = false; $webhookMessage->errored = false; $webhookMessage->uuid = $message['uuid']; $webhookMessage->message = $message; $webhookMessage->save(); app('log')->debug(sprintf('Stored new webhook message #%d', $webhookMessage->id)); } }