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