1 <?php namespace BookStack\Actions;
3 use BookStack\Auth\Permissions\PermissionService;
4 use BookStack\Auth\User;
5 use BookStack\Entities\Entity;
6 use Illuminate\Support\Collection;
7 use Illuminate\Support\Facades\Log;
13 protected $permissionService;
16 * ActivityService constructor.
18 public function __construct(Activity $activity, PermissionService $permissionService)
20 $this->activity = $activity;
21 $this->permissionService = $permissionService;
26 * Add activity data to database.
28 public function add(Entity $entity, string $activityKey, ?int $bookId = null)
30 $activity = $this->newActivityForUser($activityKey, $bookId);
31 $entity->activity()->save($activity);
32 $this->setNotification($activityKey);
36 * Adds a activity history with a message, without binding to a entity.
38 public function addMessage(string $activityKey, string $message, ?int $bookId = null)
40 $this->newActivityForUser($activityKey, $bookId)->forceFill([
44 $this->setNotification($activityKey);
48 * Get a new activity instance for the current user.
50 protected function newActivityForUser(string $key, ?int $bookId = null): Activity
52 return $this->activity->newInstance()->forceFill([
53 'key' => strtolower($key),
54 'user_id' => $this->user->id,
55 'book_id' => $bookId ?? 0,
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): Collection
66 $activities = $entity->activity()->get();
67 $entity->activity()->update([
68 'extra' => $entity->name,
76 * Gets the latest activity.
78 public function latest(int $count = 20, int $page = 0): array
80 $activityList = $this->permissionService
81 ->filterRestrictedEntityRelations($this->activity, 'activities', 'entity_id', 'entity_type')
82 ->orderBy('created_at', 'desc')
83 ->with(['user', 'entity'])
84 ->skip($count * $page)
88 return $this->filterSimilar($activityList);
92 * Gets the latest activity for an entity, Filtering out similar
93 * items to prevent a message activity list.
95 public function entityActivity(Entity $entity, int $count = 20, int $page = 1): array
97 if ($entity->isA('book')) {
98 $query = $this->activity->newQuery()->where('book_id', '=', $entity->id);
100 $query = $this->activity->newQuery()->where('entity_type', '=', $entity->getMorphClass())
101 ->where('entity_id', '=', $entity->id);
104 $activity = $this->permissionService
105 ->filterRestrictedEntityRelations($query, 'activities', 'entity_id', 'entity_type')
106 ->orderBy('created_at', 'desc')
107 ->with(['entity', 'user.avatar'])
108 ->skip($count * ($page - 1))
112 return $this->filterSimilar($activity);
116 * Get latest activity for a user, Filtering out similar items.
118 public function userActivity(User $user, int $count = 20, int $page = 0): array
120 $activityList = $this->permissionService
121 ->filterRestrictedEntityRelations($this->activity, 'activities', 'entity_id', 'entity_type')
122 ->orderBy('created_at', 'desc')
123 ->where('user_id', '=', $user->id)
124 ->skip($count * $page)
128 return $this->filterSimilar($activityList);
132 * Filters out similar activity.
133 * @param Activity[] $activities
136 protected function filterSimilar(iterable $activities): array
139 $previousItem = null;
141 foreach ($activities as $activityItem) {
142 if (!$previousItem || !$activityItem->isSimilarTo($previousItem)) {
143 $newActivity[] = $activityItem;
146 $previousItem = $activityItem;
153 * Flashes a notification message to the session if an appropriate message is available.
155 protected function setNotification(string $activityKey)
157 $notificationTextKey = 'activities.' . $activityKey . '_notification';
158 if (trans()->has($notificationTextKey)) {
159 $message = trans($notificationTextKey);
160 session()->flash('success', $message);
165 * Log out a failed login attempt, Providing the given username
166 * as part of the message if the '%u' string is used.
168 public function logFailedLogin(string $username)
170 $message = config('logging.failed_login.message');
175 $message = str_replace("%u", $username, $message);
176 $channel = config('logging.failed_login.channel');
177 Log::channel($channel)->warning($message);