aboutsummaryrefslogtreecommitdiffstats
path: root/includes/changes/ChangesFeed.php
blob: 4d00fbc543fcc360ac48fcf6fb96d1cea51de6bc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
<?php
/**
 * Feed for list of changes.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 * http://www.gnu.org/copyleft/gpl.html
 *
 * @file
 */

/**
 * Feed to Special:RecentChanges and Special:RecentChangesLinked.
 *
 * @ingroup Feed
 */
class ChangesFeed {
	private $format;

	/**
	 * @param string $format Feed's format (either 'rss' or 'atom')
	 */
	public function __construct( $format ) {
		$this->format = $format;
	}

	/**
	 * Get a ChannelFeed subclass object to use
	 *
	 * @param string $title Feed's title
	 * @param string $description Feed's description
	 * @param string $url Url of origin page
	 * @return ChannelFeed|bool ChannelFeed subclass or false on failure
	 */
	public function getFeedObject( $title, $description, $url ) {
		global $wgSitename, $wgLanguageCode, $wgFeedClasses;

		if ( !isset( $wgFeedClasses[$this->format] ) ) {
			return false;
		}

		if ( !array_key_exists( $this->format, $wgFeedClasses ) ) {
			// falling back to atom
			$this->format = 'atom';
		}

		$feedTitle = "$wgSitename  - {$title} [$wgLanguageCode]";
		return new $wgFeedClasses[$this->format](
			$feedTitle, htmlspecialchars( $description ), $url );
	}

	/**
	 * Generate the feed items given a row from the database.
	 * @param object $rows IDatabase resource with recentchanges rows
	 * @return array
	 */
	public static function buildItems( $rows ) {
		$items = [];

		# Merge adjacent edits by one user
		$sorted = [];
		$n = 0;
		foreach ( $rows as $obj ) {
			if ( $obj->rc_type == RC_EXTERNAL ) {
				continue;
			}

			if ( $n > 0 &&
				$obj->rc_type == RC_EDIT &&
				$obj->rc_namespace >= 0 &&
				$obj->rc_cur_id == $sorted[$n - 1]->rc_cur_id &&
				$obj->rc_user_text == $sorted[$n - 1]->rc_user_text ) {
				$sorted[$n - 1]->rc_last_oldid = $obj->rc_last_oldid;
			} else {
				$sorted[$n] = $obj;
				$n++;
			}
		}

		foreach ( $sorted as $obj ) {
			$title = Title::makeTitle( $obj->rc_namespace, $obj->rc_title );
			$talkpage = MWNamespace::hasTalkNamespace( $obj->rc_namespace )
				? $title->getTalkPage()->getFullURL()
				: '';

			// Skip items with deleted content (avoids partially complete/inconsistent output)
			if ( $obj->rc_deleted ) {
				continue;
			}

			if ( $obj->rc_this_oldid ) {
				$url = $title->getFullURL( [
					'diff' => $obj->rc_this_oldid,
					'oldid' => $obj->rc_last_oldid,
				] );
			} else {
				// log entry or something like that.
				$url = $title->getFullURL();
			}

			$items[] = new FeedItem(
				$title->getPrefixedText(),
				FeedUtils::formatDiff( $obj ),
				$url,
				$obj->rc_timestamp,
				( $obj->rc_deleted & Revision::DELETED_USER )
					? wfMessage( 'rev-deleted-user' )->escaped() : $obj->rc_user_text,
				$talkpage
			);
		}

		return $items;
	}
}