Completed
Branch newinternal (ffe884)
by Simon
04:07
created

Request::setForwardedIp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2
Metric Value
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 2
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
namespace Waca\DataObjects;
10
11
use DateTime;
12
use DateTimeImmutable;
13
use Exception;
14
use Waca\DataObject;
15
use Waca\Exceptions\OptimisticLockFailedException;
16
17
/**
18
 * Request data object
19
 *
20
 * This data object is the main request object.
21
 */
22
class Request extends DataObject
23
{
24
	private $email;
25
	private $ip;
26
	private $name;
27
	/** @var string|null */
28
	private $comment;
29
	private $status = "Open";
30
	private $date;
31
	private $emailsent = 0;
32
	private $emailconfirm;
33
	private $reserved = 0;
34
	private $useragent;
35
	private $forwardedip;
36
	private $hasComments = false;
37
	private $hasCommentsResolved = false;
38
39
	/**
40
	 * @throws Exception
41
	 */
42
	public function save()
43
	{
44
		if ($this->isNew()) {
45
			// insert
46
			$statement = $this->dbObject->prepare(<<<SQL
47
INSERT INTO `request` (
48
	email, ip, name, comment, status, date, emailsent,
49
	emailconfirm, reserved, useragent, forwardedip
50
) VALUES (
51
	:email, :ip, :name, :comment, :status, CURRENT_TIMESTAMP(), :emailsent,
52
	:emailconfirm, :reserved, :useragent, :forwardedip
53
);
54
SQL
55
			);
56
			$statement->bindValue(":email", $this->email);
57
			$statement->bindValue(":ip", $this->ip);
58
			$statement->bindValue(":name", $this->name);
59
			$statement->bindValue(":comment", $this->comment);
60
			$statement->bindValue(":status", $this->status);
61
			$statement->bindValue(":emailsent", $this->emailsent);
62
			$statement->bindValue(":emailconfirm", $this->emailconfirm);
63
			$statement->bindValue(":reserved", $this->reserved);
64
			$statement->bindValue(":useragent", $this->useragent);
65
			$statement->bindValue(":forwardedip", $this->forwardedip);
66
67 View Code Duplication
			if ($statement->execute()) {
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...
68
				$this->id = (int)$this->dbObject->lastInsertId();
69
			}
70
			else {
71
				throw new Exception($statement->errorInfo());
72
			}
73
		}
74
		else {
75
			// update
76
			$statement = $this->dbObject->prepare(<<<SQL
77
UPDATE `request` SET
78
	status = :status,
79
	emailsent = :emailsent,
80
	emailconfirm = :emailconfirm,
81
	reserved = :reserved,
82
	updateversion = updateversion + 1
83
WHERE id = :id AND updateversion = :updateversion
84
LIMIT 1;
85
SQL
86
			);
87
88
			$statement->bindValue(':id', $this->id);
89
			$statement->bindValue(':updateversion', $this->updateversion);
90
91
			$statement->bindValue(':status', $this->status);
92
			$statement->bindValue(':emailsent', $this->emailsent);
93
			$statement->bindValue(':emailconfirm', $this->emailconfirm);
94
			$statement->bindValue(':reserved', $this->reserved);
95
96
			if (!$statement->execute()) {
97
				throw new Exception($statement->errorInfo());
98
			}
99
100
			if ($statement->rowCount() !== 1) {
101
				throw new OptimisticLockFailedException();
102
			}
103
104
			$this->updateversion++;
105
		}
106
	}
107
108
	/**
109
	 * @return string
110
	 */
111
	public function getIp()
112
	{
113
		return $this->ip;
114
	}
115
116
	/**
117
	 * @param string $ip
118
	 */
119 1
	public function setIp($ip)
120
	{
121 1
		$this->ip = $ip;
122 1
	}
123
124
	/**
125
	 * @return string
126
	 */
127 1
	public function getName()
128
	{
129 1
		return $this->name;
130
	}
131
132
	/**
133
	 * @param string $name
134
	 */
135 1
	public function setName($name)
136
	{
137 1
		$this->name = $name;
138 1
	}
139
140
	/**
141
	 * @return string|null
142
	 */
143
	public function getComment()
144
	{
145
		return $this->comment;
146
	}
147
148
	/**
149
	 * @param string $comment
150
	 */
151
	public function setComment($comment)
152
	{
153
		$this->comment = $comment;
154
	}
155
156
	/**
157
	 * @return string
158
	 */
159
	public function getStatus()
160
	{
161
		return $this->status;
162
	}
163
164
	/**
165
	 * @param string $status
166
	 */
167
	public function setStatus($status)
168
	{
169
		$this->status = $status;
170
	}
171
172
	/**
173
	 * Returns the time the request was first submitted
174
	 *
175
	 * @return DateTimeImmutable
176
	 */
177
	public function getDate()
178
	{
179
		return new DateTimeImmutable($this->date);
180
	}
181
182
	/**
183
	 * @return bool
184
	 */
185
	public function getEmailSent()
186
	{
187
		return $this->emailsent == "1";
188
	}
189
190
	/**
191
	 * @param bool $emailSent
192
	 */
193
	public function setEmailSent($emailSent)
194
	{
195
		$this->emailsent = $emailSent ? 1 : 0;
196
	}
197
198
	/**
199
	 * @todo allow this to return null instead
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
200
	 * @return int
201
	 */
202
	public function getReserved()
203
	{
204
		return $this->reserved;
205
	}
206
207
	/**
208
	 * @param int|null $reserved
209
	 */
210
	public function setReserved($reserved)
211
	{
212
		if ($reserved === null) {
213
			// @todo this shouldn't be needed!
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
214
			$reserved = 0;
215
		}
216
217
		$this->reserved = $reserved;
218
	}
219
220
	/**
221
	 * @return string
222
	 */
223
	public function getUserAgent()
224
	{
225
		return $this->useragent;
226
	}
227
228
	/**
229
	 * @param string $useragent
230
	 */
231
	public function setUserAgent($useragent)
232
	{
233
		$this->useragent = $useragent;
234
	}
235
236
	/**
237
	 * @return string|null
238
	 */
239
	public function getForwardedIp()
240
	{
241
		return $this->forwardedip;
242
	}
243
244
	/**
245
	 * @param string|null $forwardedip
246
	 */
247
	public function setForwardedIp($forwardedip)
248
	{
249
		$this->forwardedip = $forwardedip;
250
	}
251
252
	/**
253
	 * @return bool
254
	 */
255
	public function hasComments()
256
	{
257
		if ($this->hasCommentsResolved) {
258
			return $this->hasComments;
259
		}
260
261
		if ($this->comment != "") {
262
			$this->hasComments = true;
263
			$this->hasCommentsResolved = true;
264
265
			return true;
266
		}
267
268
		$commentsQuery = $this->dbObject->prepare("SELECT COUNT(*) AS num FROM comment WHERE request = :id;");
269
		$commentsQuery->bindValue(":id", $this->id);
270
271
		$commentsQuery->execute();
272
273
		$this->hasComments = ($commentsQuery->fetchColumn() != 0);
274
		$this->hasCommentsResolved = true;
275
276
		return $this->hasComments;
277
	}
278
279
	/**
280
	 * @return string
281
	 */
282
	public function getEmailConfirm()
283
	{
284
		return $this->emailconfirm;
285
	}
286
287
	/**
288
	 * @param string $emailconfirm
289
	 */
290
	public function setEmailConfirm($emailconfirm)
291
	{
292
		$this->emailconfirm = $emailconfirm;
293
	}
294
295
	public function generateEmailConfirmationHash()
296
	{
297
		$this->emailconfirm = bin2hex(openssl_random_pseudo_bytes(16));
298
	}
299
300
	/**
301
	 * @return string|null
302
	 */
303 1
	public function getEmail()
304
	{
305 1
		return $this->email;
306
	}
307
308
	/**
309
	 * @param string|null $email
310
	 */
311 1
	public function setEmail($email)
312
	{
313 1
		$this->email = $email;
314 1
	}
315
316
	/**
317
	 * @return string
318
	 * @throws Exception
319
	 */
320
	public function getClosureReason()
321
	{
322
		if ($this->status != 'Closed') {
323
			throw new Exception("Can't get closure reason for open request.");
324
		}
325
326
		$statement = $this->dbObject->prepare(<<<SQL
327
SELECT closes.mail_desc
328
FROM log
329
INNER JOIN closes ON log.action = closes.closes
330
WHERE log.objecttype = 'Request'
331
AND log.objectid = :requestId
332
AND log.action LIKE 'Closed%'
333
ORDER BY log.timestamp DESC
334
LIMIT 1;
335
SQL
336
		);
337
338
		$statement->bindValue(":requestId", $this->id);
339
		$statement->execute();
340
		$reason = $statement->fetchColumn();
341
342
		return $reason;
343
	}
344
345
	/**
346
	 * Gets a value indicating whether the request was closed as created or not.
347
	 */
348
	public function getWasCreated()
349
	{
350
		if ($this->status != 'Closed') {
351
			throw new Exception("Can't get closure reason for open request.");
352
		}
353
354
		$statement = $this->dbObject->prepare(<<<SQL
355
SELECT emailtemplate.oncreated, log.action
356
FROM log
357
LEFT JOIN emailtemplate ON CONCAT('Closed ', emailtemplate.id) = log.action
358
WHERE log.objecttype = 'Request'
359
AND log.objectid = :requestId
360
AND log.action LIKE 'Closed%'
361
ORDER BY log.timestamp DESC
362
LIMIT 1;
363
SQL
364
		);
365
366
		$statement->bindValue(":requestId", $this->id);
367
		$statement->execute();
368
		$onCreated = $statement->fetchColumn(0);
369
		$logAction = $statement->fetchColumn(1);
370
		$statement->closeCursor();
371
372
		if ($onCreated === null) {
373
			return $logAction === "Closed custom-y";
374
		}
375
376
		return (bool)$onCreated;
377
	}
378
379
	/**
380
	 * @return DateTime
381
	 */
382 View Code Duplication
	public function getClosureDate()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
383
	{
384
		$logQuery = $this->dbObject->prepare(<<<SQL
385
SELECT timestamp FROM log
386
WHERE objectid = :request AND objecttype = 'Request' AND action LIKE 'Closed%'
387
ORDER BY timestamp DESC LIMIT 1;
388
SQL
389
		);
390
		$logQuery->bindValue(":request", $this->getId());
391
		$logQuery->execute();
392
		$logTime = $logQuery->fetchColumn();
393
		$logQuery->closeCursor();
394
395
		return new DateTime($logTime);
396
	}
397
}
398