Skip to content

Instantly share code, notes, and snippets.

@ssddanbrown
Last active November 29, 2023 20:01
Show Gist options
  • Save ssddanbrown/72e14609dd791509f3825e0aaaf4bd6c to your computer and use it in GitHub Desktop.
Save ssddanbrown/72e14609dd791509f3825e0aaaf4bd6c to your computer and use it in GitHub Desktop.
bookstack-hack-send-notifications-to-email-tags
<?php
use BookStack\Activity\ActivityType;
use BookStack\Activity\Models\Tag;
use BookStack\Activity\Notifications\Messages\BaseActivityNotification;
use BookStack\Entities\Models\Page;
use BookStack\Facades\Theme;
use BookStack\Theming\ThemeEvents;
use BookStack\Users\Models\User;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Support\Facades\Notification;
// This customization notifies page updates to emails tagged at the parent book.
// For example, If a tag, with name `Notify` and value `dan@example.com` is applied to a book,
// updates to pages within will be notified via email `dan@example.com`.
// Multiple tags could be applied to define mulitple emails to notify.
// Note: This is not officially supported, may break upon update, and the email sending may slow down operations.
// Also, users could be spammed with emails on repeated updates.
// Also, might hit email system rate-limits.
// Also, this relies on role names being stable.
// This notification class represents the notification that'll be sent to users.
// The text of the notification can be customized within the 'toMail' function.
class PageUpdateNotification extends BaseActivityNotification {
public function toMail($notifiable): MailMessage
{
/** @var Page $page */
$page = $this->detail;
$updater = $this->user;
return (new MailMessage())
->subject('BookStack page update notification')
->line("The page \"{$page->name}\" has been updated by \"{$updater->name}\"")
->action('View Page', $page->getUrl());
}
}
// This function does the work of sending notifications to the
// relevant users that are in roles denoted by a tag on the parent book.
function notifyRequiredUsers(Page $page) {
// Get our relevant tags
/** @var ?Tag $notifyTag */
$notifyTags = Tag::query()
->where('entity_type', '=', 'book')
->where('entity_id', '=', $page->book_id)
->where('name', '=', 'notify')
->get();
// Get the emails out from those tags
$emails = $notifyTags->map(fn(Tag $tag) => $tag->value)->filter(function ($email) {
return str_contains($email, '@');
})->all();
$updater = User::query()->findOrFail($page->updated_by);
// Send a notification to each of the emails we want to notify
foreach ($emails as $email) {
Notification::route('mail', $email)
->notify(new PageUpdateNotification($page, $updater));
usleep(100000); // Slight 0.1s delay to help rate limit abuse
}
}
// Listen to page update events and kick-start our notification logic
Theme::listen(ThemeEvents::ACTIVITY_LOGGED, function (string $type, $detail) {
if ($type === ActivityType::PAGE_UPDATE && $detail instanceof Page) {
notifyRequiredUsers($detail);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment