summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/Gadgets/SpecialGadgetUsage.php
blob: 8415ce166f3df557f49889b7c5821cb12e5d3717 (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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
<?php
/**
 * Implements Special:GadgetUsage
 *
 * Copyright © 2015 Niharika Kohli
 *
 * 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
 * @ingroup SpecialPage
 * @author Niharika Kohli <niharika@wikimedia.org>
 */

/**
 * Special:GadgetUsage - Lists all the gadgets on the wiki along with number of users.
 * @ingroup SpecialPage
 */
class SpecialGadgetUsage extends QueryPage {
	function __construct( $name = 'GadgetUsage' ) {
		parent::__construct( $name );
		$this->limit = 1000; // Show all gadgets
		$this->shownavigation = false;
		$this->activeUsers = $this->getConfig()->get( 'SpecialGadgetUsageActiveUsers' );
	}

	/**
	 * Flag for holding the value of config variable SpecialGadgetUsageActiveUsers
	 *
	 * @var bool $activeUsers
	 */
	public $activeUsers;

	public function isExpensive() {
		return true;
	}

	/**
	 * Define the database query that is used to generate the stats table.
	 * This uses 1 of 2 possible queries, depending on $wgSpecialGadgetUsageActiveUsers.
	 *
	 * The simple query is essentially:
	 * SELECT up_property, SUM(up_value)
	 * FROM user_properties
	 * WHERE up_property LIKE 'gadget-%'
	 * GROUP BY up_property;
	 *
	 * The more expensive query is:
	 * SELECT up_property, SUM(up_value), count(qcc_title)
	 * FROM user_properties
	 * LEFT JOIN user ON up_user = user_id
	 * LEFT JOIN querycachetwo ON user_name = qcc_title AND qcc_type = 'activeusers' AND up_value = 1
	 * WHERE up_property LIKE 'gadget-%'
	 * GROUP BY up_property;
	 * @return array
	 */
	public function getQueryInfo() {
		$dbr = wfGetDB( DB_SLAVE );
		if ( !$this->activeUsers ) {
			return [
				'tables' => [ 'user_properties' ],
				'fields' => [
					'title' => 'up_property',
					'value' => 'SUM( up_value )',
					'namespace' => NS_GADGET
				],
				'conds' => [
					'up_property' . $dbr->buildLike( 'gadget-', $dbr->anyString() )
				],
				'options' => [
					'GROUP BY' => [ 'up_property' ]
				]
			];
		} else {
			return [
				'tables' => [ 'user_properties', 'user', 'querycachetwo' ],
				'fields' => [
					'title' => 'up_property',
					'value' => 'SUM( up_value )',
					// Need to pick fields existing in the querycache table so that the results are cachable
					'namespace' => 'COUNT( qcc_title )'
				],
				'conds' => [
					'up_property' . $dbr->buildLike( 'gadget-', $dbr->anyString() )
				],
				'options' => [
					'GROUP BY' => [ 'up_property' ]
				],
				'join_conds' => [
					'user' => [
						'LEFT JOIN', [
							'up_user = user_id'
						]
					],
					'querycachetwo' => [
						'LEFT JOIN', [
							'user_name = qcc_title',
							'qcc_type = "activeusers"',
							'up_value = 1'
						]
					]
				]
			];
		}
	}

	public function getOrderFields() {
		return [ 'value' ];
	}

	/**
	 * Output the start of the table
	 * Including opening <table>, and first <tr> with column headers.
	 */
	protected function outputTableStart() {
		$html = Html::openElement( 'table', [ 'class' => [ 'sortable', 'wikitable' ] ] );
		$html .= Html::openElement( 'tr', [] );
		$headers = [ 'gadgetusage-gadget', 'gadgetusage-usercount' ];
		if ( $this->activeUsers ) {
			$headers[] = 'gadgetusage-activeusers';
		}
		foreach ( $headers as $h ) {
			if ( $h == 'gadgetusage-gadget' ) {
				$html .= Html::element( 'th', [], $this->msg( $h )->text() );
			} else {
				$html .= Html::element( 'th', [ 'data-sort-type' => 'number' ],
					$this->msg( $h )->text() );
			}
		}
		$html .= Html::closeElement( 'tr' );
		$this->getOutput()->addHTML( $html );
	}

	/**
	 * @param Skin $skin
	 * @param object $result Result row
	 * @return string|bool String of HTML
	 */
	public function formatResult( $skin, $result ) {
		$gadgetTitle = substr( $result->title, 7 );
		$gadgetUserCount = $this->getLanguage()->formatNum( $result->value );
		if ( $gadgetTitle ) {
			$html = Html::openElement( 'tr', [] );
			$html .= Html::element( 'td', [], $gadgetTitle );
			$html .= Html::element( 'td', [], $gadgetUserCount );
			if ( $this->activeUsers == true ) {
				$activeUserCount = $this->getLanguage()->formatNum( $result->namespace );
				$html .= Html::element( 'td', [], $activeUserCount );
			}
			$html .= Html::closeElement( 'tr' );
			return $html;
		}
		return false;
	}

	/**
	 * Get a list of default gadgets
	 * @param GadgetRepo $gadgetRepo
	 * @param array $gadgetIds list of gagdet ids registered in the wiki
	 * @return array
	*/
	protected function getDefaultGadgets( $gadgetRepo, $gadgetIds ) {
		$gadgetsList = [];
		foreach ( $gadgetIds as $g ) {
			$gadget = $gadgetRepo->getGadget( $g );
			if ( $gadget->isOnByDefault() ) {
				$gadgetsList[] = $gadget->getName();
			}
		}
		asort( $gadgetsList, SORT_STRING | SORT_FLAG_CASE );
		return $gadgetsList;
	}

	/**
	 * Format and output report results using the given information plus
	 * OutputPage
	 *
	 * @param OutputPage $out OutputPage to print to
	 * @param Skin $skin User skin to use
	 * @param IDatabase $dbr Database (read) connection to use
	 * @param ResultWrapper $res Result pointer
	 * @param int $num Number of available result rows
	 * @param int $offset Paging offset
	 */
	protected function outputResults( $out, $skin, $dbr, $res, $num, $offset ) {
		$gadgetRepo = GadgetRepo::singleton();
		$gadgetIds = $gadgetRepo->getGadgetIds();
		$defaultGadgets = $this->getDefaultGadgets( $gadgetRepo, $gadgetIds );
		if ( $this->activeUsers ) {
			$out->addHtml(
				$this->msg( 'gadgetusage-intro' )
					->numParams( $this->getConfig()->get( 'ActiveUserDays' ) )->parseAsBlock()
			);
		} else {
			$out->addHtml(
				$this->msg( 'gadgetusage-intro-noactive' )->parseAsBlock()
			);
		}
		if ( $num > 0 ) {
			$this->outputTableStart();
			// Append default gadgets to the table with 'default' in the total and active user fields
			foreach ( $defaultGadgets as $default ) {
				$html = Html::openElement( 'tr', [] );
				$html .= Html::element( 'td', [], $default );
				$html .= Html::element( 'td', [], $this->msg( 'gadgetusage-default' )->text() );
				if ( $this->activeUsers ) {
					$html .= Html::element( 'td', [], $this->msg( 'gadgetusage-default' )->text() );
				}
				$html .= Html::closeElement( 'tr' );
				$out->addHTML( $html );
			}
			foreach ( $res as $row ) {
				// Remove the 'gadget-' part of the result string and compare if it's present
				// in $defaultGadgets, if not we format it and add it to the output
				if ( !in_array( substr( $row->title, 7 ), $defaultGadgets ) ) {
					// Only pick gadgets which are in the list $gadgetIds to make sure they exist
					if ( in_array( substr( $row->title, 7 ), $gadgetIds ) ) {
						$line = $this->formatResult( $skin, $row );
						if ( $line ) {
							$out->addHTML( $line );
						}
					}
				}
			}
			// Close table element
			$out->addHtml( Html::closeElement( 'table' ) );
		} else {
			$out->addHtml(
				$this->msg( 'gadgetusage-noresults' )->parseAsBlock()
			);
		}
	}

	protected function getGroupName() {
		return 'wiki';
	}
}