3 namespace BookStack\Activity\Tools;
5 use BookStack\Activity\DispatchWebhookJob;
6 use BookStack\Activity\Models\Activity;
7 use BookStack\Activity\Models\Loggable;
8 use BookStack\Activity\Models\Webhook;
9 use BookStack\Activity\Notifications\NotificationManager;
10 use BookStack\Entities\Models\Entity;
11 use BookStack\Facades\Theme;
12 use BookStack\Theming\ThemeEvents;
13 use Illuminate\Database\Eloquent\Builder;
14 use Illuminate\Support\Facades\Log;
18 public function __construct(
19 protected NotificationManager $notifications
21 $this->notifications->loadDefaultHandlers();
25 * Add a generic activity event to the database.
27 public function add(string $type, string|Loggable $detail = ''): void
29 $detailToStore = ($detail instanceof Loggable) ? $detail->logDescriptor() : $detail;
31 $activity = $this->newActivityForUser($type);
32 $activity->detail = $detailToStore;
34 if ($detail instanceof Entity) {
35 $activity->entity_id = $detail->id;
36 $activity->entity_type = $detail->getMorphClass();
41 $this->setNotification($type);
42 $this->dispatchWebhooks($type, $detail);
43 $this->notifications->handle($activity, $detail, user());
44 Theme::dispatch(ThemeEvents::ACTIVITY_LOGGED, $type, $detail);
48 * Get a new activity instance for the current user.
50 protected function newActivityForUser(string $type): Activity
52 return (new Activity())->forceFill([
53 'type' => strtolower($type),
54 'user_id' => user()->id,
55 'ip' => IpFormatter::fromCurrentRequest()->format(),
60 * Removes the entity attachment from each of its activities
61 * and instead uses the 'extra' field with the entities name.
62 * Used when an entity is deleted.
64 public function removeEntity(Entity $entity): void
66 $entity->activity()->update([
67 'detail' => $entity->name,
69 'entity_type' => null,
74 * Flashes a notification message to the session if an appropriate message is available.
76 protected function setNotification(string $type): void
78 $notificationTextKey = 'activities.' . $type . '_notification';
79 if (trans()->has($notificationTextKey)) {
80 $message = trans($notificationTextKey);
81 session()->flash('success', $message);
85 protected function dispatchWebhooks(string $type, string|Loggable $detail): void
87 $webhooks = Webhook::query()
88 ->whereHas('trackedEvents', function (Builder $query) use ($type) {
89 $query->where('event', '=', $type)
90 ->orWhere('event', '=', 'all');
92 ->where('active', '=', true)
95 foreach ($webhooks as $webhook) {
96 dispatch(new DispatchWebhookJob($webhook, $type, $detail));
101 * Log out a failed login attempt, Providing the given username
102 * as part of the message if the '%u' string is used.
104 public function logFailedLogin(string $username): void
106 $message = config('logging.failed_login.message');
111 $message = str_replace('%u', $username, $message);
112 $channel = config('logging.failed_login.channel');
113 Log::channel($channel)->warning($message);