Passed
Pull Request — master (#159)
by Matt
01:47
created

idea::notification_exists()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
c 0
b 0
f 0
dl 0
loc 12
rs 10
cc 1
nc 1
nop 1
1
<?php
2
/**
3
 *
4
 * Ideas extension for the phpBB Forum Software package.
5
 *
6
 * @copyright (c) phpBB Limited <https://www.phpbb.com>
7
 * @license GNU General Public License, version 2 (GPL-2.0)
8
 *
9
 */
10
11
namespace phpbb\ideas\factory;
12
13
use phpbb\ideas\ext;
14
15
/**
16
 * Class for handling a single idea
17
 */
18
class idea extends base
19
{
20
	/**
21
	 * Returns the specified idea.
22
	 *
23
	 * @param int $id The ID of the idea to return.
24
	 *
25
	 * @return array|false The idea row set, or false if not found.
26
	 */
27
	public function get_idea($id)
28
	{
29
		$sql = 'SELECT *
30
			FROM ' . $this->table_ideas . '
31
			WHERE idea_id = ' . (int) $id;
32
		$result = $this->db->sql_query_limit($sql, 1);
33
		$row = $this->db->sql_fetchrow($result);
34
		$this->db->sql_freeresult($result);
35
36
		return $row;
37
	}
38
39
	/**
40
	 * Returns an idea specified by its topic ID.
41
	 *
42
	 * @param int $id The ID of the idea to return.
43
	 *
44
	 * @return array|false The idea row set, or false if not found.
45
	 */
46
	public function get_idea_by_topic_id($id)
47
	{
48
		$sql = 'SELECT idea_id
49
			FROM ' . $this->table_ideas . '
50
			WHERE topic_id = ' . (int) $id;
51
		$result = $this->db->sql_query_limit($sql, 1);
52
		$idea_id = (int) $this->db->sql_fetchfield('idea_id');
53
		$this->db->sql_freeresult($result);
54
55
		return $this->get_idea($idea_id);
56
	}
57
58
	/**
59
	 * Updates the status of an idea.
60
	 *
61
	 * @param int $idea_id The ID of the idea.
62
	 * @param int $status  The ID of the status.
63
	 *
64
	 * @return void
65
	 */
66
	public function set_status($idea_id, $status)
67
	{
68
		$sql_ary = array(
69
			'idea_status' => (int) $status,
70
		);
71
72
		$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas);
73
74
		// Send a notification
75
		$method = $this->notification_exists($idea_id) ? 'update_notifications' : 'add_notifications';
76
		$this->notification_manager->$method('phpbb.ideas.notification.type.status', [
77
			'idea_id' => (int) $idea_id,
78
			'status'  => (int) $status,
79
		]);
80
	}
81
82
	/**
83
	 * Sets the ID of the duplicate for an idea.
84
	 *
85
	 * @param int    $idea_id   ID of the idea to be updated.
86
	 * @param string $duplicate Idea ID of duplicate.
87
	 *
88
	 * @return bool True if set, false if invalid.
89
	 */
90
	public function set_duplicate($idea_id, $duplicate)
91
	{
92
		if ($duplicate && !is_numeric($duplicate))
93
		{
94
			return false;
95
		}
96
97
		$sql_ary = array(
98
			'duplicate_id'	=> (int) $duplicate,
99
		);
100
101
		$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas);
102
103
		return true;
104
	}
105
106
	/**
107
	 * Sets the RFC link of an idea.
108
	 *
109
	 * @param int    $idea_id ID of the idea to be updated.
110
	 * @param string $rfc     Link to the RFC.
111
	 *
112
	 * @return bool True if set, false if invalid.
113
	 */
114
	public function set_rfc($idea_id, $rfc)
115
	{
116
		$match = '/^https?:\/\/area51\.phpbb\.com\/phpBB\/viewtopic\.php/';
117
		if ($rfc && !preg_match($match, $rfc))
118
		{
119
			return false;
120
		}
121
122
		$sql_ary = array(
123
			'rfc_link'	=> $rfc, // string is escaped by build_array()
124
		);
125
126
		$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas);
127
128
		return true;
129
	}
130
131
	/**
132
	 * Sets the ticket ID of an idea.
133
	 *
134
	 * @param int    $idea_id ID of the idea to be updated.
135
	 * @param string $ticket  Ticket ID.
136
	 *
137
	 * @return bool True if set, false if invalid.
138
	 */
139
	public function set_ticket($idea_id, $ticket)
140
	{
141
		if ($ticket && !is_numeric($ticket))
142
		{
143
			return false;
144
		}
145
146
		$sql_ary = array(
147
			'ticket_id'	=> (int) $ticket,
148
		);
149
150
		$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas);
151
152
		return true;
153
	}
154
155
	/**
156
	 * Sets the implemented version of an idea.
157
	 *
158
	 * @param int    $idea_id ID of the idea to be updated.
159
	 * @param string $version Version of phpBB the idea was implemented in.
160
	 *
161
	 * @return bool True if set, false if invalid.
162
	 */
163
	public function set_implemented($idea_id, $version)
164
	{
165
		$match = '/^\d\.\d\.\d+(-\w+)?$/';
166
		if ($version && !preg_match($match, $version))
167
		{
168
			return false;
169
		}
170
171
		$sql_ary = array(
172
			'implemented_version'	=> $version, // string is escaped by build_array()
173
		);
174
175
		$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas);
176
177
		return true;
178
	}
179
180
	/**
181
	 * Sets the title of an idea.
182
	 *
183
	 * @param int    $idea_id ID of the idea to be updated.
184
	 * @param string $title   New title.
185
	 *
186
	 * @return boolean True if updated, false if invalid length.
187
	 */
188
	public function set_title($idea_id, $title)
189
	{
190
		if (utf8_clean_string($title) === '')
191
		{
192
			return false;
193
		}
194
195
		$sql_ary = array(
196
			'idea_title' => truncate_string($title, ext::SUBJECT_LENGTH),
197
		);
198
199
		$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas);
200
201
		return true;
202
	}
203
204
	/**
205
	 * Get the title of an idea.
206
	 *
207
	 * @param int $id ID of an idea
208
	 *
209
	 * @return string The idea's title, empty string if not found
210
	 */
211
	public function get_title($id)
212
	{
213
		$sql = 'SELECT idea_title
214
			FROM ' . $this->table_ideas . '
215
			WHERE idea_id = ' . (int) $id;
216
		$result = $this->db->sql_query_limit($sql, 1);
217
		$idea_title = $this->db->sql_fetchfield('idea_title');
218
		$this->db->sql_freeresult($result);
219
220
		return $idea_title ?: '';
221
	}
222
223
	/**
224
	 * Submit new idea data to the ideas table
225
	 *
226
	 * @param array $data An array of post data from a newly posted idea
227
	 *
228
	 * @return int The ID of the new idea.
229
	 */
230
	public function submit($data)
231
	{
232
		$sql_ary = [
233
			'idea_title'	=> $data['topic_title'],
234
			'idea_author'	=> $data['poster_id'],
235
			'idea_date'		=> $data['post_time'],
236
			'topic_id'		=> $data['topic_id'],
237
		];
238
239
		$idea_id = $this->insert_idea_data($sql_ary, $this->table_ideas);
240
241
		// Initial vote
242
		if (($idea = $this->get_idea($idea_id)) !== false)
243
		{
244
			$this->vote($idea, $data['poster_id'], 1);
245
		}
246
247
		return $idea_id;
248
	}
249
250
	/**
251
	 * Deletes an idea and the topic to go with it.
252
	 *
253
	 * @param int $id       The ID of the idea to be deleted.
254
	 * @param int $topic_id The ID of the idea topic. Optional, but preferred.
255
	 *
256
	 * @return boolean Whether the idea was deleted or not.
257
	 */
258
	public function delete($id, $topic_id = 0)
259
	{
260
		if (!$topic_id)
261
		{
262
			$idea = $this->get_idea($id);
263
			$topic_id = $idea ? $idea['topic_id'] : 0;
264
		}
265
266
		// Delete topic
267
		delete_posts('topic_id', $topic_id);
268
269
		// Delete idea
270
		$deleted = $this->delete_idea_data($id, $this->table_ideas);
271
272
		if ($deleted)
273
		{
274
			// Delete votes
275
			$this->delete_idea_data($id, $this->table_votes);
276
277
			// Delete notifications
278
			$this->notification_manager->delete_notifications('phpbb.ideas.notification.type.status', $id);
279
		}
280
281
		return $deleted;
282
	}
283
284
	/**
285
	 * Submits a vote on an idea.
286
	 *
287
	 * @param array $idea    The idea returned by get_idea().
288
	 * @param int   $user_id The ID of the user voting.
289
	 * @param int   $value   Up (1) or down (0)?
290
	 *
291
	 * @return array|string Array of information or string on error.
292
	 */
293
	public function vote(&$idea, $user_id, $value)
294
	{
295
		// Validate $vote - must be 0 or 1
296
		if ($value !== 0 && $value !== 1)
297
		{
298
			return 'INVALID_VOTE';
299
		}
300
301
		// Check whether user has already voted - update if they have
302
		if ($row = $this->get_users_vote($idea['idea_id'], $user_id))
303
		{
304
			if ($row['vote_value'] != $value)
305
			{
306
				$sql = 'UPDATE ' . $this->table_votes . '
307
					SET vote_value = ' . $value . '
308
					WHERE user_id = ' . (int) $user_id . '
309
						AND idea_id = ' . (int) $idea['idea_id'];
310
				$this->db->sql_query($sql);
311
312
				if ($value == 1)
313
				{
314
					// Change to upvote
315
					$idea['idea_votes_up']++;
316
					$idea['idea_votes_down']--;
317
				}
318
				else
319
				{
320
					// Change to downvote
321
					$idea['idea_votes_up']--;
322
					$idea['idea_votes_down']++;
323
				}
324
325
				$sql_ary = array(
326
					'idea_votes_up'	    => $idea['idea_votes_up'],
327
					'idea_votes_down'	=> $idea['idea_votes_down'],
328
				);
329
330
				$this->update_idea_data($sql_ary, $idea['idea_id'], $this->table_ideas);
331
			}
332
333
			return array(
334
				'message'	    => $this->language->lang('UPDATED_VOTE'),
335
				'votes_up'	    => $idea['idea_votes_up'],
336
				'votes_down'	=> $idea['idea_votes_down'],
337
				'points'        => $this->language->lang('TOTAL_POINTS', $idea['idea_votes_up'] - $idea['idea_votes_down']),
338
				'voters'		=> $this->get_voters($idea['idea_id']),
339
			);
340
		}
341
342
		// Insert vote into votes table.
343
		$sql_ary = array(
344
			'idea_id'		=> (int) $idea['idea_id'],
345
			'user_id'		=> (int) $user_id,
346
			'vote_value'	=> (int) $value,
347
		);
348
349
		$this->insert_idea_data($sql_ary, $this->table_votes);
350
351
		// Update number of votes in ideas table
352
		$idea['idea_votes_' . ($value ? 'up' : 'down')]++;
353
354
		$sql_ary = array(
355
			'idea_votes_up'	    => $idea['idea_votes_up'],
356
			'idea_votes_down'	=> $idea['idea_votes_down'],
357
		);
358
359
		$this->update_idea_data($sql_ary, $idea['idea_id'], $this->table_ideas);
360
361
		return array(
362
			'message'	    => $this->language->lang('VOTE_SUCCESS'),
363
			'votes_up'	    => $idea['idea_votes_up'],
364
			'votes_down'	=> $idea['idea_votes_down'],
365
			'points'        => $this->language->lang('TOTAL_POINTS', $idea['idea_votes_up'] - $idea['idea_votes_down']),
366
			'voters'		=> $this->get_voters($idea['idea_id']),
367
		);
368
	}
369
370
	/**
371
	 * Remove a user's vote from an idea
372
	 *
373
	 * @param array   $idea    The idea returned by get_idea().
374
	 * @param int     $user_id The ID of the user voting.
375
	 *
376
	 * @return array Array of information.
377
	 */
378
	public function remove_vote(&$idea, $user_id)
379
	{
380
		// Only change something if user has already voted
381
		if ($row = $this->get_users_vote($idea['idea_id'], $user_id))
382
		{
383
			$sql = 'DELETE FROM ' . $this->table_votes . '
384
				WHERE idea_id = ' . (int) $idea['idea_id'] . '
385
					AND user_id = ' . (int) $user_id;
386
			$this->db->sql_query($sql);
387
388
			$idea['idea_votes_' . ($row['vote_value'] == 1 ? 'up' : 'down')]--;
389
390
			$sql_ary = array(
391
				'idea_votes_up'	    => $idea['idea_votes_up'],
392
				'idea_votes_down'	=> $idea['idea_votes_down'],
393
			);
394
395
			$this->update_idea_data($sql_ary, $idea['idea_id'], $this->table_ideas);
396
		}
397
398
		return array(
399
			'message'	    => $this->language->lang('UPDATED_VOTE'),
400
			'votes_up'	    => $idea['idea_votes_up'],
401
			'votes_down'	=> $idea['idea_votes_down'],
402
			'points'        => $this->language->lang('TOTAL_POINTS', $idea['idea_votes_up'] - $idea['idea_votes_down']),
403
			'voters'		=> $this->get_voters($idea['idea_id']),
404
		);
405
	}
406
407
	/**
408
	 * Returns voter info on an idea.
409
	 *
410
	 * @param int $id ID of the idea.
411
	 *
412
	 * @return array Array of row data
413
	 */
414
	public function get_voters($id)
415
	{
416
		$sql = 'SELECT iv.user_id, iv.vote_value, u.username, u.user_colour
417
			FROM ' . $this->table_votes . ' as iv,
418
				' . USERS_TABLE . ' as u
419
			WHERE iv.idea_id = ' . (int) $id . '
420
				AND iv.user_id = u.user_id
421
			ORDER BY u.username ASC';
422
		$result = $this->db->sql_query($sql);
423
		$rows = $this->db->sql_fetchrowset($result);
424
		$this->db->sql_freeresult($result);
425
426
		// Process the username for the template now, so it is
427
		// ready to use in AJAX responses and DOM injections.
428
		$profile_url = append_sid(generate_board_url() . "/memberlist.$this->php_ext", array('mode' => 'viewprofile'));
429
		foreach ($rows as &$row)
430
		{
431
			$row['user'] = get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, $profile_url);
432
		}
433
434
		return $rows;
435
	}
436
437
	/**
438
	 * Get a user's stored vote value for a given idea
439
	 *
440
	 * @param int $idea_id The idea id
441
	 * @param int $user_id The user id
442
	 * @return mixed Array with the row data, false if the row does not exist
443
	 */
444
	protected function get_users_vote($idea_id, $user_id)
445
	{
446
		$sql = 'SELECT idea_id, vote_value
447
			FROM ' . $this->table_votes . '
448
			WHERE idea_id = ' . (int) $idea_id . '
449
				AND user_id = ' . (int) $user_id;
450
		$result = $this->db->sql_query_limit($sql, 1);
451
		$row = $this->db->sql_fetchrow();
452
		$this->db->sql_freeresult($result);
453
454
		return $row;
455
	}
456
457
	/**
458
	 * Check if a notification already exists
459
	 *
460
	 * @param int $item_id The item identifier for the notification
461
	 * @return bool
462
	 */
463
	protected function notification_exists($item_id)
464
	{
465
		$sql = 'SELECT notification_id
466
			FROM ' . NOTIFICATIONS_TABLE . '
0 ignored issues
show
Bug introduced by
The constant phpbb\ideas\factory\NOTIFICATIONS_TABLE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
467
			WHERE item_id = ' . (int) $item_id . '
468
				AND notification_type_id = ' . $this->notification_manager->get_notification_type_id('phpbb.ideas.notification.type.status');
469
470
		$result = $this->db->sql_query_limit($sql, 1);
471
		$row = $this->db->sql_fetchrow($result);
472
		$this->db->sql_freeresult($result);
473
474
		return $row !== false;
475
	}
476
}
477