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

183 lines
5.7 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)
{
}
/**
* @return array<string,mixed>
*/
/**
* @return array<string,mixed>
*/
public function make(User $recipient, BlueprintInterface $blueprint): array
{
$activityType = trim((string) $this->settings->get('sbp-jm-msteams-webhook.activity_type', 'systemDefault'));
$forumName = trim((string) $this->settings->get('forum_title', 'Flarum')) ?: 'Flarum';
$iconId = trim((string) $this->settings->get('sbp-jm-msteams-webhook.icon_id', ''));
// Diskussionstitel + URL dynamisch aus dem Subject ziehen
$discussionTitle = $this->resolveDiscussionTitle($blueprint) ?? $forumName;
$discussionUrl = $this->resolveSubjectUrl($blueprint) ?? 'https://forum.sbp.de';
$previewSnippet = $this->buildPreviewText($blueprint);
// Freie Actor+Reason-Zeile für systemDefault
$reasonText = match ($blueprint::getType()) {
'newPost' => 'Neue Antwort in beobachteter Diskussion',
'postMentioned' => 'Du wurdest in einem Beitrag erwähnt',
'userMentioned' => 'Du wurdest erwähnt',
'postLiked' => 'Dein Beitrag wurde geliked',
default => 'Neue Flarum-Benachrichtigung',
};
// Teams-App-/Tab-Ziel aus deinem aktuellen Manifest
$teamsManifestAppId = 'd92b1be6-ea92-46b1-bcb0-c08ffdd1a61a';
$teamsEntityId = '8ffe419f-ca44-4627-a4b2-f223da2d07aa';
// Diskussion in den Tab-Kontext schreiben
$contextJson = json_encode([
'subPageId' => $discussionUrl,
], JSON_UNESCAPED_SLASHES);
// Teams-Deep-Link auf den Personal Tab
$teamsDeepLink = sprintf(
'https://teams.microsoft.com/l/entity/%s/%s?webUrl=%s&label=%s&context=%s',
rawurlencode($teamsManifestAppId),
rawurlencode($teamsEntityId),
rawurlencode($discussionUrl),
rawurlencode($discussionTitle),
rawurlencode($contextJson)
);
$payload = [
'topic' => [
'source' => 'text',
'value' => $discussionTitle,
'webUrl' => $teamsDeepLink,
],
'activityType' => $activityType !== '' ? $activityType : 'systemDefault',
'previewText' => [
'content' => mb_substr($previewSnippet, 0, 150),
],
'templateParameters' => [
[
'name' => 'systemDefaultText',
'value' => $reasonText,
],
],
];
if ($iconId !== '') {
$payload['iconId'] = $iconId;
}
if (($payload['activityType'] ?? 'systemDefault') !== 'systemDefault') {
$payload['templateParameters'] = [
[
'name' => 'notificationText',
'value' => mb_substr($previewSnippet, 0, 150),
],
];
}
return $payload;
}
protected function buildPreviewText(BlueprintInterface $blueprint): string
{
if ($blueprint::getType() === 'teamsTest') {
return 'Flarum ➜ Teams Test erfolgreich angestoßen';
}
$actor = $blueprint->getFromUser();
$actorName = $actor instanceof User ? (string) ($actor->display_name ?? $actor->username ?? 'Jemand') : 'Jemand';
$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 hat in einer beobachteten Diskussion geantwortet', $actorName),
'postMentioned' => sprintf('%s hat dich in einem Beitrag erwähnt', $actorName),
'userMentioned' => sprintf('%s hat dich erwähnt', $actorName),
'postLiked' => sprintf('%s hat einen Beitrag von dir geliked', $actorName),
'discussionRenamed' => sprintf('%s hat eine Diskussion umbenannt', $actorName),
default => sprintf('%s: neue Flarum-Benachrichtigung (%s)', $actorName, $type),
};
if ($subjectTitle) {
$text .= ' ' . $subjectTitle;
}
return mb_substr($text, 0, 150);
}
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;
}
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;
}
protected function buildChainId(User $recipient, BlueprintInterface $blueprint): int
{
$subject = $blueprint->getSubject();
$subjectId = is_object($subject) && isset($subject->id) ? (string) $subject->id : '0';
return abs(crc32(implode('|', [
(string) $recipient->id,
$blueprint::getType(),
$subjectId,
])));
}
}