2021-04-30 16:07:31 +00:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Common code for all Echo event presentation models for DiscussionTools events.
|
|
|
|
*
|
|
|
|
* @file
|
|
|
|
* @ingroup Extensions
|
|
|
|
* @license MIT
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace MediaWiki\Extension\DiscussionTools\Notifications;
|
|
|
|
|
|
|
|
use EchoDiscussionParser;
|
|
|
|
use MediaWiki\Revision\RevisionRecord;
|
2021-12-21 00:47:26 +00:00
|
|
|
use WikiMap;
|
2021-04-30 16:07:31 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This trait must be only used on EchoEventPresentationModel subclasses.
|
|
|
|
*
|
|
|
|
* @property \EchoEvent $event
|
|
|
|
* @property \Language $language
|
2022-01-20 23:06:36 +00:00
|
|
|
* @property \EchoPresentationModelSection $section
|
2021-04-30 16:07:31 +00:00
|
|
|
*/
|
|
|
|
trait DiscussionToolsEventTrait {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param int $type RevisionRecord::DELETED_* constant
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
abstract protected function userCan( $type );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
abstract protected function isBundled();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return \EchoEvent[]
|
|
|
|
*/
|
|
|
|
abstract protected function getBundledEvents();
|
|
|
|
|
2021-12-09 00:13:21 +00:00
|
|
|
/**
|
|
|
|
* @return int[]|false
|
|
|
|
*/
|
|
|
|
abstract protected function getBundledIds();
|
|
|
|
|
2021-04-30 16:07:31 +00:00
|
|
|
/**
|
|
|
|
* Get a link to the individual comment, if available.
|
|
|
|
*
|
2021-12-01 14:53:20 +00:00
|
|
|
* @return string|null Full URL linking to the comment, null if not available
|
2021-04-30 16:07:31 +00:00
|
|
|
*/
|
2021-12-01 14:53:20 +00:00
|
|
|
protected function getCommentLink(): ?string {
|
2021-04-30 16:07:31 +00:00
|
|
|
if ( !$this->userCan( RevisionRecord::DELETED_TEXT ) ) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
if ( !$this->isBundled() ) {
|
|
|
|
// For a single-comment notification, make a pretty(ish) direct link to the comment.
|
|
|
|
// The browser scrolls and we highlight it client-side.
|
|
|
|
$commentId = $this->event->getExtraParam( 'comment-id' );
|
|
|
|
if ( !$commentId ) {
|
|
|
|
return null;
|
|
|
|
}
|
2022-01-20 23:06:36 +00:00
|
|
|
$title = $this->event->getTitle();
|
2021-04-30 16:07:31 +00:00
|
|
|
return $title->createFragmentTarget( $commentId )->getFullURL();
|
|
|
|
} else {
|
|
|
|
// For a multi-comment notification, we can't make a direct link, because we don't know
|
|
|
|
// which comment appears first on the page; the best we can do is a link to the section.
|
|
|
|
// We handle both scrolling and highlighting client-side, using the ugly parameter
|
|
|
|
// listing all comments.
|
|
|
|
|
|
|
|
// Bundling works differently for different notification types:
|
|
|
|
// * Subscribed topic notifications are bundled per-section.
|
|
|
|
// * User talk page notifications are bundled per-page (so basically, always bundled).
|
|
|
|
// * Mention notifications are *never* bundled.
|
|
|
|
|
2022-03-07 23:13:06 +00:00
|
|
|
// Just pass the oldest comment in the bundle. The client has access to the comment
|
2022-02-21 00:22:39 +00:00
|
|
|
// tree and so can work out all the other comments since this one.
|
2022-03-07 23:13:06 +00:00
|
|
|
|
|
|
|
// This does not include the newest comment, $this->event, but we are looking
|
|
|
|
// for the oldest comment.
|
|
|
|
$bundledEvents = $this->getBundledEvents();
|
|
|
|
$oldestEvent = end( $bundledEvents );
|
|
|
|
$params = [ 'dtnewcommentssince' => $oldestEvent->getExtraParam( 'comment-id' ) ];
|
2022-02-21 00:22:39 +00:00
|
|
|
if ( $this->event->getExtraParam( 'subscribed-comment-name' ) ) {
|
|
|
|
// Topic notifications: Tell client to restrict highlights to this thread
|
|
|
|
$params[ 'dtinthread' ] = 1;
|
2021-04-30 16:07:31 +00:00
|
|
|
}
|
2022-01-20 23:06:36 +00:00
|
|
|
// This may or may not have a fragment identifier, depending on whether it was recorded for
|
|
|
|
// the first one of the bundled events. It's usually not needed because we handle scrolling
|
|
|
|
// client-side, but we can keep it for no-JS users, and to reduce the jump when scrolling.
|
|
|
|
$titleWithOptionalSection = $this->section->getTitleWithSection();
|
|
|
|
return $titleWithOptionalSection->getFullURL( $params );
|
2021-04-30 16:07:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a snippet of the individual comment, if available.
|
|
|
|
*
|
|
|
|
* @return string The snippet, as plain text (may be empty)
|
|
|
|
*/
|
2021-12-01 14:53:20 +00:00
|
|
|
protected function getContentSnippet(): string {
|
2021-04-30 16:07:31 +00:00
|
|
|
if ( !$this->userCan( RevisionRecord::DELETED_TEXT ) ) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
// Note that we store plain text in the 'content' param.
|
|
|
|
// Echo also has a 'content' param (for mention notifications), but it contains wikitext.
|
|
|
|
$content = $this->event->getExtraParam( 'content' );
|
|
|
|
if ( !$content ) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
return $this->language->truncateForVisual( $content, EchoDiscussionParser::DEFAULT_SNIPPET_LENGTH );
|
|
|
|
}
|
|
|
|
|
2021-12-09 00:13:21 +00:00
|
|
|
/**
|
|
|
|
* Add mark-as-read params to a link array
|
|
|
|
*
|
|
|
|
* Taken from EchoEventPresentationModel::getPrimaryLinkWithMarkAsRead
|
|
|
|
* TODO: Upstream to Echo?
|
|
|
|
*
|
|
|
|
* @param array $link Link
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
protected function addMarkAsRead( $link ) {
|
|
|
|
global $wgEchoCrossWikiNotifications;
|
|
|
|
if ( $link ) {
|
|
|
|
$eventIds = [ $this->event->getId() ];
|
|
|
|
if ( $this->getBundledIds() ) {
|
|
|
|
$eventIds = array_merge( $eventIds, $this->getBundledIds() );
|
|
|
|
}
|
|
|
|
|
|
|
|
$queryParams = [ 'markasread' => implode( '|', $eventIds ) ];
|
|
|
|
if ( $wgEchoCrossWikiNotifications ) {
|
2021-12-21 00:47:26 +00:00
|
|
|
$queryParams['markasreadwiki'] = WikiMap::getCurrentWikiId();
|
2021-12-09 00:13:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
$link['url'] = wfAppendQuery( $link['url'], $queryParams );
|
|
|
|
}
|
|
|
|
return $link;
|
|
|
|
}
|
|
|
|
|
2021-04-30 16:07:31 +00:00
|
|
|
}
|