| 
									
										
										
										
											2022-03-27 00:44:34 +08:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 00:56:55 +08:00
										 |  |  | namespace BookStack\Activity\Tools; | 
					
						
							| 
									
										
										
										
											2022-03-27 00:44:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 00:56:55 +08:00
										 |  |  | use BookStack\Activity\ActivityType; | 
					
						
							|  |  |  | use BookStack\Activity\Models\Loggable; | 
					
						
							|  |  |  | use BookStack\Activity\Models\Webhook; | 
					
						
							|  |  |  | use BookStack\App\Model; | 
					
						
							| 
									
										
										
										
											2022-03-27 00:44:34 +08:00
										 |  |  | use BookStack\Entities\Models\Entity; | 
					
						
							|  |  |  | use BookStack\Entities\Models\Page; | 
					
						
							| 
									
										
										
										
											2023-05-18 00:56:55 +08:00
										 |  |  | use BookStack\Users\Models\User; | 
					
						
							| 
									
										
										
										
											2022-03-27 00:44:34 +08:00
										 |  |  | use Illuminate\Support\Carbon; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class WebhookFormatter | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     protected Webhook $webhook; | 
					
						
							|  |  |  |     protected string $event; | 
					
						
							|  |  |  |     protected User $initiator; | 
					
						
							|  |  |  |     protected int $initiatedTime; | 
					
						
							| 
									
										
										
										
											2023-07-12 23:16:12 +08:00
										 |  |  |     protected string|Loggable $detail; | 
					
						
							| 
									
										
										
										
											2022-03-27 00:44:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * @var array{condition: callable(string, Model):bool, format: callable(Model):void}[] | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected $modelFormatters = []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-12 23:16:12 +08:00
										 |  |  |     public function __construct(string $event, Webhook $webhook, string|Loggable $detail, User $initiator, int $initiatedTime) | 
					
						
							| 
									
										
										
										
											2022-03-27 00:44:34 +08:00
										 |  |  |     { | 
					
						
							|  |  |  |         $this->webhook = $webhook; | 
					
						
							|  |  |  |         $this->event = $event; | 
					
						
							|  |  |  |         $this->initiator = $initiator; | 
					
						
							|  |  |  |         $this->initiatedTime = $initiatedTime; | 
					
						
							|  |  |  |         $this->detail = is_object($detail) ? clone $detail : $detail; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function format(): array | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $data = [ | 
					
						
							|  |  |  |             'event'                    => $this->event, | 
					
						
							|  |  |  |             'text'                     => $this->formatText(), | 
					
						
							|  |  |  |             'triggered_at'             => Carbon::createFromTimestampUTC($this->initiatedTime)->toISOString(), | 
					
						
							|  |  |  |             'triggered_by'             => $this->initiator->attributesToArray(), | 
					
						
							|  |  |  |             'triggered_by_profile_url' => $this->initiator->getProfileUrl(), | 
					
						
							|  |  |  |             'webhook_id'               => $this->webhook->id, | 
					
						
							|  |  |  |             'webhook_name'             => $this->webhook->name, | 
					
						
							|  |  |  |         ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (method_exists($this->detail, 'getUrl')) { | 
					
						
							|  |  |  |             $data['url'] = $this->detail->getUrl(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ($this->detail instanceof Model) { | 
					
						
							|  |  |  |             $data['related_item'] = $this->formatModel(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $data; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * @param callable(string, Model):bool $condition | 
					
						
							| 
									
										
										
										
											2022-03-27 04:38:03 +08:00
										 |  |  |      * @param callable(Model):void         $format | 
					
						
							| 
									
										
										
										
											2022-03-27 00:44:34 +08:00
										 |  |  |      */ | 
					
						
							|  |  |  |     public function addModelFormatter(callable $condition, callable $format): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->modelFormatters[] = [ | 
					
						
							|  |  |  |             'condition' => $condition, | 
					
						
							| 
									
										
										
										
											2022-03-27 04:38:03 +08:00
										 |  |  |             'format'    => $format, | 
					
						
							| 
									
										
										
										
											2022-03-27 00:44:34 +08:00
										 |  |  |         ]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function addDefaultModelFormatters(): void | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // Load entity owner, creator, updater details
 | 
					
						
							|  |  |  |         $this->addModelFormatter( | 
					
						
							| 
									
										
										
										
											2022-03-27 04:38:03 +08:00
										 |  |  |             fn ($event, $model) => ($model instanceof Entity), | 
					
						
							|  |  |  |             fn ($model) => $model->load(['ownedBy', 'createdBy', 'updatedBy']) | 
					
						
							| 
									
										
										
										
											2022-03-27 00:44:34 +08:00
										 |  |  |         ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Load revision detail for page update and create events
 | 
					
						
							|  |  |  |         $this->addModelFormatter( | 
					
						
							| 
									
										
										
										
											2022-03-27 04:38:03 +08:00
										 |  |  |             fn ($event, $model) => ($model instanceof Page && ($event === ActivityType::PAGE_CREATE || $event === ActivityType::PAGE_UPDATE)), | 
					
						
							|  |  |  |             fn ($model) => $model->load('currentRevision') | 
					
						
							| 
									
										
										
										
											2022-03-27 00:44:34 +08:00
										 |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     protected function formatModel(): array | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /** @var Model $model */ | 
					
						
							|  |  |  |         $model = $this->detail; | 
					
						
							|  |  |  |         $model->unsetRelations(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         foreach ($this->modelFormatters as $formatter) { | 
					
						
							|  |  |  |             if ($formatter['condition']($this->event, $model)) { | 
					
						
							|  |  |  |                 $formatter['format']($model); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $model->toArray(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     protected function formatText(): string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $textParts = [ | 
					
						
							|  |  |  |             $this->initiator->name, | 
					
						
							|  |  |  |             trans('activities.' . $this->event), | 
					
						
							|  |  |  |         ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ($this->detail instanceof Entity) { | 
					
						
							|  |  |  |             $textParts[] = '"' . $this->detail->name . '"'; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return implode(' ', $textParts); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public static function getDefault(string $event, Webhook $webhook, $detail, User $initiator, int $initiatedTime): self | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-03-28 18:31:06 +08:00
										 |  |  |         $instance = new self($event, $webhook, $detail, $initiator, $initiatedTime); | 
					
						
							| 
									
										
										
										
											2022-03-27 00:44:34 +08:00
										 |  |  |         $instance->addDefaultModelFormatters(); | 
					
						
							| 
									
										
										
										
											2022-03-27 04:38:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 00:44:34 +08:00
										 |  |  |         return $instance; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-03-27 04:38:03 +08:00
										 |  |  | } |