summaryrefslogtreecommitdiff
path: root/includes/FeedUtils.php
blob: 4502c3a86123adc1f99f5cd6f0f5499519154bcf (plain)
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
<?php

/**
 * Helper functions for feeds
 *
 * @ingroup Feed
 */
class FeedUtils {

	/**
	 * Check whether feed's cache should be cleared; for changes feeds
	 * If the feed should be purged; $timekey and $key will be removed from
	 * $messageMemc
	 *
	 * @param $timekey String: cache key of the timestamp of the last item
	 * @param $key String: cache key of feed's content
	 */
	public static function checkPurge( $timekey, $key ) {
		global $wgRequest, $wgUser, $messageMemc;
		$purge = $wgRequest->getVal( 'action' ) === 'purge';
		if ( $purge && $wgUser->isAllowed('purge') ) {
			$messageMemc->delete( $timekey );
			$messageMemc->delete( $key );
		}
	}

	/**
	 * Check whether feeds can be used and that $type is a valid feed type
	 *
	 * @param $type String: feed type, as requested by the user
	 * @return Boolean
	 */
	public static function checkFeedOutput( $type ) {
		global $wgFeed, $wgFeedClasses;

		if ( !$wgFeed ) {
			global $wgOut;
			$wgOut->addWikiMsg( 'feed-unavailable' );
			return false;
		}

		if( !isset( $wgFeedClasses[$type] ) ) {
			wfHttpError( 500, "Internal Server Error", "Unsupported feed type." );
			return false;
		}

		return true;
	}

	/**
	 * Format a diff for the newsfeed
	 *
	 * @param $row Object: row from the recentchanges table
	 * @return String
	 */
	public static function formatDiff( $row ) {
		global $wgUser;

		$titleObj = Title::makeTitle( $row->rc_namespace, $row->rc_title );
		$timestamp = wfTimestamp( TS_MW, $row->rc_timestamp );
		$actiontext = '';
		if( $row->rc_type == RC_LOG ) {
			if( $row->rc_deleted & LogPage::DELETED_ACTION ) {
				$actiontext = wfMsgHtml('rev-deleted-event');
			} else {
				$actiontext = LogPage::actionText( $row->rc_log_type, $row->rc_log_action,
					$titleObj, $wgUser->getSkin(), LogPage::extractParams($row->rc_params,true,true) );
			}
		}
		return self::formatDiffRow( $titleObj,
			$row->rc_last_oldid, $row->rc_this_oldid,
			$timestamp,
			($row->rc_deleted & Revision::DELETED_COMMENT) ? wfMsgHtml('rev-deleted-comment') : $row->rc_comment,
			$actiontext );
	}

	/**
	 * Really format a diff for the newsfeed
	 *
	 * @param $title Title object
	 * @param $oldid Integer: old revision's id
	 * @param $newid Integer: new revision's id
	 * @param $timestamp Integer: new revision's timestamp
	 * @param $comment String: new revision's comment
	 * @param $actiontext String: text of the action; in case of log event
	 * @return String
	 */
	public static function formatDiffRow( $title, $oldid, $newid, $timestamp, $comment, $actiontext='' ) {
		global $wgFeedDiffCutoff, $wgLang, $wgUser;
		wfProfileIn( __METHOD__ );

		$skin = $wgUser->getSkin();
		# log enties
		$completeText = '<p>' . implode( ' ',
			array_filter(
				array(
					$actiontext,
					$skin->formatComment( $comment ) ) ) ) . "</p>\n";

		//NOTE: Check permissions for anonymous users, not current user.
		//      No "privileged" version should end up in the cache.
		//      Most feed readers will not log in anway.
		$anon = new User();
		$accErrors = $title->getUserPermissionsErrors( 'read', $anon, true );

		if( $title->getNamespace() >= 0 && !$accErrors && $newid ) {
			if( $oldid ) {
				wfProfileIn( __METHOD__."-dodiff" );

				#$diffText = $de->getDiff( wfMsg( 'revisionasof',
				#	$wgLang->timeanddate( $timestamp ),
				#	$wgLang->date( $timestamp ),
				#	$wgLang->time( $timestamp ) ),
				#	wfMsg( 'currentrev' ) );

				// Don't bother generating the diff if we won't be able to show it
				if ( $wgFeedDiffCutoff > 0 ) {
					$de = new DifferenceEngine( $title, $oldid, $newid );
					$diffText = $de->getDiff(
						wfMsg( 'previousrevision' ), // hack
						wfMsg( 'revisionasof',
							$wgLang->timeanddate( $timestamp ),
							$wgLang->date( $timestamp ),
							$wgLang->time( $timestamp ) ) );
				}

				if ( $wgFeedDiffCutoff <= 0 || ( strlen( $diffText ) > $wgFeedDiffCutoff ) ) {
					// Omit large diffs
					$diffLink = $title->escapeFullUrl(
						'diff=' . $newid .
						'&oldid=' . $oldid );
					$diffText = '<a href="' .
						$diffLink .
						'">' .
						htmlspecialchars( wfMsgForContent( 'showdiff' ) ) .
						'</a>';
				} elseif ( $diffText === false ) {
					// Error in diff engine, probably a missing revision
					$diffText = "<p>Can't load revision $newid</p>";
				} else {
					// Diff output fine, clean up any illegal UTF-8
					$diffText = UtfNormal::cleanUp( $diffText );
					$diffText = self::applyDiffStyle( $diffText );
				}
				wfProfileOut( __METHOD__."-dodiff" );
			} else {
				$rev = Revision::newFromId( $newid );
				if( is_null( $rev ) ) {
					$newtext = '';
				} else {
					$newtext = $rev->getText();
				}
				$diffText = '<p><b>' . wfMsg( 'newpage' ) . '</b></p>' .
					'<div>' . nl2br( htmlspecialchars( $newtext ) ) . '</div>';
			}
			$completeText .= $diffText;
		}

		wfProfileOut( __METHOD__ );
		return $completeText;
	}

	/**
	 * Hacky application of diff styles for the feeds.
	 * Might be 'cleaner' to use DOM or XSLT or something,
	 * but *gack* it's a pain in the ass.
	 *
	 * @param $text String: diff's HTML output
	 * @return String: modified HTML
	 * @private
	 */
	public static function applyDiffStyle( $text ) {
		$styles = array(
			'diff'             => 'background-color: white; color:black;',
			'diff-otitle'      => 'background-color: white; color:black;',
			'diff-ntitle'      => 'background-color: white; color:black;',
			'diff-addedline'   => 'background: #cfc; color:black; font-size: smaller;',
			'diff-deletedline' => 'background: #ffa; color:black; font-size: smaller;',
			'diff-context'     => 'background: #eee; color:black; font-size: smaller;',
			'diffchange'       => 'color: red; font-weight: bold; text-decoration: none;',
		);

		foreach( $styles as $class => $style ) {
			$text = preg_replace( "/(<[^>]+)class=(['\"])$class\\2([^>]*>)/",
				"\\1style=\"$style\"\\3", $text );
		}

		return $text;
	}

}