]> BookStack Code Mirror - bookstack/blob - app/Actions/WebhookFormatter.php
Added method for using enity ownership in relation queries
[bookstack] / app / Actions / WebhookFormatter.php
1 <?php
2
3 namespace BookStack\Actions;
4
5 use BookStack\Auth\User;
6 use BookStack\Entities\Models\Entity;
7 use BookStack\Entities\Models\Page;
8 use BookStack\Interfaces\Loggable;
9 use BookStack\Model;
10 use Illuminate\Support\Carbon;
11
12 class WebhookFormatter
13 {
14     protected Webhook $webhook;
15     protected string $event;
16     protected User $initiator;
17     protected int $initiatedTime;
18
19     /**
20      * @var string|Loggable
21      */
22     protected $detail;
23
24     /**
25      * @var array{condition: callable(string, Model):bool, format: callable(Model):void}[]
26      */
27     protected $modelFormatters = [];
28
29     public function __construct(string $event, Webhook $webhook, $detail, User $initiator, int $initiatedTime)
30     {
31         $this->webhook = $webhook;
32         $this->event = $event;
33         $this->initiator = $initiator;
34         $this->initiatedTime = $initiatedTime;
35         $this->detail = is_object($detail) ? clone $detail : $detail;
36     }
37
38     public function format(): array
39     {
40         $data = [
41             'event'                    => $this->event,
42             'text'                     => $this->formatText(),
43             'triggered_at'             => Carbon::createFromTimestampUTC($this->initiatedTime)->toISOString(),
44             'triggered_by'             => $this->initiator->attributesToArray(),
45             'triggered_by_profile_url' => $this->initiator->getProfileUrl(),
46             'webhook_id'               => $this->webhook->id,
47             'webhook_name'             => $this->webhook->name,
48         ];
49
50         if (method_exists($this->detail, 'getUrl')) {
51             $data['url'] = $this->detail->getUrl();
52         }
53
54         if ($this->detail instanceof Model) {
55             $data['related_item'] = $this->formatModel();
56         }
57
58         return $data;
59     }
60
61     /**
62      * @param callable(string, Model):bool $condition
63      * @param callable(Model):void         $format
64      */
65     public function addModelFormatter(callable $condition, callable $format): void
66     {
67         $this->modelFormatters[] = [
68             'condition' => $condition,
69             'format'    => $format,
70         ];
71     }
72
73     public function addDefaultModelFormatters(): void
74     {
75         // Load entity owner, creator, updater details
76         $this->addModelFormatter(
77             fn ($event, $model) => ($model instanceof Entity),
78             fn ($model) => $model->load(['ownedBy', 'createdBy', 'updatedBy'])
79         );
80
81         // Load revision detail for page update and create events
82         $this->addModelFormatter(
83             fn ($event, $model) => ($model instanceof Page && ($event === ActivityType::PAGE_CREATE || $event === ActivityType::PAGE_UPDATE)),
84             fn ($model) => $model->load('currentRevision')
85         );
86     }
87
88     protected function formatModel(): array
89     {
90         /** @var Model $model */
91         $model = $this->detail;
92         $model->unsetRelations();
93
94         foreach ($this->modelFormatters as $formatter) {
95             if ($formatter['condition']($this->event, $model)) {
96                 $formatter['format']($model);
97             }
98         }
99
100         return $model->toArray();
101     }
102
103     protected function formatText(): string
104     {
105         $textParts = [
106             $this->initiator->name,
107             trans('activities.' . $this->event),
108         ];
109
110         if ($this->detail instanceof Entity) {
111             $textParts[] = '"' . $this->detail->name . '"';
112         }
113
114         return implode(' ', $textParts);
115     }
116
117     public static function getDefault(string $event, Webhook $webhook, $detail, User $initiator, int $initiatedTime): self
118     {
119         $instance = new self($event, $webhook, $detail, $initiator, $initiatedTime);
120         $instance->addDefaultModelFormatters();
121
122         return $instance;
123     }
124 }