]> BookStack Code Mirror - bookstack/blob - app/Actions/DispatchWebhookJob.php
Revamped workings of WYSIWYG code blocks
[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         $lastError = null;
76
77         try {
78             $response = Http::asJson()
79                 ->withOptions(['allow_redirects' => ['strict' => true]])
80                 ->timeout($this->webhook->timeout)
81                 ->post($this->webhook->endpoint, $webhookData);
82         } catch (\Exception $exception) {
83             $lastError = $exception->getMessage();
84             Log::error("Webhook call to endpoint {$this->webhook->endpoint} failed with error \"{$lastError}\"");
85         }
86
87         if (isset($response) && $response->failed()) {
88             $lastError = "Response status from endpoint was {$response->status()}";
89             Log::error("Webhook call to endpoint {$this->webhook->endpoint} failed with status {$response->status()}");
90         }
91
92         $this->webhook->last_called_at = now();
93         if ($lastError) {
94             $this->webhook->last_errored_at = now();
95             $this->webhook->last_error = $lastError;
96         }
97
98         $this->webhook->save();
99     }
100
101     protected function buildWebhookData(): array
102     {
103         $textParts = [
104             $this->initiator->name,
105             trans('activities.' . $this->event),
106         ];
107
108         if ($this->detail instanceof Entity) {
109             $textParts[] = '"' . $this->detail->name . '"';
110         }
111
112         $data = [
113             'event'                    => $this->event,
114             'text'                     => implode(' ', $textParts),
115             'triggered_at'             => Carbon::createFromTimestampUTC($this->initiatedTime)->toISOString(),
116             'triggered_by'             => $this->initiator->attributesToArray(),
117             'triggered_by_profile_url' => $this->initiator->getProfileUrl(),
118             'webhook_id'               => $this->webhook->id,
119             'webhook_name'             => $this->webhook->name,
120         ];
121
122         if (method_exists($this->detail, 'getUrl')) {
123             $data['url'] = $this->detail->getUrl();
124         }
125
126         if ($this->detail instanceof Model) {
127             $data['related_item'] = $this->detail->attributesToArray();
128         }
129
130         return $data;
131     }
132 }