Issues (1061)

Sources/ManagePaid.php (7 issues)

1
<?php
2
3
/**
4
 * This file contains all the administration functions for subscriptions.
5
 * (and some more than that :P)
6
 *
7
 * Simple Machines Forum (SMF)
8
 *
9
 * @package SMF
10
 * @author Simple Machines https://www.simplemachines.org
11
 * @copyright 2020 Simple Machines and individual contributors
12
 * @license https://www.simplemachines.org/about/smf/license.php BSD
13
 *
14
 * @version 2.1 RC2
15
 */
16
17
if (!defined('SMF'))
18
	die('No direct access...');
19
20
/**
21
 * The main entrance point for the 'Paid Subscription' screen, calling
22
 * the right function based on the given sub-action.
23
 * It defaults to sub-action 'view'.
24
 * Accessed from ?action=admin;area=paidsubscribe.
25
 * It requires admin_forum permission for admin based actions.
26
 */
27
function ManagePaidSubscriptions()
28
{
29
	global $context, $txt, $modSettings;
30
31
	// Load the required language and template.
32
	loadLanguage('ManagePaid');
33
	loadTemplate('ManagePaid');
34
35
	if (!empty($modSettings['paid_enabled']))
36
		$subActions = array(
37
			'modify' => array('ModifySubscription', 'admin_forum'),
38
			'modifyuser' => array('ModifyUserSubscription', 'admin_forum'),
39
			'settings' => array('ModifySubscriptionSettings', 'admin_forum'),
40
			'view' => array('ViewSubscriptions', 'admin_forum'),
41
			'viewsub' => array('ViewSubscribedUsers', 'admin_forum'),
42
		);
43
	else
44
		$subActions = array(
45
			'settings' => array('ModifySubscriptionSettings', 'admin_forum'),
46
		);
47
48
	// Default the sub-action to 'view subscriptions', but only if they have already set things up..
49
	$_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : (!empty($modSettings['paid_currency_symbol']) && !empty($modSettings['paid_enabled']) ? 'view' : 'settings');
50
51
	// Make sure you can do this.
52
	isAllowedTo($subActions[$_REQUEST['sa']][1]);
53
54
	$context['page_title'] = $txt['paid_subscriptions'];
55
56
	// Tabs for browsing the different subscription functions.
57
	$context[$context['admin_menu_name']]['tab_data'] = array(
58
		'title' => $txt['paid_subscriptions'],
59
		'help' => '',
60
		'description' => $txt['paid_subscriptions_desc'],
61
	);
62
	if (!empty($modSettings['paid_enabled']))
63
		$context[$context['admin_menu_name']]['tab_data']['tabs'] = array(
64
			'view' => array(
65
				'description' => $txt['paid_subs_view_desc'],
66
			),
67
			'settings' => array(
68
				'description' => $txt['paid_subs_settings_desc'],
69
			),
70
		);
71
72
	call_integration_hook('integrate_manage_subscriptions', array(&$subActions));
73
74
	// Call the right function for this sub-action.
75
	call_helper($subActions[$_REQUEST['sa']][0]);
76
}
77
78
/**
79
 * Set any setting related to paid subscriptions, i.e.
80
 * modify which payment methods are to be used.
81
 * It requires the moderate_forum permission
82
 * Accessed from ?action=admin;area=paidsubscribe;sa=settings.
83
 *
84
 * @param bool $return_config Whether or not to return the $config_vars array (used for admin search)
85
 * @return void|array Returns nothing or returns the config_vars array if $return_config is true
86
 */
87
function ModifySubscriptionSettings($return_config = false)
88
{
89
	global $context, $txt, $modSettings, $sourcedir, $smcFunc, $scripturl;
90
91
	if (!empty($modSettings['paid_enabled']))
92
	{
93
		// If the currency is set to something different then we need to set it to other for this to work and set it back shortly.
94
		$modSettings['paid_currency'] = !empty($modSettings['paid_currency_code']) ? $modSettings['paid_currency_code'] : '';
95
		if (!empty($modSettings['paid_currency_code']) && !in_array($modSettings['paid_currency_code'], array('usd', 'eur', 'gbp', 'cad', 'aud')))
96
			$modSettings['paid_currency'] = 'other';
97
98
		// These are all the default settings.
99
		$config_vars = array(
100
			array(
101
				'check',
102
				'paid_enabled'
103
			),
104
			'',
105
106
			array(
107
				'select',
108
				'paid_email',
109
				array(
110
					0 => $txt['paid_email_no'],
111
					1 => $txt['paid_email_error'],
112
					2 => $txt['paid_email_all']
113
				),
114
				'subtext' => $txt['paid_email_desc']
115
			),
116
			array(
117
				'email',
118
				'paid_email_to',
119
				'subtext' => $txt['paid_email_to_desc'],
120
				'size' => 60
121
			),
122
			'',
123
124
			'dummy_currency' => array(
125
				'select',
126
				'paid_currency',
127
				array(
128
					'usd' => $txt['usd'],
129
					'eur' => $txt['eur'],
130
					'gbp' => $txt['gbp'],
131
					'cad' => $txt['cad'],
132
					'aud' => $txt['aud'],
133
					'other' => $txt['other']
134
				),
135
				'javascript' => 'onchange="toggleOther();"'
136
			),
137
			array(
138
				'text',
139
				'paid_currency_code',
140
				'subtext' => $txt['paid_currency_code_desc'],
141
				'size' => 5,
142
				'force_div_id' => 'custom_currency_code_div'
143
			),
144
			array(
145
				'text',
146
				'paid_currency_symbol',
147
				'subtext' => $txt['paid_currency_symbol_desc'],
148
				'size' => 8,
149
				'force_div_id' => 'custom_currency_symbol_div'
150
			),
151
			array(
152
				'check',
153
				'paidsubs_test',
154
				'subtext' => $txt['paidsubs_test_desc'],
155
				'onclick' => 'return document.getElementById(\'paidsubs_test\').checked ? confirm(\'' . $txt['paidsubs_test_confirm'] . '\') : true;'
156
			),
157
		);
158
159
		// Now load all the other gateway settings.
160
		$gateways = loadPaymentGateways();
161
		foreach ($gateways as $gateway)
162
		{
163
			$gatewayClass = new $gateway['display_class']();
164
			$setting_data = $gatewayClass->getGatewaySettings();
165
			if (!empty($setting_data))
166
			{
167
				$config_vars[] = array('title', $gatewayClass->title, 'text_label' => (isset($txt['paidsubs_gateway_title_' . $gatewayClass->title]) ? $txt['paidsubs_gateway_title_' . $gatewayClass->title] : $gatewayClass->title));
168
				$config_vars = array_merge($config_vars, $setting_data);
169
			}
170
		}
171
172
		$context['settings_message'] = $txt['paid_note'];
173
		$context[$context['admin_menu_name']]['current_subsection'] = 'settings';
174
		$context['settings_title'] = $txt['settings'];
175
176
		// We want javascript for our currency options.
177
		addInlineJavaScript('
178
		function toggleOther()
179
		{
180
			var otherOn = document.getElementById("paid_currency").value == \'other\';
181
			var currencydd = document.getElementById("custom_currency_code_div_dd");
182
183
			if (otherOn)
184
			{
185
				document.getElementById("custom_currency_code_div").style.display = "";
186
				document.getElementById("custom_currency_symbol_div").style.display = "";
187
188
				if (currencydd)
189
				{
190
					document.getElementById("custom_currency_code_div_dd").style.display = "";
191
					document.getElementById("custom_currency_symbol_div_dd").style.display = "";
192
				}
193
			}
194
			else
195
			{
196
				document.getElementById("custom_currency_code_div").style.display = "none";
197
				document.getElementById("custom_currency_symbol_div").style.display = "none";
198
199
				if (currencydd)
200
				{
201
					document.getElementById("custom_currency_symbol_div_dd").style.display = "none";
202
					document.getElementById("custom_currency_code_div_dd").style.display = "none";
203
				}
204
			}
205
		}
206
		toggleOther();', true);
207
	}
208
	else
209
	{
210
		$config_vars = array(
211
			array('check', 'paid_enabled'),
212
		);
213
		$context['settings_title'] = $txt['paid_subscriptions'];
214
	}
215
216
	// Just searching?
217
	if ($return_config)
218
		return $config_vars;
219
220
	// Get the settings template fired up.
221
	require_once($sourcedir . '/ManageServer.php');
222
223
	// Some important context stuff
224
	$context['page_title'] = $txt['settings'];
225
	$context['sub_template'] = 'show_settings';
226
227
	// Get the final touches in place.
228
	$context['post_url'] = $scripturl . '?action=admin;area=paidsubscribe;save;sa=settings';
229
230
	// Saving the settings?
231
	if (isset($_GET['save']))
232
	{
233
		checkSession();
234
235
		$old = !empty($modSettings['paid_enabled']);
236
		$new = !empty($_POST['paid_enabled']);
237
		if ($old != $new)
238
		{
239
			// So we're changing this fundamental status. Great.
240
			$smcFunc['db_query']('', '
241
				UPDATE {db_prefix}scheduled_tasks
242
				SET disabled = {int:disabled}
243
				WHERE task = {string:task}',
244
				array(
245
					'disabled' => $new ? 0 : 1,
246
					'task' => 'paid_subscriptions',
247
				)
248
			);
249
250
			// This may well affect the next trigger, whether we're enabling or not.
251
			require_once($sourcedir . '/ScheduledTasks.php');
252
			CalculateNextTrigger('paid_subscriptions');
253
		}
254
255
		// Check the email addresses were actually email addresses.
256
		if (!empty($_POST['paid_email_to']))
257
		{
258
			$email_addresses = array();
259
			foreach (explode(',', $_POST['paid_email_to']) as $email)
260
			{
261
				$email = trim($email);
262
				if (!empty($email) && filter_var($email, FILTER_VALIDATE_EMAIL))
263
					$email_addresses[] = $email;
264
				$_POST['paid_email_to'] = implode(',', $email_addresses);
265
			}
266
		}
267
268
		// Can only handle this stuff if it's already enabled...
269
		if (!empty($modSettings['paid_enabled']))
270
		{
271
			// Sort out the currency stuff.
272
			if ($_POST['paid_currency'] != 'other')
273
			{
274
				$_POST['paid_currency_code'] = $_POST['paid_currency'];
275
				$_POST['paid_currency_symbol'] = $txt[$_POST['paid_currency'] . '_symbol'];
276
			}
277
			unset($config_vars['dummy_currency']);
278
		}
279
280
		saveDBSettings($config_vars);
281
		$_SESSION['adm-save'] = true;
282
283
		redirectexit('action=admin;area=paidsubscribe;sa=settings');
284
	}
285
286
	// Prepare the settings...
287
	prepareDBSettingContext($config_vars);
288
}
289
290
/**
291
 * View a list of all the current subscriptions
292
 * Requires the admin_forum permission.
293
 * Accessed from ?action=admin;area=paidsubscribe;sa=view.
294
 */
295
function ViewSubscriptions()
296
{
297
	global $context, $txt, $modSettings, $sourcedir, $scripturl;
298
299
	// Not made the settings yet?
300
	if (empty($modSettings['paid_currency_symbol']))
301
		fatal_lang_error('paid_not_set_currency', false, $scripturl . '?action=admin;area=paidsubscribe;sa=settings');
0 ignored issues
show
$scripturl . '?action=ad...dsubscribe;sa=settings' of type string is incompatible with the type array expected by parameter $sprintf of fatal_lang_error(). ( Ignorable by Annotation )

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

301
		fatal_lang_error('paid_not_set_currency', false, /** @scrutinizer ignore-type */ $scripturl . '?action=admin;area=paidsubscribe;sa=settings');
Loading history...
302
303
	// Some basic stuff.
304
	$context['page_title'] = $txt['paid_subs_view'];
305
	loadSubscriptions();
306
307
	$listOptions = array(
308
		'id' => 'subscription_list',
309
		'title' => $txt['subscriptions'],
310
		'items_per_page' => $modSettings['defaultMaxListItems'],
311
		'base_href' => $scripturl . '?action=admin;area=paidsubscribe;sa=view',
312
		'get_items' => array(
313
			'function' => function($start, $items_per_page) use ($context)
314
			{
315
				$subscriptions = array();
316
				$counter = 0;
317
				$start++;
318
319
				foreach ($context['subscriptions'] as $data)
320
				{
321
					if (++$counter < $start)
322
						continue;
323
					elseif ($counter == $start + $items_per_page)
324
						break;
325
326
					$subscriptions[] = $data;
327
				}
328
				return $subscriptions;
329
			},
330
		),
331
		'get_count' => array(
332
			'function' => function() use ($context)
333
			{
334
				return count($context['subscriptions']);
335
			},
336
		),
337
		'no_items_label' => $txt['paid_none_yet'],
338
		'columns' => array(
339
			'name' => array(
340
				'header' => array(
341
					'value' => $txt['paid_name'],
342
					'style' => 'width: 35%;',
343
				),
344
				'data' => array(
345
					'function' => function($rowData) use ($scripturl)
346
					{
347
						return sprintf('<a href="%1$s?action=admin;area=paidsubscribe;sa=viewsub;sid=%2$s">%3$s</a>', $scripturl, $rowData['id'], $rowData['name']);
348
					},
349
				),
350
			),
351
			'cost' => array(
352
				'header' => array(
353
					'value' => $txt['paid_cost'],
354
				),
355
				'data' => array(
356
					'function' => function($rowData) use ($txt)
357
					{
358
						return $rowData['flexible'] ? '<em>' . $txt['flexible'] . '</em>' : $rowData['cost'] . ' / ' . $rowData['length'];
359
					},
360
				),
361
			),
362
			'pending' => array(
363
				'header' => array(
364
					'value' => $txt['paid_pending'],
365
					'style' => 'width: 18%;',
366
					'class' => 'centercol',
367
				),
368
				'data' => array(
369
					'db_htmlsafe' => 'pending',
370
					'class' => 'centercol',
371
				),
372
			),
373
			'finished' => array(
374
				'header' => array(
375
					'value' => $txt['paid_finished'],
376
					'class' => 'centercol',
377
				),
378
				'data' => array(
379
					'db_htmlsafe' => 'finished',
380
					'class' => 'centercol',
381
				),
382
			),
383
			'total' => array(
384
				'header' => array(
385
					'value' => $txt['paid_active'],
386
					'class' => 'centercol',
387
				),
388
				'data' => array(
389
					'db_htmlsafe' => 'total',
390
					'class' => 'centercol',
391
				),
392
			),
393
			'is_active' => array(
394
				'header' => array(
395
					'value' => $txt['paid_is_active'],
396
					'class' => 'centercol',
397
				),
398
				'data' => array(
399
					'function' => function($rowData) use ($txt)
400
					{
401
						return '<span style="color: ' . ($rowData['active'] ? 'green' : 'red') . '">' . ($rowData['active'] ? $txt['yes'] : $txt['no']) . '</span>';
402
					},
403
					'class' => 'centercol',
404
				),
405
			),
406
			'modify' => array(
407
				'data' => array(
408
					'function' => function($rowData) use ($txt, $scripturl)
409
					{
410
						return '<a href="' . $scripturl . '?action=admin;area=paidsubscribe;sa=modify;sid=' . $rowData['id'] . '">' . $txt['modify'] . '</a>';
411
					},
412
					'class' => 'centercol',
413
				),
414
			),
415
			'delete' => array(
416
				'data' => array(
417
					'function' => function($rowData) use ($scripturl, $txt)
418
					{
419
						return '<a href="' . $scripturl . '?action=admin;area=paidsubscribe;sa=modify;delete;sid=' . $rowData['id'] . '">' . $txt['delete'] . '</a>';
420
					},
421
					'class' => 'centercol',
422
				),
423
			),
424
		),
425
		'form' => array(
426
			'href' => $scripturl . '?action=admin;area=paidsubscribe;sa=modify',
427
		),
428
		'additional_rows' => array(
429
			array(
430
				'position' => 'above_table_headers',
431
				'value' => '<input type="submit" name="add" value="' . $txt['paid_add_subscription'] . '" class="button">',
432
			),
433
			array(
434
				'position' => 'below_table_data',
435
				'value' => '<input type="submit" name="add" value="' . $txt['paid_add_subscription'] . '" class="button">',
436
			),
437
		),
438
	);
439
440
	require_once($sourcedir . '/Subs-List.php');
441
	createList($listOptions);
442
443
	$context['sub_template'] = 'show_list';
444
	$context['default_list'] = 'subscription_list';
445
}
446
447
/**
448
 * Adding, editing and deleting subscriptions.
449
 * Accessed from ?action=admin;area=paidsubscribe;sa=modify.
450
 */
451
function ModifySubscription()
452
{
453
	global $context, $txt, $smcFunc;
454
455
	$context['sub_id'] = isset($_REQUEST['sid']) ? (int) $_REQUEST['sid'] : 0;
456
	$context['action_type'] = $context['sub_id'] ? (isset($_REQUEST['delete']) ? 'delete' : 'edit') : 'add';
457
458
	// Setup the template.
459
	$context['sub_template'] = $context['action_type'] == 'delete' ? 'delete_subscription' : 'modify_subscription';
460
	$context['page_title'] = $txt['paid_' . $context['action_type'] . '_subscription'];
461
462
	// Delete it?
463
	if (isset($_POST['delete_confirm']) && isset($_REQUEST['delete']))
464
	{
465
		checkSession();
466
		validateToken('admin-pmsd');
467
468
		// Before we delete the subscription we need to find out if anyone currently has said subscription.
469
		$request = $smcFunc['db_query']('', '
470
			SELECT ls.id_member, ls.old_id_group, mem.id_group, mem.additional_groups
471
			FROM {db_prefix}log_subscribed AS ls
472
				INNER JOIN {db_prefix}members AS mem ON (ls.id_member = mem.id_member)
473
			WHERE id_subscribe = {int:current_subscription}
474
				AND status = {int:is_active}',
475
			array(
476
				'current_subscription' => $context['sub_id'],
477
				'is_active' => 1,
478
			)
479
		);
480
		$members = array();
481
		while ($row = $smcFunc['db_fetch_assoc']($request))
482
		{
483
			$id_member = array_shift($row);
484
			$members[$id_member] = $row;
485
		}
486
		$smcFunc['db_free_result']($request);
487
488
		// If there are any members with this subscription, we have to do some more work before we go any further.
489
		if (!empty($members))
490
		{
491
			$request = $smcFunc['db_query']('', '
492
				SELECT id_group, add_groups
493
				FROM {db_prefix}subscriptions
494
				WHERE id_subscribe = {int:current_subscription}',
495
				array(
496
					'current_subscription' => $context['sub_id'],
497
				)
498
			);
499
			$id_group = 0;
500
			$add_groups = '';
501
			if ($smcFunc['db_num_rows']($request))
502
				list ($id_group, $add_groups) = $smcFunc['db_fetch_row']($request);
503
			$smcFunc['db_free_result']($request);
504
505
			$changes = array();
506
507
			// Is their group changing? This subscription may not have changed primary group.
508
			if (!empty($id_group))
509
			{
510
				foreach ($members as $id_member => $member_data)
511
				{
512
					// If their current primary group isn't what they had before the subscription, and their current group was
513
					// granted by the sub, remove it.
514
					if ($member_data['old_id_group'] != $member_data['id_group'] && $member_data['id_group'] == $id_group)
515
						$changes[$id_member]['id_group'] = $member_data['old_id_group'];
516
				}
517
			}
518
519
			// Did this subscription add secondary groups?
520
			if (!empty($add_groups))
521
			{
522
				$add_groups = explode(',', $add_groups);
523
				foreach ($members as $id_member => $member_data)
524
				{
525
					// First let's get their groups sorted.
526
					$current_groups = explode(',', $member_data['additional_groups']);
527
					$new_groups = implode(',', array_diff($current_groups, $add_groups));
528
					if ($new_groups != $member_data['additional_groups'])
529
						$changes[$id_member]['additional_groups'] = $new_groups;
530
				}
531
			}
532
533
			// We're going through changes...
534
			if (!empty($changes))
535
				foreach ($changes as $id_member => $new_values)
536
					updateMemberData($id_member, $new_values);
537
		}
538
539
		// Delete the subscription
540
		$smcFunc['db_query']('', '
541
			DELETE FROM {db_prefix}subscriptions
542
			WHERE id_subscribe = {int:current_subscription}',
543
			array(
544
				'current_subscription' => $context['sub_id'],
545
			)
546
		);
547
548
		// And delete any subscriptions to it to clear the phantom data too.
549
		$smcFunc['db_query']('', '
550
			DELETE FROM {db_prefix}log_subscribed
551
			WHERE id_subscribe = {int:current_subscription}',
552
			array(
553
				'current_subscription' => $context['sub_id'],
554
			)
555
		);
556
557
		call_integration_hook('integrate_delete_subscription', array($context['sub_id']));
558
559
		redirectexit('action=admin;area=paidsubscribe;view');
560
	}
561
562
	// Saving?
563
	if (isset($_POST['save']))
564
	{
565
		checkSession();
566
567
		// Some cleaning...
568
		$isActive = isset($_POST['active']) ? 1 : 0;
569
		$isRepeatable = isset($_POST['repeatable']) ? 1 : 0;
570
		$allowpartial = isset($_POST['allow_partial']) ? 1 : 0;
571
		$reminder = isset($_POST['reminder']) ? (int) $_POST['reminder'] : 0;
572
		$emailComplete = strlen($_POST['emailcomplete']) > 10 ? trim($_POST['emailcomplete']) : '';
573
		$_POST['prim_group'] = !empty($_POST['prim_group']) ? (int) $_POST['prim_group'] : 0;
574
575
		// Is this a fixed one?
576
		if ($_POST['duration_type'] == 'fixed')
577
		{
578
			$_POST['span_value'] = !empty($_POST['span_value']) && is_numeric($_POST['span_value']) ? ceil($_POST['span_value']) : 0;
579
580
			// There are sanity check limits on these things.
581
			$limits = array(
582
				'D' => 90,
583
				'W' => 52,
584
				'M' => 24,
585
				'Y' => 5,
586
			);
587
			if (empty($_POST['span_unit']) || empty($limits[$_POST['span_unit']]) || $_POST['span_value'] < 1)
588
				fatal_lang_error('paid_invalid_duration', false);
589
590
			if ($_POST['span_value'] > $limits[$_POST['span_unit']])
591
				fatal_lang_error('paid_invalid_duration_' . $_POST['span_unit'], false);
592
593
			// Clean the span.
594
			$span = $_POST['span_value'] . $_POST['span_unit'];
595
596
			// Sort out the cost.
597
			$cost = array('fixed' => sprintf('%01.2f', strtr($_POST['cost'], ',', '.')));
598
599
			// There needs to be something.
600
			if ($cost['fixed'] == '0.00')
601
				fatal_lang_error('paid_no_cost_value');
602
		}
603
		// Flexible is harder but more fun ;)
604
		else
605
		{
606
			$span = 'F';
607
608
			$cost = array(
609
				'day' => sprintf('%01.2f', strtr($_POST['cost_day'], ',', '.')),
610
				'week' => sprintf('%01.2f', strtr($_POST['cost_week'], ',', '.')),
611
				'month' => sprintf('%01.2f', strtr($_POST['cost_month'], ',', '.')),
612
				'year' => sprintf('%01.2f', strtr($_POST['cost_year'], ',', '.')),
613
			);
614
615
			if ($cost['day'] == '0.00' && $cost['week'] == '0.00' && $cost['month'] == '0.00' && $cost['year'] == '0.00')
616
				fatal_lang_error('paid_all_freq_blank');
617
		}
618
		$cost = $smcFunc['json_encode']($cost);
619
620
		// Having now validated everything that might throw an error, let's also now deal with the token.
621
		validateToken('admin-pms');
622
623
		// Yep, time to do additional groups.
624
		$addgroups = array();
625
		if (!empty($_POST['addgroup']))
626
			foreach ($_POST['addgroup'] as $id => $dummy)
627
				$addgroups[] = (int) $id;
628
		$addgroups = implode(',', $addgroups);
629
630
		// Is it new?!
631
		if ($context['action_type'] == 'add')
632
		{
633
			$id_subscribe = $smcFunc['db_insert']('',
634
				'{db_prefix}subscriptions',
635
				array(
636
					'name' => 'string-60', 'description' => 'string-255', 'active' => 'int', 'length' => 'string-4', 'cost' => 'string',
637
					'id_group' => 'int', 'add_groups' => 'string-40', 'repeatable' => 'int', 'allow_partial' => 'int', 'email_complete' => 'string',
638
					'reminder' => 'int',
639
				),
640
				array(
641
					$_POST['name'], $_POST['desc'], $isActive, $span, $cost,
642
					$_POST['prim_group'], $addgroups, $isRepeatable, $allowpartial, $emailComplete,
643
					$reminder,
644
				),
645
				array('id_subscribe'),
646
				1
647
			);
648
		}
649
		// Otherwise must be editing.
650
		else
651
		{
652
			// Don't do groups if there are active members
653
			$request = $smcFunc['db_query']('', '
654
				SELECT COUNT(*)
655
				FROM {db_prefix}log_subscribed
656
				WHERE id_subscribe = {int:current_subscription}
657
					AND status = {int:is_active}',
658
				array(
659
					'current_subscription' => $context['sub_id'],
660
					'is_active' => 1,
661
				)
662
			);
663
			list ($disableGroups) = $smcFunc['db_fetch_row']($request);
664
			$smcFunc['db_free_result']($request);
665
666
			$smcFunc['db_query']('substring', '
667
				UPDATE {db_prefix}subscriptions
668
					SET name = SUBSTRING({string:name}, 1, 60), description = SUBSTRING({string:description}, 1, 255), active = {int:is_active},
669
					length = SUBSTRING({string:length}, 1, 4), cost = {string:cost}' . ($disableGroups ? '' : ', id_group = {int:id_group},
670
					add_groups = {string:additional_groups}') . ', repeatable = {int:repeatable}, allow_partial = {int:allow_partial},
671
					email_complete = {string:email_complete}, reminder = {int:reminder}
672
				WHERE id_subscribe = {int:current_subscription}',
673
				array(
674
					'is_active' => $isActive,
675
					'id_group' => $_POST['prim_group'],
676
					'repeatable' => $isRepeatable,
677
					'allow_partial' => $allowpartial,
678
					'reminder' => $reminder,
679
					'current_subscription' => $context['sub_id'],
680
					'name' => $_POST['name'],
681
					'description' => $_POST['desc'],
682
					'length' => $span,
683
					'cost' => $cost,
684
					'additional_groups' => !empty($addgroups) ? $addgroups : '',
685
					'email_complete' => $emailComplete,
686
				)
687
			);
688
		}
689
		call_integration_hook('integrate_save_subscription', array(($context['action_type'] == 'add' ? $id_subscribe : $context['sub_id']), $_POST['name'], $_POST['desc'], $isActive, $span, $cost, $_POST['prim_group'], $addgroups, $isRepeatable, $allowpartial, $emailComplete, $reminder));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $id_subscribe does not seem to be defined for all execution paths leading up to this point.
Loading history...
690
691
		redirectexit('action=admin;area=paidsubscribe;view');
692
	}
693
694
	// Defaults.
695
	if ($context['action_type'] == 'add')
696
	{
697
		$context['sub'] = array(
698
			'name' => '',
699
			'desc' => '',
700
			'cost' => array(
701
				'fixed' => 0,
702
			),
703
			'span' => array(
704
				'value' => '',
705
				'unit' => 'D',
706
			),
707
			'prim_group' => 0,
708
			'add_groups' => array(),
709
			'active' => 1,
710
			'repeatable' => 1,
711
			'allow_partial' => 0,
712
			'duration' => 'fixed',
713
			'email_complete' => '',
714
			'reminder' => 0,
715
		);
716
	}
717
	// Otherwise load up all the details.
718
	else
719
	{
720
		$request = $smcFunc['db_query']('', '
721
			SELECT name, description, cost, length, id_group, add_groups, active, repeatable, allow_partial, email_complete, reminder
722
			FROM {db_prefix}subscriptions
723
			WHERE id_subscribe = {int:current_subscription}
724
			LIMIT 1',
725
			array(
726
				'current_subscription' => $context['sub_id'],
727
			)
728
		);
729
		while ($row = $smcFunc['db_fetch_assoc']($request))
730
		{
731
			// Sort the date.
732
			preg_match('~(\d*)(\w)~', $row['length'], $match);
733
			if (isset($match[2]))
734
			{
735
				$_POST['span_value'] = $match[1];
736
				$span_unit = $match[2];
737
			}
738
			else
739
			{
740
				$_POST['span_value'] = 0;
741
				$span_unit = 'D';
742
			}
743
744
			// Is this a flexible one?
745
			if ($row['length'] == 'F')
746
				$isFlexible = true;
747
			else
748
				$isFlexible = false;
749
750
			$context['sub'] = array(
751
				'name' => $row['name'],
752
				'desc' => $row['description'],
753
				'cost' => $smcFunc['json_decode']($row['cost'], true),
754
				'span' => array(
755
					'value' => $_POST['span_value'],
756
					'unit' => $span_unit,
757
				),
758
				'prim_group' => $row['id_group'],
759
				'add_groups' => explode(',', $row['add_groups']),
760
				'active' => $row['active'],
761
				'repeatable' => $row['repeatable'],
762
				'allow_partial' => $row['allow_partial'],
763
				'duration' => $isFlexible ? 'flexible' : 'fixed',
764
				'email_complete' => $smcFunc['htmlspecialchars']($row['email_complete']),
765
				'reminder' => $row['reminder'],
766
			);
767
		}
768
		$smcFunc['db_free_result']($request);
769
770
		// Does this have members who are active?
771
		$request = $smcFunc['db_query']('', '
772
			SELECT COUNT(*)
773
			FROM {db_prefix}log_subscribed
774
			WHERE id_subscribe = {int:current_subscription}
775
				AND status = {int:is_active}',
776
			array(
777
				'current_subscription' => $context['sub_id'],
778
				'is_active' => 1,
779
			)
780
		);
781
		list ($context['disable_groups']) = $smcFunc['db_fetch_row']($request);
782
		$smcFunc['db_free_result']($request);
783
	}
784
785
	// Load up all the groups.
786
	$request = $smcFunc['db_query']('', '
787
		SELECT id_group, group_name
788
		FROM {db_prefix}membergroups
789
		WHERE id_group != {int:moderator_group}
790
			AND min_posts = {int:min_posts}',
791
		array(
792
			'moderator_group' => 3,
793
			'min_posts' => -1,
794
		)
795
	);
796
	$context['groups'] = array();
797
	while ($row = $smcFunc['db_fetch_assoc']($request))
798
		$context['groups'][$row['id_group']] = $row['group_name'];
799
	$smcFunc['db_free_result']($request);
800
801
	// This always happens.
802
	createToken($context['action_type'] == 'delete' ? 'admin-pmsd' : 'admin-pms');
803
}
804
805
/**
806
 * View all the users subscribed to a particular subscription.
807
 * Requires the admin_forum permission.
808
 * Accessed from ?action=admin;area=paidsubscribe;sa=viewsub.
809
 *
810
 * Subscription ID is required, in the form of $_GET['sid'].
811
 */
812
function ViewSubscribedUsers()
813
{
814
	global $context, $txt, $scripturl, $smcFunc, $sourcedir, $modSettings;
815
816
	// Setup the template.
817
	$context['page_title'] = $txt['viewing_users_subscribed'];
818
819
	// ID of the subscription.
820
	$context['sub_id'] = (int) $_REQUEST['sid'];
821
822
	// Load the subscription information.
823
	$request = $smcFunc['db_query']('', '
824
		SELECT id_subscribe, name, description, cost, length, id_group, add_groups, active
825
		FROM {db_prefix}subscriptions
826
		WHERE id_subscribe = {int:current_subscription}',
827
		array(
828
			'current_subscription' => $context['sub_id'],
829
		)
830
	);
831
	// Something wrong?
832
	if ($smcFunc['db_num_rows']($request) == 0)
833
		fatal_lang_error('no_access', false);
834
	// Do the subscription context.
835
	$row = $smcFunc['db_fetch_assoc']($request);
836
	$context['subscription'] = array(
837
		'id' => $row['id_subscribe'],
838
		'name' => $row['name'],
839
		'desc' => $row['description'],
840
		'active' => $row['active'],
841
	);
842
	$smcFunc['db_free_result']($request);
843
844
	// Are we searching for people?
845
	$search_string = isset($_POST['ssearch']) && !empty($_POST['sub_search']) ? ' AND COALESCE(mem.real_name, {string:guest}) LIKE {string:search}' : '';
846
	$search_vars = empty($_POST['sub_search']) ? array() : array('search' => '%' . $_POST['sub_search'] . '%', 'guest' => $txt['guest']);
847
848
	$listOptions = array(
849
		'id' => 'subscribed_users_list',
850
		'title' => sprintf($txt['view_users_subscribed'], $row['name']),
851
		'items_per_page' => $modSettings['defaultMaxListItems'],
852
		'base_href' => $scripturl . '?action=admin;area=paidsubscribe;sa=viewsub;sid=' . $context['sub_id'],
853
		'default_sort_col' => 'name',
854
		'get_items' => array(
855
			'function' => 'list_getSubscribedUsers',
856
			'params' => array(
857
				$context['sub_id'],
858
				$search_string,
859
				$search_vars,
860
			),
861
		),
862
		'get_count' => array(
863
			'function' => 'list_getSubscribedUserCount',
864
			'params' => array(
865
				$context['sub_id'],
866
				$search_string,
867
				$search_vars,
868
			),
869
		),
870
		'no_items_label' => $txt['no_subscribers'],
871
		'columns' => array(
872
			'name' => array(
873
				'header' => array(
874
					'value' => $txt['who_member'],
875
					'style' => 'width: 20%;',
876
				),
877
				'data' => array(
878
					'function' => function($rowData) use ($scripturl, $txt)
879
					{
880
						return $rowData['id_member'] == 0 ? $txt['guest'] : '<a href="' . $scripturl . '?action=profile;u=' . $rowData['id_member'] . '">' . $rowData['name'] . '</a>';
881
					},
882
				),
883
				'sort' => array(
884
					'default' => 'name',
885
					'reverse' => 'name DESC',
886
				),
887
			),
888
			'status' => array(
889
				'header' => array(
890
					'value' => $txt['paid_status'],
891
					'style' => 'width: 10%;',
892
				),
893
				'data' => array(
894
					'db_htmlsafe' => 'status_text',
895
				),
896
				'sort' => array(
897
					'default' => 'status',
898
					'reverse' => 'status DESC',
899
				),
900
			),
901
			'payments_pending' => array(
902
				'header' => array(
903
					'value' => $txt['paid_payments_pending'],
904
					'style' => 'width: 15%;',
905
				),
906
				'data' => array(
907
					'db_htmlsafe' => 'pending',
908
				),
909
				'sort' => array(
910
					'default' => 'payments_pending',
911
					'reverse' => 'payments_pending DESC',
912
				),
913
			),
914
			'start_time' => array(
915
				'header' => array(
916
					'value' => $txt['start_date'],
917
					'style' => 'width: 20%;',
918
				),
919
				'data' => array(
920
					'db_htmlsafe' => 'start_date',
921
					'class' => 'smalltext',
922
				),
923
				'sort' => array(
924
					'default' => 'start_time',
925
					'reverse' => 'start_time DESC',
926
				),
927
			),
928
			'end_time' => array(
929
				'header' => array(
930
					'value' => $txt['end_date'],
931
					'style' => 'width: 20%;',
932
				),
933
				'data' => array(
934
					'db_htmlsafe' => 'end_date',
935
					'class' => 'smalltext',
936
				),
937
				'sort' => array(
938
					'default' => 'end_time',
939
					'reverse' => 'end_time DESC',
940
				),
941
			),
942
			'modify' => array(
943
				'header' => array(
944
					'style' => 'width: 10%;',
945
					'class' => 'centercol',
946
				),
947
				'data' => array(
948
					'function' => function($rowData) use ($scripturl, $txt)
949
					{
950
						return '<a href="' . $scripturl . '?action=admin;area=paidsubscribe;sa=modifyuser;lid=' . $rowData['id'] . '">' . $txt['modify'] . '</a>';
951
					},
952
					'class' => 'centercol',
953
				),
954
			),
955
			'delete' => array(
956
				'header' => array(
957
					'style' => 'width: 4%;',
958
					'class' => 'centercol',
959
				),
960
				'data' => array(
961
					'function' => function($rowData)
962
					{
963
						return '<input type="checkbox" name="delsub[' . $rowData['id'] . ']">';
964
					},
965
					'class' => 'centercol',
966
				),
967
			),
968
		),
969
		'form' => array(
970
			'href' => $scripturl . '?action=admin;area=paidsubscribe;sa=modifyuser;sid=' . $context['sub_id'],
971
		),
972
		'additional_rows' => array(
973
			array(
974
				'position' => 'below_table_data',
975
				'value' => '
976
					<input type="submit" name="add" value="' . $txt['add_subscriber'] . '" class="button">
977
					<input type="submit" name="finished" value="' . $txt['complete_selected'] . '" data-confirm="' . $txt['complete_are_sure'] . '" class="button you_sure">
978
					<input type="submit" name="delete" value="' . $txt['delete_selected'] . '" data-confirm="' . $txt['delete_are_sure'] . '" class="button you_sure">
979
				',
980
			),
981
			array(
982
				'position' => 'top_of_list',
983
				'value' => '
984
					<div class="flow_auto">
985
						<input type="submit" name="ssearch" value="' . $txt['search_sub'] . '" class="button" style="margin-top: 3px;">
986
						<input type="text" name="sub_search" value="" class="floatright">
987
					</div>
988
				',
989
			),
990
		),
991
	);
992
993
	require_once($sourcedir . '/Subs-List.php');
994
	createList($listOptions);
995
996
	$context['sub_template'] = 'show_list';
997
	$context['default_list'] = 'subscribed_users_list';
998
}
999
1000
/**
1001
 * Returns how many people are subscribed to a paid subscription.
1002
 *
1003
 * @todo refactor away
1004
 *
1005
 * @param int $id_sub The ID of the subscription
1006
 * @param string $search_string A search string
1007
 * @param array $search_vars An array of variables for the search string
1008
 * @return int The number of subscribed users matching the given parameters
1009
 */
1010
function list_getSubscribedUserCount($id_sub, $search_string, $search_vars = array())
1011
{
1012
	global $smcFunc;
1013
1014
	// Get the total amount of users.
1015
	$request = $smcFunc['db_query']('', '
1016
		SELECT COUNT(*) AS total_subs
1017
		FROM {db_prefix}log_subscribed AS ls
1018
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = ls.id_member)
1019
		WHERE ls.id_subscribe = {int:current_subscription} ' . $search_string . '
1020
			AND (ls.end_time != {int:no_end_time} OR ls.payments_pending != {int:no_pending_payments})',
1021
		array_merge($search_vars, array(
1022
			'current_subscription' => $id_sub,
1023
			'no_end_time' => 0,
1024
			'no_pending_payments' => 0,
1025
		))
1026
	);
1027
	list ($memberCount) = $smcFunc['db_fetch_row']($request);
1028
	$smcFunc['db_free_result']($request);
1029
1030
	return $memberCount;
1031
}
1032
1033
/**
1034
 * Return the subscribed users list, for the given parameters.
1035
 *
1036
 * @todo refactor outta here
1037
 *
1038
 * @param int $start The item to start with (for pagination purposes)
1039
 * @param int $items_per_page How many items to show on each page
1040
 * @param string $sort A string indicating how to sort the results
1041
 * @param int $id_sub The ID of the subscription
1042
 * @param string $search_string A search string
1043
 * @param array $search_vars The variables for the search string
1044
 * @return array An array of information about the subscribed users matching the given parameters
1045
 */
1046
function list_getSubscribedUsers($start, $items_per_page, $sort, $id_sub, $search_string, $search_vars = array())
1047
{
1048
	global $smcFunc, $txt;
1049
1050
	$request = $smcFunc['db_query']('', '
1051
		SELECT ls.id_sublog, COALESCE(mem.id_member, 0) AS id_member, COALESCE(mem.real_name, {string:guest}) AS name, ls.start_time, ls.end_time,
1052
			ls.status, ls.payments_pending
1053
		FROM {db_prefix}log_subscribed AS ls
1054
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = ls.id_member)
1055
		WHERE ls.id_subscribe = {int:current_subscription} ' . $search_string . '
1056
			AND (ls.end_time != {int:no_end_time} OR ls.payments_pending != {int:no_payments_pending})
1057
		ORDER BY {raw:sort}
1058
		LIMIT {int:start}, {int:max}',
1059
		array_merge($search_vars, array(
1060
			'current_subscription' => $id_sub,
1061
			'no_end_time' => 0,
1062
			'no_payments_pending' => 0,
1063
			'guest' => $txt['guest'],
1064
			'sort' => $sort,
1065
			'start' => $start,
1066
			'max' => $items_per_page,
1067
		))
1068
	);
1069
	$subscribers = array();
1070
	while ($row = $smcFunc['db_fetch_assoc']($request))
1071
		$subscribers[] = array(
1072
			'id' => $row['id_sublog'],
1073
			'id_member' => $row['id_member'],
1074
			'name' => $row['name'],
1075
			'start_date' => timeformat($row['start_time'], false),
1076
			'end_date' => $row['end_time'] == 0 ? 'N/A' : timeformat($row['end_time'], false),
1077
			'pending' => $row['payments_pending'],
1078
			'status' => $row['status'],
1079
			'status_text' => $row['status'] == 0 ? ($row['payments_pending'] == 0 ? $txt['paid_finished'] : $txt['paid_pending']) : $txt['paid_active'],
1080
		);
1081
	$smcFunc['db_free_result']($request);
1082
1083
	return $subscribers;
1084
}
1085
1086
/**
1087
 * Edit or add a user subscription.
1088
 * Accessed from ?action=admin;area=paidsubscribe;sa=modifyuser.
1089
 */
1090
function ModifyUserSubscription()
1091
{
1092
	global $context, $txt, $modSettings, $smcFunc;
1093
1094
	loadSubscriptions();
1095
1096
	$context['log_id'] = isset($_REQUEST['lid']) ? (int) $_REQUEST['lid'] : 0;
1097
	$context['sub_id'] = isset($_REQUEST['sid']) ? (int) $_REQUEST['sid'] : 0;
1098
	$context['action_type'] = $context['log_id'] ? 'edit' : 'add';
1099
1100
	// Setup the template.
1101
	$context['sub_template'] = 'modify_user_subscription';
1102
	$context['page_title'] = $txt[$context['action_type'] . '_subscriber'];
1103
1104
	// If we haven't been passed the subscription ID get it.
1105
	if ($context['log_id'] && !$context['sub_id'])
1106
	{
1107
		$request = $smcFunc['db_query']('', '
1108
			SELECT id_subscribe
1109
			FROM {db_prefix}log_subscribed
1110
			WHERE id_sublog = {int:current_log_item}',
1111
			array(
1112
				'current_log_item' => $context['log_id'],
1113
			)
1114
		);
1115
		if ($smcFunc['db_num_rows']($request) == 0)
1116
			fatal_lang_error('no_access', false);
1117
		list ($context['sub_id']) = $smcFunc['db_fetch_row']($request);
1118
		$smcFunc['db_free_result']($request);
1119
	}
1120
1121
	if (!isset($context['subscriptions'][$context['sub_id']]))
1122
		fatal_lang_error('no_access', false);
1123
	$context['current_subscription'] = $context['subscriptions'][$context['sub_id']];
1124
1125
	// Searching?
1126
	if (isset($_POST['ssearch']))
1127
	{
1128
		return ViewSubscribedUsers();
1129
	}
1130
	// Saving?
1131
	elseif (isset($_REQUEST['save_sub']))
1132
	{
1133
		checkSession();
1134
1135
		// Work out the dates...
1136
		$starttime = mktime($_POST['hour'], $_POST['minute'], 0, $_POST['month'], $_POST['day'], $_POST['year']);
1137
		$endtime = mktime($_POST['hourend'], $_POST['minuteend'], 0, $_POST['monthend'], $_POST['dayend'], $_POST['yearend']);
1138
1139
		// Status.
1140
		$status = $_POST['status'];
1141
1142
		// New one?
1143
		if (empty($context['log_id']))
1144
		{
1145
			// Find the user...
1146
			$request = $smcFunc['db_query']('', '
1147
				SELECT id_member, id_group
1148
				FROM {db_prefix}members
1149
				WHERE real_name = {string:name}
1150
				LIMIT 1',
1151
				array(
1152
					'name' => $_POST['name'],
1153
				)
1154
			);
1155
			if ($smcFunc['db_num_rows']($request) == 0)
1156
				fatal_lang_error('error_member_not_found');
1157
1158
			list ($id_member, $id_group) = $smcFunc['db_fetch_row']($request);
1159
			$smcFunc['db_free_result']($request);
1160
1161
			// Ensure the member doesn't already have a subscription!
1162
			$request = $smcFunc['db_query']('', '
1163
				SELECT id_subscribe
1164
				FROM {db_prefix}log_subscribed
1165
				WHERE id_subscribe = {int:current_subscription}
1166
					AND id_member = {int:current_member}',
1167
				array(
1168
					'current_subscription' => $context['sub_id'],
1169
					'current_member' => $id_member,
1170
				)
1171
			);
1172
			if ($smcFunc['db_num_rows']($request) != 0)
1173
				fatal_lang_error('member_already_subscribed');
1174
			$smcFunc['db_free_result']($request);
1175
1176
			// Actually put the subscription in place.
1177
			if ($status == 1)
1178
				addSubscription($context['sub_id'], $id_member, 0, $starttime, $endtime);
1179
			else
1180
			{
1181
				$smcFunc['db_insert']('',
1182
					'{db_prefix}log_subscribed',
1183
					array(
1184
						'id_subscribe' => 'int', 'id_member' => 'int', 'old_id_group' => 'int', 'start_time' => 'int',
1185
						'end_time' => 'int', 'status' => 'int', 'pending_details' => 'string-65534'
1186
					),
1187
					array(
1188
						$context['sub_id'], $id_member, $id_group, $starttime,
1189
						$endtime, $status, $smcFunc['json_encode'](array())
1190
					),
1191
					array('id_sublog')
1192
				);
1193
1194
			}
1195
		}
1196
		// Updating.
1197
		else
1198
		{
1199
			$request = $smcFunc['db_query']('', '
1200
				SELECT id_member, status
1201
				FROM {db_prefix}log_subscribed
1202
				WHERE id_sublog = {int:current_log_item}',
1203
				array(
1204
					'current_log_item' => $context['log_id'],
1205
				)
1206
			);
1207
			if ($smcFunc['db_num_rows']($request) == 0)
1208
				fatal_lang_error('no_access', false);
1209
1210
			list ($id_member, $old_status) = $smcFunc['db_fetch_row']($request);
1211
			$smcFunc['db_free_result']($request);
1212
1213
			// Pick the right permission stuff depending on what the status is changing from/to.
1214
			if ($old_status == 1 && $status != 1)
1215
				removeSubscription($context['sub_id'], $id_member);
1216
			elseif ($status == 1 && $old_status != 1)
1217
			{
1218
				addSubscription($context['sub_id'], $id_member, 0, $starttime, $endtime);
1219
			}
1220
			else
1221
			{
1222
				$smcFunc['db_query']('', '
1223
					UPDATE {db_prefix}log_subscribed
1224
					SET start_time = {int:start_time}, end_time = {int:end_time}, status = {int:status}
1225
					WHERE id_sublog = {int:current_log_item}',
1226
					array(
1227
						'start_time' => $starttime,
1228
						'end_time' => $endtime,
1229
						'status' => $status,
1230
						'current_log_item' => $context['log_id'],
1231
					)
1232
				);
1233
			}
1234
		}
1235
1236
		// Done - redirect...
1237
		redirectexit('action=admin;area=paidsubscribe;sa=viewsub;sid=' . $context['sub_id']);
1238
	}
1239
	// Deleting?
1240
	elseif (isset($_REQUEST['delete']) || isset($_REQUEST['finished']))
1241
	{
1242
		checkSession();
1243
1244
		// Do the actual deletes!
1245
		if (!empty($_REQUEST['delsub']))
1246
		{
1247
			$toDelete = array();
1248
			foreach ($_REQUEST['delsub'] as $id => $dummy)
1249
				$toDelete[] = (int) $id;
1250
1251
			$request = $smcFunc['db_query']('', '
1252
				SELECT id_subscribe, id_member
1253
				FROM {db_prefix}log_subscribed
1254
				WHERE id_sublog IN ({array_int:subscription_list})',
1255
				array(
1256
					'subscription_list' => $toDelete,
1257
				)
1258
			);
1259
			while ($row = $smcFunc['db_fetch_assoc']($request))
1260
				removeSubscription($row['id_subscribe'], $row['id_member'], isset($_REQUEST['delete']));
1261
			$smcFunc['db_free_result']($request);
1262
		}
1263
		redirectexit('action=admin;area=paidsubscribe;sa=viewsub;sid=' . $context['sub_id']);
1264
	}
1265
1266
	// Default attributes.
1267
	if ($context['action_type'] == 'add')
1268
	{
1269
		$context['sub'] = array(
1270
			'id' => 0,
1271
			'start' => array(
1272
				'year' => (int) strftime('%Y', time()),
1273
				'month' => (int) strftime('%m', time()),
1274
				'day' => (int) strftime('%d', time()),
1275
				'hour' => (int) strftime('%H', time()),
1276
				'min' => (int) strftime('%M', time()) < 10 ? '0' . (int) strftime('%M', time()) : (int) strftime('%M', time()),
1277
				'last_day' => 0,
1278
			),
1279
			'end' => array(
1280
				'year' => (int) strftime('%Y', time()),
1281
				'month' => (int) strftime('%m', time()),
1282
				'day' => (int) strftime('%d', time()),
1283
				'hour' => (int) strftime('%H', time()),
1284
				'min' => (int) strftime('%M', time()) < 10 ? '0' . (int) strftime('%M', time()) : (int) strftime('%M', time()),
1285
				'last_day' => 0,
1286
			),
1287
			'status' => 1,
1288
		);
1289
		$context['sub']['start']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['sub']['start']['month'] == 12 ? 1 : $context['sub']['start']['month'] + 1, 0, $context['sub']['start']['month'] == 12 ? $context['sub']['start']['year'] + 1 : $context['sub']['start']['year']));
1290
		$context['sub']['end']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['sub']['end']['month'] == 12 ? 1 : $context['sub']['end']['month'] + 1, 0, $context['sub']['end']['month'] == 12 ? $context['sub']['end']['year'] + 1 : $context['sub']['end']['year']));
1291
1292
		if (isset($_GET['uid']))
1293
		{
1294
			$request = $smcFunc['db_query']('', '
1295
				SELECT real_name
1296
				FROM {db_prefix}members
1297
				WHERE id_member = {int:current_member}',
1298
				array(
1299
					'current_member' => (int) $_GET['uid'],
1300
				)
1301
			);
1302
			list ($context['sub']['username']) = $smcFunc['db_fetch_row']($request);
1303
			$smcFunc['db_free_result']($request);
1304
		}
1305
		else
1306
			$context['sub']['username'] = '';
1307
	}
1308
	// Otherwise load the existing info.
1309
	else
1310
	{
1311
		$request = $smcFunc['db_query']('', '
1312
			SELECT ls.id_sublog, ls.id_subscribe, ls.id_member, start_time, end_time, status, payments_pending, pending_details,
1313
				COALESCE(mem.real_name, {string:blank_string}) AS username
1314
			FROM {db_prefix}log_subscribed AS ls
1315
				LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = ls.id_member)
1316
			WHERE ls.id_sublog = {int:current_subscription_item}
1317
			LIMIT 1',
1318
			array(
1319
				'current_subscription_item' => $context['log_id'],
1320
				'blank_string' => '',
1321
			)
1322
		);
1323
		if ($smcFunc['db_num_rows']($request) == 0)
1324
			fatal_lang_error('no_access', false);
1325
		$row = $smcFunc['db_fetch_assoc']($request);
1326
		$smcFunc['db_free_result']($request);
1327
1328
		// Any pending payments?
1329
		$context['pending_payments'] = array();
1330
		if (!empty($row['pending_details']))
1331
		{
1332
			$pending_details = $smcFunc['json_decode']($row['pending_details'], true);
1333
			foreach ($pending_details as $id => $pending)
1334
			{
1335
				// Only this type need be displayed.
1336
				if ($pending[3] == 'payback')
1337
				{
1338
					// Work out what the options were.
1339
					$costs = $smcFunc['json_decode']($context['current_subscription']['real_cost'], true);
1340
1341
					if ($context['current_subscription']['real_length'] == 'F')
1342
					{
1343
						foreach ($costs as $duration => $cost)
1344
						{
1345
							if ($cost != 0 && $cost == $pending[1] && $duration == $pending[2])
1346
								$context['pending_payments'][$id] = array(
1347
									'desc' => sprintf($modSettings['paid_currency_symbol'], $cost . '/' . $txt[$duration]),
1348
								);
1349
						}
1350
					}
1351
					elseif ($costs['fixed'] == $pending[1])
1352
					{
1353
						$context['pending_payments'][$id] = array(
1354
							'desc' => sprintf($modSettings['paid_currency_symbol'], $costs['fixed']),
1355
						);
1356
					}
1357
				}
1358
			}
1359
1360
			// Check if we are adding/removing any.
1361
			if (isset($_GET['pending']))
1362
			{
1363
				foreach ($pending_details as $id => $pending)
1364
				{
1365
					// Found the one to action?
1366
					if ($_GET['pending'] == $id && $pending[3] == 'payback' && isset($context['pending_payments'][$id]))
1367
					{
1368
						// Flexible?
1369
						if (isset($_GET['accept']))
1370
							addSubscription($context['current_subscription']['id'], $row['id_member'], $context['current_subscription']['real_length'] == 'F' ? strtoupper(substr($pending[2], 0, 1)) : 0);
1371
						unset($pending_details[$id]);
1372
1373
						$new_details = $smcFunc['json_encode']($pending_details);
1374
1375
						// Update the entry.
1376
						$smcFunc['db_query']('', '
1377
							UPDATE {db_prefix}log_subscribed
1378
							SET payments_pending = payments_pending - 1, pending_details = {string:pending_details}
1379
							WHERE id_sublog = {int:current_subscription_item}',
1380
							array(
1381
								'current_subscription_item' => $context['log_id'],
1382
								'pending_details' => $new_details,
1383
							)
1384
						);
1385
1386
						// Reload
1387
						redirectexit('action=admin;area=paidsubscribe;sa=modifyuser;lid=' . $context['log_id']);
1388
					}
1389
				}
1390
			}
1391
		}
1392
1393
		$context['sub_id'] = $row['id_subscribe'];
1394
		$context['sub'] = array(
1395
			'id' => 0,
1396
			'start' => array(
1397
				'year' => (int) strftime('%Y', $row['start_time']),
1398
				'month' => (int) strftime('%m', $row['start_time']),
1399
				'day' => (int) strftime('%d', $row['start_time']),
1400
				'hour' => (int) strftime('%H', $row['start_time']),
1401
				'min' => (int) strftime('%M', $row['start_time']) < 10 ? '0' . (int) strftime('%M', $row['start_time']) : (int) strftime('%M', $row['start_time']),
1402
				'last_day' => 0,
1403
			),
1404
			'end' => array(
1405
				'year' => (int) strftime('%Y', $row['end_time']),
1406
				'month' => (int) strftime('%m', $row['end_time']),
1407
				'day' => (int) strftime('%d', $row['end_time']),
1408
				'hour' => (int) strftime('%H', $row['end_time']),
1409
				'min' => (int) strftime('%M', $row['end_time']) < 10 ? '0' . (int) strftime('%M', $row['end_time']) : (int) strftime('%M', $row['end_time']),
1410
				'last_day' => 0,
1411
			),
1412
			'status' => $row['status'],
1413
			'username' => $row['username'],
1414
		);
1415
		$context['sub']['start']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['sub']['start']['month'] == 12 ? 1 : $context['sub']['start']['month'] + 1, 0, $context['sub']['start']['month'] == 12 ? $context['sub']['start']['year'] + 1 : $context['sub']['start']['year']));
1416
		$context['sub']['end']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['sub']['end']['month'] == 12 ? 1 : $context['sub']['end']['month'] + 1, 0, $context['sub']['end']['month'] == 12 ? $context['sub']['end']['year'] + 1 : $context['sub']['end']['year']));
1417
	}
1418
1419
	loadJavaScriptFile('suggest.js', array('defer' => false, 'minimize' => true), 'smf_suggest');
1420
}
1421
1422
/**
1423
 * Reapplies all subscription rules for each of the users.
1424
 *
1425
 * @param array $users An array of user IDs
1426
 */
1427
function reapplySubscriptions($users)
1428
{
1429
	global $smcFunc;
1430
1431
	// Make it an array.
1432
	if (!is_array($users))
0 ignored issues
show
The condition is_array($users) is always true.
Loading history...
1433
		$users = array($users);
1434
1435
	// Get all the members current groups.
1436
	$groups = array();
1437
	$request = $smcFunc['db_query']('', '
1438
		SELECT id_member, id_group, additional_groups
1439
		FROM {db_prefix}members
1440
		WHERE id_member IN ({array_int:user_list})',
1441
		array(
1442
			'user_list' => $users,
1443
		)
1444
	);
1445
	while ($row = $smcFunc['db_fetch_assoc']($request))
1446
	{
1447
		$groups[$row['id_member']] = array(
1448
			'primary' => $row['id_group'],
1449
			'additional' => explode(',', $row['additional_groups']),
1450
		);
1451
	}
1452
	$smcFunc['db_free_result']($request);
1453
1454
	$request = $smcFunc['db_query']('', '
1455
		SELECT ls.id_member, ls.old_id_group, s.id_group, s.add_groups
1456
		FROM {db_prefix}log_subscribed AS ls
1457
			INNER JOIN {db_prefix}subscriptions AS s ON (s.id_subscribe = ls.id_subscribe)
1458
		WHERE ls.id_member IN ({array_int:user_list})
1459
			AND ls.end_time > {int:current_time}',
1460
		array(
1461
			'user_list' => $users,
1462
			'current_time' => time(),
1463
		)
1464
	);
1465
	while ($row = $smcFunc['db_fetch_assoc']($request))
1466
	{
1467
		// Specific primary group?
1468
		if ($row['id_group'] != 0)
1469
		{
1470
			// If this is changing - add the old one to the additional groups so it's not lost.
1471
			if ($row['id_group'] != $groups[$row['id_member']]['primary'])
1472
				$groups[$row['id_member']]['additional'][] = $groups[$row['id_member']]['primary'];
1473
			$groups[$row['id_member']]['primary'] = $row['id_group'];
1474
		}
1475
1476
		// Additional groups.
1477
		if (!empty($row['add_groups']))
1478
			$groups[$row['id_member']]['additional'] = array_merge($groups[$row['id_member']]['additional'], explode(',', $row['add_groups']));
1479
	}
1480
	$smcFunc['db_free_result']($request);
1481
1482
	// Update all the members.
1483
	foreach ($groups as $id => $group)
1484
	{
1485
		$group['additional'] = array_unique($group['additional']);
1486
		foreach ($group['additional'] as $key => $value)
1487
			if (empty($value))
1488
				unset($group['additional'][$key]);
1489
		$addgroups = implode(',', $group['additional']);
1490
1491
		$smcFunc['db_query']('', '
1492
			UPDATE {db_prefix}members
1493
			SET id_group = {int:primary_group}, additional_groups = {string:additional_groups}
1494
			WHERE id_member = {int:current_member}
1495
			LIMIT 1',
1496
			array(
1497
				'primary_group' => $group['primary'],
1498
				'current_member' => $id,
1499
				'additional_groups' => $addgroups,
1500
			)
1501
		);
1502
	}
1503
}
1504
1505
/**
1506
 * Add or extend a subscription of a user.
1507
 *
1508
 * @param int $id_subscribe The subscription ID
1509
 * @param int $id_member The ID of the member
1510
 * @param int|string $renewal 0 if we're forcing start/end time, otherwise a string indicating how long to renew the subscription for ('D', 'W', 'M' or 'Y')
1511
 * @param int $forceStartTime If set, forces the subscription to start at the specified time
1512
 * @param int $forceEndTime If set, forces the subscription to end at the specified time
1513
 */
1514
function addSubscription($id_subscribe, $id_member, $renewal = 0, $forceStartTime = 0, $forceEndTime = 0)
1515
{
1516
	global $context, $smcFunc;
1517
1518
	// Take the easy way out...
1519
	loadSubscriptions();
1520
1521
	// Exists, yes?
1522
	if (!isset($context['subscriptions'][$id_subscribe]))
1523
		return;
1524
1525
	$curSub = $context['subscriptions'][$id_subscribe];
1526
1527
	// Grab the duration.
1528
	$duration = $curSub['num_length'];
1529
1530
	// If this is a renewal change the duration to be correct.
1531
	if (!empty($renewal))
1532
	{
1533
		switch ($renewal)
1534
		{
1535
			case 'D':
1536
				$duration = 86400;
1537
				break;
1538
			case 'W':
1539
				$duration = 604800;
1540
				break;
1541
			case 'M':
1542
				$duration = 2629743;
1543
				break;
1544
			case 'Y':
1545
				$duration = 31556926;
1546
				break;
1547
			default:
1548
				break;
1549
		}
1550
	}
1551
1552
	// Firstly, see whether it exists, and is active. If so then this is meerly an extension.
1553
	$request = $smcFunc['db_query']('', '
1554
		SELECT id_sublog, end_time, start_time
1555
		FROM {db_prefix}log_subscribed
1556
		WHERE id_subscribe = {int:current_subscription}
1557
			AND id_member = {int:current_member}
1558
			AND status = {int:is_active}',
1559
		array(
1560
			'current_subscription' => $id_subscribe,
1561
			'current_member' => $id_member,
1562
			'is_active' => 1,
1563
		)
1564
	);
1565
1566
	if ($smcFunc['db_num_rows']($request) != 0)
1567
	{
1568
		list ($id_sublog, $endtime, $starttime) = $smcFunc['db_fetch_row']($request);
1569
1570
		// If this has already expired but is active, extension means the period from now.
1571
		if ($endtime < time())
1572
			$endtime = time();
1573
		if ($starttime == 0)
1574
			$starttime = time();
1575
1576
		// Work out the new expiry date.
1577
		$endtime += $duration;
1578
1579
		if ($forceEndTime != 0)
1580
			$endtime = $forceEndTime;
1581
1582
		// As everything else should be good, just update!
1583
		$smcFunc['db_query']('', '
1584
			UPDATE {db_prefix}log_subscribed
1585
			SET end_time = {int:end_time}, start_time = {int:start_time}, reminder_sent = {int:no_reminder_sent}
1586
			WHERE id_sublog = {int:current_subscription_item}',
1587
			array(
1588
				'end_time' => $endtime,
1589
				'start_time' => $starttime,
1590
				'current_subscription_item' => $id_sublog,
1591
				'no_reminder_sent' => 0,
1592
			)
1593
		);
1594
1595
		return;
1596
	}
1597
	$smcFunc['db_free_result']($request);
1598
1599
	// If we're here, that means we don't have an active subscription - that means we need to do some work!
1600
	$request = $smcFunc['db_query']('', '
1601
		SELECT m.id_group, m.additional_groups
1602
		FROM {db_prefix}members AS m
1603
		WHERE m.id_member = {int:current_member}',
1604
		array(
1605
			'current_member' => $id_member,
1606
		)
1607
	);
1608
1609
	// Just in case the member doesn't exist.
1610
	if ($smcFunc['db_num_rows']($request) == 0)
1611
		return;
1612
1613
	list ($old_id_group, $additional_groups) = $smcFunc['db_fetch_row']($request);
1614
	$smcFunc['db_free_result']($request);
1615
1616
	// Prepare additional groups.
1617
	$newAddGroups = explode(',', $curSub['add_groups']);
1618
	$curAddGroups = explode(',', $additional_groups);
1619
1620
	$newAddGroups = array_merge($newAddGroups, $curAddGroups);
1621
1622
	// Simple, simple, simple - hopefully... id_group first.
1623
	if ($curSub['prim_group'] != 0)
1624
	{
1625
		$id_group = $curSub['prim_group'];
1626
1627
		// Ensure their old privileges are maintained.
1628
		if ($old_id_group != 0)
1629
			$newAddGroups[] = $old_id_group;
1630
	}
1631
	else
1632
		$id_group = $old_id_group;
1633
1634
	// Yep, make sure it's unique, and no empties.
1635
	foreach ($newAddGroups as $k => $v)
1636
		if (empty($v))
1637
			unset($newAddGroups[$k]);
1638
	$newAddGroups = array_unique($newAddGroups);
1639
	$newAddGroups = implode(',', $newAddGroups);
1640
1641
	// Store the new settings.
1642
	$smcFunc['db_query']('', '
1643
		UPDATE {db_prefix}members
1644
		SET id_group = {int:primary_group}, additional_groups = {string:additional_groups}
1645
		WHERE id_member = {int:current_member}',
1646
		array(
1647
			'primary_group' => $id_group,
1648
			'current_member' => $id_member,
1649
			'additional_groups' => $newAddGroups,
1650
		)
1651
	);
1652
1653
	// Now log the subscription - maybe we have a dorment subscription we can restore?
1654
	$request = $smcFunc['db_query']('', '
1655
		SELECT id_sublog, end_time, start_time
1656
		FROM {db_prefix}log_subscribed
1657
		WHERE id_subscribe = {int:current_subscription}
1658
			AND id_member = {int:current_member}',
1659
		array(
1660
			'current_subscription' => $id_subscribe,
1661
			'current_member' => $id_member,
1662
		)
1663
	);
1664
1665
	/**
1666
	 * @todo Don't really need to do this twice...
1667
	 */
1668
	if ($smcFunc['db_num_rows']($request) != 0)
1669
	{
1670
		list ($id_sublog, $endtime, $starttime) = $smcFunc['db_fetch_row']($request);
1671
1672
		// If this has already expired but is active, extension means the period from now.
1673
		if ($endtime < time())
1674
			$endtime = time();
1675
		if ($starttime == 0)
1676
			$starttime = time();
1677
1678
		// Work out the new expiry date.
1679
		$endtime += $duration;
1680
1681
		if ($forceEndTime != 0)
1682
			$endtime = $forceEndTime;
1683
1684
		// As everything else should be good, just update!
1685
		$smcFunc['db_query']('', '
1686
			UPDATE {db_prefix}log_subscribed
1687
			SET start_time = {int:start_time}, end_time = {int:end_time}, old_id_group = {int:old_id_group}, status = {int:is_active}, reminder_sent = {int:no_reminder_sent}
1688
			WHERE id_sublog = {int:current_subscription_item}',
1689
			array(
1690
				'start_time' => $starttime,
1691
				'end_time' => $endtime,
1692
				'old_id_group' => $old_id_group,
1693
				'is_active' => 1,
1694
				'no_reminder_sent' => 0,
1695
				'current_subscription_item' => $id_sublog,
1696
			)
1697
		);
1698
1699
		return;
1700
	}
1701
	$smcFunc['db_free_result']($request);
1702
1703
	// Otherwise a very simple insert.
1704
	$endtime = time() + $duration;
1705
	if ($forceEndTime != 0)
1706
		$endtime = $forceEndTime;
1707
1708
	if ($forceStartTime == 0)
1709
		$starttime = time();
1710
	else
1711
		$starttime = $forceStartTime;
1712
1713
	$smcFunc['db_insert']('',
1714
		'{db_prefix}log_subscribed',
1715
		array(
1716
			'id_subscribe' => 'int', 'id_member' => 'int', 'old_id_group' => 'int', 'start_time' => 'int',
1717
			'end_time' => 'int', 'status' => 'int', 'pending_details' => 'string',
1718
		),
1719
		array(
1720
			$id_subscribe, $id_member, $old_id_group, $starttime,
1721
			$endtime, 1, '',
1722
		),
1723
		array('id_sublog')
1724
	);
1725
}
1726
1727
/**
1728
 * Removes a subscription from a user, as in removes the groups.
1729
 *
1730
 * @param int $id_subscribe The ID of the subscription
1731
 * @param int $id_member The ID of the member
1732
 * @param bool $delete Whether to delete the subscription or just disable it
1733
 */
1734
function removeSubscription($id_subscribe, $id_member, $delete = false)
1735
{
1736
	global $context, $smcFunc;
1737
1738
	loadSubscriptions();
1739
1740
	// Load the user core bits.
1741
	$request = $smcFunc['db_query']('', '
1742
		SELECT m.id_group, m.additional_groups
1743
		FROM {db_prefix}members AS m
1744
		WHERE m.id_member = {int:current_member}',
1745
		array(
1746
			'current_member' => $id_member,
1747
		)
1748
	);
1749
1750
	// Just in case of errors.
1751
	if ($smcFunc['db_num_rows']($request) == 0)
1752
	{
1753
		$smcFunc['db_query']('', '
1754
			DELETE FROM {db_prefix}log_subscribed
1755
			WHERE id_member = {int:current_member}',
1756
			array(
1757
				'current_member' => $id_member,
1758
			)
1759
		);
1760
		return;
1761
	}
1762
	list ($id_group, $additional_groups) = $smcFunc['db_fetch_row']($request);
1763
	$smcFunc['db_free_result']($request);
1764
1765
	// Get all of the subscriptions for this user that are active - it will be necessary!
1766
	$request = $smcFunc['db_query']('', '
1767
		SELECT id_subscribe, old_id_group
1768
		FROM {db_prefix}log_subscribed
1769
		WHERE id_member = {int:current_member}
1770
			AND status = {int:is_active}',
1771
		array(
1772
			'current_member' => $id_member,
1773
			'is_active' => 1,
1774
		)
1775
	);
1776
1777
	// These variables will be handy, honest ;)
1778
	$removals = array();
1779
	$allowed = array();
1780
	$old_id_group = 0;
1781
	$new_id_group = -1;
1782
	while ($row = $smcFunc['db_fetch_assoc']($request))
1783
	{
1784
		if (!isset($context['subscriptions'][$row['id_subscribe']]))
1785
			continue;
1786
1787
		// The one we're removing?
1788
		if ($row['id_subscribe'] == $id_subscribe)
1789
		{
1790
			$removals = explode(',', $context['subscriptions'][$row['id_subscribe']]['add_groups']);
1791
			if ($context['subscriptions'][$row['id_subscribe']]['prim_group'] != 0)
1792
				$removals[] = $context['subscriptions'][$row['id_subscribe']]['prim_group'];
1793
			$old_id_group = $row['old_id_group'];
1794
		}
1795
		// Otherwise things we allow.
1796
		else
1797
		{
1798
			$allowed = array_merge($allowed, explode(',', $context['subscriptions'][$row['id_subscribe']]['add_groups']));
1799
			if ($context['subscriptions'][$row['id_subscribe']]['prim_group'] != 0)
1800
			{
1801
				$allowed[] = $context['subscriptions'][$row['id_subscribe']]['prim_group'];
1802
				$new_id_group = $context['subscriptions'][$row['id_subscribe']]['prim_group'];
1803
			}
1804
		}
1805
	}
1806
	$smcFunc['db_free_result']($request);
1807
1808
	// Now, for everything we are removing check they definitely are not allowed it.
1809
	$existingGroups = explode(',', $additional_groups);
1810
	foreach ($existingGroups as $key => $group)
1811
		if (empty($group) || (in_array($group, $removals) && !in_array($group, $allowed)))
1812
			unset($existingGroups[$key]);
1813
1814
	// Finally, do something with the current primary group.
1815
	if (in_array($id_group, $removals))
1816
	{
1817
		// If this primary group is actually allowed keep it.
1818
		if (in_array($id_group, $allowed))
1819
			$existingGroups[] = $id_group;
1820
1821
		// Either way, change the id_group back.
1822
		if ($new_id_group < 1)
1823
		{
1824
			// If we revert to the old id-group we need to ensure it wasn't from a subscription.
1825
			foreach ($context['subscriptions'] as $id => $group)
1826
				// It was? Make them a regular member then!
1827
				if ($group['prim_group'] == $old_id_group)
1828
					$old_id_group = 0;
1829
1830
			$id_group = $old_id_group;
1831
		}
1832
		else
1833
			$id_group = $new_id_group;
1834
	}
1835
1836
	// Crazy stuff, we seem to have our groups fixed, just make them unique
1837
	$existingGroups = array_unique($existingGroups);
1838
	$existingGroups = implode(',', $existingGroups);
1839
1840
	// Update the member
1841
	$smcFunc['db_query']('', '
1842
		UPDATE {db_prefix}members
1843
		SET id_group = {int:primary_group}, additional_groups = {string:existing_groups}
1844
		WHERE id_member = {int:current_member}',
1845
		array(
1846
			'primary_group' => $id_group,
1847
			'current_member' => $id_member,
1848
			'existing_groups' => $existingGroups,
1849
		)
1850
	);
1851
1852
	// Disable the subscription.
1853
	if (!$delete)
1854
		$smcFunc['db_query']('', '
1855
			UPDATE {db_prefix}log_subscribed
1856
			SET status = {int:not_active}
1857
			WHERE id_member = {int:current_member}
1858
				AND id_subscribe = {int:current_subscription}',
1859
			array(
1860
				'not_active' => 0,
1861
				'current_member' => $id_member,
1862
				'current_subscription' => $id_subscribe,
1863
			)
1864
		);
1865
	// Otherwise delete it!
1866
	else
1867
		$smcFunc['db_query']('', '
1868
			DELETE FROM {db_prefix}log_subscribed
1869
			WHERE id_member = {int:current_member}
1870
				AND id_subscribe = {int:current_subscription}',
1871
			array(
1872
				'current_member' => $id_member,
1873
				'current_subscription' => $id_subscribe,
1874
			)
1875
		);
1876
}
1877
1878
/**
1879
 * This just kind of caches all the subscription data.
1880
 */
1881
function loadSubscriptions()
1882
{
1883
	global $context, $txt, $modSettings, $smcFunc;
1884
1885
	if (!empty($context['subscriptions']))
1886
		return;
1887
1888
	// Make sure this is loaded, just in case.
1889
	loadLanguage('ManagePaid');
1890
1891
	$request = $smcFunc['db_query']('', '
1892
		SELECT id_subscribe, name, description, cost, length, id_group, add_groups, active, repeatable
1893
		FROM {db_prefix}subscriptions',
1894
		array(
1895
		)
1896
	);
1897
	$context['subscriptions'] = array();
1898
	while ($row = $smcFunc['db_fetch_assoc']($request))
1899
	{
1900
		// Pick a cost.
1901
		$costs = $smcFunc['json_decode']($row['cost'], true);
1902
1903
		if ($row['length'] != 'F' && !empty($modSettings['paid_currency_symbol']) && !empty($costs['fixed']))
1904
			$cost = sprintf($modSettings['paid_currency_symbol'], $costs['fixed']);
1905
		else
1906
			$cost = '???';
1907
1908
		// Do the span.
1909
		preg_match('~(\d*)(\w)~', $row['length'], $match);
1910
		if (isset($match[2]))
1911
		{
1912
			$num_length = $match[1];
1913
			$length = $match[1] . ' ';
1914
			switch ($match[2])
1915
			{
1916
				case 'D':
1917
					$length .= $txt['paid_mod_span_days'];
1918
					$num_length *= 86400;
1919
					break;
1920
				case 'W':
1921
					$length .= $txt['paid_mod_span_weeks'];
1922
					$num_length *= 604800;
1923
					break;
1924
				case 'M':
1925
					$length .= $txt['paid_mod_span_months'];
1926
					$num_length *= 2629743;
1927
					break;
1928
				case 'Y':
1929
					$length .= $txt['paid_mod_span_years'];
1930
					$num_length *= 31556926;
1931
					break;
1932
			}
1933
		}
1934
		else
1935
			$length = '??';
1936
1937
		$context['subscriptions'][$row['id_subscribe']] = array(
1938
			'id' => $row['id_subscribe'],
1939
			'name' => $row['name'],
1940
			'desc' => $row['description'],
1941
			'cost' => $cost,
1942
			'real_cost' => $row['cost'],
1943
			'length' => $length,
1944
			'num_length' => $num_length,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $num_length does not seem to be defined for all execution paths leading up to this point.
Loading history...
1945
			'real_length' => $row['length'],
1946
			'pending' => 0,
1947
			'finished' => 0,
1948
			'total' => 0,
1949
			'active' => $row['active'],
1950
			'prim_group' => $row['id_group'],
1951
			'add_groups' => $row['add_groups'],
1952
			'flexible' => $row['length'] == 'F' ? true : false,
1953
			'repeatable' => $row['repeatable'],
1954
		);
1955
	}
1956
	$smcFunc['db_free_result']($request);
1957
1958
	// Do the counts.
1959
	$request = $smcFunc['db_query']('', '
1960
		SELECT COUNT(id_sublog) AS member_count, id_subscribe, status
1961
		FROM {db_prefix}log_subscribed
1962
		GROUP BY id_subscribe, status',
1963
		array(
1964
		)
1965
	);
1966
	while ($row = $smcFunc['db_fetch_assoc']($request))
1967
	{
1968
		$ind = $row['status'] == 0 ? 'finished' : 'total';
1969
1970
		if (isset($context['subscriptions'][$row['id_subscribe']]))
1971
			$context['subscriptions'][$row['id_subscribe']][$ind] = $row['member_count'];
1972
	}
1973
	$smcFunc['db_free_result']($request);
1974
1975
	// How many payments are we waiting on?
1976
	$request = $smcFunc['db_query']('', '
1977
		SELECT SUM(payments_pending) AS total_pending, id_subscribe
1978
		FROM {db_prefix}log_subscribed
1979
		GROUP BY id_subscribe',
1980
		array(
1981
		)
1982
	);
1983
	while ($row = $smcFunc['db_fetch_assoc']($request))
1984
	{
1985
		if (isset($context['subscriptions'][$row['id_subscribe']]))
1986
			$context['subscriptions'][$row['id_subscribe']]['pending'] = $row['total_pending'];
1987
	}
1988
	$smcFunc['db_free_result']($request);
1989
}
1990
1991
/**
1992
 * Load all the payment gateways.
1993
 * Checks the Sources directory for any files fitting the format of a payment gateway,
1994
 * loads each file to check it's valid, includes each file and returns the
1995
 * function name and whether it should work with this version of SMF.
1996
 *
1997
 * @return array An array of information about available payment gateways
1998
 */
1999
function loadPaymentGateways()
2000
{
2001
	global $sourcedir;
2002
2003
	$gateways = array();
2004
	if ($dh = opendir($sourcedir))
2005
	{
2006
		while (($file = readdir($dh)) !== false)
2007
		{
2008
			if (is_file($sourcedir . '/' . $file) && preg_match('~^Subscriptions-([A-Za-z\d]+)\.php$~', $file, $matches))
2009
			{
2010
				// Check this is definitely a valid gateway!
2011
				$fp = fopen($sourcedir . '/' . $file, 'rb');
2012
				$header = fread($fp, 4096);
0 ignored issues
show
It seems like $fp can also be of type false; however, parameter $handle of fread() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

2012
				$header = fread(/** @scrutinizer ignore-type */ $fp, 4096);
Loading history...
2013
				fclose($fp);
0 ignored issues
show
It seems like $fp can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

2013
				fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
2014
2015
				if (strpos($header, '// SMF Payment Gateway: ' . strtolower($matches[1])) !== false)
2016
				{
2017
					require_once($sourcedir . '/' . $file);
2018
2019
					$gateways[] = array(
2020
						'filename' => $file,
2021
						'code' => strtolower($matches[1]),
2022
						// Don't need anything snazzier than this yet.
2023
						'valid_version' => class_exists(strtolower($matches[1]) . '_payment') && class_exists(strtolower($matches[1]) . '_display'),
2024
						'payment_class' => strtolower($matches[1]) . '_payment',
2025
						'display_class' => strtolower($matches[1]) . '_display',
2026
					);
2027
				}
2028
			}
2029
		}
2030
	}
2031
	closedir($dh);
0 ignored issues
show
It seems like $dh can also be of type false; however, parameter $dir_handle of closedir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

2031
	closedir(/** @scrutinizer ignore-type */ $dh);
Loading history...
2032
2033
	return $gateways;
2034
}
2035
2036
?>