]> BookStack Code Mirror - bookstack/blob - app/Actions/DispatchWebhookJob.php
57cb2feabad6afc8b375070e8aaf3697f139e424
[bookstack] / app / Actions / DispatchWebhookJob.php
1 <?php
2
3 namespace BookStack\Actions;
4
5 use BookStack\Auth\User;
6 use BookStack\Entities\Models\Entity;
7 use BookStack\Facades\Theme;
8 use BookStack\Interfaces\Loggable;
9 use BookStack\Model;
10 use BookStack\Theming\ThemeEvents;
11 use Illuminate\Bus\Queueable;
12 use Illuminate\Contracts\Queue\ShouldQueue;
13 use Illuminate\Foundation\Bus\Dispatchable;
14 use Illuminate\Queue\InteractsWithQueue;
15 use Illuminate\Queue\SerializesModels;
16 use Illuminate\Support\Carbon;
17 use Illuminate\Support\Facades\Http;
18 use Illuminate\Support\Facades\Log;
19
20 class DispatchWebhookJob implements ShouldQueue
21 {
22     use Dispatchable;
23     use InteractsWithQueue;
24     use Queueable;
25     use SerializesModels;
26
27     /**
28      * @var Webhook
29      */
30     protected $webhook;
31
32     /**
33      * @var string
34      */
35     protected $event;
36
37     /**
38      * @var string|Loggable
39      */
40     protected $detail;
41
42     /**
43      * @var User
44      */
45     protected $initiator;
46
47     /**
48      * @var int
49      */
50     protected $initiatedTime;
51
52     /**
53      * Create a new job instance.
54      *
55      * @return void
56      */
57     public function __construct(Webhook $webhook, string $event, $detail)
58     {
59         $this->webhook = $webhook;
60         $this->event = $event;
61         $this->detail = $detail;
62         $this->initiator = user();
63         $this->initiatedTime = time();
64     }
65
66     /**
67      * Execute the job.
68      *
69      * @return void
70      */
71     public function handle()
72     {
73         $themeResponse = Theme::dispatch(ThemeEvents::WEBHOOK_CALL_BEFORE, $this->event, $this->webhook, $this->detail);
74         $webhookData = $themeResponse ?? $this->buildWebhookData();
75
76         try {
77             $response = Http::asJson()
78                 ->withOptions(['allow_redirects' => ['strict' => true]])
79                 ->timeout(3)
80                 ->post($this->webhook->endpoint, $webhookData);
81
82         } catch (\Exception $exception) {
83             Log::error("Webhook call to endpoint {$this->webhook->endpoint} failed with error \"{$exception->getMessage()}\"");
84             return;
85         }
86
87         if ($response->failed()) {
88             Log::error("Webhook call to endpoint {$this->webhook->endpoint} failed with status {$response->status()}");
89         }
90     }
91
92     protected function buildWebhookData(): array
93     {
94         $textParts = [
95             $this->initiator->name,
96             trans('activities.' . $this->event),
97         ];
98
99         if ($this->detail instanceof Entity) {
100             $textParts[] = '"' . $this->detail->name . '"';
101         }
102
103         $data = [
104             'event'                    => $this->event,
105             'text'                     => implode(' ', $textParts),
106             'triggered_at'             => Carbon::createFromTimestampUTC($this->initiatedTime)->toISOString(),
107             'triggered_by'             => $this->initiator->attributesToArray(),
108             'triggered_by_profile_url' => $this->initiator->getProfileUrl(),
109             'webhook_id'               => $this->webhook->id,
110             'webhook_name'             => $this->webhook->name,
111         ];
112
113         if (method_exists($this->detail, 'getUrl')) {
114             $data['url'] = $this->detail->getUrl();
115         }
116
117         if ($this->detail instanceof Model) {
118             $data['related_item'] = $this->detail->attributesToArray();
119         }
120
121         return $data;
122     }
123 }