Passed
Push — newinternal-releasecandidate ( 40acd0...67549a )
by Simon
10:15
created
includes/Security/RoleConfiguration.php 1 patch
Indentation   +360 added lines, -360 removed lines patch added patch discarded remove patch
@@ -47,391 +47,391 @@
 block discarded – undo
47 47
 
48 48
 class RoleConfiguration
49 49
 {
50
-    const ACCESS_ALLOW = 1;
51
-    const ACCESS_DENY = -1;
52
-    const ACCESS_DEFAULT = 0;
53
-    const MAIN = 'main';
54
-    const ALL = '*';
55
-    /**
56
-     * A map of roles to rights
57
-     *
58
-     * For example:
59
-     *
60
-     * array(
61
-     *   'myrole' => array(
62
-     *       PageMyPage::class => array(
63
-     *           'edit' => self::ACCESS_ALLOW,
64
-     *           'create' => self::ACCESS_DENY,
65
-     *       )
66
-     *   )
67
-     * )
68
-     *
69
-     * Note that DENY takes precedence over everything else when roles are combined, followed by ALLOW, followed by
70
-     * DEFAULT. Thus, if you have the following ([A]llow, [D]eny, [-] (default)) grants in different roles, this should
71
-     * be the expected result:
72
-     *
73
-     * - (-,-,-) = - (default because nothing to explicitly say allowed or denied equates to a denial)
74
-     * - (A,-,-) = A
75
-     * - (D,-,-) = D
76
-     * - (A,D,-) = D (deny takes precedence over allow)
77
-     * - (A,A,A) = A (repetition has no effect)
78
-     *
79
-     * The public role is special, and is applied to all users automatically. Avoid using deny on this role.
80
-     *
81
-     * @var array
82
-     */
83
-    private $roleConfig = array(
84
-        'public'            => array(
85
-            /*
50
+	const ACCESS_ALLOW = 1;
51
+	const ACCESS_DENY = -1;
52
+	const ACCESS_DEFAULT = 0;
53
+	const MAIN = 'main';
54
+	const ALL = '*';
55
+	/**
56
+	 * A map of roles to rights
57
+	 *
58
+	 * For example:
59
+	 *
60
+	 * array(
61
+	 *   'myrole' => array(
62
+	 *       PageMyPage::class => array(
63
+	 *           'edit' => self::ACCESS_ALLOW,
64
+	 *           'create' => self::ACCESS_DENY,
65
+	 *       )
66
+	 *   )
67
+	 * )
68
+	 *
69
+	 * Note that DENY takes precedence over everything else when roles are combined, followed by ALLOW, followed by
70
+	 * DEFAULT. Thus, if you have the following ([A]llow, [D]eny, [-] (default)) grants in different roles, this should
71
+	 * be the expected result:
72
+	 *
73
+	 * - (-,-,-) = - (default because nothing to explicitly say allowed or denied equates to a denial)
74
+	 * - (A,-,-) = A
75
+	 * - (D,-,-) = D
76
+	 * - (A,D,-) = D (deny takes precedence over allow)
77
+	 * - (A,A,A) = A (repetition has no effect)
78
+	 *
79
+	 * The public role is special, and is applied to all users automatically. Avoid using deny on this role.
80
+	 *
81
+	 * @var array
82
+	 */
83
+	private $roleConfig = array(
84
+		'public'            => array(
85
+			/*
86 86
              * THIS ROLE IS GRANTED TO ALL LOGGED *OUT* USERS IMPLICITLY.
87 87
              *
88 88
              * USERS IN THIS ROLE DO NOT HAVE TO BE IDENTIFIED TO GET THE RIGHTS CONFERRED HERE.
89 89
              * DO NOT ADD ANY SECURITY-SENSITIVE RIGHTS HERE.
90 90
              */
91
-            '_childRoles'   => array(
92
-                'publicStats',
93
-            ),
94
-            PageTeam::class => array(
95
-                self::MAIN => self::ACCESS_ALLOW,
96
-            ),
97
-            PageXffDemo::class        => array(
98
-                self::MAIN  => self::ACCESS_ALLOW,
99
-            )
100
-        ),
101
-        'loggedIn'          => array(
102
-            /*
91
+			'_childRoles'   => array(
92
+				'publicStats',
93
+			),
94
+			PageTeam::class => array(
95
+				self::MAIN => self::ACCESS_ALLOW,
96
+			),
97
+			PageXffDemo::class        => array(
98
+				self::MAIN  => self::ACCESS_ALLOW,
99
+			)
100
+		),
101
+		'loggedIn'          => array(
102
+			/*
103 103
              * THIS ROLE IS GRANTED TO ALL LOGGED IN USERS IMPLICITLY.
104 104
              *
105 105
              * USERS IN THIS ROLE DO NOT HAVE TO BE IDENTIFIED TO GET THE RIGHTS CONFERRED HERE.
106 106
              * DO NOT ADD ANY SECURITY-SENSITIVE RIGHTS HERE.
107 107
              */
108
-            '_childRoles'             => array(
109
-                'public',
110
-            ),
111
-            PagePreferences::class    => array(
112
-                self::MAIN => self::ACCESS_ALLOW,
113
-                'refreshOAuth' => self::ACCESS_ALLOW,
114
-            ),
115
-            PageChangePassword::class => array(
116
-                self::MAIN => self::ACCESS_ALLOW,
117
-            ),
118
-            PageMultiFactor::class    => array(
119
-                self::MAIN          => self::ACCESS_ALLOW,
120
-                'scratch'           => self::ACCESS_ALLOW,
121
-                'enableYubikeyOtp'  => self::ACCESS_ALLOW,
122
-                'disableYubikeyOtp' => self::ACCESS_ALLOW,
123
-                'enableTotp'        => self::ACCESS_ALLOW,
124
-                'disableTotp'       => self::ACCESS_ALLOW,
125
-            ),
126
-            PageOAuth::class          => array(
127
-                'attach' => self::ACCESS_ALLOW,
128
-                'detach' => self::ACCESS_ALLOW,
129
-            ),
130
-        ),
131
-        'user'              => array(
132
-            '_description'                       => 'A standard tool user.',
133
-            '_editableBy'                        => array('admin', 'toolRoot'),
134
-            '_childRoles'                        => array(
135
-                'internalStats',
136
-            ),
137
-            PageMain::class                      => array(
138
-                self::MAIN => self::ACCESS_ALLOW,
139
-            ),
140
-            PageBan::class                       => array(
141
-                self::MAIN => self::ACCESS_ALLOW,
142
-            ),
143
-            PageEditComment::class               => array(
144
-                self::MAIN => self::ACCESS_ALLOW,
145
-            ),
146
-            PageEmailManagement::class           => array(
147
-                self::MAIN => self::ACCESS_ALLOW,
148
-                'view'     => self::ACCESS_ALLOW,
149
-            ),
150
-            PageExpandedRequestList::class       => array(
151
-                self::MAIN => self::ACCESS_ALLOW,
152
-            ),
153
-            PageLog::class                       => array(
154
-                self::MAIN => self::ACCESS_ALLOW,
155
-            ),
156
-            PageSearch::class                    => array(
157
-                self::MAIN => self::ACCESS_ALLOW,
158
-            ),
159
-            PageWelcomeTemplateManagement::class => array(
160
-                self::MAIN => self::ACCESS_ALLOW,
161
-                'select'   => self::ACCESS_ALLOW,
162
-                'view'     => self::ACCESS_ALLOW,
163
-            ),
164
-            PageViewRequest::class               => array(
165
-                self::MAIN       => self::ACCESS_ALLOW,
166
-                'seeAllRequests' => self::ACCESS_ALLOW,
167
-            ),
168
-            'RequestData'                        => array(
169
-                'seePrivateDataWhenReserved' => self::ACCESS_ALLOW,
170
-                'seePrivateDataWithHash'     => self::ACCESS_ALLOW,
171
-            ),
172
-            PageCustomClose::class               => array(
173
-                self::MAIN => self::ACCESS_ALLOW,
174
-            ),
175
-            PageComment::class                   => array(
176
-                self::MAIN => self::ACCESS_ALLOW,
177
-            ),
178
-            PageCloseRequest::class              => array(
179
-                self::MAIN => self::ACCESS_ALLOW,
180
-            ),
181
-            PageCreateRequest::class             => array(
182
-                self::MAIN => self::ACCESS_ALLOW,
183
-            ),
184
-            PageDeferRequest::class              => array(
185
-                self::MAIN => self::ACCESS_ALLOW,
186
-            ),
187
-            PageDropRequest::class               => array(
188
-                self::MAIN => self::ACCESS_ALLOW,
189
-            ),
190
-            PageReservation::class               => array(
191
-                self::MAIN => self::ACCESS_ALLOW,
192
-            ),
193
-            PageSendToUser::class                => array(
194
-                self::MAIN => self::ACCESS_ALLOW,
195
-            ),
196
-            PageBreakReservation::class          => array(
197
-                self::MAIN => self::ACCESS_ALLOW,
198
-            ),
199
-            PageJobQueue::class                  => array(
200
-                self::MAIN => self::ACCESS_ALLOW,
201
-                'view'     => self::ACCESS_ALLOW,
202
-                'all'      => self::ACCESS_ALLOW,
203
-            ),
204
-            'RequestCreation'                    => array(
205
-                User::CREATION_MANUAL => self::ACCESS_ALLOW,
206
-            ),
207
-            'GlobalInfo'                         => array(
208
-                'viewSiteNotice' => self::ACCESS_ALLOW,
209
-                'viewOnlineUsers' => self::ACCESS_ALLOW,
210
-            ),
211
-        ),
212
-        'admin'             => array(
213
-            '_description'                       => 'A tool administrator.',
214
-            '_editableBy'                        => array('admin', 'toolRoot'),
215
-            '_childRoles'                        => array(
216
-                'user',
217
-                'requestAdminTools',
218
-            ),
219
-            PageEmailManagement::class           => array(
220
-                'edit'   => self::ACCESS_ALLOW,
221
-                'create' => self::ACCESS_ALLOW,
222
-            ),
223
-            PageSiteNotice::class                => array(
224
-                self::MAIN => self::ACCESS_ALLOW,
225
-            ),
226
-            PageUserManagement::class            => array(
227
-                self::MAIN  => self::ACCESS_ALLOW,
228
-                'approve'   => self::ACCESS_ALLOW,
229
-                'decline'   => self::ACCESS_ALLOW,
230
-                'rename'    => self::ACCESS_ALLOW,
231
-                'editUser'  => self::ACCESS_ALLOW,
232
-                'suspend'   => self::ACCESS_ALLOW,
233
-                'editRoles' => self::ACCESS_ALLOW,
234
-            ),
235
-            PageWelcomeTemplateManagement::class => array(
236
-                'edit'   => self::ACCESS_ALLOW,
237
-                'delete' => self::ACCESS_ALLOW,
238
-                'add'    => self::ACCESS_ALLOW,
239
-            ),
240
-            PageJobQueue::class                  => array(
241
-                'acknowledge' => self::ACCESS_ALLOW,
242
-                'requeue'     => self::ACCESS_ALLOW,
243
-            ),
244
-        ),
245
-        'checkuser'         => array(
246
-            '_description'            => 'A user with CheckUser access',
247
-            '_editableBy'             => array('checkuser', 'toolRoot'),
248
-            '_childRoles'             => array(
249
-                'user',
250
-                'requestAdminTools',
251
-            ),
252
-            PageUserManagement::class => array(
253
-                self::MAIN  => self::ACCESS_ALLOW,
254
-                'suspend'   => self::ACCESS_ALLOW,
255
-                'editRoles' => self::ACCESS_ALLOW,
256
-            ),
257
-            'RequestData'             => array(
258
-                'seeUserAgentData' => self::ACCESS_ALLOW,
259
-            ),
260
-        ),
261
-        'toolRoot'          => array(
262
-            '_description' => 'A user with shell access to the servers running the tool',
263
-            '_editableBy'  => array('toolRoot'),
264
-            '_childRoles'  => array(
265
-                'admin',
266
-            ),
267
-            PageMultiFactor::class => array(
268
-                'enableU2F'         => self::ACCESS_ALLOW,
269
-                'disableU2F'        => self::ACCESS_ALLOW,
270
-            )
271
-        ),
272
-        'botCreation'       => array(
273
-            '_description'    => 'A user allowed to use the bot to perform account creations',
274
-            '_editableBy'     => array('admin', 'toolRoot'),
275
-            '_childRoles'     => array(),
276
-            'RequestCreation' => array(
277
-                User::CREATION_BOT => self::ACCESS_ALLOW,
278
-            ),
279
-        ),
280
-        'oauthCreation'       => array(
281
-            '_description'    => 'A user allowed to use the OAuth to perform account creations',
282
-            '_editableBy'     => array('admin', 'toolRoot'),
283
-            '_childRoles'     => array(),
284
-            'RequestCreation'                    => array(
285
-                User::CREATION_OAUTH  => self::ACCESS_ALLOW,
286
-            ),
287
-        ),
108
+			'_childRoles'             => array(
109
+				'public',
110
+			),
111
+			PagePreferences::class    => array(
112
+				self::MAIN => self::ACCESS_ALLOW,
113
+				'refreshOAuth' => self::ACCESS_ALLOW,
114
+			),
115
+			PageChangePassword::class => array(
116
+				self::MAIN => self::ACCESS_ALLOW,
117
+			),
118
+			PageMultiFactor::class    => array(
119
+				self::MAIN          => self::ACCESS_ALLOW,
120
+				'scratch'           => self::ACCESS_ALLOW,
121
+				'enableYubikeyOtp'  => self::ACCESS_ALLOW,
122
+				'disableYubikeyOtp' => self::ACCESS_ALLOW,
123
+				'enableTotp'        => self::ACCESS_ALLOW,
124
+				'disableTotp'       => self::ACCESS_ALLOW,
125
+			),
126
+			PageOAuth::class          => array(
127
+				'attach' => self::ACCESS_ALLOW,
128
+				'detach' => self::ACCESS_ALLOW,
129
+			),
130
+		),
131
+		'user'              => array(
132
+			'_description'                       => 'A standard tool user.',
133
+			'_editableBy'                        => array('admin', 'toolRoot'),
134
+			'_childRoles'                        => array(
135
+				'internalStats',
136
+			),
137
+			PageMain::class                      => array(
138
+				self::MAIN => self::ACCESS_ALLOW,
139
+			),
140
+			PageBan::class                       => array(
141
+				self::MAIN => self::ACCESS_ALLOW,
142
+			),
143
+			PageEditComment::class               => array(
144
+				self::MAIN => self::ACCESS_ALLOW,
145
+			),
146
+			PageEmailManagement::class           => array(
147
+				self::MAIN => self::ACCESS_ALLOW,
148
+				'view'     => self::ACCESS_ALLOW,
149
+			),
150
+			PageExpandedRequestList::class       => array(
151
+				self::MAIN => self::ACCESS_ALLOW,
152
+			),
153
+			PageLog::class                       => array(
154
+				self::MAIN => self::ACCESS_ALLOW,
155
+			),
156
+			PageSearch::class                    => array(
157
+				self::MAIN => self::ACCESS_ALLOW,
158
+			),
159
+			PageWelcomeTemplateManagement::class => array(
160
+				self::MAIN => self::ACCESS_ALLOW,
161
+				'select'   => self::ACCESS_ALLOW,
162
+				'view'     => self::ACCESS_ALLOW,
163
+			),
164
+			PageViewRequest::class               => array(
165
+				self::MAIN       => self::ACCESS_ALLOW,
166
+				'seeAllRequests' => self::ACCESS_ALLOW,
167
+			),
168
+			'RequestData'                        => array(
169
+				'seePrivateDataWhenReserved' => self::ACCESS_ALLOW,
170
+				'seePrivateDataWithHash'     => self::ACCESS_ALLOW,
171
+			),
172
+			PageCustomClose::class               => array(
173
+				self::MAIN => self::ACCESS_ALLOW,
174
+			),
175
+			PageComment::class                   => array(
176
+				self::MAIN => self::ACCESS_ALLOW,
177
+			),
178
+			PageCloseRequest::class              => array(
179
+				self::MAIN => self::ACCESS_ALLOW,
180
+			),
181
+			PageCreateRequest::class             => array(
182
+				self::MAIN => self::ACCESS_ALLOW,
183
+			),
184
+			PageDeferRequest::class              => array(
185
+				self::MAIN => self::ACCESS_ALLOW,
186
+			),
187
+			PageDropRequest::class               => array(
188
+				self::MAIN => self::ACCESS_ALLOW,
189
+			),
190
+			PageReservation::class               => array(
191
+				self::MAIN => self::ACCESS_ALLOW,
192
+			),
193
+			PageSendToUser::class                => array(
194
+				self::MAIN => self::ACCESS_ALLOW,
195
+			),
196
+			PageBreakReservation::class          => array(
197
+				self::MAIN => self::ACCESS_ALLOW,
198
+			),
199
+			PageJobQueue::class                  => array(
200
+				self::MAIN => self::ACCESS_ALLOW,
201
+				'view'     => self::ACCESS_ALLOW,
202
+				'all'      => self::ACCESS_ALLOW,
203
+			),
204
+			'RequestCreation'                    => array(
205
+				User::CREATION_MANUAL => self::ACCESS_ALLOW,
206
+			),
207
+			'GlobalInfo'                         => array(
208
+				'viewSiteNotice' => self::ACCESS_ALLOW,
209
+				'viewOnlineUsers' => self::ACCESS_ALLOW,
210
+			),
211
+		),
212
+		'admin'             => array(
213
+			'_description'                       => 'A tool administrator.',
214
+			'_editableBy'                        => array('admin', 'toolRoot'),
215
+			'_childRoles'                        => array(
216
+				'user',
217
+				'requestAdminTools',
218
+			),
219
+			PageEmailManagement::class           => array(
220
+				'edit'   => self::ACCESS_ALLOW,
221
+				'create' => self::ACCESS_ALLOW,
222
+			),
223
+			PageSiteNotice::class                => array(
224
+				self::MAIN => self::ACCESS_ALLOW,
225
+			),
226
+			PageUserManagement::class            => array(
227
+				self::MAIN  => self::ACCESS_ALLOW,
228
+				'approve'   => self::ACCESS_ALLOW,
229
+				'decline'   => self::ACCESS_ALLOW,
230
+				'rename'    => self::ACCESS_ALLOW,
231
+				'editUser'  => self::ACCESS_ALLOW,
232
+				'suspend'   => self::ACCESS_ALLOW,
233
+				'editRoles' => self::ACCESS_ALLOW,
234
+			),
235
+			PageWelcomeTemplateManagement::class => array(
236
+				'edit'   => self::ACCESS_ALLOW,
237
+				'delete' => self::ACCESS_ALLOW,
238
+				'add'    => self::ACCESS_ALLOW,
239
+			),
240
+			PageJobQueue::class                  => array(
241
+				'acknowledge' => self::ACCESS_ALLOW,
242
+				'requeue'     => self::ACCESS_ALLOW,
243
+			),
244
+		),
245
+		'checkuser'         => array(
246
+			'_description'            => 'A user with CheckUser access',
247
+			'_editableBy'             => array('checkuser', 'toolRoot'),
248
+			'_childRoles'             => array(
249
+				'user',
250
+				'requestAdminTools',
251
+			),
252
+			PageUserManagement::class => array(
253
+				self::MAIN  => self::ACCESS_ALLOW,
254
+				'suspend'   => self::ACCESS_ALLOW,
255
+				'editRoles' => self::ACCESS_ALLOW,
256
+			),
257
+			'RequestData'             => array(
258
+				'seeUserAgentData' => self::ACCESS_ALLOW,
259
+			),
260
+		),
261
+		'toolRoot'          => array(
262
+			'_description' => 'A user with shell access to the servers running the tool',
263
+			'_editableBy'  => array('toolRoot'),
264
+			'_childRoles'  => array(
265
+				'admin',
266
+			),
267
+			PageMultiFactor::class => array(
268
+				'enableU2F'         => self::ACCESS_ALLOW,
269
+				'disableU2F'        => self::ACCESS_ALLOW,
270
+			)
271
+		),
272
+		'botCreation'       => array(
273
+			'_description'    => 'A user allowed to use the bot to perform account creations',
274
+			'_editableBy'     => array('admin', 'toolRoot'),
275
+			'_childRoles'     => array(),
276
+			'RequestCreation' => array(
277
+				User::CREATION_BOT => self::ACCESS_ALLOW,
278
+			),
279
+		),
280
+		'oauthCreation'       => array(
281
+			'_description'    => 'A user allowed to use the OAuth to perform account creations',
282
+			'_editableBy'     => array('admin', 'toolRoot'),
283
+			'_childRoles'     => array(),
284
+			'RequestCreation'                    => array(
285
+				User::CREATION_OAUTH  => self::ACCESS_ALLOW,
286
+			),
287
+		),
288 288
 
289 289
 
290
-        // Child roles go below this point
291
-        'publicStats'       => array(
292
-            '_hidden'               => true,
293
-            StatsUsers::class       => array(
294
-                self::MAIN => self::ACCESS_ALLOW,
295
-                'detail'   => self::ACCESS_ALLOW,
296
-            ),
297
-            StatsTopCreators::class => array(
298
-                self::MAIN => self::ACCESS_ALLOW,
299
-            ),
300
-        ),
301
-        'internalStats'     => array(
302
-            '_hidden'                    => true,
303
-            StatsMain::class             => array(
304
-                self::MAIN => self::ACCESS_ALLOW,
305
-            ),
306
-            StatsFastCloses::class       => array(
307
-                self::MAIN => self::ACCESS_ALLOW,
308
-            ),
309
-            StatsInactiveUsers::class    => array(
310
-                self::MAIN => self::ACCESS_ALLOW,
311
-            ),
312
-            StatsMonthlyStats::class     => array(
313
-                self::MAIN => self::ACCESS_ALLOW,
314
-            ),
315
-            StatsReservedRequests::class => array(
316
-                self::MAIN => self::ACCESS_ALLOW,
317
-            ),
318
-            StatsTemplateStats::class    => array(
319
-                self::MAIN => self::ACCESS_ALLOW,
320
-            ),
321
-        ),
322
-        'requestAdminTools' => array(
323
-            '_hidden'                   => true,
324
-            PageBan::class              => array(
325
-                self::MAIN => self::ACCESS_ALLOW,
326
-                'set'      => self::ACCESS_ALLOW,
327
-                'remove'   => self::ACCESS_ALLOW,
328
-            ),
329
-            PageEditComment::class      => array(
330
-                'editOthers' => self::ACCESS_ALLOW,
331
-            ),
332
-            PageBreakReservation::class => array(
333
-                'force' => self::ACCESS_ALLOW,
334
-            ),
335
-            PageCustomClose::class      => array(
336
-                'skipCcMailingList' => self::ACCESS_ALLOW,
337
-            ),
338
-            'RequestData'               => array(
339
-                'reopenOldRequest'      => self::ACCESS_ALLOW,
340
-                'alwaysSeePrivateData'  => self::ACCESS_ALLOW,
341
-                'alwaysSeeHash'         => self::ACCESS_ALLOW,
342
-                'seeRestrictedComments' => self::ACCESS_ALLOW,
343
-            ),
344
-        ),
345
-    );
346
-    /** @var array
347
-     * List of roles which are *exempt* from the identification requirements
348
-     *
349
-     * Think twice about adding roles to this list.
350
-     *
351
-     * @category Security-Critical
352
-     */
353
-    private $identificationExempt = array('public', 'loggedIn');
290
+		// Child roles go below this point
291
+		'publicStats'       => array(
292
+			'_hidden'               => true,
293
+			StatsUsers::class       => array(
294
+				self::MAIN => self::ACCESS_ALLOW,
295
+				'detail'   => self::ACCESS_ALLOW,
296
+			),
297
+			StatsTopCreators::class => array(
298
+				self::MAIN => self::ACCESS_ALLOW,
299
+			),
300
+		),
301
+		'internalStats'     => array(
302
+			'_hidden'                    => true,
303
+			StatsMain::class             => array(
304
+				self::MAIN => self::ACCESS_ALLOW,
305
+			),
306
+			StatsFastCloses::class       => array(
307
+				self::MAIN => self::ACCESS_ALLOW,
308
+			),
309
+			StatsInactiveUsers::class    => array(
310
+				self::MAIN => self::ACCESS_ALLOW,
311
+			),
312
+			StatsMonthlyStats::class     => array(
313
+				self::MAIN => self::ACCESS_ALLOW,
314
+			),
315
+			StatsReservedRequests::class => array(
316
+				self::MAIN => self::ACCESS_ALLOW,
317
+			),
318
+			StatsTemplateStats::class    => array(
319
+				self::MAIN => self::ACCESS_ALLOW,
320
+			),
321
+		),
322
+		'requestAdminTools' => array(
323
+			'_hidden'                   => true,
324
+			PageBan::class              => array(
325
+				self::MAIN => self::ACCESS_ALLOW,
326
+				'set'      => self::ACCESS_ALLOW,
327
+				'remove'   => self::ACCESS_ALLOW,
328
+			),
329
+			PageEditComment::class      => array(
330
+				'editOthers' => self::ACCESS_ALLOW,
331
+			),
332
+			PageBreakReservation::class => array(
333
+				'force' => self::ACCESS_ALLOW,
334
+			),
335
+			PageCustomClose::class      => array(
336
+				'skipCcMailingList' => self::ACCESS_ALLOW,
337
+			),
338
+			'RequestData'               => array(
339
+				'reopenOldRequest'      => self::ACCESS_ALLOW,
340
+				'alwaysSeePrivateData'  => self::ACCESS_ALLOW,
341
+				'alwaysSeeHash'         => self::ACCESS_ALLOW,
342
+				'seeRestrictedComments' => self::ACCESS_ALLOW,
343
+			),
344
+		),
345
+	);
346
+	/** @var array
347
+	 * List of roles which are *exempt* from the identification requirements
348
+	 *
349
+	 * Think twice about adding roles to this list.
350
+	 *
351
+	 * @category Security-Critical
352
+	 */
353
+	private $identificationExempt = array('public', 'loggedIn');
354 354
 
355
-    /**
356
-     * RoleConfiguration constructor.
357
-     *
358
-     * @param array $roleConfig           Set to non-null to override the default configuration.
359
-     * @param array $identificationExempt Set to non-null to override the default configuration.
360
-     */
361
-    public function __construct(array $roleConfig = null, array $identificationExempt = null)
362
-    {
363
-        if ($roleConfig !== null) {
364
-            $this->roleConfig = $roleConfig;
365
-        }
355
+	/**
356
+	 * RoleConfiguration constructor.
357
+	 *
358
+	 * @param array $roleConfig           Set to non-null to override the default configuration.
359
+	 * @param array $identificationExempt Set to non-null to override the default configuration.
360
+	 */
361
+	public function __construct(array $roleConfig = null, array $identificationExempt = null)
362
+	{
363
+		if ($roleConfig !== null) {
364
+			$this->roleConfig = $roleConfig;
365
+		}
366 366
 
367
-        if ($identificationExempt !== null) {
368
-            $this->identificationExempt = $identificationExempt;
369
-        }
370
-    }
367
+		if ($identificationExempt !== null) {
368
+			$this->identificationExempt = $identificationExempt;
369
+		}
370
+	}
371 371
 
372
-    /**
373
-     * @param array $roles The roles to check
374
-     *
375
-     * @return array
376
-     */
377
-    public function getApplicableRoles(array $roles)
378
-    {
379
-        $available = array();
372
+	/**
373
+	 * @param array $roles The roles to check
374
+	 *
375
+	 * @return array
376
+	 */
377
+	public function getApplicableRoles(array $roles)
378
+	{
379
+		$available = array();
380 380
 
381
-        foreach ($roles as $role) {
382
-            if (!isset($this->roleConfig[$role])) {
383
-                // wat
384
-                continue;
385
-            }
381
+		foreach ($roles as $role) {
382
+			if (!isset($this->roleConfig[$role])) {
383
+				// wat
384
+				continue;
385
+			}
386 386
 
387
-            $available[$role] = $this->roleConfig[$role];
387
+			$available[$role] = $this->roleConfig[$role];
388 388
 
389
-            if (isset($available[$role]['_childRoles'])) {
390
-                $childRoles = $this->getApplicableRoles($available[$role]['_childRoles']);
391
-                $available = array_merge($available, $childRoles);
389
+			if (isset($available[$role]['_childRoles'])) {
390
+				$childRoles = $this->getApplicableRoles($available[$role]['_childRoles']);
391
+				$available = array_merge($available, $childRoles);
392 392
 
393
-                unset($available[$role]['_childRoles']);
394
-            }
393
+				unset($available[$role]['_childRoles']);
394
+			}
395 395
 
396
-            foreach (array('_hidden', '_editableBy', '_description') as $item) {
397
-                if (isset($available[$role][$item])) {
398
-                    unset($available[$role][$item]);
399
-                }
400
-            }
401
-        }
396
+			foreach (array('_hidden', '_editableBy', '_description') as $item) {
397
+				if (isset($available[$role][$item])) {
398
+					unset($available[$role][$item]);
399
+				}
400
+			}
401
+		}
402 402
 
403
-        return $available;
404
-    }
403
+		return $available;
404
+	}
405 405
 
406
-    public function getAvailableRoles()
407
-    {
408
-        $possible = array_diff(array_keys($this->roleConfig), array('public', 'loggedIn'));
406
+	public function getAvailableRoles()
407
+	{
408
+		$possible = array_diff(array_keys($this->roleConfig), array('public', 'loggedIn'));
409 409
 
410
-        $actual = array();
410
+		$actual = array();
411 411
 
412
-        foreach ($possible as $role) {
413
-            if (!isset($this->roleConfig[$role]['_hidden'])) {
414
-                $actual[$role] = array(
415
-                    'description' => $this->roleConfig[$role]['_description'],
416
-                    'editableBy'  => $this->roleConfig[$role]['_editableBy'],
417
-                );
418
-            }
419
-        }
412
+		foreach ($possible as $role) {
413
+			if (!isset($this->roleConfig[$role]['_hidden'])) {
414
+				$actual[$role] = array(
415
+					'description' => $this->roleConfig[$role]['_description'],
416
+					'editableBy'  => $this->roleConfig[$role]['_editableBy'],
417
+				);
418
+			}
419
+		}
420 420
 
421
-        return $actual;
422
-    }
421
+		return $actual;
422
+	}
423 423
 
424
-    /**
425
-     * @param string $role
426
-     *
427
-     * @return bool
428
-     */
429
-    public function roleNeedsIdentification($role)
430
-    {
431
-        if (in_array($role, $this->identificationExempt)) {
432
-            return false;
433
-        }
424
+	/**
425
+	 * @param string $role
426
+	 *
427
+	 * @return bool
428
+	 */
429
+	public function roleNeedsIdentification($role)
430
+	{
431
+		if (in_array($role, $this->identificationExempt)) {
432
+			return false;
433
+		}
434 434
 
435
-        return true;
436
-    }
435
+		return true;
436
+	}
437 437
 }
Please login to merge, or discard this patch.
includes/Offline.php 1 patch
Indentation   +37 added lines, -37 removed lines patch added patch discarded remove patch
@@ -17,16 +17,16 @@  discard block
 block discarded – undo
17 17
  */
18 18
 class Offline
19 19
 {
20
-    /**
21
-     * Determines if the tool is offline
22
-     * @return bool
23
-     */
24
-    public static function isOffline()
25
-    {
26
-        global $dontUseDb;
20
+	/**
21
+	 * Determines if the tool is offline
22
+	 * @return bool
23
+	 */
24
+	public static function isOffline()
25
+	{
26
+		global $dontUseDb;
27 27
 
28
-        return (bool)$dontUseDb;
29
-    }
28
+		return (bool)$dontUseDb;
29
+	}
30 30
 
31 31
 	/**
32 32
 	 * Gets the offline message
@@ -37,38 +37,38 @@  discard block
 block discarded – undo
37 37
 	 * @return string
38 38
 	 * @throws SmartyException
39 39
 	 */
40
-    public static function getOfflineMessage($external, $message = null)
41
-    {
42
-        global $dontUseDbCulprit, $dontUseDbReason, $baseurl;
40
+	public static function getOfflineMessage($external, $message = null)
41
+	{
42
+		global $dontUseDbCulprit, $dontUseDbReason, $baseurl;
43 43
 
44
-        $smarty = new Smarty();
45
-        $smarty->assign("baseurl", $baseurl);
46
-        $smarty->assign("alerts", []);
47
-        $smarty->assign("toolversion", Environment::getToolVersion());
44
+		$smarty = new Smarty();
45
+		$smarty->assign("baseurl", $baseurl);
46
+		$smarty->assign("alerts", []);
47
+		$smarty->assign("toolversion", Environment::getToolVersion());
48 48
 
49
-        if (!headers_sent()) {
50
-            header("HTTP/1.1 503 Service Unavailable");
51
-        }
49
+		if (!headers_sent()) {
50
+			header("HTTP/1.1 503 Service Unavailable");
51
+		}
52 52
 
53
-        if ($external) {
54
-            return $smarty->fetch("offline/external.tpl");
55
-        }
56
-        else {
57
-            $hideCulprit = true;
53
+		if ($external) {
54
+			return $smarty->fetch("offline/external.tpl");
55
+		}
56
+		else {
57
+			$hideCulprit = true;
58 58
 
59
-            // Use the provided message if possible
60
-            if ($message === null) {
61
-                $hideCulprit = false;
62
-                $message = $dontUseDbReason;
63
-            }
59
+			// Use the provided message if possible
60
+			if ($message === null) {
61
+				$hideCulprit = false;
62
+				$message = $dontUseDbReason;
63
+			}
64 64
 
65
-            $smarty->assign("hideCulprit", $hideCulprit);
66
-            $smarty->assign("dontUseDbCulprit", $dontUseDbCulprit);
67
-            $smarty->assign("dontUseDbReason", $message);
68
-            $smarty->assign("alerts", array());
69
-            $smarty->assign('currentUser', User::getCommunity());
65
+			$smarty->assign("hideCulprit", $hideCulprit);
66
+			$smarty->assign("dontUseDbCulprit", $dontUseDbCulprit);
67
+			$smarty->assign("dontUseDbReason", $message);
68
+			$smarty->assign("alerts", array());
69
+			$smarty->assign('currentUser', User::getCommunity());
70 70
 
71
-            return $smarty->fetch("offline/internal.tpl");
72
-        }
73
-    }
71
+			return $smarty->fetch("offline/internal.tpl");
72
+		}
73
+	}
74 74
 }
Please login to merge, or discard this patch.
includes/Router/RequestRouter.php 1 patch
Indentation   +441 added lines, -441 removed lines patch added patch discarded remove patch
@@ -63,445 +63,445 @@
 block discarded – undo
63 63
  */
64 64
 class RequestRouter implements IRequestRouter
65 65
 {
66
-    /**
67
-     * This is the core routing table for the application. The basic idea is:
68
-     *
69
-     *      array(
70
-     *          "foo" =>
71
-     *              array(
72
-     *                  "class"   => PageFoo::class,
73
-     *                  "actions" => array("bar", "other")
74
-     *              ),
75
-     * );
76
-     *
77
-     * Things to note:
78
-     *     - If no page is requested, we go to PageMain. PageMain can't have actions defined.
79
-     *
80
-     *     - If a page is defined and requested, but no action is requested, go to that page's main() method
81
-     *     - If a page is defined and requested, and an action is defined and requested, go to that action's method.
82
-     *     - If a page is defined and requested, and an action NOT defined and requested, go to Page404 and it's main()
83
-     *       method.
84
-     *     - If a page is NOT defined and requested, go to Page404 and it's main() method.
85
-     *
86
-     *     - Query parameters are ignored.
87
-     *
88
-     * The key point here is request routing with validation that this is allowed, before we start hitting the
89
-     * filesystem through the AutoLoader, and opening random files. Also, so that we validate the action requested
90
-     * before we start calling random methods through the web UI.
91
-     *
92
-     * Examples:
93
-     * /internal.php                => returns instance of PageMain, routed to main()
94
-     * /internal.php?query          => returns instance of PageMain, routed to main()
95
-     * /internal.php/foo            => returns instance of PageFoo, routed to main()
96
-     * /internal.php/foo?query      => returns instance of PageFoo, routed to main()
97
-     * /internal.php/foo/bar        => returns instance of PageFoo, routed to bar()
98
-     * /internal.php/foo/bar?query  => returns instance of PageFoo, routed to bar()
99
-     * /internal.php/foo/baz        => returns instance of Page404, routed to main()
100
-     * /internal.php/foo/baz?query  => returns instance of Page404, routed to main()
101
-     * /internal.php/bar            => returns instance of Page404, routed to main()
102
-     * /internal.php/bar?query      => returns instance of Page404, routed to main()
103
-     * /internal.php/bar/baz        => returns instance of Page404, routed to main()
104
-     * /internal.php/bar/baz?query  => returns instance of Page404, routed to main()
105
-     *
106
-     * Take care when changing this - a lot of places rely on the array key for redirects and other links. If you need
107
-     * to change the key, then you'll likely have to update a lot of files.
108
-     *
109
-     * @var array
110
-     */
111
-    private $routeMap = array(
112
-
113
-        //////////////////////////////////////////////////////////////////////////////////////////////////
114
-        // Login and registration
115
-        'logout'                      =>
116
-            array(
117
-                'class'   => PageLogout::class,
118
-                'actions' => array(),
119
-            ),
120
-        'login'                       =>
121
-            array(
122
-                'class'   => PagePasswordLogin::class,
123
-                'actions' => array(),
124
-            ),
125
-        'login/otp'                   =>
126
-            array(
127
-                'class'   => PageOtpLogin::class,
128
-                'actions' => array(),
129
-            ),
130
-        'login/u2f'                   =>
131
-            array(
132
-                'class'   => PageU2FLogin::class,
133
-                'actions' => array(),
134
-            ),
135
-        'forgotPassword'              =>
136
-            array(
137
-                'class'   => PageForgotPassword::class,
138
-                'actions' => array('reset'),
139
-            ),
140
-        'register'                    =>
141
-            array(
142
-                'class'   => PageRegisterOption::class,
143
-                'actions' => array(),
144
-            ),
145
-        'register/standard'           =>
146
-            array(
147
-                'class'   => PageRegisterStandard::class,
148
-                'actions' => array('done'),
149
-            ),
150
-
151
-        //////////////////////////////////////////////////////////////////////////////////////////////////
152
-        // Discovery
153
-        'search'                      =>
154
-            array(
155
-                'class'   => PageSearch::class,
156
-                'actions' => array(),
157
-            ),
158
-        'logs'                        =>
159
-            array(
160
-                'class'   => PageLog::class,
161
-                'actions' => array(),
162
-            ),
163
-
164
-        //////////////////////////////////////////////////////////////////////////////////////////////////
165
-        // Administration
166
-        'bans'                        =>
167
-            array(
168
-                'class'   => PageBan::class,
169
-                'actions' => array('set', 'remove'),
170
-            ),
171
-        'userManagement'              =>
172
-            array(
173
-                'class'   => PageUserManagement::class,
174
-                'actions' => array(
175
-                    'approve',
176
-                    'decline',
177
-                    'rename',
178
-                    'editUser',
179
-                    'suspend',
180
-                    'editRoles',
181
-                ),
182
-            ),
183
-        'siteNotice'                  =>
184
-            array(
185
-                'class'   => PageSiteNotice::class,
186
-                'actions' => array(),
187
-            ),
188
-        'emailManagement'             =>
189
-            array(
190
-                'class'   => PageEmailManagement::class,
191
-                'actions' => array('create', 'edit', 'view'),
192
-            ),
193
-        'jobQueue'                    =>
194
-            array(
195
-                'class'   => PageJobQueue::class,
196
-                'actions' => array('acknowledge', 'requeue', 'view', 'all'),
197
-            ),
198
-
199
-        //////////////////////////////////////////////////////////////////////////////////////////////////
200
-        // Personal preferences
201
-        'preferences'                 =>
202
-            array(
203
-                'class'   => PagePreferences::class,
204
-                'actions' => array(
205
-                    'refreshOAuth'
206
-                ),
207
-            ),
208
-        'changePassword'              =>
209
-            array(
210
-                'class'   => PageChangePassword::class,
211
-                'actions' => array(),
212
-            ),
213
-        'multiFactor'                 =>
214
-            array(
215
-                'class'   => PageMultiFactor::class,
216
-                'actions' => array(
217
-                    'scratch',
218
-                    'enableYubikeyOtp',
219
-                    'disableYubikeyOtp',
220
-                    'enableTotp',
221
-                    'disableTotp',
222
-                    'enableU2F',
223
-                    'disableU2F',
224
-                ),
225
-            ),
226
-        'oauth'                       =>
227
-            array(
228
-                'class'   => PageOAuth::class,
229
-                'actions' => array('detach', 'attach'),
230
-            ),
231
-        'oauth/callback'              =>
232
-            array(
233
-                'class'   => PageOAuthCallback::class,
234
-                'actions' => array('authorise', 'create'),
235
-            ),
236
-
237
-        //////////////////////////////////////////////////////////////////////////////////////////////////
238
-        // Welcomer configuration
239
-        'welcomeTemplates'            =>
240
-            array(
241
-                'class'   => PageWelcomeTemplateManagement::class,
242
-                'actions' => array('select', 'edit', 'delete', 'add', 'view'),
243
-            ),
244
-
245
-        //////////////////////////////////////////////////////////////////////////////////////////////////
246
-        // Statistics
247
-        'statistics'                  =>
248
-            array(
249
-                'class'   => StatsMain::class,
250
-                'actions' => array(),
251
-            ),
252
-        'statistics/fastCloses'       =>
253
-            array(
254
-                'class'   => StatsFastCloses::class,
255
-                'actions' => array(),
256
-            ),
257
-        'statistics/inactiveUsers'    =>
258
-            array(
259
-                'class'   => StatsInactiveUsers::class,
260
-                'actions' => array(),
261
-            ),
262
-        'statistics/monthlyStats'     =>
263
-            array(
264
-                'class'   => StatsMonthlyStats::class,
265
-                'actions' => array(),
266
-            ),
267
-        'statistics/reservedRequests' =>
268
-            array(
269
-                'class'   => StatsReservedRequests::class,
270
-                'actions' => array(),
271
-            ),
272
-        'statistics/templateStats'    =>
273
-            array(
274
-                'class'   => StatsTemplateStats::class,
275
-                'actions' => array(),
276
-            ),
277
-        'statistics/topCreators'      =>
278
-            array(
279
-                'class'   => StatsTopCreators::class,
280
-                'actions' => array(),
281
-            ),
282
-        'statistics/users'            =>
283
-            array(
284
-                'class'   => StatsUsers::class,
285
-                'actions' => array('detail'),
286
-            ),
287
-
288
-        //////////////////////////////////////////////////////////////////////////////////////////////////
289
-        // Zoom page
290
-        'viewRequest'                 =>
291
-            array(
292
-                'class'   => PageViewRequest::class,
293
-                'actions' => array(),
294
-            ),
295
-        'viewRequest/reserve'         =>
296
-            array(
297
-                'class'   => PageReservation::class,
298
-                'actions' => array(),
299
-            ),
300
-        'viewRequest/breakReserve'    =>
301
-            array(
302
-                'class'   => PageBreakReservation::class,
303
-                'actions' => array(),
304
-            ),
305
-        'viewRequest/defer'           =>
306
-            array(
307
-                'class'   => PageDeferRequest::class,
308
-                'actions' => array(),
309
-            ),
310
-        'viewRequest/comment'         =>
311
-            array(
312
-                'class'   => PageComment::class,
313
-                'actions' => array(),
314
-            ),
315
-        'viewRequest/sendToUser'      =>
316
-            array(
317
-                'class'   => PageSendToUser::class,
318
-                'actions' => array(),
319
-            ),
320
-        'viewRequest/close'           =>
321
-            array(
322
-                'class'   => PageCloseRequest::class,
323
-                'actions' => array(),
324
-            ),
325
-        'viewRequest/create'          =>
326
-            array(
327
-                'class'   => PageCreateRequest::class,
328
-                'actions' => array(),
329
-            ),
330
-        'viewRequest/drop'            =>
331
-            array(
332
-                'class'   => PageDropRequest::class,
333
-                'actions' => array(),
334
-            ),
335
-        'viewRequest/custom'          =>
336
-            array(
337
-                'class'   => PageCustomClose::class,
338
-                'actions' => array(),
339
-            ),
340
-        'editComment'                 =>
341
-            array(
342
-                'class'   => PageEditComment::class,
343
-                'actions' => array(),
344
-            ),
345
-
346
-        //////////////////////////////////////////////////////////////////////////////////////////////////
347
-        // Misc stuff
348
-        'team'                        =>
349
-            array(
350
-                'class'   => PageTeam::class,
351
-                'actions' => array(),
352
-            ),
353
-        'requestList'                 =>
354
-            array(
355
-                'class'   => PageExpandedRequestList::class,
356
-                'actions' => array(),
357
-            ),
358
-        'xffdemo'                     =>
359
-            array(
360
-                'class'   => PageXffDemo::class,
361
-                'actions' => array(),
362
-            ),
363
-    );
364
-
365
-    /**
366
-     * @return IRoutedTask
367
-     * @throws Exception
368
-     */
369
-    final public function route()
370
-    {
371
-        $pathInfo = WebRequest::pathInfo();
372
-
373
-        list($pageClass, $action) = $this->getRouteFromPath($pathInfo);
374
-
375
-        /** @var IRoutedTask $page */
376
-        $page = new $pageClass();
377
-
378
-        // Dynamic creation, so we've got to be careful here. We can't use built-in language type protection, so
379
-        // let's use our own.
380
-        if (!($page instanceof IRoutedTask)) {
381
-            throw new Exception('Expected a page, but this is not a page.');
382
-        }
383
-
384
-        // OK, I'm happy at this point that we know we're running a page, and we know it's probably what we want if it
385
-        // inherits PageBase and has been created from the routing map.
386
-        $page->setRoute($action);
387
-
388
-        return $page;
389
-    }
390
-
391
-    /**
392
-     * @param $pathInfo
393
-     *
394
-     * @return array
395
-     */
396
-    protected function getRouteFromPath($pathInfo)
397
-    {
398
-        if (count($pathInfo) === 0) {
399
-            // No pathInfo, so no page to load. Load the main page.
400
-            return $this->getDefaultRoute();
401
-        }
402
-        elseif (count($pathInfo) === 1) {
403
-            // Exactly one path info segment, it's got to be a page.
404
-            $classSegment = $pathInfo[0];
405
-
406
-            return $this->routeSinglePathSegment($classSegment);
407
-        }
408
-
409
-        // OK, we have two or more segments now.
410
-        if (count($pathInfo) > 2) {
411
-            // Let's handle more than two, and collapse it down into two.
412
-            $requestedAction = array_pop($pathInfo);
413
-            $classSegment = implode('/', $pathInfo);
414
-        }
415
-        else {
416
-            // Two path info segments.
417
-            $classSegment = $pathInfo[0];
418
-            $requestedAction = $pathInfo[1];
419
-        }
420
-
421
-        $routeMap = $this->routePathSegments($classSegment, $requestedAction);
422
-
423
-        if ($routeMap[0] === Page404::class) {
424
-            $routeMap = $this->routeSinglePathSegment($classSegment . '/' . $requestedAction);
425
-        }
426
-
427
-        return $routeMap;
428
-    }
429
-
430
-    /**
431
-     * @param $classSegment
432
-     *
433
-     * @return array
434
-     */
435
-    final protected function routeSinglePathSegment($classSegment)
436
-    {
437
-        $routeMap = $this->getRouteMap();
438
-        if (array_key_exists($classSegment, $routeMap)) {
439
-            // Route exists, but we don't have an action in path info, so default to main.
440
-            $pageClass = $routeMap[$classSegment]['class'];
441
-            $action = 'main';
442
-
443
-            return array($pageClass, $action);
444
-        }
445
-        else {
446
-            // Doesn't exist in map. Fall back to 404
447
-            $pageClass = Page404::class;
448
-            $action = "main";
449
-
450
-            return array($pageClass, $action);
451
-        }
452
-    }
453
-
454
-    /**
455
-     * @param $classSegment
456
-     * @param $requestedAction
457
-     *
458
-     * @return array
459
-     */
460
-    final protected function routePathSegments($classSegment, $requestedAction)
461
-    {
462
-        $routeMap = $this->getRouteMap();
463
-        if (array_key_exists($classSegment, $routeMap)) {
464
-            // Route exists, but we don't have an action in path info, so default to main.
465
-
466
-            if (isset($routeMap[$classSegment]['actions'])
467
-                && array_search($requestedAction, $routeMap[$classSegment]['actions']) !== false
468
-            ) {
469
-                // Action exists in allowed action list. Allow both the page and the action
470
-                $pageClass = $routeMap[$classSegment]['class'];
471
-                $action = $requestedAction;
472
-
473
-                return array($pageClass, $action);
474
-            }
475
-            else {
476
-                // Valid page, invalid action. 404 our way out.
477
-                $pageClass = Page404::class;
478
-                $action = 'main';
479
-
480
-                return array($pageClass, $action);
481
-            }
482
-        }
483
-        else {
484
-            // Class doesn't exist in map. Fall back to 404
485
-            $pageClass = Page404::class;
486
-            $action = 'main';
487
-
488
-            return array($pageClass, $action);
489
-        }
490
-    }
491
-
492
-    /**
493
-     * @return array
494
-     */
495
-    protected function getRouteMap()
496
-    {
497
-        return $this->routeMap;
498
-    }
499
-
500
-    /**
501
-     * @return array
502
-     */
503
-    protected function getDefaultRoute()
504
-    {
505
-        return array(PageMain::class, "main");
506
-    }
66
+	/**
67
+	 * This is the core routing table for the application. The basic idea is:
68
+	 *
69
+	 *      array(
70
+	 *          "foo" =>
71
+	 *              array(
72
+	 *                  "class"   => PageFoo::class,
73
+	 *                  "actions" => array("bar", "other")
74
+	 *              ),
75
+	 * );
76
+	 *
77
+	 * Things to note:
78
+	 *     - If no page is requested, we go to PageMain. PageMain can't have actions defined.
79
+	 *
80
+	 *     - If a page is defined and requested, but no action is requested, go to that page's main() method
81
+	 *     - If a page is defined and requested, and an action is defined and requested, go to that action's method.
82
+	 *     - If a page is defined and requested, and an action NOT defined and requested, go to Page404 and it's main()
83
+	 *       method.
84
+	 *     - If a page is NOT defined and requested, go to Page404 and it's main() method.
85
+	 *
86
+	 *     - Query parameters are ignored.
87
+	 *
88
+	 * The key point here is request routing with validation that this is allowed, before we start hitting the
89
+	 * filesystem through the AutoLoader, and opening random files. Also, so that we validate the action requested
90
+	 * before we start calling random methods through the web UI.
91
+	 *
92
+	 * Examples:
93
+	 * /internal.php                => returns instance of PageMain, routed to main()
94
+	 * /internal.php?query          => returns instance of PageMain, routed to main()
95
+	 * /internal.php/foo            => returns instance of PageFoo, routed to main()
96
+	 * /internal.php/foo?query      => returns instance of PageFoo, routed to main()
97
+	 * /internal.php/foo/bar        => returns instance of PageFoo, routed to bar()
98
+	 * /internal.php/foo/bar?query  => returns instance of PageFoo, routed to bar()
99
+	 * /internal.php/foo/baz        => returns instance of Page404, routed to main()
100
+	 * /internal.php/foo/baz?query  => returns instance of Page404, routed to main()
101
+	 * /internal.php/bar            => returns instance of Page404, routed to main()
102
+	 * /internal.php/bar?query      => returns instance of Page404, routed to main()
103
+	 * /internal.php/bar/baz        => returns instance of Page404, routed to main()
104
+	 * /internal.php/bar/baz?query  => returns instance of Page404, routed to main()
105
+	 *
106
+	 * Take care when changing this - a lot of places rely on the array key for redirects and other links. If you need
107
+	 * to change the key, then you'll likely have to update a lot of files.
108
+	 *
109
+	 * @var array
110
+	 */
111
+	private $routeMap = array(
112
+
113
+		//////////////////////////////////////////////////////////////////////////////////////////////////
114
+		// Login and registration
115
+		'logout'                      =>
116
+			array(
117
+				'class'   => PageLogout::class,
118
+				'actions' => array(),
119
+			),
120
+		'login'                       =>
121
+			array(
122
+				'class'   => PagePasswordLogin::class,
123
+				'actions' => array(),
124
+			),
125
+		'login/otp'                   =>
126
+			array(
127
+				'class'   => PageOtpLogin::class,
128
+				'actions' => array(),
129
+			),
130
+		'login/u2f'                   =>
131
+			array(
132
+				'class'   => PageU2FLogin::class,
133
+				'actions' => array(),
134
+			),
135
+		'forgotPassword'              =>
136
+			array(
137
+				'class'   => PageForgotPassword::class,
138
+				'actions' => array('reset'),
139
+			),
140
+		'register'                    =>
141
+			array(
142
+				'class'   => PageRegisterOption::class,
143
+				'actions' => array(),
144
+			),
145
+		'register/standard'           =>
146
+			array(
147
+				'class'   => PageRegisterStandard::class,
148
+				'actions' => array('done'),
149
+			),
150
+
151
+		//////////////////////////////////////////////////////////////////////////////////////////////////
152
+		// Discovery
153
+		'search'                      =>
154
+			array(
155
+				'class'   => PageSearch::class,
156
+				'actions' => array(),
157
+			),
158
+		'logs'                        =>
159
+			array(
160
+				'class'   => PageLog::class,
161
+				'actions' => array(),
162
+			),
163
+
164
+		//////////////////////////////////////////////////////////////////////////////////////////////////
165
+		// Administration
166
+		'bans'                        =>
167
+			array(
168
+				'class'   => PageBan::class,
169
+				'actions' => array('set', 'remove'),
170
+			),
171
+		'userManagement'              =>
172
+			array(
173
+				'class'   => PageUserManagement::class,
174
+				'actions' => array(
175
+					'approve',
176
+					'decline',
177
+					'rename',
178
+					'editUser',
179
+					'suspend',
180
+					'editRoles',
181
+				),
182
+			),
183
+		'siteNotice'                  =>
184
+			array(
185
+				'class'   => PageSiteNotice::class,
186
+				'actions' => array(),
187
+			),
188
+		'emailManagement'             =>
189
+			array(
190
+				'class'   => PageEmailManagement::class,
191
+				'actions' => array('create', 'edit', 'view'),
192
+			),
193
+		'jobQueue'                    =>
194
+			array(
195
+				'class'   => PageJobQueue::class,
196
+				'actions' => array('acknowledge', 'requeue', 'view', 'all'),
197
+			),
198
+
199
+		//////////////////////////////////////////////////////////////////////////////////////////////////
200
+		// Personal preferences
201
+		'preferences'                 =>
202
+			array(
203
+				'class'   => PagePreferences::class,
204
+				'actions' => array(
205
+					'refreshOAuth'
206
+				),
207
+			),
208
+		'changePassword'              =>
209
+			array(
210
+				'class'   => PageChangePassword::class,
211
+				'actions' => array(),
212
+			),
213
+		'multiFactor'                 =>
214
+			array(
215
+				'class'   => PageMultiFactor::class,
216
+				'actions' => array(
217
+					'scratch',
218
+					'enableYubikeyOtp',
219
+					'disableYubikeyOtp',
220
+					'enableTotp',
221
+					'disableTotp',
222
+					'enableU2F',
223
+					'disableU2F',
224
+				),
225
+			),
226
+		'oauth'                       =>
227
+			array(
228
+				'class'   => PageOAuth::class,
229
+				'actions' => array('detach', 'attach'),
230
+			),
231
+		'oauth/callback'              =>
232
+			array(
233
+				'class'   => PageOAuthCallback::class,
234
+				'actions' => array('authorise', 'create'),
235
+			),
236
+
237
+		//////////////////////////////////////////////////////////////////////////////////////////////////
238
+		// Welcomer configuration
239
+		'welcomeTemplates'            =>
240
+			array(
241
+				'class'   => PageWelcomeTemplateManagement::class,
242
+				'actions' => array('select', 'edit', 'delete', 'add', 'view'),
243
+			),
244
+
245
+		//////////////////////////////////////////////////////////////////////////////////////////////////
246
+		// Statistics
247
+		'statistics'                  =>
248
+			array(
249
+				'class'   => StatsMain::class,
250
+				'actions' => array(),
251
+			),
252
+		'statistics/fastCloses'       =>
253
+			array(
254
+				'class'   => StatsFastCloses::class,
255
+				'actions' => array(),
256
+			),
257
+		'statistics/inactiveUsers'    =>
258
+			array(
259
+				'class'   => StatsInactiveUsers::class,
260
+				'actions' => array(),
261
+			),
262
+		'statistics/monthlyStats'     =>
263
+			array(
264
+				'class'   => StatsMonthlyStats::class,
265
+				'actions' => array(),
266
+			),
267
+		'statistics/reservedRequests' =>
268
+			array(
269
+				'class'   => StatsReservedRequests::class,
270
+				'actions' => array(),
271
+			),
272
+		'statistics/templateStats'    =>
273
+			array(
274
+				'class'   => StatsTemplateStats::class,
275
+				'actions' => array(),
276
+			),
277
+		'statistics/topCreators'      =>
278
+			array(
279
+				'class'   => StatsTopCreators::class,
280
+				'actions' => array(),
281
+			),
282
+		'statistics/users'            =>
283
+			array(
284
+				'class'   => StatsUsers::class,
285
+				'actions' => array('detail'),
286
+			),
287
+
288
+		//////////////////////////////////////////////////////////////////////////////////////////////////
289
+		// Zoom page
290
+		'viewRequest'                 =>
291
+			array(
292
+				'class'   => PageViewRequest::class,
293
+				'actions' => array(),
294
+			),
295
+		'viewRequest/reserve'         =>
296
+			array(
297
+				'class'   => PageReservation::class,
298
+				'actions' => array(),
299
+			),
300
+		'viewRequest/breakReserve'    =>
301
+			array(
302
+				'class'   => PageBreakReservation::class,
303
+				'actions' => array(),
304
+			),
305
+		'viewRequest/defer'           =>
306
+			array(
307
+				'class'   => PageDeferRequest::class,
308
+				'actions' => array(),
309
+			),
310
+		'viewRequest/comment'         =>
311
+			array(
312
+				'class'   => PageComment::class,
313
+				'actions' => array(),
314
+			),
315
+		'viewRequest/sendToUser'      =>
316
+			array(
317
+				'class'   => PageSendToUser::class,
318
+				'actions' => array(),
319
+			),
320
+		'viewRequest/close'           =>
321
+			array(
322
+				'class'   => PageCloseRequest::class,
323
+				'actions' => array(),
324
+			),
325
+		'viewRequest/create'          =>
326
+			array(
327
+				'class'   => PageCreateRequest::class,
328
+				'actions' => array(),
329
+			),
330
+		'viewRequest/drop'            =>
331
+			array(
332
+				'class'   => PageDropRequest::class,
333
+				'actions' => array(),
334
+			),
335
+		'viewRequest/custom'          =>
336
+			array(
337
+				'class'   => PageCustomClose::class,
338
+				'actions' => array(),
339
+			),
340
+		'editComment'                 =>
341
+			array(
342
+				'class'   => PageEditComment::class,
343
+				'actions' => array(),
344
+			),
345
+
346
+		//////////////////////////////////////////////////////////////////////////////////////////////////
347
+		// Misc stuff
348
+		'team'                        =>
349
+			array(
350
+				'class'   => PageTeam::class,
351
+				'actions' => array(),
352
+			),
353
+		'requestList'                 =>
354
+			array(
355
+				'class'   => PageExpandedRequestList::class,
356
+				'actions' => array(),
357
+			),
358
+		'xffdemo'                     =>
359
+			array(
360
+				'class'   => PageXffDemo::class,
361
+				'actions' => array(),
362
+			),
363
+	);
364
+
365
+	/**
366
+	 * @return IRoutedTask
367
+	 * @throws Exception
368
+	 */
369
+	final public function route()
370
+	{
371
+		$pathInfo = WebRequest::pathInfo();
372
+
373
+		list($pageClass, $action) = $this->getRouteFromPath($pathInfo);
374
+
375
+		/** @var IRoutedTask $page */
376
+		$page = new $pageClass();
377
+
378
+		// Dynamic creation, so we've got to be careful here. We can't use built-in language type protection, so
379
+		// let's use our own.
380
+		if (!($page instanceof IRoutedTask)) {
381
+			throw new Exception('Expected a page, but this is not a page.');
382
+		}
383
+
384
+		// OK, I'm happy at this point that we know we're running a page, and we know it's probably what we want if it
385
+		// inherits PageBase and has been created from the routing map.
386
+		$page->setRoute($action);
387
+
388
+		return $page;
389
+	}
390
+
391
+	/**
392
+	 * @param $pathInfo
393
+	 *
394
+	 * @return array
395
+	 */
396
+	protected function getRouteFromPath($pathInfo)
397
+	{
398
+		if (count($pathInfo) === 0) {
399
+			// No pathInfo, so no page to load. Load the main page.
400
+			return $this->getDefaultRoute();
401
+		}
402
+		elseif (count($pathInfo) === 1) {
403
+			// Exactly one path info segment, it's got to be a page.
404
+			$classSegment = $pathInfo[0];
405
+
406
+			return $this->routeSinglePathSegment($classSegment);
407
+		}
408
+
409
+		// OK, we have two or more segments now.
410
+		if (count($pathInfo) > 2) {
411
+			// Let's handle more than two, and collapse it down into two.
412
+			$requestedAction = array_pop($pathInfo);
413
+			$classSegment = implode('/', $pathInfo);
414
+		}
415
+		else {
416
+			// Two path info segments.
417
+			$classSegment = $pathInfo[0];
418
+			$requestedAction = $pathInfo[1];
419
+		}
420
+
421
+		$routeMap = $this->routePathSegments($classSegment, $requestedAction);
422
+
423
+		if ($routeMap[0] === Page404::class) {
424
+			$routeMap = $this->routeSinglePathSegment($classSegment . '/' . $requestedAction);
425
+		}
426
+
427
+		return $routeMap;
428
+	}
429
+
430
+	/**
431
+	 * @param $classSegment
432
+	 *
433
+	 * @return array
434
+	 */
435
+	final protected function routeSinglePathSegment($classSegment)
436
+	{
437
+		$routeMap = $this->getRouteMap();
438
+		if (array_key_exists($classSegment, $routeMap)) {
439
+			// Route exists, but we don't have an action in path info, so default to main.
440
+			$pageClass = $routeMap[$classSegment]['class'];
441
+			$action = 'main';
442
+
443
+			return array($pageClass, $action);
444
+		}
445
+		else {
446
+			// Doesn't exist in map. Fall back to 404
447
+			$pageClass = Page404::class;
448
+			$action = "main";
449
+
450
+			return array($pageClass, $action);
451
+		}
452
+	}
453
+
454
+	/**
455
+	 * @param $classSegment
456
+	 * @param $requestedAction
457
+	 *
458
+	 * @return array
459
+	 */
460
+	final protected function routePathSegments($classSegment, $requestedAction)
461
+	{
462
+		$routeMap = $this->getRouteMap();
463
+		if (array_key_exists($classSegment, $routeMap)) {
464
+			// Route exists, but we don't have an action in path info, so default to main.
465
+
466
+			if (isset($routeMap[$classSegment]['actions'])
467
+				&& array_search($requestedAction, $routeMap[$classSegment]['actions']) !== false
468
+			) {
469
+				// Action exists in allowed action list. Allow both the page and the action
470
+				$pageClass = $routeMap[$classSegment]['class'];
471
+				$action = $requestedAction;
472
+
473
+				return array($pageClass, $action);
474
+			}
475
+			else {
476
+				// Valid page, invalid action. 404 our way out.
477
+				$pageClass = Page404::class;
478
+				$action = 'main';
479
+
480
+				return array($pageClass, $action);
481
+			}
482
+		}
483
+		else {
484
+			// Class doesn't exist in map. Fall back to 404
485
+			$pageClass = Page404::class;
486
+			$action = 'main';
487
+
488
+			return array($pageClass, $action);
489
+		}
490
+	}
491
+
492
+	/**
493
+	 * @return array
494
+	 */
495
+	protected function getRouteMap()
496
+	{
497
+		return $this->routeMap;
498
+	}
499
+
500
+	/**
501
+	 * @return array
502
+	 */
503
+	protected function getDefaultRoute()
504
+	{
505
+		return array(PageMain::class, "main");
506
+	}
507 507
 }
Please login to merge, or discard this patch.
includes/Helpers/BotMediaWikiClient.php 1 patch
Indentation   +132 added lines, -132 removed lines patch added patch discarded remove patch
@@ -16,136 +16,136 @@
 block discarded – undo
16 16
 
17 17
 class BotMediaWikiClient implements IMediaWikiClient
18 18
 {
19
-    /**
20
-     * @var HttpHelper
21
-     */
22
-    private $httpHelper;
23
-    /** @var string */
24
-    private $mediawikiWebServiceEndpoint;
25
-    /** @var string */
26
-    private $creationBotUsername;
27
-    /** @var string */
28
-    private $creationBotPassword;
29
-    /** @var bool */
30
-    private $knownLoggedIn = false;
31
-
32
-    /**
33
-     * BotMediaWikiClient constructor.
34
-     *
35
-     * @param SiteConfiguration $siteConfiguration
36
-     */
37
-    public function __construct(SiteConfiguration $siteConfiguration)
38
-    {
39
-        $this->mediawikiWebServiceEndpoint = $siteConfiguration->getMediawikiWebServiceEndpoint();
40
-
41
-        $this->creationBotUsername = $siteConfiguration->getCreationBotUsername();
42
-        $this->creationBotPassword = $siteConfiguration->getCreationBotPassword();
43
-
44
-        $this->httpHelper = new HttpHelper(
45
-            $siteConfiguration->getUserAgent(),
46
-            $siteConfiguration->getCurlDisableVerifyPeer(),
47
-            $siteConfiguration->getCurlCookieJar()
48
-        );
49
-    }
50
-
51
-    public function doApiCall($apiParams, $method = 'GET')
52
-    {
53
-        $this->ensureLoggedIn();
54
-        $apiParams['assert'] = 'user';
55
-
56
-        return $this->callApi($apiParams, $method);
57
-    }
58
-
59
-    private function ensureLoggedIn()
60
-    {
61
-        if ($this->knownLoggedIn) {
62
-            return;
63
-        }
64
-
65
-        $userinfoResult = $this->callApi(array('action' => 'query', 'meta' => 'userinfo'), 'GET');
66
-        if (isset($userinfoResult->query->userinfo->anon)) {
67
-            // not logged in.
68
-            $this->logIn();
69
-
70
-            // retest
71
-            $userinfoResult = $this->callApi(array('action' => 'query', 'meta' => 'userinfo'), 'GET');
72
-            if (isset($userinfoResult->query->userinfo->anon)) {
73
-                throw new MediaWikiApiException('Unable to log in.');
74
-            }
75
-            else {
76
-                $this->knownLoggedIn = true;
77
-            }
78
-        }
79
-        else {
80
-            $this->knownLoggedIn = true;
81
-        }
82
-    }
83
-
84
-    /**
85
-     * @param $apiParams
86
-     * @param $method
87
-     *
88
-     * @return mixed
89
-     * @throws ApplicationLogicException
90
-     * @throws CurlException
91
-     */
92
-    private function callApi($apiParams, $method)
93
-    {
94
-        $apiParams['format'] = 'json';
95
-
96
-        if ($method == 'GET') {
97
-            $data = $this->httpHelper->get($this->mediawikiWebServiceEndpoint, $apiParams);
98
-        }
99
-        elseif ($method == 'POST') {
100
-            $data = $this->httpHelper->post($this->mediawikiWebServiceEndpoint, $apiParams);
101
-        }
102
-        else {
103
-            throw new ApplicationLogicException('Unsupported HTTP Method');
104
-        }
105
-
106
-        if ($data === false) {
107
-            throw new CurlException('Curl error: ' . $this->httpHelper->getError());
108
-        }
109
-
110
-        $result = json_decode($data);
111
-
112
-        return $result;
113
-    }
114
-
115
-    private function logIn()
116
-    {
117
-        // get token
118
-        $tokenParams = array(
119
-            'action' => 'query',
120
-            'meta'   => 'tokens',
121
-            'type'   => 'login',
122
-        );
123
-
124
-        $response = $this->callApi($tokenParams, 'POST');
125
-
126
-        if (isset($response->error)) {
127
-            throw new MediaWikiApiException($response->error->code . ': ' . $response->error->info);
128
-        }
129
-
130
-        $token = $response->query->tokens->logintoken;
131
-
132
-        if ($token === null) {
133
-            throw new MediaWikiApiException('Edit token could not be acquired');
134
-        }
135
-
136
-        $params = array(
137
-            'action' => 'login',
138
-            'lgname' => $this->creationBotUsername,
139
-            'lgpassword' => $this->creationBotPassword,
140
-            'lgtoken' => $token,
141
-        );
142
-
143
-        $loginResponse = $this->callApi($params, 'POST');
144
-
145
-        if($loginResponse->login->result == 'Success'){
146
-            return;
147
-        }
148
-
149
-        throw new ApplicationLogicException(json_encode($loginResponse));
150
-    }
19
+	/**
20
+	 * @var HttpHelper
21
+	 */
22
+	private $httpHelper;
23
+	/** @var string */
24
+	private $mediawikiWebServiceEndpoint;
25
+	/** @var string */
26
+	private $creationBotUsername;
27
+	/** @var string */
28
+	private $creationBotPassword;
29
+	/** @var bool */
30
+	private $knownLoggedIn = false;
31
+
32
+	/**
33
+	 * BotMediaWikiClient constructor.
34
+	 *
35
+	 * @param SiteConfiguration $siteConfiguration
36
+	 */
37
+	public function __construct(SiteConfiguration $siteConfiguration)
38
+	{
39
+		$this->mediawikiWebServiceEndpoint = $siteConfiguration->getMediawikiWebServiceEndpoint();
40
+
41
+		$this->creationBotUsername = $siteConfiguration->getCreationBotUsername();
42
+		$this->creationBotPassword = $siteConfiguration->getCreationBotPassword();
43
+
44
+		$this->httpHelper = new HttpHelper(
45
+			$siteConfiguration->getUserAgent(),
46
+			$siteConfiguration->getCurlDisableVerifyPeer(),
47
+			$siteConfiguration->getCurlCookieJar()
48
+		);
49
+	}
50
+
51
+	public function doApiCall($apiParams, $method = 'GET')
52
+	{
53
+		$this->ensureLoggedIn();
54
+		$apiParams['assert'] = 'user';
55
+
56
+		return $this->callApi($apiParams, $method);
57
+	}
58
+
59
+	private function ensureLoggedIn()
60
+	{
61
+		if ($this->knownLoggedIn) {
62
+			return;
63
+		}
64
+
65
+		$userinfoResult = $this->callApi(array('action' => 'query', 'meta' => 'userinfo'), 'GET');
66
+		if (isset($userinfoResult->query->userinfo->anon)) {
67
+			// not logged in.
68
+			$this->logIn();
69
+
70
+			// retest
71
+			$userinfoResult = $this->callApi(array('action' => 'query', 'meta' => 'userinfo'), 'GET');
72
+			if (isset($userinfoResult->query->userinfo->anon)) {
73
+				throw new MediaWikiApiException('Unable to log in.');
74
+			}
75
+			else {
76
+				$this->knownLoggedIn = true;
77
+			}
78
+		}
79
+		else {
80
+			$this->knownLoggedIn = true;
81
+		}
82
+	}
83
+
84
+	/**
85
+	 * @param $apiParams
86
+	 * @param $method
87
+	 *
88
+	 * @return mixed
89
+	 * @throws ApplicationLogicException
90
+	 * @throws CurlException
91
+	 */
92
+	private function callApi($apiParams, $method)
93
+	{
94
+		$apiParams['format'] = 'json';
95
+
96
+		if ($method == 'GET') {
97
+			$data = $this->httpHelper->get($this->mediawikiWebServiceEndpoint, $apiParams);
98
+		}
99
+		elseif ($method == 'POST') {
100
+			$data = $this->httpHelper->post($this->mediawikiWebServiceEndpoint, $apiParams);
101
+		}
102
+		else {
103
+			throw new ApplicationLogicException('Unsupported HTTP Method');
104
+		}
105
+
106
+		if ($data === false) {
107
+			throw new CurlException('Curl error: ' . $this->httpHelper->getError());
108
+		}
109
+
110
+		$result = json_decode($data);
111
+
112
+		return $result;
113
+	}
114
+
115
+	private function logIn()
116
+	{
117
+		// get token
118
+		$tokenParams = array(
119
+			'action' => 'query',
120
+			'meta'   => 'tokens',
121
+			'type'   => 'login',
122
+		);
123
+
124
+		$response = $this->callApi($tokenParams, 'POST');
125
+
126
+		if (isset($response->error)) {
127
+			throw new MediaWikiApiException($response->error->code . ': ' . $response->error->info);
128
+		}
129
+
130
+		$token = $response->query->tokens->logintoken;
131
+
132
+		if ($token === null) {
133
+			throw new MediaWikiApiException('Edit token could not be acquired');
134
+		}
135
+
136
+		$params = array(
137
+			'action' => 'login',
138
+			'lgname' => $this->creationBotUsername,
139
+			'lgpassword' => $this->creationBotPassword,
140
+			'lgtoken' => $token,
141
+		);
142
+
143
+		$loginResponse = $this->callApi($params, 'POST');
144
+
145
+		if($loginResponse->login->result == 'Success'){
146
+			return;
147
+		}
148
+
149
+		throw new ApplicationLogicException(json_encode($loginResponse));
150
+	}
151 151
 }
152 152
\ No newline at end of file
Please login to merge, or discard this patch.
includes/Helpers/SearchHelpers/SearchHelperBase.php 1 patch
Indentation   +271 added lines, -271 removed lines patch added patch discarded remove patch
@@ -16,275 +16,275 @@
 block discarded – undo
16 16
 
17 17
 abstract class SearchHelperBase
18 18
 {
19
-    /** @var PdoDatabase */
20
-    protected $database;
21
-    /** @var array */
22
-    protected $parameterList = array();
23
-    /** @var null|int */
24
-    private $limit = null;
25
-    /** @var null|int */
26
-    private $offset = null;
27
-    private $orderBy = null;
28
-    /**
29
-     * @var string The where clause.
30
-     *
31
-     * (the 1=1 condition will be optimised out of the query by the query planner, and simplifies our code here). Note
32
-     * that we use positional parameters instead of named parameters because we don't know many times different options
33
-     * will be called (looking at excluding() here, but there's the option for others).
34
-     */
35
-    protected $whereClause = ' WHERE 1 = 1';
36
-    /** @var string */
37
-    protected $table;
38
-    protected $joinClause = '';
39
-    protected $groupByClause = '';
40
-    protected $modifiersClause = '';
41
-    private $targetClass;
42
-
43
-    /**
44
-     * SearchHelperBase constructor.
45
-     *
46
-     * @param PdoDatabase $database
47
-     * @param string      $table
48
-     * @param             $targetClass
49
-     * @param null|string $order Order by clause, excluding ORDER BY.
50
-     */
51
-    protected function __construct(PdoDatabase $database, $table, $targetClass, $order = null)
52
-    {
53
-        $this->database = $database;
54
-        $this->table = $table;
55
-        $this->orderBy = $order;
56
-        $this->targetClass = $targetClass;
57
-    }
58
-
59
-    /**
60
-     * Finalises the database query, and executes it, returning a set of objects.
61
-     *
62
-     * @return DataObject[]
63
-     */
64
-    public function fetch()
65
-    {
66
-        $statement = $this->getData();
67
-
68
-        /** @var DataObject[] $returnedObjects */
69
-        $returnedObjects = $statement->fetchAll(PDO::FETCH_CLASS, $this->targetClass);
70
-        foreach ($returnedObjects as $req) {
71
-            $req->setDatabase($this->database);
72
-        }
73
-
74
-        return $returnedObjects;
75
-    }
76
-
77
-    /**
78
-     * @param string $whereClauseSection
79
-     * @param array  $values
80
-     *
81
-     * @return array
82
-     */
83
-    protected function fetchByParameter($whereClauseSection, $values)
84
-    {
85
-        $this->whereClause .= $whereClauseSection;
86
-
87
-        $countQuery = 'SELECT /* SearchHelper */ COUNT(*) FROM ' . $this->table . ' origin ';
88
-        $countQuery .= $this->joinClause . $this->whereClause;
89
-
90
-        $query = $this->buildQuery(array('*'));
91
-        $query .= $this->applyOrder();
92
-
93
-        // shuffle around hackily TODO: fix this abomination - T593
94
-        $localParameterList = $this->parameterList;
95
-        $this->parameterList = array();
96
-
97
-        $query .= $this->applyLimit();
98
-
99
-        $limitParameters = $this->parameterList;
100
-
101
-        $statement = $this->database->prepare($query);
102
-        $countStatement = $this->database->prepare($countQuery);
103
-
104
-        $result = array();
105
-        foreach ($values as $v) {
106
-            // reset parameter list
107
-            $params = $localParameterList;
108
-            $params[] = $v;
109
-
110
-            $countStatement->execute($params);
111
-
112
-            // reapply the limit parameters
113
-            $params = array_merge($params, $limitParameters);
114
-
115
-            $statement->execute($params);
116
-
117
-            /** @var DataObject[] $returnedObjects */
118
-            $returnedObjects = $statement->fetchAll(PDO::FETCH_CLASS, $this->targetClass);
119
-            foreach ($returnedObjects as $req) {
120
-                $req->setDatabase($this->database);
121
-            }
122
-
123
-            $result[$v] = array(
124
-                'count' => $countStatement->fetchColumn(0),
125
-                'data'  => $returnedObjects,
126
-            );
127
-        }
128
-
129
-        return $result;
130
-    }
131
-
132
-    /**
133
-     * Finalises the database query, and executes it, returning only the requested column.
134
-     *
135
-     * @param string $column The required column
136
-     *
137
-     * @param bool   $distinct
138
-     *
139
-     * @return array
140
-     * @throws ApplicationLogicException
141
-     */
142
-    public function fetchColumn($column, $distinct = false)
143
-    {
144
-        if ($distinct) {
145
-            if ($this->groupByClause !== '') {
146
-                throw new ApplicationLogicException('Cannot apply distinct to column fetch already using group by');
147
-            }
148
-
149
-            $this->groupByClause = ' GROUP BY origin.' . $column;
150
-        }
151
-
152
-        $statement = $this->getData(array($column));
153
-
154
-        return $statement->fetchAll(PDO::FETCH_COLUMN);
155
-    }
156
-
157
-    public function fetchMap($column)
158
-    {
159
-        $statement = $this->getData(array('id', $column));
160
-
161
-        $data = $statement->fetchAll(PDO::FETCH_ASSOC);
162
-        $map = array();
163
-
164
-        foreach ($data as $row) {
165
-            $map[$row['id']] = $row[$column];
166
-        }
167
-
168
-        return $map;
169
-    }
170
-
171
-    /**
172
-     * @param int $count Returns the record count of the result set
173
-     *
174
-     * @return $this
175
-     */
176
-    public function getRecordCount(&$count)
177
-    {
178
-        $query = 'SELECT /* SearchHelper */ COUNT(*) FROM ' . $this->table . ' origin ';
179
-        $query .= $this->joinClause . $this->whereClause;
180
-
181
-        $statement = $this->database->prepare($query);
182
-        $statement->execute($this->parameterList);
183
-
184
-        $count = $statement->fetchColumn(0);
185
-        $statement->closeCursor();
186
-
187
-        return $this;
188
-    }
189
-
190
-    /**
191
-     * Limits the results
192
-     *
193
-     * @param integer      $limit
194
-     * @param integer|null $offset
195
-     *
196
-     * @return $this
197
-     *
198
-     */
199
-    public function limit($limit, $offset = null)
200
-    {
201
-        $this->limit = $limit;
202
-        $this->offset = $offset;
203
-
204
-        return $this;
205
-    }
206
-
207
-    private function applyLimit()
208
-    {
209
-        $clause = '';
210
-        if ($this->limit !== null) {
211
-            $clause = ' LIMIT ?';
212
-            $this->parameterList[] = $this->limit;
213
-
214
-            if ($this->offset !== null) {
215
-                $clause .= ' OFFSET ?';
216
-                $this->parameterList[] = $this->offset;
217
-            }
218
-        }
219
-
220
-        return $clause;
221
-    }
222
-
223
-    private function applyOrder()
224
-    {
225
-        if ($this->orderBy !== null) {
226
-            return ' ORDER BY ' . $this->orderBy;
227
-        }
228
-
229
-        return '';
230
-    }
231
-
232
-    /**
233
-     * @param array $columns
234
-     *
235
-     * @return PDOStatement
236
-     */
237
-    private function getData($columns = array('*'))
238
-    {
239
-        $query = $this->buildQuery($columns);
240
-        $query .= $this->applyOrder();
241
-        $query .= $this->applyLimit();
242
-
243
-        /** @var PDOStatement $statement */
244
-        $statement = $this->database->prepare($query);
245
-        $statement->execute($this->parameterList);
246
-
247
-        return $statement;
248
-    }
249
-
250
-    /**
251
-     * @param array $columns
252
-     *
253
-     * @return string
254
-     */
255
-    protected function buildQuery($columns)
256
-    {
257
-        $colData = array();
258
-        foreach ($columns as $c) {
259
-            $colData[] = 'origin.' . $c;
260
-        }
261
-
262
-        $query = "SELECT {$this->modifiersClause} /* SearchHelper */ " . implode(', ', $colData) . ' FROM ' . $this->table . ' origin ';
263
-        $query .= $this->joinClause . $this->whereClause . $this->groupByClause;
264
-
265
-        return $query;
266
-    }
267
-
268
-    public function inIds($idList)
269
-    {
270
-        $this->inClause('id', $idList);
271
-
272
-        return $this;
273
-    }
274
-
275
-    protected function inClause($column, $values)
276
-    {
277
-        if (count($values) === 0) {
278
-            return;
279
-        }
280
-
281
-        // Urgh. OK. You can't use IN() with parameters directly, so let's munge something together.
282
-        $valueCount = count($values);
283
-
284
-        // Firstly, let's create a string of question marks, which will do as positional parameters.
285
-        $inSection = str_repeat('?,', $valueCount - 1) . '?';
286
-
287
-        $this->whereClause .= " AND {$column} IN ({$inSection})";
288
-        $this->parameterList = array_merge($this->parameterList, $values);
289
-    }
19
+	/** @var PdoDatabase */
20
+	protected $database;
21
+	/** @var array */
22
+	protected $parameterList = array();
23
+	/** @var null|int */
24
+	private $limit = null;
25
+	/** @var null|int */
26
+	private $offset = null;
27
+	private $orderBy = null;
28
+	/**
29
+	 * @var string The where clause.
30
+	 *
31
+	 * (the 1=1 condition will be optimised out of the query by the query planner, and simplifies our code here). Note
32
+	 * that we use positional parameters instead of named parameters because we don't know many times different options
33
+	 * will be called (looking at excluding() here, but there's the option for others).
34
+	 */
35
+	protected $whereClause = ' WHERE 1 = 1';
36
+	/** @var string */
37
+	protected $table;
38
+	protected $joinClause = '';
39
+	protected $groupByClause = '';
40
+	protected $modifiersClause = '';
41
+	private $targetClass;
42
+
43
+	/**
44
+	 * SearchHelperBase constructor.
45
+	 *
46
+	 * @param PdoDatabase $database
47
+	 * @param string      $table
48
+	 * @param             $targetClass
49
+	 * @param null|string $order Order by clause, excluding ORDER BY.
50
+	 */
51
+	protected function __construct(PdoDatabase $database, $table, $targetClass, $order = null)
52
+	{
53
+		$this->database = $database;
54
+		$this->table = $table;
55
+		$this->orderBy = $order;
56
+		$this->targetClass = $targetClass;
57
+	}
58
+
59
+	/**
60
+	 * Finalises the database query, and executes it, returning a set of objects.
61
+	 *
62
+	 * @return DataObject[]
63
+	 */
64
+	public function fetch()
65
+	{
66
+		$statement = $this->getData();
67
+
68
+		/** @var DataObject[] $returnedObjects */
69
+		$returnedObjects = $statement->fetchAll(PDO::FETCH_CLASS, $this->targetClass);
70
+		foreach ($returnedObjects as $req) {
71
+			$req->setDatabase($this->database);
72
+		}
73
+
74
+		return $returnedObjects;
75
+	}
76
+
77
+	/**
78
+	 * @param string $whereClauseSection
79
+	 * @param array  $values
80
+	 *
81
+	 * @return array
82
+	 */
83
+	protected function fetchByParameter($whereClauseSection, $values)
84
+	{
85
+		$this->whereClause .= $whereClauseSection;
86
+
87
+		$countQuery = 'SELECT /* SearchHelper */ COUNT(*) FROM ' . $this->table . ' origin ';
88
+		$countQuery .= $this->joinClause . $this->whereClause;
89
+
90
+		$query = $this->buildQuery(array('*'));
91
+		$query .= $this->applyOrder();
92
+
93
+		// shuffle around hackily TODO: fix this abomination - T593
94
+		$localParameterList = $this->parameterList;
95
+		$this->parameterList = array();
96
+
97
+		$query .= $this->applyLimit();
98
+
99
+		$limitParameters = $this->parameterList;
100
+
101
+		$statement = $this->database->prepare($query);
102
+		$countStatement = $this->database->prepare($countQuery);
103
+
104
+		$result = array();
105
+		foreach ($values as $v) {
106
+			// reset parameter list
107
+			$params = $localParameterList;
108
+			$params[] = $v;
109
+
110
+			$countStatement->execute($params);
111
+
112
+			// reapply the limit parameters
113
+			$params = array_merge($params, $limitParameters);
114
+
115
+			$statement->execute($params);
116
+
117
+			/** @var DataObject[] $returnedObjects */
118
+			$returnedObjects = $statement->fetchAll(PDO::FETCH_CLASS, $this->targetClass);
119
+			foreach ($returnedObjects as $req) {
120
+				$req->setDatabase($this->database);
121
+			}
122
+
123
+			$result[$v] = array(
124
+				'count' => $countStatement->fetchColumn(0),
125
+				'data'  => $returnedObjects,
126
+			);
127
+		}
128
+
129
+		return $result;
130
+	}
131
+
132
+	/**
133
+	 * Finalises the database query, and executes it, returning only the requested column.
134
+	 *
135
+	 * @param string $column The required column
136
+	 *
137
+	 * @param bool   $distinct
138
+	 *
139
+	 * @return array
140
+	 * @throws ApplicationLogicException
141
+	 */
142
+	public function fetchColumn($column, $distinct = false)
143
+	{
144
+		if ($distinct) {
145
+			if ($this->groupByClause !== '') {
146
+				throw new ApplicationLogicException('Cannot apply distinct to column fetch already using group by');
147
+			}
148
+
149
+			$this->groupByClause = ' GROUP BY origin.' . $column;
150
+		}
151
+
152
+		$statement = $this->getData(array($column));
153
+
154
+		return $statement->fetchAll(PDO::FETCH_COLUMN);
155
+	}
156
+
157
+	public function fetchMap($column)
158
+	{
159
+		$statement = $this->getData(array('id', $column));
160
+
161
+		$data = $statement->fetchAll(PDO::FETCH_ASSOC);
162
+		$map = array();
163
+
164
+		foreach ($data as $row) {
165
+			$map[$row['id']] = $row[$column];
166
+		}
167
+
168
+		return $map;
169
+	}
170
+
171
+	/**
172
+	 * @param int $count Returns the record count of the result set
173
+	 *
174
+	 * @return $this
175
+	 */
176
+	public function getRecordCount(&$count)
177
+	{
178
+		$query = 'SELECT /* SearchHelper */ COUNT(*) FROM ' . $this->table . ' origin ';
179
+		$query .= $this->joinClause . $this->whereClause;
180
+
181
+		$statement = $this->database->prepare($query);
182
+		$statement->execute($this->parameterList);
183
+
184
+		$count = $statement->fetchColumn(0);
185
+		$statement->closeCursor();
186
+
187
+		return $this;
188
+	}
189
+
190
+	/**
191
+	 * Limits the results
192
+	 *
193
+	 * @param integer      $limit
194
+	 * @param integer|null $offset
195
+	 *
196
+	 * @return $this
197
+	 *
198
+	 */
199
+	public function limit($limit, $offset = null)
200
+	{
201
+		$this->limit = $limit;
202
+		$this->offset = $offset;
203
+
204
+		return $this;
205
+	}
206
+
207
+	private function applyLimit()
208
+	{
209
+		$clause = '';
210
+		if ($this->limit !== null) {
211
+			$clause = ' LIMIT ?';
212
+			$this->parameterList[] = $this->limit;
213
+
214
+			if ($this->offset !== null) {
215
+				$clause .= ' OFFSET ?';
216
+				$this->parameterList[] = $this->offset;
217
+			}
218
+		}
219
+
220
+		return $clause;
221
+	}
222
+
223
+	private function applyOrder()
224
+	{
225
+		if ($this->orderBy !== null) {
226
+			return ' ORDER BY ' . $this->orderBy;
227
+		}
228
+
229
+		return '';
230
+	}
231
+
232
+	/**
233
+	 * @param array $columns
234
+	 *
235
+	 * @return PDOStatement
236
+	 */
237
+	private function getData($columns = array('*'))
238
+	{
239
+		$query = $this->buildQuery($columns);
240
+		$query .= $this->applyOrder();
241
+		$query .= $this->applyLimit();
242
+
243
+		/** @var PDOStatement $statement */
244
+		$statement = $this->database->prepare($query);
245
+		$statement->execute($this->parameterList);
246
+
247
+		return $statement;
248
+	}
249
+
250
+	/**
251
+	 * @param array $columns
252
+	 *
253
+	 * @return string
254
+	 */
255
+	protected function buildQuery($columns)
256
+	{
257
+		$colData = array();
258
+		foreach ($columns as $c) {
259
+			$colData[] = 'origin.' . $c;
260
+		}
261
+
262
+		$query = "SELECT {$this->modifiersClause} /* SearchHelper */ " . implode(', ', $colData) . ' FROM ' . $this->table . ' origin ';
263
+		$query .= $this->joinClause . $this->whereClause . $this->groupByClause;
264
+
265
+		return $query;
266
+	}
267
+
268
+	public function inIds($idList)
269
+	{
270
+		$this->inClause('id', $idList);
271
+
272
+		return $this;
273
+	}
274
+
275
+	protected function inClause($column, $values)
276
+	{
277
+		if (count($values) === 0) {
278
+			return;
279
+		}
280
+
281
+		// Urgh. OK. You can't use IN() with parameters directly, so let's munge something together.
282
+		$valueCount = count($values);
283
+
284
+		// Firstly, let's create a string of question marks, which will do as positional parameters.
285
+		$inSection = str_repeat('?,', $valueCount - 1) . '?';
286
+
287
+		$this->whereClause .= " AND {$column} IN ({$inSection})";
288
+		$this->parameterList = array_merge($this->parameterList, $values);
289
+	}
290 290
 }
Please login to merge, or discard this patch.
includes/Helpers/LogHelper.php 1 patch
Indentation   +403 added lines, -403 removed lines patch added patch discarded remove patch
@@ -27,414 +27,414 @@
 block discarded – undo
27 27
 
28 28
 class LogHelper
29 29
 {
30
-    /**
31
-     * Summary of getRequestLogsWithComments
32
-     *
33
-     * @param int             $requestId
34
-     * @param PdoDatabase     $db
35
-     * @param SecurityManager $securityManager
36
-     *
37
-     * @return DataObject[]
38
-     */
39
-    public static function getRequestLogsWithComments($requestId, PdoDatabase $db, SecurityManager $securityManager)
40
-    {
41
-        $logs = LogSearchHelper::get($db)->byObjectType('Request')->byObjectId($requestId)->fetch();
42
-
43
-        $currentUser = User::getCurrent($db);
44
-        $securityResult = $securityManager->allows('RequestData', 'seeRestrictedComments', $currentUser);
45
-        $showAllComments = $securityResult === SecurityManager::ALLOWED;
46
-
47
-        $comments = Comment::getForRequest($requestId, $db, $showAllComments, $currentUser->getId());
48
-
49
-        $items = array_merge($logs, $comments);
50
-
51
-        /**
52
-         * @param DataObject $item
53
-         *
54
-         * @return int
55
-         */
56
-        $sortKey = function(DataObject $item) {
57
-            if ($item instanceof Log) {
58
-                return $item->getTimestamp()->getTimestamp();
59
-            }
60
-
61
-            if ($item instanceof Comment) {
62
-                return $item->getTime()->getTimestamp();
63
-            }
64
-
65
-            return 0;
66
-        };
67
-
68
-        do {
69
-            $flag = false;
70
-
71
-            $loopLimit = (count($items) - 1);
72
-            for ($i = 0; $i < $loopLimit; $i++) {
73
-                // are these two items out of order?
74
-                if ($sortKey($items[$i]) > $sortKey($items[$i + 1])) {
75
-                    // swap them
76
-                    $swap = $items[$i];
77
-                    $items[$i] = $items[$i + 1];
78
-                    $items[$i + 1] = $swap;
79
-
80
-                    // set a flag to say we've modified the array this time around
81
-                    $flag = true;
82
-                }
83
-            }
84
-        }
85
-        while ($flag);
86
-
87
-        return $items;
88
-    }
89
-
90
-    /**
91
-     * Summary of getLogDescription
92
-     *
93
-     * @param Log $entry
94
-     *
95
-     * @return string
96
-     */
97
-    public static function getLogDescription(Log $entry)
98
-    {
99
-        $text = "Deferred to ";
100
-        if (substr($entry->getAction(), 0, strlen($text)) == $text) {
101
-            // Deferred to a different queue
102
-            // This is exactly what we want to display.
103
-            return $entry->getAction();
104
-        }
105
-
106
-        $text = "Closed custom-n";
107
-        if ($entry->getAction() == $text) {
108
-            // Custom-closed
109
-            return "closed (custom reason - account not created)";
110
-        }
111
-
112
-        $text = "Closed custom-y";
113
-        if ($entry->getAction() == $text) {
114
-            // Custom-closed
115
-            return "closed (custom reason - account created)";
116
-        }
117
-
118
-        $text = "Closed 0";
119
-        if ($entry->getAction() == $text) {
120
-            // Dropped the request - short-circuit the lookup
121
-            return "dropped request";
122
-        }
123
-
124
-        $text = "Closed ";
125
-        if (substr($entry->getAction(), 0, strlen($text)) == $text) {
126
-            // Closed with a reason - do a lookup here.
127
-            $id = substr($entry->getAction(), strlen($text));
128
-            /** @var EmailTemplate $template */
129
-            $template = EmailTemplate::getById((int)$id, $entry->getDatabase());
130
-
131
-            if ($template != false) {
132
-                return "closed (" . $template->getName() . ")";
133
-            }
134
-        }
135
-
136
-        // Fall back to the basic stuff
137
-        $lookup = array(
138
-            'Reserved'            => 'reserved',
139
-            'Email Confirmed'     => 'email-confirmed',
140
-            'Unreserved'          => 'unreserved',
141
-            'Approved'            => 'approved',
142
-            'Suspended'           => 'suspended',
143
-            'RoleChange'          => 'changed roles',
144
-            'Banned'              => 'banned',
145
-            'Edited'              => 'edited interface message',
146
-            'Declined'            => 'declined',
147
-            'EditComment-c'       => 'edited a comment',
148
-            'EditComment-r'       => 'edited a comment',
149
-            'Unbanned'            => 'unbanned',
150
-            'Promoted'            => 'promoted to tool admin',
151
-            'BreakReserve'        => 'forcibly broke the reservation',
152
-            'Prefchange'          => 'changed user preferences',
153
-            'Renamed'             => 'renamed',
154
-            'Demoted'             => 'demoted from tool admin',
155
-            'ReceiveReserved'     => 'received the reservation',
156
-            'SendReserved'        => 'sent the reservation',
157
-            'EditedEmail'         => 'edited email',
158
-            'DeletedTemplate'     => 'deleted template',
159
-            'EditedTemplate'      => 'edited template',
160
-            'CreatedEmail'        => 'created email',
161
-            'CreatedTemplate'     => 'created template',
162
-            'SentMail'            => 'sent an email to the requestor',
163
-            'Registered'          => 'registered a tool account',
164
-            'JobIssue'            => 'ran a background job unsuccessfully',
165
-            'JobCompleted'        => 'completed a background job',
166
-            'JobAcknowledged'     => 'acknowledged a job failure',
167
-            'JobRequeued'         => 'requeued a job for re-execution',
168
-            'EnqueuedJobQueue'    => 'scheduled for creation',
169
-            'Hospitalised'        => 'sent to the hospital',
170
-        );
171
-
172
-        if (array_key_exists($entry->getAction(), $lookup)) {
173
-            return $lookup[$entry->getAction()];
174
-        }
175
-
176
-        // OK, I don't know what this is. Fall back to something sane.
177
-        return "performed an unknown action ({$entry->getAction()})";
178
-    }
179
-
180
-    /**
181
-     * @param PdoDatabase $database
182
-     *
183
-     * @return array
184
-     */
185
-    public static function getLogActions(PdoDatabase $database)
186
-    {
187
-        $lookup = array(
188
-            'Reserved'            => 'reserved',
189
-            'Email Confirmed'     => 'email-confirmed',
190
-            'Unreserved'          => 'unreserved',
191
-            'Approved'            => 'approved',
192
-            'Suspended'           => 'suspended',
193
-            'RoleChange'          => 'changed roles',
194
-            'Banned'              => 'banned',
195
-            'Edited'              => 'edited interface message',
196
-            'Declined'            => 'declined',
197
-            'EditComment-c'       => 'edited a comment (by comment ID)',
198
-            'EditComment-r'       => 'edited a comment (by request)',
199
-            'Unbanned'            => 'unbanned',
200
-            'Promoted'            => 'promoted to tool admin',
201
-            'BreakReserve'        => 'forcibly broke the reservation',
202
-            'Prefchange'          => 'changed user preferences',
203
-            'Renamed'             => 'renamed',
204
-            'Demoted'             => 'demoted from tool admin',
205
-            'ReceiveReserved'     => 'received the reservation',
206
-            'SendReserved'        => 'sent the reservation',
207
-            'EditedEmail'         => 'edited email',
208
-            'DeletedTemplate'     => 'deleted template',
209
-            'EditedTemplate'      => 'edited template',
210
-            'CreatedEmail'        => 'created email',
211
-            'CreatedTemplate'     => 'created template',
212
-            'SentMail'            => 'sent an email to the requestor',
213
-            'Registered'          => 'registered a tool account',
214
-            'Closed 0'            => 'dropped request',
215
-            'JobIssue'            => 'ran a background job unsuccessfully',
216
-            'JobCompleted'        => 'completed a background job',
217
-            'JobAcknowledged'     => 'acknowledged a job failure',
218
-            'JobRequeued'         => 'requeued a job for re-execution',
219
-            'EnqueuedJobQueue'    => 'scheduled for creation',
220
-            'Hospitalised'        => 'sent to the hospital',
221
-        );
222
-
223
-        $statement = $database->query(<<<SQL
30
+	/**
31
+	 * Summary of getRequestLogsWithComments
32
+	 *
33
+	 * @param int             $requestId
34
+	 * @param PdoDatabase     $db
35
+	 * @param SecurityManager $securityManager
36
+	 *
37
+	 * @return DataObject[]
38
+	 */
39
+	public static function getRequestLogsWithComments($requestId, PdoDatabase $db, SecurityManager $securityManager)
40
+	{
41
+		$logs = LogSearchHelper::get($db)->byObjectType('Request')->byObjectId($requestId)->fetch();
42
+
43
+		$currentUser = User::getCurrent($db);
44
+		$securityResult = $securityManager->allows('RequestData', 'seeRestrictedComments', $currentUser);
45
+		$showAllComments = $securityResult === SecurityManager::ALLOWED;
46
+
47
+		$comments = Comment::getForRequest($requestId, $db, $showAllComments, $currentUser->getId());
48
+
49
+		$items = array_merge($logs, $comments);
50
+
51
+		/**
52
+		 * @param DataObject $item
53
+		 *
54
+		 * @return int
55
+		 */
56
+		$sortKey = function(DataObject $item) {
57
+			if ($item instanceof Log) {
58
+				return $item->getTimestamp()->getTimestamp();
59
+			}
60
+
61
+			if ($item instanceof Comment) {
62
+				return $item->getTime()->getTimestamp();
63
+			}
64
+
65
+			return 0;
66
+		};
67
+
68
+		do {
69
+			$flag = false;
70
+
71
+			$loopLimit = (count($items) - 1);
72
+			for ($i = 0; $i < $loopLimit; $i++) {
73
+				// are these two items out of order?
74
+				if ($sortKey($items[$i]) > $sortKey($items[$i + 1])) {
75
+					// swap them
76
+					$swap = $items[$i];
77
+					$items[$i] = $items[$i + 1];
78
+					$items[$i + 1] = $swap;
79
+
80
+					// set a flag to say we've modified the array this time around
81
+					$flag = true;
82
+				}
83
+			}
84
+		}
85
+		while ($flag);
86
+
87
+		return $items;
88
+	}
89
+
90
+	/**
91
+	 * Summary of getLogDescription
92
+	 *
93
+	 * @param Log $entry
94
+	 *
95
+	 * @return string
96
+	 */
97
+	public static function getLogDescription(Log $entry)
98
+	{
99
+		$text = "Deferred to ";
100
+		if (substr($entry->getAction(), 0, strlen($text)) == $text) {
101
+			// Deferred to a different queue
102
+			// This is exactly what we want to display.
103
+			return $entry->getAction();
104
+		}
105
+
106
+		$text = "Closed custom-n";
107
+		if ($entry->getAction() == $text) {
108
+			// Custom-closed
109
+			return "closed (custom reason - account not created)";
110
+		}
111
+
112
+		$text = "Closed custom-y";
113
+		if ($entry->getAction() == $text) {
114
+			// Custom-closed
115
+			return "closed (custom reason - account created)";
116
+		}
117
+
118
+		$text = "Closed 0";
119
+		if ($entry->getAction() == $text) {
120
+			// Dropped the request - short-circuit the lookup
121
+			return "dropped request";
122
+		}
123
+
124
+		$text = "Closed ";
125
+		if (substr($entry->getAction(), 0, strlen($text)) == $text) {
126
+			// Closed with a reason - do a lookup here.
127
+			$id = substr($entry->getAction(), strlen($text));
128
+			/** @var EmailTemplate $template */
129
+			$template = EmailTemplate::getById((int)$id, $entry->getDatabase());
130
+
131
+			if ($template != false) {
132
+				return "closed (" . $template->getName() . ")";
133
+			}
134
+		}
135
+
136
+		// Fall back to the basic stuff
137
+		$lookup = array(
138
+			'Reserved'            => 'reserved',
139
+			'Email Confirmed'     => 'email-confirmed',
140
+			'Unreserved'          => 'unreserved',
141
+			'Approved'            => 'approved',
142
+			'Suspended'           => 'suspended',
143
+			'RoleChange'          => 'changed roles',
144
+			'Banned'              => 'banned',
145
+			'Edited'              => 'edited interface message',
146
+			'Declined'            => 'declined',
147
+			'EditComment-c'       => 'edited a comment',
148
+			'EditComment-r'       => 'edited a comment',
149
+			'Unbanned'            => 'unbanned',
150
+			'Promoted'            => 'promoted to tool admin',
151
+			'BreakReserve'        => 'forcibly broke the reservation',
152
+			'Prefchange'          => 'changed user preferences',
153
+			'Renamed'             => 'renamed',
154
+			'Demoted'             => 'demoted from tool admin',
155
+			'ReceiveReserved'     => 'received the reservation',
156
+			'SendReserved'        => 'sent the reservation',
157
+			'EditedEmail'         => 'edited email',
158
+			'DeletedTemplate'     => 'deleted template',
159
+			'EditedTemplate'      => 'edited template',
160
+			'CreatedEmail'        => 'created email',
161
+			'CreatedTemplate'     => 'created template',
162
+			'SentMail'            => 'sent an email to the requestor',
163
+			'Registered'          => 'registered a tool account',
164
+			'JobIssue'            => 'ran a background job unsuccessfully',
165
+			'JobCompleted'        => 'completed a background job',
166
+			'JobAcknowledged'     => 'acknowledged a job failure',
167
+			'JobRequeued'         => 'requeued a job for re-execution',
168
+			'EnqueuedJobQueue'    => 'scheduled for creation',
169
+			'Hospitalised'        => 'sent to the hospital',
170
+		);
171
+
172
+		if (array_key_exists($entry->getAction(), $lookup)) {
173
+			return $lookup[$entry->getAction()];
174
+		}
175
+
176
+		// OK, I don't know what this is. Fall back to something sane.
177
+		return "performed an unknown action ({$entry->getAction()})";
178
+	}
179
+
180
+	/**
181
+	 * @param PdoDatabase $database
182
+	 *
183
+	 * @return array
184
+	 */
185
+	public static function getLogActions(PdoDatabase $database)
186
+	{
187
+		$lookup = array(
188
+			'Reserved'            => 'reserved',
189
+			'Email Confirmed'     => 'email-confirmed',
190
+			'Unreserved'          => 'unreserved',
191
+			'Approved'            => 'approved',
192
+			'Suspended'           => 'suspended',
193
+			'RoleChange'          => 'changed roles',
194
+			'Banned'              => 'banned',
195
+			'Edited'              => 'edited interface message',
196
+			'Declined'            => 'declined',
197
+			'EditComment-c'       => 'edited a comment (by comment ID)',
198
+			'EditComment-r'       => 'edited a comment (by request)',
199
+			'Unbanned'            => 'unbanned',
200
+			'Promoted'            => 'promoted to tool admin',
201
+			'BreakReserve'        => 'forcibly broke the reservation',
202
+			'Prefchange'          => 'changed user preferences',
203
+			'Renamed'             => 'renamed',
204
+			'Demoted'             => 'demoted from tool admin',
205
+			'ReceiveReserved'     => 'received the reservation',
206
+			'SendReserved'        => 'sent the reservation',
207
+			'EditedEmail'         => 'edited email',
208
+			'DeletedTemplate'     => 'deleted template',
209
+			'EditedTemplate'      => 'edited template',
210
+			'CreatedEmail'        => 'created email',
211
+			'CreatedTemplate'     => 'created template',
212
+			'SentMail'            => 'sent an email to the requestor',
213
+			'Registered'          => 'registered a tool account',
214
+			'Closed 0'            => 'dropped request',
215
+			'JobIssue'            => 'ran a background job unsuccessfully',
216
+			'JobCompleted'        => 'completed a background job',
217
+			'JobAcknowledged'     => 'acknowledged a job failure',
218
+			'JobRequeued'         => 'requeued a job for re-execution',
219
+			'EnqueuedJobQueue'    => 'scheduled for creation',
220
+			'Hospitalised'        => 'sent to the hospital',
221
+		);
222
+
223
+		$statement = $database->query(<<<SQL
224 224
 SELECT CONCAT('Closed ', id) AS k, CONCAT('closed (',name,')') AS v
225 225
 FROM emailtemplate;
226 226
 SQL
227
-        );
228
-        foreach ($statement->fetchAll(PDO::FETCH_ASSOC) as $row) {
229
-            $lookup[$row['k']] = $row['v'];
230
-        }
231
-
232
-        return $lookup;
233
-    }
234
-
235
-    public static function getObjectTypes()
236
-    {
237
-        return array(
238
-            'Ban'             => 'Ban',
239
-            'Comment'         => 'Comment',
240
-            'EmailTemplate'   => 'Email template',
241
-            'JobQueue'        => 'Job queue item',
242
-            'Request'         => 'Request',
243
-            'SiteNotice'      => 'Site notice',
244
-            'User'            => 'User',
245
-            'WelcomeTemplate' => 'Welcome template',
246
-        );
247
-    }
248
-
249
-    /**
250
-     * This returns a HTML
251
-     *
252
-     * @param string            $objectId
253
-     * @param string            $objectType
254
-     * @param PdoDatabase       $database
255
-     * @param SiteConfiguration $configuration
256
-     *
257
-     * @return null|string
258
-     * @category Security-Critical
259
-     */
260
-    private static function getObjectDescription(
261
-        $objectId,
262
-        $objectType,
263
-        PdoDatabase $database,
264
-        SiteConfiguration $configuration
265
-    ) {
266
-        if ($objectType == '') {
267
-            return null;
268
-        }
269
-
270
-        $baseurl = $configuration->getBaseUrl();
271
-
272
-        switch ($objectType) {
273
-            case 'Ban':
274
-                /** @var Ban $ban */
275
-                $ban = Ban::getById($objectId, $database);
276
-
277
-                if ($ban === false) {
278
-                    return 'Ban #' . $objectId . "</a>";
279
-                }
280
-
281
-                return 'Ban #' . $objectId . " (" . htmlentities($ban->getTarget()) . ")</a>";
282
-            case 'EmailTemplate':
283
-                /** @var EmailTemplate $emailTemplate */
284
-                $emailTemplate = EmailTemplate::getById($objectId, $database);
285
-                $name = htmlentities($emailTemplate->getName(), ENT_COMPAT, 'UTF-8');
286
-
287
-                return <<<HTML
227
+		);
228
+		foreach ($statement->fetchAll(PDO::FETCH_ASSOC) as $row) {
229
+			$lookup[$row['k']] = $row['v'];
230
+		}
231
+
232
+		return $lookup;
233
+	}
234
+
235
+	public static function getObjectTypes()
236
+	{
237
+		return array(
238
+			'Ban'             => 'Ban',
239
+			'Comment'         => 'Comment',
240
+			'EmailTemplate'   => 'Email template',
241
+			'JobQueue'        => 'Job queue item',
242
+			'Request'         => 'Request',
243
+			'SiteNotice'      => 'Site notice',
244
+			'User'            => 'User',
245
+			'WelcomeTemplate' => 'Welcome template',
246
+		);
247
+	}
248
+
249
+	/**
250
+	 * This returns a HTML
251
+	 *
252
+	 * @param string            $objectId
253
+	 * @param string            $objectType
254
+	 * @param PdoDatabase       $database
255
+	 * @param SiteConfiguration $configuration
256
+	 *
257
+	 * @return null|string
258
+	 * @category Security-Critical
259
+	 */
260
+	private static function getObjectDescription(
261
+		$objectId,
262
+		$objectType,
263
+		PdoDatabase $database,
264
+		SiteConfiguration $configuration
265
+	) {
266
+		if ($objectType == '') {
267
+			return null;
268
+		}
269
+
270
+		$baseurl = $configuration->getBaseUrl();
271
+
272
+		switch ($objectType) {
273
+			case 'Ban':
274
+				/** @var Ban $ban */
275
+				$ban = Ban::getById($objectId, $database);
276
+
277
+				if ($ban === false) {
278
+					return 'Ban #' . $objectId . "</a>";
279
+				}
280
+
281
+				return 'Ban #' . $objectId . " (" . htmlentities($ban->getTarget()) . ")</a>";
282
+			case 'EmailTemplate':
283
+				/** @var EmailTemplate $emailTemplate */
284
+				$emailTemplate = EmailTemplate::getById($objectId, $database);
285
+				$name = htmlentities($emailTemplate->getName(), ENT_COMPAT, 'UTF-8');
286
+
287
+				return <<<HTML
288 288
 <a href="{$baseurl}/internal.php/emailManagement/view?id={$objectId}">Email Template #{$objectId} ({$name})</a>
289 289
 HTML;
290
-            case 'SiteNotice':
291
-                return "<a href=\"{$baseurl}/internal.php/siteNotice\">the site notice</a>";
292
-            case 'Request':
293
-                /** @var Request $request */
294
-                $request = Request::getById($objectId, $database);
295
-                $name = htmlentities($request->getName(), ENT_COMPAT, 'UTF-8');
296
-
297
-                return <<<HTML
290
+			case 'SiteNotice':
291
+				return "<a href=\"{$baseurl}/internal.php/siteNotice\">the site notice</a>";
292
+			case 'Request':
293
+				/** @var Request $request */
294
+				$request = Request::getById($objectId, $database);
295
+				$name = htmlentities($request->getName(), ENT_COMPAT, 'UTF-8');
296
+
297
+				return <<<HTML
298 298
 <a href="{$baseurl}/internal.php/viewRequest?id={$objectId}">Request #{$objectId} ({$name})</a>
299 299
 HTML;
300
-            case 'User':
301
-                /** @var User $user */
302
-                $user = User::getById($objectId, $database);
303
-                $username = htmlentities($user->getUsername(), ENT_COMPAT, 'UTF-8');
304
-
305
-                return "<a href=\"{$baseurl}/internal.php/statistics/users/detail?user={$objectId}\">{$username}</a>";
306
-            case 'WelcomeTemplate':
307
-                /** @var WelcomeTemplate $welcomeTemplate */
308
-                $welcomeTemplate = WelcomeTemplate::getById($objectId, $database);
309
-
310
-                // some old templates have been completely deleted and lost to the depths of time.
311
-                if ($welcomeTemplate === false) {
312
-                    return "Welcome template #{$objectId}";
313
-                }
314
-                else {
315
-                    $userCode = htmlentities($welcomeTemplate->getUserCode(), ENT_COMPAT, 'UTF-8');
316
-
317
-                    return "<a href=\"{$baseurl}/internal.php/welcomeTemplates/view?template={$objectId}\">{$userCode}</a>";
318
-                }
319
-            case 'JobQueue':
320
-                /** @var JobQueue $job */
321
-                $job = JobQueue::getById($objectId, $database);
322
-
323
-                $taskDescriptions = JobQueue::getTaskDescriptions();
324
-
325
-                $task = $job->getTask();
326
-                if(isset($taskDescriptions[$task])){
327
-                    $description = $taskDescriptions[$task];
328
-                } else {
329
-                    $description = 'Unknown task';
330
-                }
331
-
332
-                return "<a href=\"{$baseurl}/internal.php/jobQueue/view?id={$objectId}\">Job #{$job->getId()} ({$description})</a>";
333
-            default:
334
-                return '[' . $objectType . " " . $objectId . ']';
335
-        }
336
-    }
337
-
338
-    /**
339
-     * @param Log[]             $logs
340
-     * @param PdoDatabase       $database
341
-     * @param SiteConfiguration $configuration
342
-     *
343
-     * @return array
344
-     * @throws Exception
345
-     */
346
-    public static function prepareLogsForTemplate($logs, PdoDatabase $database, SiteConfiguration $configuration)
347
-    {
348
-        $userIds = array();
349
-
350
-	    foreach ($logs as $logEntry) {
351
-            if (!$logEntry instanceof Log) {
352
-                // if this happens, we've done something wrong with passing back the log data.
353
-                throw new Exception('Log entry is not an instance of a Log, this should never happen.');
354
-            }
355
-
356
-            $user = $logEntry->getUser();
357
-            if ($user === -1) {
358
-                continue;
359
-            }
360
-
361
-            if (!array_search($user, $userIds)) {
362
-                $userIds[] = $user;
363
-            }
364
-        }
365
-
366
-        $users = UserSearchHelper::get($database)->inIds($userIds)->fetchMap('username');
367
-        $users[-1] = User::getCommunity()->getUsername();
368
-
369
-        $logData = array();
370
-
371
-	    foreach ($logs as $logEntry) {
372
-            $objectDescription = self::getObjectDescription($logEntry->getObjectId(), $logEntry->getObjectType(),
373
-                $database, $configuration);
374
-
375
-            // initialise to sane default
376
-            $comment = null;
377
-
378
-            switch ($logEntry->getAction()) {
379
-                case 'Renamed':
380
-                    $renameData = unserialize($logEntry->getComment());
381
-                    $oldName = htmlentities($renameData['old'], ENT_COMPAT, 'UTF-8');
382
-                    $newName = htmlentities($renameData['new'], ENT_COMPAT, 'UTF-8');
383
-                    $comment = 'Renamed \'' . $oldName . '\' to \'' . $newName . '\'.';
384
-                    break;
385
-                case 'RoleChange':
386
-                    $roleChangeData = unserialize($logEntry->getComment());
387
-
388
-                    $removed = array();
389
-                    foreach ($roleChangeData['removed'] as $r) {
390
-                        $removed[] = htmlentities($r, ENT_COMPAT, 'UTF-8');
391
-                    }
392
-
393
-                    $added = array();
394
-                    foreach ($roleChangeData['added'] as $r) {
395
-                        $added[] = htmlentities($r, ENT_COMPAT, 'UTF-8');
396
-                    }
397
-
398
-                    $reason = htmlentities($roleChangeData['reason'], ENT_COMPAT, 'UTF-8');
399
-
400
-                    $roleDelta = 'Removed [' . implode(', ', $removed) . '], Added [' . implode(', ', $added) . ']';
401
-                    $comment = $roleDelta . ' with comment: ' . $reason;
402
-                    break;
403
-                case 'JobIssue':
404
-                    $jobIssueData = unserialize($logEntry->getComment());
405
-                    $errorMessage = $jobIssueData['error'];
406
-                    $status = $jobIssueData['status'];
407
-
408
-                    $comment = 'Job ' . htmlentities($status, ENT_COMPAT, 'UTF-8') . ': ';
409
-                    $comment .= htmlentities($errorMessage, ENT_COMPAT, 'UTF-8');
410
-                    break;
411
-                case 'JobIssueRequest':
412
-                case 'JobCompletedRequest':
413
-                    $jobData = unserialize($logEntry->getComment());
414
-
415
-                    /** @var JobQueue $job */
416
-                    $job = JobQueue::getById($jobData['job'], $database);
417
-                    $descs = JobQueue::getTaskDescriptions();
418
-                    $comment = htmlentities($descs[$job->getTask()], ENT_COMPAT, 'UTF-8');
419
-                    break;
420
-
421
-                case 'JobCompleted':
422
-                    break;
423
-                default:
424
-                    $comment = $logEntry->getComment();
425
-                    break;
426
-            }
427
-
428
-            $logData[] = array(
429
-                'timestamp'         => $logEntry->getTimestamp(),
430
-                'userid'            => $logEntry->getUser(),
431
-                'username'          => $users[$logEntry->getUser()],
432
-                'description'       => self::getLogDescription($logEntry),
433
-                'objectdescription' => $objectDescription,
434
-                'comment'           => $comment,
435
-            );
436
-        }
437
-
438
-        return array($users, $logData);
439
-    }
300
+			case 'User':
301
+				/** @var User $user */
302
+				$user = User::getById($objectId, $database);
303
+				$username = htmlentities($user->getUsername(), ENT_COMPAT, 'UTF-8');
304
+
305
+				return "<a href=\"{$baseurl}/internal.php/statistics/users/detail?user={$objectId}\">{$username}</a>";
306
+			case 'WelcomeTemplate':
307
+				/** @var WelcomeTemplate $welcomeTemplate */
308
+				$welcomeTemplate = WelcomeTemplate::getById($objectId, $database);
309
+
310
+				// some old templates have been completely deleted and lost to the depths of time.
311
+				if ($welcomeTemplate === false) {
312
+					return "Welcome template #{$objectId}";
313
+				}
314
+				else {
315
+					$userCode = htmlentities($welcomeTemplate->getUserCode(), ENT_COMPAT, 'UTF-8');
316
+
317
+					return "<a href=\"{$baseurl}/internal.php/welcomeTemplates/view?template={$objectId}\">{$userCode}</a>";
318
+				}
319
+			case 'JobQueue':
320
+				/** @var JobQueue $job */
321
+				$job = JobQueue::getById($objectId, $database);
322
+
323
+				$taskDescriptions = JobQueue::getTaskDescriptions();
324
+
325
+				$task = $job->getTask();
326
+				if(isset($taskDescriptions[$task])){
327
+					$description = $taskDescriptions[$task];
328
+				} else {
329
+					$description = 'Unknown task';
330
+				}
331
+
332
+				return "<a href=\"{$baseurl}/internal.php/jobQueue/view?id={$objectId}\">Job #{$job->getId()} ({$description})</a>";
333
+			default:
334
+				return '[' . $objectType . " " . $objectId . ']';
335
+		}
336
+	}
337
+
338
+	/**
339
+	 * @param Log[]             $logs
340
+	 * @param PdoDatabase       $database
341
+	 * @param SiteConfiguration $configuration
342
+	 *
343
+	 * @return array
344
+	 * @throws Exception
345
+	 */
346
+	public static function prepareLogsForTemplate($logs, PdoDatabase $database, SiteConfiguration $configuration)
347
+	{
348
+		$userIds = array();
349
+
350
+		foreach ($logs as $logEntry) {
351
+			if (!$logEntry instanceof Log) {
352
+				// if this happens, we've done something wrong with passing back the log data.
353
+				throw new Exception('Log entry is not an instance of a Log, this should never happen.');
354
+			}
355
+
356
+			$user = $logEntry->getUser();
357
+			if ($user === -1) {
358
+				continue;
359
+			}
360
+
361
+			if (!array_search($user, $userIds)) {
362
+				$userIds[] = $user;
363
+			}
364
+		}
365
+
366
+		$users = UserSearchHelper::get($database)->inIds($userIds)->fetchMap('username');
367
+		$users[-1] = User::getCommunity()->getUsername();
368
+
369
+		$logData = array();
370
+
371
+		foreach ($logs as $logEntry) {
372
+			$objectDescription = self::getObjectDescription($logEntry->getObjectId(), $logEntry->getObjectType(),
373
+				$database, $configuration);
374
+
375
+			// initialise to sane default
376
+			$comment = null;
377
+
378
+			switch ($logEntry->getAction()) {
379
+				case 'Renamed':
380
+					$renameData = unserialize($logEntry->getComment());
381
+					$oldName = htmlentities($renameData['old'], ENT_COMPAT, 'UTF-8');
382
+					$newName = htmlentities($renameData['new'], ENT_COMPAT, 'UTF-8');
383
+					$comment = 'Renamed \'' . $oldName . '\' to \'' . $newName . '\'.';
384
+					break;
385
+				case 'RoleChange':
386
+					$roleChangeData = unserialize($logEntry->getComment());
387
+
388
+					$removed = array();
389
+					foreach ($roleChangeData['removed'] as $r) {
390
+						$removed[] = htmlentities($r, ENT_COMPAT, 'UTF-8');
391
+					}
392
+
393
+					$added = array();
394
+					foreach ($roleChangeData['added'] as $r) {
395
+						$added[] = htmlentities($r, ENT_COMPAT, 'UTF-8');
396
+					}
397
+
398
+					$reason = htmlentities($roleChangeData['reason'], ENT_COMPAT, 'UTF-8');
399
+
400
+					$roleDelta = 'Removed [' . implode(', ', $removed) . '], Added [' . implode(', ', $added) . ']';
401
+					$comment = $roleDelta . ' with comment: ' . $reason;
402
+					break;
403
+				case 'JobIssue':
404
+					$jobIssueData = unserialize($logEntry->getComment());
405
+					$errorMessage = $jobIssueData['error'];
406
+					$status = $jobIssueData['status'];
407
+
408
+					$comment = 'Job ' . htmlentities($status, ENT_COMPAT, 'UTF-8') . ': ';
409
+					$comment .= htmlentities($errorMessage, ENT_COMPAT, 'UTF-8');
410
+					break;
411
+				case 'JobIssueRequest':
412
+				case 'JobCompletedRequest':
413
+					$jobData = unserialize($logEntry->getComment());
414
+
415
+					/** @var JobQueue $job */
416
+					$job = JobQueue::getById($jobData['job'], $database);
417
+					$descs = JobQueue::getTaskDescriptions();
418
+					$comment = htmlentities($descs[$job->getTask()], ENT_COMPAT, 'UTF-8');
419
+					break;
420
+
421
+				case 'JobCompleted':
422
+					break;
423
+				default:
424
+					$comment = $logEntry->getComment();
425
+					break;
426
+			}
427
+
428
+			$logData[] = array(
429
+				'timestamp'         => $logEntry->getTimestamp(),
430
+				'userid'            => $logEntry->getUser(),
431
+				'username'          => $users[$logEntry->getUser()],
432
+				'description'       => self::getLogDescription($logEntry),
433
+				'objectdescription' => $objectDescription,
434
+				'comment'           => $comment,
435
+			);
436
+		}
437
+
438
+		return array($users, $logData);
439
+	}
440 440
 }
Please login to merge, or discard this patch.
includes/ConsoleTasks/RunJobQueueTask.php 1 patch
Indentation   +114 added lines, -114 removed lines patch added patch discarded remove patch
@@ -21,118 +21,118 @@
 block discarded – undo
21 21
 
22 22
 class RunJobQueueTask extends ConsoleTaskBase
23 23
 {
24
-    private $taskList = array(
25
-        WelcomeUserTask::class,
26
-        BotCreationTask::class,
27
-        UserCreationTask::class
28
-    );
29
-
30
-    public function execute()
31
-    {
32
-        $database = $this->getDatabase();
33
-
34
-        // ensure we're running inside a tx here.
35
-        if (!$database->hasActiveTransaction()) {
36
-            $database->beginTransaction();
37
-        }
38
-
39
-        $sql = 'SELECT * FROM jobqueue WHERE status = :status ORDER BY enqueue LIMIT :lim';
40
-        $statement = $database->prepare($sql);
41
-        $statement->execute(array(':status' => JobQueue::STATUS_READY, ':lim' => 10));
42
-        /** @var JobQueue[] $queuedJobs */
43
-        $queuedJobs = $statement->fetchAll(PDO::FETCH_CLASS, JobQueue::class);
44
-
45
-        // mark all the jobs as running, and commit the txn so we're not holding onto long-running transactions.
46
-        // We'll re-lock the row when we get to it.
47
-        foreach ($queuedJobs as $job) {
48
-            $job->setDatabase($database);
49
-            $job->setStatus(JobQueue::STATUS_WAITING);
50
-            $job->setError(null);
51
-            $job->setAcknowledged(null);
52
-            $job->save();
53
-        }
54
-
55
-        $database->commit();
56
-
57
-        set_error_handler(array(RunJobQueueTask::class, 'errorHandler'), E_ALL);
58
-
59
-        foreach ($queuedJobs as $job) {
60
-            try {
61
-                // refresh from the database
62
-                /** @var JobQueue $job */
63
-                $job = JobQueue::getById($job->getId(), $database);
64
-
65
-                if ($job->getStatus() !== JobQueue::STATUS_WAITING) {
66
-                    continue;
67
-                }
68
-
69
-                $database->beginTransaction();
70
-                $job->setStatus(JobQueue::STATUS_RUNNING);
71
-                $job->save();
72
-                $database->commit();
73
-
74
-                $database->beginTransaction();
75
-
76
-                // re-lock the job
77
-                $job->setStatus(JobQueue::STATUS_RUNNING);
78
-                $job->save();
79
-
80
-                // validate we're allowed to run the requested task (whitelist)
81
-                if (!in_array($job->getTask(), $this->taskList)) {
82
-                    throw new ApplicationLogicException('Job task not registered');
83
-                }
84
-
85
-                // Create a task.
86
-                $taskName = $job->getTask();
87
-
88
-                if(!class_exists($taskName)) {
89
-                    throw new ApplicationLogicException('Job task does not exist');
90
-                }
91
-
92
-                /** @var BackgroundTaskBase $task */
93
-                $task = new $taskName;
94
-
95
-                $this->setupTask($task, $job);
96
-                $task->run();
97
-            }
98
-            catch (Exception $ex) {
99
-                $database->rollBack();
100
-                $database->beginTransaction();
101
-
102
-                /** @var JobQueue $job */
103
-                $job = JobQueue::getById($job->getId(), $database);
104
-                $job->setDatabase($database);
105
-                $job->setStatus(JobQueue::STATUS_FAILED);
106
-                $job->setError($ex->getMessage());
107
-                $job->setAcknowledged(0);
108
-                $job->save();
109
-
110
-                Logger::backgroundJobIssue($this->getDatabase(), $job);
111
-
112
-                $database->commit();
113
-            }
114
-            finally {
115
-                $database->commit();
116
-            }
117
-        }
118
-    }
119
-
120
-    /**
121
-     * @param BackgroundTaskBase $task
122
-     * @param JobQueue           $job
123
-     */
124
-    private function setupTask(BackgroundTaskBase $task, JobQueue $job)
125
-    {
126
-        $task->setJob($job);
127
-        $task->setDatabase($this->getDatabase());
128
-        $task->setHttpHelper($this->getHttpHelper());
129
-        $task->setOauthProtocolHelper($this->getOAuthProtocolHelper());
130
-        $task->setEmailHelper($this->getEmailHelper());
131
-        $task->setSiteConfiguration($this->getSiteConfiguration());
132
-        $task->setNotificationHelper($this->getNotificationHelper());
133
-    }
134
-
135
-    public static function errorHandler($errno, $errstr, $errfile, $errline) {
136
-        throw new Exception($errfile . "@" . $errline . ": " . $errstr);
137
-    }
24
+	private $taskList = array(
25
+		WelcomeUserTask::class,
26
+		BotCreationTask::class,
27
+		UserCreationTask::class
28
+	);
29
+
30
+	public function execute()
31
+	{
32
+		$database = $this->getDatabase();
33
+
34
+		// ensure we're running inside a tx here.
35
+		if (!$database->hasActiveTransaction()) {
36
+			$database->beginTransaction();
37
+		}
38
+
39
+		$sql = 'SELECT * FROM jobqueue WHERE status = :status ORDER BY enqueue LIMIT :lim';
40
+		$statement = $database->prepare($sql);
41
+		$statement->execute(array(':status' => JobQueue::STATUS_READY, ':lim' => 10));
42
+		/** @var JobQueue[] $queuedJobs */
43
+		$queuedJobs = $statement->fetchAll(PDO::FETCH_CLASS, JobQueue::class);
44
+
45
+		// mark all the jobs as running, and commit the txn so we're not holding onto long-running transactions.
46
+		// We'll re-lock the row when we get to it.
47
+		foreach ($queuedJobs as $job) {
48
+			$job->setDatabase($database);
49
+			$job->setStatus(JobQueue::STATUS_WAITING);
50
+			$job->setError(null);
51
+			$job->setAcknowledged(null);
52
+			$job->save();
53
+		}
54
+
55
+		$database->commit();
56
+
57
+		set_error_handler(array(RunJobQueueTask::class, 'errorHandler'), E_ALL);
58
+
59
+		foreach ($queuedJobs as $job) {
60
+			try {
61
+				// refresh from the database
62
+				/** @var JobQueue $job */
63
+				$job = JobQueue::getById($job->getId(), $database);
64
+
65
+				if ($job->getStatus() !== JobQueue::STATUS_WAITING) {
66
+					continue;
67
+				}
68
+
69
+				$database->beginTransaction();
70
+				$job->setStatus(JobQueue::STATUS_RUNNING);
71
+				$job->save();
72
+				$database->commit();
73
+
74
+				$database->beginTransaction();
75
+
76
+				// re-lock the job
77
+				$job->setStatus(JobQueue::STATUS_RUNNING);
78
+				$job->save();
79
+
80
+				// validate we're allowed to run the requested task (whitelist)
81
+				if (!in_array($job->getTask(), $this->taskList)) {
82
+					throw new ApplicationLogicException('Job task not registered');
83
+				}
84
+
85
+				// Create a task.
86
+				$taskName = $job->getTask();
87
+
88
+				if(!class_exists($taskName)) {
89
+					throw new ApplicationLogicException('Job task does not exist');
90
+				}
91
+
92
+				/** @var BackgroundTaskBase $task */
93
+				$task = new $taskName;
94
+
95
+				$this->setupTask($task, $job);
96
+				$task->run();
97
+			}
98
+			catch (Exception $ex) {
99
+				$database->rollBack();
100
+				$database->beginTransaction();
101
+
102
+				/** @var JobQueue $job */
103
+				$job = JobQueue::getById($job->getId(), $database);
104
+				$job->setDatabase($database);
105
+				$job->setStatus(JobQueue::STATUS_FAILED);
106
+				$job->setError($ex->getMessage());
107
+				$job->setAcknowledged(0);
108
+				$job->save();
109
+
110
+				Logger::backgroundJobIssue($this->getDatabase(), $job);
111
+
112
+				$database->commit();
113
+			}
114
+			finally {
115
+				$database->commit();
116
+			}
117
+		}
118
+	}
119
+
120
+	/**
121
+	 * @param BackgroundTaskBase $task
122
+	 * @param JobQueue           $job
123
+	 */
124
+	private function setupTask(BackgroundTaskBase $task, JobQueue $job)
125
+	{
126
+		$task->setJob($job);
127
+		$task->setDatabase($this->getDatabase());
128
+		$task->setHttpHelper($this->getHttpHelper());
129
+		$task->setOauthProtocolHelper($this->getOAuthProtocolHelper());
130
+		$task->setEmailHelper($this->getEmailHelper());
131
+		$task->setSiteConfiguration($this->getSiteConfiguration());
132
+		$task->setNotificationHelper($this->getNotificationHelper());
133
+	}
134
+
135
+	public static function errorHandler($errno, $errstr, $errfile, $errline) {
136
+		throw new Exception($errfile . "@" . $errline . ": " . $errstr);
137
+	}
138 138
 }
Please login to merge, or discard this patch.