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