116 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
			
		
		
	
	
			116 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
<?php
 | 
						|
 | 
						|
namespace BookStack\Activity\Tools;
 | 
						|
 | 
						|
use BookStack\Activity\DispatchWebhookJob;
 | 
						|
use BookStack\Activity\Models\Activity;
 | 
						|
use BookStack\Activity\Models\Loggable;
 | 
						|
use BookStack\Activity\Models\Webhook;
 | 
						|
use BookStack\Activity\Notifications\NotificationManager;
 | 
						|
use BookStack\Entities\Models\Entity;
 | 
						|
use BookStack\Facades\Theme;
 | 
						|
use BookStack\Theming\ThemeEvents;
 | 
						|
use Illuminate\Database\Eloquent\Builder;
 | 
						|
use Illuminate\Support\Facades\Log;
 | 
						|
 | 
						|
class ActivityLogger
 | 
						|
{
 | 
						|
    public function __construct(
 | 
						|
        protected NotificationManager $notifications
 | 
						|
    ) {
 | 
						|
        $this->notifications->loadDefaultHandlers();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Add a generic activity event to the database.
 | 
						|
     */
 | 
						|
    public function add(string $type, string|Loggable $detail = ''): void
 | 
						|
    {
 | 
						|
        $detailToStore = ($detail instanceof Loggable) ? $detail->logDescriptor() : $detail;
 | 
						|
 | 
						|
        $activity = $this->newActivityForUser($type);
 | 
						|
        $activity->detail = $detailToStore;
 | 
						|
 | 
						|
        if ($detail instanceof Entity) {
 | 
						|
            $activity->entity_id = $detail->id;
 | 
						|
            $activity->entity_type = $detail->getMorphClass();
 | 
						|
        }
 | 
						|
 | 
						|
        $activity->save();
 | 
						|
 | 
						|
        $this->setNotification($type);
 | 
						|
        $this->dispatchWebhooks($type, $detail);
 | 
						|
        $this->notifications->handle($activity, $detail, user());
 | 
						|
        Theme::dispatch(ThemeEvents::ACTIVITY_LOGGED, $type, $detail);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get a new activity instance for the current user.
 | 
						|
     */
 | 
						|
    protected function newActivityForUser(string $type): Activity
 | 
						|
    {
 | 
						|
        return (new Activity())->forceFill([
 | 
						|
            'type'     => strtolower($type),
 | 
						|
            'user_id'  => user()->id,
 | 
						|
            'ip'       => IpFormatter::fromCurrentRequest()->format(),
 | 
						|
        ]);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Removes the entity attachment from each of its activities
 | 
						|
     * and instead uses the 'extra' field with the entities name.
 | 
						|
     * Used when an entity is deleted.
 | 
						|
     */
 | 
						|
    public function removeEntity(Entity $entity): void
 | 
						|
    {
 | 
						|
        $entity->activity()->update([
 | 
						|
            'detail'       => $entity->name,
 | 
						|
            'entity_id'    => null,
 | 
						|
            'entity_type'  => null,
 | 
						|
        ]);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Flashes a notification message to the session if an appropriate message is available.
 | 
						|
     */
 | 
						|
    protected function setNotification(string $type): void
 | 
						|
    {
 | 
						|
        $notificationTextKey = 'activities.' . $type . '_notification';
 | 
						|
        if (trans()->has($notificationTextKey)) {
 | 
						|
            $message = trans($notificationTextKey);
 | 
						|
            session()->flash('success', $message);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    protected function dispatchWebhooks(string $type, string|Loggable $detail): void
 | 
						|
    {
 | 
						|
        $webhooks = Webhook::query()
 | 
						|
            ->whereHas('trackedEvents', function (Builder $query) use ($type) {
 | 
						|
                $query->where('event', '=', $type)
 | 
						|
                    ->orWhere('event', '=', 'all');
 | 
						|
            })
 | 
						|
            ->where('active', '=', true)
 | 
						|
            ->get();
 | 
						|
 | 
						|
        foreach ($webhooks as $webhook) {
 | 
						|
            dispatch(new DispatchWebhookJob($webhook, $type, $detail));
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Log out a failed login attempt, Providing the given username
 | 
						|
     * as part of the message if the '%u' string is used.
 | 
						|
     */
 | 
						|
    public function logFailedLogin(string $username): void
 | 
						|
    {
 | 
						|
        $message = config('logging.failed_login.message');
 | 
						|
        if (!$message) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        $message = str_replace('%u', $username, $message);
 | 
						|
        $channel = config('logging.failed_login.channel');
 | 
						|
        Log::channel($channel)->warning($message);
 | 
						|
    }
 | 
						|
}
 |