Completed
Branch newinternal (e32466)
by Simon
03:39
created

LogHelper::getLogActions()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 41
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 41
ccs 0
cts 39
cp 0
rs 8.8571
cc 2
eloc 33
nc 2
nop 1
crap 6
1
<?php
2
/******************************************************************************
3
 * Wikipedia Account Creation Assistance tool                                 *
4
 *                                                                            *
5
 * All code in this file is released into the public domain by the ACC        *
6
 * Development Team. Please see team.json for a list of contributors.         *
7
 ******************************************************************************/
8
9
/**
10
 * Created by PhpStorm.
11
 * User: stwalkerster
12
 * Date: 26/03/2016
13
 * Time: 02:55
14
 */
15
16
namespace Waca\Helpers;
17
18
use Exception;
19
use PDO;
20
use Waca\DataObject;
21
use Waca\DataObjects\Ban;
22
use Waca\DataObjects\Comment;
23
use Waca\DataObjects\EmailTemplate;
24
use Waca\DataObjects\Log;
25
use Waca\DataObjects\Request;
26
use Waca\DataObjects\User;
27
use Waca\DataObjects\WelcomeTemplate;
28
use Waca\Helpers\SearchHelpers\LogSearchHelper;
29
use Waca\PdoDatabase;
30
use Waca\SiteConfiguration;
31
32
class LogHelper
33
{
34
	/**
35
	 * Summary of getRequestLogsWithComments
36
	 *
37
	 * @param int         $requestId
38
	 * @param PdoDatabase $db
39
	 *
40
	 * @return DataObject[]
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<Log|Comment>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
41
	 */
42
	public static function getRequestLogsWithComments($requestId, PdoDatabase $db)
43
	{
44
		$logs = LogSearchHelper::get($db)->byObjectType('Request')->byObjectId($requestId)->fetch();
45
		$comments = Comment::getForRequest($requestId, $db);
46
47
		$items = array_merge($logs, $comments);
48
49
		/**
50
		 * @param DataObject $item
51
		 *
52
		 * @return int
53
		 */
54
		$sortKey = function(DataObject $item) {
55
			if ($item instanceof Log) {
56
				return $item->getTimestamp()->getTimestamp();
57
			}
58
59
			if ($item instanceof Comment) {
60
				return $item->getTime()->getTimestamp();
61
			}
62
63
			return 0;
64
		};
65
66
		do {
67
			$flag = false;
68
69
			$loopLimit = (count($items) - 1);
70
			for ($i = 0; $i < $loopLimit; $i++) {
71
				// are these two items out of order?
72
				if ($sortKey($items[$i]) > $sortKey($items[$i + 1])) {
73
					// swap them
74
					$swap = $items[$i];
75
					$items[$i] = $items[$i + 1];
76
					$items[$i + 1] = $swap;
77
78
					// set a flag to say we've modified the array this time around
79
					$flag = true;
80
				}
81
			}
82
		}
83
		while ($flag);
84
85
		return $items;
86
	}
87
88
	/**
89
	 * Summary of getLogDescription
90
	 *
91
	 * @param Log $entry
92
	 *
93
	 * @return string
94
	 */
95
	public static function getLogDescription(Log $entry)
96
	{
97
		$text = "Deferred to ";
98
		if (substr($entry->getAction(), 0, strlen($text)) == $text) {
99
			// Deferred to a different queue
100
			// This is exactly what we want to display.
101
			return $entry->getAction();
102
		}
103
104
		$text = "Closed custom-n";
105
		if ($entry->getAction() == $text) {
106
			// Custom-closed
107
			return "closed (custom reason - account not created)";
108
		}
109
110
		$text = "Closed custom-y";
111
		if ($entry->getAction() == $text) {
112
			// Custom-closed
113
			return "closed (custom reason - account created)";
114
		}
115
116
		$text = "Closed 0";
117
		if ($entry->getAction() == $text) {
118
			// Dropped the request - short-circuit the lookup
119
			return "dropped request";
120
		}
121
122
		$text = "Closed ";
123
		if (substr($entry->getAction(), 0, strlen($text)) == $text) {
124
			// Closed with a reason - do a lookup here.
125
			$id = substr($entry->getAction(), strlen($text));
126
			/** @var EmailTemplate $template */
127
			$template = EmailTemplate::getById((int)$id, $entry->getDatabase());
128
129
			if ($template != false) {
130
				return "closed (" . $template->getName() . ")";
131
			}
132
		}
133
134
		// Fall back to the basic stuff
135
		$lookup = array(
136
			'Reserved'        => 'reserved',
137
			'Email Confirmed' => 'email-confirmed',
138
			'Unreserved'      => 'unreserved',
139
			'Approved'        => 'approved',
140
			'Suspended'       => 'suspended',
141
			'Banned'          => 'banned',
142
			'Edited'          => 'edited interface message',
143
			'Declined'        => 'declined',
144
			'EditComment-c'   => 'edited a comment',
145
			'EditComment-r'   => 'edited a comment',
146
			'Unbanned'        => 'unbanned',
147
			'Promoted'        => 'promoted to tool admin',
148
			'BreakReserve'    => 'forcibly broke the reservation',
149
			'Prefchange'      => 'changed user preferences',
150
			'Renamed'         => 'renamed',
151
			'Demoted'         => 'demoted from tool admin',
152
			'ReceiveReserved' => 'received the reservation',
153
			'SendReserved'    => 'sent the reservation',
154
			'EditedEmail'     => 'edited email',
155
			'DeletedTemplate' => 'deleted template',
156
			'EditedTemplate'  => 'edited template',
157
			'CreatedEmail'    => 'created email',
158
			'CreatedTemplate' => 'created template',
159
			'SentMail'        => 'sent an email to the requestor',
160
			'Registered'      => 'registered a tool account',
161
		);
162
163
		if (array_key_exists($entry->getAction(), $lookup)) {
164
			return $lookup[$entry->getAction()];
165
		}
166
167
		// OK, I don't know what this is. Fall back to something sane.
168
		return "performed an unknown action ({$entry->getAction()})";
169
	}
170
171
	/**
172
	 * @param PdoDatabase $database
173
	 *
174
	 * @return array
175
	 */
176
	public static function getLogActions(PdoDatabase $database)
177
	{
178
		$lookup = array(
179
			'Reserved'        => 'reserved',
180
			'Email Confirmed' => 'email-confirmed',
181
			'Unreserved'      => 'unreserved',
182
			'Approved'        => 'approved',
183
			'Suspended'       => 'suspended',
184
			'Banned'          => 'banned',
185
			'Edited'          => 'edited interface message',
186
			'Declined'        => 'declined',
187
			'EditComment-c'   => 'edited a comment',
188
			'EditComment-r'   => 'edited a comment',
189
			'Unbanned'        => 'unbanned',
190
			'Promoted'        => 'promoted to tool admin',
191
			'BreakReserve'    => 'forcibly broke the reservation',
192
			'Prefchange'      => 'changed user preferences',
193
			'Renamed'         => 'renamed',
194
			'Demoted'         => 'demoted from tool admin',
195
			'ReceiveReserved' => 'received the reservation',
196
			'SendReserved'    => 'sent the reservation',
197
			'EditedEmail'     => 'edited email',
198
			'DeletedTemplate' => 'deleted template',
199
			'EditedTemplate'  => 'edited template',
200
			'CreatedEmail'    => 'created email',
201
			'CreatedTemplate' => 'created template',
202
			'SentMail'        => 'sent an email to the requestor',
203
			'Registered'      => 'registered a tool account',
204
		);
205
206
		$statement = $database->query(<<<SQL
207
SELECT CONCAT('Closed ', id) AS k, CONCAT('closed (',name,')') AS v
208
FROM emailtemplate;
209
SQL
210
		);
211
		foreach ($statement->fetchAll(PDO::FETCH_ASSOC) as $row) {
212
			$lookup[$row['k']] = $row['v'];
213
		}
214
215
		return $lookup;
216
	}
217
218
	/**
219
	 * This returns a HTML
220
	 *
221
	 * @param string            $objectId
222
	 * @param string            $objectType
223
	 * @param PdoDatabase       $database
224
	 * @param SiteConfiguration $configuration
225
	 *
226
	 * @return null|string
227
	 * @category Security-Critical
228
	 */
229
	private static function getObjectDescription(
230
		$objectId,
231
		$objectType,
232
		PdoDatabase $database,
233
		SiteConfiguration $configuration
234
	) {
235
		if ($objectType == '') {
236
			return null;
237
		}
238
239
		$baseurl = $configuration->getBaseUrl();
240
241
		switch ($objectType) {
242
			case 'Ban':
243
				/** @var Ban $ban */
244
				$ban = Ban::getById($objectId, $database);
245
246
				return 'Ban #' . $objectId . " (" . htmlentities($ban->getTarget()) . ")</a>";
247 View Code Duplication
			case 'EmailTemplate':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
248
				/** @var EmailTemplate $emailTemplate */
249
				$emailTemplate = EmailTemplate::getById($objectId, $database);
250
				$name = htmlentities($emailTemplate->getName(), ENT_COMPAT, 'UTF-8');
251
252
				return <<<HTML
253
<a href="{$baseurl}/internal.php/emailManagement/view?id={$objectId}">Email Template #{$objectId} ({$name})</a>
254
HTML;
255
			case 'SiteNotice':
256
				return "<a href=\"{$baseurl}/internal.php/siteNotice\">the site notice</a>";
257 View Code Duplication
			case 'Request':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
258
				/** @var Request $request */
259
				$request = Request::getById($objectId, $database);
260
				$name = htmlentities($request->getName(), ENT_COMPAT, 'UTF-8');
261
262
				return <<<HTML
263
<a href="{$baseurl}/internal.php/viewRequest?id={$objectId}">Request #{$objectId} ({$name})</a>
264
HTML;
265
			case 'User':
266
				/** @var User $user */
267
				$user = User::getById($objectId, $database);
268
				$username = htmlentities($user->getUsername(), ENT_COMPAT, 'UTF-8');
269
270
				return "<a href=\"{$baseurl}/internal.php/statistics/users/detail?user={$objectId}\">{$username}</a>";
271
			case 'WelcomeTemplate':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
272
				/** @var WelcomeTemplate $welcomeTemplate */
273
				$welcomeTemplate = WelcomeTemplate::getById($objectId, $database);
274
275
				// some old templates have been completely deleted and lost to the depths of time.
276
				if ($welcomeTemplate === false) {
277
					return "Welcome template #{$objectId}";
278
				}
279
				else {
280
					$userCode = htmlentities($welcomeTemplate->getUserCode(), ENT_COMPAT, 'UTF-8');
281
282
					return "<a href=\"{$baseurl}/internal.php/welcomeTemplates/view?template={$objectId}\">{$userCode}</a>";
283
				}
284
			default:
285
				return '[' . $objectType . " " . $objectId . ']';
286
		}
287
	}
288
289
	/**
290
	 * @param    Log[]          $logs
291
	 * @param     PdoDatabase   $database
292
	 * @param SiteConfiguration $configuration
293
	 *
294
	 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
295
	 * @throws Exception
296
	 */
297
	public static function prepareLogsForTemplate($logs, PdoDatabase $database, SiteConfiguration $configuration)
298
	{
299
		$userIds = array();
300
301
		/** @var Log $logEntry */
302
		foreach ($logs as $logEntry) {
303
			if (!$logEntry instanceof Log) {
304
				// if this happens, we've done something wrong with passing back the log data.
305
				throw new Exception('Log entry is not an instance of a Log, this should never happen.');
306
			}
307
308
			$user = $logEntry->getUser();
309
			if ($user === -1) {
310
				continue;
311
			}
312
313
			if (!array_search($user, $userIds)) {
314
				$userIds[] = $user;
315
			}
316
		}
317
318
		$users = User::getUsernames($userIds, $database);
319
		$users[-1] = User::getCommunity()->getUsername();
320
321
		$logData = array();
322
323
		/** @var Log $logEntry */
324
		foreach ($logs as $logEntry) {
325
			$objectDescription = self::getObjectDescription($logEntry->getObjectId(), $logEntry->getObjectType(),
326
				$database, $configuration);
327
328
			if ($logEntry->getAction() === 'Renamed') {
329
				$renameData = unserialize($logEntry->getComment());
330
				$oldName = htmlentities($renameData['old'], ENT_COMPAT, 'UTF-8');
331
				$newName = htmlentities($renameData['new'], ENT_COMPAT, 'UTF-8');
332
				$comment = 'Renamed \'' . $oldName . '\' to \'' . $newName . '\'.';
333
			}
334
			else {
335
				$comment = $logEntry->getComment();
336
			}
337
338
			$logData[] = array(
339
				'timestamp'         => $logEntry->getTimestamp(),
340
				'userid'            => $logEntry->getUser(),
341
				'username'          => $users[$logEntry->getUser()],
342
				'description'       => self::getLogDescription($logEntry),
343
				'objectdescription' => $objectDescription,
344
				'comment'           => $comment,
345
			);
346
		}
347
348
		return array($users, $logData);
349
	}
350
}