comparison forum/Sources/Subs-Boards.php @ 76:e3e11437ecea website

Add forum code
author Chris Cannam
date Sun, 07 Jul 2013 11:25:48 +0200
parents
children
comparison
equal deleted inserted replaced
75:72f59aa7e503 76:e3e11437ecea
1 <?php
2
3 /**
4 * Simple Machines Forum (SMF)
5 *
6 * @package SMF
7 * @author Simple Machines http://www.simplemachines.org
8 * @copyright 2011 Simple Machines
9 * @license http://www.simplemachines.org/about/smf/license.php BSD
10 *
11 * @version 2.0
12 */
13
14 if (!defined('SMF'))
15 die('Hacking attempt...');
16
17 /* This file is mainly concerned with minor tasks relating to boards, such as
18 marking them read, collapsing categories, or quick moderation. It defines
19 the following list of functions:
20
21 void markBoardsRead(array boards)
22 // !!!
23
24 void MarkRead()
25 // !!!
26
27 int getMsgMemberID(int id_msg)
28 // !!!
29
30 void modifyBoard(int board_id, array boardOptions)
31 - general function to modify the settings and position of a board.
32 - used by ManageBoards.php to change the settings of a board.
33
34 int createBoard(array boardOptions)
35 - general function to create a new board and set its position.
36 - allows (almost) the same options as the modifyBoard() function.
37 - with the option inherit_permissions set, the parent board permissions
38 will be inherited.
39 - returns the ID of the newly created board.
40
41 void deleteBoards(array boards_to_remove, moveChildrenTo = null)
42 - general function to delete one or more boards.
43 - allows to move the children of the board before deleting it
44 - if moveChildrenTo is set to null, the child boards will be deleted.
45 - deletes all topics that are on the given boards.
46 - deletes all information that's associated with the given boards.
47 - updates the statistics to reflect the new situation.
48
49 void reorderBoards()
50 - updates the database to put all boards in the right order.
51 - sorts the records of the boards table.
52 - used by modifyBoard(), deleteBoards(), modifyCategory(), and
53 deleteCategories() functions.
54
55 void fixChildren(int parent, int newLevel, int newParent)
56 - recursively updates the children of parent's child_level and
57 id_parent to newLevel and newParent.
58 - used when a board is deleted or moved, to affect its children.
59
60 bool isChildOf(int child, int parent)
61 - determines if child is a child of parent.
62 - recurses down the tree until there are no more parents.
63 - returns true if child is a child of parent.
64
65 void getBoardTree()
66 - load information regarding the boards and categories.
67 - the information retrieved is stored in globals:
68 - $boards properties of each board.
69 - $boardList a list of boards grouped by category ID.
70 - $cat_tree properties of each category.
71
72 void recursiveBoards()
73 - function used by getBoardTree to recursively get a list of boards.
74
75 bool isChildOf(int child, int parent)
76 - determine if a certain board id is a child of another board.
77 - the parent might be several levels higher than the child.
78 */
79
80 // Mark a board or multiple boards read.
81 function markBoardsRead($boards, $unread = false)
82 {
83 global $user_info, $modSettings, $smcFunc;
84
85 // Force $boards to be an array.
86 if (!is_array($boards))
87 $boards = array($boards);
88 else
89 $boards = array_unique($boards);
90
91 // No boards, nothing to mark as read.
92 if (empty($boards))
93 return;
94
95 // Allow the user to mark a board as unread.
96 if ($unread)
97 {
98 // Clear out all the places where this lovely info is stored.
99 // !! Maybe not log_mark_read?
100 $smcFunc['db_query']('', '
101 DELETE FROM {db_prefix}log_mark_read
102 WHERE id_board IN ({array_int:board_list})
103 AND id_member = {int:current_member}',
104 array(
105 'current_member' => $user_info['id'],
106 'board_list' => $boards,
107 )
108 );
109 $smcFunc['db_query']('', '
110 DELETE FROM {db_prefix}log_boards
111 WHERE id_board IN ({array_int:board_list})
112 AND id_member = {int:current_member}',
113 array(
114 'current_member' => $user_info['id'],
115 'board_list' => $boards,
116 )
117 );
118 }
119 // Otherwise mark the board as read.
120 else
121 {
122 $markRead = array();
123 foreach ($boards as $board)
124 $markRead[] = array($modSettings['maxMsgID'], $user_info['id'], $board);
125
126 // Update log_mark_read and log_boards.
127 $smcFunc['db_insert']('replace',
128 '{db_prefix}log_mark_read',
129 array('id_msg' => 'int', 'id_member' => 'int', 'id_board' => 'int'),
130 $markRead,
131 array('id_board', 'id_member')
132 );
133
134 $smcFunc['db_insert']('replace',
135 '{db_prefix}log_boards',
136 array('id_msg' => 'int', 'id_member' => 'int', 'id_board' => 'int'),
137 $markRead,
138 array('id_board', 'id_member')
139 );
140 }
141
142 // Get rid of useless log_topics data, because log_mark_read is better for it - even if marking unread - I think so...
143 $result = $smcFunc['db_query']('', '
144 SELECT MIN(id_topic)
145 FROM {db_prefix}log_topics
146 WHERE id_member = {int:current_member}',
147 array(
148 'current_member' => $user_info['id'],
149 )
150 );
151 list ($lowest_topic) = $smcFunc['db_fetch_row']($result);
152 $smcFunc['db_free_result']($result);
153
154 if (empty($lowest_topic))
155 return;
156
157 // !!!SLOW This query seems to eat it sometimes.
158 $result = $smcFunc['db_query']('', '
159 SELECT lt.id_topic
160 FROM {db_prefix}log_topics AS lt
161 INNER JOIN {db_prefix}topics AS t /*!40000 USE INDEX (PRIMARY) */ ON (t.id_topic = lt.id_topic
162 AND t.id_board IN ({array_int:board_list}))
163 WHERE lt.id_member = {int:current_member}
164 AND lt.id_topic >= {int:lowest_topic}',
165 array(
166 'current_member' => $user_info['id'],
167 'board_list' => $boards,
168 'lowest_topic' => $lowest_topic,
169 )
170 );
171 $topics = array();
172 while ($row = $smcFunc['db_fetch_assoc']($result))
173 $topics[] = $row['id_topic'];
174 $smcFunc['db_free_result']($result);
175
176 if (!empty($topics))
177 $smcFunc['db_query']('', '
178 DELETE FROM {db_prefix}log_topics
179 WHERE id_member = {int:current_member}
180 AND id_topic IN ({array_int:topic_list})',
181 array(
182 'current_member' => $user_info['id'],
183 'topic_list' => $topics,
184 )
185 );
186 }
187
188 // Mark one or more boards as read.
189 function MarkRead()
190 {
191 global $board, $topic, $user_info, $board_info, $modSettings, $smcFunc;
192
193 // No Guests allowed!
194 is_not_guest();
195
196 checkSession('get');
197
198 if (isset($_REQUEST['sa']) && $_REQUEST['sa'] == 'all')
199 {
200 // Find all the boards this user can see.
201 $result = $smcFunc['db_query']('', '
202 SELECT b.id_board
203 FROM {db_prefix}boards AS b
204 WHERE {query_see_board}',
205 array(
206 )
207 );
208 $boards = array();
209 while ($row = $smcFunc['db_fetch_assoc']($result))
210 $boards[] = $row['id_board'];
211 $smcFunc['db_free_result']($result);
212
213 if (!empty($boards))
214 markBoardsRead($boards, isset($_REQUEST['unread']));
215
216 $_SESSION['id_msg_last_visit'] = $modSettings['maxMsgID'];
217 if (!empty($_SESSION['old_url']) && strpos($_SESSION['old_url'], 'action=unread') !== false)
218 redirectexit('action=unread');
219
220 if (isset($_SESSION['topicseen_cache']))
221 $_SESSION['topicseen_cache'] = array();
222
223 redirectexit();
224 }
225 elseif (isset($_REQUEST['sa']) && $_REQUEST['sa'] == 'unreadreplies')
226 {
227 // Make sure all the boards are integers!
228 $topics = explode('-', $_REQUEST['topics']);
229
230 $markRead = array();
231 foreach ($topics as $id_topic)
232 $markRead[] = array($modSettings['maxMsgID'], $user_info['id'], (int) $id_topic);
233
234 $smcFunc['db_insert']('replace',
235 '{db_prefix}log_topics',
236 array('id_msg' => 'int', 'id_member' => 'int', 'id_topic' => 'int'),
237 $markRead,
238 array('id_member', 'id_topic')
239 );
240
241 if (isset($_SESSION['topicseen_cache']))
242 $_SESSION['topicseen_cache'] = array();
243
244 redirectexit('action=unreadreplies');
245 }
246
247 // Special case: mark a topic unread!
248 elseif (isset($_REQUEST['sa']) && $_REQUEST['sa'] == 'topic')
249 {
250 // First, let's figure out what the latest message is.
251 $result = $smcFunc['db_query']('', '
252 SELECT id_first_msg, id_last_msg
253 FROM {db_prefix}topics
254 WHERE id_topic = {int:current_topic}',
255 array(
256 'current_topic' => $topic,
257 )
258 );
259 $topicinfo = $smcFunc['db_fetch_assoc']($result);
260 $smcFunc['db_free_result']($result);
261
262 if (!empty($_GET['t']))
263 {
264 // If they read the whole topic, go back to the beginning.
265 if ($_GET['t'] >= $topicinfo['id_last_msg'])
266 $earlyMsg = 0;
267 // If they want to mark the whole thing read, same.
268 elseif ($_GET['t'] <= $topicinfo['id_first_msg'])
269 $earlyMsg = 0;
270 // Otherwise, get the latest message before the named one.
271 else
272 {
273 $result = $smcFunc['db_query']('', '
274 SELECT MAX(id_msg)
275 FROM {db_prefix}messages
276 WHERE id_topic = {int:current_topic}
277 AND id_msg >= {int:id_first_msg}
278 AND id_msg < {int:topic_msg_id}',
279 array(
280 'current_topic' => $topic,
281 'topic_msg_id' => (int) $_GET['t'],
282 'id_first_msg' => $topicinfo['id_first_msg'],
283 )
284 );
285 list ($earlyMsg) = $smcFunc['db_fetch_row']($result);
286 $smcFunc['db_free_result']($result);
287 }
288 }
289 // Marking read from first page? That's the whole topic.
290 elseif ($_REQUEST['start'] == 0)
291 $earlyMsg = 0;
292 else
293 {
294 $result = $smcFunc['db_query']('', '
295 SELECT id_msg
296 FROM {db_prefix}messages
297 WHERE id_topic = {int:current_topic}
298 ORDER BY id_msg
299 LIMIT ' . (int) $_REQUEST['start'] . ', 1',
300 array(
301 'current_topic' => $topic,
302 )
303 );
304 list ($earlyMsg) = $smcFunc['db_fetch_row']($result);
305 $smcFunc['db_free_result']($result);
306
307 $earlyMsg--;
308 }
309
310 // Blam, unread!
311 $smcFunc['db_insert']('replace',
312 '{db_prefix}log_topics',
313 array('id_msg' => 'int', 'id_member' => 'int', 'id_topic' => 'int'),
314 array($earlyMsg, $user_info['id'], $topic),
315 array('id_member', 'id_topic')
316 );
317
318 redirectexit('board=' . $board . '.0');
319 }
320 else
321 {
322 $categories = array();
323 $boards = array();
324
325 if (isset($_REQUEST['c']))
326 {
327 $_REQUEST['c'] = explode(',', $_REQUEST['c']);
328 foreach ($_REQUEST['c'] as $c)
329 $categories[] = (int) $c;
330 }
331 if (isset($_REQUEST['boards']))
332 {
333 $_REQUEST['boards'] = explode(',', $_REQUEST['boards']);
334 foreach ($_REQUEST['boards'] as $b)
335 $boards[] = (int) $b;
336 }
337 if (!empty($board))
338 $boards[] = (int) $board;
339
340 if (isset($_REQUEST['children']) && !empty($boards))
341 {
342 // They want to mark the entire tree starting with the boards specified
343 // The easist thing is to just get all the boards they can see, but since we've specified the top of tree we ignore some of them
344
345 $request = $smcFunc['db_query']('', '
346 SELECT b.id_board, b.id_parent
347 FROM {db_prefix}boards AS b
348 WHERE {query_see_board}
349 AND b.child_level > {int:no_parents}
350 AND b.id_board NOT IN ({array_int:board_list})
351 ORDER BY child_level ASC
352 ',
353 array(
354 'no_parents' => 0,
355 'board_list' => $boards,
356 )
357 );
358 while ($row = $smcFunc['db_fetch_assoc']($request))
359 if (in_array($row['id_parent'], $boards))
360 $boards[] = $row['id_board'];
361 $smcFunc['db_free_result']($request);
362 }
363
364 $clauses = array();
365 $clauseParameters = array();
366 if (!empty($categories))
367 {
368 $clauses[] = 'id_cat IN ({array_int:category_list})';
369 $clauseParameters['category_list'] = $categories;
370 }
371 if (!empty($boards))
372 {
373 $clauses[] = 'id_board IN ({array_int:board_list})';
374 $clauseParameters['board_list'] = $boards;
375 }
376
377 if (empty($clauses))
378 redirectexit();
379
380 $request = $smcFunc['db_query']('', '
381 SELECT b.id_board
382 FROM {db_prefix}boards AS b
383 WHERE {query_see_board}
384 AND b.' . implode(' OR b.', $clauses),
385 array_merge($clauseParameters, array(
386 ))
387 );
388 $boards = array();
389 while ($row = $smcFunc['db_fetch_assoc']($request))
390 $boards[] = $row['id_board'];
391 $smcFunc['db_free_result']($request);
392
393 if (empty($boards))
394 redirectexit();
395
396 markBoardsRead($boards, isset($_REQUEST['unread']));
397
398 foreach ($boards as $b)
399 {
400 if (isset($_SESSION['topicseen_cache'][$b]))
401 $_SESSION['topicseen_cache'][$b] = array();
402 }
403
404 if (!isset($_REQUEST['unread']))
405 {
406 // Find all the boards this user can see.
407 $result = $smcFunc['db_query']('', '
408 SELECT b.id_board
409 FROM {db_prefix}boards AS b
410 WHERE b.id_parent IN ({array_int:parent_list})
411 AND {query_see_board}',
412 array(
413 'parent_list' => $boards,
414 )
415 );
416 if ($smcFunc['db_num_rows']($result) > 0)
417 {
418 $logBoardInserts = '';
419 while ($row = $smcFunc['db_fetch_assoc']($result))
420 $logBoardInserts[] = array($modSettings['maxMsgID'], $user_info['id'], $row['id_board']);
421
422 $smcFunc['db_insert']('replace',
423 '{db_prefix}log_boards',
424 array('id_msg' => 'int', 'id_member' => 'int', 'id_board' => 'int'),
425 $logBoardInserts,
426 array('id_member', 'id_board')
427 );
428 }
429 $smcFunc['db_free_result']($result);
430
431 if (empty($board))
432 redirectexit();
433 else
434 redirectexit('board=' . $board . '.0');
435 }
436 else
437 {
438 if (empty($board_info['parent']))
439 redirectexit();
440 else
441 redirectexit('board=' . $board_info['parent'] . '.0');
442 }
443 }
444 }
445
446 // Get the id_member associated with the specified message.
447 function getMsgMemberID($messageID)
448 {
449 global $smcFunc;
450
451 // Find the topic and make sure the member still exists.
452 $result = $smcFunc['db_query']('', '
453 SELECT IFNULL(mem.id_member, 0)
454 FROM {db_prefix}messages AS m
455 LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
456 WHERE m.id_msg = {int:selected_message}
457 LIMIT 1',
458 array(
459 'selected_message' => (int) $messageID,
460 )
461 );
462 if ($smcFunc['db_num_rows']($result) > 0)
463 list ($memberID) = $smcFunc['db_fetch_row']($result);
464 // The message doesn't even exist.
465 else
466 $memberID = 0;
467 $smcFunc['db_free_result']($result);
468
469 return (int) $memberID;
470 }
471
472 // Modify the settings and position of a board.
473 function modifyBoard($board_id, &$boardOptions)
474 {
475 global $sourcedir, $cat_tree, $boards, $boardList, $modSettings, $smcFunc;
476
477 // Get some basic information about all boards and categories.
478 getBoardTree();
479
480 // Make sure given boards and categories exist.
481 if (!isset($boards[$board_id]) || (isset($boardOptions['target_board']) && !isset($boards[$boardOptions['target_board']])) || (isset($boardOptions['target_category']) && !isset($cat_tree[$boardOptions['target_category']])))
482 fatal_lang_error('no_board');
483
484 // All things that will be updated in the database will be in $boardUpdates.
485 $boardUpdates = array();
486 $boardUpdateParameters = array();
487
488 // In case the board has to be moved
489 if (isset($boardOptions['move_to']))
490 {
491 // Move the board to the top of a given category.
492 if ($boardOptions['move_to'] == 'top')
493 {
494 $id_cat = $boardOptions['target_category'];
495 $child_level = 0;
496 $id_parent = 0;
497 $after = $cat_tree[$id_cat]['last_board_order'];
498 }
499
500 // Move the board to the bottom of a given category.
501 elseif ($boardOptions['move_to'] == 'bottom')
502 {
503 $id_cat = $boardOptions['target_category'];
504 $child_level = 0;
505 $id_parent = 0;
506 $after = 0;
507 foreach ($cat_tree[$id_cat]['children'] as $id_board => $dummy)
508 $after = max($after, $boards[$id_board]['order']);
509 }
510
511 // Make the board a child of a given board.
512 elseif ($boardOptions['move_to'] == 'child')
513 {
514 $id_cat = $boards[$boardOptions['target_board']]['category'];
515 $child_level = $boards[$boardOptions['target_board']]['level'] + 1;
516 $id_parent = $boardOptions['target_board'];
517
518 // People can be creative, in many ways...
519 if (isChildOf($id_parent, $board_id))
520 fatal_lang_error('mboards_parent_own_child_error', false);
521 elseif ($id_parent == $board_id)
522 fatal_lang_error('mboards_board_own_child_error', false);
523
524 $after = $boards[$boardOptions['target_board']]['order'];
525
526 // Check if there are already children and (if so) get the max board order.
527 if (!empty($boards[$id_parent]['tree']['children']) && empty($boardOptions['move_first_child']))
528 foreach ($boards[$id_parent]['tree']['children'] as $childBoard_id => $dummy)
529 $after = max($after, $boards[$childBoard_id]['order']);
530 }
531
532 // Place a board before or after another board, on the same child level.
533 elseif (in_array($boardOptions['move_to'], array('before', 'after')))
534 {
535 $id_cat = $boards[$boardOptions['target_board']]['category'];
536 $child_level = $boards[$boardOptions['target_board']]['level'];
537 $id_parent = $boards[$boardOptions['target_board']]['parent'];
538 $after = $boards[$boardOptions['target_board']]['order'] - ($boardOptions['move_to'] == 'before' ? 1 : 0);
539 }
540
541 // Oops...?
542 else
543 trigger_error('modifyBoard(): The move_to value \'' . $boardOptions['move_to'] . '\' is incorrect', E_USER_ERROR);
544
545 // Get a list of children of this board.
546 $childList = array();
547 recursiveBoards($childList, $boards[$board_id]['tree']);
548
549 // See if there are changes that affect children.
550 $childUpdates = array();
551 $levelDiff = $child_level - $boards[$board_id]['level'];
552 if ($levelDiff != 0)
553 $childUpdates[] = 'child_level = child_level ' . ($levelDiff > 0 ? '+ ' : '') . '{int:level_diff}';
554 if ($id_cat != $boards[$board_id]['category'])
555 $childUpdates[] = 'id_cat = {int:category}';
556
557 // Fix the children of this board.
558 if (!empty($childList) && !empty($childUpdates))
559 $smcFunc['db_query']('', '
560 UPDATE {db_prefix}boards
561 SET ' . implode(',
562 ', $childUpdates) . '
563 WHERE id_board IN ({array_int:board_list})',
564 array(
565 'board_list' => $childList,
566 'category' => $id_cat,
567 'level_diff' => $levelDiff,
568 )
569 );
570
571 // Make some room for this spot.
572 $smcFunc['db_query']('', '
573 UPDATE {db_prefix}boards
574 SET board_order = board_order + {int:new_order}
575 WHERE board_order > {int:insert_after}
576 AND id_board != {int:selected_board}',
577 array(
578 'insert_after' => $after,
579 'selected_board' => $board_id,
580 'new_order' => 1 + count($childList),
581 )
582 );
583
584 $boardUpdates[] = 'id_cat = {int:id_cat}';
585 $boardUpdates[] = 'id_parent = {int:id_parent}';
586 $boardUpdates[] = 'child_level = {int:child_level}';
587 $boardUpdates[] = 'board_order = {int:board_order}';
588 $boardUpdateParameters += array(
589 'id_cat' => $id_cat,
590 'id_parent' => $id_parent,
591 'child_level' => $child_level,
592 'board_order' => $after + 1,
593 );
594 }
595
596 // This setting is a little twisted in the database...
597 if (isset($boardOptions['posts_count']))
598 {
599 $boardUpdates[] = 'count_posts = {int:count_posts}';
600 $boardUpdateParameters['count_posts'] = $boardOptions['posts_count'] ? 0 : 1;
601 }
602
603 // Set the theme for this board.
604 if (isset($boardOptions['board_theme']))
605 {
606 $boardUpdates[] = 'id_theme = {int:id_theme}';
607 $boardUpdateParameters['id_theme'] = (int) $boardOptions['board_theme'];
608 }
609
610 // Should the board theme override the user preferred theme?
611 if (isset($boardOptions['override_theme']))
612 {
613 $boardUpdates[] = 'override_theme = {int:override_theme}';
614 $boardUpdateParameters['override_theme'] = $boardOptions['override_theme'] ? 1 : 0;
615 }
616
617 // Who's allowed to access this board.
618 if (isset($boardOptions['access_groups']))
619 {
620 $boardUpdates[] = 'member_groups = {string:member_groups}';
621 $boardUpdateParameters['member_groups'] = implode(',', $boardOptions['access_groups']);
622 }
623
624 if (isset($boardOptions['board_name']))
625 {
626 $boardUpdates[] = 'name = {string:board_name}';
627 $boardUpdateParameters['board_name'] = $boardOptions['board_name'];
628 }
629
630 if (isset($boardOptions['board_description']))
631 {
632 $boardUpdates[] = 'description = {string:board_description}';
633 $boardUpdateParameters['board_description'] = $boardOptions['board_description'];
634 }
635
636 if (isset($boardOptions['profile']))
637 {
638 $boardUpdates[] = 'id_profile = {int:profile}';
639 $boardUpdateParameters['profile'] = (int) $boardOptions['profile'];
640 }
641
642 if (isset($boardOptions['redirect']))
643 {
644 $boardUpdates[] = 'redirect = {string:redirect}';
645 $boardUpdateParameters['redirect'] = $boardOptions['redirect'];
646 }
647
648 if (isset($boardOptions['num_posts']))
649 {
650 $boardUpdates[] = 'num_posts = {int:num_posts}';
651 $boardUpdateParameters['num_posts'] = (int) $boardOptions['num_posts'];
652 }
653
654 // Do the updates (if any).
655 if (!empty($boardUpdates))
656 $request = $smcFunc['db_query']('', '
657 UPDATE {db_prefix}boards
658 SET
659 ' . implode(',
660 ', $boardUpdates) . '
661 WHERE id_board = {int:selected_board}',
662 array_merge($boardUpdateParameters, array(
663 'selected_board' => $board_id,
664 ))
665 );
666
667 // Set moderators of this board.
668 if (isset($boardOptions['moderators']) || isset($boardOptions['moderator_string']))
669 {
670 // Reset current moderators for this board - if there are any!
671 $smcFunc['db_query']('', '
672 DELETE FROM {db_prefix}moderators
673 WHERE id_board = {int:board_list}',
674 array(
675 'board_list' => $board_id,
676 )
677 );
678
679 // Validate and get the IDs of the new moderators.
680 if (isset($boardOptions['moderator_string']) && trim($boardOptions['moderator_string']) != '')
681 {
682 // Divvy out the usernames, remove extra space.
683 $moderator_string = strtr($smcFunc['htmlspecialchars']($boardOptions['moderator_string'], ENT_QUOTES), array('&quot;' => '"'));
684 preg_match_all('~"([^"]+)"~', $moderator_string, $matches);
685 $moderators = array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $moderator_string)));
686 for ($k = 0, $n = count($moderators); $k < $n; $k++)
687 {
688 $moderators[$k] = trim($moderators[$k]);
689
690 if (strlen($moderators[$k]) == 0)
691 unset($moderators[$k]);
692 }
693
694 // Find all the id_member's for the member_name's in the list.
695 if (empty($boardOptions['moderators']))
696 $boardOptions['moderators'] = array();
697 if (!empty($moderators))
698 {
699 $request = $smcFunc['db_query']('', '
700 SELECT id_member
701 FROM {db_prefix}members
702 WHERE member_name IN ({array_string:moderator_list}) OR real_name IN ({array_string:moderator_list})
703 LIMIT ' . count($moderators),
704 array(
705 'moderator_list' => $moderators,
706 )
707 );
708 while ($row = $smcFunc['db_fetch_assoc']($request))
709 $boardOptions['moderators'][] = $row['id_member'];
710 $smcFunc['db_free_result']($request);
711 }
712 }
713
714 // Add the moderators to the board.
715 if (!empty($boardOptions['moderators']))
716 {
717 $inserts = array();
718 foreach ($boardOptions['moderators'] as $moderator)
719 $inserts[] = array($board_id, $moderator);
720
721 $smcFunc['db_insert']('insert',
722 '{db_prefix}moderators',
723 array('id_board' => 'int', 'id_member' => 'int'),
724 $inserts,
725 array('id_board', 'id_member')
726 );
727 }
728
729 // Note that caches can now be wrong!
730 updateSettings(array('settings_updated' => time()));
731 }
732
733 if (isset($boardOptions['move_to']))
734 reorderBoards();
735
736 clean_cache('data');
737
738 if (empty($boardOptions['dont_log']))
739 logAction('edit_board', array('board' => $board_id), 'admin');
740 }
741
742 // Create a new board and set its properties and position.
743 function createBoard($boardOptions)
744 {
745 global $boards, $modSettings, $smcFunc;
746
747 // Trigger an error if one of the required values is not set.
748 if (!isset($boardOptions['board_name']) || trim($boardOptions['board_name']) == '' || !isset($boardOptions['move_to']) || !isset($boardOptions['target_category']))
749 trigger_error('createBoard(): One or more of the required options is not set', E_USER_ERROR);
750
751 if (in_array($boardOptions['move_to'], array('child', 'before', 'after')) && !isset($boardOptions['target_board']))
752 trigger_error('createBoard(): Target board is not set', E_USER_ERROR);
753
754 // Set every optional value to its default value.
755 $boardOptions += array(
756 'posts_count' => true,
757 'override_theme' => false,
758 'board_theme' => 0,
759 'access_groups' => array(),
760 'board_description' => '',
761 'profile' => 1,
762 'moderators' => '',
763 'inherit_permissions' => true,
764 'dont_log' => true,
765 );
766
767 // Insert a board, the settings are dealt with later.
768 $smcFunc['db_insert']('',
769 '{db_prefix}boards',
770 array(
771 'id_cat' => 'int', 'name' => 'string-255', 'description' => 'string', 'board_order' => 'int',
772 'member_groups' => 'string', 'redirect' => 'string',
773 ),
774 array(
775 $boardOptions['target_category'], $boardOptions['board_name'] , '', 0,
776 '-1,0', '',
777 ),
778 array('id_board')
779 );
780 $board_id = $smcFunc['db_insert_id']('{db_prefix}boards', 'id_board');
781
782 if (empty($board_id))
783 return 0;
784
785 // Change the board according to the given specifications.
786 modifyBoard($board_id, $boardOptions);
787
788 // Do we want the parent permissions to be inherited?
789 if ($boardOptions['inherit_permissions'])
790 {
791 getBoardTree();
792
793 if (!empty($boards[$board_id]['parent']))
794 {
795 $request = $smcFunc['db_query']('', '
796 SELECT id_profile
797 FROM {db_prefix}boards
798 WHERE id_board = {int:board_parent}
799 LIMIT 1',
800 array(
801 'board_parent' => (int) $boards[$board_id]['parent'],
802 )
803 );
804 list ($boardOptions['profile']) = $smcFunc['db_fetch_row']($request);
805 $smcFunc['db_free_result']($request);
806
807 $smcFunc['db_query']('', '
808 UPDATE {db_prefix}boards
809 SET id_profile = {int:new_profile}
810 WHERE id_board = {int:current_board}',
811 array(
812 'new_profile' => $boardOptions['profile'],
813 'current_board' => $board_id,
814 )
815 );
816 }
817 }
818
819 // Clean the data cache.
820 clean_cache('data');
821
822 // Created it.
823 logAction('add_board', array('board' => $board_id), 'admin');
824
825 // Here you are, a new board, ready to be spammed.
826 return $board_id;
827 }
828
829 // Remove one or more boards.
830 function deleteBoards($boards_to_remove, $moveChildrenTo = null)
831 {
832 global $sourcedir, $boards, $smcFunc;
833
834 // No boards to delete? Return!
835 if (empty($boards_to_remove))
836 return;
837
838 getBoardTree();
839
840 // If $moveChildrenTo is set to null, include the children in the removal.
841 if ($moveChildrenTo === null)
842 {
843 // Get a list of the child boards that will also be removed.
844 $child_boards_to_remove = array();
845 foreach ($boards_to_remove as $board_to_remove)
846 recursiveBoards($child_boards_to_remove, $boards[$board_to_remove]['tree']);
847
848 // Merge the children with their parents.
849 if (!empty($child_boards_to_remove))
850 $boards_to_remove = array_unique(array_merge($boards_to_remove, $child_boards_to_remove));
851 }
852 // Move the children to a safe home.
853 else
854 {
855 foreach ($boards_to_remove as $id_board)
856 {
857 // !!! Separate category?
858 if ($moveChildrenTo === 0)
859 fixChildren($id_board, 0, 0);
860 else
861 fixChildren($id_board, $boards[$moveChildrenTo]['level'] + 1, $moveChildrenTo);
862 }
863 }
864
865 // Delete ALL topics in the selected boards (done first so topics can't be marooned.)
866 $request = $smcFunc['db_query']('', '
867 SELECT id_topic
868 FROM {db_prefix}topics
869 WHERE id_board IN ({array_int:boards_to_remove})',
870 array(
871 'boards_to_remove' => $boards_to_remove,
872 )
873 );
874 $topics = array();
875 while ($row = $smcFunc['db_fetch_assoc']($request))
876 $topics[] = $row['id_topic'];
877 $smcFunc['db_free_result']($request);
878
879 require_once($sourcedir . '/RemoveTopic.php');
880 removeTopics($topics, false);
881
882 // Delete the board's logs.
883 $smcFunc['db_query']('', '
884 DELETE FROM {db_prefix}log_mark_read
885 WHERE id_board IN ({array_int:boards_to_remove})',
886 array(
887 'boards_to_remove' => $boards_to_remove,
888 )
889 );
890 $smcFunc['db_query']('', '
891 DELETE FROM {db_prefix}log_boards
892 WHERE id_board IN ({array_int:boards_to_remove})',
893 array(
894 'boards_to_remove' => $boards_to_remove,
895 )
896 );
897 $smcFunc['db_query']('', '
898 DELETE FROM {db_prefix}log_notify
899 WHERE id_board IN ({array_int:boards_to_remove})',
900 array(
901 'boards_to_remove' => $boards_to_remove,
902 )
903 );
904
905 // Delete this board's moderators.
906 $smcFunc['db_query']('', '
907 DELETE FROM {db_prefix}moderators
908 WHERE id_board IN ({array_int:boards_to_remove})',
909 array(
910 'boards_to_remove' => $boards_to_remove,
911 )
912 );
913
914 // Delete any extra events in the calendar.
915 $smcFunc['db_query']('', '
916 DELETE FROM {db_prefix}calendar
917 WHERE id_board IN ({array_int:boards_to_remove})',
918 array(
919 'boards_to_remove' => $boards_to_remove,
920 )
921 );
922
923 // Delete any message icons that only appear on these boards.
924 $smcFunc['db_query']('', '
925 DELETE FROM {db_prefix}message_icons
926 WHERE id_board IN ({array_int:boards_to_remove})',
927 array(
928 'boards_to_remove' => $boards_to_remove,
929 )
930 );
931
932 // Delete the boards.
933 $smcFunc['db_query']('', '
934 DELETE FROM {db_prefix}boards
935 WHERE id_board IN ({array_int:boards_to_remove})',
936 array(
937 'boards_to_remove' => $boards_to_remove,
938 )
939 );
940
941 // Latest message/topic might not be there anymore.
942 updateStats('message');
943 updateStats('topic');
944 updateSettings(array(
945 'calendar_updated' => time(),
946 ));
947
948 // Plus reset the cache to stop people getting odd results.
949 updateSettings(array('settings_updated' => time()));
950
951 // Clean the cache as well.
952 clean_cache('data');
953
954 // Let's do some serious logging.
955 foreach ($boards_to_remove as $id_board)
956 logAction('delete_board', array('boardname' => $boards[$id_board]['name']), 'admin');
957
958 reorderBoards();
959 }
960
961 // Put all boards in the right order.
962 function reorderBoards()
963 {
964 global $cat_tree, $boardList, $boards, $smcFunc;
965
966 getBoardTree();
967
968 // Set the board order for each category.
969 $board_order = 0;
970 foreach ($cat_tree as $catID => $dummy)
971 {
972 foreach ($boardList[$catID] as $boardID)
973 if ($boards[$boardID]['order'] != ++$board_order)
974 $smcFunc['db_query']('', '
975 UPDATE {db_prefix}boards
976 SET board_order = {int:new_order}
977 WHERE id_board = {int:selected_board}',
978 array(
979 'new_order' => $board_order,
980 'selected_board' => $boardID,
981 )
982 );
983 }
984
985 // Sort the records of the boards table on the board_order value.
986 $smcFunc['db_query']('alter_table_boards', '
987 ALTER TABLE {db_prefix}boards
988 ORDER BY board_order',
989 array(
990 'db_error_skip' => true,
991 )
992 );
993 }
994
995 // Fixes the children of a board by setting their child_levels to new values.
996 function fixChildren($parent, $newLevel, $newParent)
997 {
998 global $smcFunc;
999
1000 // Grab all children of $parent...
1001 $result = $smcFunc['db_query']('', '
1002 SELECT id_board
1003 FROM {db_prefix}boards
1004 WHERE id_parent = {int:parent_board}',
1005 array(
1006 'parent_board' => $parent,
1007 )
1008 );
1009 $children = array();
1010 while ($row = $smcFunc['db_fetch_assoc']($result))
1011 $children[] = $row['id_board'];
1012 $smcFunc['db_free_result']($result);
1013
1014 // ...and set it to a new parent and child_level.
1015 $smcFunc['db_query']('', '
1016 UPDATE {db_prefix}boards
1017 SET id_parent = {int:new_parent}, child_level = {int:new_child_level}
1018 WHERE id_parent = {int:parent_board}',
1019 array(
1020 'new_parent' => $newParent,
1021 'new_child_level' => $newLevel,
1022 'parent_board' => $parent,
1023 )
1024 );
1025
1026 // Recursively fix the children of the children.
1027 foreach ($children as $child)
1028 fixChildren($child, $newLevel + 1, $child);
1029 }
1030
1031 // Load a lot of useful information regarding the boards and categories.
1032 function getBoardTree()
1033 {
1034 global $cat_tree, $boards, $boardList, $txt, $modSettings, $smcFunc;
1035
1036 // Getting all the board and category information you'd ever wanted.
1037 $request = $smcFunc['db_query']('', '
1038 SELECT
1039 IFNULL(b.id_board, 0) AS id_board, b.id_parent, b.name AS board_name, b.description, b.child_level,
1040 b.board_order, b.count_posts, b.member_groups, b.id_theme, b.override_theme, b.id_profile, b.redirect,
1041 b.num_posts, b.num_topics, c.id_cat, c.name AS cat_name, c.cat_order, c.can_collapse
1042 FROM {db_prefix}categories AS c
1043 LEFT JOIN {db_prefix}boards AS b ON (b.id_cat = c.id_cat)
1044 ORDER BY c.cat_order, b.child_level, b.board_order',
1045 array(
1046 )
1047 );
1048 $cat_tree = array();
1049 $boards = array();
1050 $last_board_order = 0;
1051 while ($row = $smcFunc['db_fetch_assoc']($request))
1052 {
1053 if (!isset($cat_tree[$row['id_cat']]))
1054 {
1055 $cat_tree[$row['id_cat']] = array(
1056 'node' => array(
1057 'id' => $row['id_cat'],
1058 'name' => $row['cat_name'],
1059 'order' => $row['cat_order'],
1060 'can_collapse' => $row['can_collapse']
1061 ),
1062 'is_first' => empty($cat_tree),
1063 'last_board_order' => $last_board_order,
1064 'children' => array()
1065 );
1066 $prevBoard = 0;
1067 $curLevel = 0;
1068 }
1069
1070 if (!empty($row['id_board']))
1071 {
1072 if ($row['child_level'] != $curLevel)
1073 $prevBoard = 0;
1074
1075 $boards[$row['id_board']] = array(
1076 'id' => $row['id_board'],
1077 'category' => $row['id_cat'],
1078 'parent' => $row['id_parent'],
1079 'level' => $row['child_level'],
1080 'order' => $row['board_order'],
1081 'name' => $row['board_name'],
1082 'member_groups' => explode(',', $row['member_groups']),
1083 'description' => $row['description'],
1084 'count_posts' => empty($row['count_posts']),
1085 'posts' => $row['num_posts'],
1086 'topics' => $row['num_topics'],
1087 'theme' => $row['id_theme'],
1088 'override_theme' => $row['override_theme'],
1089 'profile' => $row['id_profile'],
1090 'redirect' => $row['redirect'],
1091 'prev_board' => $prevBoard
1092 );
1093 $prevBoard = $row['id_board'];
1094 $last_board_order = $row['board_order'];
1095
1096 if (empty($row['child_level']))
1097 {
1098 $cat_tree[$row['id_cat']]['children'][$row['id_board']] = array(
1099 'node' => &$boards[$row['id_board']],
1100 'is_first' => empty($cat_tree[$row['id_cat']]['children']),
1101 'children' => array()
1102 );
1103 $boards[$row['id_board']]['tree'] = &$cat_tree[$row['id_cat']]['children'][$row['id_board']];
1104 }
1105 else
1106 {
1107 // Parent doesn't exist!
1108 if (!isset($boards[$row['id_parent']]['tree']))
1109 fatal_lang_error('no_valid_parent', false, array($row['board_name']));
1110
1111 // Wrong childlevel...we can silently fix this...
1112 if ($boards[$row['id_parent']]['tree']['node']['level'] != $row['child_level'] - 1)
1113 $smcFunc['db_query']('', '
1114 UPDATE {db_prefix}boards
1115 SET child_level = {int:new_child_level}
1116 WHERE id_board = {int:selected_board}',
1117 array(
1118 'new_child_level' => $boards[$row['id_parent']]['tree']['node']['level'] + 1,
1119 'selected_board' => $row['id_board'],
1120 )
1121 );
1122
1123 $boards[$row['id_parent']]['tree']['children'][$row['id_board']] = array(
1124 'node' => &$boards[$row['id_board']],
1125 'is_first' => empty($boards[$row['id_parent']]['tree']['children']),
1126 'children' => array()
1127 );
1128 $boards[$row['id_board']]['tree'] = &$boards[$row['id_parent']]['tree']['children'][$row['id_board']];
1129 }
1130 }
1131 }
1132 $smcFunc['db_free_result']($request);
1133
1134 // Get a list of all the boards in each category (using recursion).
1135 $boardList = array();
1136 foreach ($cat_tree as $catID => $node)
1137 {
1138 $boardList[$catID] = array();
1139 recursiveBoards($boardList[$catID], $node);
1140 }
1141 }
1142
1143 // Recursively get a list of boards.
1144 function recursiveBoards(&$_boardList, &$_tree)
1145 {
1146 if (empty($_tree['children']))
1147 return;
1148
1149 foreach ($_tree['children'] as $id => $node)
1150 {
1151 $_boardList[] = $id;
1152 recursiveBoards($_boardList, $node);
1153 }
1154 }
1155
1156 // Returns whether the child board id is actually a child of the parent (recursive).
1157 function isChildOf($child, $parent)
1158 {
1159 global $boards;
1160
1161 if (empty($boards[$child]['parent']))
1162 return false;
1163
1164 if ($boards[$child]['parent'] == $parent)
1165 return true;
1166
1167 return isChildOf($boards[$child]['parent'], $parent);
1168 }
1169
1170 ?>