Passed
Push — myDevel ( d43be7...574062 )
by Spuds
05:08
created

addConversionJS()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 2
c 1
b 0
f 1
nc 1
nop 1
dl 0
loc 5
rs 10
1
<?php
2
3
/**
4
 * @package SimplePortal ElkArte
5
 *
6
 * @author SimplePortal Team
7
 * @copyright 2015-2021 SimplePortal Team
8
 * @license BSD 3-clause
9
 * @version 1.0.0 RC2
10
 */
11
12
13
/**
14
 * Fetches all the classes (blocks) in the system
15
 *
16
 * - If supplied a name gets just that functions id
17
 * - Returns the functions in the order found in the file system
18
 * - Will not return blocks according to block setting for security reasons
19
 * - Uses naming pattern of subs/spblocks/xyz.block.php
20
 *
21
 * @param string|null $function
22
 *
23
 * @return array
24
 */
25
function getFunctionInfo($function = null)
26
{
27
	global $txt;
28
29
	$return = array();
30
31
	// Looking for a specific block or all of them
32
	if ($function !== null)
33
	{
34
		// Replace dots with nothing to avoid security issues
35
		$function = strtr($function, array('.' => ''));
36
		$pattern = SUBSDIR . '/spblocks/' . $function . '.block.php';
37
	}
38
	else
39
	{
40
		$pattern = SUBSDIR . '/spblocks/*.block.php';
41
	}
42
43
	// Iterates through a file system in a similar fashion to glob().
44
	$fs = new GlobIterator($pattern);
45
46
	// Loop on the glob-ules !
47
	foreach ($fs as $item)
48
	{
49
		// Convert file names to class names, UserInfo.block.pbp => User_Info_Block
50
		$class = str_replace('.block.php', '_Block', trim(preg_replace('/((?<=)\p{Lu}(?=\p{Ll}))/', '_$1', $item->getFilename()), '_'));
51
52
		// Load the block, make sure we can access it
53
		require_once($item->getPathname());
54
		if (!class_exists($class))
55
		{
56
			continue;
57
		}
58
59
		// Check if the block has defined any special permissions
60
		if (!allowedTo($class::permissionsRequired()))
61
		{
62
			continue;
63
		}
64
65
		// Add it to our allowed lists
66
		$return[] = array(
67
			'id' => $class,
68
			'function' => str_replace('_Block', '', $class),
69
			'custom_label' => $class::blockName(),
70
			'custom_desc' => $class::blockDescription(),
71
			'standard_label' => isset($txt['sp_function_' . str_replace('_Block', '', $class) . '_label']) ? $txt['sp_function_' . str_replace('_Block', '', $class) . '_label'] : str_replace('_Block', '', $class)
72
		);
73
	}
74
75
	// Show the block list in alpha order
76
	if ($function === null)
77
	{
78
		usort($return, function ($a, $b) {
79
			$a_string = !empty($a['custom_label']) ? $a['custom_label'] : $a['standard_label'];
80
			$b_string = !empty($b['custom_label']) ? $b['custom_label'] : $b['standard_label'];
81
			return strcmp($a_string, $b_string);
82
		});
83
	}
84
85
	return $function === null ? $return : current($return);
86
}
87
88
/**
89
 * Assigns row id's to each block in a specified column
90
 *
91
 * - Ensures each block has a unique row id
92
 * - For each block in a column, it will sequentially number the row id
93
 * based on the order the blocks are returned via getBlockInfo
94
 *
95
 * @param int|null $column_id
96
 */
97
function fixColumnRows($column_id = null)
98
{
99
	$db = database();
100
101
	// Get the list of all blocks in this column
102
	$blockList = getBlockInfo($column_id);
103
	$blockIds = array();
104
105
	foreach ($blockList as $block)
106
	{
107
		$blockIds[] = $block['id'];
108
	}
109
110
	$counter = 0;
111
112
	// Now sequentially set the row number for each block in this column
113
	foreach ($blockIds as $block)
114
	{
115
		$counter = $counter + 1;
116
117
		$db->query('', '
118
			UPDATE {db_prefix}sp_blocks
119
			SET row = {int:counter}
120
			WHERE id_block = {int:block}',
121
			array(
122
				'counter' => $counter,
123
				'block' => $block,
124
			)
125
		);
126
	}
127
}
128
129
/**
130
 * Toggles the active state of a passed control ID of a given Type
131
 *
132
 * @param string|null $type type of control
133
 * @param int|null $id specific id of the control
134
 *
135
 * @return int|bool
136
 */
137
function sp_changeState($type = null, $id = null)
138
{
139
	$db = database();
140
141
	if ($type === 'block')
142
	{
143
		$query = array(
144
			'column' => 'state',
145
			'table' => 'sp_blocks',
146
			'query_id' => 'id_block',
147
			'id' => $id
148
		);
149
	}
150
	elseif ($type === 'category')
151
	{
152
		$query = array(
153
			'column' => 'status',
154
			'table' => 'sp_categories',
155
			'query_id' => 'id_category',
156
			'id' => $id
157
		);
158
	}
159
	elseif ($type === 'article')
160
	{
161
		$query = array(
162
			'column' => 'status',
163
			'table' => 'sp_articles',
164
			'query_id' => 'id_article',
165
			'id' => $id
166
		);
167
	}
168
	elseif ($type === 'page')
169
	{
170
		$query = array(
171
			'column' => 'status',
172
			'table' => 'sp_pages',
173
			'query_id' => 'id_page',
174
			'id' => $id
175
		);
176
	}
177
	elseif ($type === 'shout')
178
	{
179
		$query = array(
180
			'column' => 'status',
181
			'table' => 'sp_shoutboxes',
182
			'query_id' => 'id_shoutbox',
183
			'id' => $id
184
		);
185
	}
186
	else
187
	{
188
		return false;
189
	}
190
191
	// Clap on, Clap off
192
	$db->query('', '
193
		UPDATE {db_prefix}{raw:table}
194
		SET {raw:column} = CASE WHEN {raw:column} = {int:is_active} THEN 0 ELSE 1 END
195
		WHERE {raw:query_id} = {int:id}',
196
		array(
197
			'table' => $query['table'],
198
			'column' => $query['column'],
199
			'query_id' => $query['query_id'],
200
			'id' => $id,
201
			'is_active' => 1,
202
		)
203
	);
204
205
	// Get the new state
206
	$request = $db->query('', '
207
		SELECT {raw:column}
208
		FROM {db_prefix}{raw:table}
209
		WHERE {raw:query_id} = {int:id}',
210
		array(
211
			'table' => $query['table'],
212
			'column' => $query['column'],
213
			'query_id' => $query['query_id'],
214
			'id' => $id,
215
		)
216
	);
217
	list ($state) = $db->fetch_row($request);
218
	$db->free_result($request);
219
220
	return $state;
221
}
222
223
/**
224
 * Load the default theme names
225
 *
226
 * @return array
227
 */
228
function sp_general_load_themes()
229
{
230
	global $txt;
231
232
	$db = database();
233
234
	$request = $db->query('', '
235
		SELECT
236
			id_theme, value AS name
237
		FROM {db_prefix}themes
238
		WHERE variable = {string:name}
239
			AND id_member = {int:member}
240
		ORDER BY id_theme',
241
		array(
242
			'member' => 0,
243
			'name' => 'name',
244
		)
245
	);
246
	$SPortal_themes = array('0' => &$txt['portalthemedefault']);
247
	while ($row = $db->fetch_assoc($request))
248
		$SPortal_themes[$row['id_theme']] = $row['name'];
249
	$db->free_result($request);
250
251
	return $SPortal_themes;
252
}
253
254
/**
255
 * This will file the $context['member_groups'] to the given options
256
 *
257
 * @param int[]|string $selectedGroups - all groups who should be shown as selected, if you like to check all than
258
 *     insert an 'all' You can also Give the function a string with '2,3,4'
259
 * @param string $show - 'normal' => will show all groups, and add a guest and regular member (Standard)
260
 *                       'post' => will load only post groups
261
 *                       'master' => will load only not postbased groups
262
 * @param string $contextName - where the data should stored in the $context
263
 * @param string $subContext
264
 *
265
 * @return null
266
 */
267
function sp_loadMemberGroups($selectedGroups = array(), $show = 'normal', $contextName = 'member_groups', $subContext = 'SPortal')
268
{
269
	global $context, $txt;
270
271
	$db = database();
272
273
	// Some additional Language stings are needed
274
	loadLanguage('ManageBoards');
275
276
	// Make sure its empty
277
	if (!empty($subContext))
278
	{
279
		$context[$subContext][$contextName] = array();
280
	}
281
	else
282
	{
283
		$context[$contextName] = array();
284
	}
285
286
	// Presetting some things :)
287
	if (!is_array($selectedGroups))
288
	{
289
		$checked = strtolower($selectedGroups) === 'all';
290
	}
291
	else
292
	{
293
		$checked = false;
294
	}
295
296
	if (!$checked && isset($selectedGroups) && $selectedGroups == '0')
297
	{
298
		$selectedGroups = array(0);
299
	}
300
	elseif (!$checked && !empty($selectedGroups))
301
	{
302
		if (!is_array($selectedGroups))
303
		{
304
			$selectedGroups = explode(',', $selectedGroups);
305
		}
306
307
		// Remove all strings, i will only allow ids :P
308
		foreach ($selectedGroups as $k => $i)
309
		{
310
			$selectedGroups[$k] = (int) $i;
311
		}
312
313
		$selectedGroups = array_unique($selectedGroups);
314
	}
315
	else
316
	{
317
		$selectedGroups = array();
318
	}
319
320
	// Okay let's checkup the show function
321
	$show_option = array(
322
		'normal' => 'id_group != 3',
323
		'moderator' => 'id_group != 1 AND id_group != 3',
324
		'post' => 'min_posts != -1',
325
		'master' => 'min_posts = -1 AND id_group != 3',
326
	);
327
328
	$show = strtolower($show);
329
330
	if (!isset($show_option[$show]))
331
	{
332
		$show = 'normal';
333
	}
334
335
	// Guest and Members are added manually. Only on normal and master View =)
336
	if ($show === 'normal' || $show === 'master' || $show === 'moderator')
337
	{
338
		if ($show !== 'moderator')
339
		{
340
			$context[$contextName][-1] = array(
341
				'id' => -1,
342
				'name' => $txt['membergroups_guests'],
343
				'checked' => $checked || in_array(-1, $selectedGroups),
344
				'is_post_group' => false,
345
			);
346
		}
347
348
		$context[$contextName][0] = array(
349
			'id' => 0,
350
			'name' => $txt['membergroups_members'],
351
			'checked' => $checked || in_array(0, $selectedGroups),
352
			'is_post_group' => false,
353
		);
354
	}
355
356
	// Load membergroups.
357
	$request = $db->query('', '
358
		SELECT
359
			group_name, id_group, min_posts
360
		FROM {db_prefix}membergroups
361
		WHERE {raw:show}
362
		ORDER BY min_posts, id_group != {int:global_moderator}, group_name',
363
		array(
364
			'show' => $show_option[$show],
365
			'global_moderator' => 2,
366
		)
367
	);
368
	while ($row = $db->fetch_assoc($request))
369
	{
370
		$context[$contextName][(int) $row['id_group']] = array(
371
			'id' => $row['id_group'],
372
			'name' => trim($row['group_name']),
373
			'checked' => $checked || in_array($row['id_group'], $selectedGroups),
374
			'is_post_group' => $row['min_posts'] != -1,
375
		);
376
	}
377
	$db->free_result($request);
378
}
379
380
/**
381
 * Loads the membergroups in the system
382
 *
383
 * - Excludes moderator groups
384
 * - Loads id and name for each group
385
 * - Used for template group select lists / permissions
386
 *
387
 * @return array
388
 */
389
function sp_load_membergroups()
390
{
391
	global $txt;
392
393
	$db = database();
394
395
	// Need to speak the right language
396
	loadLanguage('ManageBoards');
397
398
	// Start off with some known ones, guests and regular members
399
	$groups = array(
400
		-1 => $txt['parent_guests_only'],
401
		0 => $txt['parent_members_only'],
402
	);
403
404
	// Load up all groups in the system as long as they are not moderator groups
405
	$request = $db->query('', '
406
		SELECT
407
			group_name, id_group, min_posts
408
		FROM {db_prefix}membergroups
409
		WHERE id_group != {int:moderator_group}
410
		ORDER BY min_posts, group_name',
411
		array(
412
			'moderator_group' => 3,
413
		)
414
	);
415
	while ($row = $db->fetch_assoc($request))
416
		$groups[(int) $row['id_group']] = trim($row['group_name']);
417
	$db->free_result($request);
418
419
	return $groups;
420
}
421
422
/**
423
 * Returns the total count of categories in the system
424
 *
425
 * @return int
426
 */
427
function sp_count_categories()
428
{
429
	$db = database();
430
431
	$request = $db->query('', '
432
		SELECT COUNT(*)
433
		FROM {db_prefix}sp_categories'
434
	);
435
	list ($total_categories) = $db->fetch_row($request);
436
	$db->free_result($request);
437
438
	return $total_categories;
439
}
440
441
/**
442
 * Loads all of the category's in the system
443
 *
444
 * - Returns an indexed array of the categories
445
 *
446
 * @param int|null $start
447
 * @param int|null $items_per_page
448
 * @param string|null $sort
449
 *
450
 * @return array
451
 */
452
function sp_load_categories($start = null, $items_per_page = null, $sort = null)
453
{
454
	global $scripturl, $txt, $context;
455
456
	$db = database();
457
458
	$request = $db->query('', '
459
		SELECT
460
			id_category, name, namespace, articles, status
461
		FROM {db_prefix}sp_categories' . (isset($sort) ? '
462
		ORDER BY {raw:sort}' : '') . (isset($start) ? '
463
		LIMIT {int:start}, {int:limit}' : ''),
464
		array(
465
			'sort' => $sort,
466
			'start' => $start,
467
			'limit' => $items_per_page,
468
		)
469
	);
470
	$categories = array();
471
	while ($row = $db->fetch_assoc($request))
472
	{
473
		$categories[$row['id_category']] = array(
474
			'id' => $row['id_category'],
475
			'category_id' => $row['namespace'],
476
			'name' => $row['name'],
477
			'href' => $scripturl . '?category=' . $row['namespace'],
478
			'link' => '<a href="' . $scripturl . '?category=' . $row['namespace'] . '">' . $row['name'] . '</a>',
479
			'articles' => $row['articles'],
480
			'status' => $row['status'],
481
			'status_image' => '<a href="' . $scripturl . '?action=admin;area=portalcategories;sa=status;category_id=' . $row['id_category'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '"
482
				onclick="sp_change_status(\'' . $row['id_category'] . '\', \'category\');return false;">' .
483
				sp_embed_image(empty($row['status']) ? 'deactive' : 'active', $txt['sp_admin_categories_' . (!empty($row['status']) ? 'de' : '') . 'activate'], null, null, true, 'status_image_' . $row['id_category']) . '</a>',
0 ignored issues
show
Bug introduced by
'status_image_' . $row['id_category'] of type string is incompatible with the type integer|null expected by parameter $id of sp_embed_image(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

483
				sp_embed_image(empty($row['status']) ? 'deactive' : 'active', $txt['sp_admin_categories_' . (!empty($row['status']) ? 'de' : '') . 'activate'], null, null, true, /** @scrutinizer ignore-type */ 'status_image_' . $row['id_category']) . '</a>',
Loading history...
484
		);
485
	}
486
	$db->free_result($request);
487
488
	return $categories;
489
}
490
491
/**
492
 * Checks if a namespace is already in use by a category_id
493
 *
494
 * @param int $id
495
 * @param string $namespace
496
 */
497
function sp_check_duplicate_category($id, $namespace = '')
498
{
499
	$db = database();
500
501
	$result = $db->query('', '
502
		SELECT 
503
			id_category
504
		FROM {db_prefix}sp_categories
505
		WHERE namespace = {string:namespace}
506
			AND id_category != {int:current}
507
		LIMIT {int:limit}',
508
		array(
509
			'limit' => 1,
510
			'namespace' => $namespace,
511
			'current' => (int) $id,
512
		)
513
	);
514
	list ($has_duplicate) = $db->fetch_row($result);
515
	$db->free_result($result);
516
517
	return $has_duplicate;
518
}
519
520
/**
521
 * Update an existing category or add a new one to the database
522
 *
523
 * If adding a new one, will return the id of the new category
524
 *
525
 * @param array $data field name to value for use in query
526
 * @param boolean $is_new
527
 *
528
 * @return int
529
 */
530
function sp_update_category($data, $is_new = false)
531
{
532
	$db = database();
533
534
	$id = $data['id'] ?? null;
535
536
	// Field definitions
537
	$fields = array(
538
		'namespace' => 'string',
539
		'name' => 'string',
540
		'description' => 'string',
541
		'permissions' => 'int',
542
		'status' => 'int',
543
	);
544
545
	// New category?
546
	if ($is_new)
547
	{
548
		unset($data['id']);
549
		$db->insert('', '
550
			{db_prefix}sp_categories',
551
			$fields,
552
			$data,
553
			array('id_category')
554
		);
555
		$id = $db->insert_id('{db_prefix}sp_categories', 'id_category');
556
	}
557
	// Update an existing one then
558
	else
559
	{
560
		$update_fields = array();
561
562
		foreach ($fields as $name => $type)
563
		{
564
			$update_fields[] = $name . ' = {' . $type . ':' . $name . '}';
565
		}
566
567
		$db->query('', '
568
			UPDATE {db_prefix}sp_categories
569
			SET ' . implode(', ', $update_fields) . '
570
			WHERE id_category = {int:id}', $data
571
		);
572
	}
573
574
	return $id;
575
}
576
577
/**
578
 * Removes a category or group of categories by id
579
 *
580
 * @param int[] $category_ids
581
 *
582
 * @return null
583
 */
584
function sp_delete_categories($category_ids = array())
585
{
586
	$db = database();
587
588
	// Remove the categories
589
	$db->query('', '
590
		DELETE FROM {db_prefix}sp_categories
591
		WHERE id_category IN ({array_int:categories})',
592
		array(
593
			'categories' => $category_ids,
594
		)
595
	);
596
597
	// And remove the articles that were in those categories
598
	$db->query('', '
599
		DELETE FROM {db_prefix}sp_articles
600
		WHERE id_category IN ({array_int:categories})',
601
		array(
602
			'categories' => $category_ids,
603
		)
604
	);
605
}
606
607
/**
608
 * Updates the total articles in a category
609
 *
610
 * @param int $category_id
611
 *
612
 * @return null
613
 */
614
function sp_category_update_total($category_id)
615
{
616
	$db = database();
617
618
	$db->query('', '
619
		UPDATE {db_prefix}sp_categories
620
		SET articles = articles - 1
621
		WHERE id_category = {int:id}',
622
		array(
623
			'id' => $category_id,
624
		)
625
	);
626
}
627
628
/**
629
 * Returns the total count of articles in the system
630
 *
631
 * @return int
632
 */
633
function sp_count_articles()
634
{
635
	$db = database();
636
637
	$request = $db->query('', '
638
		SELECT 
639
		    COUNT(*)
640
		FROM {db_prefix}sp_articles'
641
	);
642
	list ($total_articles) = $db->fetch_row($request);
643
	$db->free_result($request);
644
645
	return $total_articles;
646
}
647
648
/**
649
 * Loads all of the articles in the system
650
 * Returns an indexed array of the articles
651
 *
652
 * @param int $start
653
 * @param int $items_per_page
654
 * @param string $sort
655
 *
656
 * @return array
657
 */
658
function sp_load_articles($start, $items_per_page, $sort)
659
{
660
	global $scripturl, $txt, $context;
661
662
	$db = database();
663
664
	$request = $db->query('', '
665
		SELECT
666
			spa.id_article, spa.id_category, spa.title, spa.type, spa.date, spa.status,
667
			spc.name, spc.namespace AS category_namespace,
668
			IFNULL(m.id_member, 0) AS id_author, IFNULL(m.real_name, spa.member_name) AS author_name,
669
			spa.namespace AS article_namespace
670
		FROM {db_prefix}sp_articles AS spa
671
			INNER JOIN {db_prefix}sp_categories AS spc ON (spc.id_category = spa.id_category)
672
			LEFT JOIN {db_prefix}members AS m ON (m.id_member = spa.id_member)
673
		ORDER BY {raw:sort}
674
		LIMIT {int:start}, {int:limit}',
675
		array(
676
			'sort' => $sort,
677
			'start' => $start,
678
			'limit' => $items_per_page,
679
		)
680
	);
681
	$articles = array();
682
	while ($row = $db->fetch_assoc($request))
683
	{
684
		$articles[$row['id_article']] = array(
685
			'id' => $row['id_article'],
686
			'article_id' => $row['article_namespace'],
687
			'title' => $row['title'],
688
			'href' => $scripturl . '?article=' . $row['article_namespace'],
689
			'link' => '<a href="' . $scripturl . '?article=' . $row['article_namespace'] . '">' . $row['title'] . '</a>',
690
			'category_name' => $row['name'],
691
			'author_name' => $row['author_name'],
692
			'category' => array(
693
				'id' => $row['id_category'],
694
				'name' => $row['name'],
695
				'href' => $scripturl . '?category=' . $row['category_namespace'],
696
				'link' => '<a class="sp_cat_link" href="' . $scripturl . '?category=' . $row['category_namespace'] . '">' . $row['name'] . '</a>',
697
			),
698
			'author' => array(
699
				'id' => $row['id_author'],
700
				'name' => $row['author_name'],
701
				'href' => $scripturl . '?action=profile;u=' . $row['id_author'],
702
				'link' => $row['id_author']
703
					? ('<a href="' . $scripturl . '?action=profile;u=' . $row['id_author'] . '">' . $row['author_name'] . '</a>')
704
					: $row['author_name'],
705
			),
706
			'type' => $row['type'],
707
			'type_text' => $txt['sp_articles_type_' . $row['type']],
708
			'date' => standardTime($row['date']),
709
			'status' => $row['status'],
710
			'status_image' => '<a href="' . $scripturl . '?action=admin;area=portalarticles;sa=status;article_id=' . $row['id_article'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '" 
711
				onclick="sp_change_status(\'' . $row['id_article'] . '\', \'articles\');return false;">' .
712
				sp_embed_image(empty($row['status']) ? 'deactive' : 'active', $txt['sp_admin_articles_' . (!empty($row['status']) ? 'de' : '') . 'activate'], null, null, true, 'status_image_' . $row['id_article']) . '</a>',
0 ignored issues
show
Bug introduced by
'status_image_' . $row['id_article'] of type string is incompatible with the type integer|null expected by parameter $id of sp_embed_image(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

712
				sp_embed_image(empty($row['status']) ? 'deactive' : 'active', $txt['sp_admin_articles_' . (!empty($row['status']) ? 'de' : '') . 'activate'], null, null, true, /** @scrutinizer ignore-type */ 'status_image_' . $row['id_article']) . '</a>',
Loading history...
713
			'actions' => array(
714
				'edit' => '<a href="' . $scripturl . '?action=admin;area=portalarticles;sa=edit;article_id=' . $row['id_article'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '">' . sp_embed_image('modify') . '</a>',
715
				'delete' => '<a href="' . $scripturl . '?action=admin;area=portalarticles;sa=delete;article_id=' . $row['id_article'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '" onclick="return confirm(\'', $txt['sp_admin_articles_delete_confirm'], '\');">' . sp_embed_image('delete') . '</a>',
716
			)
717
		);
718
	}
719
	$db->free_result($request);
720
721
	return $articles;
722
}
723
724
/**
725
 * Removes a article or group of articles by id's
726
 *
727
 * @param int[]|int $article_ids
728
 */
729
function sp_delete_articles($article_ids = array())
730
{
731
	global $modSettings;
732
733
	$db = database();
734
735
	if (!is_array($article_ids))
736
	{
737
		$article_ids = array($article_ids);
738
	}
739
740
	$db->query('', '
741
		DELETE FROM {db_prefix}sp_articles
742
		WHERE id_article = {array_int:id}',
743
		array(
744
			'id' => $article_ids,
745
		)
746
	);
747
748
	// Remove attachments, thumbs, etc for these articles
749
	foreach ($article_ids as $aid)
750
	{
751
		$attachmentQuery = array(
752
			'id_article' => $aid,
753
			'id_folder' => $modSettings['sp_articles_attachment_dir'],
754
		);
755
756
		removeArticleAttachments($attachmentQuery);
757
	}
758
}
759
760
/**
761
 * Validates that an articles id is not duplicated in a given namespace
762
 *
763
 * return true if its a duplicate or false if its unique
764
 *
765
 * @param int $article_id
766
 * @param string $namespace
767
 *
768
 * @return bool
769
 */
770
function sp_duplicate_articles($article_id, $namespace)
771
{
772
	$db = database();
773
774
	$result = $db->query('', '
775
		SELECT
776
			id_article
777
		FROM {db_prefix}sp_articles
778
		WHERE namespace = {string:namespace}
779
			AND id_article != {int:current}
780
		LIMIT 1',
781
		array(
782
			'limit' => 1,
783
			'namespace' => $namespace,
784
			'current' => $article_id,
785
		)
786
	);
787
	list ($has_duplicate) = $db->fetch_row($result);
788
	$db->free_result($result);
789
790
	return $has_duplicate;
791
}
792
793
/**
794
 * Saves or updates an articles information
795
 *
796
 * - expects to have $context populated from sportal_get_articles()
797
 * - add items as a new article is is_new is true otherwise updates and existing one
798
 *
799
 * @param array $article_info array of fields details to save/update
800
 * @param boolean $is_new true for new insertion, false to update
801
 * @param boolean $update_counts true to update category counts
802
 *
803
 * @return int
804
 */
805
function sp_save_article($article_info, $is_new = false, $update_counts = true)
806
{
807
	global $context, $user_info;
808
809
	$db = database();
810
811
	// Our base article database looks like this, so shall you comply
812
	$fields = array(
813
		'id_category' => 'int',
814
		'namespace' => 'string',
815
		'title' => 'string',
816
		'body' => 'string',
817
		'type' => 'string',
818
		'permissions' => 'int',
819
		'styles' => 'int',
820
		'status' => 'int',
821
	);
822
823
	// Brand new, insert it
824
	if ($is_new)
825
	{
826
		// New will set this
827
		unset($article_info['id']);
828
829
		// If new we set these one time fields
830
		$fields = array_merge($fields, array(
831
			'id_member' => 'int',
832
			'member_name' => 'string',
833
			'date' => 'int',
834
		));
835
836
		// And populate them with data
837
		$article_info = array_merge($article_info, array(
838
			'id_member' => $user_info['id'],
839
			'member_name' => $user_info['name'],
840
			'date' => time(),
841
		));
842
843
		// Add the new article to the system
844
		$db->insert('', '
845
			{db_prefix}sp_articles',
846
			$fields,
847
			$article_info,
848
			array('id_article')
849
		);
850
		$article_info['id'] = $db->insert_id('{db_prefix}sp_articles', 'id_article');
851
	}
852
	// The editing so we update what was there
853
	else
854
	{
855
		// They may have chosen to [attach] to an existing image
856
		$currentAttachments = sportal_get_articles_attachments($article_info['id']);
857
		if (!empty($currentAttachments[$article_info['id']]))
858
		{
859
			foreach ($currentAttachments[$article_info['id']] as $attachment)
860
			{
861
				// Replace ila attach tags with the new valid attachment id and [spattach] tag
862
				$article_info['body'] = preg_replace('~\[attach(.*?)\]' . $attachment['id_attach'] . '\[\/attach\]~', '[spattach$1]' . $attachment['id_attach'] . '[/spattach]', $article_info['body']);
863
			}
864
		}
865
866
		$update_fields = array();
867
		foreach ($fields as $name => $type)
868
		{
869
			$update_fields[] = $name . ' = {' . $type . ':' . $name . '}';
870
		}
871
872
		$db->query('', '
873
			UPDATE {db_prefix}sp_articles
874
			SET ' . implode(', ', $update_fields) . '
875
			WHERE id_article = {int:id}',
876
			array_merge(array(
877
				'id' => $article_info['id']),
878
				$article_info)
879
		);
880
	}
881
882
	// Now is a good time to update the counters if needed
883
	if ($update_counts && ($is_new || $article_info['id_category'] != $context['article']['category']['id']))
884
	{
885
		// Increase the number of items in this category
886
		$db->query('', '
887
			UPDATE {db_prefix}sp_categories
888
			SET articles = articles + 1
889
			WHERE id_category = {int:id}',
890
			array(
891
				'id' => $article_info['id_category'],
892
			)
893
		);
894
895
		// Not new then moved, so decrease the old category count
896
		if (!$is_new)
897
		{
898
			$db->query('', '
899
				UPDATE {db_prefix}sp_categories
900
				SET articles = articles - 1
901
				WHERE id_category = {int:id}',
902
				array(
903
					'id' => $context['article']['category']['id'],
904
				)
905
			);
906
		}
907
	}
908
909
	return $article_info['id'];
910
}
911
912
/**
913
 * Returns the total count of pages in the system
914
 *
915
 * @return int
916
 */
917
function sp_count_pages()
918
{
919
	$db = database();
920
921
	$request = $db->query('', '
922
		SELECT 
923
		    COUNT(*)
924
		FROM {db_prefix}sp_pages'
925
	);
926
	list ($total_pages) = $db->fetch_row($request);
927
	$db->free_result($request);
928
929
	return $total_pages;
930
}
931
932
/**
933
 * Loads all of the pages in the system
934
 * Returns an indexed array of the pages
935
 *
936
 * @param int $start
937
 * @param int $items_per_page
938
 * @param string $sort
939
 *
940
 * @return array
941
 */
942
function sp_load_pages($start, $items_per_page, $sort)
943
{
944
	global $scripturl, $txt, $context;
945
946
	$db = database();
947
948
	$request = $db->query('', '
949
		SELECT
950
			id_page, namespace, title, type, views, status
951
		FROM {db_prefix}sp_pages
952
		ORDER BY {raw:sort}
953
		LIMIT {int:start}, {int:limit}',
954
		array(
955
			'sort' => $sort,
956
			'start' => $start,
957
			'limit' => $items_per_page,
958
		)
959
	);
960
	$pages = array();
961
	while ($row = $db->fetch_assoc($request))
962
	{
963
		$pages[$row['id_page']] = array(
964
			'id' => $row['id_page'],
965
			'page_id' => $row['namespace'],
966
			'title' => $row['title'],
967
			'href' => $scripturl . '?page=' . $row['namespace'],
968
			'link' => '<a href="' . $scripturl . '?page=' . $row['namespace'] . '">' . $row['title'] . '</a>',
969
			'type' => $row['type'],
970
			'type_text' => $txt['sp_pages_type_' . $row['type']],
971
			'views' => $row['views'],
972
			'status' => $row['status'],
973
			'status_image' => '<a href="' . $scripturl . '?action=admin;area=portalpages;sa=status;page_id=' . $row['id_page'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '"
974
				onclick="sp_change_status(\'' . $row['id_page'] . '\', \'page\');return false;">' .
975
				sp_embed_image(empty($row['status']) ? 'deactive' : 'active', $txt['sp_admin_pages_' . (!empty($row['status']) ? 'de' : '') . 'activate'], null, null, true, 'status_image_' . $row['id_page']) . '</a>',
0 ignored issues
show
Bug introduced by
'status_image_' . $row['id_page'] of type string is incompatible with the type integer|null expected by parameter $id of sp_embed_image(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

975
				sp_embed_image(empty($row['status']) ? 'deactive' : 'active', $txt['sp_admin_pages_' . (!empty($row['status']) ? 'de' : '') . 'activate'], null, null, true, /** @scrutinizer ignore-type */ 'status_image_' . $row['id_page']) . '</a>',
Loading history...
976
			'actions' => array(
977
				'edit' => '<a href="' . $scripturl . '?action=admin;area=portalpages;sa=edit;page_id=' . $row['id_page'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '">' . sp_embed_image('modify') . '</a>',
978
				'delete' => '<a href="' . $scripturl . '?action=admin;area=portalpages;sa=delete;page_id=' . $row['id_page'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '" onclick="return confirm(\'', $txt['sp_admin_pages_delete_confirm'], '\');">' . sp_embed_image('delete') . '</a>',
979
			)
980
		);
981
	}
982
	$db->free_result($request);
983
984
	return $pages;
985
}
986
987
/**
988
 * Removes a page or group of pages by id
989
 *
990
 * @param int[] $page_ids
991
 */
992
function sp_delete_pages($page_ids = array())
993
{
994
	$db = database();
995
996
	$db->query('', '
997
		DELETE FROM {db_prefix}sp_pages
998
		WHERE id_page IN ({array_int:pages})',
999
		array(
1000
			'pages' => $page_ids,
1001
		)
1002
	);
1003
}
1004
1005
/**
1006
 * Saves or updates an page
1007
 *
1008
 * - Add items as a new page is is_new is true otherwise updates and existing one
1009
 *
1010
 * @param array $page_info array of fields details to save/update
1011
 * @param boolean $is_new true for new insertion, false to update
1012
 *
1013
 * @return int
1014
 */
1015
function sp_save_page($page_info, $is_new = false)
1016
{
1017
	$db = database();
1018
1019
	// Our base page database looks like this, so shall you
1020
	$fields = array(
1021
		'namespace' => 'string',
1022
		'title' => 'string',
1023
		'body' => 'string',
1024
		'type' => 'string',
1025
		'permissions' => 'int',
1026
		'styles' => 'int',
1027
		'status' => 'int',
1028
	);
1029
1030
	// Brand new, insert it
1031
	if ($is_new)
1032
	{
1033
		unset($page_info['id']);
1034
1035
		$db->insert('', '
1036
			{db_prefix}sp_pages',
1037
			$fields,
1038
			$page_info,
1039
			array('id_page')
1040
		);
1041
1042
		$page_info['id'] = $db->insert_id('{db_prefix}sp_pages', 'id_page');
1043
	}
1044
	// The editing so we update what was there
1045
	else
1046
	{
1047
		$update_fields = array();
1048
		foreach ($fields as $name => $type)
1049
		{
1050
			$update_fields[] = $name . ' = {' . $type . ':' . $name . '}';
1051
		}
1052
1053
		$db->query('', '
1054
			UPDATE {db_prefix}sp_pages
1055
			SET ' . implode(', ', $update_fields) . '
1056
			WHERE id_page = {int:id}', $page_info
1057
		);
1058
	}
1059
1060
	return $page_info['id'];
1061
}
1062
1063
/**
1064
 * Checks for duplicate page names in the same namespace
1065
 *
1066
 * @param string $namespace
1067
 * @param int $page_id
1068
 */
1069
function sp_check_duplicate_pages($namespace, $page_id)
1070
{
1071
	$db = database();
1072
1073
	// Can't have the same name in the same space twice
1074
	$result = $db->query('', '
1075
		SELECT id_page
1076
		FROM {db_prefix}sp_pages
1077
		WHERE namespace = {string:namespace}
1078
			AND id_page != {int:current}
1079
		LIMIT {int:limit}',
1080
		array(
1081
			'limit' => 1,
1082
			'namespace' => Util::htmlspecialchars($namespace, ENT_QUOTES),
1083
			'current' => (int) $page_id,
1084
		)
1085
	);
1086
	list ($has_duplicate) = $db->fetch_row($result);
1087
	$db->free_result($result);
1088
1089
	return $has_duplicate;
1090
}
1091
1092
/**
1093
 * Returns the total count of shoutboxes in the system
1094
 *
1095
 * @return int
1096
 */
1097
function sp_count_shoutbox()
1098
{
1099
	$db = database();
1100
1101
	$request = $db->query('', '
1102
		SELECT 
1103
		    COUNT(*)
1104
		FROM {db_prefix}sp_shoutboxes'
1105
	);
1106
	list ($total_shoutbox) = $db->fetch_row($request);
1107
	$db->free_result($request);
1108
1109
	return $total_shoutbox;
1110
}
1111
1112
/**
1113
 * Loads all of the shoutboxes in the system
1114
 * Returns an indexed array of the shoutboxes
1115
 *
1116
 * @param int $start
1117
 * @param int $items_per_page
1118
 * @param string $sort
1119
 *
1120
 * @return array
1121
 */
1122
function sp_load_shoutbox($start, $items_per_page, $sort)
1123
{
1124
	global $scripturl, $txt, $context;
1125
1126
	$db = database();
1127
1128
	$request = $db->query('', '
1129
		SELECT
1130
			id_shoutbox, name, caching, status, num_shouts
1131
		FROM {db_prefix}sp_shoutboxes
1132
		ORDER BY id_shoutbox, {raw:sort}
1133
		LIMIT {int:start}, {int:limit}',
1134
		array(
1135
			'sort' => $sort,
1136
			'start' => $start,
1137
			'limit' => $items_per_page,
1138
		)
1139
	);
1140
	$shoutboxes = array();
1141
	while ($row = $db->fetch_assoc($request))
1142
	{
1143
		$shoutboxes[$row['id_shoutbox']] = array(
1144
			'id' => $row['id_shoutbox'],
1145
			'name' => $row['name'],
1146
			'shouts' => $row['num_shouts'],
1147
			'caching' => $row['caching'],
1148
			'status' => $row['status'],
1149
			'status_image' => '<a href="' . $scripturl . '?action=admin;area=portalshoutbox;sa=status;shoutbox_id=' . $row['id_shoutbox'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '">' . sp_embed_image(empty($row['status'])
1150
					? 'deactive' : 'active', $txt['sp_admin_shoutbox_' . (!empty($row['status']) ? 'de'
1151
					: '') . 'activate']) . '</a>',
1152
			'actions' => array(
1153
				'edit' => '<a href="' . $scripturl . '?action=admin;area=portalshoutbox;sa=edit;shoutbox_id=' . $row['id_shoutbox'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '">' . sp_embed_image('modify') . '</a>',
1154
				'prune' => '<a href="' . $scripturl . '?action=admin;area=portalshoutbox;sa=prune;shoutbox_id=' . $row['id_shoutbox'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '">' . sp_embed_image('bin') . '</a>',
1155
				'delete' => '<a href="' . $scripturl . '?action=admin;area=portalshoutbox;sa=delete;shoutbox_id=' . $row['id_shoutbox'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '" onclick="return confirm(\'', $txt['sp_admin_shoutbox_delete_confirm'], '\');">' . sp_embed_image('delete') . '</a>',
1156
			)
1157
		);
1158
	}
1159
	$db->free_result($request);
1160
1161
	return $shoutboxes;
1162
}
1163
1164
/**
1165
 * Removes a shoutbox or group of shoutboxes by id
1166
 *
1167
 * @param int[] $shoutbox_ids
1168
 */
1169
function sp_delete_shoutbox($shoutbox_ids = array())
1170
{
1171
	$db = database();
1172
1173
	$db->query('', '
1174
		DELETE FROM {db_prefix}sp_shoutboxes
1175
		WHERE id_shoutbox IN ({array_int:shoutbox})',
1176
		array(
1177
			'shoutbox' => $shoutbox_ids,
1178
		)
1179
	);
1180
1181
	$db->query('', '
1182
		DELETE FROM {db_prefix}sp_shouts
1183
		WHERE id_shoutbox IN ({array_int:shoutbox})',
1184
		array(
1185
			'shoutbox' => $shoutbox_ids,
1186
		)
1187
	);
1188
}
1189
1190
/**
1191
 * Checks if a shoutbox with the same name and id already exists
1192
 *
1193
 * @param string $name
1194
 * @param int $shoutbox_id
1195
 *
1196
 * @return int
1197
 */
1198
function sp_check_duplicate_shoutbox($name, $shoutbox_id)
1199
{
1200
	$db = database();
1201
1202
	$result = $db->query('', '
1203
		SELECT
1204
			id_shoutbox
1205
		FROM {db_prefix}sp_shoutboxes
1206
		WHERE name = {string:name}
1207
			AND id_shoutbox != {int:current}
1208
		LIMIT {int:limit}',
1209
		array(
1210
			'limit' => 1,
1211
			'name' => Util::htmlspecialchars($name, ENT_QUOTES),
1212
			'current' => (int) $shoutbox_id,
1213
		)
1214
	);
1215
	list ($has_duplicate) = $db->fetch_row($result);
1216
	$db->free_result($result);
1217
1218
	return $has_duplicate;
1219
}
1220
1221
/**
1222
 * Add or update a shoutbox on the system
1223
 *
1224
 * @param array $shoutbox_info
1225
 * @param bool $is_new
1226
 *
1227
 * @return int
1228
 */
1229
function sp_edit_shoutbox($shoutbox_info, $is_new = false)
1230
{
1231
	$db = database();
1232
1233
	// Our base shoutbox database looks like this
1234
	$fields = array(
1235
		'name' => 'string',
1236
		'permissions' => 'int',
1237
		'moderator_groups' => 'string',
1238
		'warning' => 'string',
1239
		'allowed_bbc' => 'string',
1240
		'height' => 'int',
1241
		'num_show' => 'int',
1242
		'num_max' => 'int',
1243
		'reverse' => 'int',
1244
		'caching' => 'int',
1245
		'refresh' => 'int',
1246
		'status' => 'int',
1247
	);
1248
1249
	// Brand new, insert it
1250
	if ($is_new)
1251
	{
1252
		// Drop any old id, get a new one
1253
		unset($shoutbox_info['id']);
1254
1255
		$db->insert('', '
1256
			{db_prefix}sp_shoutboxes',
1257
			$fields,
1258
			$shoutbox_info,
1259
			array('id_shoutbox')
1260
		);
1261
1262
		$shoutbox_info['id'] = $db->insert_id('{db_prefix}sp_shoutboxes', 'id_shoutbox');
1263
	}
1264
	// Then editing so we update what was there
1265
	else
1266
	{
1267
		$update_fields = array();
1268
		foreach ($fields as $name => $type)
1269
		{
1270
			$update_fields[] = $name . ' = {' . $type . ':' . $name . '}';
1271
		}
1272
1273
		$db->query('', '
1274
			UPDATE {db_prefix}sp_shoutboxes
1275
			SET ' . implode(', ', $update_fields) . '
1276
			WHERE id_shoutbox = {int:id}', $shoutbox_info
1277
		);
1278
	}
1279
1280
	return $shoutbox_info['id'];
1281
}
1282
1283
/**
1284
 * Gets a members ID from their userid or display name, used to
1285
 * prune a members shouts from a box
1286
 *
1287
 * @param string $member
1288
 *
1289
 * @return int
1290
 */
1291
function sp_shoutbox_prune_member($member)
1292
{
1293
	$db = database();
1294
1295
	$request = $db->query('', '
1296
		SELECT
1297
			id_member
1298
		FROM {db_prefix}members
1299
		WHERE member_name = {string:member}
1300
			OR real_name = {string:member}
1301
		LIMIT {int:limit}',
1302
		array(
1303
			'member' => strtr(trim(Util::htmlspecialchars($member, ENT_QUOTES)), array('\'' => '&#039;')),
1304
			'limit' => 1,
1305
		)
1306
	);
1307
	list ($member_id) = $db->fetch_row($request);
1308
	$db->free_result($request);
1309
1310
	return (int) $member_id;
1311
}
1312
1313
/**
1314
 * Removes selectively some shouts or all shouts from a shoutbox
1315
 *
1316
 * @param int $shoutbox_id
1317
 * @param array $where
1318
 * @param array $parameters
1319
 * @param bool $all
1320
 */
1321
function sp_prune_shoutbox($shoutbox_id, $where, $parameters, $all = false)
1322
{
1323
	$db = database();
1324
1325
	// Do the pruning
1326
	$db->query('', '
1327
		DELETE FROM {db_prefix}sp_shouts
1328
		WHERE ' . implode(' AND ', $where),
1329
		$parameters
1330
	);
1331
1332
	// If we did not get them all, how many shouts are left?
1333
	$total_shouts = 0;
1334
	if (!$all)
1335
	{
1336
		$request = $db->query('', '
1337
			SELECT COUNT(*)
1338
			FROM {db_prefix}sp_shouts
1339
			WHERE id_shoutbox = {int:shoutbox_id}
1340
			LIMIT {int:limit}',
1341
			array(
1342
				'shoutbox_id' => $shoutbox_id,
1343
				'limit' => 1,
1344
			)
1345
		);
1346
		list ($total_shouts) = $db->fetch_row($request);
1347
		$db->free_result($request);
1348
	}
1349
1350
	// Update the shout count
1351
	$db->query('', '
1352
		UPDATE {db_prefix}sp_shoutboxes
1353
		SET num_shouts = {int:total_shouts}
1354
		WHERE id_shoutbox = {int:shoutbox_id}',
1355
		array(
1356
			'shoutbox_id' => $shoutbox_id,
1357
			'total_shouts' => $total_shouts,
1358
		)
1359
	);
1360
}
1361
1362
/**
1363
 * Returns the total count of profiles in the system
1364
 *
1365
 * @param int $type (1 = permissions, 2 = styles, 3 = visability)
1366
 */
1367
function sp_count_profiles($type = 1)
1368
{
1369
	$db = database();
1370
1371
	$request = $db->query('', '
1372
		SELECT COUNT(*)
1373
		FROM {db_prefix}sp_profiles
1374
		WHERE type = {int:type}',
1375
		array(
1376
			'type' => $type,
1377
		)
1378
	);
1379
	list ($total_profiles) = $db->fetch_row($request);
1380
	$db->free_result($request);
1381
1382
	return $total_profiles;
1383
}
1384
1385
/**
1386
 * Loads all of the permission profiles in the system
1387
 * Returns an indexed array of them
1388
 *
1389
 * @param int $start
1390
 * @param int $items_per_page
1391
 * @param string $sort
1392
 * @param int $type (1 = permissions, 2 = styles, 3 = display)
1393
 *
1394
 * @return array
1395
 */
1396
function sp_load_profiles($start, $items_per_page, $sort, $type = 1)
1397
{
1398
	global $scripturl, $txt, $context;
1399
1400
	$db = database();
1401
1402
	// First load up all of the permission profiles names in the system
1403
	$request = $db->query('', '
1404
		SELECT
1405
			id_profile, name
1406
		FROM {db_prefix}sp_profiles
1407
		WHERE type = {int:type}
1408
		ORDER BY {raw:sort}
1409
		LIMIT {int:start}, {int:limit}',
1410
		array(
1411
			'type' => $type,
1412
			'sort' => $sort,
1413
			'start' => $start,
1414
			'limit' => $items_per_page,
1415
		)
1416
	);
1417
	$profiles = array();
1418
	while ($row = $db->fetch_assoc($request))
1419
	{
1420
		$profiles[$row['id_profile']] = array(
1421
			'id' => $row['id_profile'],
1422
			'name' => $row['name'],
1423
			'label' => $txt['sp_admin_profiles' . substr($row['name'], 1)] ?? $row['name'],
1424
			'actions' => array(
1425
				'edit' => '<a href="' . $scripturl . '?action=admin;area=portalprofiles;sa=editpermission;profile_id=' . $row['id_profile'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '">' . sp_embed_image('modify') . '</a>',
1426
				'delete' => '<a href="' . $scripturl . '?action=admin;area=portalprofiles;sa=deletepermission;profile_id=' . $row['id_profile'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '" onclick="return confirm(\'', $txt['sp_admin_profiles_delete_confirm'], '\');">' . sp_embed_image('delete') . '</a>',
1427
			)
1428
		);
1429
	}
1430
	$db->free_result($request);
1431
1432
	// Now for each profile, load up the specific in-use for each area of the portal
1433
	switch ($type)
1434
	{
1435
		case 2:
1436
			$select = 'styles, COUNT(*) AS used';
1437
			$area = array('articles', 'blocks', 'pages');
1438
			$group = 'styles';
1439
			break;
1440
		case 3:
1441
			$select = 'visibility, COUNT(*) AS used';
1442
			$area = array('blocks');
1443
			$group = 'visibility';
1444
			break;
1445
		default:
1446
			$select = 'permissions, COUNT(*) AS used';
1447
			$area = array('articles', 'blocks', 'categories', 'pages', 'shoutboxes');
1448
			$group = 'permissions';
1449
			break;
1450
	}
1451
1452
	foreach ($area as $module)
1453
	{
1454
		$request = $db->query('', '
1455
			SELECT ' . $select . '
1456
			FROM {db_prefix}sp_' . $module . '
1457
			GROUP BY ' . $group
1458
		);
1459
		while ($row = $db->fetch_assoc($request))
1460
		{
1461
			if (isset($profiles[$row[$group]]))
1462
			{
1463
				$profiles[$row[$group]][$module] = $row['used'];
1464
			}
1465
		}
1466
		$db->free_result($request);
1467
	}
1468
1469
	return $profiles;
1470
}
1471
1472
/**
1473
 * Removes a group of profiles by id
1474
 *
1475
 * @param int[] $remove_ids
1476
 */
1477
function sp_delete_profiles($remove_ids = array())
1478
{
1479
	$db = database();
1480
1481
	$db->query('', '
1482
		DELETE FROM {db_prefix}sp_profiles
1483
		WHERE id_profile IN ({array_int:profiles})',
1484
		array(
1485
			'profiles' => $remove_ids,
1486
		)
1487
	);
1488
}
1489
1490
/**
1491
 * Updates the position of the block in the portal (column and row in column)
1492
 *
1493
 * - Makes room above or below a position where a new block is inserted by renumbering
1494
 *
1495
 * @param int $current_row
1496
 * @param int $row
1497
 * @param int $col
1498
 * @param boolean $decrement
1499
 *
1500
 * @return null
1501
 */
1502
function sp_update_block_row($current_row, $row, $col, $decrement = true)
1503
{
1504
	$db = database();
1505
1506
	if ($decrement)
1507
	{
1508
		$db->query('', '
1509
			UPDATE {db_prefix}sp_blocks
1510
			SET row = row - 1
1511
			WHERE col = {int:col}
1512
				AND row > {int:start}
1513
				AND row <= {int:end}',
1514
			array(
1515
				'col' => (int) $col,
1516
				'start' => $current_row,
1517
				'end' => $row,
1518
			)
1519
		);
1520
	}
1521
	else
1522
	{
1523
		$db->query('', '
1524
			UPDATE {db_prefix}sp_blocks
1525
			SET row = row + 1
1526
			WHERE col = {int:col}
1527
				AND row >= {int:start}' . (!empty($current_row) ? '
1528
				AND row < {int:end}' : ''),
1529
			array(
1530
				'col' => (int) $col,
1531
				'start' => $row,
1532
				'end' => !empty($current_row) ? $current_row : 0,
1533
			)
1534
		);
1535
	}
1536
}
1537
1538
/**
1539
 * Update a portals block display
1540
 *
1541
 * @param int $id
1542
 * @param array $data
1543
 *
1544
 * @return null
1545
 */
1546
function sp_update_block_visibility($id, $data)
1547
{
1548
	$db = database();
1549
1550
	$db->query('', '
1551
		UPDATE {db_prefix}sp_blocks
1552
		SET
1553
			display = {string:display},
1554
			display_custom = {string:display_custom}
1555
		WHERE id_block = {int:id}',
1556
		array(
1557
			'id' => $id,
1558
			'display' => $data['display'],
1559
			'display_custom' => $data['display_custom'],
1560
		)
1561
	);
1562
}
1563
1564
/**
1565
 * Fetches the rows from a specified column and returns the values
1566
 *
1567
 * - If a current block ID is not specified the next available row number in
1568
 * the specified column is returned
1569
 * - If a block id is specified, its row number + 1 is returned
1570
 *
1571
 * @param int $block_column
1572
 * @param int $block_id
1573
 */
1574
function sp_block_nextrow($block_column, $block_id = 0)
1575
{
1576
	$db = database();
1577
1578
	$request = $db->query('', '
1579
		SELECT
1580
			row
1581
		FROM {db_prefix}sp_blocks
1582
		WHERE col = {int:col}' . (!empty($block_id) ? '
1583
			AND id_block != {int:current_id}' : '') . '
1584
		ORDER BY row DESC
1585
		LIMIT 1',
1586
		array(
1587
			'col' => $block_column,
1588
			'current_id' => $block_id,
1589
		)
1590
	);
1591
	list ($row) = $db->fetch_row($request);
1592
	$db->free_result($request);
1593
1594
	return $row + 1;
1595
}
1596
1597
/**
1598
 * Inserts a new block to the portal
1599
 *
1600
 * @param array $blockInfo
1601
 */
1602
function sp_block_insert($blockInfo)
1603
{
1604
	$db = database();
1605
1606
	$db->insert('', '
1607
		{db_prefix}sp_blocks',
1608
		array(
1609
			'label' => 'string', 'type' => 'string', 'col' => 'int', 'row' => 'int', 'permissions' => 'int', 'styles' => 'int',
1610
			'visibility' => 'int', 'state' => 'int', 'force_view' => 'int'),
1611
		$blockInfo,
1612
		array('id_block')
1613
	);
1614
1615
	return $db->insert_id('{db_prefix}sp_blocks', 'id_block');
1616
}
1617
1618
/**
1619
 * Updates an existing portal block with new values
1620
 *
1621
 * - Removes all parameters stored with the box in anticipation of new
1622
 * ones being supplied
1623
 *
1624
 * @param array $blockInfo
1625
 */
1626
function sp_block_update($blockInfo)
1627
{
1628
	$db = database();
1629
1630
	// The fields in the database
1631
	$block_fields = array(
1632
		"label = {string:label}",
1633
		"permissions = {int:permissions}",
1634
		"styles={int:styles}",
1635
		"visibility = {int:visibility}",
1636
		"state = {int:state}",
1637
		"force_view = {int:force_view}",
1638
	);
1639
1640
	if (!empty($blockInfo['row']))
1641
	{
1642
		$block_fields[] = "row = {int:row}";
1643
	}
1644
	else
1645
	{
1646
		unset($blockInfo['row']);
1647
	}
1648
1649
	// Update all the blocks fields
1650
	$db->query('', '
1651
		UPDATE {db_prefix}sp_blocks
1652
		SET ' . implode(', ', $block_fields) . '
1653
		WHERE id_block = {int:id}', $blockInfo
1654
	);
1655
1656
	// Remove any parameters it has
1657
	$db->query('', '
1658
		DELETE FROM {db_prefix}sp_parameters
1659
		WHERE id_block = {int:id}',
1660
		array(
1661
			'id' => $blockInfo['id'],
1662
		)
1663
	);
1664
}
1665
1666
/**
1667
 * Inserts parameters for a specific block
1668
 *
1669
 * @param array $new_parameters
1670
 * @param int $id_block
1671
 */
1672
function sp_block_insert_parameters($new_parameters, $id_block)
1673
{
1674
	$db = database();
1675
1676
	$parameters = array();
1677
	foreach ($new_parameters as $variable => $value)
1678
	{
1679
		$parameters[] = array(
1680
			'id_block' => $id_block,
1681
			'variable' => $variable,
1682
			'value' => $value,
1683
		);
1684
	}
1685
1686
	$db->insert('', '
1687
		{db_prefix}sp_parameters',
1688
		array('id_block' => 'int', 'variable' => 'string', 'value' => 'string'),
1689
		$parameters,
1690
		array()
1691
	);
1692
}
1693
1694
/**
1695
 * Returns the current column and row for a given block id
1696
 *
1697
 * @param int $block_id
1698
 *
1699
 * @return array
1700
 */
1701
function sp_block_get_position($block_id)
1702
{
1703
	$db = database();
1704
1705
	$request = $db->query('', '
1706
		SELECT
1707
			col, row
1708
		FROM {db_prefix}sp_blocks
1709
		WHERE id_block = {int:block_id}
1710
		LIMIT 1',
1711
		array(
1712
			'block_id' => $block_id,
1713
		)
1714
	);
1715
	list ($current_side, $current_row) = $db->fetch_row($request);
1716
	$db->free_result($request);
1717
1718
	return array($current_side, $current_row);
1719
}
1720
1721
/**
1722
 * Move a block to the end of a new column
1723
 *
1724
 * @param int $block_id
1725
 * @param int $target_side
1726
 */
1727
function sp_block_move_col($block_id, $target_side)
1728
{
1729
	$db = database();
1730
1731
	// Moving to a new column, lets place it at the end
1732
	$current_row = 100;
1733
1734
	$db->query('', '
1735
		UPDATE {db_prefix}sp_blocks
1736
		SET col = {int:target_side}, row = {int:temp_row}
1737
		WHERE id_block = {int:block_id}',
1738
		array(
1739
			'target_side' => $target_side,
1740
			'temp_row' => $current_row,
1741
			'block_id' => $block_id,
1742
		)
1743
	);
1744
}
1745
1746
/**
1747
 * Adds the portal block to the new row position
1748
 *
1749
 * - Opens up space in the column by shift all rows below the insertion point down one
1750
 * - Adds the block ID to the specified column and row
1751
 *
1752
 * @param int $block_id
1753
 * @param int $target_side
1754
 * @param int $target_row
1755
 */
1756
function sp_blocks_move_row($block_id, $target_side, $target_row)
1757
{
1758
	$db = database();
1759
1760
	// Shift all the rows below the insertion point down one
1761
	$db->query('', '
1762
		UPDATE {db_prefix}sp_blocks
1763
		SET row = row + 1
1764
		WHERE col = {int:target_side}
1765
			AND row >= {int:target_row}',
1766
		array(
1767
			'target_side' => $target_side,
1768
			'target_row' => $target_row,
1769
		)
1770
	);
1771
1772
	// Set the new block to the now available row position
1773
	$db->query('', '
1774
		UPDATE {db_prefix}sp_blocks
1775
		SET row = {int:target_row}
1776
		WHERE id_block = {int:block_id}',
1777
		array(
1778
			'target_row' => $target_row,
1779
			'block_id' => $block_id,
1780
		)
1781
	);
1782
}
1783
1784
/**
1785
 * Remove a block from the portal
1786
 *
1787
 * - removes the block from the portal
1788
 * - removes the blocks parameters
1789
 *
1790
 * @param int $block_id
1791
 */
1792
function sp_block_delete($block_id)
1793
{
1794
	$db = database();
1795
1796
	$block_id = (int) $block_id;
1797
1798
	// No block
1799
	$db->query('', '
1800
		DELETE FROM {db_prefix}sp_blocks
1801
		WHERE id_block = {int:id}',
1802
		array(
1803
			'id' => $block_id,
1804
		)
1805
	);
1806
1807
	// No parameters
1808
	$db->query('', '
1809
		DELETE FROM {db_prefix}sp_parameters
1810
		WHERE id_block = {int:id}',
1811
		array(
1812
			'id' => $block_id,
1813
		)
1814
	);
1815
}
1816
1817
/**
1818
 * Function to add or update a profile, style, permissions or display
1819
 *
1820
 * @param array $profile_info The data to insert/update
1821
 * @param bool $is_new if to update or insert
1822
 *
1823
 * @return int
1824
 */
1825
function sp_add_permission_profile($profile_info, $is_new = false)
1826
{
1827
	$db = database();
1828
1829
	// Our database fields
1830
	$fields = array(
1831
		'type' => 'int',
1832
		'name' => 'string',
1833
		'value' => 'string',
1834
	);
1835
1836
	// A new profile?
1837
	if ($is_new)
1838
	{
1839
		// Don't need this, we will create it instead
1840
		unset($profile_info['id']);
1841
1842
		$db->insert('',
1843
			'{db_prefix}sp_profiles',
1844
			$fields,
1845
			$profile_info,
1846
			array('id_profile')
1847
		);
1848
1849
		$profile_info['id'] = $db->insert_id('{db_prefix}sp_profiles', 'id_profile');
1850
	}
1851
	// Or an edit, we do a little update
1852
	else
1853
	{
1854
		$update_fields = array();
1855
		foreach ($fields as $name => $type)
1856
		{
1857
			$update_fields[] = $name . ' = {' . $type . ':' . $name . '}';
1858
		}
1859
1860
		$db->query('', '
1861
			UPDATE {db_prefix}sp_profiles
1862
			SET ' . implode(', ', $update_fields) . '
1863
			WHERE id_profile = {int:id}',
1864
			$profile_info
1865
		);
1866
	}
1867
1868
	return (int) $profile_info['id'];
1869
}
1870
1871
/**
1872
 * Removes a single permission profile from the system
1873
 *
1874
 * @param int $profile_id
1875
 */
1876
function sp_delete_profile($profile_id)
1877
{
1878
	$db = database();
1879
1880
	$db->query('', '
1881
		DELETE FROM {db_prefix}sp_profiles
1882
		WHERE id_profile = {int:id}',
1883
		array(
1884
			'id' => $profile_id,
1885
		)
1886
	);
1887
}
1888
1889
/**
1890
 * Loads boards and pages for template selection
1891
 *
1892
 * - Returns the results in $context for the template
1893
 *
1894
 * @return array
1895
 */
1896
function sp_block_template_helpers()
1897
{
1898
	$db = database();
1899
1900
	$helpers = array();
1901
1902
	// Get a list of board names for use in the template
1903
	$request = $db->query('', '
1904
		SELECT
1905
			id_board, name
1906
		FROM {db_prefix}boards
1907
		WHERE redirect = {string:empty}
1908
		ORDER BY name DESC',
1909
		array(
1910
			'empty' => '',
1911
		)
1912
	);
1913
	$helpers['boards'] = array();
1914
	while ($row = $db->fetch_assoc($request))
1915
		$helpers['boards']['b' . $row['id_board']] = $row['name'];
1916
	$db->free_result($request);
1917
1918
	// Get all the pages loaded in the system for template use
1919
	$request = $db->query('', '
1920
		SELECT
1921
			id_page, title
1922
		FROM {db_prefix}sp_pages
1923
		ORDER BY title DESC'
1924
	);
1925
	$helpers['pages'] = array();
1926
	while ($row = $db->fetch_assoc($request))
1927
		$helpers['pages']['p' . $row['id_page']] = $row['title'];
1928
	$db->free_result($request);
1929
1930
	// Same for categories
1931
	$request = $db->query('', '
1932
		SELECT
1933
			id_category, name
1934
		FROM {db_prefix}sp_categories
1935
		ORDER BY name DESC'
1936
	);
1937
	$helpers['categories'] = array();
1938
	while ($row = $db->fetch_assoc($request))
1939
		$helpers['categories']['c' . $row['id_category']] = $row['name'];
1940
	$db->free_result($request);
1941
1942
	// And finish up with articles
1943
	$request = $db->query('', '
1944
		SELECT
1945
			id_article, title
1946
		FROM {db_prefix}sp_articles
1947
		ORDER BY title DESC'
1948
	);
1949
	$helpers['articles'] = array();
1950
	while ($row = $db->fetch_assoc($request))
1951
		$helpers['articles']['a' . $row['id_article']] = $row['title'];
1952
	$db->free_result($request);
1953
1954
	return $helpers;
1955
}
1956
1957
/**
1958
 * Remove a group of menus from the system
1959
 *
1960
 * @param int|int[] $remove_ids
1961
 */
1962
function sp_remove_menu($remove_ids)
1963
{
1964
	$db = database();
1965
1966
	if (!is_array($remove_ids))
1967
	{
1968
		$remove_ids = array($remove_ids);
1969
	}
1970
1971
	$db->query('', '
1972
		DELETE FROM {db_prefix}sp_custom_menus
1973
		WHERE id_menu IN ({array_int:menus})',
1974
		array(
1975
			'menus' => $remove_ids,
1976
		)
1977
	);
1978
}
1979
1980
/**
1981
 * Remove the menus items
1982
 *
1983
 * @param int|int[] $remove_ids
1984
 */
1985
function sp_remove_menu_items($remove_ids)
1986
{
1987
	$db = database();
1988
1989
	if (!is_array($remove_ids))
1990
	{
1991
		$remove_ids = array($remove_ids);
1992
	}
1993
1994
	$db->query('', '
1995
		DELETE FROM {db_prefix}sp_menu_items
1996
		WHERE id_menu = {array_int:id}',
1997
		array(
1998
			'id' => $remove_ids,
1999
		)
2000
	);
2001
}
2002
2003
/**
2004
 * Determine the menu count, used for create List
2005
 *
2006
 * @return int
2007
 */
2008
function sp_menu_count()
2009
{
2010
	$db = database();
2011
2012
	$request = $db->query('', '
2013
		SELECT COUNT(*)
2014
		FROM {db_prefix}sp_custom_menus'
2015
	);
2016
	list ($total_menus) = $db->fetch_row($request);
2017
	$db->free_result($request);
2018
2019
	return $total_menus;
2020
}
2021
2022
/**
2023
 * Return menu & items, helper function for createlist
2024
 *
2025
 * @param int $start
2026
 * @param int $items_per_page
2027
 * @param string $sort
2028
 *
2029
 * @return array
2030
 */
2031
function sp_custom_menu_items($start, $items_per_page, $sort)
2032
{
2033
	$db = database();
2034
2035
	$request = $db->query('', '
2036
		SELECT
2037
			cm.id_menu, cm.name, COUNT(mi.id_item) AS items
2038
		FROM {db_prefix}sp_custom_menus AS cm
2039
			LEFT JOIN {db_prefix}sp_menu_items AS mi ON (mi.id_menu = cm.id_menu)
2040
		GROUP BY cm.id_menu
2041
		ORDER BY {raw:sort}
2042
		LIMIT {int:start}, {int:limit}',
2043
		array(
2044
			'sort' => $sort,
2045
			'start' => $start,
2046
			'limit' => $items_per_page,
2047
		)
2048
	);
2049
	$menus = array();
2050
	while ($row = $db->fetch_assoc($request))
2051
	{
2052
		$menus[$row['id_menu']] = array(
2053
			'id' => $row['id_menu'],
2054
			'name' => $row['name'],
2055
			'items' => $row['items'],
2056
		);
2057
	}
2058
	$db->free_result($request);
2059
2060
	return $menus;
2061
}
2062
2063
/**
2064
 * Function to add or update a menu
2065
 *
2066
 * @param array $menu_info The data to insert/update
2067
 * @param bool $is_new if to update or insert
2068
 *
2069
 * @return int
2070
 */
2071
function sp_add_menu($menu_info, $is_new = false)
2072
{
2073
	$db = database();
2074
2075
	// Our database fields
2076
	$fields = array(
2077
		'name' => 'string',
2078
	);
2079
2080
	// A new profile?
2081
	if ($is_new)
2082
	{
2083
		// Don't need this, we will create it instead
2084
		unset($menu_info['id']);
2085
2086
		$db->insert('',
2087
			'{db_prefix}sp_custom_menus',
2088
			$fields,
2089
			$menu_info,
2090
			array('id_menu')
2091
		);
2092
2093
		$menu_info['id'] = $db->insert_id('{db_prefix}sp_custom_menus', 'id_menu');
2094
	}
2095
	// Or an edit, we do a little update
2096
	else
2097
	{
2098
		$update_fields = array();
2099
		foreach ($fields as $name => $type)
2100
		{
2101
			$update_fields[] = $name . ' = {' . $type . ':' . $name . '}';
2102
		}
2103
2104
		$db->query('', '
2105
			UPDATE {db_prefix}sp_custom_menus
2106
			SET ' . implode(', ', $update_fields) . '
2107
			WHERE id_menu = {int:id}',
2108
			$menu_info
2109
		);
2110
	}
2111
2112
	return (int) $menu_info['id'];
2113
}
2114
2115
/**
2116
 * Check for duplicate items in a menu / namespace
2117
 *
2118
 * @param $id
2119
 * @param $namespace
2120
 *
2121
 * @return mixed
2122
 */
2123
function sp_menu_check_duplicate_items($id, $namespace)
2124
{
2125
	$db = database();
2126
2127
	$result = $db->query('', '
2128
		SELECT
2129
			id_item
2130
		FROM {db_prefix}sp_menu_items
2131
		WHERE namespace = {string:namespace}
2132
			AND id_item != {int:current}
2133
		LIMIT {int:limit}',
2134
		array(
2135
			'namespace' => $namespace,
2136
			'current' => $id,
2137
			'limit' => 1,
2138
		)
2139
	);
2140
	list ($has_duplicate) = $db->fetch_row($result);
2141
	$db->free_result($result);
2142
2143
	return $has_duplicate;
2144
}
2145
2146
/**
2147
 * Add or update custom items to a custom menu
2148
 *
2149
 * @param $item_info
2150
 * @param $is_new
2151
 *
2152
 * @return mixed
2153
 */
2154
function sp_add_menu_item($item_info, $is_new)
2155
{
2156
	$db = database();
2157
2158
	// Our database fields
2159
	$fields = array(
2160
		'id_menu' => 'int',
2161
		'namespace' => 'string',
2162
		'title' => 'string',
2163
		'href' => 'string',
2164
		'target' => 'int',
2165
	);
2166
2167
	// Adding a new item
2168
	if ($is_new)
2169
	{
2170
		// We will get a new one for this
2171
		unset($item_info['id']);
2172
2173
		$db->insert('',
2174
			'{db_prefix}sp_menu_items',
2175
			$fields,
2176
			$item_info,
2177
			array('id_item')
2178
		);
2179
2180
		$item_info['id'] = $db->insert_id('{db_prefix}sp_menu_items', 'id_item');
2181
	}
2182
	// Update what we have
2183
	else
2184
	{
2185
		$update_fields = array();
2186
		foreach ($fields as $name => $type)
2187
		{
2188
			$update_fields[] = $name . ' = {' . $type . ':' . $name . '}';
2189
		}
2190
2191
		$db->query('', '
2192
			UPDATE {db_prefix}sp_menu_items
2193
			SET ' . implode(', ', $update_fields) . '
2194
			WHERE id_item = {int:id}',
2195
			$item_info
2196
		);
2197
	}
2198
2199
	return $item_info['id'];
2200
}
2201
2202
/**
2203
 * Determine the menu count, used for create List
2204
 *
2205
 * @param int $menu_id
2206
 * @return int
2207
 */
2208
function sp_menu_item_count($menu_id)
2209
{
2210
	$db = database();
2211
2212
	$request = $db->query('', '
2213
		SELECT COUNT(*)
2214
		FROM {db_prefix}sp_menu_items
2215
		WHERE id_menu = {int:menu}',
2216
		array(
2217
			'menu' => $menu_id,
2218
		)
2219
	);
2220
	list ($total_menus) = $db->fetch_row($request);
2221
	$db->free_result($request);
2222
2223
	return $total_menus;
2224
}
2225
2226
/**
2227
 * Return menu items, helper function for createlist
2228
 *
2229
 * @param int $start
2230
 * @param int $items_per_page
2231
 * @param string $sort
2232
 * @param int $menu_id
2233
 *
2234
 * @return array
2235
 */
2236
function sp_menu_items($start, $items_per_page, $sort, $menu_id)
2237
{
2238
	global $txt;
2239
2240
	$db = database();
2241
2242
	$request = $db->query('', '
2243
		SELECT
2244
			id_item, title, namespace, target
2245
		FROM {db_prefix}sp_menu_items
2246
		WHERE id_menu = {int:menu}
2247
		ORDER BY {raw:sort}
2248
		LIMIT {int:start}, {int:limit}',
2249
		array(
2250
			'menu' => $menu_id,
2251
			'sort' => $sort,
2252
			'start' => $start,
2253
			'limit' => $items_per_page,
2254
		)
2255
	);
2256
	$items = array();
2257
	while ($row = $db->fetch_assoc($request))
2258
	{
2259
		$items[$row['id_item']] = array(
2260
			'id' => $row['id_item'],
2261
			'menu' => $menu_id,
2262
			'title' => $row['title'],
2263
			'namespace' => $row['namespace'],
2264
			'target' => $txt['sp_admin_menus_link_target_' . $row['target']],
2265
		);
2266
	}
2267
	$db->free_result($request);
2268
2269
	return $items;
2270
}
2271
2272
/**
2273
 * SCEditor spplugin Plugin.
2274
 * Used to set editor initial state and the setup so type conversion can
2275
 * happen.  Just call the plugin with initial and new states.
2276
 *
2277
 * @param string $type
2278
 */
2279
function addConversionJS($type)
2280
{
2281
	// Set the globals, spplugin will be called with editor init to set mode
2282
	addInlineJavascript('
2283
		let start_state = "' . $type . '",
2284
			editor;
2285
			
2286
		$.sceditor.plugins.spplugin = function(initial_state, new_state) {
2287
			let base = this;
2288
		
2289
			if (typeof new_state !== "undefined")
2290
			{
2291
				sp_to_new(initial_state, new_state);
2292
			}
2293
		
2294
			base.init = function() {
2295
				editor = this;
2296
			};
2297
		
2298
			base.signalReady = function() {
2299
				if (start_state !== "bbc")
2300
				{
2301
					editor.sourceMode(true);
2302
					document.getElementById("editor_toolbar_container").style.display = "none";
2303
				}
2304
			};
2305
		};
2306
	');
2307
}