3 namespace BookStack\Activity\Tools;
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;
14 class WebhookFormatter
16 protected Webhook $webhook;
17 protected string $event;
18 protected User $initiator;
19 protected int $initiatedTime;
22 * @var string|Loggable
27 * @var array{condition: callable(string, Model):bool, format: callable(Model):void}[]
29 protected $modelFormatters = [];
31 public function __construct(string $event, Webhook $webhook, $detail, User $initiator, int $initiatedTime)
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;
40 public function format(): array
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,
52 if (method_exists($this->detail, 'getUrl')) {
53 $data['url'] = $this->detail->getUrl();
56 if ($this->detail instanceof Model) {
57 $data['related_item'] = $this->formatModel();
64 * @param callable(string, Model):bool $condition
65 * @param callable(Model):void $format
67 public function addModelFormatter(callable $condition, callable $format): void
69 $this->modelFormatters[] = [
70 'condition' => $condition,
75 public function addDefaultModelFormatters(): void
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'])
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')
90 protected function formatModel(): array
92 /** @var Model $model */
93 $model = $this->detail;
94 $model->unsetRelations();
96 foreach ($this->modelFormatters as $formatter) {
97 if ($formatter['condition']($this->event, $model)) {
98 $formatter['format']($model);
102 return $model->toArray();
105 protected function formatText(): string
108 $this->initiator->name,
109 trans('activities.' . $this->event),
112 if ($this->detail instanceof Entity) {
113 $textParts[] = '"' . $this->detail->name . '"';
116 return implode(' ', $textParts);
119 public static function getDefault(string $event, Webhook $webhook, $detail, User $initiator, int $initiatedTime): self
121 $instance = new self($event, $webhook, $detail, $initiator, $initiatedTime);
122 $instance->addDefaultModelFormatters();