Last active
November 29, 2023 20:01
-
-
Save ssddanbrown/72e14609dd791509f3825e0aaaf4bd6c to your computer and use it in GitHub Desktop.
bookstack-hack-send-notifications-to-email-tags
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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