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
|
|
View Code Duplication |
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
|
|
View Code Duplication |
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
|
|
|
* Returns the status name from the status ID specified. |
60
|
|
|
* |
61
|
|
|
* @param int $id ID of the status. |
62
|
|
|
* |
63
|
|
|
* @return string|bool The status name if it exists, false otherwise. |
64
|
|
|
*/ |
65
|
|
|
public function get_status_from_id($id) |
66
|
|
|
{ |
67
|
|
|
return $this->language->lang(array_search($id, ext::$statuses)); |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* Updates the status of an idea. |
72
|
|
|
* |
73
|
|
|
* @param int $idea_id The ID of the idea. |
74
|
|
|
* @param int $status The ID of the status. |
75
|
|
|
* |
76
|
|
|
* @return void |
77
|
|
|
*/ |
78
|
|
|
public function set_status($idea_id, $status) |
79
|
|
|
{ |
80
|
|
|
$sql_ary = array( |
81
|
|
|
'idea_status' => (int) $status, |
82
|
|
|
); |
83
|
|
|
|
84
|
|
|
$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas); |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* Sets the ID of the duplicate for an idea. |
89
|
|
|
* |
90
|
|
|
* @param int $idea_id ID of the idea to be updated. |
91
|
|
|
* @param string $duplicate Idea ID of duplicate. |
92
|
|
|
* |
93
|
|
|
* @return bool True if set, false if invalid. |
94
|
|
|
*/ |
95
|
|
View Code Duplication |
public function set_duplicate($idea_id, $duplicate) |
|
|
|
|
96
|
|
|
{ |
97
|
|
|
if ($duplicate && !is_numeric($duplicate)) |
98
|
|
|
{ |
99
|
|
|
return false; |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
$sql_ary = array( |
103
|
|
|
'duplicate_id' => (int) $duplicate, |
104
|
|
|
); |
105
|
|
|
|
106
|
|
|
$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas); |
107
|
|
|
|
108
|
|
|
return true; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Sets the RFC link of an idea. |
113
|
|
|
* |
114
|
|
|
* @param int $idea_id ID of the idea to be updated. |
115
|
|
|
* @param string $rfc Link to the RFC. |
116
|
|
|
* |
117
|
|
|
* @return bool True if set, false if invalid. |
118
|
|
|
*/ |
119
|
|
View Code Duplication |
public function set_rfc($idea_id, $rfc) |
|
|
|
|
120
|
|
|
{ |
121
|
|
|
$match = '/^https?:\/\/area51\.phpbb\.com\/phpBB\/viewtopic\.php/'; |
122
|
|
|
if ($rfc && !preg_match($match, $rfc)) |
123
|
|
|
{ |
124
|
|
|
return false; |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
$sql_ary = array( |
128
|
|
|
'rfc_link' => $rfc, // string is escaped by build_array() |
129
|
|
|
); |
130
|
|
|
|
131
|
|
|
$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas); |
132
|
|
|
|
133
|
|
|
return true; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* Sets the ticket ID of an idea. |
138
|
|
|
* |
139
|
|
|
* @param int $idea_id ID of the idea to be updated. |
140
|
|
|
* @param string $ticket Ticket ID. |
141
|
|
|
* |
142
|
|
|
* @return bool True if set, false if invalid. |
143
|
|
|
*/ |
144
|
|
View Code Duplication |
public function set_ticket($idea_id, $ticket) |
|
|
|
|
145
|
|
|
{ |
146
|
|
|
if ($ticket && !is_numeric($ticket)) |
147
|
|
|
{ |
148
|
|
|
return false; |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
$sql_ary = array( |
152
|
|
|
'ticket_id' => (int) $ticket, |
153
|
|
|
); |
154
|
|
|
|
155
|
|
|
$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas); |
156
|
|
|
|
157
|
|
|
return true; |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* Sets the implemented version of an idea. |
162
|
|
|
* |
163
|
|
|
* @param int $idea_id ID of the idea to be updated. |
164
|
|
|
* @param string $version Version of phpBB the idea was implemented in. |
165
|
|
|
* |
166
|
|
|
* @return bool True if set, false if invalid. |
167
|
|
|
*/ |
168
|
|
View Code Duplication |
public function set_implemented($idea_id, $version) |
|
|
|
|
169
|
|
|
{ |
170
|
|
|
$match = '/^\d\.\d\.\d+(\-\w+)?$/'; |
171
|
|
|
if ($version && !preg_match($match, $version)) |
172
|
|
|
{ |
173
|
|
|
return false; |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
$sql_ary = array( |
177
|
|
|
'implemented_version' => $version, // string is escaped by build_array() |
178
|
|
|
); |
179
|
|
|
|
180
|
|
|
$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas); |
181
|
|
|
|
182
|
|
|
return true; |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* Sets the title of an idea. |
187
|
|
|
* |
188
|
|
|
* @param int $idea_id ID of the idea to be updated. |
189
|
|
|
* @param string $title New title. |
190
|
|
|
* |
191
|
|
|
* @return boolean True if updated, false if invalid length. |
192
|
|
|
*/ |
193
|
|
|
public function set_title($idea_id, $title) |
194
|
|
|
{ |
195
|
|
|
if (utf8_clean_string($title) === '') |
196
|
|
|
{ |
197
|
|
|
return false; |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
$sql_ary = array( |
201
|
|
|
'idea_title' => truncate_string($title, ext::SUBJECT_LENGTH), |
202
|
|
|
); |
203
|
|
|
|
204
|
|
|
$this->update_idea_data($sql_ary, $idea_id, $this->table_ideas); |
205
|
|
|
|
206
|
|
|
return true; |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* Get the title of an idea. |
211
|
|
|
* |
212
|
|
|
* @param int $id ID of an idea |
213
|
|
|
* |
214
|
|
|
* @return string The idea's title, empty string if not found |
215
|
|
|
*/ |
216
|
|
|
public function get_title($id) |
217
|
|
|
{ |
218
|
|
|
$sql = 'SELECT idea_title |
219
|
|
|
FROM ' . $this->table_ideas . ' |
220
|
|
|
WHERE idea_id = ' . (int) $id; |
221
|
|
|
$result = $this->db->sql_query_limit($sql, 1); |
222
|
|
|
$idea_title = $this->db->sql_fetchfield('idea_title'); |
223
|
|
|
$this->db->sql_freeresult($result); |
224
|
|
|
|
225
|
|
|
return $idea_title ?: ''; |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* Submit new idea data to the ideas table |
230
|
|
|
* |
231
|
|
|
* @param array $data An array of post data from a newly posted idea |
232
|
|
|
* |
233
|
|
|
* @return int The ID of the new idea. |
234
|
|
|
*/ |
235
|
|
|
public function submit($data) |
236
|
|
|
{ |
237
|
|
|
$sql_ary = [ |
238
|
|
|
'idea_title' => $data['topic_title'], |
239
|
|
|
'idea_author' => $data['poster_id'], |
240
|
|
|
'idea_date' => $data['post_time'], |
241
|
|
|
'topic_id' => $data['topic_id'], |
242
|
|
|
]; |
243
|
|
|
|
244
|
|
|
$idea_id = $this->insert_idea_data($sql_ary, $this->table_ideas); |
245
|
|
|
|
246
|
|
|
// Initial vote |
247
|
|
|
if (($idea = $this->get_idea($idea_id)) !== false) |
248
|
|
|
{ |
249
|
|
|
$this->vote($idea, $data['poster_id'], 1); |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
return $idea_id; |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
/** |
256
|
|
|
* Deletes an idea and the topic to go with it. |
257
|
|
|
* |
258
|
|
|
* @param int $id The ID of the idea to be deleted. |
259
|
|
|
* @param int $topic_id The ID of the idea topic. Optional, but preferred. |
260
|
|
|
* |
261
|
|
|
* @return boolean Whether the idea was deleted or not. |
262
|
|
|
*/ |
263
|
|
|
public function delete($id, $topic_id = 0) |
264
|
|
|
{ |
265
|
|
|
if (!$topic_id) |
266
|
|
|
{ |
267
|
|
|
$idea = $this->get_idea($id); |
268
|
|
|
$topic_id = $idea['topic_id']; |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
// Delete topic |
272
|
|
|
delete_posts('topic_id', $topic_id); |
273
|
|
|
|
274
|
|
|
// Delete idea |
275
|
|
|
$deleted = $this->delete_idea_data($id, $this->table_ideas); |
276
|
|
|
|
277
|
|
|
// Delete votes |
278
|
|
|
$this->delete_idea_data($id, $this->table_votes); |
279
|
|
|
|
280
|
|
|
return $deleted; |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
/** |
284
|
|
|
* Submits a vote on an idea. |
285
|
|
|
* |
286
|
|
|
* @param array $idea The idea returned by get_idea(). |
287
|
|
|
* @param int $user_id The ID of the user voting. |
288
|
|
|
* @param int $value Up (1) or down (0)? |
289
|
|
|
* |
290
|
|
|
* @return array|string Array of information or string on error. |
291
|
|
|
*/ |
292
|
|
|
public function vote(&$idea, $user_id, $value) |
293
|
|
|
{ |
294
|
|
|
// Validate $vote - must be 0 or 1 |
295
|
|
|
if ($value !== 0 && $value !== 1) |
296
|
|
|
{ |
297
|
|
|
return 'INVALID_VOTE'; |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
// Check whether user has already voted - update if they have |
301
|
|
|
$sql = 'SELECT idea_id, vote_value |
302
|
|
|
FROM ' . $this->table_votes . ' |
303
|
|
|
WHERE idea_id = ' . (int) $idea['idea_id'] . ' |
304
|
|
|
AND user_id = ' . (int) $user_id; |
305
|
|
|
$this->db->sql_query_limit($sql, 1); |
306
|
|
|
if ($row = $this->db->sql_fetchrow()) |
307
|
|
|
{ |
308
|
|
|
if ($row['vote_value'] != $value) |
309
|
|
|
{ |
310
|
|
|
$sql = 'UPDATE ' . $this->table_votes . ' |
311
|
|
|
SET vote_value = ' . $value . ' |
312
|
|
|
WHERE user_id = ' . (int) $user_id . ' |
313
|
|
|
AND idea_id = ' . (int) $idea['idea_id']; |
314
|
|
|
$this->db->sql_query($sql); |
315
|
|
|
|
316
|
|
|
if ($value == 1) |
317
|
|
|
{ |
318
|
|
|
// Change to upvote |
319
|
|
|
$idea['idea_votes_up']++; |
320
|
|
|
$idea['idea_votes_down']--; |
321
|
|
|
} |
322
|
|
|
else |
323
|
|
|
{ |
324
|
|
|
// Change to downvote |
325
|
|
|
$idea['idea_votes_up']--; |
326
|
|
|
$idea['idea_votes_down']++; |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
$sql_ary = array( |
330
|
|
|
'idea_votes_up' => $idea['idea_votes_up'], |
331
|
|
|
'idea_votes_down' => $idea['idea_votes_down'], |
332
|
|
|
); |
333
|
|
|
|
334
|
|
|
$this->update_idea_data($sql_ary, $idea['idea_id'], $this->table_ideas); |
335
|
|
|
} |
336
|
|
|
|
337
|
|
|
return array( |
338
|
|
|
'message' => $this->language->lang('UPDATED_VOTE'), |
339
|
|
|
'votes_up' => $idea['idea_votes_up'], |
340
|
|
|
'votes_down' => $idea['idea_votes_down'], |
341
|
|
|
'points' => $this->language->lang('TOTAL_POINTS', $idea['idea_votes_up'] - $idea['idea_votes_down']), |
342
|
|
|
'voters' => $this->get_voters($idea['idea_id']), |
343
|
|
|
); |
344
|
|
|
} |
345
|
|
|
|
346
|
|
|
// Insert vote into votes table. |
347
|
|
|
$sql_ary = array( |
348
|
|
|
'idea_id' => (int) $idea['idea_id'], |
349
|
|
|
'user_id' => (int) $user_id, |
350
|
|
|
'vote_value' => (int) $value, |
351
|
|
|
); |
352
|
|
|
|
353
|
|
|
$this->insert_idea_data($sql_ary, $this->table_votes); |
354
|
|
|
|
355
|
|
|
// Update number of votes in ideas table |
356
|
|
|
$idea['idea_votes_' . ($value ? 'up' : 'down')]++; |
357
|
|
|
|
358
|
|
|
$sql_ary = array( |
359
|
|
|
'idea_votes_up' => $idea['idea_votes_up'], |
360
|
|
|
'idea_votes_down' => $idea['idea_votes_down'], |
361
|
|
|
); |
362
|
|
|
|
363
|
|
|
$this->update_idea_data($sql_ary, $idea['idea_id'], $this->table_ideas); |
364
|
|
|
|
365
|
|
|
return array( |
366
|
|
|
'message' => $this->language->lang('VOTE_SUCCESS'), |
367
|
|
|
'votes_up' => $idea['idea_votes_up'], |
368
|
|
|
'votes_down' => $idea['idea_votes_down'], |
369
|
|
|
'points' => $this->language->lang('TOTAL_POINTS', $idea['idea_votes_up'] - $idea['idea_votes_down']), |
370
|
|
|
'voters' => $this->get_voters($idea['idea_id']), |
371
|
|
|
); |
372
|
|
|
} |
373
|
|
|
|
374
|
|
|
/** |
375
|
|
|
* Remove a user's vote from an idea |
376
|
|
|
* |
377
|
|
|
* @param array $idea The idea returned by get_idea(). |
378
|
|
|
* @param int $user_id The ID of the user voting. |
379
|
|
|
* |
380
|
|
|
* @return array Array of information. |
381
|
|
|
*/ |
382
|
|
|
public function remove_vote(&$idea, $user_id) |
383
|
|
|
{ |
384
|
|
|
// Only change something if user has already voted |
385
|
|
|
$sql = 'SELECT idea_id, vote_value |
386
|
|
|
FROM ' . $this->table_votes . ' |
387
|
|
|
WHERE idea_id = ' . (int) $idea['idea_id'] . ' |
388
|
|
|
AND user_id = ' . (int) $user_id; |
389
|
|
|
$this->db->sql_query_limit($sql, 1); |
390
|
|
|
if ($row = $this->db->sql_fetchrow()) |
391
|
|
|
{ |
392
|
|
|
$sql = 'DELETE FROM ' . $this->table_votes . ' |
393
|
|
|
WHERE idea_id = ' . (int) $idea['idea_id'] . ' |
394
|
|
|
AND user_id = ' . (int) $user_id; |
395
|
|
|
$this->db->sql_query($sql); |
396
|
|
|
|
397
|
|
|
$idea['idea_votes_' . ($row['vote_value'] == 1 ? 'up' : 'down')]--; |
398
|
|
|
|
399
|
|
|
$sql_ary = array( |
400
|
|
|
'idea_votes_up' => $idea['idea_votes_up'], |
401
|
|
|
'idea_votes_down' => $idea['idea_votes_down'], |
402
|
|
|
); |
403
|
|
|
|
404
|
|
|
$this->update_idea_data($sql_ary, $idea['idea_id'], $this->table_ideas); |
405
|
|
|
} |
406
|
|
|
|
407
|
|
|
return array( |
408
|
|
|
'message' => $this->language->lang('UPDATED_VOTE'), |
409
|
|
|
'votes_up' => $idea['idea_votes_up'], |
410
|
|
|
'votes_down' => $idea['idea_votes_down'], |
411
|
|
|
'points' => $this->language->lang('TOTAL_POINTS', $idea['idea_votes_up'] - $idea['idea_votes_down']), |
412
|
|
|
'voters' => $this->get_voters($idea['idea_id']), |
413
|
|
|
); |
414
|
|
|
} |
415
|
|
|
|
416
|
|
|
/** |
417
|
|
|
* Returns voter info on an idea. |
418
|
|
|
* |
419
|
|
|
* @param int $id ID of the idea. |
420
|
|
|
* |
421
|
|
|
* @return array Array of row data |
422
|
|
|
*/ |
423
|
|
|
public function get_voters($id) |
424
|
|
|
{ |
425
|
|
|
$sql = 'SELECT iv.user_id, iv.vote_value, u.username, u.user_colour |
426
|
|
|
FROM ' . $this->table_votes . ' as iv, |
427
|
|
|
' . USERS_TABLE . ' as u |
428
|
|
|
WHERE iv.idea_id = ' . (int) $id . ' |
429
|
|
|
AND iv.user_id = u.user_id |
430
|
|
|
ORDER BY u.username ASC'; |
431
|
|
|
$result = $this->db->sql_query($sql); |
432
|
|
|
$rows = $this->db->sql_fetchrowset($result); |
433
|
|
|
$this->db->sql_freeresult($result); |
434
|
|
|
|
435
|
|
|
// Process the username for the template now, so it is |
436
|
|
|
// ready to use in AJAX responses and DOM injections. |
437
|
|
|
$profile_url = append_sid(generate_board_url() . "/memberlist.{$this->php_ext}", array('mode' => 'viewprofile')); |
438
|
|
|
foreach ($rows as &$row) |
439
|
|
|
{ |
440
|
|
|
$row['user'] = get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, $profile_url); |
441
|
|
|
} |
442
|
|
|
|
443
|
|
|
return $rows; |
444
|
|
|
} |
445
|
|
|
} |
446
|
|
|
|
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.