Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 33 |
|
0.00% |
0 / 3 |
CRAP | |
0.00% |
0 / 1 |
DiscussionToolsEventTrait | |
0.00% |
0 / 33 |
|
0.00% |
0 / 3 |
182 | |
0.00% |
0 / 1 |
userCan | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
isBundled | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
getBundledEvents | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
getBundledIds | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
getCommentLink | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
42 | |||
getContentSnippet | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
addMarkAsRead | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
20 |
1 | <?php |
2 | /** |
3 | * Common code for all Echo event presentation models for DiscussionTools events. |
4 | * |
5 | * @file |
6 | * @ingroup Extensions |
7 | * @license MIT |
8 | */ |
9 | |
10 | namespace MediaWiki\Extension\DiscussionTools\Notifications; |
11 | |
12 | use MediaWiki\Extension\Notifications\DiscussionParser; |
13 | use MediaWiki\Extension\Notifications\Formatters\EchoPresentationModelSection; |
14 | use MediaWiki\Extension\Notifications\Model\Event; |
15 | use MediaWiki\Language\Language; |
16 | use MediaWiki\Revision\RevisionRecord; |
17 | use MediaWiki\WikiMap\WikiMap; |
18 | |
19 | /** |
20 | * This trait must be only used on EchoEventPresentationModel subclasses. |
21 | * |
22 | * @property Event $event |
23 | * @property Language $language |
24 | * @property EchoPresentationModelSection $section |
25 | */ |
26 | trait DiscussionToolsEventTrait { |
27 | |
28 | /** |
29 | * @param int $type RevisionRecord::DELETED_* constant |
30 | * @return bool |
31 | */ |
32 | abstract protected function userCan( $type ); |
33 | |
34 | /** |
35 | * @return bool |
36 | */ |
37 | abstract protected function isBundled(); |
38 | |
39 | /** |
40 | * @return Event[] |
41 | */ |
42 | abstract protected function getBundledEvents(); |
43 | |
44 | /** |
45 | * @return int[]|false |
46 | */ |
47 | abstract protected function getBundledIds(); |
48 | |
49 | /** |
50 | * Get a link to the individual comment, if available. |
51 | * |
52 | * @return string|null Full URL linking to the comment, null if not available |
53 | */ |
54 | protected function getCommentLink(): ?string { |
55 | if ( !$this->userCan( RevisionRecord::DELETED_TEXT ) ) { |
56 | return null; |
57 | } |
58 | if ( !$this->isBundled() ) { |
59 | // For a single-comment notification, make a pretty(ish) direct link to the comment. |
60 | // The browser scrolls and we highlight it client-side. |
61 | $commentId = $this->event->getExtraParam( 'comment-id' ); |
62 | if ( !$commentId ) { |
63 | return null; |
64 | } |
65 | $title = $this->event->getTitle(); |
66 | return $title->createFragmentTarget( $commentId )->getFullURL(); |
67 | } else { |
68 | // For a multi-comment notification, we can't make a direct link, because we don't know |
69 | // which comment appears first on the page; the best we can do is a link to the section. |
70 | // We handle both scrolling and highlighting client-side, using the ugly parameter |
71 | // listing all comments. |
72 | |
73 | // Bundling works differently for different notification types: |
74 | // * Subscribed topic notifications are bundled per-section. |
75 | // * User talk page notifications are bundled per-page (so basically, always bundled). |
76 | // * Mention notifications are *never* bundled. |
77 | |
78 | // Just pass the oldest comment in the bundle. The client has access to the comment |
79 | // tree and so can work out all the other comments since this one. |
80 | |
81 | // This does not include the newest comment, $this->event, but we are looking |
82 | // for the oldest comment. |
83 | $bundledEvents = $this->getBundledEvents(); |
84 | $oldestEvent = end( $bundledEvents ); |
85 | $params = [ 'dtnewcommentssince' => $oldestEvent->getExtraParam( 'comment-id' ) ]; |
86 | if ( $this->event->getType() === 'dt-added-topic' ) { |
87 | // New topics notifications: Tell client to only highlight topics **started** since this one |
88 | $params[ 'dtsincethread' ] = 1; |
89 | } elseif ( $this->event->getExtraParam( 'subscribed-comment-name' ) ) { |
90 | // Topic notifications: Tell client to restrict highlights to this thread |
91 | $params[ 'dtinthread' ] = 1; |
92 | } |
93 | // This may or may not have a fragment identifier, depending on whether it was recorded for |
94 | // the first one of the bundled events. It's usually not needed because we handle scrolling |
95 | // client-side, but we can keep it for no-JS users, and to reduce the jump when scrolling. |
96 | $titleWithOptionalSection = $this->section->getTitleWithSection(); |
97 | return $titleWithOptionalSection->getFullURL( $params ); |
98 | } |
99 | } |
100 | |
101 | /** |
102 | * Get a snippet of the individual comment, if available. |
103 | * |
104 | * @return string The snippet, as plain text (may be empty) |
105 | */ |
106 | protected function getContentSnippet(): string { |
107 | if ( !$this->userCan( RevisionRecord::DELETED_TEXT ) ) { |
108 | return ''; |
109 | } |
110 | // Note that we store plain text in the 'content' param. |
111 | // Echo also has a 'content' param (for mention notifications), but it contains wikitext. |
112 | $content = $this->event->getExtraParam( 'content' ); |
113 | if ( !$content ) { |
114 | return ''; |
115 | } |
116 | return $this->language->truncateForVisual( $content, DiscussionParser::DEFAULT_SNIPPET_LENGTH ); |
117 | } |
118 | |
119 | /** |
120 | * Add mark-as-read params to a link array |
121 | * |
122 | * Taken from EchoEventPresentationModel::getPrimaryLinkWithMarkAsRead |
123 | * TODO: Upstream to Echo? |
124 | * |
125 | * @param array $link Link |
126 | * @return array |
127 | */ |
128 | protected function addMarkAsRead( $link ) { |
129 | global $wgEchoCrossWikiNotifications; |
130 | if ( $link ) { |
131 | $eventIds = [ $this->event->getId() ]; |
132 | if ( $this->getBundledIds() ) { |
133 | $eventIds = array_merge( $eventIds, $this->getBundledIds() ); |
134 | } |
135 | |
136 | $queryParams = [ 'markasread' => implode( '|', $eventIds ) ]; |
137 | if ( $wgEchoCrossWikiNotifications ) { |
138 | $queryParams['markasreadwiki'] = WikiMap::getCurrentWikiId(); |
139 | } |
140 | |
141 | $link['url'] = wfAppendQuery( $link['url'], $queryParams ); |
142 | } |
143 | return $link; |
144 | } |
145 | |
146 | } |