Issues (1014)

Sources/PostModeration.php (1 issue)

1
<?php
2
3
/**
4
 * This file's job is to handle things related to post moderation.
5
 *
6
 * Simple Machines Forum (SMF)
7
 *
8
 * @package SMF
9
 * @author Simple Machines https://www.simplemachines.org
10
 * @copyright 2022 Simple Machines and individual contributors
11
 * @license https://www.simplemachines.org/about/smf/license.php BSD
12
 *
13
 * @version 2.1.0
14
 */
15
16
if (!defined('SMF'))
17
	die('No direct access...');
18
19
/**
20
 * This is a handling function for all things post moderation.
21
 */
22
function PostModerationMain()
23
{
24
	global $sourcedir;
25
26
	// @todo We'll shift these later bud.
27
	loadLanguage('ModerationCenter');
28
	loadTemplate('ModerationCenter');
29
30
	// Probably need this...
31
	require_once($sourcedir . '/ModerationCenter.php');
32
33
	// Allowed sub-actions, you know the drill by now!
34
	$subActions = array(
35
		'approve' => 'ApproveMessage',
36
		'attachments' => 'UnapprovedAttachments',
37
		'replies' => 'UnapprovedPosts',
38
		'topics' => 'UnapprovedPosts',
39
	);
40
41
	// Pick something valid...
42
	if (!isset($_REQUEST['sa']) || !isset($subActions[$_REQUEST['sa']]))
43
		$_REQUEST['sa'] = 'replies';
44
45
	call_integration_hook('integrate_post_moderation', array(&$subActions));
46
47
	call_helper($subActions[$_REQUEST['sa']]);
48
}
49
50
/**
51
 * View all unapproved posts.
52
 */
53
function UnapprovedPosts()
54
{
55
	global $txt, $scripturl, $context, $user_info, $smcFunc, $options, $modSettings;
56
57
	$context['current_view'] = isset($_GET['sa']) && $_GET['sa'] == 'topics' ? 'topics' : 'replies';
58
	$context['page_title'] = $txt['mc_unapproved_posts'];
59
60
	// Work out what boards we can work in!
61
	$approve_boards = boardsAllowedTo('approve_posts');
62
63
	// If we filtered by board remove ones outside of this board.
64
	// @todo Put a message saying we're filtered?
65
	if (isset($_REQUEST['brd']))
66
	{
67
		$filter_board = array((int) $_REQUEST['brd']);
68
		$approve_boards = $approve_boards == array(0) ? $filter_board : array_intersect($approve_boards, $filter_board);
69
	}
70
71
	if ($approve_boards == array(0))
72
		$approve_query = '';
73
	elseif (!empty($approve_boards))
74
		$approve_query = ' AND m.id_board IN (' . implode(',', $approve_boards) . ')';
75
	// Nada, zip, etc...
76
	else
77
		$approve_query = ' AND 1=0';
78
79
	// We also need to know where we can delete topics and/or replies to.
80
	$boards_can = boardsAllowedTo(array('remove_any', 'remove_own', 'delete_own', 'delete_any', 'delete_own_replies'), true, false);
81
	if ($context['current_view'] == 'topics')
82
	{
83
		$delete_own_boards = $boards_can['remove_own'];
84
		$delete_any_boards = $boards_can['remove_any'];
85
		$delete_own_replies = array();
86
	}
87
	else
88
	{
89
		$delete_own_boards = $boards_can['delete_own'];
90
		$delete_any_boards = $boards_can['delete_any'];
91
		$delete_own_replies = $boards_can['delete_own_replies'];
92
	}
93
94
	$toAction = array();
95
	// Check if we have something to do?
96
	if (isset($_GET['approve']))
97
		$toAction[] = (int) $_GET['approve'];
98
	// Just a deletion?
99
	elseif (isset($_GET['delete']))
100
		$toAction[] = (int) $_GET['delete'];
101
	// Lots of approvals?
102
	elseif (isset($_POST['item']))
103
		foreach ($_POST['item'] as $item)
104
			$toAction[] = (int) $item;
105
106
	// What are we actually doing.
107
	if (isset($_GET['approve']) || (isset($_POST['do']) && $_POST['do'] == 'approve'))
108
		$curAction = 'approve';
109
	elseif (isset($_GET['delete']) || (isset($_POST['do']) && $_POST['do'] == 'delete'))
110
		$curAction = 'delete';
111
112
	// Right, so we have something to do?
113
	if (!empty($toAction) && isset($curAction))
114
	{
115
		checkSession('request');
116
117
		// Handy shortcut.
118
		$any_array = $curAction == 'approve' ? $approve_boards : $delete_any_boards;
119
120
		// Now for each message work out whether it's actually a topic, and what board it's on.
121
		$request = $smcFunc['db_query']('', '
122
			SELECT m.id_msg, m.id_member, m.id_board, m.subject, t.id_topic, t.id_first_msg, t.id_member_started
123
			FROM {db_prefix}messages AS m
124
				INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
125
			WHERE m.id_msg IN ({array_int:message_list})
126
				AND m.approved = {int:not_approved}
127
				AND {query_see_message_board}',
128
			array(
129
				'message_list' => $toAction,
130
				'not_approved' => 0,
131
			)
132
		);
133
		$toAction = array();
134
		$details = array();
135
		while ($row = $smcFunc['db_fetch_assoc']($request))
136
		{
137
			// If it's not within what our view is ignore it...
138
			if (($row['id_msg'] == $row['id_first_msg'] && $context['current_view'] != 'topics') || ($row['id_msg'] != $row['id_first_msg'] && $context['current_view'] != 'replies'))
139
				continue;
140
141
			$can_add = false;
142
			// If we're approving this is simple.
143
			if ($curAction == 'approve' && ($any_array == array(0) || in_array($row['id_board'], $any_array)))
144
			{
145
				$can_add = true;
146
			}
147
			// Delete requires more permission checks...
148
			elseif ($curAction == 'delete')
149
			{
150
				// Own post is easy!
151
				if ($row['id_member'] == $user_info['id'] && ($delete_own_boards == array(0) || in_array($row['id_board'], $delete_own_boards)))
152
					$can_add = true;
153
				// Is it a reply to their own topic?
154
				elseif ($row['id_member'] == $row['id_member_started'] && $row['id_msg'] != $row['id_first_msg'] && ($delete_own_replies == array(0) || in_array($row['id_board'], $delete_own_replies)))
155
					$can_add = true;
156
				// Someone elses?
157
				elseif ($row['id_member'] != $user_info['id'] && ($delete_any_boards == array(0) || in_array($row['id_board'], $delete_any_boards)))
158
					$can_add = true;
159
			}
160
161
			if ($can_add)
162
				$anItem = $context['current_view'] == 'topics' ? $row['id_topic'] : $row['id_msg'];
163
			$toAction[] = $anItem;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $anItem does not seem to be defined for all execution paths leading up to this point.
Loading history...
164
165
			// All clear. What have we got now, what, what?
166
			$details[$anItem] = array();
167
			$details[$anItem]["subject"] = $row['subject'];
168
			$details[$anItem]["topic"] = $row['id_topic'];
169
			$details[$anItem]["member"] = ($context['current_view'] == 'topics') ? $row['id_member_started'] : $row['id_member'];
170
			$details[$anItem]["board"] = $row['id_board'];
171
		}
172
		$smcFunc['db_free_result']($request);
173
174
		// If we have anything left we can actually do the approving (etc).
175
		if (!empty($toAction))
176
		{
177
			if ($curAction == 'approve')
178
			{
179
				approveMessages($toAction, $details, $context['current_view']);
180
			}
181
			else
182
			{
183
				removeMessages($toAction, $details, $context['current_view']);
184
			}
185
		}
186
	}
187
188
	// How many unapproved posts are there?
189
	$request = $smcFunc['db_query']('', '
190
		SELECT COUNT(*)
191
		FROM {db_prefix}messages AS m
192
			INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic AND t.id_first_msg != m.id_msg)
193
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
194
		WHERE m.approved = {int:not_approved}
195
			AND {query_see_board}
196
			' . $approve_query,
197
		array(
198
			'not_approved' => 0,
199
		)
200
	);
201
	list ($context['total_unapproved_posts']) = $smcFunc['db_fetch_row']($request);
202
	$smcFunc['db_free_result']($request);
203
204
	// What about topics?  Normally we'd use the table alias t for topics but lets use m so we don't have to redo our approve query.
205
	$request = $smcFunc['db_query']('', '
206
		SELECT COUNT(*)
207
		FROM {db_prefix}topics AS m
208
		WHERE m.approved = {int:not_approved}
209
			AND {query_see_message_board}
210
			' . $approve_query,
211
		array(
212
			'not_approved' => 0,
213
		)
214
	);
215
	list ($context['total_unapproved_topics']) = $smcFunc['db_fetch_row']($request);
216
	$smcFunc['db_free_result']($request);
217
218
	// Limit to how many? (obey the user setting)
219
	$limit = !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages'];
220
221
	$context['page_index'] = constructPageIndex($scripturl . '?action=moderate;area=postmod;sa=' . $context['current_view'] . (isset($_REQUEST['brd']) ? ';brd=' . (int) $_REQUEST['brd'] : ''), $_GET['start'], $context['current_view'] == 'topics' ? $context['total_unapproved_topics'] : $context['total_unapproved_posts'], $limit);
222
	$context['start'] = $_GET['start'];
223
224
	// We have enough to make some pretty tabs!
225
	$context[$context['moderation_menu_name']]['tab_data'] = array(
226
		'title' => $txt['mc_unapproved_posts'],
227
		'help' => 'postmod',
228
		'description' => $txt['mc_unapproved_posts_desc'],
229
	);
230
231
	// Update the tabs with the correct number of posts.
232
	$context['menu_data_' . $context['moderation_menu_id']]['sections']['posts']['areas']['postmod']['subsections']['posts']['label'] .= ' (' . $context['total_unapproved_posts'] . ')';
233
	$context['menu_data_' . $context['moderation_menu_id']]['sections']['posts']['areas']['postmod']['subsections']['topics']['label'] .= ' (' . $context['total_unapproved_topics'] . ')';
234
235
	// If we are filtering some boards out then make sure to send that along with the links.
236
	if (isset($_REQUEST['brd']))
237
	{
238
		$context['menu_data_' . $context['moderation_menu_id']]['sections']['posts']['areas']['postmod']['subsections']['posts']['add_params'] = ';brd=' . (int) $_REQUEST['brd'];
239
		$context['menu_data_' . $context['moderation_menu_id']]['sections']['posts']['areas']['postmod']['subsections']['topics']['add_params'] = ';brd=' . (int) $_REQUEST['brd'];
240
	}
241
242
	// Get all unapproved posts.
243
	$request = $smcFunc['db_query']('', '
244
		SELECT m.id_msg, m.id_topic, m.id_board, m.subject, m.body, m.id_member,
245
			COALESCE(mem.real_name, m.poster_name) AS poster_name, m.poster_time, m.smileys_enabled,
246
			t.id_member_started, t.id_first_msg, b.name AS board_name, c.id_cat, c.name AS cat_name
247
		FROM {db_prefix}messages AS m
248
			INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
249
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board)
250
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
251
			LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat)
252
		WHERE m.approved = {int:not_approved}
253
			AND t.id_first_msg ' . ($context['current_view'] == 'topics' ? '=' : '!=') . ' m.id_msg
254
			AND {query_see_board}
255
			' . $approve_query . '
256
		LIMIT {int:start}, {int:limit}',
257
		array(
258
			'not_approved' => 0,
259
			'start' => $context['start'],
260
			'limit' => $limit,
261
		)
262
	);
263
	$context['unapproved_items'] = array();
264
	for ($i = 1; $row = $smcFunc['db_fetch_assoc']($request); $i++)
265
	{
266
		// Can delete is complicated, let's solve it first... is it their own post?
267
		if ($row['id_member'] == $user_info['id'] && ($delete_own_boards == array(0) || in_array($row['id_board'], $delete_own_boards)))
268
			$can_delete = true;
269
		// Is it a reply to their own topic?
270
		elseif ($row['id_member'] == $row['id_member_started'] && $row['id_msg'] != $row['id_first_msg'] && ($delete_own_replies == array(0) || in_array($row['id_board'], $delete_own_replies)))
271
			$can_delete = true;
272
		// Someone elses?
273
		elseif ($row['id_member'] != $user_info['id'] && ($delete_any_boards == array(0) || in_array($row['id_board'], $delete_any_boards)))
274
			$can_delete = true;
275
		else
276
			$can_delete = false;
277
278
		$context['unapproved_items'][] = array(
279
			'id' => $row['id_msg'],
280
			'counter' => $context['start'] + $i,
281
			'href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'],
282
			'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'] . '">' . $row['subject'] . '</a>',
283
			'subject' => $row['subject'],
284
			'body' => parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']),
285
			'time' => timeformat($row['poster_time']),
286
			'poster' => array(
287
				'id' => $row['id_member'],
288
				'name' => $row['poster_name'],
289
				'link' => $row['id_member'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['poster_name'] . '</a>' : $row['poster_name'],
290
				'href' => $scripturl . '?action=profile;u=' . $row['id_member'],
291
			),
292
			'topic' => array(
293
				'id' => $row['id_topic'],
294
			),
295
			'board' => array(
296
				'id' => $row['id_board'],
297
				'name' => $row['board_name'],
298
				'link' => '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['board_name'] . '</a>',
299
			),
300
			'category' => array(
301
				'id' => $row['id_cat'],
302
				'name' => $row['cat_name'],
303
				'link' => '<a href="' . $scripturl . '#c' . $row['id_cat'] . '">' . $row['cat_name'] . '</a>',
304
			),
305
			'can_delete' => $can_delete,
306
		);
307
	}
308
	$smcFunc['db_free_result']($request);
309
310
	$context['sub_template'] = 'unapproved_posts';
311
}
312
313
/**
314
 * View all unapproved attachments.
315
 */
316
function UnapprovedAttachments()
317
{
318
	global $txt, $scripturl, $context, $sourcedir, $smcFunc, $modSettings;
319
320
	$context['page_title'] = $txt['mc_unapproved_attachments'];
321
322
	// Once again, permissions are king!
323
	$approve_boards = boardsAllowedTo('approve_posts');
324
325
	if ($approve_boards == array(0))
326
		$approve_query = '';
327
	elseif (!empty($approve_boards))
328
		$approve_query = ' AND m.id_board IN (' . implode(',', $approve_boards) . ')';
329
	else
330
		$approve_query = ' AND 1=0';
331
332
	// Get together the array of things to act on, if any.
333
	$attachments = array();
334
	if (isset($_GET['approve']))
335
		$attachments[] = (int) $_GET['approve'];
336
	elseif (isset($_GET['delete']))
337
		$attachments[] = (int) $_GET['delete'];
338
	elseif (isset($_POST['item']))
339
		foreach ($_POST['item'] as $item)
340
			$attachments[] = (int) $item;
341
342
	// Are we approving or deleting?
343
	if (isset($_GET['approve']) || (isset($_POST['do']) && $_POST['do'] == 'approve'))
344
		$curAction = 'approve';
345
	elseif (isset($_GET['delete']) || (isset($_POST['do']) && $_POST['do'] == 'delete'))
346
		$curAction = 'delete';
347
348
	// Something to do, let's do it!
349
	if (!empty($attachments) && isset($curAction))
350
	{
351
		checkSession('request');
352
353
		// This will be handy.
354
		require_once($sourcedir . '/ManageAttachments.php');
355
356
		// Confirm the attachments are eligible for changing!
357
		$request = $smcFunc['db_query']('', '
358
			SELECT a.id_attach
359
			FROM {db_prefix}attachments AS a
360
				INNER JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg)
361
			WHERE a.id_attach IN ({array_int:attachments})
362
				AND a.approved = {int:not_approved}
363
				AND a.attachment_type = {int:attachment_type}
364
				AND {query_see_message_board}
365
				' . $approve_query,
366
			array(
367
				'attachments' => $attachments,
368
				'not_approved' => 0,
369
				'attachment_type' => 0,
370
			)
371
		);
372
		$attachments = array();
373
		while ($row = $smcFunc['db_fetch_assoc']($request))
374
			$attachments[] = $row['id_attach'];
375
		$smcFunc['db_free_result']($request);
376
377
		// Assuming it wasn't all like, proper illegal, we can do the approving.
378
		if (!empty($attachments))
379
		{
380
			if ($curAction == 'approve')
381
				ApproveAttachments($attachments);
382
			else
383
				removeAttachments(array('id_attach' => $attachments, 'do_logging' => true));
384
		}
385
	}
386
387
	require_once($sourcedir . '/Subs-List.php');
388
389
	$listOptions = array(
390
		'id' => 'mc_unapproved_attach',
391
		'width' => '100%',
392
		'items_per_page' => $modSettings['defaultMaxListItems'],
393
		'no_items_label' => $txt['mc_unapproved_attachments_none_found'],
394
		'base_href' => $scripturl . '?action=moderate;area=attachmod;sa=attachments',
395
		'default_sort_col' => 'attach_name',
396
		'get_items' => array(
397
			'function' => 'list_getUnapprovedAttachments',
398
			'params' => array(
399
				$approve_query,
400
			),
401
		),
402
		'get_count' => array(
403
			'function' => 'list_getNumUnapprovedAttachments',
404
			'params' => array(
405
				$approve_query,
406
			),
407
		),
408
		'columns' => array(
409
			'attach_name' => array(
410
				'header' => array(
411
					'value' => $txt['mc_unapproved_attach_name'],
412
				),
413
				'data' => array(
414
					'db' => 'filename',
415
				),
416
				'sort' => array(
417
					'default' => 'a.filename',
418
					'reverse' => 'a.filename DESC',
419
				),
420
			),
421
			'attach_size' => array(
422
				'header' => array(
423
					'value' => $txt['mc_unapproved_attach_size'],
424
				),
425
				'data' => array(
426
					'db' => 'size',
427
				),
428
				'sort' => array(
429
					'default' => 'a.size',
430
					'reverse' => 'a.size DESC',
431
				),
432
			),
433
			'attach_poster' => array(
434
				'header' => array(
435
					'value' => $txt['mc_unapproved_attach_poster'],
436
				),
437
				'data' => array(
438
					'function' => function($data)
439
					{
440
						return $data['poster']['link'];
441
					},
442
				),
443
				'sort' => array(
444
					'default' => 'm.id_member',
445
					'reverse' => 'm.id_member DESC',
446
				),
447
			),
448
			'date' => array(
449
				'header' => array(
450
					'value' => $txt['date'],
451
					'style' => 'width: 18%;',
452
				),
453
				'data' => array(
454
					'db' => 'time',
455
					'class' => 'smalltext',
456
					'style' => 'white-space:nowrap;',
457
				),
458
				'sort' => array(
459
					'default' => 'm.poster_time',
460
					'reverse' => 'm.poster_time DESC',
461
				),
462
			),
463
			'message' => array(
464
				'header' => array(
465
					'value' => $txt['post'],
466
				),
467
				'data' => array(
468
					'function' => function($data)
469
					{
470
						return '<a href="' . $data['message']['href'] . '">' . shorten_subject($data['message']['subject'], 20) . '</a>';
471
					},
472
					'class' => 'smalltext',
473
					'style' => 'width:15em;',
474
				),
475
				'sort' => array(
476
					'default' => 'm.subject',
477
					'reverse' => 'm.subject DESC',
478
				),
479
			),
480
			'action' => array(
481
				'header' => array(
482
					'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" checked>',
483
					'style' => 'width: 4%;',
484
					'class' => 'centercol',
485
				),
486
				'data' => array(
487
					'sprintf' => array(
488
						'format' => '<input type="checkbox" name="item[]" value="%1$d" checked>',
489
						'params' => array(
490
							'id' => false,
491
						),
492
					),
493
					'class' => 'centercol',
494
				),
495
			),
496
		),
497
		'form' => array(
498
			'href' => $scripturl . '?action=moderate;area=attachmod;sa=attachments',
499
			'include_sort' => true,
500
			'include_start' => true,
501
			'hidden_fields' => array(
502
				$context['session_var'] => $context['session_id'],
503
			),
504
			'token' => 'mod-ap',
505
		),
506
		'additional_rows' => array(
507
			array(
508
				'position' => 'bottom_of_list',
509
				'value' => '
510
					<select name="do" onchange="if (this.value != 0 &amp;&amp; confirm(\'' . $txt['mc_unapproved_sure'] . '\')) submit();">
511
						<option value="0">' . $txt['with_selected'] . ':</option>
512
						<option value="0" disabled>-------------------</option>
513
						<option value="approve">&nbsp;--&nbsp;' . $txt['approve'] . '</option>
514
						<option value="delete">&nbsp;--&nbsp;' . $txt['delete'] . '</option>
515
					</select>
516
					<noscript><input type="submit" name="ml_go" value="' . $txt['go'] . '" class="button"></noscript>',
517
				'class' => 'floatright',
518
			),
519
		),
520
	);
521
522
	// Create the request list.
523
	createToken('mod-ap');
524
	createList($listOptions);
525
526
	$context['sub_template'] = 'show_list';
527
	$context['default_list'] = 'mc_unapproved_attach';
528
529
	$context[$context['moderation_menu_name']]['tab_data'] = array(
530
		'title' => $txt['mc_unapproved_attachments'],
531
		'help' => '',
532
		'description' => $txt['mc_unapproved_attachments_desc']
533
	);
534
}
535
536
/**
537
 * Callback function for UnapprovedAttachments
538
 * retrieve all the attachments waiting for approval the approver can approve
539
 *
540
 * @param int $start The item to start with (for pagination purposes)
541
 * @param int $items_per_page How many items to show on each page
542
 * @param string $sort A string indicating how to sort the results
543
 * @param string $approve_query Additional restrictions based on the boards the approver can see
544
 * @return array An array of information about the unapproved attachments
545
 */
546
function list_getUnapprovedAttachments($start, $items_per_page, $sort, $approve_query)
547
{
548
	global $smcFunc, $scripturl;
549
550
	// Get all unapproved attachments.
551
	$request = $smcFunc['db_query']('', '
552
		SELECT a.id_attach, a.filename, a.size, m.id_msg, m.id_topic, m.id_board, m.subject, m.body, m.id_member,
553
			COALESCE(mem.real_name, m.poster_name) AS poster_name, m.poster_time,
554
			t.id_member_started, t.id_first_msg, b.name AS board_name, c.id_cat, c.name AS cat_name
555
		FROM {db_prefix}attachments AS a
556
			INNER JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg)
557
			INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
558
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board)
559
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
560
			LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat)
561
		WHERE a.approved = {int:not_approved}
562
			AND a.attachment_type = {int:attachment_type}
563
			AND {query_see_board}
564
			{raw:approve_query}
565
		ORDER BY {raw:sort}
566
		LIMIT {int:start}, {int:items_per_page}',
567
		array(
568
			'not_approved' => 0,
569
			'attachment_type' => 0,
570
			'start' => $start,
571
			'sort' => $sort,
572
			'items_per_page' => $items_per_page,
573
			'approve_query' => $approve_query,
574
		)
575
	);
576
577
	$unapproved_items = array();
578
	while ($row = $smcFunc['db_fetch_assoc']($request))
579
	{
580
		$unapproved_items[] = array(
581
			'id' => $row['id_attach'],
582
			'filename' => $row['filename'],
583
			'size' => round($row['size'] / 1024, 2),
584
			'time' => timeformat($row['poster_time']),
585
			'poster' => array(
586
				'id' => $row['id_member'],
587
				'name' => $row['poster_name'],
588
				'link' => $row['id_member'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['poster_name'] . '</a>' : $row['poster_name'],
589
				'href' => $scripturl . '?action=profile;u=' . $row['id_member'],
590
			),
591
			'message' => array(
592
				'id' => $row['id_msg'],
593
				'subject' => $row['subject'],
594
				'body' => parse_bbc($row['body']),
595
				'time' => timeformat($row['poster_time']),
596
				'href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'],
597
			),
598
			'topic' => array(
599
				'id' => $row['id_topic'],
600
			),
601
			'board' => array(
602
				'id' => $row['id_board'],
603
				'name' => $row['board_name'],
604
			),
605
			'category' => array(
606
				'id' => $row['id_cat'],
607
				'name' => $row['cat_name'],
608
			),
609
		);
610
	}
611
	$smcFunc['db_free_result']($request);
612
613
	return $unapproved_items;
614
}
615
616
/**
617
 * Callback function for UnapprovedAttachments
618
 * count all the attachments waiting for approval that this approver can approve
619
 *
620
 * @param string $approve_query Additional restrictions based on the boards the approver can see
621
 * @return int The number of unapproved attachments
622
 */
623
function list_getNumUnapprovedAttachments($approve_query)
624
{
625
	global $smcFunc;
626
627
	// How many unapproved attachments in total?
628
	$request = $smcFunc['db_query']('', '
629
		SELECT COUNT(*)
630
		FROM {db_prefix}attachments AS a
631
			INNER JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg)
632
		WHERE a.approved = {int:not_approved}
633
			AND a.attachment_type = {int:attachment_type}
634
			AND {query_see_message_board}
635
			' . $approve_query,
636
		array(
637
			'not_approved' => 0,
638
			'attachment_type' => 0,
639
		)
640
	);
641
	list ($total_unapproved_attachments) = $smcFunc['db_fetch_row']($request);
642
	$smcFunc['db_free_result']($request);
643
644
	return $total_unapproved_attachments;
645
}
646
647
/**
648
 * Approve a post, just the one.
649
 */
650
function ApproveMessage()
651
{
652
	global $user_info, $topic, $board, $sourcedir, $smcFunc;
653
654
	checkSession('get');
655
656
	$_REQUEST['msg'] = (int) $_REQUEST['msg'];
657
658
	require_once($sourcedir . '/Subs-Post.php');
659
660
	isAllowedTo('approve_posts');
661
662
	$request = $smcFunc['db_query']('', '
663
		SELECT t.id_member_started, t.id_first_msg, m.id_member, m.subject, m.approved
664
		FROM {db_prefix}messages AS m
665
			INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
666
		WHERE m.id_msg = {int:id_msg}
667
			AND m.id_topic = {int:current_topic}
668
		LIMIT 1',
669
		array(
670
			'current_topic' => $topic,
671
			'id_msg' => $_REQUEST['msg'],
672
		)
673
	);
674
	list ($starter, $first_msg, $poster, $subject, $approved) = $smcFunc['db_fetch_row']($request);
675
	$smcFunc['db_free_result']($request);
676
677
	// If it's the first in a topic then the whole topic gets approved!
678
	if ($first_msg == $_REQUEST['msg'])
679
	{
680
		approveTopics($topic, !$approved);
681
682
		if ($starter != $user_info['id'])
683
			logAction(($approved ? 'un' : '') . 'approve_topic', array('topic' => $topic, 'subject' => $subject, 'member' => $starter, 'board' => $board));
684
	}
685
	else
686
	{
687
		approvePosts($_REQUEST['msg'], !$approved);
688
689
		if ($poster != $user_info['id'])
690
			logAction(($approved ? 'un' : '') . 'approve', array('topic' => $topic, 'subject' => $subject, 'member' => $poster, 'board' => $board));
691
	}
692
693
	redirectexit('topic=' . $topic . '.msg' . $_REQUEST['msg'] . '#msg' . $_REQUEST['msg']);
694
}
695
696
/**
697
 * Approve a batch of posts (or topics in their own right)
698
 *
699
 * @param array $messages The IDs of the messages to approve
700
 * @param array $messageDetails An array of information about each message, for the log
701
 * @param string $current_view What type of unapproved items we're approving - can be 'topics' or 'replies'
702
 */
703
function approveMessages($messages, $messageDetails, $current_view = 'replies')
704
{
705
	global $sourcedir;
706
707
	require_once($sourcedir . '/Subs-Post.php');
708
	if ($current_view == 'topics')
709
	{
710
		approveTopics($messages);
711
		// and tell the world about it
712
		foreach ($messages as $topic)
713
		{
714
			logAction('approve_topic', array('topic' => $topic, 'subject' => $messageDetails[$topic]['subject'], 'member' => $messageDetails[$topic]['member'], 'board' => $messageDetails[$topic]['board']));
715
		}
716
	}
717
	else
718
	{
719
		approvePosts($messages);
720
		// and tell the world about it again
721
		foreach ($messages as $post)
722
		{
723
			logAction('approve', array('topic' => $messageDetails[$post]['topic'], 'subject' => $messageDetails[$post]['subject'], 'member' => $messageDetails[$post]['member'], 'board' => $messageDetails[$post]['board']));
724
		}
725
	}
726
}
727
728
/**
729
 * This is a helper function - basically approve everything!
730
 */
731
function approveAllData()
732
{
733
	global $smcFunc, $sourcedir;
734
735
	// Start with messages and topics.
736
	$request = $smcFunc['db_query']('', '
737
		SELECT id_msg
738
		FROM {db_prefix}messages
739
		WHERE approved = {int:not_approved}',
740
		array(
741
			'not_approved' => 0,
742
		)
743
	);
744
	$msgs = array();
745
	while ($row = $smcFunc['db_fetch_row']($request))
746
		$msgs[] = $row[0];
747
	$smcFunc['db_free_result']($request);
748
749
	if (!empty($msgs))
750
	{
751
		require_once($sourcedir . '/Subs-Post.php');
752
		approvePosts($msgs);
753
	}
754
755
	// Now do attachments
756
	$request = $smcFunc['db_query']('', '
757
		SELECT id_attach
758
		FROM {db_prefix}attachments
759
		WHERE approved = {int:not_approved}',
760
		array(
761
			'not_approved' => 0,
762
		)
763
	);
764
	$attaches = array();
765
	while ($row = $smcFunc['db_fetch_row']($request))
766
		$attaches[] = $row[0];
767
	$smcFunc['db_free_result']($request);
768
769
	if (!empty($attaches))
770
	{
771
		require_once($sourcedir . '/ManageAttachments.php');
772
		ApproveAttachments($attaches);
773
	}
774
}
775
776
/**
777
 * Remove a batch of messages (or topics)
778
 *
779
 * @param array $messages The IDs of the messages to remove
780
 * @param array $messageDetails An array of information about the messages for the log
781
 * @param string $current_view What type of item we're removing - can be 'topics' or 'replies'
782
 */
783
function removeMessages($messages, $messageDetails, $current_view = 'replies')
784
{
785
	global $sourcedir, $modSettings;
786
787
	// @todo something's not right, removeMessage() does check permissions,
788
	// removeTopics() doesn't
789
	require_once($sourcedir . '/RemoveTopic.php');
790
	if ($current_view == 'topics')
791
	{
792
		removeTopics($messages);
793
		// and tell the world about it
794
		foreach ($messages as $topic)
795
			// Note, only log topic ID in native form if it's not gone forever.
796
			logAction('remove', array(
797
				(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']));
798
	}
799
	else
800
	{
801
		foreach ($messages as $post)
802
		{
803
			removeMessage($post);
804
			logAction('delete', array(
805
				(empty($modSettings['recycle_enable']) || $modSettings['recycle_board'] != $messageDetails[$post]['board'] ? 'topic' : 'old_topic_id') => $messageDetails[$post]['topic'], 'subject' => $messageDetails[$post]['subject'], 'member' => $messageDetails[$post]['member'], 'board' => $messageDetails[$post]['board']));
806
		}
807
	}
808
}
809
810
?>