]> BookStack Code Mirror - bookstack/blob - app/Activity/Tools/ActivityLogger.php
Comments: Updated reply-to and general styling
[bookstack] / app / Activity / Tools / ActivityLogger.php
1 <?php
2
3 namespace BookStack\Activity\Tools;
4
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\Entities\Models\Entity;
10 use BookStack\Facades\Theme;
11 use BookStack\Theming\ThemeEvents;
12 use Illuminate\Database\Eloquent\Builder;
13 use Illuminate\Support\Facades\Log;
14
15 class ActivityLogger
16 {
17     /**
18      * Add a generic activity event to the database.
19      *
20      * @param string|Loggable $detail
21      */
22     public function add(string $type, $detail = '')
23     {
24         $detailToStore = ($detail instanceof Loggable) ? $detail->logDescriptor() : $detail;
25
26         $activity = $this->newActivityForUser($type);
27         $activity->detail = $detailToStore;
28
29         if ($detail instanceof Entity) {
30             $activity->entity_id = $detail->id;
31             $activity->entity_type = $detail->getMorphClass();
32         }
33
34         $activity->save();
35
36         $this->setNotification($type);
37         $this->dispatchWebhooks($type, $detail);
38         Theme::dispatch(ThemeEvents::ACTIVITY_LOGGED, $type, $detail);
39     }
40
41     /**
42      * Get a new activity instance for the current user.
43      */
44     protected function newActivityForUser(string $type): Activity
45     {
46         return (new Activity())->forceFill([
47             'type'     => strtolower($type),
48             'user_id'  => user()->id,
49             'ip'       => IpFormatter::fromCurrentRequest()->format(),
50         ]);
51     }
52
53     /**
54      * Removes the entity attachment from each of its activities
55      * and instead uses the 'extra' field with the entities name.
56      * Used when an entity is deleted.
57      */
58     public function removeEntity(Entity $entity)
59     {
60         $entity->activity()->update([
61             'detail'       => $entity->name,
62             'entity_id'    => null,
63             'entity_type'  => null,
64         ]);
65     }
66
67     /**
68      * Flashes a notification message to the session if an appropriate message is available.
69      */
70     protected function setNotification(string $type): void
71     {
72         $notificationTextKey = 'activities.' . $type . '_notification';
73         if (trans()->has($notificationTextKey)) {
74             $message = trans($notificationTextKey);
75             session()->flash('success', $message);
76         }
77     }
78
79     /**
80      * @param string|Loggable $detail
81      */
82     protected function dispatchWebhooks(string $type, $detail): void
83     {
84         $webhooks = Webhook::query()
85             ->whereHas('trackedEvents', function (Builder $query) use ($type) {
86                 $query->where('event', '=', $type)
87                     ->orWhere('event', '=', 'all');
88             })
89             ->where('active', '=', true)
90             ->get();
91
92         foreach ($webhooks as $webhook) {
93             dispatch(new DispatchWebhookJob($webhook, $type, $detail));
94         }
95     }
96
97     /**
98      * Log out a failed login attempt, Providing the given username
99      * as part of the message if the '%u' string is used.
100      */
101     public function logFailedLogin(string $username)
102     {
103         $message = config('logging.failed_login.message');
104         if (!$message) {
105             return;
106         }
107
108         $message = str_replace('%u', $username, $message);
109         $channel = config('logging.failed_login.channel');
110         Log::channel($channel)->warning($message);
111     }
112 }