|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* This file contains functions for dealing with topics. Low-level functions, |
|
5
|
|
|
* i.e. database operations needed to perform. |
|
6
|
|
|
* These functions do NOT make permissions checks. (they assume those were |
|
7
|
|
|
* already made). |
|
8
|
|
|
* |
|
9
|
|
|
* @name ElkArte Forum |
|
10
|
|
|
* @copyright ElkArte Forum contributors |
|
11
|
|
|
* @license BSD http://opensource.org/licenses/BSD-3-Clause |
|
12
|
|
|
* |
|
13
|
|
|
* This file contains code covered by: |
|
14
|
|
|
* copyright: 2011 Simple Machines (http://www.simplemachines.org) |
|
15
|
|
|
* license: BSD, See included LICENSE.TXT for terms and conditions. |
|
16
|
|
|
* |
|
17
|
|
|
* @version 1.1 |
|
18
|
|
|
* |
|
19
|
|
|
*/ |
|
20
|
|
|
|
|
21
|
|
|
/** |
|
22
|
|
|
* Removes the passed id_topic's checking for permissions. |
|
23
|
|
|
* |
|
24
|
|
|
* @param int[]|int $topics The topics to remove (can be an id or an array of ids). |
|
25
|
|
|
* @throws Elk_Exception |
|
26
|
|
|
*/ |
|
27
|
|
|
function removeTopicsPermissions($topics) |
|
28
|
|
|
{ |
|
29
|
|
|
global $board, $user_info; |
|
30
|
|
|
|
|
31
|
|
|
// They can only delete their own topics. (we wouldn't be here if they couldn't do that..) |
|
32
|
|
|
$possible_remove = topicAttribute($topics, array('id_topic', 'id_board', 'id_member_started')); |
|
33
|
|
|
|
|
34
|
|
|
$removeCache = array(); |
|
35
|
|
|
$removeCacheBoards = array(); |
|
36
|
|
|
$test_owner = !empty($board) && !allowedTo('remove_any'); |
|
37
|
|
|
foreach ($possible_remove as $row) |
|
38
|
|
|
{ |
|
39
|
|
|
// Skip if we have to test the owner *and* the user is not the owner |
|
40
|
|
|
if ($test_owner && $row['id_member_started'] != $user_info['id']) |
|
41
|
|
|
continue; |
|
42
|
|
|
|
|
43
|
|
|
$removeCache[] = $row['id_topic']; |
|
44
|
|
|
$removeCacheBoards[$row['id_topic']] = $row['id_board']; |
|
45
|
|
|
} |
|
46
|
|
|
|
|
47
|
|
|
// Maybe *none* were their own topics. |
|
48
|
|
|
if (!empty($removeCache)) |
|
49
|
|
|
removeTopics($removeCache, true, false, true, $removeCacheBoards); |
|
50
|
|
|
} |
|
51
|
|
|
|
|
52
|
|
|
/** |
|
53
|
|
|
* Removes the passed id_topic's. |
|
54
|
|
|
* |
|
55
|
|
|
* - Permissions are NOT checked here because the function is used in a scheduled task |
|
56
|
|
|
* |
|
57
|
|
|
* @param int[]|int $topics The topics to remove (can be an id or an array of ids). |
|
58
|
|
|
* @param bool $decreasePostCount if true users' post count will be reduced |
|
59
|
|
|
* @param bool $ignoreRecycling if true topics are not moved to the recycle board (if it exists). |
|
60
|
|
|
* @param bool $log if true logs the action. |
|
61
|
|
|
* @param int[] $removeCacheBoards an array matching topics and boards. |
|
62
|
|
|
* @throws Elk_Exception |
|
63
|
|
|
*/ |
|
64
|
|
|
function removeTopics($topics, $decreasePostCount = true, $ignoreRecycling = false, $log = false, $removeCacheBoards = array()) |
|
65
|
|
|
{ |
|
66
|
36 |
|
global $modSettings; |
|
67
|
|
|
|
|
68
|
|
|
// Nothing to do? |
|
69
|
36 |
|
if (empty($topics)) |
|
70
|
24 |
|
return; |
|
71
|
|
|
|
|
72
|
36 |
|
$db = database(); |
|
73
|
36 |
|
$cache = Cache::instance(); |
|
74
|
|
|
|
|
75
|
|
|
// Only a single topic. |
|
76
|
36 |
|
if (!is_array($topics)) |
|
77
|
36 |
|
$topics = array($topics); |
|
78
|
|
|
|
|
79
|
12 |
|
if ($log) |
|
80
|
24 |
|
{ |
|
81
|
|
|
// Gotta send the notifications *first*! |
|
82
|
|
|
foreach ($topics as $topic) |
|
83
|
|
|
{ |
|
84
|
|
|
// Only log the topic ID if it's not in the recycle board. |
|
85
|
|
|
logAction('remove', array((empty($modSettings['recycle_enable']) || $modSettings['recycle_board'] != $removeCacheBoards[$topic] ? 'topic' : 'old_topic_id') => $topic, 'board' => $removeCacheBoards[$topic])); |
|
86
|
|
|
sendNotifications($topic, 'remove'); |
|
87
|
|
|
} |
|
88
|
|
|
} |
|
89
|
|
|
|
|
90
|
|
|
// Decrease the post counts for members. |
|
91
|
12 |
|
if ($decreasePostCount) |
|
92
|
24 |
|
{ |
|
93
|
36 |
|
$requestMembers = $db->query('', ' |
|
94
|
|
|
SELECT m.id_member, COUNT(*) AS posts |
|
95
|
|
|
FROM {db_prefix}messages AS m |
|
96
|
|
|
INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board) |
|
97
|
|
|
WHERE m.id_topic IN ({array_int:topics}) |
|
98
|
|
|
AND m.icon != {string:recycled} |
|
99
|
|
|
AND b.count_posts = {int:do_count_posts} |
|
100
|
|
|
AND m.approved = {int:is_approved} |
|
101
|
24 |
|
GROUP BY m.id_member', |
|
102
|
|
|
array( |
|
103
|
36 |
|
'do_count_posts' => 0, |
|
104
|
36 |
|
'recycled' => 'recycled', |
|
105
|
36 |
|
'topics' => $topics, |
|
106
|
36 |
|
'is_approved' => 1, |
|
107
|
|
|
) |
|
108
|
24 |
|
); |
|
109
|
36 |
|
if ($db->num_rows($requestMembers) > 0) |
|
110
|
24 |
|
{ |
|
111
|
36 |
|
require_once(SUBSDIR . '/Members.subs.php'); |
|
112
|
36 |
|
while ($rowMembers = $db->fetch_assoc($requestMembers)) |
|
113
|
36 |
|
updateMemberData($rowMembers['id_member'], array('posts' => 'posts - ' . $rowMembers['posts'])); |
|
114
|
24 |
|
} |
|
115
|
36 |
|
$db->free_result($requestMembers); |
|
116
|
24 |
|
} |
|
117
|
|
|
|
|
118
|
|
|
// Recycle topics that aren't in the recycle board... |
|
119
|
36 |
|
if (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 && !$ignoreRecycling) |
|
120
|
24 |
|
{ |
|
121
|
|
|
$possible_recycle = topicAttribute($topics, array('id_topic', 'id_board', 'unapproved_posts', 'approved')); |
|
122
|
|
|
|
|
123
|
|
|
if (!empty($possible_recycle)) |
|
124
|
|
|
{ |
|
125
|
|
|
detectServer()->setTimeLimit(300); |
|
126
|
|
|
|
|
127
|
|
|
// Get topics that will be recycled. |
|
128
|
|
|
$recycleTopics = array(); |
|
129
|
|
|
foreach ($possible_recycle as $row) |
|
130
|
|
|
{ |
|
131
|
|
|
// If it's already in the recycle board do nothing |
|
132
|
|
|
if ($row['id_board'] == $modSettings['recycle_board']) |
|
133
|
|
|
continue; |
|
134
|
|
|
|
|
135
|
|
|
$recycleTopics[] = $row['id_topic']; |
|
136
|
|
|
|
|
137
|
|
|
// Set the id_previous_board for this topic - and make it not sticky. |
|
138
|
|
|
setTopicAttribute($row['id_topic'], array( |
|
139
|
|
|
'id_previous_board' => $row['id_board'], |
|
140
|
|
|
'is_sticky' => 0, |
|
141
|
|
|
)); |
|
142
|
|
|
} |
|
143
|
|
|
|
|
144
|
|
|
if (!empty($recycleTopics)) |
|
145
|
|
|
{ |
|
146
|
|
|
// Mark recycled topics as recycled. |
|
147
|
|
|
$db->query('', ' |
|
148
|
|
|
UPDATE {db_prefix}messages |
|
149
|
|
|
SET icon = {string:recycled} |
|
150
|
|
|
WHERE id_topic IN ({array_int:recycle_topics})', |
|
151
|
|
|
array( |
|
152
|
|
|
'recycle_topics' => $recycleTopics, |
|
153
|
|
|
'recycled' => 'recycled', |
|
154
|
|
|
) |
|
155
|
|
|
); |
|
156
|
|
|
|
|
157
|
|
|
// Move the topics to the recycle board. |
|
158
|
|
|
require_once(SUBSDIR . '/Topic.subs.php'); |
|
159
|
|
|
moveTopics($recycleTopics, $modSettings['recycle_board']); |
|
160
|
|
|
|
|
161
|
|
|
// Close reports that are being recycled. |
|
162
|
|
|
require_once(SUBSDIR . '/Moderation.subs.php'); |
|
163
|
|
|
|
|
164
|
|
|
$db->query('', ' |
|
165
|
|
|
UPDATE {db_prefix}log_reported |
|
166
|
|
|
SET closed = {int:is_closed} |
|
167
|
|
|
WHERE id_topic IN ({array_int:recycle_topics})', |
|
168
|
|
|
array( |
|
169
|
|
|
'recycle_topics' => $recycleTopics, |
|
170
|
|
|
'is_closed' => 1, |
|
171
|
|
|
) |
|
172
|
|
|
); |
|
173
|
|
|
|
|
174
|
|
|
updateSettings(array('last_mod_report_action' => time())); |
|
175
|
|
|
recountOpenReports(); |
|
176
|
|
|
|
|
177
|
|
|
// Topics that were recycled don't need to be deleted, so subtract them. |
|
178
|
|
|
$topics = array_diff($topics, $recycleTopics); |
|
179
|
|
|
} |
|
180
|
|
|
} |
|
181
|
|
|
} |
|
182
|
|
|
|
|
183
|
|
|
// Still topics left to delete? |
|
184
|
36 |
|
if (empty($topics)) |
|
185
|
24 |
|
return; |
|
186
|
|
|
|
|
187
|
36 |
|
$adjustBoards = array(); |
|
188
|
|
|
|
|
189
|
|
|
// Find out how many posts we are deleting. |
|
190
|
36 |
|
$request = $db->query('', ' |
|
191
|
|
|
SELECT id_board, approved, COUNT(*) AS num_topics, SUM(unapproved_posts) AS unapproved_posts, |
|
192
|
|
|
SUM(num_replies) AS num_replies |
|
193
|
|
|
FROM {db_prefix}topics |
|
194
|
|
|
WHERE id_topic IN ({array_int:topics}) |
|
195
|
24 |
|
GROUP BY id_board, approved', |
|
196
|
|
|
array( |
|
197
|
36 |
|
'topics' => $topics, |
|
198
|
|
|
) |
|
199
|
24 |
|
); |
|
200
|
36 |
View Code Duplication |
while ($row = $db->fetch_assoc($request)) |
|
201
|
|
|
{ |
|
202
|
36 |
|
if (!isset($adjustBoards[$row['id_board']]['num_posts'])) |
|
203
|
24 |
|
{ |
|
204
|
36 |
|
$cache->remove('board-' . $row['id_board']); |
|
205
|
|
|
|
|
206
|
36 |
|
$adjustBoards[$row['id_board']] = array( |
|
207
|
36 |
|
'num_posts' => 0, |
|
208
|
36 |
|
'num_topics' => 0, |
|
209
|
36 |
|
'unapproved_posts' => 0, |
|
210
|
36 |
|
'unapproved_topics' => 0, |
|
211
|
36 |
|
'id_board' => $row['id_board'] |
|
212
|
24 |
|
); |
|
213
|
24 |
|
} |
|
214
|
|
|
// Posts = (num_replies + 1) for each approved topic. |
|
215
|
36 |
|
$adjustBoards[$row['id_board']]['num_posts'] += $row['num_replies'] + ($row['approved'] ? $row['num_topics'] : 0); |
|
216
|
36 |
|
$adjustBoards[$row['id_board']]['unapproved_posts'] += $row['unapproved_posts']; |
|
217
|
|
|
|
|
218
|
|
|
// Add the topics to the right type. |
|
219
|
36 |
|
if ($row['approved']) |
|
220
|
36 |
|
$adjustBoards[$row['id_board']]['num_topics'] += $row['num_topics']; |
|
221
|
|
|
else |
|
222
|
|
|
$adjustBoards[$row['id_board']]['unapproved_topics'] += $row['num_topics']; |
|
223
|
24 |
|
} |
|
224
|
36 |
|
$db->free_result($request); |
|
225
|
|
|
|
|
226
|
|
|
// Decrease number of posts and topics for each board. |
|
227
|
36 |
|
detectServer()->setTimeLimit(300); |
|
228
|
36 |
View Code Duplication |
foreach ($adjustBoards as $stats) |
|
229
|
|
|
{ |
|
230
|
36 |
|
$db->query('', ' |
|
231
|
|
|
UPDATE {db_prefix}boards |
|
232
|
|
|
SET |
|
233
|
|
|
num_posts = CASE WHEN {int:num_posts} > num_posts THEN 0 ELSE num_posts - {int:num_posts} END, |
|
234
|
|
|
num_topics = CASE WHEN {int:num_topics} > num_topics THEN 0 ELSE num_topics - {int:num_topics} END, |
|
235
|
|
|
unapproved_posts = CASE WHEN {int:unapproved_posts} > unapproved_posts THEN 0 ELSE unapproved_posts - {int:unapproved_posts} END, |
|
236
|
|
|
unapproved_topics = CASE WHEN {int:unapproved_topics} > unapproved_topics THEN 0 ELSE unapproved_topics - {int:unapproved_topics} END |
|
237
|
24 |
|
WHERE id_board = {int:id_board}', |
|
238
|
|
|
array( |
|
239
|
36 |
|
'id_board' => $stats['id_board'], |
|
240
|
36 |
|
'num_posts' => $stats['num_posts'], |
|
241
|
36 |
|
'num_topics' => $stats['num_topics'], |
|
242
|
36 |
|
'unapproved_posts' => $stats['unapproved_posts'], |
|
243
|
36 |
|
'unapproved_topics' => $stats['unapproved_topics'], |
|
244
|
|
|
) |
|
245
|
24 |
|
); |
|
246
|
24 |
|
} |
|
247
|
|
|
|
|
248
|
|
|
// Remove polls for these topics. |
|
249
|
36 |
|
$possible_polls = topicAttribute($topics, 'id_poll'); |
|
250
|
36 |
|
$polls = array(); |
|
251
|
36 |
|
foreach ($possible_polls as $row) |
|
252
|
|
|
{ |
|
253
|
36 |
|
if (!empty($row['id_poll'])) |
|
254
|
36 |
|
$polls[] = $row['id_poll']; |
|
255
|
24 |
|
} |
|
256
|
|
|
|
|
257
|
36 |
|
if (!empty($polls)) |
|
258
|
24 |
|
{ |
|
259
|
18 |
|
$db->query('', ' |
|
260
|
|
|
DELETE FROM {db_prefix}polls |
|
261
|
12 |
|
WHERE id_poll IN ({array_int:polls})', |
|
262
|
|
|
array( |
|
263
|
18 |
|
'polls' => $polls, |
|
264
|
|
|
) |
|
265
|
12 |
|
); |
|
266
|
18 |
|
$db->query('', ' |
|
267
|
|
|
DELETE FROM {db_prefix}poll_choices |
|
268
|
12 |
|
WHERE id_poll IN ({array_int:polls})', |
|
269
|
|
|
array( |
|
270
|
18 |
|
'polls' => $polls, |
|
271
|
|
|
) |
|
272
|
12 |
|
); |
|
273
|
18 |
|
$db->query('', ' |
|
274
|
|
|
DELETE FROM {db_prefix}log_polls |
|
275
|
12 |
|
WHERE id_poll IN ({array_int:polls})', |
|
276
|
|
|
array( |
|
277
|
18 |
|
'polls' => $polls, |
|
278
|
|
|
) |
|
279
|
12 |
|
); |
|
280
|
12 |
|
} |
|
281
|
|
|
|
|
282
|
|
|
// Get rid of the attachment(s). |
|
283
|
36 |
|
require_once(SUBSDIR . '/ManageAttachments.subs.php'); |
|
284
|
|
|
$attachmentQuery = array( |
|
285
|
36 |
|
'attachment_type' => 0, |
|
286
|
36 |
|
'id_topic' => $topics, |
|
287
|
24 |
|
); |
|
288
|
36 |
|
removeAttachments($attachmentQuery, 'messages'); |
|
289
|
|
|
|
|
290
|
|
|
// Delete search index entries. |
|
291
|
36 |
|
if (!empty($modSettings['search_custom_index_config'])) |
|
292
|
24 |
|
{ |
|
293
|
|
|
$customIndexSettings = Util::unserialize($modSettings['search_custom_index_config']); |
|
294
|
|
|
|
|
295
|
|
|
$request = $db->query('', ' |
|
296
|
|
|
SELECT id_msg, body |
|
297
|
|
|
FROM {db_prefix}messages |
|
298
|
|
|
WHERE id_topic IN ({array_int:topics})', |
|
299
|
|
|
array( |
|
300
|
|
|
'topics' => $topics, |
|
301
|
|
|
) |
|
302
|
|
|
); |
|
303
|
|
|
$words = array(); |
|
304
|
|
|
$messages = array(); |
|
305
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
306
|
|
|
{ |
|
307
|
|
|
detectServer()->setTimeLimit(300); |
|
308
|
|
|
|
|
309
|
|
|
$words = array_merge($words, text2words($row['body'], $customIndexSettings['bytes_per_word'], true)); |
|
310
|
|
|
$messages[] = $row['id_msg']; |
|
311
|
|
|
} |
|
312
|
|
|
$db->free_result($request); |
|
313
|
|
|
$words = array_unique($words); |
|
314
|
|
|
|
|
315
|
|
|
if (!empty($words) && !empty($messages)) |
|
316
|
|
|
$db->query('', ' |
|
317
|
|
|
DELETE FROM {db_prefix}log_search_words |
|
318
|
|
|
WHERE id_word IN ({array_int:word_list}) |
|
319
|
|
|
AND id_msg IN ({array_int:message_list})', |
|
320
|
|
|
array( |
|
321
|
|
|
'word_list' => $words, |
|
322
|
|
|
'message_list' => $messages, |
|
323
|
|
|
) |
|
324
|
|
|
); |
|
325
|
|
|
} |
|
326
|
|
|
|
|
327
|
|
|
// Reuse the message array if available |
|
328
|
36 |
|
if (empty($messages)) |
|
329
|
36 |
|
$messages = messagesInTopics($topics); |
|
330
|
|
|
|
|
331
|
|
|
// If there are messages left in this topic |
|
332
|
36 |
|
if (!empty($messages)) |
|
333
|
24 |
|
{ |
|
334
|
|
|
// Decrease / Update the member like counts |
|
335
|
36 |
|
require_once(SUBSDIR . '/Likes.subs.php'); |
|
336
|
36 |
|
decreaseLikeCounts($messages); |
|
337
|
|
|
|
|
338
|
|
|
// Remove all likes now that the topic is gone |
|
339
|
36 |
|
$db->query('', ' |
|
340
|
|
|
DELETE FROM {db_prefix}message_likes |
|
341
|
24 |
|
WHERE id_msg IN ({array_int:messages})', |
|
342
|
|
|
array( |
|
343
|
36 |
|
'messages' => $messages, |
|
344
|
|
|
) |
|
345
|
24 |
|
); |
|
346
|
|
|
|
|
347
|
|
|
// Remove all mentions now that the topic is gone |
|
348
|
36 |
|
$db->query('', ' |
|
349
|
|
|
DELETE FROM {db_prefix}log_mentions |
|
350
|
|
|
WHERE id_target IN ({array_int:messages}) |
|
351
|
24 |
|
AND mention_type IN ({array_string:mension_types})', |
|
352
|
|
|
array( |
|
353
|
36 |
|
'messages' => $messages, |
|
354
|
24 |
|
'mension_types' => array('mentionmem', 'likemsg', 'rlikemsg'), |
|
355
|
|
|
) |
|
356
|
24 |
|
); |
|
357
|
24 |
|
} |
|
358
|
|
|
|
|
359
|
|
|
// Delete messages in each topic. |
|
360
|
36 |
|
$db->query('', ' |
|
361
|
|
|
DELETE FROM {db_prefix}messages |
|
362
|
24 |
|
WHERE id_topic IN ({array_int:topics})', |
|
363
|
|
|
array( |
|
364
|
36 |
|
'topics' => $topics, |
|
365
|
|
|
) |
|
366
|
24 |
|
); |
|
367
|
|
|
|
|
368
|
|
|
// Remove linked calendar events. |
|
369
|
|
|
// @todo if unlinked events are enabled, wouldn't this be expected to keep them? |
|
370
|
36 |
|
$db->query('', ' |
|
371
|
|
|
DELETE FROM {db_prefix}calendar |
|
372
|
24 |
|
WHERE id_topic IN ({array_int:topics})', |
|
373
|
|
|
array( |
|
374
|
36 |
|
'topics' => $topics, |
|
375
|
|
|
) |
|
376
|
24 |
|
); |
|
377
|
|
|
|
|
378
|
|
|
// Delete log_topics data |
|
379
|
36 |
|
$db->query('', ' |
|
380
|
|
|
DELETE FROM {db_prefix}log_topics |
|
381
|
24 |
|
WHERE id_topic IN ({array_int:topics})', |
|
382
|
|
|
array( |
|
383
|
36 |
|
'topics' => $topics, |
|
384
|
|
|
) |
|
385
|
24 |
|
); |
|
386
|
|
|
|
|
387
|
|
|
// Delete notifications |
|
388
|
36 |
|
$db->query('', ' |
|
389
|
|
|
DELETE FROM {db_prefix}log_notify |
|
390
|
24 |
|
WHERE id_topic IN ({array_int:topics})', |
|
391
|
|
|
array( |
|
392
|
36 |
|
'topics' => $topics, |
|
393
|
|
|
) |
|
394
|
24 |
|
); |
|
395
|
|
|
|
|
396
|
|
|
// Delete the topics themselves |
|
397
|
36 |
|
$db->query('', ' |
|
398
|
|
|
DELETE FROM {db_prefix}topics |
|
399
|
24 |
|
WHERE id_topic IN ({array_int:topics})', |
|
400
|
|
|
array( |
|
401
|
36 |
|
'topics' => $topics, |
|
402
|
|
|
) |
|
403
|
24 |
|
); |
|
404
|
|
|
|
|
405
|
|
|
// Remove data from the subjects for search cache |
|
406
|
36 |
|
$db->query('', ' |
|
407
|
|
|
DELETE FROM {db_prefix}log_search_subjects |
|
408
|
24 |
|
WHERE id_topic IN ({array_int:topics})', |
|
409
|
|
|
array( |
|
410
|
36 |
|
'topics' => $topics, |
|
411
|
|
|
) |
|
412
|
24 |
|
); |
|
413
|
36 |
|
require_once(SUBSDIR . '/FollowUps.subs.php'); |
|
414
|
36 |
|
removeFollowUpsByTopic($topics); |
|
415
|
|
|
|
|
416
|
36 |
|
foreach ($topics as $topic_id) |
|
417
|
36 |
|
$cache->remove('topic_board-' . $topic_id); |
|
418
|
|
|
|
|
419
|
|
|
// Maybe there's an addon that wants to delete topic related data of its own |
|
420
|
36 |
|
call_integration_hook('integrate_remove_topics', array($topics)); |
|
421
|
|
|
|
|
422
|
|
|
// Update the totals... |
|
423
|
36 |
|
require_once(SUBSDIR . '/Messages.subs.php'); |
|
424
|
36 |
|
updateMessageStats(); |
|
425
|
36 |
|
updateTopicStats(); |
|
426
|
36 |
|
updateSettings(array( |
|
427
|
36 |
|
'calendar_updated' => time(), |
|
428
|
24 |
|
)); |
|
429
|
|
|
|
|
430
|
36 |
|
require_once(SUBSDIR . '/Post.subs.php'); |
|
431
|
36 |
|
$updates = array(); |
|
432
|
36 |
|
foreach ($adjustBoards as $stats) |
|
433
|
36 |
|
$updates[] = $stats['id_board']; |
|
434
|
36 |
|
updateLastMessages($updates); |
|
435
|
36 |
|
} |
|
436
|
|
|
|
|
437
|
|
|
/** |
|
438
|
|
|
* Moves lots of topics to a specific board and checks if the user can move them |
|
439
|
|
|
* |
|
440
|
|
|
* @param array $moveCache [0] => int[] is the topic, [1] => int[] is the board to move to. |
|
441
|
|
|
* @throws Elk_Exception |
|
442
|
|
|
*/ |
|
443
|
|
|
function moveTopicsPermissions($moveCache) |
|
444
|
|
|
{ |
|
445
|
|
|
global $board, $user_info; |
|
446
|
|
|
|
|
447
|
|
|
$db = database(); |
|
448
|
|
|
|
|
449
|
|
|
// I know - I just KNOW you're trying to beat the system. Too bad for you... we CHECK :P. |
|
450
|
|
|
$request = $db->query('', ' |
|
451
|
|
|
SELECT t.id_topic, t.id_board, b.count_posts |
|
452
|
|
|
FROM {db_prefix}topics AS t |
|
453
|
|
|
LEFT JOIN {db_prefix}boards AS b ON (t.id_board = b.id_board) |
|
454
|
|
|
WHERE t.id_topic IN ({array_int:move_topic_ids})' . (!empty($board) && !allowedTo('move_any') ? ' |
|
455
|
|
|
AND t.id_member_started = {int:current_member}' : '') . ' |
|
456
|
|
|
LIMIT ' . count($moveCache[0]), |
|
457
|
|
|
array( |
|
458
|
|
|
'current_member' => $user_info['id'], |
|
459
|
|
|
'move_topic_ids' => $moveCache[0], |
|
460
|
|
|
) |
|
461
|
|
|
); |
|
462
|
|
|
$moveTos = array(); |
|
463
|
|
|
$moveCache2 = array(); |
|
464
|
|
|
$countPosts = array(); |
|
465
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
466
|
|
|
{ |
|
467
|
|
|
$to = $moveCache[1][$row['id_topic']]; |
|
468
|
|
|
|
|
469
|
|
|
if (empty($to)) |
|
470
|
|
|
continue; |
|
471
|
|
|
|
|
472
|
|
|
// Does this topic's board count the posts or not? |
|
473
|
|
|
$countPosts[$row['id_topic']] = empty($row['count_posts']); |
|
474
|
|
|
|
|
475
|
|
|
if (!isset($moveTos[$to])) |
|
476
|
|
|
$moveTos[$to] = array(); |
|
477
|
|
|
|
|
478
|
|
|
$moveTos[$to][] = $row['id_topic']; |
|
479
|
|
|
|
|
480
|
|
|
// For reporting... |
|
481
|
|
|
$moveCache2[] = array($row['id_topic'], $row['id_board'], $to); |
|
482
|
|
|
} |
|
483
|
|
|
$db->free_result($request); |
|
484
|
|
|
|
|
485
|
|
|
// Do the actual moves... |
|
486
|
|
|
foreach ($moveTos as $to => $topics) |
|
487
|
|
|
moveTopics($topics, $to, true); |
|
488
|
|
|
|
|
489
|
|
|
// Does the post counts need to be updated? |
|
490
|
|
|
if (!empty($moveTos)) |
|
491
|
|
|
{ |
|
492
|
|
|
require_once(SUBSDIR . '/Boards.subs.php'); |
|
493
|
|
|
$topicRecounts = array(); |
|
494
|
|
|
$boards_info = fetchBoardsInfo(array('boards' => array_keys($moveTos)), array('selects' => 'posts')); |
|
495
|
|
|
|
|
496
|
|
|
foreach ($boards_info as $row) |
|
497
|
|
|
{ |
|
498
|
|
|
$cp = empty($row['count_posts']); |
|
499
|
|
|
|
|
500
|
|
|
// Go through all the topics that are being moved to this board. |
|
501
|
|
|
foreach ($moveTos[$row['id_board']] as $topic) |
|
502
|
|
|
{ |
|
503
|
|
|
// If both boards have the same value for post counting then no adjustment needs to be made. |
|
504
|
|
|
if ($countPosts[$topic] != $cp) |
|
505
|
|
|
{ |
|
506
|
|
|
// If the board being moved to does count the posts then the other one doesn't so add to their post count. |
|
507
|
|
|
$topicRecounts[$topic] = $cp ? 1 : -1; |
|
508
|
|
|
} |
|
509
|
|
|
} |
|
510
|
|
|
} |
|
511
|
|
|
|
|
512
|
|
|
if (!empty($topicRecounts)) |
|
513
|
|
|
{ |
|
514
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
|
515
|
|
|
|
|
516
|
|
|
// Get all the members who have posted in the moved topics. |
|
517
|
|
|
$posters = topicsPosters(array_keys($topicRecounts)); |
|
518
|
|
|
foreach ($posters as $id_member => $topics) |
|
519
|
|
|
{ |
|
520
|
|
|
$post_adj = 0; |
|
521
|
|
|
foreach ($topics as $id_topic) |
|
522
|
|
|
$post_adj += $topicRecounts[$id_topic]; |
|
523
|
|
|
|
|
524
|
|
|
// And now update that member's post counts |
|
525
|
|
|
if (!empty($post_adj)) |
|
526
|
|
|
{ |
|
527
|
|
|
updateMemberData($id_member, array('posts' => 'posts + ' . $post_adj)); |
|
528
|
|
|
} |
|
529
|
|
|
} |
|
530
|
|
|
} |
|
531
|
|
|
} |
|
532
|
|
|
} |
|
533
|
|
|
|
|
534
|
|
|
/** |
|
535
|
|
|
* Moves one or more topics to a specific board. |
|
536
|
|
|
* |
|
537
|
|
|
* What it does: |
|
538
|
|
|
* |
|
539
|
|
|
* - Determines the source boards for the supplied topics |
|
540
|
|
|
* - Handles the moving of mark_read data |
|
541
|
|
|
* - Updates the posts count of the affected boards |
|
542
|
|
|
* - This function doesn't check permissions. |
|
543
|
|
|
* |
|
544
|
|
|
* @param int[]|int $topics |
|
545
|
|
|
* @param int $toBoard |
|
546
|
|
|
* @param bool $log if true logs the action. |
|
547
|
|
|
* @throws Elk_Exception |
|
548
|
|
|
*/ |
|
549
|
|
|
function moveTopics($topics, $toBoard, $log = false) |
|
550
|
|
|
{ |
|
551
|
|
|
global $user_info, $modSettings; |
|
552
|
|
|
|
|
553
|
|
|
// No topics or no board? |
|
554
|
|
|
if (empty($topics) || empty($toBoard)) |
|
555
|
|
|
return; |
|
556
|
|
|
|
|
557
|
|
|
$db = database(); |
|
558
|
|
|
|
|
559
|
|
|
// Only a single topic. |
|
560
|
|
|
if (!is_array($topics)) |
|
561
|
|
|
$topics = array($topics); |
|
562
|
|
|
|
|
563
|
|
|
$fromBoards = array(); |
|
564
|
|
|
$fromCacheBoards = array(); |
|
565
|
|
|
|
|
566
|
|
|
// Are we moving to the recycle board? |
|
567
|
|
|
$isRecycleDest = !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $toBoard; |
|
568
|
|
|
|
|
569
|
|
|
// Determine the source boards... |
|
570
|
|
|
$request = $db->query('', ' |
|
571
|
|
|
SELECT id_topic, id_board, approved, COUNT(*) AS num_topics, SUM(unapproved_posts) AS unapproved_posts, |
|
572
|
|
|
SUM(num_replies) AS num_replies |
|
573
|
|
|
FROM {db_prefix}topics |
|
574
|
|
|
WHERE id_topic IN ({array_int:topics}) |
|
575
|
|
|
GROUP BY id_board, approved', |
|
576
|
|
|
array( |
|
577
|
|
|
'topics' => $topics, |
|
578
|
|
|
) |
|
579
|
|
|
); |
|
580
|
|
|
// Num of rows = 0 -> no topics found. Num of rows > 1 -> topics are on multiple boards. |
|
581
|
|
|
if ($db->num_rows($request) == 0) |
|
582
|
|
|
return; |
|
583
|
|
|
|
|
584
|
|
View Code Duplication |
while ($row = $db->fetch_assoc($request)) |
|
585
|
|
|
{ |
|
586
|
|
|
$fromCacheBoards[$row['id_topic']] = $row['id_board']; |
|
587
|
|
|
if (!isset($fromBoards[$row['id_board']]['num_posts'])) |
|
588
|
|
|
{ |
|
589
|
|
|
$fromBoards[$row['id_board']] = array( |
|
590
|
|
|
'num_posts' => 0, |
|
591
|
|
|
'num_topics' => 0, |
|
592
|
|
|
'unapproved_posts' => 0, |
|
593
|
|
|
'unapproved_topics' => 0, |
|
594
|
|
|
'id_board' => $row['id_board'] |
|
595
|
|
|
); |
|
596
|
|
|
} |
|
597
|
|
|
// Posts = (num_replies + 1) for each approved topic. |
|
598
|
|
|
$fromBoards[$row['id_board']]['num_posts'] += $row['num_replies'] + ($row['approved'] ? $row['num_topics'] : 0); |
|
599
|
|
|
$fromBoards[$row['id_board']]['unapproved_posts'] += $row['unapproved_posts']; |
|
600
|
|
|
|
|
601
|
|
|
// Add the topics to the right type. |
|
602
|
|
|
if ($row['approved']) |
|
603
|
|
|
$fromBoards[$row['id_board']]['num_topics'] += $row['num_topics']; |
|
604
|
|
|
else |
|
605
|
|
|
$fromBoards[$row['id_board']]['unapproved_topics'] += $row['num_topics']; |
|
606
|
|
|
} |
|
607
|
|
|
$db->free_result($request); |
|
608
|
|
|
|
|
609
|
|
|
// Move over the mark_read data. (because it may be read and now not by some!) |
|
610
|
|
|
$SaveAServer = max(0, $modSettings['maxMsgID'] - 50000); |
|
611
|
|
|
$request = $db->query('', ' |
|
612
|
|
|
SELECT lmr.id_member, lmr.id_msg, t.id_topic, COALESCE(lt.unwatched, 0) as unwatched |
|
613
|
|
|
FROM {db_prefix}topics AS t |
|
614
|
|
|
INNER JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board |
|
615
|
|
|
AND lmr.id_msg > t.id_first_msg AND lmr.id_msg > {int:protect_lmr_msg}) |
|
616
|
|
|
LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = lmr.id_member) |
|
617
|
|
|
WHERE t.id_topic IN ({array_int:topics}) |
|
618
|
|
|
AND lmr.id_msg > COALESCE(lt.id_msg, 0)', |
|
619
|
|
|
array( |
|
620
|
|
|
'protect_lmr_msg' => $SaveAServer, |
|
621
|
|
|
'topics' => $topics, |
|
622
|
|
|
) |
|
623
|
|
|
); |
|
624
|
|
|
$log_topics = array(); |
|
625
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
626
|
|
|
{ |
|
627
|
|
|
$log_topics[] = array($row['id_member'], $row['id_topic'], $row['id_msg'], $row['unwatched']); |
|
628
|
|
|
|
|
629
|
|
|
// Prevent queries from getting too big. Taking some steam off. |
|
630
|
|
|
if (count($log_topics) > 500) |
|
631
|
|
|
{ |
|
632
|
|
|
markTopicsRead($log_topics, true); |
|
633
|
|
|
$log_topics = array(); |
|
634
|
|
|
} |
|
635
|
|
|
} |
|
636
|
|
|
$db->free_result($request); |
|
637
|
|
|
|
|
638
|
|
|
// Now that we have all the topics that *should* be marked read, and by which members... |
|
639
|
|
|
if (!empty($log_topics)) |
|
640
|
|
|
{ |
|
641
|
|
|
// Insert that information into the database! |
|
642
|
|
|
markTopicsRead($log_topics, true); |
|
643
|
|
|
} |
|
644
|
|
|
|
|
645
|
|
|
// Update the number of posts on each board. |
|
646
|
|
|
$totalTopics = 0; |
|
647
|
|
|
$totalPosts = 0; |
|
648
|
|
|
$totalUnapprovedTopics = 0; |
|
649
|
|
|
$totalUnapprovedPosts = 0; |
|
650
|
|
|
foreach ($fromBoards as $stats) |
|
651
|
|
|
{ |
|
652
|
|
|
$db->query('', ' |
|
653
|
|
|
UPDATE {db_prefix}boards |
|
654
|
|
|
SET |
|
655
|
|
|
num_posts = CASE WHEN {int:num_posts} > num_posts THEN 0 ELSE num_posts - {int:num_posts} END, |
|
656
|
|
|
num_topics = CASE WHEN {int:num_topics} > num_topics THEN 0 ELSE num_topics - {int:num_topics} END, |
|
657
|
|
|
unapproved_posts = CASE WHEN {int:unapproved_posts} > unapproved_posts THEN 0 ELSE unapproved_posts - {int:unapproved_posts} END, |
|
658
|
|
|
unapproved_topics = CASE WHEN {int:unapproved_topics} > unapproved_topics THEN 0 ELSE unapproved_topics - {int:unapproved_topics} END |
|
659
|
|
|
WHERE id_board = {int:id_board}', |
|
660
|
|
|
array( |
|
661
|
|
|
'id_board' => $stats['id_board'], |
|
662
|
|
|
'num_posts' => $stats['num_posts'], |
|
663
|
|
|
'num_topics' => $stats['num_topics'], |
|
664
|
|
|
'unapproved_posts' => $stats['unapproved_posts'], |
|
665
|
|
|
'unapproved_topics' => $stats['unapproved_topics'], |
|
666
|
|
|
) |
|
667
|
|
|
); |
|
668
|
|
|
$totalTopics += $stats['num_topics']; |
|
669
|
|
|
$totalPosts += $stats['num_posts']; |
|
670
|
|
|
$totalUnapprovedTopics += $stats['unapproved_topics']; |
|
671
|
|
|
$totalUnapprovedPosts += $stats['unapproved_posts']; |
|
672
|
|
|
} |
|
673
|
|
|
$db->query('', ' |
|
674
|
|
|
UPDATE {db_prefix}boards |
|
675
|
|
|
SET |
|
676
|
|
|
num_topics = num_topics + {int:total_topics}, |
|
677
|
|
|
num_posts = num_posts + {int:total_posts},' . ($isRecycleDest ? ' |
|
678
|
|
|
unapproved_posts = {int:no_unapproved}, unapproved_topics = {int:no_unapproved}' : ' |
|
679
|
|
|
unapproved_posts = unapproved_posts + {int:total_unapproved_posts}, |
|
680
|
|
|
unapproved_topics = unapproved_topics + {int:total_unapproved_topics}') . ' |
|
681
|
|
|
WHERE id_board = {int:id_board}', |
|
682
|
|
|
array( |
|
683
|
|
|
'id_board' => $toBoard, |
|
684
|
|
|
'total_topics' => $totalTopics, |
|
685
|
|
|
'total_posts' => $totalPosts, |
|
686
|
|
|
'total_unapproved_topics' => $totalUnapprovedTopics, |
|
687
|
|
|
'total_unapproved_posts' => $totalUnapprovedPosts, |
|
688
|
|
|
'no_unapproved' => 0, |
|
689
|
|
|
) |
|
690
|
|
|
); |
|
691
|
|
|
|
|
692
|
|
|
if ($isRecycleDest) |
|
693
|
|
|
{ |
|
694
|
|
|
$attributes = array( |
|
695
|
|
|
'id_board' => $toBoard, |
|
696
|
|
|
'approved' => 1, |
|
697
|
|
|
'unapproved_posts' => 0, |
|
698
|
|
|
); |
|
699
|
|
|
} |
|
700
|
|
|
else |
|
701
|
|
|
{ |
|
702
|
|
|
$attributes = array('id_board' => $toBoard); |
|
703
|
|
|
} |
|
704
|
|
|
|
|
705
|
|
|
// Move the topic. Done. :P |
|
706
|
|
|
setTopicAttribute($topics, $attributes); |
|
707
|
|
|
|
|
708
|
|
|
// If this was going to the recycle bin, check what messages are being recycled, and remove them from the queue. |
|
709
|
|
|
if ($isRecycleDest && ($totalUnapprovedTopics || $totalUnapprovedPosts)) |
|
710
|
|
|
{ |
|
711
|
|
|
$request = $db->query('', ' |
|
712
|
|
|
SELECT id_msg |
|
713
|
|
|
FROM {db_prefix}messages |
|
714
|
|
|
WHERE id_topic IN ({array_int:topics}) |
|
715
|
|
|
and approved = {int:not_approved}', |
|
716
|
|
|
array( |
|
717
|
|
|
'topics' => $topics, |
|
718
|
|
|
'not_approved' => 0, |
|
719
|
|
|
) |
|
720
|
|
|
); |
|
721
|
|
|
$approval_msgs = array(); |
|
722
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
723
|
|
|
$approval_msgs[] = $row['id_msg']; |
|
724
|
|
|
$db->free_result($request); |
|
725
|
|
|
|
|
726
|
|
|
// Empty the approval queue for these, as we're going to approve them next. |
|
727
|
|
|
if (!empty($approval_msgs)) |
|
728
|
|
|
$db->query('', ' |
|
729
|
|
|
DELETE FROM {db_prefix}approval_queue |
|
730
|
|
|
WHERE id_msg IN ({array_int:message_list}) |
|
731
|
|
|
AND id_attach = {int:id_attach}', |
|
732
|
|
|
array( |
|
733
|
|
|
'message_list' => $approval_msgs, |
|
734
|
|
|
'id_attach' => 0, |
|
735
|
|
|
) |
|
736
|
|
|
); |
|
737
|
|
|
|
|
738
|
|
|
// Get all the current max and mins. |
|
739
|
|
|
$topicAttribute = topicAttribute($topics, array('id_topic', 'id_first_msg', 'id_last_msg')); |
|
740
|
|
|
$topicMaxMin = array(); |
|
741
|
|
|
foreach ($topicAttribute as $row) |
|
742
|
|
|
{ |
|
743
|
|
|
$topicMaxMin[$row['id_topic']] = array( |
|
744
|
|
|
'min' => $row['id_first_msg'], |
|
745
|
|
|
'max' => $row['id_last_msg'], |
|
746
|
|
|
); |
|
747
|
|
|
} |
|
748
|
|
|
|
|
749
|
|
|
// Check the MAX and MIN are correct. |
|
750
|
|
|
$request = $db->query('', ' |
|
751
|
|
|
SELECT id_topic, MIN(id_msg) AS first_msg, MAX(id_msg) AS last_msg |
|
752
|
|
|
FROM {db_prefix}messages |
|
753
|
|
|
WHERE id_topic IN ({array_int:topics}) |
|
754
|
|
|
GROUP BY id_topic', |
|
755
|
|
|
array( |
|
756
|
|
|
'topics' => $topics, |
|
757
|
|
|
) |
|
758
|
|
|
); |
|
759
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
760
|
|
|
{ |
|
761
|
|
|
// If not, update. |
|
762
|
|
|
if ($row['first_msg'] != $topicMaxMin[$row['id_topic']]['min'] || $row['last_msg'] != $topicMaxMin[$row['id_topic']]['max']) |
|
763
|
|
|
setTopicAttribute($row['id_topic'], array( |
|
764
|
|
|
'id_first_msg' => $row['first_msg'], |
|
765
|
|
|
'id_last_msg' => $row['last_msg'], |
|
766
|
|
|
)); |
|
767
|
|
|
} |
|
768
|
|
|
$db->free_result($request); |
|
769
|
|
|
} |
|
770
|
|
|
|
|
771
|
|
|
$db->query('', ' |
|
772
|
|
|
UPDATE {db_prefix}messages |
|
773
|
|
|
SET id_board = {int:id_board}' . ($isRecycleDest ? ',approved = {int:is_approved}' : '') . ' |
|
774
|
|
|
WHERE id_topic IN ({array_int:topics})', |
|
775
|
|
|
array( |
|
776
|
|
|
'id_board' => $toBoard, |
|
777
|
|
|
'topics' => $topics, |
|
778
|
|
|
'is_approved' => 1, |
|
779
|
|
|
) |
|
780
|
|
|
); |
|
781
|
|
|
$db->query('', ' |
|
782
|
|
|
UPDATE {db_prefix}log_reported |
|
783
|
|
|
SET id_board = {int:id_board} |
|
784
|
|
|
WHERE id_topic IN ({array_int:topics})', |
|
785
|
|
|
array( |
|
786
|
|
|
'id_board' => $toBoard, |
|
787
|
|
|
'topics' => $topics, |
|
788
|
|
|
) |
|
789
|
|
|
); |
|
790
|
|
|
$db->query('', ' |
|
791
|
|
|
UPDATE {db_prefix}calendar |
|
792
|
|
|
SET id_board = {int:id_board} |
|
793
|
|
|
WHERE id_topic IN ({array_int:topics})', |
|
794
|
|
|
array( |
|
795
|
|
|
'id_board' => $toBoard, |
|
796
|
|
|
'topics' => $topics, |
|
797
|
|
|
) |
|
798
|
|
|
); |
|
799
|
|
|
|
|
800
|
|
|
// Mark target board as seen, if it was already marked as seen before. |
|
801
|
|
|
$request = $db->query('', ' |
|
802
|
|
|
SELECT (COALESCE(lb.id_msg, 0) >= b.id_msg_updated) AS isSeen |
|
803
|
|
|
FROM {db_prefix}boards AS b |
|
804
|
|
|
LEFT JOIN {db_prefix}log_boards AS lb ON (lb.id_board = b.id_board AND lb.id_member = {int:current_member}) |
|
805
|
|
|
WHERE b.id_board = {int:id_board}', |
|
806
|
|
|
array( |
|
807
|
|
|
'current_member' => $user_info['id'], |
|
808
|
|
|
'id_board' => $toBoard, |
|
809
|
|
|
) |
|
810
|
|
|
); |
|
811
|
|
|
list ($isSeen) = $db->fetch_row($request); |
|
812
|
|
|
$db->free_result($request); |
|
813
|
|
|
|
|
814
|
|
|
if (!empty($isSeen) && !$user_info['is_guest']) |
|
815
|
|
|
{ |
|
816
|
|
|
require_once(SUBSDIR . '/Boards.subs.php'); |
|
817
|
|
|
markBoardsRead($toBoard); |
|
818
|
|
|
} |
|
819
|
|
|
|
|
820
|
|
|
$cache = Cache::instance(); |
|
821
|
|
|
// Update the cache? |
|
822
|
|
|
foreach ($topics as $topic_id) |
|
823
|
|
|
$cache->remove('topic_board-' . $topic_id); |
|
824
|
|
|
|
|
825
|
|
|
require_once(SUBSDIR . '/Post.subs.php'); |
|
826
|
|
|
|
|
827
|
|
|
$updates = array_keys($fromBoards); |
|
828
|
|
|
$updates[] = $toBoard; |
|
829
|
|
|
|
|
830
|
|
|
updateLastMessages(array_unique($updates)); |
|
831
|
|
|
|
|
832
|
|
|
// Update 'em pesky stats. |
|
833
|
|
|
updateTopicStats(); |
|
834
|
|
|
require_once(SUBSDIR . '/Messages.subs.php'); |
|
835
|
|
|
updateMessageStats(); |
|
836
|
|
|
updateSettings(array( |
|
837
|
|
|
'calendar_updated' => time(), |
|
838
|
|
|
)); |
|
839
|
|
|
|
|
840
|
|
|
if ($log) |
|
841
|
|
|
{ |
|
842
|
|
|
foreach ($topics as $topic) |
|
843
|
|
|
{ |
|
844
|
|
|
logAction('move', array('topic' => $topic, 'board_from' => $fromCacheBoards[$topic], 'board_to' => $toBoard)); |
|
845
|
|
|
sendNotifications($topic, 'move'); |
|
846
|
|
|
} |
|
847
|
|
|
} |
|
848
|
|
|
} |
|
849
|
|
|
|
|
850
|
|
|
/** |
|
851
|
|
|
* Called after a topic is moved to update $board_link and $topic_link to point |
|
852
|
|
|
* to new location |
|
853
|
|
|
* |
|
854
|
|
|
* @param int $move_from The board the topic belongs to |
|
855
|
|
|
* @param int $id_board The "current" board |
|
856
|
|
|
* @param int $id_topic The topic id |
|
857
|
|
|
* |
|
858
|
|
|
* @return bool |
|
859
|
|
|
* @throws Elk_Exception topic_already_moved |
|
860
|
|
|
*/ |
|
861
|
|
|
function moveTopicConcurrence($move_from, $id_board, $id_topic) |
|
862
|
|
|
{ |
|
863
|
|
|
global $scripturl; |
|
864
|
|
|
|
|
865
|
|
|
$db = database(); |
|
866
|
|
|
|
|
867
|
|
|
if (empty($move_from) || empty($id_board) || empty($id_topic)) |
|
868
|
|
|
{ |
|
869
|
|
|
return true; |
|
870
|
|
|
} |
|
871
|
|
|
|
|
872
|
|
|
if ($move_from == $id_board) |
|
873
|
|
|
{ |
|
874
|
|
|
return true; |
|
875
|
|
|
} |
|
876
|
|
|
else |
|
877
|
|
|
{ |
|
878
|
|
|
$request = $db->query('', ' |
|
879
|
|
|
SELECT m.subject, b.name |
|
880
|
|
|
FROM {db_prefix}topics AS t |
|
881
|
|
|
LEFT JOIN {db_prefix}boards AS b ON (t.id_board = b.id_board) |
|
882
|
|
|
LEFT JOIN {db_prefix}messages AS m ON (t.id_first_msg = m.id_msg) |
|
883
|
|
|
WHERE t.id_topic = {int:topic_id} |
|
884
|
|
|
LIMIT 1', |
|
885
|
|
|
array( |
|
886
|
|
|
'topic_id' => $id_topic, |
|
887
|
|
|
) |
|
888
|
|
|
); |
|
889
|
|
|
list ($topic_subject, $board_name) = $db->fetch_row($request); |
|
890
|
|
|
$db->free_result($request); |
|
891
|
|
|
|
|
892
|
|
|
$board_link = '<a href="' . $scripturl . '?board=' . $id_board . '.0">' . $board_name . '</a>'; |
|
893
|
|
|
$topic_link = '<a href="' . $scripturl . '?topic=' . $id_topic . '.0">' . $topic_subject . '</a>'; |
|
894
|
|
|
throw new Elk_Exception('topic_already_moved', false, array($topic_link, $board_link)); |
|
895
|
|
|
} |
|
896
|
|
|
} |
|
897
|
|
|
|
|
898
|
|
|
/** |
|
899
|
|
|
* Determine if the topic has already been deleted by another user. |
|
900
|
|
|
* |
|
901
|
|
|
* What it does: |
|
902
|
|
|
* - If the topic has been removed and resides in the recycle bin, present confirm dialog |
|
903
|
|
|
* - If recycling is not enabled, or user confirms or topic is not in recycle simply returns |
|
904
|
|
|
*/ |
|
905
|
|
|
function removeDeleteConcurrence() |
|
906
|
|
|
{ |
|
907
|
|
|
global $modSettings, $board, $scripturl, $context; |
|
908
|
|
|
|
|
909
|
|
|
$recycled_enabled = !empty($modSettings['recycle_enable']) && !empty($modSettings['recycle_board']); |
|
910
|
|
|
|
|
911
|
|
|
if ($recycled_enabled && !empty($board)) |
|
912
|
|
|
{ |
|
913
|
|
|
// Trying to removed from the recycle bin |
|
914
|
|
|
if (!isset($_GET['confirm_delete']) && $modSettings['recycle_board'] == $board) |
|
915
|
|
|
{ |
|
916
|
|
|
if (isset($_REQUEST['msg'])) |
|
917
|
|
|
{ |
|
918
|
|
|
$confirm_url = $scripturl . '?action=deletemsg;confirm_delete;topic=' . $context['current_topic'] . '.0;msg=' . $_REQUEST['msg'] . ';' . $context['session_var'] . '=' . $context['session_id']; |
|
919
|
|
|
} |
|
920
|
|
|
else |
|
921
|
|
|
{ |
|
922
|
|
|
$confirm_url = $scripturl . '?action=removetopic2;confirm_delete;topic=' . $context['current_topic'] . '.0;' . $context['session_var'] . '=' . $context['session_id']; |
|
923
|
|
|
} |
|
924
|
|
|
|
|
925
|
|
|
// Give them a prompt before we remove the message |
|
926
|
|
|
throw new Elk_Exception('post_already_deleted', false, array($confirm_url)); |
|
927
|
|
|
} |
|
928
|
|
|
} |
|
929
|
|
|
} |
|
930
|
|
|
|
|
931
|
|
|
/** |
|
932
|
|
|
* Increase the number of views of this topic. |
|
933
|
|
|
* |
|
934
|
|
|
* @param int $id_topic the topic being viewed or whatnot. |
|
935
|
|
|
*/ |
|
936
|
|
|
function increaseViewCounter($id_topic) |
|
937
|
|
|
{ |
|
938
|
|
|
$db = database(); |
|
939
|
|
|
|
|
940
|
|
|
$db->query('', ' |
|
941
|
|
|
UPDATE {db_prefix}topics |
|
942
|
|
|
SET num_views = num_views + 1 |
|
943
|
|
|
WHERE id_topic = {int:current_topic}', |
|
944
|
|
|
array( |
|
945
|
|
|
'current_topic' => $id_topic, |
|
946
|
|
|
) |
|
947
|
|
|
); |
|
948
|
|
|
} |
|
949
|
|
|
|
|
950
|
|
|
/** |
|
951
|
|
|
* Mark topic(s) as read by the given member, at the specified message. |
|
952
|
|
|
* |
|
953
|
|
|
* @param mixed[] $mark_topics array($id_member, $id_topic, $id_msg) |
|
954
|
|
|
* @param bool $was_set = false - whether the topic has been previously read by the user |
|
955
|
|
|
*/ |
|
956
|
|
|
function markTopicsRead($mark_topics, $was_set = false) |
|
957
|
|
|
{ |
|
958
|
|
|
$db = database(); |
|
959
|
|
|
|
|
960
|
|
|
if (!is_array($mark_topics)) |
|
961
|
|
|
return; |
|
962
|
|
|
|
|
963
|
|
|
$db->insert($was_set ? 'replace' : 'ignore', |
|
964
|
|
|
'{db_prefix}log_topics', |
|
965
|
|
|
array( |
|
966
|
|
|
'id_member' => 'int', 'id_topic' => 'int', 'id_msg' => 'int', 'unwatched' => 'int', |
|
967
|
|
|
), |
|
968
|
|
|
$mark_topics, |
|
969
|
|
|
array('id_member', 'id_topic') |
|
970
|
|
|
); |
|
971
|
|
|
} |
|
972
|
|
|
|
|
973
|
|
|
/** |
|
974
|
|
|
* Update user notifications for a topic... or the board it's in. |
|
975
|
|
|
* @todo look at board notification... |
|
976
|
|
|
* |
|
977
|
|
|
* @param int $id_topic |
|
978
|
|
|
* @param int $id_board |
|
979
|
|
|
*/ |
|
980
|
|
|
function updateReadNotificationsFor($id_topic, $id_board) |
|
981
|
|
|
{ |
|
982
|
|
|
global $user_info, $context; |
|
983
|
|
|
|
|
984
|
|
|
$db = database(); |
|
985
|
|
|
|
|
986
|
|
|
// Check for notifications on this topic OR board. |
|
987
|
|
|
$request = $db->query('', ' |
|
988
|
|
|
SELECT sent, id_topic |
|
989
|
|
|
FROM {db_prefix}log_notify |
|
990
|
|
|
WHERE (id_topic = {int:current_topic} OR id_board = {int:current_board}) |
|
991
|
|
|
AND id_member = {int:current_member} |
|
992
|
|
|
LIMIT 2', |
|
993
|
|
|
array( |
|
994
|
|
|
'current_board' => $id_board, |
|
995
|
|
|
'current_member' => $user_info['id'], |
|
996
|
|
|
'current_topic' => $id_topic, |
|
997
|
|
|
) |
|
998
|
|
|
); |
|
999
|
|
|
|
|
1000
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
1001
|
|
|
{ |
|
1002
|
|
|
// Find if this topic is marked for notification... |
|
1003
|
|
|
if (!empty($row['id_topic'])) |
|
1004
|
|
|
$context['is_marked_notify'] = true; |
|
1005
|
|
|
|
|
1006
|
|
|
// Only do this once, but mark the notifications as "not sent yet" for next time. |
|
1007
|
|
|
if (!empty($row['sent'])) |
|
1008
|
|
|
{ |
|
1009
|
|
|
$db->query('', ' |
|
1010
|
|
|
UPDATE {db_prefix}log_notify |
|
1011
|
|
|
SET sent = {int:is_not_sent} |
|
1012
|
|
|
WHERE (id_topic = {int:current_topic} OR id_board = {int:current_board}) |
|
1013
|
|
|
AND id_member = {int:current_member}', |
|
1014
|
|
|
array( |
|
1015
|
|
|
'current_board' => $id_board, |
|
1016
|
|
|
'current_member' => $user_info['id'], |
|
1017
|
|
|
'current_topic' => $id_topic, |
|
1018
|
|
|
'is_not_sent' => 0, |
|
1019
|
|
|
) |
|
1020
|
|
|
); |
|
1021
|
|
|
break; |
|
1022
|
|
|
} |
|
1023
|
|
|
} |
|
1024
|
|
|
$db->free_result($request); |
|
1025
|
|
|
} |
|
1026
|
|
|
|
|
1027
|
|
|
/** |
|
1028
|
|
|
* How many topics are still unread since (last visit) |
|
1029
|
|
|
* |
|
1030
|
|
|
* @param int $id_board |
|
1031
|
|
|
* @param int $id_msg_last_visit |
|
1032
|
|
|
* @return int |
|
1033
|
|
|
*/ |
|
1034
|
|
View Code Duplication |
function getUnreadCountSince($id_board, $id_msg_last_visit) |
|
|
|
|
|
|
1035
|
|
|
{ |
|
1036
|
|
|
global $user_info; |
|
1037
|
|
|
|
|
1038
|
|
|
$db = database(); |
|
1039
|
|
|
|
|
1040
|
|
|
$request = $db->query('', ' |
|
1041
|
|
|
SELECT COUNT(*) |
|
1042
|
|
|
FROM {db_prefix}topics AS t |
|
1043
|
|
|
LEFT JOIN {db_prefix}log_boards AS lb ON (lb.id_board = {int:current_board} AND lb.id_member = {int:current_member}) |
|
1044
|
|
|
LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member}) |
|
1045
|
|
|
WHERE t.id_board = {int:current_board} |
|
1046
|
|
|
AND t.id_last_msg > COALESCE(lb.id_msg, 0) |
|
1047
|
|
|
AND t.id_last_msg > COALESCE(lt.id_msg, 0)' . |
|
1048
|
|
|
(empty($id_msg_last_visit) ? '' : ' |
|
1049
|
|
|
AND t.id_last_msg > {int:id_msg_last_visit}'), |
|
1050
|
|
|
array( |
|
1051
|
|
|
'current_board' => $id_board, |
|
1052
|
|
|
'current_member' => $user_info['id'], |
|
1053
|
|
|
'id_msg_last_visit' => (int) $id_msg_last_visit, |
|
1054
|
|
|
) |
|
1055
|
|
|
); |
|
1056
|
|
|
list ($unread) = $db->fetch_row($request); |
|
1057
|
|
|
$db->free_result($request); |
|
1058
|
|
|
|
|
1059
|
|
|
return $unread; |
|
1060
|
|
|
} |
|
1061
|
|
|
|
|
1062
|
|
|
/** |
|
1063
|
|
|
* Returns whether this member has notification turned on for the specified topic. |
|
1064
|
|
|
* |
|
1065
|
|
|
* @param int $id_member |
|
1066
|
|
|
* @param int $id_topic |
|
1067
|
|
|
* @return bool |
|
1068
|
|
|
*/ |
|
1069
|
|
|
function hasTopicNotification($id_member, $id_topic) |
|
1070
|
|
|
{ |
|
1071
|
|
|
$db = database(); |
|
1072
|
|
|
|
|
1073
|
|
|
// Find out if they have notification set for this topic already. |
|
1074
|
|
|
$request = $db->query('', ' |
|
1075
|
|
|
SELECT id_member |
|
1076
|
|
|
FROM {db_prefix}log_notify |
|
1077
|
|
|
WHERE id_member = {int:current_member} |
|
1078
|
|
|
AND id_topic = {int:current_topic} |
|
1079
|
|
|
LIMIT 1', |
|
1080
|
|
|
array( |
|
1081
|
|
|
'current_member' => $id_member, |
|
1082
|
|
|
'current_topic' => $id_topic, |
|
1083
|
|
|
) |
|
1084
|
|
|
); |
|
1085
|
|
|
$hasNotification = $db->num_rows($request) != 0; |
|
1086
|
|
|
$db->free_result($request); |
|
1087
|
|
|
|
|
1088
|
|
|
return $hasNotification; |
|
1089
|
|
|
} |
|
1090
|
|
|
|
|
1091
|
|
|
/** |
|
1092
|
|
|
* Set topic notification on or off for the given member. |
|
1093
|
|
|
* |
|
1094
|
|
|
* @param int $id_member |
|
1095
|
|
|
* @param int $id_topic |
|
1096
|
|
|
* @param bool $on |
|
1097
|
|
|
*/ |
|
1098
|
|
View Code Duplication |
function setTopicNotification($id_member, $id_topic, $on = false) |
|
|
|
|
|
|
1099
|
|
|
{ |
|
1100
|
|
|
$db = database(); |
|
1101
|
|
|
|
|
1102
|
|
|
if ($on) |
|
1103
|
|
|
{ |
|
1104
|
|
|
// Attempt to turn notifications on. |
|
1105
|
|
|
$db->insert('ignore', |
|
1106
|
|
|
'{db_prefix}log_notify', |
|
1107
|
|
|
array('id_member' => 'int', 'id_topic' => 'int'), |
|
1108
|
|
|
array($id_member, $id_topic), |
|
1109
|
|
|
array('id_member', 'id_topic') |
|
1110
|
|
|
); |
|
1111
|
|
|
} |
|
1112
|
|
|
else |
|
1113
|
|
|
{ |
|
1114
|
|
|
// Just turn notifications off. |
|
1115
|
|
|
$db->query('', ' |
|
1116
|
|
|
DELETE FROM {db_prefix}log_notify |
|
1117
|
|
|
WHERE id_member = {int:current_member} |
|
1118
|
|
|
AND id_topic = {int:current_topic}', |
|
1119
|
|
|
array( |
|
1120
|
|
|
'current_member' => $id_member, |
|
1121
|
|
|
'current_topic' => $id_topic, |
|
1122
|
|
|
) |
|
1123
|
|
|
); |
|
1124
|
|
|
} |
|
1125
|
|
|
} |
|
1126
|
|
|
|
|
1127
|
|
|
/** |
|
1128
|
|
|
* Get the previous topic from where we are. |
|
1129
|
|
|
* |
|
1130
|
|
|
* @param int $id_topic origin topic id |
|
1131
|
|
|
* @param int $id_board board id |
|
1132
|
|
|
* @param int $id_member = 0 member id |
|
1133
|
|
|
* @param bool $includeUnapproved = false whether to include unapproved topics |
|
1134
|
|
|
* @param bool $includeStickies = true whether to include sticky topics |
|
1135
|
|
|
* @return int topic number |
|
1136
|
|
|
*/ |
|
1137
|
|
|
function previousTopic($id_topic, $id_board, $id_member = 0, $includeUnapproved = false, $includeStickies = true) |
|
1138
|
|
|
{ |
|
1139
|
|
|
return topicPointer($id_topic, $id_board, false, $id_member, $includeUnapproved, $includeStickies); |
|
1140
|
|
|
} |
|
1141
|
|
|
|
|
1142
|
|
|
/** |
|
1143
|
|
|
* Get the next topic from where we are. |
|
1144
|
|
|
* |
|
1145
|
|
|
* @param int $id_topic origin topic id |
|
1146
|
|
|
* @param int $id_board board id |
|
1147
|
|
|
* @param int $id_member = 0 member id |
|
1148
|
|
|
* @param bool $includeUnapproved = false whether to include unapproved topics |
|
1149
|
|
|
* @param bool $includeStickies = true whether to include sticky topics |
|
1150
|
|
|
* @return int topic number |
|
1151
|
|
|
*/ |
|
1152
|
|
|
function nextTopic($id_topic, $id_board, $id_member = 0, $includeUnapproved = false, $includeStickies = true) |
|
1153
|
|
|
{ |
|
1154
|
|
|
return topicPointer($id_topic, $id_board, true, $id_member, $includeUnapproved, $includeStickies); |
|
1155
|
|
|
} |
|
1156
|
|
|
|
|
1157
|
|
|
/** |
|
1158
|
|
|
* Advance topic pointer. |
|
1159
|
|
|
* (in either direction) |
|
1160
|
|
|
* This function is used by previousTopic() and nextTopic() |
|
1161
|
|
|
* The boolean parameter $next determines direction. |
|
1162
|
|
|
* |
|
1163
|
|
|
* @param int $id_topic origin topic id |
|
1164
|
|
|
* @param int $id_board board id |
|
1165
|
|
|
* @param bool $next = true whether to increase or decrease the pointer |
|
1166
|
|
|
* @param int $id_member = 0 member id |
|
1167
|
|
|
* @param bool $includeUnapproved = false whether to include unapproved topics |
|
1168
|
|
|
* @param bool $includeStickies = true whether to include sticky topics |
|
1169
|
|
|
* @return int the topic number |
|
1170
|
|
|
*/ |
|
1171
|
|
|
function topicPointer($id_topic, $id_board, $next = true, $id_member = 0, $includeUnapproved = false, $includeStickies = true) |
|
1172
|
|
|
{ |
|
1173
|
|
|
$db = database(); |
|
1174
|
|
|
|
|
1175
|
|
|
$request = $db->query('', ' |
|
1176
|
|
|
SELECT t2.id_topic |
|
1177
|
|
|
FROM {db_prefix}topics AS t |
|
1178
|
|
|
INNER JOIN {db_prefix}topics AS t2 ON (' . |
|
1179
|
|
|
(empty($includeStickies) ? ' |
|
1180
|
|
|
t2.id_last_msg {raw:strictly} t.id_last_msg' : ' |
|
1181
|
|
|
(t2.id_last_msg {raw:strictly} t.id_last_msg AND t2.is_sticky {raw:strictly_equal} t.is_sticky) OR t2.is_sticky {raw:strictly} t.is_sticky') |
|
1182
|
|
|
. ') |
|
1183
|
|
|
WHERE t.id_topic = {int:current_topic} |
|
1184
|
|
|
AND t2.id_board = {int:current_board}' . |
|
1185
|
|
|
($includeUnapproved ? '' : ' |
|
1186
|
|
|
AND (t2.approved = {int:is_approved} OR (t2.id_member_started != {int:id_member_started} AND t2.id_member_started = {int:current_member}))' |
|
1187
|
|
|
) . ' |
|
1188
|
|
|
ORDER BY' . ( |
|
1189
|
|
|
$includeStickies ? ' |
|
1190
|
|
|
t2.is_sticky {raw:sorting},' : |
|
1191
|
|
|
'') . |
|
1192
|
|
|
' t2.id_last_msg {raw:sorting} |
|
1193
|
|
|
LIMIT 1', |
|
1194
|
|
|
array( |
|
1195
|
|
|
'strictly' => $next ? '<' : '>', |
|
1196
|
|
|
'strictly_equal' => $next ? '<=' : '>=', |
|
1197
|
|
|
'sorting' => $next ? 'DESC' : '', |
|
1198
|
|
|
'current_board' => $id_board, |
|
1199
|
|
|
'current_member' => $id_member, |
|
1200
|
|
|
'current_topic' => $id_topic, |
|
1201
|
|
|
'is_approved' => 1, |
|
1202
|
|
|
'id_member_started' => 0, |
|
1203
|
|
|
) |
|
1204
|
|
|
); |
|
1205
|
|
|
|
|
1206
|
|
|
// Was there any? |
|
1207
|
|
|
if ($db->num_rows($request) == 0) |
|
1208
|
|
|
{ |
|
1209
|
|
|
$db->free_result($request); |
|
1210
|
|
|
|
|
1211
|
|
|
// Roll over - if we're going prev, get the last - otherwise the first. |
|
1212
|
|
|
$request = $db->query('', ' |
|
1213
|
|
|
SELECT id_topic |
|
1214
|
|
|
FROM {db_prefix}topics |
|
1215
|
|
|
WHERE id_board = {int:current_board}' . |
|
1216
|
|
|
($includeUnapproved ? '' : ' |
|
1217
|
|
|
AND (approved = {int:is_approved} OR (id_member_started != {int:id_member_started} AND id_member_started = {int:current_member}))') . ' |
|
1218
|
|
|
ORDER BY' . ( |
|
1219
|
|
|
$includeStickies ? ' is_sticky {raw:sorting},' : '') . |
|
1220
|
|
|
' id_last_msg {raw:sorting} |
|
1221
|
|
|
LIMIT 1', |
|
1222
|
|
|
array( |
|
1223
|
|
|
'sorting' => $next ? 'DESC' : '', |
|
1224
|
|
|
'current_board' => $id_board, |
|
1225
|
|
|
'current_member' => $id_member, |
|
1226
|
|
|
'is_approved' => 1, |
|
1227
|
|
|
'id_member_started' => 0, |
|
1228
|
|
|
) |
|
1229
|
|
|
); |
|
1230
|
|
|
} |
|
1231
|
|
|
// Now you can be sure $topic is the id_topic to view. |
|
1232
|
|
|
list ($topic) = $db->fetch_row($request); |
|
1233
|
|
|
$db->free_result($request); |
|
1234
|
|
|
|
|
1235
|
|
|
return $topic; |
|
1236
|
|
|
} |
|
1237
|
|
|
|
|
1238
|
|
|
/** |
|
1239
|
|
|
* Set off/on unread reply subscription for a topic |
|
1240
|
|
|
* |
|
1241
|
|
|
* @param int $id_member |
|
1242
|
|
|
* @param int $topic |
|
1243
|
|
|
* @param bool $on = false |
|
1244
|
|
|
*/ |
|
1245
|
|
|
function setTopicWatch($id_member, $topic, $on = false) |
|
1246
|
|
|
{ |
|
1247
|
|
|
global $user_info; |
|
1248
|
|
|
|
|
1249
|
|
|
$db = database(); |
|
1250
|
|
|
|
|
1251
|
|
|
// find the current entry if it exists that is |
|
1252
|
|
|
$was_set = getLoggedTopics($user_info['id'], array($topic)); |
|
1253
|
|
|
|
|
1254
|
|
|
// Set topic unwatched on/off for this topic. |
|
1255
|
|
|
$db->insert(empty($was_set[$topic]) ? 'ignore' : 'replace', |
|
1256
|
|
|
'{db_prefix}log_topics', |
|
1257
|
|
|
array('id_member' => 'int', 'id_topic' => 'int', 'id_msg' => 'int', 'unwatched' => 'int'), |
|
1258
|
|
|
array($id_member, $topic, !empty($was_set[$topic]['id_msg']) ? $was_set[$topic]['id_msg'] : 0, $on ? 1 : 0), |
|
1259
|
|
|
array('id_member', 'id_topic') |
|
1260
|
|
|
); |
|
1261
|
|
|
} |
|
1262
|
|
|
|
|
1263
|
|
|
/** |
|
1264
|
|
|
* Get all the details for a given topic |
|
1265
|
|
|
* - returns the basic topic information when $full is false |
|
1266
|
|
|
* - returns topic details, subject, last message read, etc when full is true |
|
1267
|
|
|
* - uses any integration information (value selects, tables and parameters) if passed and full is true |
|
1268
|
|
|
* |
|
1269
|
|
|
* @param mixed[]|int $topic_parameters can also accept a int value for a topic |
|
1270
|
|
|
* @param string $full defines the values returned by the function: |
|
1271
|
|
|
* - if empty returns only the data from {db_prefix}topics |
|
1272
|
|
|
* - if 'message' returns also information about the message (subject, body, etc.) |
|
1273
|
|
|
* - if 'starter' returns also information about the topic starter (id_member and poster_name) |
|
1274
|
|
|
* - if 'all' returns additional infos about the read/unwatched status |
|
1275
|
|
|
* @param string[] $selects (optional from integration) |
|
1276
|
|
|
* @param string[] $tables (optional from integration) |
|
1277
|
|
|
* @return array to topic attributes |
|
1278
|
|
|
*/ |
|
1279
|
|
|
function getTopicInfo($topic_parameters, $full = '', $selects = array(), $tables = array()) |
|
1280
|
|
|
{ |
|
1281
|
|
|
global $user_info, $modSettings, $board; |
|
1282
|
|
|
|
|
1283
|
|
|
$db = database(); |
|
1284
|
|
|
|
|
1285
|
|
|
// Nothing to do |
|
1286
|
|
|
if (empty($topic_parameters)) |
|
1287
|
|
|
return false; |
|
1288
|
|
|
|
|
1289
|
|
|
// Build what we can with what we were given |
|
1290
|
|
|
if (!is_array($topic_parameters)) |
|
1291
|
|
|
$topic_parameters = array( |
|
1292
|
|
|
'topic' => $topic_parameters, |
|
1293
|
|
|
'member' => $user_info['id'], |
|
1294
|
|
|
'board' => (int) $board, |
|
1295
|
|
|
); |
|
1296
|
|
|
|
|
1297
|
|
|
$messages_table = $full === 'message' || $full === 'all' || $full === 'starter'; |
|
1298
|
|
|
$members_table = $full === 'starter'; |
|
1299
|
|
|
$logs_table = $full === 'all'; |
|
1300
|
|
|
|
|
1301
|
|
|
// Create the query, taking full and integration in to account |
|
1302
|
|
|
$request = $db->query('', ' |
|
1303
|
|
|
SELECT |
|
1304
|
|
|
t.id_topic, t.is_sticky, t.id_board, t.id_first_msg, t.id_last_msg, |
|
1305
|
|
|
t.id_member_started, t.id_member_updated, t.id_poll, |
|
1306
|
|
|
t.num_replies, t.num_views, t.num_likes, t.locked, t.redirect_expires, |
|
1307
|
|
|
t.id_redirect_topic, t.unapproved_posts, t.approved' . ($messages_table ? ', |
|
1308
|
|
|
ms.subject, ms.body, ms.id_member, ms.poster_time, ms.approved as msg_approved' : '') . ($members_table ? ', |
|
1309
|
|
|
COALESCE(mem.real_name, ms.poster_name) AS poster_name' : '') . ($logs_table ? ', |
|
1310
|
|
|
' . ($user_info['is_guest'] ? 't.id_last_msg + 1' : 'COALESCE(lt.id_msg, lmr.id_msg, -1) + 1') . ' AS new_from |
|
1311
|
|
|
' . (!empty($modSettings['recycle_board']) && $modSettings['recycle_board'] == $board ? ', t.id_previous_board, t.id_previous_topic' : '') . ' |
|
1312
|
|
|
' . (!$user_info['is_guest'] ? ', COALESCE(lt.unwatched, 0) as unwatched' : '') : '') . |
|
1313
|
|
|
(!empty($selects) ? ', ' . implode(', ', $selects) : '') . ' |
|
1314
|
|
|
FROM {db_prefix}topics AS t' . ($messages_table ? ' |
|
1315
|
|
|
INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg)' : '') . ($members_table ? ' |
|
1316
|
|
|
LEFT JOIN {db_prefix}members as mem ON (mem.id_member = ms.id_member)' : '') . ($logs_table && !$user_info['is_guest'] ? ' |
|
1317
|
|
|
LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = {int:topic} AND lt.id_member = {int:member}) |
|
1318
|
|
|
LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = {int:board} AND lmr.id_member = {int:member})' : '') . (!empty($tables) ? ' |
|
1319
|
|
|
' . implode("\n\t\t\t", $tables) : '') . ' |
|
1320
|
|
|
WHERE t.id_topic = {int:topic} |
|
1321
|
|
|
LIMIT 1', |
|
1322
|
|
|
$topic_parameters |
|
1323
|
|
|
); |
|
1324
|
|
|
$topic_info = array(); |
|
1325
|
|
|
if ($request !== false) |
|
1326
|
|
|
$topic_info = $db->fetch_assoc($request); |
|
1327
|
|
|
$db->free_result($request); |
|
1328
|
|
|
|
|
1329
|
|
|
return $topic_info; |
|
1330
|
|
|
} |
|
1331
|
|
|
|
|
1332
|
|
|
/** |
|
1333
|
|
|
* Get all the details for a given topic and message. |
|
1334
|
|
|
* Respects permissions and post moderation |
|
1335
|
|
|
* |
|
1336
|
|
|
* @param int $topic id of a topic |
|
1337
|
|
|
* @param int|null $msg the id of a message, if empty, t.id_first_msg is used |
|
1338
|
|
|
* @return mixed[]|boolean to topic attributes |
|
1339
|
|
|
*/ |
|
1340
|
|
|
function getTopicInfoByMsg($topic, $msg = null) |
|
1341
|
|
|
{ |
|
1342
|
|
|
global $user_info, $modSettings; |
|
1343
|
|
|
|
|
1344
|
|
|
// Nothing to do |
|
1345
|
|
|
if (empty($topic)) |
|
1346
|
|
|
return false; |
|
1347
|
|
|
|
|
1348
|
|
|
$db = database(); |
|
1349
|
|
|
|
|
1350
|
|
|
$request = $db->query('', ' |
|
1351
|
|
|
SELECT |
|
1352
|
|
|
t.locked, t.num_replies, t.id_member_started, t.id_first_msg, |
|
1353
|
|
|
m.id_msg, m.id_member, m.poster_time, m.subject, m.smileys_enabled, m.body, m.icon, |
|
1354
|
|
|
m.modified_time, m.modified_name, m.approved |
|
1355
|
|
|
FROM {db_prefix}messages AS m |
|
1356
|
|
|
INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic}) |
|
1357
|
|
|
WHERE m.id_msg = {raw:id_msg} |
|
1358
|
|
|
AND m.id_topic = {int:current_topic}' . (allowedTo('modify_any') || allowedTo('approve_posts') ? '' : (!$modSettings['postmod_active'] ? ' |
|
1359
|
|
|
AND (m.id_member != {int:guest_id} AND m.id_member = {int:current_member})' : ' |
|
1360
|
|
|
AND (m.approved = {int:is_approved} OR (m.id_member != {int:guest_id} AND m.id_member = {int:current_member}))')), |
|
1361
|
|
|
array( |
|
1362
|
|
|
'current_member' => $user_info['id'], |
|
1363
|
|
|
'current_topic' => $topic, |
|
1364
|
|
|
'id_msg' => empty($msg) ? 't.id_first_msg' : $msg, |
|
1365
|
|
|
'is_approved' => 1, |
|
1366
|
|
|
'guest_id' => 0, |
|
1367
|
|
|
) |
|
1368
|
|
|
); |
|
1369
|
|
|
$topic_info = array(); |
|
1370
|
|
|
if ($request !== false) |
|
1371
|
|
|
{ |
|
1372
|
|
|
$topic_info = $db->fetch_assoc($request); |
|
1373
|
|
|
} |
|
1374
|
|
|
$db->free_result($request); |
|
1375
|
|
|
|
|
1376
|
|
|
return $topic_info; |
|
1377
|
|
|
} |
|
1378
|
|
|
|
|
1379
|
|
|
/** |
|
1380
|
|
|
* So long as you are sure... all old posts will be gone. |
|
1381
|
|
|
* Used in Maintenance.controller.php to prune old topics. |
|
1382
|
|
|
* |
|
1383
|
|
|
* @param int[] $boards |
|
1384
|
|
|
* @param string $delete_type |
|
1385
|
|
|
* @param boolean $exclude_stickies |
|
1386
|
|
|
* @param int $older_than |
|
1387
|
|
|
* @throws Elk_Exception |
|
1388
|
|
|
*/ |
|
1389
|
|
|
function removeOldTopics(array $boards, $delete_type, $exclude_stickies, $older_than) |
|
1390
|
|
|
{ |
|
1391
|
|
|
$db = database(); |
|
1392
|
|
|
|
|
1393
|
|
|
// Custom conditions. |
|
1394
|
|
|
$condition = ''; |
|
1395
|
|
|
$condition_params = array( |
|
1396
|
|
|
'boards' => $boards, |
|
1397
|
|
|
'poster_time' => $older_than, |
|
1398
|
|
|
); |
|
1399
|
|
|
|
|
1400
|
|
|
// Just moved notice topics? |
|
1401
|
|
|
if ($delete_type == 'moved') |
|
1402
|
|
|
{ |
|
1403
|
|
|
$condition .= ' |
|
1404
|
|
|
AND m.icon = {string:icon} |
|
1405
|
|
|
AND t.locked = {int:locked}'; |
|
1406
|
|
|
$condition_params['icon'] = 'moved'; |
|
1407
|
|
|
$condition_params['locked'] = 1; |
|
1408
|
|
|
} |
|
1409
|
|
|
// Otherwise, maybe locked topics only? |
|
1410
|
|
|
elseif ($delete_type == 'locked') |
|
1411
|
|
|
{ |
|
1412
|
|
|
$condition .= ' |
|
1413
|
|
|
AND t.locked = {int:locked}'; |
|
1414
|
|
|
$condition_params['locked'] = 1; |
|
1415
|
|
|
} |
|
1416
|
|
|
|
|
1417
|
|
|
// Exclude stickies? |
|
1418
|
|
|
if ($exclude_stickies) |
|
1419
|
|
|
{ |
|
1420
|
|
|
$condition .= ' |
|
1421
|
|
|
AND t.is_sticky = {int:is_sticky}'; |
|
1422
|
|
|
$condition_params['is_sticky'] = 0; |
|
1423
|
|
|
} |
|
1424
|
|
|
|
|
1425
|
|
|
// All we're gonna do here is grab the id_topic's and send them to removeTopics(). |
|
1426
|
|
|
$request = $db->query('', ' |
|
1427
|
|
|
SELECT t.id_topic |
|
1428
|
|
|
FROM {db_prefix}topics AS t |
|
1429
|
|
|
INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_last_msg) |
|
1430
|
|
|
WHERE |
|
1431
|
|
|
m.poster_time < {int:poster_time}' . $condition . ' |
|
1432
|
|
|
AND t.id_board IN ({array_int:boards})', |
|
1433
|
|
|
$condition_params |
|
1434
|
|
|
); |
|
1435
|
|
|
$topics = array(); |
|
1436
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
1437
|
|
|
$topics[] = $row['id_topic']; |
|
1438
|
|
|
$db->free_result($request); |
|
1439
|
|
|
|
|
1440
|
|
|
removeTopics($topics, false, true); |
|
1441
|
|
|
} |
|
1442
|
|
|
|
|
1443
|
|
|
/** |
|
1444
|
|
|
* Retrieve all topics started by the given member. |
|
1445
|
|
|
* |
|
1446
|
|
|
* @param int $memberID |
|
1447
|
|
|
*/ |
|
1448
|
|
|
function topicsStartedBy($memberID) |
|
1449
|
|
|
{ |
|
1450
|
|
|
$db = database(); |
|
1451
|
|
|
|
|
1452
|
|
|
// Fetch all topics started by this user. |
|
1453
|
|
|
$request = $db->query('', ' |
|
1454
|
|
|
SELECT t.id_topic |
|
1455
|
|
|
FROM {db_prefix}topics AS t |
|
1456
|
|
|
WHERE t.id_member_started = {int:selected_member}', |
|
1457
|
|
|
array( |
|
1458
|
|
|
'selected_member' => $memberID, |
|
1459
|
|
|
) |
|
1460
|
|
|
); |
|
1461
|
|
|
$topicIDs = array(); |
|
1462
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
1463
|
|
|
$topicIDs[] = $row['id_topic']; |
|
1464
|
|
|
$db->free_result($request); |
|
1465
|
|
|
|
|
1466
|
|
|
return $topicIDs; |
|
1467
|
|
|
} |
|
1468
|
|
|
|
|
1469
|
|
|
/** |
|
1470
|
|
|
* Retrieve the messages of the given topic, that are at or after |
|
1471
|
|
|
* a message. |
|
1472
|
|
|
* Used by split topics actions. |
|
1473
|
|
|
* |
|
1474
|
|
|
* @param int $id_topic |
|
1475
|
|
|
* @param int $id_msg |
|
1476
|
|
|
* @param bool $include_current = false |
|
1477
|
|
|
* @param bool $only_approved = false |
|
1478
|
|
|
* |
|
1479
|
|
|
* @return array message ids |
|
1480
|
|
|
*/ |
|
1481
|
|
|
function messagesSince($id_topic, $id_msg, $include_current = false, $only_approved = false) |
|
1482
|
|
|
{ |
|
1483
|
|
|
$db = database(); |
|
1484
|
|
|
|
|
1485
|
|
|
// Fetch the message IDs of the topic that are at or after the message. |
|
1486
|
|
|
$request = $db->query('', ' |
|
1487
|
|
|
SELECT id_msg |
|
1488
|
|
|
FROM {db_prefix}messages |
|
1489
|
|
|
WHERE id_topic = {int:current_topic} |
|
1490
|
|
|
AND id_msg ' . ($include_current ? '>=' : '>') . ' {int:last_msg}' . ($only_approved ? ' |
|
1491
|
|
|
AND approved = {int:approved}' : ''), |
|
1492
|
|
|
array( |
|
1493
|
|
|
'current_topic' => $id_topic, |
|
1494
|
|
|
'last_msg' => $id_msg, |
|
1495
|
|
|
'approved' => 1, |
|
1496
|
|
|
) |
|
1497
|
|
|
); |
|
1498
|
|
|
$messages = array(); |
|
1499
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
1500
|
|
|
$messages[] = $row['id_msg']; |
|
1501
|
|
|
$db->free_result($request); |
|
1502
|
|
|
|
|
1503
|
|
|
return $messages; |
|
1504
|
|
|
} |
|
1505
|
|
|
|
|
1506
|
|
|
/** |
|
1507
|
|
|
* This function returns the number of messages in a topic, |
|
1508
|
|
|
* posted after $id_msg. |
|
1509
|
|
|
* |
|
1510
|
|
|
* @param int $id_topic |
|
1511
|
|
|
* @param int $id_msg |
|
1512
|
|
|
* @param bool $include_current = false |
|
1513
|
|
|
* @param bool $only_approved = false |
|
1514
|
|
|
* |
|
1515
|
|
|
* @return int |
|
1516
|
|
|
*/ |
|
1517
|
|
|
function countMessagesSince($id_topic, $id_msg, $include_current = false, $only_approved = false) |
|
1518
|
|
|
{ |
|
1519
|
|
|
$db = database(); |
|
1520
|
|
|
|
|
1521
|
|
|
// Give us something to work with |
|
1522
|
|
|
if (empty($id_topic) || empty($id_msg)) |
|
1523
|
|
|
return false; |
|
1524
|
|
|
|
|
1525
|
|
|
$request = $db->query('', ' |
|
1526
|
|
|
SELECT COUNT(*) |
|
1527
|
|
|
FROM {db_prefix}messages |
|
1528
|
|
|
WHERE id_topic = {int:current_topic} |
|
1529
|
|
|
AND id_msg ' . ($include_current ? '>=' : '>') . ' {int:last_msg}' . ($only_approved ? ' |
|
1530
|
|
|
AND approved = {int:approved}' : '') . ' |
|
1531
|
|
|
LIMIT 1', |
|
1532
|
|
|
array( |
|
1533
|
|
|
'current_topic' => $id_topic, |
|
1534
|
|
|
'last_msg' => $id_msg, |
|
1535
|
|
|
'approved' => 1, |
|
1536
|
|
|
) |
|
1537
|
|
|
); |
|
1538
|
|
|
list ($count) = $db->fetch_row($request); |
|
1539
|
|
|
$db->free_result($request); |
|
1540
|
|
|
|
|
1541
|
|
|
return $count; |
|
1542
|
|
|
} |
|
1543
|
|
|
|
|
1544
|
|
|
/** |
|
1545
|
|
|
* Returns how many messages are in a topic before the specified message id. |
|
1546
|
|
|
* Used in display to compute the start value for a specific message. |
|
1547
|
|
|
* |
|
1548
|
|
|
* @param int $id_topic |
|
1549
|
|
|
* @param int $id_msg |
|
1550
|
|
|
* @param bool $include_current = false |
|
1551
|
|
|
* @param bool $only_approved = false |
|
1552
|
|
|
* @param bool $include_own = false |
|
1553
|
|
|
* @return int |
|
1554
|
|
|
*/ |
|
1555
|
|
|
function countMessagesBefore($id_topic, $id_msg, $include_current = false, $only_approved = false, $include_own = false) |
|
1556
|
|
|
{ |
|
1557
|
|
|
global $user_info; |
|
1558
|
|
|
|
|
1559
|
|
|
$db = database(); |
|
1560
|
|
|
|
|
1561
|
|
|
$request = $db->query('', ' |
|
1562
|
|
|
SELECT COUNT(*) |
|
1563
|
|
|
FROM {db_prefix}messages |
|
1564
|
|
|
WHERE id_msg ' . ($include_current ? '<=' : '<') . ' {int:id_msg} |
|
1565
|
|
|
AND id_topic = {int:current_topic}' . ($only_approved ? ' |
|
1566
|
|
|
AND (approved = {int:is_approved}' . ($include_own ? ' |
|
1567
|
|
|
OR id_member = {int:current_member}' : '') . ')' : ''), |
|
1568
|
|
|
array( |
|
1569
|
|
|
'current_member' => $user_info['id'], |
|
1570
|
|
|
'current_topic' => $id_topic, |
|
1571
|
|
|
'id_msg' => $id_msg, |
|
1572
|
|
|
'is_approved' => 1, |
|
1573
|
|
|
) |
|
1574
|
|
|
); |
|
1575
|
|
|
list ($count) = $db->fetch_row($request); |
|
1576
|
|
|
$db->free_result($request); |
|
1577
|
|
|
|
|
1578
|
|
|
return $count; |
|
1579
|
|
|
} |
|
1580
|
|
|
|
|
1581
|
|
|
/** |
|
1582
|
|
|
* Select a part of the messages in a topic. |
|
1583
|
|
|
* |
|
1584
|
|
|
* @param int $topic |
|
1585
|
|
|
* @param int $start The item to start with (for pagination purposes) |
|
1586
|
|
|
* @param int $items_per_page The number of items to show per page |
|
1587
|
|
|
* @param mixed[] $messages |
|
1588
|
|
|
* @param bool $only_approved |
|
1589
|
|
|
*/ |
|
1590
|
|
|
function selectMessages($topic, $start, $items_per_page, $messages = array(), $only_approved = false) |
|
1591
|
|
|
{ |
|
1592
|
|
|
$db = database(); |
|
1593
|
|
|
|
|
1594
|
|
|
// Get the messages and stick them into an array. |
|
1595
|
|
|
$request = $db->query('', ' |
|
1596
|
|
|
SELECT m.subject, COALESCE(mem.real_name, m.poster_name) AS real_name, m.poster_time, m.body, m.id_msg, m.smileys_enabled, m.id_member |
|
1597
|
|
|
FROM {db_prefix}messages AS m |
|
1598
|
|
|
LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) |
|
1599
|
|
|
WHERE m.id_topic = {int:current_topic}' . (empty($messages['before']) ? '' : ' |
|
1600
|
|
|
AND m.id_msg < {int:msg_before}') . (empty($messages['after']) ? '' : ' |
|
1601
|
|
|
AND m.id_msg > {int:msg_after}') . (empty($messages['excluded']) ? '' : ' |
|
1602
|
|
|
AND m.id_msg NOT IN ({array_int:no_split_msgs})') . (empty($messages['included']) ? '' : ' |
|
1603
|
|
|
AND m.id_msg IN ({array_int:split_msgs})') . (!$only_approved ? '' : ' |
|
1604
|
|
|
AND approved = {int:is_approved}') . ' |
|
1605
|
|
|
ORDER BY m.id_msg DESC |
|
1606
|
|
|
LIMIT {int:start}, {int:messages_per_page}', |
|
1607
|
|
|
array( |
|
1608
|
|
|
'current_topic' => $topic, |
|
1609
|
|
|
'no_split_msgs' => !empty($messages['excluded']) ? $messages['excluded'] : array(), |
|
1610
|
|
|
'split_msgs' => !empty($messages['included']) ? $messages['included'] : array(), |
|
1611
|
|
|
'is_approved' => 1, |
|
1612
|
|
|
'start' => $start, |
|
1613
|
|
|
'messages_per_page' => $items_per_page, |
|
1614
|
|
|
'msg_before' => !empty($messages['before']) ? (int) $messages['before'] : 0, |
|
1615
|
|
|
'msg_after' => !empty($messages['after']) ? (int) $messages['after'] : 0, |
|
1616
|
|
|
) |
|
1617
|
|
|
); |
|
1618
|
|
|
|
|
1619
|
|
|
$messages = array(); |
|
1620
|
|
|
$parser = \BBC\ParserWrapper::instance(); |
|
1621
|
|
|
|
|
1622
|
|
|
for ($counter = 0; $row = $db->fetch_assoc($request); $counter++) |
|
1623
|
|
|
{ |
|
1624
|
|
|
$row['subject'] = censor($row['subject']); |
|
1625
|
|
|
$row['body'] = censor($row['body']); |
|
1626
|
|
|
|
|
1627
|
|
|
$row['body'] = $parser->parseMessage($row['body'], (bool) $row['smileys_enabled']); |
|
1628
|
|
|
|
|
1629
|
|
|
$messages[$row['id_msg']] = array( |
|
1630
|
|
|
'id' => $row['id_msg'], |
|
1631
|
|
|
'alternate' => $counter % 2, |
|
1632
|
|
|
'subject' => $row['subject'], |
|
1633
|
|
|
'time' => standardTime($row['poster_time']), |
|
1634
|
|
|
'html_time' => htmlTime($row['poster_time']), |
|
1635
|
|
|
'timestamp' => forum_time(true, $row['poster_time']), |
|
1636
|
|
|
'body' => $row['body'], |
|
1637
|
|
|
'poster' => $row['real_name'], |
|
1638
|
|
|
'id_poster' => $row['id_member'], |
|
1639
|
|
|
); |
|
1640
|
|
|
} |
|
1641
|
|
|
$db->free_result($request); |
|
1642
|
|
|
|
|
1643
|
|
|
return $messages; |
|
1644
|
|
|
} |
|
1645
|
|
|
|
|
1646
|
|
|
/** |
|
1647
|
|
|
* Loads all the messages of a topic |
|
1648
|
|
|
* Used when printing or other functions that require a topic listing |
|
1649
|
|
|
* |
|
1650
|
|
|
* @param int $topic |
|
1651
|
|
|
* @param string $render defaults to print style rendering for parse_bbc |
|
1652
|
|
|
*/ |
|
1653
|
|
|
function topicMessages($topic, $render = 'print') |
|
1654
|
|
|
{ |
|
1655
|
|
|
global $modSettings, $user_info; |
|
1656
|
|
|
|
|
1657
|
|
|
$db = database(); |
|
1658
|
|
|
|
|
1659
|
|
|
$request = $db->query('', ' |
|
1660
|
|
|
SELECT subject, poster_time, body, COALESCE(mem.real_name, poster_name) AS poster_name, id_msg |
|
1661
|
|
|
FROM {db_prefix}messages AS m |
|
1662
|
|
|
LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) |
|
1663
|
|
|
WHERE m.id_topic = {int:current_topic}' . ($modSettings['postmod_active'] && !allowedTo('approve_posts') ? ' |
|
1664
|
|
|
AND (m.approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR m.id_member = {int:current_member}') . ')' : '') . ' |
|
1665
|
|
|
ORDER BY m.id_msg', |
|
1666
|
|
|
array( |
|
1667
|
|
|
'current_topic' => $topic, |
|
1668
|
|
|
'is_approved' => 1, |
|
1669
|
|
|
'current_member' => $user_info['id'], |
|
1670
|
|
|
) |
|
1671
|
|
|
); |
|
1672
|
|
|
|
|
1673
|
|
|
$posts = array(); |
|
1674
|
|
|
$parser = \BBC\ParserWrapper::instance(); |
|
1675
|
|
|
|
|
1676
|
|
|
if ($render === 'print') |
|
1677
|
|
|
{ |
|
1678
|
|
|
$parser->getCodes()->setForPrinting(); |
|
1679
|
|
|
} |
|
1680
|
|
|
|
|
1681
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
1682
|
|
|
{ |
|
1683
|
|
|
// Censor the subject and message. |
|
1684
|
|
|
$row['subject'] = censor($row['subject']); |
|
1685
|
|
|
$row['body'] = censor($row['body']); |
|
1686
|
|
|
|
|
1687
|
|
|
$posts[$row['id_msg']] = array( |
|
1688
|
|
|
'subject' => $row['subject'], |
|
1689
|
|
|
'member' => $row['poster_name'], |
|
1690
|
|
|
'time' => standardTime($row['poster_time'], false), |
|
1691
|
|
|
'html_time' => htmlTime($row['poster_time']), |
|
1692
|
|
|
'timestamp' => forum_time(true, $row['poster_time']), |
|
1693
|
|
|
'body' => $parser->parseMessage($row['body'], $render !== 'print'), |
|
1694
|
|
|
'id_msg' => $row['id_msg'], |
|
1695
|
|
|
); |
|
1696
|
|
|
} |
|
1697
|
|
|
$db->free_result($request); |
|
1698
|
|
|
|
|
1699
|
|
|
return $posts; |
|
1700
|
|
|
} |
|
1701
|
|
|
|
|
1702
|
|
|
/** |
|
1703
|
|
|
* Load message image attachments for use in the print page function |
|
1704
|
|
|
* Returns array of file attachment name along with width/height properties |
|
1705
|
|
|
* Will only return approved attachments |
|
1706
|
|
|
* |
|
1707
|
|
|
* @param int[] $id_messages |
|
1708
|
|
|
*/ |
|
1709
|
|
|
function messagesAttachments($id_messages) |
|
1710
|
|
|
{ |
|
1711
|
|
|
global $modSettings; |
|
1712
|
|
|
|
|
1713
|
|
|
require_once(SUBSDIR . '/Attachments.subs.php'); |
|
1714
|
|
|
|
|
1715
|
|
|
$db = database(); |
|
1716
|
|
|
|
|
1717
|
|
|
$request = $db->query('', ' |
|
1718
|
|
|
SELECT |
|
1719
|
|
|
a.id_attach, a.id_msg, a.approved, a.width, a.height, a.file_hash, a.filename, a.id_folder, a.mime_type |
|
1720
|
|
|
FROM {db_prefix}attachments AS a |
|
1721
|
|
|
WHERE a.id_msg IN ({array_int:message_list}) |
|
1722
|
|
|
AND a.attachment_type = {int:attachment_type}', |
|
1723
|
|
|
array( |
|
1724
|
|
|
'message_list' => $id_messages, |
|
1725
|
|
|
'attachment_type' => 0, |
|
1726
|
|
|
'is_approved' => 1, |
|
1727
|
|
|
) |
|
1728
|
|
|
); |
|
1729
|
|
|
$temp = array(); |
|
1730
|
|
|
$printattach = array(); |
|
1731
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
1732
|
|
|
{ |
|
1733
|
|
|
$temp[$row['id_attach']] = $row; |
|
1734
|
|
|
if (!isset($printattach[$row['id_msg']])) |
|
1735
|
|
|
$printattach[$row['id_msg']] = array(); |
|
1736
|
|
|
} |
|
1737
|
|
|
$db->free_result($request); |
|
1738
|
|
|
ksort($temp); |
|
1739
|
|
|
|
|
1740
|
|
|
// Load them into $context so the template can use them |
|
1741
|
|
|
foreach ($temp as $row) |
|
1742
|
|
|
{ |
|
1743
|
|
|
if (!empty($row['width']) && !empty($row['height'])) |
|
1744
|
|
|
{ |
|
1745
|
|
|
if (!empty($modSettings['max_image_width']) && (empty($modSettings['max_image_height']) || $row['height'] * ($modSettings['max_image_width'] / $row['width']) <= $modSettings['max_image_height'])) |
|
1746
|
|
|
{ |
|
1747
|
|
View Code Duplication |
if ($row['width'] > $modSettings['max_image_width']) |
|
1748
|
|
|
{ |
|
1749
|
|
|
$row['height'] = floor($row['height'] * ($modSettings['max_image_width'] / $row['width'])); |
|
1750
|
|
|
$row['width'] = $modSettings['max_image_width']; |
|
1751
|
|
|
} |
|
1752
|
|
|
} |
|
1753
|
|
View Code Duplication |
elseif (!empty($modSettings['max_image_width'])) |
|
1754
|
|
|
{ |
|
1755
|
|
|
if ($row['height'] > $modSettings['max_image_height']) |
|
1756
|
|
|
{ |
|
1757
|
|
|
$row['width'] = floor($row['width'] * $modSettings['max_image_height'] / $row['height']); |
|
1758
|
|
|
$row['height'] = $modSettings['max_image_height']; |
|
1759
|
|
|
} |
|
1760
|
|
|
} |
|
1761
|
|
|
|
|
1762
|
|
|
$row['filename'] = getAttachmentFilename($row['filename'], $row['id_attach'], $row['id_folder'], false, $row['file_hash']); |
|
1763
|
|
|
|
|
1764
|
|
|
// save for the template |
|
1765
|
|
|
$printattach[$row['id_msg']][] = $row; |
|
1766
|
|
|
} |
|
1767
|
|
|
} |
|
1768
|
|
|
|
|
1769
|
|
|
return $printattach; |
|
1770
|
|
|
} |
|
1771
|
|
|
|
|
1772
|
|
|
/** |
|
1773
|
|
|
* Retrieve unapproved posts of the member |
|
1774
|
|
|
* in a specific topic |
|
1775
|
|
|
* |
|
1776
|
|
|
* @param int $id_topic topic id |
|
1777
|
|
|
* @param int $id_member member id |
|
1778
|
|
|
* @return array|int empty array if no member supplied, otherwise number of posts |
|
1779
|
|
|
*/ |
|
1780
|
|
|
function unapprovedPosts($id_topic, $id_member) |
|
1781
|
|
|
{ |
|
1782
|
|
|
$db = database(); |
|
1783
|
|
|
|
|
1784
|
|
|
// not all guests are the same! |
|
1785
|
|
|
if (empty($id_member)) |
|
1786
|
|
|
return array(); |
|
1787
|
|
|
|
|
1788
|
|
|
$request = $db->query('', ' |
|
1789
|
|
|
SELECT COUNT(id_member) AS my_unapproved_posts |
|
1790
|
|
|
FROM {db_prefix}messages |
|
1791
|
|
|
WHERE id_topic = {int:current_topic} |
|
1792
|
|
|
AND id_member = {int:current_member} |
|
1793
|
|
|
AND approved = 0', |
|
1794
|
|
|
array( |
|
1795
|
|
|
'current_topic' => $id_topic, |
|
1796
|
|
|
'current_member' => $id_member, |
|
1797
|
|
|
) |
|
1798
|
|
|
); |
|
1799
|
|
|
list ($myUnapprovedPosts) = $db->fetch_row($request); |
|
1800
|
|
|
$db->free_result($request); |
|
1801
|
|
|
|
|
1802
|
|
|
return $myUnapprovedPosts; |
|
1803
|
|
|
} |
|
1804
|
|
|
|
|
1805
|
|
|
/** |
|
1806
|
|
|
* Update topic info after a successful split of a topic. |
|
1807
|
|
|
* |
|
1808
|
|
|
* @param mixed[] $options |
|
1809
|
|
|
* @param int $id_board |
|
1810
|
|
|
*/ |
|
1811
|
|
|
function updateSplitTopics($options, $id_board) |
|
1812
|
|
|
{ |
|
1813
|
|
|
$db = database(); |
|
1814
|
|
|
|
|
1815
|
|
|
// Any associated reported posts better follow... |
|
1816
|
|
|
$db->query('', ' |
|
1817
|
|
|
UPDATE {db_prefix}log_reported |
|
1818
|
|
|
SET id_topic = {int:id_topic} |
|
1819
|
|
|
WHERE id_msg IN ({array_int:split_msgs}) |
|
1820
|
|
|
AND type = {string:a_message}', |
|
1821
|
|
|
array( |
|
1822
|
|
|
'split_msgs' => $options['splitMessages'], |
|
1823
|
|
|
'id_topic' => $options['split2_ID_TOPIC'], |
|
1824
|
|
|
'a_message' => 'msg', |
|
1825
|
|
|
) |
|
1826
|
|
|
); |
|
1827
|
|
|
|
|
1828
|
|
|
// Mess with the old topic's first, last, and number of messages. |
|
1829
|
|
|
setTopicAttribute($options['split1_ID_TOPIC'], array( |
|
1830
|
|
|
'num_replies' => $options['split1_replies'], |
|
1831
|
|
|
'id_first_msg' => $options['split1_first_msg'], |
|
1832
|
|
|
'id_last_msg' => $options['split1_last_msg'], |
|
1833
|
|
|
'id_member_started' => $options['split1_firstMem'], |
|
1834
|
|
|
'id_member_updated' => $options['split1_lastMem'], |
|
1835
|
|
|
'unapproved_posts' => $options['split1_unapprovedposts'], |
|
1836
|
|
|
)); |
|
1837
|
|
|
|
|
1838
|
|
|
// Now, put the first/last message back to what they should be. |
|
1839
|
|
|
setTopicAttribute($options['split2_ID_TOPIC'], array( |
|
1840
|
|
|
'id_first_msg' => $options['split2_first_msg'], |
|
1841
|
|
|
'id_last_msg' => $options['split2_last_msg'], |
|
1842
|
|
|
)); |
|
1843
|
|
|
|
|
1844
|
|
|
// If the new topic isn't approved ensure the first message flags |
|
1845
|
|
|
// this just in case. |
|
1846
|
|
|
if (!$options['split2_approved']) |
|
1847
|
|
|
$db->query('', ' |
|
1848
|
|
|
UPDATE {db_prefix}messages |
|
1849
|
|
|
SET approved = {int:approved} |
|
1850
|
|
|
WHERE id_msg = {int:id_msg} |
|
1851
|
|
|
AND id_topic = {int:id_topic}', |
|
1852
|
|
|
array( |
|
1853
|
|
|
'approved' => 0, |
|
1854
|
|
|
'id_msg' => $options['split2_first_msg'], |
|
1855
|
|
|
'id_topic' => $options['split2_ID_TOPIC'], |
|
1856
|
|
|
) |
|
1857
|
|
|
); |
|
1858
|
|
|
|
|
1859
|
|
|
// The board has more topics now (Or more unapproved ones!). |
|
1860
|
|
|
$db->query('', ' |
|
1861
|
|
|
UPDATE {db_prefix}boards |
|
1862
|
|
|
SET ' . ($options['split2_approved'] ? ' |
|
1863
|
|
|
num_topics = num_topics + 1' : ' |
|
1864
|
|
|
unapproved_topics = unapproved_topics + 1') . ' |
|
1865
|
|
|
WHERE id_board = {int:id_board}', |
|
1866
|
|
|
array( |
|
1867
|
|
|
'id_board' => $id_board, |
|
1868
|
|
|
) |
|
1869
|
|
|
); |
|
1870
|
|
|
} |
|
1871
|
|
|
|
|
1872
|
|
|
/** |
|
1873
|
|
|
* Find out who started a topic, and the lock status |
|
1874
|
|
|
* |
|
1875
|
|
|
* @param int $topic |
|
1876
|
|
|
* @return array with id_member_started and locked |
|
1877
|
|
|
*/ |
|
1878
|
|
|
function topicStatus($topic) |
|
1879
|
|
|
{ |
|
1880
|
|
|
// Find out who started the topic, and the lock status. |
|
1881
|
|
|
$starter = topicAttribute($topic, array('id_member_started', 'locked')); |
|
1882
|
|
|
|
|
1883
|
|
|
return array($starter['id_member_started'], $starter['locked']); |
|
1884
|
|
|
} |
|
1885
|
|
|
|
|
1886
|
|
|
/** |
|
1887
|
|
|
* Set attributes for a topic, i.e. locked, sticky. |
|
1888
|
|
|
* Parameter $attributes is an array where the key is the column name of the |
|
1889
|
|
|
* attribute to change, and the value is... the new value of the attribute. |
|
1890
|
|
|
* It sets the new value for the attribute as passed to it. |
|
1891
|
|
|
* <b>It is currently limited to integer values only</b> |
|
1892
|
|
|
* |
|
1893
|
|
|
* @param int|int[] $topic |
|
1894
|
|
|
* @param mixed[] $attributes |
|
1895
|
|
|
* @todo limited to integer attributes |
|
1896
|
|
|
* @return int number of row affected |
|
1897
|
|
|
*/ |
|
1898
|
|
|
function setTopicAttribute($topic, $attributes) |
|
1899
|
|
|
{ |
|
1900
|
|
|
$db = database(); |
|
1901
|
|
|
|
|
1902
|
|
|
$update = array(); |
|
1903
|
|
|
foreach ($attributes as $key => $attr) |
|
1904
|
|
|
{ |
|
1905
|
|
|
$attributes[$key] = (int) $attr; |
|
1906
|
24 |
|
$update[] = ' |
|
1907
|
|
|
' . $key . ' = {int:' . $key . '}'; |
|
1908
|
24 |
|
} |
|
1909
|
24 |
|
|
|
1910
|
|
|
if (empty($update)) |
|
1911
|
|
|
return false; |
|
1912
|
24 |
|
|
|
1913
|
16 |
|
$attributes['current_topic'] = (array) $topic; |
|
1914
|
|
|
|
|
1915
|
|
|
$db->query('', ' |
|
1916
|
|
|
UPDATE {db_prefix}topics |
|
1917
|
|
|
SET ' . implode(',', $update) . ' |
|
1918
|
24 |
|
WHERE id_topic IN ({array_int:current_topic})', |
|
1919
|
24 |
|
$attributes |
|
1920
|
24 |
|
); |
|
1921
|
16 |
|
|
|
1922
|
|
|
return $db->affected_rows(); |
|
1923
|
24 |
|
} |
|
1924
|
16 |
|
|
|
1925
|
|
|
/** |
|
1926
|
24 |
|
* Retrieve the locked or sticky status of a topic. |
|
1927
|
|
|
* |
|
1928
|
24 |
|
* @param int|int[] $id_topic topic to get the status for |
|
1929
|
|
|
* @param string|string[] $attributes Basically the column names |
|
1930
|
24 |
|
* @return array named array based on attributes requested |
|
1931
|
16 |
|
*/ |
|
1932
|
8 |
|
function topicAttribute($id_topic, $attributes) |
|
1933
|
16 |
|
{ |
|
1934
|
|
|
$db = database(); |
|
1935
|
24 |
|
|
|
1936
|
|
|
// @todo maybe add a filer for known attributes... or not |
|
1937
|
|
|
// $attributes = array( |
|
1938
|
|
|
// 'locked' => 'locked', |
|
1939
|
|
|
// 'sticky' => 'is_sticky', |
|
1940
|
|
|
// ); |
|
1941
|
|
|
|
|
1942
|
|
|
// check the lock status |
|
1943
|
|
|
$request = $db->query('', ' |
|
1944
|
|
|
SELECT {raw:attribute} |
|
1945
|
|
|
FROM {db_prefix}topics |
|
1946
|
|
|
WHERE id_topic IN ({array_int:current_topic})', |
|
1947
|
36 |
|
array( |
|
1948
|
|
|
'current_topic' => (array) $id_topic, |
|
1949
|
|
|
'attribute' => implode(',', (array) $attributes), |
|
1950
|
|
|
) |
|
1951
|
|
|
); |
|
1952
|
|
|
|
|
1953
|
|
|
if (is_array($id_topic)) |
|
1954
|
|
|
{ |
|
1955
|
|
|
$status = array(); |
|
1956
|
36 |
|
while ($row = $db->fetch_assoc($request)) |
|
1957
|
|
|
$status[] = $row; |
|
1958
|
|
|
} |
|
1959
|
24 |
|
else |
|
1960
|
|
|
{ |
|
1961
|
36 |
|
$status = $db->fetch_assoc($request); |
|
1962
|
36 |
|
} |
|
1963
|
|
|
$db->free_result($request); |
|
1964
|
24 |
|
|
|
1965
|
|
|
return $status; |
|
1966
|
36 |
|
} |
|
1967
|
24 |
|
|
|
1968
|
36 |
|
/** |
|
1969
|
36 |
|
* Retrieve some topic attributes based on the user: |
|
1970
|
36 |
|
* - locked |
|
1971
|
24 |
|
* - notify |
|
1972
|
|
|
* - is_sticky |
|
1973
|
|
|
* - id_poll |
|
1974
|
18 |
|
* - id_last_msg |
|
1975
|
|
|
* - id_member of the first message in the topic |
|
1976
|
36 |
|
* - id_first_msg |
|
1977
|
|
|
* - subject of the first message in the topic |
|
1978
|
36 |
|
* - last_post_time that is poster_time if poster_time > modified_time, or |
|
1979
|
|
|
* modified_time otherwise |
|
1980
|
|
|
* |
|
1981
|
|
|
* @param int $id_topic topic to get the status for |
|
1982
|
|
|
* @param int $user a user id |
|
1983
|
|
|
* @return mixed[] |
|
1984
|
|
|
*/ |
|
1985
|
|
|
function topicUserAttributes($id_topic, $user) |
|
1986
|
|
|
{ |
|
1987
|
|
|
$db = database(); |
|
1988
|
|
|
|
|
1989
|
|
|
$request = $db->query('', ' |
|
1990
|
|
|
SELECT |
|
1991
|
|
|
t.locked, COALESCE(ln.id_topic, 0) AS notify, t.is_sticky, t.id_poll, |
|
1992
|
|
|
t.id_last_msg, mf.id_member, t.id_first_msg, mf.subject, |
|
1993
|
|
|
CASE WHEN ml.poster_time > ml.modified_time THEN ml.poster_time ELSE ml.modified_time END AS last_post_time |
|
1994
|
|
|
FROM {db_prefix}topics AS t |
|
1995
|
|
|
LEFT JOIN {db_prefix}log_notify AS ln ON (ln.id_topic = t.id_topic AND ln.id_member = {int:current_member}) |
|
1996
|
|
|
LEFT JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_first_msg) |
|
1997
|
|
|
LEFT JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg) |
|
1998
|
|
|
WHERE t.id_topic = {int:current_topic} |
|
1999
|
|
|
LIMIT 1', |
|
2000
|
|
|
array( |
|
2001
|
|
|
'current_member' => $user, |
|
2002
|
|
|
'current_topic' => $id_topic, |
|
2003
|
|
|
) |
|
2004
|
|
|
); |
|
2005
|
|
|
$return = $db->fetch_assoc($request); |
|
2006
|
|
|
$db->free_result($request); |
|
2007
|
|
|
|
|
2008
|
|
|
return $return; |
|
2009
|
|
|
} |
|
2010
|
|
|
|
|
2011
|
|
|
/** |
|
2012
|
|
|
* Retrieve some details about the topic |
|
2013
|
|
|
* |
|
2014
|
|
|
* @param int[] $topics an array of topic id |
|
2015
|
|
|
*/ |
|
2016
|
|
|
function topicsDetails($topics) |
|
2017
|
|
|
{ |
|
2018
|
|
|
$returns = topicAttribute($topics, array('id_topic', 'id_member_started', 'id_board', 'locked', 'approved', 'unapproved_posts')); |
|
2019
|
|
|
|
|
2020
|
|
|
return $returns; |
|
2021
|
|
|
} |
|
2022
|
|
|
|
|
2023
|
|
|
/** |
|
2024
|
|
|
* Toggle sticky status for the passed topics and logs the action. |
|
2025
|
|
|
* |
|
2026
|
|
|
* @param int[] $topics |
|
2027
|
|
|
* @param bool $log If true the action is logged |
|
2028
|
|
|
* @return int Number of topics toggled |
|
2029
|
|
|
* @throws Elk_Exception |
|
2030
|
|
|
*/ |
|
2031
|
|
|
function toggleTopicSticky($topics, $log = false) |
|
2032
|
|
|
{ |
|
2033
|
|
|
$db = database(); |
|
2034
|
|
|
|
|
2035
|
|
|
$topics = is_array($topics) ? $topics : array($topics); |
|
2036
|
|
|
|
|
2037
|
|
|
$db->query('', ' |
|
2038
|
|
|
UPDATE {db_prefix}topics |
|
2039
|
|
|
SET is_sticky = CASE WHEN is_sticky = 1 THEN 0 ELSE 1 END |
|
2040
|
|
|
WHERE id_topic IN ({array_int:sticky_topic_ids})', |
|
2041
|
|
|
array( |
|
2042
|
|
|
'sticky_topic_ids' => $topics, |
|
2043
|
|
|
) |
|
2044
|
|
|
); |
|
2045
|
|
|
|
|
2046
|
|
|
$toggled = $db->affected_rows(); |
|
2047
|
|
|
|
|
2048
|
|
|
if ($log) |
|
2049
|
|
|
{ |
|
2050
|
|
|
// Get the board IDs and Sticky status |
|
2051
|
|
|
$topicAttributes = topicAttribute($topics, array('id_topic', 'id_board', 'is_sticky')); |
|
2052
|
|
|
$stickyCacheBoards = array(); |
|
2053
|
|
|
$stickyCacheStatus = array(); |
|
2054
|
|
|
foreach ($topicAttributes as $row) |
|
2055
|
|
|
{ |
|
2056
|
|
|
$stickyCacheBoards[$row['id_topic']] = $row['id_board']; |
|
2057
|
|
|
$stickyCacheStatus[$row['id_topic']] = empty($row['is_sticky']); |
|
2058
|
|
|
} |
|
2059
|
|
|
|
|
2060
|
|
|
foreach ($topics as $topic) |
|
2061
|
|
|
{ |
|
2062
|
|
|
logAction($stickyCacheStatus[$topic] ? 'unsticky' : 'sticky', array('topic' => $topic, 'board' => $stickyCacheBoards[$topic])); |
|
2063
|
|
|
sendNotifications($topic, 'sticky'); |
|
2064
|
|
|
} |
|
2065
|
|
|
} |
|
2066
|
|
|
|
|
2067
|
|
|
return $toggled; |
|
2068
|
|
|
} |
|
2069
|
|
|
|
|
2070
|
|
|
/** |
|
2071
|
|
|
* Get topics from the log_topics table belonging to a certain user |
|
2072
|
|
|
* |
|
2073
|
|
|
* @param int $member a member id |
|
2074
|
|
|
* @param int[] $topics an array of topics |
|
2075
|
|
|
* @return array an array of topics in the table (key) and its unwatched status (value) |
|
2076
|
|
|
* |
|
2077
|
|
|
* @todo find a better name |
|
2078
|
|
|
*/ |
|
2079
|
|
View Code Duplication |
function getLoggedTopics($member, $topics) |
|
|
|
|
|
|
2080
|
|
|
{ |
|
2081
|
|
|
$db = database(); |
|
2082
|
|
|
|
|
2083
|
|
|
$request = $db->query('', ' |
|
2084
|
|
|
SELECT id_topic, id_msg, unwatched |
|
2085
|
|
|
FROM {db_prefix}log_topics |
|
2086
|
|
|
WHERE id_topic IN ({array_int:selected_topics}) |
|
2087
|
|
|
AND id_member = {int:current_user}', |
|
2088
|
|
|
array( |
|
2089
|
|
|
'selected_topics' => $topics, |
|
2090
|
|
|
'current_user' => $member, |
|
2091
|
|
|
) |
|
2092
|
|
|
); |
|
2093
|
|
|
$logged_topics = array(); |
|
2094
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
2095
|
|
|
$logged_topics[$row['id_topic']] = $row; |
|
2096
|
|
|
$db->free_result($request); |
|
2097
|
|
|
|
|
2098
|
|
|
return $logged_topics; |
|
2099
|
|
|
} |
|
2100
|
|
|
|
|
2101
|
|
|
/** |
|
2102
|
|
|
* Returns a list of topics ids and their subjects |
|
2103
|
|
|
* |
|
2104
|
|
|
* @param int[] $topic_ids |
|
2105
|
|
|
*/ |
|
2106
|
|
|
function topicsList($topic_ids) |
|
2107
|
|
|
{ |
|
2108
|
|
|
global $modSettings; |
|
2109
|
|
|
|
|
2110
|
|
|
// you have to want *something* from this function |
|
2111
|
|
|
if (empty($topic_ids)) |
|
2112
|
|
|
return array(); |
|
2113
|
|
|
|
|
2114
|
|
|
$db = database(); |
|
2115
|
|
|
|
|
2116
|
|
|
$topics = array(); |
|
2117
|
|
|
|
|
2118
|
|
|
$result = $db->query('', ' |
|
2119
|
|
|
SELECT t.id_topic, m.subject |
|
2120
|
|
|
FROM {db_prefix}topics AS t |
|
2121
|
|
|
INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) |
|
2122
|
|
|
INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg) |
|
2123
|
|
|
WHERE {query_see_board} |
|
2124
|
|
|
AND t.id_topic IN ({array_int:topic_list})' . ($modSettings['postmod_active'] ? ' |
|
2125
|
|
|
AND t.approved = {int:is_approved}' : '') . ' |
|
2126
|
|
|
LIMIT {int:limit}', |
|
2127
|
|
|
array( |
|
2128
|
|
|
'topic_list' => $topic_ids, |
|
2129
|
|
|
'is_approved' => 1, |
|
2130
|
|
|
'limit' => count($topic_ids), |
|
2131
|
|
|
) |
|
2132
|
|
|
); |
|
2133
|
|
|
while ($row = $db->fetch_assoc($result)) |
|
2134
|
|
|
{ |
|
2135
|
|
|
$topics[$row['id_topic']] = array( |
|
2136
|
|
|
'id_topic' => $row['id_topic'], |
|
2137
|
|
|
'subject' => censor($row['subject']), |
|
2138
|
|
|
); |
|
2139
|
|
|
} |
|
2140
|
|
|
$db->free_result($result); |
|
2141
|
|
|
|
|
2142
|
|
|
return $topics; |
|
2143
|
|
|
} |
|
2144
|
|
|
|
|
2145
|
|
|
/** |
|
2146
|
|
|
* Get each post and poster in this topic and take care of user settings such as |
|
2147
|
|
|
* limit or sort direction. |
|
2148
|
|
|
* |
|
2149
|
|
|
* @param int $topic |
|
2150
|
|
|
* @param mixed[] $limit |
|
2151
|
|
|
* @param boolean $sort set to false for a desc sort |
|
2152
|
|
|
* @return array |
|
2153
|
|
|
*/ |
|
2154
|
|
|
function getTopicsPostsAndPoster($topic, $limit, $sort) |
|
2155
|
|
|
{ |
|
2156
|
|
|
global $modSettings, $user_info; |
|
2157
|
|
|
|
|
2158
|
|
|
$db = database(); |
|
2159
|
|
|
|
|
2160
|
|
|
$topic_details = array( |
|
2161
|
|
|
'messages' => array(), |
|
2162
|
|
|
'all_posters' => array(), |
|
2163
|
|
|
); |
|
2164
|
|
|
|
|
2165
|
|
|
$request = $db->query('display_get_post_poster', ' |
|
2166
|
|
|
SELECT id_msg, id_member, approved |
|
2167
|
|
|
FROM {db_prefix}messages |
|
2168
|
|
|
WHERE id_topic = {int:current_topic}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : ' |
|
2169
|
|
|
GROUP BY id_msg |
|
2170
|
|
|
HAVING (approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR id_member = {int:current_member}') . ')') . ' |
|
2171
|
|
|
ORDER BY id_msg ' . ($sort ? '' : 'DESC') . ($limit['messages_per_page'] == -1 ? '' : ' |
|
2172
|
|
|
LIMIT ' . $limit['start'] . ', ' . $limit['offset']), |
|
2173
|
|
|
array( |
|
2174
|
|
|
'current_member' => $user_info['id'], |
|
2175
|
|
|
'current_topic' => $topic, |
|
2176
|
|
|
'is_approved' => 1, |
|
2177
|
|
|
'blank_id_member' => 0, |
|
2178
|
|
|
) |
|
2179
|
|
|
); |
|
2180
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
2181
|
|
|
{ |
|
2182
|
|
|
if (!empty($row['id_member'])) |
|
2183
|
|
|
$topic_details['all_posters'][$row['id_msg']] = $row['id_member']; |
|
2184
|
|
|
$topic_details['messages'][] = $row['id_msg']; |
|
2185
|
|
|
} |
|
2186
|
|
|
$db->free_result($request); |
|
2187
|
|
|
|
|
2188
|
|
|
return $topic_details; |
|
2189
|
|
|
} |
|
2190
|
|
|
|
|
2191
|
|
|
/** |
|
2192
|
|
|
* Remove a batch of messages (or topics) |
|
2193
|
|
|
* |
|
2194
|
|
|
* @param int[] $messages |
|
2195
|
|
|
* @param mixed[] $messageDetails |
|
2196
|
|
|
* @param string $type = replies |
|
2197
|
|
|
* @throws Elk_Exception |
|
2198
|
|
|
*/ |
|
2199
|
|
|
function removeMessages($messages, $messageDetails, $type = 'replies') |
|
2200
|
|
|
{ |
|
2201
|
|
|
global $modSettings; |
|
2202
|
|
|
|
|
2203
|
|
|
// @todo something's not right, removeMessage() does check permissions, |
|
2204
|
|
|
// removeTopics() doesn't |
|
2205
|
|
|
if ($type == 'topics') |
|
2206
|
|
|
{ |
|
2207
|
|
|
removeTopics($messages); |
|
2208
|
|
|
|
|
2209
|
|
|
// and tell the world about it |
|
2210
|
|
|
foreach ($messages as $topic) |
|
2211
|
|
|
{ |
|
2212
|
|
|
// Note, only log topic ID in native form if it's not gone forever. |
|
2213
|
|
|
logAction('remove', array( |
|
2214
|
|
|
(empty($modSettings['recycle_enable']) || $modSettings['recycle_board'] != $messageDetails[$topic]['board'] ? 'topic' : 'old_topic_id') => $topic, 'subject' => $messageDetails[$topic]['subject'], 'member' => $messageDetails[$topic]['member'], 'board' => $messageDetails[$topic]['board'])); |
|
2215
|
|
|
} |
|
2216
|
|
|
} |
|
2217
|
|
|
else |
|
2218
|
|
|
{ |
|
2219
|
|
|
$remover = new MessagesDelete($modSettings['recycle_enable'], $modSettings['recycle_board']); |
|
2220
|
|
|
foreach ($messages as $post) |
|
2221
|
|
|
{ |
|
2222
|
|
|
$remover->removeMessage($post); |
|
2223
|
|
|
} |
|
2224
|
|
|
} |
|
2225
|
|
|
} |
|
2226
|
|
|
|
|
2227
|
|
|
/** |
|
2228
|
|
|
* Approve a batch of posts (or topics in their own right) |
|
2229
|
|
|
* |
|
2230
|
|
|
* @param int[] $messages |
|
2231
|
|
|
* @param mixed[] $messageDetails |
|
2232
|
|
|
* @param string $type = replies |
|
2233
|
|
|
* @throws Elk_Exception |
|
2234
|
|
|
*/ |
|
2235
|
|
|
function approveMessages($messages, $messageDetails, $type = 'replies') |
|
2236
|
|
|
{ |
|
2237
|
|
|
if ($type == 'topics') |
|
2238
|
|
|
{ |
|
2239
|
|
|
approveTopics($messages, true, true); |
|
2240
|
|
|
} |
|
2241
|
|
|
else |
|
2242
|
|
|
{ |
|
2243
|
|
|
require_once(SUBSDIR . '/Post.subs.php'); |
|
2244
|
|
|
approvePosts($messages); |
|
2245
|
|
|
|
|
2246
|
|
|
// and tell the world about it again |
|
2247
|
|
|
foreach ($messages as $post) |
|
2248
|
|
|
logAction('approve', array('topic' => $messageDetails[$post]['topic'], 'subject' => $messageDetails[$post]['subject'], 'member' => $messageDetails[$post]['member'], 'board' => $messageDetails[$post]['board'])); |
|
2249
|
|
|
} |
|
2250
|
|
|
} |
|
2251
|
|
|
|
|
2252
|
|
|
/** |
|
2253
|
|
|
* Approve topics, all we got. |
|
2254
|
|
|
* |
|
2255
|
|
|
* @param int[] $topics array of topics ids |
|
2256
|
|
|
* @param bool $approve = true |
|
2257
|
|
|
* @param bool $log if true logs the action. |
|
2258
|
|
|
* @throws Elk_Exception |
|
2259
|
|
|
*/ |
|
2260
|
|
|
function approveTopics($topics, $approve = true, $log = false) |
|
2261
|
|
|
{ |
|
2262
|
|
|
global $board; |
|
2263
|
|
|
|
|
2264
|
|
|
if (!is_array($topics)) |
|
2265
|
|
|
$topics = array($topics); |
|
2266
|
|
|
|
|
2267
|
|
|
if (empty($topics)) |
|
2268
|
|
|
return false; |
|
2269
|
|
|
|
|
2270
|
|
|
$db = database(); |
|
2271
|
|
|
|
|
2272
|
|
|
$approve_type = $approve ? 0 : 1; |
|
2273
|
|
|
|
|
2274
|
|
|
if ($log) |
|
2275
|
|
|
{ |
|
2276
|
|
|
$log_action = $approve ? 'approve_topic' : 'unapprove_topic'; |
|
2277
|
|
|
|
|
2278
|
|
|
// We need unapproved topic ids, their authors and the subjects! |
|
2279
|
|
|
$request = $db->query('', ' |
|
2280
|
|
|
SELECT t.id_topic, t.id_member_started, m.subject |
|
2281
|
|
|
FROM {db_prefix}topics as t |
|
2282
|
|
|
LEFT JOIN {db_prefix}messages AS m ON (t.id_first_msg = m.id_msg) |
|
2283
|
|
|
WHERE t.id_topic IN ({array_int:approve_topic_ids}) |
|
2284
|
|
|
AND t.approved = {int:approve_type} |
|
2285
|
|
|
LIMIT ' . count($topics), |
|
2286
|
|
|
array( |
|
2287
|
|
|
'approve_topic_ids' => $topics, |
|
2288
|
|
|
'approve_type' => $approve_type, |
|
2289
|
|
|
) |
|
2290
|
|
|
); |
|
2291
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
2292
|
|
|
{ |
|
2293
|
|
|
logAction($log_action, array('topic' => $row['id_topic'], 'subject' => $row['subject'], 'member' => $row['id_member_started'], 'board' => $board)); |
|
2294
|
|
|
} |
|
2295
|
|
|
$db->free_result($request); |
|
2296
|
|
|
} |
|
2297
|
|
|
|
|
2298
|
|
|
// Just get the messages to be approved and pass through... |
|
2299
|
|
|
$request = $db->query('', ' |
|
2300
|
|
|
SELECT id_msg |
|
2301
|
|
|
FROM {db_prefix}messages |
|
2302
|
|
|
WHERE id_topic IN ({array_int:topic_list}) |
|
2303
|
|
|
AND approved = {int:approve_type}', |
|
2304
|
|
|
array( |
|
2305
|
|
|
'topic_list' => $topics, |
|
2306
|
|
|
'approve_type' => $approve_type, |
|
2307
|
|
|
) |
|
2308
|
|
|
); |
|
2309
|
|
|
$msgs = array(); |
|
2310
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
2311
|
|
|
$msgs[] = $row['id_msg']; |
|
2312
|
|
|
$db->free_result($request); |
|
2313
|
|
|
|
|
2314
|
|
|
require_once(SUBSDIR . '/Post.subs.php'); |
|
2315
|
|
|
return approvePosts($msgs, $approve); |
|
2316
|
|
|
} |
|
2317
|
|
|
|
|
2318
|
|
|
/** |
|
2319
|
|
|
* Post a message at the end of the original topic |
|
2320
|
|
|
* |
|
2321
|
|
|
* @param string $reason the text that will become the message body |
|
2322
|
|
|
* @param string $subject the text that will become the message subject |
|
2323
|
|
|
* @param mixed[] $board_info some board information (at least id, name, if posts are counted) |
|
2324
|
|
|
* @param string $new_topic used to build the url for moving to a new topic |
|
2325
|
|
|
* @throws Elk_Exception |
|
2326
|
|
|
*/ |
|
2327
|
|
|
function postSplitRedirect($reason, $subject, $board_info, $new_topic) |
|
2328
|
|
|
{ |
|
2329
|
|
|
global $scripturl, $user_info, $language, $txt, $topic, $board; |
|
2330
|
|
|
|
|
2331
|
|
|
// Should be in the boardwide language. |
|
2332
|
|
|
if ($user_info['language'] != $language) |
|
2333
|
|
|
theme()->getTemplates()->loadLanguageFile('index', $language); |
|
2334
|
|
|
|
|
2335
|
|
|
preparsecode($reason); |
|
2336
|
|
|
|
|
2337
|
|
|
// Add a URL onto the message. |
|
2338
|
|
|
$reason = strtr($reason, array( |
|
2339
|
|
|
$txt['movetopic_auto_board'] => '[url=' . $scripturl . '?board=' . $board_info['id'] . '.0]' . $board_info['name'] . '[/url]', |
|
2340
|
|
|
$txt['movetopic_auto_topic'] => '[iurl]' . $scripturl . '?topic=' . $new_topic . '.0[/iurl]' |
|
2341
|
|
|
)); |
|
2342
|
|
|
|
|
2343
|
|
|
$msgOptions = array( |
|
2344
|
|
|
'subject' => $txt['split'] . ': ' . strtr(Util::htmltrim(Util::htmlspecialchars($subject)), array("\r" => '', "\n" => '', "\t" => '')), |
|
2345
|
|
|
'body' => $reason, |
|
2346
|
|
|
'icon' => 'moved', |
|
2347
|
|
|
'smileys_enabled' => 1, |
|
2348
|
|
|
); |
|
2349
|
|
|
|
|
2350
|
|
|
$topicOptions = array( |
|
2351
|
|
|
'id' => $topic, |
|
2352
|
|
|
'board' => $board, |
|
2353
|
|
|
'mark_as_read' => true, |
|
2354
|
|
|
); |
|
2355
|
|
|
|
|
2356
|
|
|
$posterOptions = array( |
|
2357
|
|
|
'id' => $user_info['id'], |
|
2358
|
|
|
'update_post_count' => empty($board_info['count_posts']), |
|
2359
|
|
|
); |
|
2360
|
|
|
|
|
2361
|
|
|
createPost($msgOptions, $topicOptions, $posterOptions); |
|
2362
|
|
|
} |
|
2363
|
|
|
|
|
2364
|
|
|
/** |
|
2365
|
|
|
* General function to split off a topic. |
|
2366
|
|
|
* creates a new topic and moves the messages with the IDs in |
|
2367
|
|
|
* array messagesToBeSplit to the new topic. |
|
2368
|
|
|
* the subject of the newly created topic is set to 'newSubject'. |
|
2369
|
|
|
* marks the newly created message as read for the user splitting it. |
|
2370
|
|
|
* updates the statistics to reflect a newly created topic. |
|
2371
|
|
|
* logs the action in the moderation log. |
|
2372
|
|
|
* a notification is sent to all users monitoring this topic. |
|
2373
|
|
|
* |
|
2374
|
|
|
* @param int $split1_ID_TOPIC |
|
2375
|
|
|
* @param int[] $splitMessages |
|
2376
|
|
|
* @param string $new_subject |
|
2377
|
|
|
* |
|
2378
|
|
|
* @return int the topic ID of the new split topic. |
|
2379
|
|
|
* @throws Elk_Exception no_posts_selected |
|
2380
|
|
|
*/ |
|
2381
|
|
|
function splitTopic($split1_ID_TOPIC, $splitMessages, $new_subject) |
|
2382
|
|
|
{ |
|
2383
|
|
|
global $txt; |
|
2384
|
|
|
|
|
2385
|
|
|
$db = database(); |
|
2386
|
|
|
|
|
2387
|
|
|
// Nothing to split? |
|
2388
|
|
|
if (empty($splitMessages)) |
|
2389
|
|
|
throw new Elk_Exception('no_posts_selected', false); |
|
2390
|
|
|
|
|
2391
|
|
|
// Get some board info. |
|
2392
|
|
|
$topicAttribute = topicAttribute($split1_ID_TOPIC, array('id_board', 'approved')); |
|
2393
|
|
|
$id_board = $topicAttribute['id_board']; |
|
2394
|
|
|
$split1_approved = $topicAttribute['approved']; |
|
2395
|
|
|
|
|
2396
|
|
|
// Find the new first and last not in the list. (old topic) |
|
2397
|
|
|
$request = $db->query('', ' |
|
2398
|
|
|
SELECT |
|
2399
|
|
|
MIN(m.id_msg) AS myid_first_msg, MAX(m.id_msg) AS myid_last_msg, COUNT(*) AS message_count, m.approved |
|
2400
|
|
|
FROM {db_prefix}messages AS m |
|
2401
|
|
|
INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:id_topic}) |
|
2402
|
|
|
WHERE m.id_msg NOT IN ({array_int:no_msg_list}) |
|
2403
|
|
|
AND m.id_topic = {int:id_topic} |
|
2404
|
|
|
GROUP BY m.approved |
|
2405
|
|
|
ORDER BY m.approved DESC |
|
2406
|
|
|
LIMIT 2', |
|
2407
|
|
|
array( |
|
2408
|
|
|
'id_topic' => $split1_ID_TOPIC, |
|
2409
|
|
|
'no_msg_list' => $splitMessages, |
|
2410
|
|
|
) |
|
2411
|
|
|
); |
|
2412
|
|
|
// You can't select ALL the messages! |
|
2413
|
|
|
if ($db->num_rows($request) == 0) |
|
2414
|
|
|
throw new Elk_Exception('selected_all_posts', false); |
|
2415
|
|
|
|
|
2416
|
|
|
$split1_first_msg = null; |
|
2417
|
|
|
$split1_last_msg = null; |
|
2418
|
|
|
|
|
2419
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
2420
|
|
|
{ |
|
2421
|
|
|
// Get the right first and last message dependant on approved state... |
|
2422
|
|
|
if (empty($split1_first_msg) || $row['myid_first_msg'] < $split1_first_msg) |
|
2423
|
|
|
$split1_first_msg = $row['myid_first_msg']; |
|
2424
|
|
|
|
|
2425
|
|
|
if (empty($split1_last_msg) || $row['approved']) |
|
2426
|
|
|
$split1_last_msg = $row['myid_last_msg']; |
|
2427
|
|
|
|
|
2428
|
|
|
// Get the counts correct... |
|
2429
|
|
|
if ($row['approved']) |
|
2430
|
|
|
{ |
|
2431
|
|
|
$split1_replies = $row['message_count'] - 1; |
|
2432
|
|
|
$split1_unapprovedposts = 0; |
|
2433
|
|
|
} |
|
2434
|
|
|
else |
|
2435
|
|
|
{ |
|
2436
|
|
|
if (!isset($split1_replies)) |
|
2437
|
|
|
$split1_replies = 0; |
|
2438
|
|
|
// If the topic isn't approved then num replies must go up by one... as first post wouldn't be counted. |
|
2439
|
|
|
elseif (!$split1_approved) |
|
2440
|
|
|
$split1_replies++; |
|
2441
|
|
|
|
|
2442
|
|
|
$split1_unapprovedposts = $row['message_count']; |
|
2443
|
|
|
} |
|
2444
|
|
|
} |
|
2445
|
|
|
$db->free_result($request); |
|
2446
|
|
|
$split1_firstMem = getMsgMemberID($split1_first_msg); |
|
2447
|
|
|
$split1_lastMem = getMsgMemberID($split1_last_msg); |
|
2448
|
|
|
|
|
2449
|
|
|
// Find the first and last in the list. (new topic) |
|
2450
|
|
|
$request = $db->query('', ' |
|
2451
|
|
|
SELECT MIN(id_msg) AS myid_first_msg, MAX(id_msg) AS myid_last_msg, COUNT(*) AS message_count, approved |
|
2452
|
|
|
FROM {db_prefix}messages |
|
2453
|
|
|
WHERE id_msg IN ({array_int:msg_list}) |
|
2454
|
|
|
AND id_topic = {int:id_topic} |
|
2455
|
|
|
GROUP BY id_topic, approved |
|
2456
|
|
|
ORDER BY approved DESC |
|
2457
|
|
|
LIMIT 2', |
|
2458
|
|
|
array( |
|
2459
|
|
|
'msg_list' => $splitMessages, |
|
2460
|
|
|
'id_topic' => $split1_ID_TOPIC, |
|
2461
|
|
|
) |
|
2462
|
|
|
); |
|
2463
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
2464
|
|
|
{ |
|
2465
|
|
|
// As before get the right first and last message dependant on approved state... |
|
2466
|
|
|
if (empty($split2_first_msg) || $row['myid_first_msg'] < $split2_first_msg) |
|
2467
|
|
|
$split2_first_msg = $row['myid_first_msg']; |
|
2468
|
|
|
|
|
2469
|
|
|
if (empty($split2_last_msg) || $row['approved']) |
|
2470
|
|
|
$split2_last_msg = $row['myid_last_msg']; |
|
2471
|
|
|
|
|
2472
|
|
|
// Then do the counts again... |
|
2473
|
|
|
if ($row['approved']) |
|
2474
|
|
|
{ |
|
2475
|
|
|
$split2_approved = true; |
|
2476
|
|
|
$split2_replies = $row['message_count'] - 1; |
|
2477
|
|
|
$split2_unapprovedposts = 0; |
|
2478
|
|
|
} |
|
2479
|
|
|
else |
|
2480
|
|
|
{ |
|
2481
|
|
|
// Should this one be approved?? |
|
2482
|
|
|
if ($split2_first_msg == $row['myid_first_msg']) |
|
2483
|
|
|
$split2_approved = false; |
|
2484
|
|
|
|
|
2485
|
|
|
if (!isset($split2_replies)) |
|
2486
|
|
|
$split2_replies = 0; |
|
2487
|
|
|
// As before, fix number of replies. |
|
2488
|
|
|
elseif (!$split2_approved) |
|
|
|
|
|
|
2489
|
|
|
$split2_replies++; |
|
2490
|
|
|
|
|
2491
|
|
|
$split2_unapprovedposts = $row['message_count']; |
|
2492
|
|
|
} |
|
2493
|
|
|
} |
|
2494
|
|
|
$db->free_result($request); |
|
2495
|
|
|
$split2_firstMem = getMsgMemberID($split2_first_msg); |
|
|
|
|
|
|
2496
|
|
|
$split2_lastMem = getMsgMemberID($split2_last_msg); |
|
|
|
|
|
|
2497
|
|
|
|
|
2498
|
|
|
// No database changes yet, so let's double check to see if everything makes at least a little sense. |
|
2499
|
|
|
if ($split1_first_msg <= 0 || $split1_last_msg <= 0 || $split2_first_msg <= 0 || $split2_last_msg <= 0 || $split1_replies < 0 || $split2_replies < 0 || $split1_unapprovedposts < 0 || $split2_unapprovedposts < 0 || !isset($split1_approved) || !isset($split2_approved)) |
|
|
|
|
|
|
2500
|
|
|
throw new Elk_Exception('cant_find_messages'); |
|
2501
|
|
|
|
|
2502
|
|
|
// You cannot split off the first message of a topic. |
|
2503
|
|
|
if ($split1_first_msg > $split2_first_msg) |
|
2504
|
|
|
throw new Elk_Exception('split_first_post', false); |
|
2505
|
|
|
|
|
2506
|
|
|
// The message that is starting the new topic may have likes, these become topic likes |
|
2507
|
|
|
require_once(SUBSDIR . '/Likes.subs.php'); |
|
2508
|
|
|
$split2_first_msg_likes = messageLikeCount($split2_first_msg); |
|
2509
|
|
|
|
|
2510
|
|
|
// We're off to insert the new topic! Use 0 for now to avoid UNIQUE errors. |
|
2511
|
|
|
$db->insert('', |
|
2512
|
|
|
'{db_prefix}topics', |
|
2513
|
|
|
array( |
|
2514
|
|
|
'id_board' => 'int', |
|
2515
|
|
|
'id_member_started' => 'int', |
|
2516
|
|
|
'id_member_updated' => 'int', |
|
2517
|
|
|
'id_first_msg' => 'int', |
|
2518
|
|
|
'id_last_msg' => 'int', |
|
2519
|
|
|
'num_replies' => 'int', |
|
2520
|
|
|
'unapproved_posts' => 'int', |
|
2521
|
|
|
'approved' => 'int', |
|
2522
|
|
|
'is_sticky' => 'int', |
|
2523
|
|
|
'num_likes' => 'int', |
|
2524
|
|
|
), |
|
2525
|
|
|
array( |
|
2526
|
|
|
(int) $id_board, $split2_firstMem, $split2_lastMem, 0, |
|
2527
|
|
|
0, $split2_replies, $split2_unapprovedposts, (int) $split2_approved, 0, $split2_first_msg_likes, |
|
2528
|
|
|
), |
|
2529
|
|
|
array('id_topic') |
|
2530
|
|
|
); |
|
2531
|
|
|
$split2_ID_TOPIC = $db->insert_id('{db_prefix}topics', 'id_topic'); |
|
2532
|
|
|
if ($split2_ID_TOPIC <= 0) |
|
2533
|
|
|
throw new Elk_Exception('cant_insert_topic'); |
|
2534
|
|
|
|
|
2535
|
|
|
// Move the messages over to the other topic. |
|
2536
|
|
|
$new_subject = strtr(Util::htmltrim(Util::htmlspecialchars($new_subject)), array("\r" => '', "\n" => '', "\t" => '')); |
|
2537
|
|
|
|
|
2538
|
|
|
// Check the subject length. |
|
2539
|
|
|
if (Util::strlen($new_subject) > 100) |
|
2540
|
|
|
$new_subject = Util::substr($new_subject, 0, 100); |
|
2541
|
|
|
|
|
2542
|
|
|
// Valid subject? |
|
2543
|
|
|
if ($new_subject != '') |
|
2544
|
|
|
{ |
|
2545
|
|
|
$db->query('', ' |
|
2546
|
|
|
UPDATE {db_prefix}messages |
|
2547
|
|
|
SET |
|
2548
|
|
|
id_topic = {int:id_topic}, |
|
2549
|
|
|
subject = CASE WHEN id_msg = {int:split_first_msg} THEN {string:new_subject} ELSE {string:new_subject_replies} END |
|
2550
|
|
|
WHERE id_msg IN ({array_int:split_msgs})', |
|
2551
|
|
|
array( |
|
2552
|
|
|
'split_msgs' => $splitMessages, |
|
2553
|
|
|
'id_topic' => $split2_ID_TOPIC, |
|
2554
|
|
|
'new_subject' => $new_subject, |
|
2555
|
|
|
'split_first_msg' => $split2_first_msg, |
|
2556
|
|
|
'new_subject_replies' => $txt['response_prefix'] . $new_subject, |
|
2557
|
|
|
) |
|
2558
|
|
|
); |
|
2559
|
|
|
|
|
2560
|
|
|
// Cache the new topics subject... we can do it now as all the subjects are the same! |
|
2561
|
|
|
require_once(SUBSDIR . '/Messages.subs.php'); |
|
2562
|
|
|
updateSubjectStats($split2_ID_TOPIC, $new_subject); |
|
2563
|
|
|
} |
|
2564
|
|
|
|
|
2565
|
|
|
// Any associated reported posts better follow... |
|
2566
|
|
|
require_once(SUBSDIR . '/Topic.subs.php'); |
|
2567
|
|
|
updateSplitTopics(array( |
|
2568
|
|
|
'splitMessages' => $splitMessages, |
|
2569
|
|
|
'split1_replies' => $split1_replies, |
|
2570
|
|
|
'split1_first_msg' => $split1_first_msg, |
|
2571
|
|
|
'split1_last_msg' => $split1_last_msg, |
|
2572
|
|
|
'split1_firstMem' => $split1_firstMem, |
|
2573
|
|
|
'split1_lastMem' => $split1_lastMem, |
|
2574
|
|
|
'split1_unapprovedposts' => $split1_unapprovedposts, |
|
2575
|
|
|
'split1_ID_TOPIC' => $split1_ID_TOPIC, |
|
2576
|
|
|
'split2_first_msg' => $split2_first_msg, |
|
2577
|
|
|
'split2_last_msg' => $split2_last_msg, |
|
2578
|
|
|
'split2_ID_TOPIC' => $split2_ID_TOPIC, |
|
2579
|
|
|
'split2_approved' => $split2_approved, |
|
2580
|
|
|
), $id_board); |
|
2581
|
|
|
|
|
2582
|
|
|
require_once(SUBSDIR . '/FollowUps.subs.php'); |
|
2583
|
|
|
|
|
2584
|
|
|
// Let's see if we can create a stronger bridge between the two topics |
|
2585
|
|
|
// @todo not sure what message from the oldest topic I should link to the new one, so I'll go with the first |
|
2586
|
|
|
linkMessages($split1_first_msg, $split2_ID_TOPIC); |
|
2587
|
|
|
|
|
2588
|
|
|
// Copy log topic entries. |
|
2589
|
|
|
// @todo This should really be chunked. |
|
2590
|
|
|
$request = $db->query('', ' |
|
2591
|
|
|
SELECT id_member, id_msg, unwatched |
|
2592
|
|
|
FROM {db_prefix}log_topics |
|
2593
|
|
|
WHERE id_topic = {int:id_topic}', |
|
2594
|
|
|
array( |
|
2595
|
|
|
'id_topic' => (int) $split1_ID_TOPIC, |
|
2596
|
|
|
) |
|
2597
|
|
|
); |
|
2598
|
|
|
if ($db->num_rows($request) > 0) |
|
2599
|
|
|
{ |
|
2600
|
|
|
$replaceEntries = array(); |
|
2601
|
|
View Code Duplication |
while ($row = $db->fetch_assoc($request)) |
|
2602
|
|
|
$replaceEntries[] = array($row['id_member'], $split2_ID_TOPIC, $row['id_msg'], $row['unwatched']); |
|
2603
|
|
|
|
|
2604
|
|
|
require_once(SUBSDIR . '/Topic.subs.php'); |
|
2605
|
|
|
markTopicsRead($replaceEntries, false); |
|
2606
|
|
|
unset($replaceEntries); |
|
2607
|
|
|
} |
|
2608
|
|
|
$db->free_result($request); |
|
2609
|
|
|
|
|
2610
|
|
|
// Housekeeping. |
|
2611
|
|
|
updateTopicStats(); |
|
2612
|
|
|
updateLastMessages($id_board); |
|
2613
|
|
|
|
|
2614
|
|
|
logAction('split', array('topic' => $split1_ID_TOPIC, 'new_topic' => $split2_ID_TOPIC, 'board' => $id_board)); |
|
2615
|
|
|
|
|
2616
|
|
|
// Notify people that this topic has been split? |
|
2617
|
|
|
require_once(SUBSDIR . '/Notification.subs.php'); |
|
2618
|
|
|
sendNotifications($split1_ID_TOPIC, 'split'); |
|
2619
|
|
|
|
|
2620
|
|
|
// If there's a search index that needs updating, update it... |
|
2621
|
|
|
$search = new \ElkArte\Search\Search; |
|
2622
|
|
|
$searchAPI = $search->findSearchAPI(); |
|
2623
|
|
|
if (is_callable(array($searchAPI, 'topicSplit'))) |
|
2624
|
|
|
$searchAPI->topicSplit($split2_ID_TOPIC, $splitMessages); |
|
2625
|
|
|
|
|
2626
|
|
|
// Return the ID of the newly created topic. |
|
2627
|
|
|
return $split2_ID_TOPIC; |
|
2628
|
|
|
} |
|
2629
|
|
|
|
|
2630
|
|
|
/** |
|
2631
|
|
|
* If we are also moving the topic somewhere else, let's try do to it |
|
2632
|
|
|
* Includes checks for permissions move_own/any, etc. |
|
2633
|
|
|
* |
|
2634
|
|
|
* @param mixed[] $boards an array containing basic info of the origin and destination boards (from splitDestinationBoard) |
|
2635
|
|
|
* @param int $totopic id of the destination topic |
|
2636
|
|
|
* @throws Elk_Exception |
|
2637
|
|
|
*/ |
|
2638
|
|
|
function splitAttemptMove($boards, $totopic) |
|
2639
|
|
|
{ |
|
2640
|
|
|
global $board, $user_info; |
|
2641
|
|
|
|
|
2642
|
|
|
$db = database(); |
|
2643
|
|
|
|
|
2644
|
|
|
// If the starting and final boards are different we have to check some permissions and stuff |
|
2645
|
|
|
if ($boards['destination']['id'] != $board) |
|
2646
|
|
|
{ |
|
2647
|
|
|
$doMove = false; |
|
2648
|
|
|
if (allowedTo('move_any')) |
|
2649
|
|
|
$doMove = true; |
|
2650
|
|
|
else |
|
2651
|
|
|
{ |
|
2652
|
|
|
$new_topic = getTopicInfo($totopic); |
|
2653
|
|
|
if ($new_topic['id_member_started'] == $user_info['id'] && allowedTo('move_own')) |
|
2654
|
|
|
$doMove = true; |
|
2655
|
|
|
} |
|
2656
|
|
|
|
|
2657
|
|
|
if ($doMove) |
|
2658
|
|
|
{ |
|
2659
|
|
|
// Update member statistics if needed |
|
2660
|
|
|
// @todo this should probably go into a function... |
|
2661
|
|
|
if ($boards['destination']['count_posts'] != $boards['current']['count_posts']) |
|
2662
|
|
|
{ |
|
2663
|
|
|
$request = $db->query('', ' |
|
2664
|
|
|
SELECT id_member |
|
2665
|
|
|
FROM {db_prefix}messages |
|
2666
|
|
|
WHERE id_topic = {int:current_topic} |
|
2667
|
|
|
AND approved = {int:is_approved}', |
|
2668
|
|
|
array( |
|
2669
|
|
|
'current_topic' => $totopic, |
|
2670
|
|
|
'is_approved' => 1, |
|
2671
|
|
|
) |
|
2672
|
|
|
); |
|
2673
|
|
|
$posters = array(); |
|
2674
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
2675
|
|
|
{ |
|
2676
|
|
|
if (!isset($posters[$row['id_member']])) |
|
2677
|
|
|
$posters[$row['id_member']] = 0; |
|
2678
|
|
|
|
|
2679
|
|
|
$posters[$row['id_member']]++; |
|
2680
|
|
|
} |
|
2681
|
|
|
$db->free_result($request); |
|
2682
|
|
|
|
|
2683
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
|
2684
|
|
View Code Duplication |
foreach ($posters as $id_member => $posts) |
|
2685
|
|
|
{ |
|
2686
|
|
|
// The board we're moving from counted posts, but not to. |
|
2687
|
|
|
if (empty($boards['current']['count_posts'])) |
|
2688
|
|
|
updateMemberData($id_member, array('posts' => 'posts - ' . $posts)); |
|
2689
|
|
|
// The reverse: from didn't, to did. |
|
2690
|
|
|
else |
|
2691
|
|
|
updateMemberData($id_member, array('posts' => 'posts + ' . $posts)); |
|
2692
|
|
|
} |
|
2693
|
|
|
} |
|
2694
|
|
|
|
|
2695
|
|
|
// And finally move it! |
|
2696
|
|
|
moveTopics($totopic, $boards['destination']['id']); |
|
2697
|
|
|
} |
|
2698
|
|
|
else |
|
2699
|
|
|
$boards['destination'] = $boards['current']; |
|
2700
|
|
|
} |
|
2701
|
|
|
} |
|
2702
|
|
|
|
|
2703
|
|
|
/** |
|
2704
|
|
|
* Retrieves information of the current and destination board of a split topic |
|
2705
|
|
|
* |
|
2706
|
|
|
* @param int $toboard |
|
2707
|
|
|
* |
|
2708
|
|
|
* @return array |
|
2709
|
|
|
* @throws Elk_Exception no_board |
|
2710
|
|
|
*/ |
|
2711
|
|
|
function splitDestinationBoard($toboard = 0) |
|
2712
|
|
|
{ |
|
2713
|
|
|
global $board, $topic; |
|
2714
|
|
|
|
|
2715
|
|
|
$current_board = boardInfo($board, $topic); |
|
2716
|
|
|
if (empty($current_board)) |
|
2717
|
|
|
throw new Elk_Exception('no_board'); |
|
2718
|
|
|
|
|
2719
|
|
|
if (!empty($toboard) && $board !== $toboard) |
|
2720
|
|
|
{ |
|
2721
|
|
|
$destination_board = boardInfo($toboard); |
|
2722
|
|
|
if (empty($destination_board)) |
|
2723
|
|
|
throw new Elk_Exception('no_board'); |
|
2724
|
|
|
} |
|
2725
|
|
|
|
|
2726
|
|
|
if (!isset($destination_board)) |
|
2727
|
|
|
$destination_board = array_merge($current_board, array('id' => $board)); |
|
2728
|
|
|
else |
|
2729
|
|
|
$destination_board['id'] = $toboard; |
|
2730
|
|
|
|
|
2731
|
|
|
return array('current' => $current_board, 'destination' => $destination_board); |
|
2732
|
|
|
} |
|
2733
|
|
|
|
|
2734
|
|
|
/** |
|
2735
|
|
|
* Retrieve topic notifications count. |
|
2736
|
|
|
* (used by createList() callbacks, amongst others.) |
|
2737
|
|
|
* |
|
2738
|
|
|
* @param int $memID id_member |
|
2739
|
|
|
* @return integer |
|
2740
|
|
|
*/ |
|
2741
|
|
|
function topicNotificationCount($memID) |
|
2742
|
|
|
{ |
|
2743
|
|
|
global $user_info, $modSettings; |
|
2744
|
|
|
|
|
2745
|
|
|
$db = database(); |
|
2746
|
|
|
|
|
2747
|
|
|
$request = $db->query('', ' |
|
2748
|
|
|
SELECT COUNT(*) |
|
2749
|
|
|
FROM {db_prefix}log_notify AS ln' . (!$modSettings['postmod_active'] && $user_info['query_see_board'] === '1=1' ? '' : ' |
|
2750
|
|
|
INNER JOIN {db_prefix}topics AS t ON (t.id_topic = ln.id_topic)') . ($user_info['query_see_board'] === '1=1' ? '' : ' |
|
2751
|
|
|
INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)') . ' |
|
2752
|
|
|
WHERE ln.id_member = {int:selected_member}' . ($user_info['query_see_board'] === '1=1' ? '' : ' |
|
2753
|
|
|
AND {query_see_board}') . ($modSettings['postmod_active'] ? ' |
|
2754
|
|
|
AND t.approved = {int:is_approved}' : ''), |
|
2755
|
|
|
array( |
|
2756
|
|
|
'selected_member' => $memID, |
|
2757
|
|
|
'is_approved' => 1, |
|
2758
|
|
|
) |
|
2759
|
|
|
); |
|
2760
|
|
|
list ($totalNotifications) = $db->fetch_row($request); |
|
2761
|
|
|
$db->free_result($request); |
|
2762
|
|
|
|
|
2763
|
|
|
return (int) $totalNotifications; |
|
2764
|
|
|
} |
|
2765
|
|
|
|
|
2766
|
|
|
/** |
|
2767
|
|
|
* Retrieve all topic notifications for the given user. |
|
2768
|
|
|
* (used by createList() callbacks) |
|
2769
|
|
|
* |
|
2770
|
|
|
* @param int $start The item to start with (for pagination purposes) |
|
2771
|
|
|
* @param int $items_per_page The number of items to show per page |
|
2772
|
|
|
* @param string $sort A string indicating how to sort the results |
|
2773
|
|
|
* @param int $memID id_member |
|
2774
|
|
|
* @return array |
|
2775
|
|
|
*/ |
|
2776
|
|
|
function topicNotifications($start, $items_per_page, $sort, $memID) |
|
2777
|
|
|
{ |
|
2778
|
|
|
global $scripturl, $user_info, $modSettings; |
|
2779
|
|
|
|
|
2780
|
|
|
$db = database(); |
|
2781
|
|
|
|
|
2782
|
|
|
// All the topics with notification on... |
|
2783
|
|
|
$request = $db->query('', ' |
|
2784
|
|
|
SELECT |
|
2785
|
|
|
COALESCE(lt.id_msg, lmr.id_msg, -1) + 1 AS new_from, b.id_board, b.name, |
|
2786
|
|
|
t.id_topic, ms.subject, ms.id_member, COALESCE(mem.real_name, ms.poster_name) AS real_name_col, |
|
2787
|
|
|
ml.id_msg_modified, ml.poster_time, ml.id_member AS id_member_updated, |
|
2788
|
|
|
COALESCE(mem2.real_name, ml.poster_name) AS last_real_name |
|
2789
|
|
|
FROM {db_prefix}log_notify AS ln |
|
2790
|
|
|
INNER JOIN {db_prefix}topics AS t ON (t.id_topic = ln.id_topic' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved}' : '') . ') |
|
2791
|
|
|
INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board AND {query_see_board}) |
|
2792
|
|
|
INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg) |
|
2793
|
|
|
INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg) |
|
2794
|
|
|
LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = ms.id_member) |
|
2795
|
|
|
LEFT JOIN {db_prefix}members AS mem2 ON (mem2.id_member = ml.id_member) |
|
2796
|
|
|
LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member}) |
|
2797
|
|
|
LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = b.id_board AND lmr.id_member = {int:current_member}) |
|
2798
|
|
|
WHERE ln.id_member = {int:selected_member} |
|
2799
|
|
|
ORDER BY {raw:sort} |
|
2800
|
|
|
LIMIT {int:offset}, {int:items_per_page}', |
|
2801
|
|
|
array( |
|
2802
|
|
|
'current_member' => $user_info['id'], |
|
2803
|
|
|
'is_approved' => 1, |
|
2804
|
|
|
'selected_member' => $memID, |
|
2805
|
|
|
'sort' => $sort, |
|
2806
|
|
|
'offset' => $start, |
|
2807
|
|
|
'items_per_page' => $items_per_page, |
|
2808
|
|
|
) |
|
2809
|
|
|
); |
|
2810
|
|
|
$notification_topics = array(); |
|
2811
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
2812
|
|
|
{ |
|
2813
|
|
|
$row['subject'] = censor($row['subject']); |
|
2814
|
|
|
|
|
2815
|
|
|
$notification_topics[] = array( |
|
2816
|
|
|
'id' => $row['id_topic'], |
|
2817
|
|
|
'poster_link' => empty($row['id_member']) ? $row['real_name_col'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name_col'] . '</a>', |
|
2818
|
|
|
'poster_updated_link' => empty($row['id_member_updated']) ? $row['last_real_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member_updated'] . '">' . $row['last_real_name'] . '</a>', |
|
2819
|
|
|
'subject' => $row['subject'], |
|
2820
|
|
|
'href' => $scripturl . '?topic=' . $row['id_topic'] . '.0', |
|
2821
|
|
|
'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0">' . $row['subject'] . '</a>', |
|
2822
|
|
|
'new' => $row['new_from'] <= $row['id_msg_modified'], |
|
2823
|
|
|
'new_from' => $row['new_from'], |
|
2824
|
|
|
'updated' => standardTime($row['poster_time']), |
|
2825
|
|
|
'new_href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['new_from'] . '#new', |
|
2826
|
|
|
'new_link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['new_from'] . '#new">' . $row['subject'] . '</a>', |
|
2827
|
|
|
'board_link' => '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['name'] . '</a>', |
|
2828
|
|
|
); |
|
2829
|
|
|
} |
|
2830
|
|
|
$db->free_result($request); |
|
2831
|
|
|
|
|
2832
|
|
|
return $notification_topics; |
|
2833
|
|
|
} |
|
2834
|
|
|
|
|
2835
|
|
|
/** |
|
2836
|
|
|
* Get a list of posters in this topic, and their posts counts in the topic. |
|
2837
|
|
|
* Used to update users posts counts when topics are moved or are deleted. |
|
2838
|
|
|
* |
|
2839
|
|
|
* @param int $id_topic topic id to work with |
|
2840
|
|
|
*/ |
|
2841
|
|
|
function postersCount($id_topic) |
|
2842
|
|
|
{ |
|
2843
|
|
|
$db = database(); |
|
2844
|
|
|
|
|
2845
|
|
|
// We only care about approved topics, the rest don't count. |
|
2846
|
|
|
$request = $db->query('', ' |
|
2847
|
|
|
SELECT id_member |
|
2848
|
|
|
FROM {db_prefix}messages |
|
2849
|
|
|
WHERE id_topic = {int:current_topic} |
|
2850
|
|
|
AND approved = {int:is_approved}', |
|
2851
|
|
|
array( |
|
2852
|
|
|
'current_topic' => $id_topic, |
|
2853
|
|
|
'is_approved' => 1, |
|
2854
|
|
|
) |
|
2855
|
|
|
); |
|
2856
|
|
|
$posters = array(); |
|
2857
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
2858
|
|
|
{ |
|
2859
|
|
|
if (!isset($posters[$row['id_member']])) |
|
2860
|
|
|
$posters[$row['id_member']] = 0; |
|
2861
|
|
|
|
|
2862
|
|
|
$posters[$row['id_member']]++; |
|
2863
|
|
|
} |
|
2864
|
|
|
$db->free_result($request); |
|
2865
|
|
|
|
|
2866
|
|
|
return $posters; |
|
2867
|
|
|
} |
|
2868
|
|
|
|
|
2869
|
|
|
/** |
|
2870
|
|
|
* Counts topics from the given id_board. |
|
2871
|
|
|
* |
|
2872
|
|
|
* @param int $board |
|
2873
|
|
|
* @param bool $approved |
|
2874
|
|
|
* @return int |
|
2875
|
|
|
*/ |
|
2876
|
|
|
function countTopicsByBoard($board, $approved = false) |
|
2877
|
|
|
{ |
|
2878
|
|
|
$db = database(); |
|
2879
|
|
|
|
|
2880
|
|
|
// How many topics are on this board? (used for paging.) |
|
2881
|
|
|
$request = $db->query('', ' |
|
2882
|
|
|
SELECT COUNT(*) |
|
2883
|
|
|
FROM {db_prefix}topics AS t |
|
2884
|
|
|
WHERE t.id_board = {int:id_board}' . (empty($approved) ? ' |
|
2885
|
|
|
AND t.approved = {int:is_approved}' : ''), |
|
2886
|
|
|
array( |
|
2887
|
|
|
'id_board' => $board, |
|
2888
|
|
|
'is_approved' => 1, |
|
2889
|
|
|
) |
|
2890
|
|
|
); |
|
2891
|
|
|
list ($topics) = $db->fetch_row($request); |
|
2892
|
|
|
$db->free_result($request); |
|
2893
|
|
|
|
|
2894
|
|
|
return $topics; |
|
2895
|
|
|
} |
|
2896
|
|
|
|
|
2897
|
|
|
/** |
|
2898
|
|
|
* Determines topics which can be merged from a specific board. |
|
2899
|
|
|
* |
|
2900
|
|
|
* @param int $id_board |
|
2901
|
|
|
* @param int $id_topic |
|
2902
|
|
|
* @param bool $approved |
|
2903
|
|
|
* @param int $offset |
|
2904
|
|
|
* @return array |
|
2905
|
|
|
*/ |
|
2906
|
|
|
function mergeableTopics($id_board, $id_topic, $approved, $offset) |
|
2907
|
|
|
{ |
|
2908
|
|
|
global $modSettings, $scripturl; |
|
2909
|
|
|
|
|
2910
|
|
|
$db = database(); |
|
2911
|
|
|
|
|
2912
|
|
|
// Get some topics to merge it with. |
|
2913
|
|
|
$request = $db->query('', ' |
|
2914
|
|
|
SELECT t.id_topic, m.subject, m.id_member, COALESCE(mem.real_name, m.poster_name) AS poster_name |
|
2915
|
|
|
FROM {db_prefix}topics AS t |
|
2916
|
|
|
INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg) |
|
2917
|
|
|
LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) |
|
2918
|
|
|
WHERE t.id_board = {int:id_board} |
|
2919
|
|
|
AND t.id_topic != {int:id_topic}' . (empty($approved) ? ' |
|
2920
|
|
|
AND t.approved = {int:is_approved}' : '') . ' |
|
2921
|
|
|
ORDER BY t.is_sticky DESC, t.id_last_msg DESC |
|
2922
|
|
|
LIMIT {int:offset}, {int:limit}', |
|
2923
|
|
|
array( |
|
2924
|
|
|
'id_board' => $id_board, |
|
2925
|
|
|
'id_topic' => $id_topic, |
|
2926
|
|
|
'offset' => $offset, |
|
2927
|
|
|
'limit' => $modSettings['defaultMaxTopics'], |
|
2928
|
|
|
'is_approved' => 1, |
|
2929
|
|
|
) |
|
2930
|
|
|
); |
|
2931
|
|
|
$topics = array(); |
|
2932
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
2933
|
|
|
{ |
|
2934
|
|
|
$row['subject'] = censor($row['subject']); |
|
2935
|
|
|
|
|
2936
|
|
|
$topics[] = array( |
|
2937
|
|
|
'id' => $row['id_topic'], |
|
2938
|
|
|
'poster' => array( |
|
2939
|
|
|
'id' => $row['id_member'], |
|
2940
|
|
|
'name' => $row['poster_name'], |
|
2941
|
|
|
'href' => empty($row['id_member']) ? '' : $scripturl . '?action=profile;u=' . $row['id_member'], |
|
2942
|
|
|
'link' => empty($row['id_member']) ? $row['poster_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '" target="_blank" class="new_win">' . $row['poster_name'] . '</a>' |
|
2943
|
|
|
), |
|
2944
|
|
|
'subject' => $row['subject'], |
|
2945
|
|
|
'js_subject' => addcslashes(addslashes($row['subject']), '/') |
|
2946
|
|
|
); |
|
2947
|
|
|
} |
|
2948
|
|
|
$db->free_result($request); |
|
2949
|
|
|
|
|
2950
|
|
|
return $topics; |
|
2951
|
|
|
} |
|
2952
|
|
|
|
|
2953
|
|
|
/** |
|
2954
|
|
|
* Determines all messages from a given array of topics. |
|
2955
|
|
|
* |
|
2956
|
|
|
* @param int[] $topics integer array of topics to work with |
|
2957
|
|
|
* @return array |
|
2958
|
|
|
*/ |
|
2959
|
|
|
function messagesInTopics($topics) |
|
2960
|
|
|
{ |
|
2961
|
|
|
$db = database(); |
|
2962
|
|
|
|
|
2963
|
|
|
// Obtain all the message ids we are going to affect. |
|
2964
|
|
|
$request = $db->query('', ' |
|
2965
|
|
|
SELECT id_msg |
|
2966
|
|
|
FROM {db_prefix}messages |
|
2967
|
|
|
WHERE id_topic IN ({array_int:topic_list})', |
|
2968
|
|
|
array( |
|
2969
|
|
|
'topic_list' => $topics, |
|
2970
|
|
|
)); |
|
2971
|
|
|
$messages = array(); |
|
2972
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
2973
|
|
|
$messages[] = $row['id_msg']; |
|
2974
|
36 |
|
$db->free_result($request); |
|
2975
|
|
|
|
|
2976
|
|
|
return $messages; |
|
2977
|
36 |
|
} |
|
2978
|
|
|
|
|
2979
|
|
|
/** |
|
2980
|
24 |
|
* Retrieves the members that posted in a group of topics. |
|
2981
|
|
|
* |
|
2982
|
36 |
|
* @param int[] $topics integer array of topics to work with |
|
2983
|
24 |
|
* @return array of topics each member posted in (grouped by members) |
|
2984
|
36 |
|
*/ |
|
2985
|
36 |
|
function topicsPosters($topics) |
|
2986
|
36 |
|
{ |
|
2987
|
36 |
|
$db = database(); |
|
2988
|
|
|
|
|
2989
|
36 |
|
// Obtain all the member ids |
|
2990
|
|
|
$members = array(); |
|
2991
|
|
|
$request = $db->query('', ' |
|
2992
|
|
|
SELECT id_member, id_topic |
|
2993
|
|
|
FROM {db_prefix}messages |
|
2994
|
|
|
WHERE id_topic IN ({array_int:topic_list})', |
|
2995
|
|
|
array( |
|
2996
|
|
|
'topic_list' => $topics, |
|
2997
|
|
|
)); |
|
2998
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
2999
|
|
|
$members[$row['id_member']][] = $row['id_topic']; |
|
3000
|
|
|
$db->free_result($request); |
|
3001
|
|
|
|
|
3002
|
|
|
return $members; |
|
3003
|
|
|
} |
|
3004
|
|
|
|
|
3005
|
|
|
/** |
|
3006
|
|
|
* Updates all the tables involved when two or more topics are merged |
|
3007
|
|
|
* |
|
3008
|
|
|
* @param int $first_msg the first message of the new topic |
|
3009
|
|
|
* @param int[] $topics ids of all the topics merged |
|
3010
|
|
|
* @param int $id_topic id of the merged topic |
|
3011
|
|
|
* @param int $target_board id of the target board where the topic will resides |
|
3012
|
|
|
* @param string $target_subject subject of the new topic |
|
3013
|
|
|
* @param string $enforce_subject if not empty all the messages will be set to the same subject |
|
3014
|
|
|
* @param int[] $notifications array of topics with active notifications |
|
3015
|
|
|
*/ |
|
3016
|
|
|
function fixMergedTopics($first_msg, $topics, $id_topic, $target_board, $target_subject, $enforce_subject, $notifications) |
|
3017
|
|
|
{ |
|
3018
|
|
|
$db = database(); |
|
3019
|
|
|
|
|
3020
|
|
|
// Delete the remaining topics. |
|
3021
|
|
|
$deleted_topics = array_diff($topics, array($id_topic)); |
|
3022
|
|
|
$db->query('', ' |
|
3023
|
|
|
DELETE FROM {db_prefix}topics |
|
3024
|
|
|
WHERE id_topic IN ({array_int:deleted_topics})', |
|
3025
|
|
|
array( |
|
3026
|
|
|
'deleted_topics' => $deleted_topics, |
|
3027
|
|
|
) |
|
3028
|
|
|
); |
|
3029
|
|
|
|
|
3030
|
|
|
$db->query('', ' |
|
3031
|
|
|
DELETE FROM {db_prefix}log_search_subjects |
|
3032
|
|
|
WHERE id_topic IN ({array_int:deleted_topics})', |
|
3033
|
|
|
array( |
|
3034
|
|
|
'deleted_topics' => $deleted_topics, |
|
3035
|
|
|
) |
|
3036
|
|
|
); |
|
3037
|
|
|
|
|
3038
|
|
|
// Change the topic IDs of all messages that will be merged. Also adjust subjects if 'enforce subject' was checked. |
|
3039
|
|
|
$db->query('', ' |
|
3040
|
|
|
UPDATE {db_prefix}messages |
|
3041
|
|
|
SET |
|
3042
|
|
|
id_topic = {int:id_topic}, |
|
3043
|
|
|
id_board = {int:target_board}' . (empty($enforce_subject) ? '' : ', |
|
3044
|
|
|
subject = {string:subject}') . ' |
|
3045
|
|
|
WHERE id_topic IN ({array_int:topic_list})', |
|
3046
|
|
|
array( |
|
3047
|
|
|
'topic_list' => $topics, |
|
3048
|
|
|
'id_topic' => $id_topic, |
|
3049
|
|
|
'target_board' => $target_board, |
|
3050
|
|
|
'subject' => response_prefix() . $target_subject, |
|
3051
|
|
|
) |
|
3052
|
|
|
); |
|
3053
|
|
|
|
|
3054
|
|
|
// Any reported posts should reflect the new board. |
|
3055
|
|
|
$db->query('', ' |
|
3056
|
|
|
UPDATE {db_prefix}log_reported |
|
3057
|
|
|
SET |
|
3058
|
|
|
id_topic = {int:id_topic}, |
|
3059
|
|
|
id_board = {int:target_board} |
|
3060
|
|
|
WHERE id_topic IN ({array_int:topics_list})', |
|
3061
|
|
|
array( |
|
3062
|
|
|
'topics_list' => $topics, |
|
3063
|
|
|
'id_topic' => $id_topic, |
|
3064
|
|
|
'target_board' => $target_board, |
|
3065
|
|
|
) |
|
3066
|
|
|
); |
|
3067
|
|
|
|
|
3068
|
|
|
// Change the subject of the first message... |
|
3069
|
|
|
$db->query('', ' |
|
3070
|
|
|
UPDATE {db_prefix}messages |
|
3071
|
|
|
SET subject = {string:target_subject} |
|
3072
|
|
|
WHERE id_msg = {int:first_msg}', |
|
3073
|
|
|
array( |
|
3074
|
|
|
'first_msg' => $first_msg, |
|
3075
|
|
|
'target_subject' => $target_subject, |
|
3076
|
|
|
) |
|
3077
|
|
|
); |
|
3078
|
|
|
|
|
3079
|
|
|
// Adjust all calendar events to point to the new topic. |
|
3080
|
|
|
$db->query('', ' |
|
3081
|
|
|
UPDATE {db_prefix}calendar |
|
3082
|
|
|
SET |
|
3083
|
|
|
id_topic = {int:id_topic}, |
|
3084
|
|
|
id_board = {int:target_board} |
|
3085
|
|
|
WHERE id_topic IN ({array_int:deleted_topics})', |
|
3086
|
|
|
array( |
|
3087
|
|
|
'deleted_topics' => $deleted_topics, |
|
3088
|
|
|
'id_topic' => $id_topic, |
|
3089
|
|
|
'target_board' => $target_board, |
|
3090
|
|
|
) |
|
3091
|
|
|
); |
|
3092
|
|
|
|
|
3093
|
|
|
// Merge log topic entries. |
|
3094
|
|
|
// The unwatched setting comes from the oldest topic |
|
3095
|
|
|
$request = $db->query('', ' |
|
3096
|
|
|
SELECT id_member, MIN(id_msg) AS new_id_msg, unwatched |
|
3097
|
|
|
FROM {db_prefix}log_topics |
|
3098
|
|
|
WHERE id_topic IN ({array_int:topics}) |
|
3099
|
|
|
GROUP BY id_member', |
|
3100
|
|
|
array( |
|
3101
|
|
|
'topics' => $topics, |
|
3102
|
|
|
) |
|
3103
|
|
|
); |
|
3104
|
|
|
|
|
3105
|
|
|
if ($db->num_rows($request) > 0) |
|
3106
|
|
|
{ |
|
3107
|
|
|
$replaceEntries = array(); |
|
3108
|
|
View Code Duplication |
while ($row = $db->fetch_assoc($request)) |
|
3109
|
|
|
$replaceEntries[] = array($row['id_member'], $id_topic, $row['new_id_msg'], $row['unwatched']); |
|
3110
|
|
|
|
|
3111
|
|
|
markTopicsRead($replaceEntries, true); |
|
3112
|
|
|
unset($replaceEntries); |
|
3113
|
|
|
|
|
3114
|
|
|
// Get rid of the old log entries. |
|
3115
|
|
|
$db->query('', ' |
|
3116
|
|
|
DELETE FROM {db_prefix}log_topics |
|
3117
|
|
|
WHERE id_topic IN ({array_int:deleted_topics})', |
|
3118
|
|
|
array( |
|
3119
|
|
|
'deleted_topics' => $deleted_topics, |
|
3120
|
|
|
) |
|
3121
|
|
|
); |
|
3122
|
|
|
} |
|
3123
|
|
|
$db->free_result($request); |
|
3124
|
|
|
|
|
3125
|
|
|
if (!empty($notifications)) |
|
3126
|
|
|
{ |
|
3127
|
|
|
$request = $db->query('', ' |
|
3128
|
|
|
SELECT id_member, MAX(sent) AS sent |
|
3129
|
|
|
FROM {db_prefix}log_notify |
|
3130
|
|
|
WHERE id_topic IN ({array_int:topics_list}) |
|
3131
|
|
|
GROUP BY id_member', |
|
3132
|
|
|
array( |
|
3133
|
|
|
'topics_list' => $notifications, |
|
3134
|
|
|
) |
|
3135
|
|
|
); |
|
3136
|
|
|
if ($db->num_rows($request) > 0) |
|
3137
|
|
|
{ |
|
3138
|
|
|
$replaceEntries = array(); |
|
3139
|
|
View Code Duplication |
while ($row = $db->fetch_assoc($request)) |
|
3140
|
|
|
$replaceEntries[] = array($row['id_member'], $id_topic, 0, $row['sent']); |
|
3141
|
|
|
|
|
3142
|
|
|
$db->insert('replace', |
|
3143
|
|
|
'{db_prefix}log_notify', |
|
3144
|
|
|
array('id_member' => 'int', 'id_topic' => 'int', 'id_board' => 'int', 'sent' => 'int'), |
|
3145
|
|
|
$replaceEntries, |
|
3146
|
|
|
array('id_member', 'id_topic', 'id_board') |
|
3147
|
|
|
); |
|
3148
|
|
|
unset($replaceEntries); |
|
3149
|
|
|
|
|
3150
|
|
|
$db->query('', ' |
|
3151
|
|
|
DELETE FROM {db_prefix}log_topics |
|
3152
|
|
|
WHERE id_topic IN ({array_int:deleted_topics})', |
|
3153
|
|
|
array( |
|
3154
|
|
|
'deleted_topics' => $deleted_topics, |
|
3155
|
|
|
) |
|
3156
|
|
|
); |
|
3157
|
|
|
} |
|
3158
|
|
|
$db->free_result($request); |
|
3159
|
|
|
} |
|
3160
|
|
|
} |
|
3161
|
|
|
|
|
3162
|
|
|
/** |
|
3163
|
|
|
* Load the subject from a given topic id. |
|
3164
|
|
|
* |
|
3165
|
|
|
* @param int $id_topic |
|
3166
|
|
|
* |
|
3167
|
|
|
* @return string |
|
3168
|
|
|
* @throws Elk_Exception topic_gone |
|
3169
|
|
|
*/ |
|
3170
|
|
|
function getSubject($id_topic) |
|
3171
|
|
|
{ |
|
3172
|
|
|
global $modSettings; |
|
3173
|
|
|
|
|
3174
|
|
|
$db = database(); |
|
3175
|
|
|
|
|
3176
|
|
|
$request = $db->query('', ' |
|
3177
|
|
|
SELECT ms.subject |
|
3178
|
|
|
FROM {db_prefix}topics AS t |
|
3179
|
|
|
INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) |
|
3180
|
|
|
INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg) |
|
3181
|
|
|
WHERE t.id_topic = {int:search_topic_id} |
|
3182
|
|
|
AND {query_see_board}' . ($modSettings['postmod_active'] ? ' |
|
3183
|
|
|
AND t.approved = {int:is_approved_true}' : '') . ' |
|
3184
|
|
|
LIMIT 1', |
|
3185
|
|
|
array( |
|
3186
|
|
|
'is_approved_true' => 1, |
|
3187
|
|
|
'search_topic_id' => $id_topic, |
|
3188
|
|
|
) |
|
3189
|
|
|
); |
|
3190
|
|
|
|
|
3191
|
|
|
if ($db->num_rows($request) == 0) |
|
3192
|
|
|
throw new Elk_Exception('topic_gone', false); |
|
3193
|
|
|
|
|
3194
|
|
|
list ($subject) = $db->fetch_row($request); |
|
3195
|
|
|
$db->free_result($request); |
|
3196
|
|
|
|
|
3197
|
|
|
return $subject; |
|
3198
|
|
|
} |
|
3199
|
|
|
|
|
3200
|
|
|
/** |
|
3201
|
|
|
* This function updates the total number of topics, |
|
3202
|
|
|
* or if parameter $increment is true it simply increments them. |
|
3203
|
|
|
* |
|
3204
|
|
|
* @param bool|null $increment = null if true, increment + 1 the total topics, otherwise recount all topics |
|
3205
|
|
|
*/ |
|
3206
|
|
|
function updateTopicStats($increment = null) |
|
3207
|
|
|
{ |
|
3208
|
|
|
global $modSettings; |
|
3209
|
|
|
|
|
3210
|
|
|
$db = database(); |
|
3211
|
|
|
|
|
3212
|
|
|
if ($increment === true) |
|
3213
|
|
|
updateSettings(array('totalTopics' => true), true); |
|
3214
|
|
|
else |
|
3215
|
|
|
{ |
|
3216
|
|
|
// Get the number of topics - a SUM is better for InnoDB tables. |
|
3217
|
|
|
// We also ignore the recycle bin here because there will probably be a bunch of one-post topics there. |
|
3218
|
|
|
$request = $db->query('', ' |
|
3219
|
|
|
SELECT SUM(num_topics + unapproved_topics) AS total_topics |
|
3220
|
|
|
FROM {db_prefix}boards' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? ' |
|
3221
|
60 |
|
WHERE id_board != {int:recycle_board}' : ''), |
|
3222
|
|
|
array( |
|
3223
|
60 |
|
'recycle_board' => !empty($modSettings['recycle_board']) ? $modSettings['recycle_board'] : 0, |
|
3224
|
|
|
) |
|
3225
|
60 |
|
); |
|
3226
|
60 |
|
$row = $db->fetch_assoc($request); |
|
3227
|
|
|
$db->free_result($request); |
|
3228
|
|
|
|
|
3229
|
|
|
updateSettings(array('totalTopics' => $row['total_topics'] === null ? 0 : $row['total_topics'])); |
|
3230
|
|
|
} |
|
3231
|
36 |
|
} |
|
3232
|
|
|
|
|
3233
|
36 |
|
/** |
|
3234
|
36 |
|
* Toggles the locked status of the passed id_topic's checking for permissions. |
|
3235
|
|
|
* |
|
3236
|
36 |
|
* @param int[] $topics The topics to lock (can be an id or an array of ids). |
|
3237
|
|
|
* @param bool $log if true logs the action. |
|
3238
|
24 |
|
* @throws Elk_Exception |
|
3239
|
36 |
|
*/ |
|
3240
|
36 |
|
function toggleTopicsLock($topics, $log = false) |
|
3241
|
|
|
{ |
|
3242
|
36 |
|
global $board, $user_info; |
|
3243
|
|
|
|
|
3244
|
60 |
|
$db = database(); |
|
3245
|
|
|
|
|
3246
|
|
|
$needs_check = !empty($board) && !allowedTo('lock_any'); |
|
3247
|
|
|
$lockCache = array(); |
|
3248
|
|
|
|
|
3249
|
|
|
$topicAttribute = topicAttribute($topics, array('id_topic', 'locked', 'id_board', 'id_member_started')); |
|
3250
|
|
|
|
|
3251
|
|
|
foreach ($topicAttribute as $row) |
|
3252
|
|
|
{ |
|
3253
|
|
|
// Skip the entry if it needs to be checked and the user is not the owen and |
|
3254
|
|
|
// the topic was not locked or locked by someone with more permissions |
|
3255
|
|
|
if ($needs_check && ($user_info['id'] != $row['id_member_started'] || !in_array($row['locked'], array(0, 2)))) |
|
3256
|
|
|
continue; |
|
3257
|
|
|
|
|
3258
|
|
|
$lockCache[] = $row['id_topic']; |
|
3259
|
|
|
|
|
3260
|
|
|
if ($log) |
|
3261
|
|
|
{ |
|
3262
|
|
|
$lockStatus = empty($row['locked']) ? 'lock' : 'unlock'; |
|
3263
|
|
|
|
|
3264
|
|
|
logAction($lockStatus, array('topic' => $row['id_topic'], 'board' => $row['id_board'])); |
|
3265
|
|
|
sendNotifications($row['id_topic'], $lockStatus); |
|
3266
|
|
|
} |
|
3267
|
|
|
} |
|
3268
|
|
|
|
|
3269
|
|
|
// It could just be that *none* were their own topics... |
|
3270
|
|
|
if (!empty($lockCache)) |
|
3271
|
|
|
{ |
|
3272
|
|
|
// Alternate the locked value. |
|
3273
|
|
|
$db->query('', ' |
|
3274
|
|
|
UPDATE {db_prefix}topics |
|
3275
|
|
|
SET locked = CASE WHEN locked = {int:is_locked} THEN ' . (allowedTo('lock_any') ? '1' : '2') . ' ELSE 0 END |
|
3276
|
|
|
WHERE id_topic IN ({array_int:locked_topic_ids})', |
|
3277
|
|
|
array( |
|
3278
|
|
|
'locked_topic_ids' => $lockCache, |
|
3279
|
|
|
'is_locked' => 0, |
|
3280
|
|
|
) |
|
3281
|
|
|
); |
|
3282
|
|
|
} |
|
3283
|
|
|
} |
|
3284
|
|
|
|
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.