comparison forum/Sources/Reports.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 exclusively for generating reports to help assist forum
18 administrators keep track of their forum configuration and state. The
19 core report generation is done in two areas. Firstly, a report "generator"
20 will fill context with relevant data. Secondly, the choice of sub-template
21 will determine how this data is shown to the user. It has the following
22 functions:
23
24 void ReportsMain()
25 - requires the admin_forum permission.
26 - loads the Reports template and language files.
27 - decides which type of report to generate, if this isn't passed
28 through the querystring it will set the report_type sub-template to
29 force the user to choose which type.
30 - when generating a report chooses which sub_template to use.
31 - depends on the cal_enabled setting, and many of the other cal_
32 settings.
33 - will call the relevant report generation function.
34 - if generating report will call finishTables before returning.
35 - accessed through ?action=admin;area=reports.
36
37 void xxxxxxReport()
38 - functions ending with "Report" are responsible for generating data
39 for reporting.
40 - they are all called from ReportsMain.
41 - never access the context directly, but use the data handling
42 functions to do so.
43
44 void newTable(string title = '', string default_value = '',
45 string shading = 'all', string width_normal = 'auto',
46 string align_normal = 'center', string width_shaded = 'auto',
47 string align_shaded = 'auto')
48 - the core of this file, it creates a new, but empty, table of data in
49 context, ready for filling using addData().
50 - takes a lot of possible attributes, these have the following effect:
51 + title = Title to be displayed with this data table.
52 + default_value = Value to be displayed if a key is missing from a
53 row.
54 + shading = Should the left, top or both (all) parts of the table
55 beshaded?
56 + width_normal = width of an unshaded column (auto means not
57 defined).
58 + align_normal = alignment of data in an unshaded column.
59 + width_shaded = width of a shaded column (auto means not
60 defined).
61 + align_shaded = alignment of data in a shaded column.
62 - fills the context variable current_table with the ID of the table
63 created.
64 - keeps track of the current table count using context variable
65 table_count.
66
67 void addData(array inc_data, int custom_table = null)
68 - adds an array of data into an existing table.
69 - if there are no existing tables, will create one with default
70 attributes.
71 - if custom_table isn't specified, it will use the last table created,
72 if it is specified and doesn't exist the function will return false.
73 - if a set of keys have been specified, the function will check each
74 required key is present in the incoming data. If this data is missing
75 the current tables default value will be used.
76 - if any key in the incoming data begins with '#sep#', the function
77 will add a separator accross the table at this point.
78 - once the incoming data has been sanitized, it is added to the table.
79
80 void addSeparator(string title = '', int custom_table = null)
81 - adds a separator with title given by attribute "title" after the
82 current row in the table.
83 - if there are no existing tables, will create one with default
84 attributes.
85 - if custom_table isn't specified, it will use the last table created,
86 if it is specified and doesn't exist the function will return false.
87 - if the table is currently having data added by column this may have
88 unpredictable visual results.
89
90 void finishTables()
91 - is (unfortunately) required to create some useful variables for
92 templates.
93 - foreach data table created, it will count the number of rows and
94 columns in the table.
95 - will also create a max_width variable for the table, to give an
96 estimate width for the whole table - if it can.
97
98 void setKeys(string method = 'rows', array keys = array(),
99 bool reverse = false)
100 - sets the current set of "keys" expected in each data array passed to
101 addData. It also sets the way we are adding data to the data table.
102 - method specifies whether the data passed to addData represents a new
103 column, or a new row.
104 - keys is an array whose keys are the keys for data being passed to
105 addData().
106 - if reverse is set to true, then the values of the variable "keys"
107 are used as oppossed to the keys(!)
108 */
109
110 // Handling function for generating reports.
111 function ReportsMain()
112 {
113 global $txt, $modSettings, $context, $scripturl;
114
115 // Only admins, only EVER admins!
116 isAllowedTo('admin_forum');
117
118 // Let's get our things running...
119 loadTemplate('Reports');
120 loadLanguage('Reports');
121
122 $context['page_title'] = $txt['generate_reports'];
123
124 // These are the types of reports which exist - and the functions to generate them.
125 $context['report_types'] = array(
126 'boards' => 'BoardReport',
127 'board_perms' => 'BoardPermissionsReport',
128 'member_groups' => 'MemberGroupsReport',
129 'group_perms' => 'GroupPermissionsReport',
130 'staff' => 'StaffReport',
131 );
132
133 $is_first = 0;
134 foreach ($context['report_types'] as $k => $temp)
135 $context['report_types'][$k] = array(
136 'id' => $k,
137 'title' => isset($txt['gr_type_' . $k]) ? $txt['gr_type_' . $k] : $type['id'],
138 'description' => isset($txt['gr_type_desc_' . $k]) ? $txt['gr_type_desc_' . $k] : null,
139 'function' => $temp,
140 'is_first' => $is_first++ == 0,
141 );
142
143 // If they haven't choosen a report type which is valid, send them off to the report type chooser!
144 if (empty($_REQUEST['rt']) || !isset($context['report_types'][$_REQUEST['rt']]))
145 {
146 $context['sub_template'] = 'report_type';
147 return;
148 }
149 $context['report_type'] = $_REQUEST['rt'];
150
151 // What are valid templates for showing reports?
152 $reportTemplates = array(
153 'main' => array(
154 'layers' => null,
155 ),
156 'print' => array(
157 'layers' => array('print'),
158 ),
159 );
160
161 // Specific template? Use that instead of main!
162 if (isset($_REQUEST['st']) && isset($reportTemplates[$_REQUEST['st']]))
163 {
164 $context['sub_template'] = $_REQUEST['st'];
165
166 // Are we disabling the other layers - print friendly for example?
167 if ($reportTemplates[$_REQUEST['st']]['layers'] !== null)
168 $context['template_layers'] = $reportTemplates[$_REQUEST['st']]['layers'];
169 }
170
171 // Make the page title more descriptive.
172 $context['page_title'] .= ' - ' . (isset($txt['gr_type_' . $context['report_type']]) ? $txt['gr_type_' . $context['report_type']] : $context['report_type']);
173 // Now generate the data.
174 $context['report_types'][$context['report_type']]['function']();
175
176 // Finish the tables before exiting - this is to help the templates a little more.
177 finishTables();
178 }
179
180 // Standard report about what settings the boards have.
181 function BoardReport()
182 {
183 global $context, $txt, $sourcedir, $smcFunc;
184
185 // Load the permission profiles.
186 require_once($sourcedir . '/ManagePermissions.php');
187 loadLanguage('ManagePermissions');
188 loadPermissionProfiles();
189
190 // Get every moderator.
191 $request = $smcFunc['db_query']('', '
192 SELECT mods.id_board, mods.id_member, mem.real_name
193 FROM {db_prefix}moderators AS mods
194 INNER JOIN {db_prefix}members AS mem ON (mem.id_member = mods.id_member)',
195 array(
196 )
197 );
198 $moderators = array();
199 while ($row = $smcFunc['db_fetch_assoc']($request))
200 $moderators[$row['id_board']][] = $row['real_name'];
201 $smcFunc['db_free_result']($request);
202
203 // Get all the possible membergroups!
204 $request = $smcFunc['db_query']('', '
205 SELECT id_group, group_name, online_color
206 FROM {db_prefix}membergroups',
207 array(
208 )
209 );
210 $groups = array(-1 => $txt['guest_title'], 0 => $txt['full_member']);
211 while ($row = $smcFunc['db_fetch_assoc']($request))
212 $groups[$row['id_group']] = empty($row['online_color']) ? $row['group_name'] : '<span style="color: ' . $row['online_color'] . '">' . $row['group_name'] . '</span>';
213 $smcFunc['db_free_result']($request);
214
215 // All the fields we'll show.
216 $boardSettings = array(
217 'category' => $txt['board_category'],
218 'parent' => $txt['board_parent'],
219 'num_topics' => $txt['board_num_topics'],
220 'num_posts' => $txt['board_num_posts'],
221 'count_posts' => $txt['board_count_posts'],
222 'theme' => $txt['board_theme'],
223 'override_theme' => $txt['board_override_theme'],
224 'profile' => $txt['board_profile'],
225 'moderators' => $txt['board_moderators'],
226 'groups' => $txt['board_groups'],
227 );
228
229 // Do it in columns, it's just easier.
230 setKeys('cols');
231
232 // Go through each board!
233 $request = $smcFunc['db_query']('order_by_board_order', '
234 SELECT b.id_board, b.name, b.num_posts, b.num_topics, b.count_posts, b.member_groups, b.override_theme, b.id_profile,
235 c.name AS cat_name, IFNULL(par.name, {string:text_none}) AS parent_name, IFNULL(th.value, {string:text_none}) AS theme_name
236 FROM {db_prefix}boards AS b
237 LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat)
238 LEFT JOIN {db_prefix}boards AS par ON (par.id_board = b.id_parent)
239 LEFT JOIN {db_prefix}themes AS th ON (th.id_theme = b.id_theme AND th.variable = {string:name})',
240 array(
241 'name' => 'name',
242 'text_none' => $txt['none'],
243 )
244 );
245 $boards = array(0 => array('name' => $txt['global_boards']));
246 while ($row = $smcFunc['db_fetch_assoc']($request))
247 {
248 // Each board has it's own table.
249 newTable($row['name'], '', 'left', 'auto', 'left', 200, 'left');
250
251 // First off, add in the side key.
252 addData($boardSettings);
253
254 // Format the profile name.
255 $profile_name = $context['profiles'][$row['id_profile']]['name'];
256
257 // Create the main data array.
258 $boardData = array(
259 'category' => $row['cat_name'],
260 'parent' => $row['parent_name'],
261 'num_posts' => $row['num_posts'],
262 'num_topics' => $row['num_topics'],
263 'count_posts' => empty($row['count_posts']) ? $txt['yes'] : $txt['no'],
264 'theme' => $row['theme_name'],
265 'profile' => $profile_name,
266 'override_theme' => $row['override_theme'] ? $txt['yes'] : $txt['no'],
267 'moderators' => empty($moderators[$row['id_board']]) ? $txt['none'] : implode(', ', $moderators[$row['id_board']]),
268 );
269
270 // Work out the membergroups who can access it.
271 $allowedGroups = explode(',', $row['member_groups']);
272 foreach ($allowedGroups as $key => $group)
273 {
274 if (isset($groups[$group]))
275 $allowedGroups[$key] = $groups[$group];
276 else
277 unset($allowedGroups[$key]);
278 }
279 $boardData['groups'] = implode(', ', $allowedGroups);
280
281 // Next add the main data.
282 addData($boardData);
283 }
284 $smcFunc['db_free_result']($request);
285 }
286
287 // Generate a report on the current permissions by board and membergroup.
288 function BoardPermissionsReport()
289 {
290 global $context, $txt, $modSettings, $smcFunc;
291
292 // Get as much memory as possible as this can be big.
293 @ini_set('memory_limit', '256M');
294
295 if (isset($_REQUEST['boards']))
296 {
297 if (!is_array($_REQUEST['boards']))
298 $_REQUEST['boards'] = explode(',', $_REQUEST['boards']);
299 foreach ($_REQUEST['boards'] as $k => $dummy)
300 $_REQUEST['boards'][$k] = (int) $dummy;
301
302 $board_clause = 'id_board IN ({array_int:boards})';
303 }
304 else
305 $board_clause = '1=1';
306
307 if (isset($_REQUEST['groups']))
308 {
309 if (!is_array($_REQUEST['groups']))
310 $_REQUEST['groups'] = explode(',', $_REQUEST['groups']);
311 foreach ($_REQUEST['groups'] as $k => $dummy)
312 $_REQUEST['groups'][$k] = (int) $dummy;
313
314 $group_clause = 'id_group IN ({array_int:groups})';
315 }
316 else
317 $group_clause = '1=1';
318
319 // Fetch all the board names.
320 $request = $smcFunc['db_query']('', '
321 SELECT id_board, name, id_profile
322 FROM {db_prefix}boards
323 WHERE ' . $board_clause . '
324 ORDER BY id_board',
325 array(
326 'boards' => isset($_REQUEST['boards']) ? $_REQUEST['boards'] : array(),
327 )
328 );
329 $profiles = array();
330 while ($row = $smcFunc['db_fetch_assoc']($request))
331 {
332 $boards[$row['id_board']] = array(
333 'name' => $row['name'],
334 'profile' => $row['id_profile'],
335 );
336 $profiles[] = $row['id_profile'];
337 }
338 $smcFunc['db_free_result']($request);
339
340 // Get all the possible membergroups, except admin!
341 $request = $smcFunc['db_query']('', '
342 SELECT id_group, group_name
343 FROM {db_prefix}membergroups
344 WHERE ' . $group_clause . '
345 AND id_group != {int:admin_group}' . (empty($modSettings['permission_enable_postgroups']) ? '
346 AND min_posts = {int:min_posts}' : '') . '
347 ORDER BY min_posts, CASE WHEN id_group < {int:newbie_group} THEN id_group ELSE 4 END, group_name',
348 array(
349 'admin_group' => 1,
350 'min_posts' => -1,
351 'newbie_group' => 4,
352 'groups' => isset($_REQUEST['groups']) ? $_REQUEST['groups'] : array(),
353 )
354 );
355 if (!isset($_REQUEST['groups']) || in_array(-1, $_REQUEST['groups']) || in_array(0, $_REQUEST['groups']))
356 $member_groups = array('col' => '', -1 => $txt['membergroups_guests'], 0 => $txt['membergroups_members']);
357 else
358 $member_groups = array('col' => '');
359 while ($row = $smcFunc['db_fetch_assoc']($request))
360 $member_groups[$row['id_group']] = $row['group_name'];
361 $smcFunc['db_free_result']($request);
362
363 // Make sure that every group is represented - plus in rows!
364 setKeys('rows', $member_groups);
365
366 // Cache every permission setting, to make sure we don't miss any allows.
367 $permissions = array();
368 $board_permissions = array();
369 $request = $smcFunc['db_query']('', '
370 SELECT id_profile, id_group, add_deny, permission
371 FROM {db_prefix}board_permissions
372 WHERE id_profile IN ({array_int:profile_list})
373 AND ' . $group_clause . (empty($modSettings['permission_enable_deny']) ? '
374 AND add_deny = {int:not_deny}' : '') . '
375 ORDER BY id_profile, permission',
376 array(
377 'profile_list' => $profiles,
378 'not_deny' => 1,
379 'groups' => isset($_REQUEST['groups']) ? $_REQUEST['groups'] : array(),
380 )
381 );
382 while ($row = $smcFunc['db_fetch_assoc']($request))
383 {
384 foreach ($boards as $id => $board)
385 if ($board['profile'] == $row['id_profile'])
386 $board_permissions[$id][$row['id_group']][$row['permission']] = $row['add_deny'];
387
388 // Make sure we get every permission.
389 if (!isset($permissions[$row['permission']]))
390 {
391 // This will be reused on other boards.
392 $permissions[$row['permission']] = array(
393 'title' => isset($txt['board_perms_name_' . $row['permission']]) ? $txt['board_perms_name_' . $row['permission']] : $row['permission'],
394 );
395 }
396 }
397 $smcFunc['db_free_result']($request);
398
399 // Now cycle through the board permissions array... lots to do ;)
400 foreach ($board_permissions as $board => $groups)
401 {
402 // Create the table for this board first.
403 newTable($boards[$board]['name'], 'x', 'all', 100, 'center', 200, 'left');
404
405 // Add the header row - shows all the membergroups.
406 addData($member_groups);
407
408 // Add the separator.
409 addSeparator($txt['board_perms_permission']);
410
411 // Here cycle through all the detected permissions.
412 foreach ($permissions as $ID_PERM => $perm_info)
413 {
414 // Is this identical to the global?
415 $identicalGlobal = $board == 0 ? false : true;
416
417 // Default data for this row.
418 $curData = array('col' => $perm_info['title']);
419
420 // Now cycle each membergroup in this set of permissions.
421 foreach ($member_groups as $id_group => $name)
422 {
423 // Don't overwrite the key column!
424 if ($id_group === 'col')
425 continue;
426
427 $group_permissions = isset($groups[$id_group]) ? $groups[$id_group] : array();
428
429 // Do we have any data for this group?
430 if (isset($group_permissions[$ID_PERM]))
431 {
432 // Set the data for this group to be the local permission.
433 $curData[$id_group] = $group_permissions[$ID_PERM];
434 }
435 // Otherwise means it's set to disallow..
436 else
437 {
438 $curData[$id_group] = 'x';
439 }
440
441 // Now actually make the data for the group look right.
442 if (empty($curData[$id_group]))
443 $curData[$id_group] = '<span style="color: red;">' . $txt['board_perms_deny'] . '</span>';
444 elseif ($curData[$id_group] == 1)
445 $curData[$id_group] = '<span style="color: darkgreen;">' . $txt['board_perms_allow'] . '</span>';
446 else
447 $curData[$id_group] = 'x';
448
449 // Embolden those permissions different from global (makes it a lot easier!)
450 if (@$board_permissions[0][$id_group][$ID_PERM] != @$group_permissions[$ID_PERM])
451 $curData[$id_group] = '<strong>' . $curData[$id_group] . '</strong>';
452 }
453
454 // Now add the data for this permission.
455 addData($curData);
456 }
457 }
458 }
459
460 // Show what the membergroups are made of.
461 function MemberGroupsReport()
462 {
463 global $context, $txt, $settings, $modSettings, $smcFunc;
464
465 // Fetch all the board names.
466 $request = $smcFunc['db_query']('', '
467 SELECT id_board, name, member_groups, id_profile
468 FROM {db_prefix}boards',
469 array(
470 )
471 );
472 while ($row = $smcFunc['db_fetch_assoc']($request))
473 {
474 if (trim($row['member_groups']) == '')
475 $groups = array(1);
476 else
477 $groups = array_merge(array(1), explode(',', $row['member_groups']));
478
479 $boards[$row['id_board']] = array(
480 'id' => $row['id_board'],
481 'name' => $row['name'],
482 'profile' => $row['id_profile'],
483 'groups' => $groups,
484 );
485 }
486 $smcFunc['db_free_result']($request);
487
488 // Standard settings.
489 $mgSettings = array(
490 'name' => '',
491 '#sep#1' => $txt['member_group_settings'],
492 'color' => $txt['member_group_color'],
493 'min_posts' => $txt['member_group_min_posts'],
494 'max_messages' => $txt['member_group_max_messages'],
495 'stars' => $txt['member_group_stars'],
496 '#sep#2' => $txt['member_group_access'],
497 );
498
499 // Add on the boards!
500 foreach ($boards as $board)
501 $mgSettings['board_' . $board['id']] = $board['name'];
502
503 // Add all the membergroup settings, plus we'll be adding in columns!
504 setKeys('cols', $mgSettings);
505
506 // Only one table this time!
507 newTable($txt['gr_type_member_groups'], '-', 'all', 100, 'center', 200, 'left');
508
509 // Get the shaded column in.
510 addData($mgSettings);
511
512 // Now start cycling the membergroups!
513 $request = $smcFunc['db_query']('', '
514 SELECT mg.id_group, mg.group_name, mg.online_color, mg.min_posts, mg.max_messages, mg.stars,
515 CASE WHEN bp.permission IS NOT NULL OR mg.id_group = {int:admin_group} THEN 1 ELSE 0 END AS can_moderate
516 FROM {db_prefix}membergroups AS mg
517 LEFT JOIN {db_prefix}board_permissions AS bp ON (bp.id_group = mg.id_group AND bp.id_profile = {int:default_profile} AND bp.permission = {string:moderate_board})
518 ORDER BY mg.min_posts, CASE WHEN mg.id_group < {int:newbie_group} THEN mg.id_group ELSE 4 END, mg.group_name',
519 array(
520 'admin_group' => 1,
521 'default_profile' => 1,
522 'newbie_group' => 4,
523 'moderate_board' => 'moderate_board',
524 )
525 );
526
527 // Cache them so we get regular members too.
528 $rows = array(
529 array(
530 'id_group' => -1,
531 'group_name' => $txt['membergroups_guests'],
532 'online_color' => '',
533 'min_posts' => -1,
534 'max_messages' => null,
535 'stars' => ''
536 ),
537 array(
538 'id_group' => 0,
539 'group_name' => $txt['membergroups_members'],
540 'online_color' => '',
541 'min_posts' => -1,
542 'max_messages' => null,
543 'stars' => ''
544 ),
545 );
546 while ($row = $smcFunc['db_fetch_assoc']($request))
547 $rows[] = $row;
548 $smcFunc['db_free_result']($request);
549
550 foreach ($rows as $row)
551 {
552 $row['stars'] = explode('#', $row['stars']);
553
554 $group = array(
555 'name' => $row['group_name'],
556 'color' => empty($row['online_color']) ? '-' : '<span style="color: ' . $row['online_color'] . ';">' . $row['online_color'] . '</span>',
557 'min_posts' => $row['min_posts'] == -1 ? 'N/A' : $row['min_posts'],
558 'max_messages' => $row['max_messages'],
559 'stars' => !empty($row['stars'][0]) && !empty($row['stars'][1]) ? str_repeat('<img src="' . $settings['images_url'] . '/' . $row['stars'][1] . '" alt="*" />', $row['stars'][0]) : '',
560 );
561
562 // Board permissions.
563 foreach ($boards as $board)
564 $group['board_' . $board['id']] = in_array($row['id_group'], $board['groups']) ? '<span style="color: darkgreen;">' . $txt['board_perms_allow'] . '</span>' : 'x';
565
566 addData($group);
567 }
568 }
569
570 // Show the large variety of group permissions assigned to each membergroup.
571 function GroupPermissionsReport()
572 {
573 global $context, $txt, $modSettings, $smcFunc;
574
575 if (isset($_REQUEST['groups']))
576 {
577 if (!is_array($_REQUEST['groups']))
578 $_REQUEST['groups'] = explode(',', $_REQUEST['groups']);
579 foreach ($_REQUEST['groups'] as $k => $dummy)
580 $_REQUEST['groups'][$k] = (int) $dummy;
581 $_REQUEST['groups'] = array_diff($_REQUEST['groups'], array(3));
582
583 $clause = 'id_group IN ({array_int:groups})';
584 }
585 else
586 $clause = 'id_group != {int:moderator_group}';
587
588 // Get all the possible membergroups, except admin!
589 $request = $smcFunc['db_query']('', '
590 SELECT id_group, group_name
591 FROM {db_prefix}membergroups
592 WHERE ' . $clause . '
593 AND id_group != {int:admin_group}' . (empty($modSettings['permission_enable_postgroups']) ? '
594 AND min_posts = {int:min_posts}' : '') . '
595 ORDER BY min_posts, CASE WHEN id_group < {int:newbie_group} THEN id_group ELSE 4 END, group_name',
596 array(
597 'admin_group' => 1,
598 'min_posts' => -1,
599 'newbie_group' => 4,
600 'moderator_group' => 3,
601 'groups' => isset($_REQUEST['groups']) ? $_REQUEST['groups'] : array(),
602 )
603 );
604 if (!isset($_REQUEST['groups']) || in_array(-1, $_REQUEST['groups']) || in_array(0, $_REQUEST['groups']))
605 $groups = array('col' => '', -1 => $txt['membergroups_guests'], 0 => $txt['membergroups_members']);
606 else
607 $groups = array('col' => '');
608 while ($row = $smcFunc['db_fetch_assoc']($request))
609 $groups[$row['id_group']] = $row['group_name'];
610 $smcFunc['db_free_result']($request);
611
612 // Make sure that every group is represented!
613 setKeys('rows', $groups);
614
615 // Create the table first.
616 newTable($txt['gr_type_group_perms'], '-', 'all', 100, 'center', 200, 'left');
617
618 // Show all the groups
619 addData($groups);
620
621 // Add a separator
622 addSeparator($txt['board_perms_permission']);
623
624 // Now the big permission fetch!
625 $request = $smcFunc['db_query']('', '
626 SELECT id_group, add_deny, permission
627 FROM {db_prefix}permissions
628 WHERE ' . $clause . (empty($modSettings['permission_enable_deny']) ? '
629 AND add_deny = {int:not_denied}' : '') . '
630 ORDER BY permission',
631 array(
632 'not_denied' => 1,
633 'moderator_group' => 3,
634 'groups' => isset($_REQUEST['groups']) ? $_REQUEST['groups'] : array(),
635 )
636 );
637 $lastPermission = null;
638 while ($row = $smcFunc['db_fetch_assoc']($request))
639 {
640 // If this is a new permission flush the last row.
641 if ($row['permission'] != $lastPermission)
642 {
643 // Send the data!
644 if ($lastPermission !== null)
645 addData($curData);
646
647 // Add the permission name in the left column.
648 $curData = array('col' => isset($txt['group_perms_name_' . $row['permission']]) ? $txt['group_perms_name_' . $row['permission']] : $row['permission']);
649
650 $lastPermission = $row['permission'];
651 }
652
653 // Good stuff - add the permission to the list!
654 if ($row['add_deny'])
655 $curData[$row['id_group']] = '<span style="color: darkgreen;">' . $txt['board_perms_allow'] . '</span>';
656 else
657 $curData[$row['id_group']] = '<span style="color: red;">' . $txt['board_perms_deny'] . '</span>';
658 }
659 $smcFunc['db_free_result']($request);
660
661 // Flush the last data!
662 addData($curData);
663 }
664
665 // Report for showing all the forum staff members - quite a feat!
666 function StaffReport()
667 {
668 global $sourcedir, $context, $txt, $smcFunc;
669
670 require_once($sourcedir . '/Subs-Members.php');
671
672 // Fetch all the board names.
673 $request = $smcFunc['db_query']('', '
674 SELECT id_board, name
675 FROM {db_prefix}boards',
676 array(
677 )
678 );
679 $boards = array();
680 while ($row = $smcFunc['db_fetch_assoc']($request))
681 $boards[$row['id_board']] = $row['name'];
682 $smcFunc['db_free_result']($request);
683
684 // Get every moderator.
685 $request = $smcFunc['db_query']('', '
686 SELECT mods.id_board, mods.id_member
687 FROM {db_prefix}moderators AS mods',
688 array(
689 )
690 );
691 $moderators = array();
692 $local_mods = array();
693 while ($row = $smcFunc['db_fetch_assoc']($request))
694 {
695 $moderators[$row['id_member']][] = $row['id_board'];
696 $local_mods[$row['id_member']] = $row['id_member'];
697 }
698 $smcFunc['db_free_result']($request);
699
700 // Get a list of global moderators (i.e. members with moderation powers).
701 $global_mods = array_intersect(membersAllowedTo('moderate_board', 0), membersAllowedTo('approve_posts', 0), membersAllowedTo('remove_any', 0), membersAllowedTo('modify_any', 0));
702
703 // How about anyone else who is special?
704 $allStaff = array_merge(membersAllowedTo('admin_forum'), membersAllowedTo('manage_membergroups'), membersAllowedTo('manage_permissions'), $local_mods, $global_mods);
705
706 // Make sure everyone is there once - no admin less important than any other!
707 $allStaff = array_unique($allStaff);
708
709 // This is a bit of a cop out - but we're protecting their forum, really!
710 if (count($allStaff) > 300)
711 fatal_lang_error('report_error_too_many_staff');
712
713 // Get all the possible membergroups!
714 $request = $smcFunc['db_query']('', '
715 SELECT id_group, group_name, online_color
716 FROM {db_prefix}membergroups',
717 array(
718 )
719 );
720 $groups = array(0 => $txt['full_member']);
721 while ($row = $smcFunc['db_fetch_assoc']($request))
722 $groups[$row['id_group']] = empty($row['online_color']) ? $row['group_name'] : '<span style="color: ' . $row['online_color'] . '">' . $row['group_name'] . '</span>';
723 $smcFunc['db_free_result']($request);
724
725 // All the fields we'll show.
726 $staffSettings = array(
727 'position' => $txt['report_staff_position'],
728 'moderates' => $txt['report_staff_moderates'],
729 'posts' => $txt['report_staff_posts'],
730 'last_login' => $txt['report_staff_last_login'],
731 );
732
733 // Do it in columns, it's just easier.
734 setKeys('cols');
735
736 // Get each member!
737 $request = $smcFunc['db_query']('', '
738 SELECT id_member, real_name, id_group, posts, last_login
739 FROM {db_prefix}members
740 WHERE id_member IN ({array_int:staff_list})
741 ORDER BY real_name',
742 array(
743 'staff_list' => $allStaff,
744 )
745 );
746 while ($row = $smcFunc['db_fetch_assoc']($request))
747 {
748 // Each member gets their own table!.
749 newTable($row['real_name'], '', 'left', 'auto', 'left', 200, 'center');
750
751 // First off, add in the side key.
752 addData($staffSettings);
753
754 // Create the main data array.
755 $staffData = array(
756 'position' => isset($groups[$row['id_group']]) ? $groups[$row['id_group']] : $groups[0],
757 'posts' => $row['posts'],
758 'last_login' => timeformat($row['last_login']),
759 'moderates' => array(),
760 );
761
762 // What do they moderate?
763 if (in_array($row['id_member'], $global_mods))
764 $staffData['moderates'] = '<em>' . $txt['report_staff_all_boards'] . '</em>';
765 elseif (isset($moderators[$row['id_member']]))
766 {
767 // Get the names
768 foreach ($moderators[$row['id_member']] as $board)
769 if (isset($boards[$board]))
770 $staffData['moderates'][] = $boards[$board];
771
772 $staffData['moderates'] = implode(', ', $staffData['moderates']);
773 }
774 else
775 $staffData['moderates'] = '<em>' . $txt['report_staff_no_boards'] . '</em>';
776
777 // Next add the main data.
778 addData($staffData);
779 }
780 $smcFunc['db_free_result']($request);
781 }
782
783 // This function creates a new table of data, most functions will only use it once.
784 function newTable($title = '', $default_value = '', $shading = 'all', $width_normal = 'auto', $align_normal = 'center', $width_shaded = 'auto', $align_shaded = 'auto')
785 {
786 global $context;
787
788 // Set the table count if needed.
789 if (empty($context['table_count']))
790 $context['table_count'] = 0;
791
792 // Create the table!
793 $context['tables'][$context['table_count']] = array(
794 'title' => $title,
795 'default_value' => $default_value,
796 'shading' => array(
797 'left' => $shading == 'all' || $shading == 'left',
798 'top' => $shading == 'all' || $shading == 'top',
799 ),
800 'width' => array(
801 'normal' => $width_normal,
802 'shaded' => $width_shaded,
803 ),
804 'align' => array(
805 'normal' => $align_normal,
806 'shaded' => $align_shaded,
807 ),
808 'data' => array(),
809 );
810
811 $context['current_table'] = $context['table_count'];
812
813 // Increment the count...
814 $context['table_count']++;
815 }
816
817 // Add an extra slice of data to the table
818 function addData($inc_data, $custom_table = null)
819 {
820 global $context;
821
822 // No tables? Create one even though we are probably already in a bad state!
823 if (empty($context['table_count']))
824 newTable();
825
826 // Specific table?
827 if ($custom_table !== null && !isset($context['tables'][$custom_table]))
828 return false;
829 elseif ($custom_table !== null)
830 $table = $custom_table;
831 else
832 $table = $context['current_table'];
833
834 // If we have keys, sanitise the data...
835 if (!empty($context['keys']))
836 {
837 // Basically, check every key exists!
838 foreach ($context['keys'] as $key => $dummy)
839 {
840 $data[$key] = array(
841 'v' => empty($inc_data[$key]) ? $context['tables'][$table]['default_value'] : $inc_data[$key],
842 );
843 // Special "hack" the adding separators when doing data by column.
844 if (substr($key, 0, 5) == '#sep#')
845 $data[$key]['separator'] = true;
846 }
847 }
848 else
849 {
850 $data = $inc_data;
851 foreach ($data as $key => $value)
852 {
853 $data[$key] = array(
854 'v' => $value,
855 );
856 if (substr($key, 0, 5) == '#sep#')
857 $data[$key]['separator'] = true;
858 }
859 }
860
861 // Is it by row?
862 if (empty($context['key_method']) || $context['key_method'] == 'rows')
863 {
864 // Add the data!
865 $context['tables'][$table]['data'][] = $data;
866 }
867 // Otherwise, tricky!
868 else
869 {
870 foreach ($data as $key => $item)
871 $context['tables'][$table]['data'][$key][] = $item;
872 }
873 }
874
875 // Add a separator row, only really used when adding data by rows.
876 function addSeparator($title = '', $custom_table = null)
877 {
878 global $context;
879
880 // No tables - return?
881 if (empty($context['table_count']))
882 return;
883
884 // Specific table?
885 if ($custom_table !== null && !isset($context['tables'][$table]))
886 return false;
887 elseif ($custom_table !== null)
888 $table = $custom_table;
889 else
890 $table = $context['current_table'];
891
892 // Plumb in the separator
893 $context['tables'][$table]['data'][] = array(0 => array(
894 'separator' => true,
895 'v' => $title
896 ));
897 }
898
899 // This does the necessary count of table data before displaying them.
900 function finishTables()
901 {
902 global $context;
903
904 if (empty($context['tables']))
905 return;
906
907 // Loop through each table counting up some basic values, to help with the templating.
908 foreach ($context['tables'] as $id => $table)
909 {
910 $context['tables'][$id]['id'] = $id;
911 $context['tables'][$id]['row_count'] = count($table['data']);
912 $curElement = current($table['data']);
913 $context['tables'][$id]['column_count'] = count($curElement);
914
915 // Work out the rough width - for templates like the print template. Without this we might get funny tables.
916 if ($table['shading']['left'] && $table['width']['shaded'] != 'auto' && $table['width']['normal'] != 'auto')
917 $context['tables'][$id]['max_width'] = $table['width']['shaded'] + ($context['tables'][$id]['column_count'] - 1) * $table['width']['normal'];
918 elseif ($table['width']['normal'] != 'auto')
919 $context['tables'][$id]['max_width'] = $context['tables'][$id]['column_count'] * $table['width']['normal'];
920 else
921 $context['tables'][$id]['max_width'] = 'auto';
922 }
923 }
924
925 // Set the keys in use by the tables - these ensure entries MUST exist if the data isn't sent.
926 function setKeys($method = 'rows', $keys = array(), $reverse = false)
927 {
928 global $context;
929
930 // Do we want to use the keys of the keys as the keys? :P
931 if ($reverse)
932 $context['keys'] = array_flip($keys);
933 else
934 $context['keys'] = $keys;
935
936 // Rows or columns?
937 $context['key_method'] = $method == 'rows' ? 'rows' : 'cols';
938 }
939
940 ?>