flarum-msteams-webhook/src/Support/NotificationPayloadFactory.php

170 lines
5.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
namespace SbpJm\FlarumMSTeamsWebhook\Support;
use Flarum\Discussion\Discussion;
use Flarum\Notification\Blueprint\BlueprintInterface;
use Flarum\Post\Post;
use Flarum\Settings\SettingsRepositoryInterface;
use Flarum\User\User;
class NotificationPayloadFactory
{
public function __construct(
protected SettingsRepositoryInterface $settings
) {}
/**
* Build the payload for Microsoft Teams Activity Feed.
*
* Informational only (systemDefault).
* No clickable navigation from the Activity Feed is expected.
*
* @return array<string, mixed>
*/
public function make(User $recipient, BlueprintInterface $blueprint): array
{
// Activity Feed is informational only
$activityType = 'systemDefault';
$forumName = trim((string) $this->settings->get('forum_title', 'Flarum')) ?: 'Flarum';
// Resolve dynamic data
$discussionTitle = $this->resolveDiscussionTitle($blueprint) ?? $forumName;
$discussionUrl = $this->resolveSubjectUrl($blueprint)
?? rtrim((string) $this->settings->get('sbp-jm-msteams-webhook.forum_base_url', ''), '/');
$previewSnippet = $this->buildPreviewText($blueprint);
$reasonText = $this->buildReasonTextEn($blueprint);
// Teams requires /l/ URLs for topic.source = text
// /l/browser is the official, neutral deep link for external pages
$teamsBrowserLink = 'https://teams.microsoft.com/l/browser/' . rawurlencode($discussionUrl);
return [
'topic' => [
'source' => 'text',
'value' => $discussionTitle,
'webUrl' => $teamsBrowserLink,
],
'activityType' => $activityType,
'previewText' => [
'content' => mb_substr($previewSnippet, 0, 150),
],
'templateParameters' => [
[
'name' => 'systemDefaultText',
'value' => $reasonText,
],
],
];
}
/**
* Resolve the discussion title from the notification subject.
*/
protected function resolveDiscussionTitle(BlueprintInterface $blueprint): ?string
{
$subject = $blueprint->getSubject();
if ($subject instanceof Discussion) {
return (string) $subject->title;
}
if ($subject instanceof Post && $subject->discussion) {
return (string) $subject->discussion->title;
}
return null;
}
/**
* Resolve the URL to the discussion or specific post.
*/
protected function resolveSubjectUrl(BlueprintInterface $blueprint): ?string
{
$baseUrl = rtrim(
(string) $this->settings->get('sbp-jm-msteams-webhook.forum_base_url', ''),
'/'
);
if ($baseUrl === '') {
return null;
}
$subject = $blueprint->getSubject();
if ($subject instanceof Discussion) {
return sprintf('%s/d/%s', $baseUrl, $subject->id);
}
if ($subject instanceof Post) {
$discussionId = $subject->discussion_id;
$postNumber = $subject->number;
if ($discussionId !== null && $postNumber !== null) {
return sprintf('%s/d/%s/%s', $baseUrl, $discussionId, $postNumber);
}
}
return $baseUrl;
}
/**
* English reason text for Activity Feed (systemDefault).
*/
protected function buildReasonTextEn(BlueprintInterface $blueprint): string
{
return match ($blueprint::getType()) {
'newPost' => 'There was a new reply in a discussion you are following',
'postMentioned' => 'You were mentioned in a post',
'userMentioned' => 'You were mentioned',
'postLiked' => 'Your post was liked',
'discussionRenamed' => 'A discussion was renamed',
default => 'New forum activity',
};
}
/**
* Build a short preview snippet shown in the Activity Feed.
*/
protected function buildPreviewText(BlueprintInterface $blueprint): string
{
if ($blueprint::getType() === 'teamsTest') {
return 'Flarum → Teams test notification sent successfully';
}
$actor = $blueprint->getFromUser();
$actorName = $actor instanceof User
? (string) ($actor->display_name ?? $actor->username ?? 'Someone')
: 'Someone';
$type = $blueprint::getType();
$subject = $blueprint->getSubject();
$subjectTitle = null;
if ($subject instanceof Discussion) {
$subjectTitle = (string) $subject->title;
} elseif ($subject instanceof Post && $subject->discussion) {
$subjectTitle = (string) $subject->discussion->title;
}
$text = match ($type) {
'newPost' => sprintf('%s replied to a discussion', $actorName),
'postMentioned' => sprintf('%s mentioned you in a post', $actorName),
'userMentioned' => sprintf('%s mentioned you', $actorName),
'postLiked' => sprintf('%s liked your post', $actorName),
'discussionRenamed' => sprintf('%s renamed a discussion', $actorName),
default => sprintf('%s: new forum activity', $actorName),
};
if ($subjectTitle) {
$text .= ' ' . $subjectTitle;
}
return mb_substr($text, 0, 150);
}
}