ManagePaid::action_modify()   F
last analyzed

Complexity

Conditions 24
Paths 4736

Size

Total Lines 171
Code Lines 95

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 600

Importance

Changes 0
Metric Value
cc 24
eloc 95
c 0
b 0
f 0
nc 4736
nop 0
dl 0
loc 171
ccs 0
cts 74
cp 0
crap 600
rs 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This file contains all the administration functions for subscriptions.
5
 * (and some more than that :P)
6
 *
7
 * @package   ElkArte Forum
8
 * @copyright ElkArte Forum contributors
9
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
10
 *
11
 * This file contains code covered by:
12
 * copyright: 2011 Simple Machines (http://www.simplemachines.org)
13
 *
14
 * @version 2.0 dev
15
 *
16
 */
17
18
namespace ElkArte\AdminController;
19
20
use ElkArte\AbstractController;
21
use ElkArte\Action;
22
use ElkArte\Exceptions\Exception;
23
use ElkArte\Helper\DataValidator;
24
use ElkArte\Helper\Util;
25
use ElkArte\Languages\Txt;
26
use ElkArte\SettingsForm\SettingsForm;
27
28
/**
29
 * ManagePaid controller, administration controller for paid subscriptions.
30
 *
31
 * @package Subscriptions
32
 */
33
class ManagePaid extends AbstractController
34
{
35
	/**
36
	 * The main entrance point for the 'Paid Subscription' screen,
37
	 *
38
	 * What it does:
39
	 *
40
	 * - calling the right function based on the given sub-action.
41
	 * - It defaults to sub-action 'view'.
42
	 * - Accessed from ?action=admin;area=paidsubscribe.
43
	 * - It requires admin_forum permission for admin based actions.
44
	 *
45
	 * @event integrate_sa_manage_subscriptions
46
	 * @see \ElkArte\AbstractController::action_index()
47
	 */
48
	public function action_index()
49
	{
50
		global $context, $txt, $modSettings;
51
52
		// Load the required language and template.
53
		Txt::load('ManagePaid');
54
		theme()->getTemplates()->load('ManagePaid');
55
56
		$subActions = array(
57
			'modify' => array(
58
				'controller' => $this,
59
				'function' => 'action_modify',
60
				'permission' => 'admin_forum'),
61
			'modifyuser' => array(
62
				'controller' => $this,
63
				'function' => 'action_modifyuser',
64
				'permission' => 'admin_forum'),
65
			'settings' => array(
66
				'controller' => $this,
67
				'function' => 'action_paidSettings_display',
68
				'permission' => 'admin_forum'),
69
			'view' => array(
70
				'controller' => $this,
71
				'function' => 'action_view',
72
				'permission' => 'admin_forum'),
73
			'viewsub' => array(
74
				'controller' => $this,
75
				'function' => 'action_viewsub',
76
				'permission' => 'admin_forum'),
77
		);
78
79
		// Some actions
80
		$action = new Action('manage_subscriptions');
81
82
		// Load in the subActions, call integrate_sa_manage_subscriptions
83
		$subAction = $action->initialize($subActions, empty($modSettings['paid_currency_symbol']) ? 'settings' : 'view');
84
85
		// Final things for the template
86
		$context['page_title'] = $txt['paid_subscriptions'];
87
		$context['sub_action'] = $subAction;
88
89
		// Tabs for browsing the different subscription functions.
90
		$context[$context['admin_menu_name']]['object']->prepareTabData([
91
			'title' => 'paid_subscriptions',
92
			'description' => 'paid_subscriptions_desc',
93
			'prefix' => 'paid_subs',
94
			'tabs' => [
95
				'view' => [
96
					'disabled' => empty($modSettings['paid_currency_symbol']),
97
				],
98
			],
99
		]);
100
101
		// Call the right function for this sub-action.
102
		$action->dispatch($subAction);
103
	}
104
105
	/**
106
	 * Set any setting related to paid subscriptions,
107
	 *
108
	 * - i.e. modify which payment methods are to be used.
109
	 * - It requires the moderate_forum permission
110
	 * - Accessed from ?action=admin;area=paidsubscribe;sa=settings.
111
	 *
112
	 * @event integrate_save_subscription_settings
113
	 */
114
	public function action_paidSettings_display()
115
	{
116
		global $context, $txt, $modSettings;
117
118
		require_once(SUBSDIR . '/PaidSubscriptions.subs.php');
119
120
		// Initialize the form
121
		$settingsForm = new SettingsForm(SettingsForm::DB_ADAPTER);
122
123
		// Initialize it with our settings
124
		$config_vars = $this->_settings();
125
		$settingsForm->setConfigVars($config_vars);
126
127
		// Some important context stuff
128
		$context['page_title'] = $txt['settings'];
129
		$context['sub_template'] = 'show_settings';
130
		$context['settings_message'] = replaceBasicActionUrl($txt['paid_note']);
131
132
		// Get the final touches in place.
133
		$context['post_url'] = getUrl('admin', ['action' => 'admin', 'area' => 'paidsubscribe', 'save', 'sa' => 'settings']);
134
		$context['settings_title'] = $txt['settings'];
135
136
		// We want javascript for our currency options.
137
		theme()->addInlineJavascript('
138
		toggleCurrencyOther();', true);
139
140
		// Saving the settings?
141
		if (isset($this->_req->query->save))
142
		{
143
			checkSession();
144
145
			call_integration_hook('integrate_save_subscription_settings');
146
147
			// Check that the entered email addresses are valid
148
			if (!empty($this->_req->post->paid_email_to))
149
			{
150
				$validator = new DataValidator();
151
152
				// Some cleaning and some rules
153
				$validator->sanitation_rules(array('paid_email_to' => 'trim'));
154
				$validator->validation_rules(array('paid_email_to' => 'valid_email'));
155
				$validator->input_processing(array('paid_email_to' => 'csv'));
156
				$validator->text_replacements(array('paid_email_to' => $txt['paid_email_to']));
157
158
				if ($validator->validate($this->_req->post))
159
				{
160
					$this->_req->post->paid_email_to = $validator->validation_data('paid_email_to');
161
				}
162
				else
163
				{
164
					// That's not an email, lets set it back in the form to be fixed and let them know its wrong
165
					$modSettings['paid_email_to'] = $this->_req->post->paid_email_to;
166
					$context['error_type'] = 'minor';
167
					$context['settings_message'] = array();
168
					foreach ($validator->validation_errors() as $error)
169
					{
170
						$context['settings_message'][] = $error;
171
					}
172
				}
173
			}
174
175
			// No errors, then save away
176
			if (empty($context['error_type']))
177
			{
178
				// Sort out the currency stuff.
179
				if ($this->_req->post->paid_currency !== 'other')
180
				{
181
					$this->_req->post->paid_currency_code = $this->_req->post->paid_currency;
182
					$this->_req->post->paid_currency_symbol = $txt[$this->_req->post->paid_currency . '_symbol'];
183
				}
184
185
				$this->_req->post->paid_currency_code = trim($this->_req->post->paid_currency_code);
186
187
				unset($config_vars['dummy_currency']);
188
				$settingsForm->setConfigVars($config_vars);
189
				$settingsForm->setConfigValues((array) $this->_req->post);
190
				$settingsForm->save();
191
				redirectexit('action=admin;area=paidsubscribe;sa=settings');
192
			}
193
		}
194
195
		// Prepare the settings...
196
		$settingsForm->prepare();
197
	}
198
199
	/**
200
	 * Retrieve subscriptions settings.
201
	 *
202
	 * @event integrate_modify_subscription_settings
203
	 */
204
	private function _settings()
205
	{
206 2
		global $modSettings, $txt;
207
208 2
		// 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.
209
		$modSettings['paid_currency'] = empty($modSettings['paid_currency_code']) ? '' : $modSettings['paid_currency_code'];
210
		if (!empty($modSettings['paid_currency_code']) && !in_array($modSettings['paid_currency_code'], array('usd', 'eur', 'gbp')))
211 2
		{
212 2
			$modSettings['paid_currency'] = 'other';
213
		}
214
215
		// These are all the default settings.
216
		$config_vars = array(
217
			array('select', 'paid_email', array(0 => $txt['paid_email_no'], 1 => $txt['paid_email_error'], 2 => $txt['paid_email_all']), 'subtext' => $txt['paid_email_desc']),
218
			array('text', 'paid_email_to', 'subtext' => $txt['paid_email_to_desc'], 'size' => 60),
219 2
			'',
220 2
			'dummy_currency' => array('select', 'paid_currency', array('usd' => $txt['usd'], 'eur' => $txt['eur'], 'gbp' => $txt['gbp'], 'other' => $txt['other']), 'javascript' => 'onchange="toggleCurrencyOther();"'),
221 2
			array('text', 'paid_currency_code', 'subtext' => $txt['paid_currency_code_desc'], 'size' => 5, 'force_div_id' => 'custom_currency_code_div'),
222 2
			array('text', 'paid_currency_symbol', 'subtext' => $txt['paid_currency_symbol_desc'], 'size' => 8, 'force_div_id' => 'custom_currency_symbol_div'),
223 2
			array('check', 'paidsubs_test', 'subtext' => $txt['paidsubs_test_desc'], 'onclick' => "return document.getElementById('paidsubs_test').checked ? confirm('" . $txt['paidsubs_test_confirm'] . "') : true;"),
224 2
		);
225 2
226
		// Now load all the other gateway settings.
227
		require_once(SUBSDIR . '/PaidSubscriptions.subs.php');
228
		$gateways = loadPaymentGateways();
229 2
		foreach ($gateways as $gateway)
230 2
		{
231 2
			$gatewayClass = new $gateway['display_class']();
232
			$setting_data = $gatewayClass->getGatewaySettings();
233 2
			if (!empty($setting_data))
234 2
			{
235 2
				$config_vars[] = array('title', $gatewayClass->title, 'text_label' => ($txt['paidsubs_gateway_title_' . $gatewayClass->title] ?? $gatewayClass->title));
236
				$config_vars = array_merge($config_vars, $setting_data);
237 2
			}
238 2
		}
239
240
		call_integration_hook('integrate_modify_subscription_settings', array(&$config_vars));
241
242 2
		return $config_vars;
243
	}
244 2
245
	/**
246
	 * Return the paid sub settings for use in admin search
247
	 */
248
	public function settings_search()
249
	{
250 2
		return $this->_settings();
251
	}
252 2
253
	/**
254
	 * View a list of all the current subscriptions
255
	 *
256
	 * What it does:
257
	 *
258
	 * - Requires the admin_forum permission.
259
	 * - Accessed from ?action=admin;area=paidsubscribe;sa=view.
260
	 *
261
	 * @event integrate_list_subscription_list
262
	 */
263
	public function action_view()
264
	{
265
		global $context, $txt, $modSettings;
266
267
		// Not made the settings yet?
268
		if (empty($modSettings['paid_currency_symbol']))
269
		{
270
			throw new Exception('paid_not_set_currency', false, array(getUrl('admin', ['action' => 'admin', 'area' => 'paidsubscribe', 'sa' => 'settings'])));
271
		}
272
273
		// Some basic stuff.
274
		$context['page_title'] = $txt['paid_subs_view'];
275
		require_once(SUBSDIR . '/PaidSubscriptions.subs.php');
276
		loadSubscriptions();
277
278
		$listOptions = array(
279
			'id' => 'subscription_list',
280
			'title' => $txt['subscriptions'],
281
			'items_per_page' => 20,
282
			'base_href' => getUrl('admin', ['action' => 'admin', 'area' => 'paidsubscribe', 'sa' => 'view']),
283
			'get_items' => array(
284
				'function' => static function () {
285
					global $context;
286
287
					return $context['subscriptions'];
288
				},
289
			),
290
			'get_count' => array(
291
				'function' => static function () {
292
					global $context;
293
294
					return count($context['subscriptions']);
295
				},
296
			),
297
			'no_items_label' => $txt['paid_none_yet'],
298
			'columns' => array(
299
				'name' => array(
300
					'header' => array(
301
						'value' => $txt['paid_name'],
302
						'style' => 'width: 30%;',
303
					),
304
					'data' => array(
305
						'function' => static fn($rowData) => sprintf('<a href="' . getUrl('admin', ['action' => 'admin', 'area' => 'paidsubscribe', 'sa' => 'viewsub', 'sid' => $rowData['id']]) . '">%1$s</a>', $rowData['name']),
306
					),
307
				),
308
				'cost' => array(
309
					'header' => array(
310
						'value' => $txt['paid_cost'],
311
					),
312
					'data' => array(
313
						'function' => static function ($rowData) {
314
							global $txt;
315
316
							return $rowData['flexible'] ? '<em>' . $txt['flexible'] . '</em>' : $rowData['cost'] . ' / ' . $rowData['length'];
317
						},
318
					),
319
				),
320
				'pending' => array(
321
					'header' => array(
322
						'value' => $txt['paid_pending'],
323
						'class' => 'nowrap',
324
					),
325
					'data' => array(
326
						'db_htmlsafe' => 'pending',
327
					),
328
				),
329
				'finished' => array(
330
					'header' => array(
331
						'value' => $txt['paid_finished'],
332
					),
333
					'data' => array(
334
						'db_htmlsafe' => 'finished',
335
					),
336
				),
337
				'total' => array(
338
					'header' => array(
339
						'value' => $txt['paid_active'],
340
					),
341
					'data' => array(
342
						'db_htmlsafe' => 'total',
343
					),
344
				),
345
				'is_active' => array(
346
					'header' => array(
347
						'value' => $txt['paid_is_active'],
348
					),
349
					'data' => array(
350
						'function' => static function ($rowData) {
351
							global $txt;
352
353
							return '<span class="' . ($rowData['active'] ? 'success' : 'alert') . '">' . ($rowData['active'] ? $txt['yes'] : $txt['no']) . '</span>';
354
						},
355
					),
356
				),
357
				'subscribers' => array(
358
					'header' => array(
359
						'value' => $txt['subscribers'],
360
					),
361
					'data' => array(
362
						'function' => static function ($rowData) {
363
							global $txt;
364
365
							return '<a href="' . getUrl('admin', ['action' => 'admin', 'area' => 'paidsubscribe', 'sa' => 'viewsub', 'sid' => $rowData['id']]) . '"><i class="icon i-view" title="' . $txt['view'] . '"></i></a>';
366
						},
367
						'class' => 'centertext',
368
					),
369
				),
370
				'modify' => array(
371
					'header' => array(
372
						'value' => $txt['modify'],
373
					),
374
					'data' => array(
375
						'function' => static function ($rowData) {
376
							global $txt;
377
378
							return '<a href="' . getUrl('admin', ['action' => 'admin', 'area' => 'paidsubscribe', 'sa' => 'modify', 'sid' => $rowData['id']]) . '"><i class="icon i-modify" title="' . $txt['modify'] . '"></i></a>';
379
						},
380
						'class' => 'centertext',
381
					),
382
				),
383
				'delete' => array(
384
					'header' => array(
385
						'value' => $txt['remove']
386
					),
387
					'data' => array(
388
						'function' => static function ($rowData) {
389
							global $txt;
390
391
							return '<a href="' . getUrl('admin', ['action' => 'admin', 'area' => 'paidsubscribe', 'sa' => 'modify', 'delete', 'sid' => $rowData['id']]) . '"><i class="icon i-delete" title="' . $txt['delete'] . '"></i></a>';
392
						},
393
						'class' => 'centertext',
394
					),
395
				),
396
			),
397
			'form' => array(
398
				'href' => getUrl('admin', ['action' => 'admin', 'area' => 'paidsubscribe', 'sa' => 'modify']),
399
			),
400
			'additional_rows' => array(
401
				array(
402
					'position' => 'below_table_data',
403
					'class' => 'flow_flex_additional_row',
404
					'value' => '<input type="submit" name="add" value="' . $txt['paid_add_subscription'] . '" class="right_submit" />',
405
				),
406
			),
407
		);
408
409
		createList($listOptions);
410
411
		$context['sub_template'] = 'show_list';
412
		$context['default_list'] = 'subscription_list';
413
	}
414
415
	/**
416
	 * Adding, editing and deleting subscriptions.
417
	 *
418
	 * - Accessed from ?action=admin;area=paidsubscribe;sa=modify.
419
	 *
420
	 * @event integrate_delete_subscription passed ID of deletion
421
	 * @event integrate_save_subscription
422
	 */
423
	public function action_modify()
424
	{
425
		global $context, $txt;
426
427
		require_once(SUBSDIR . '/PaidSubscriptions.subs.php');
428
429
		$context['sub_id'] = isset($this->_req->query->sid) ? (int) $this->_req->query->sid : 0;
430
		$context['action_type'] = $context['sub_id'] !== 0 ? (isset($this->_req->query->delete) ? 'delete' : 'edit') : 'add';
431
432
		// Setup the template.
433
		$context['sub_template'] = $context['action_type'] === 'delete' ? 'delete_subscription' : 'modify_subscription';
434
		$context['page_title'] = $txt['paid_' . $context['action_type'] . '_subscription'];
435
436
		// Delete it?
437
		if (isset($this->_req->post->delete_confirm, $this->_req->query->delete))
438
		{
439
			checkSession();
440
			validateToken('admin-pmsd');
441
442
			deleteSubscription($context['sub_id']);
443
444
			call_integration_hook('integrate_delete_subscription', array($context['sub_id']));
445
446
			redirectexit('action=admin;area=paidsubscribe;view');
447
		}
448
449
		// Saving?
450
		if (isset($this->_req->post->save))
451
		{
452
			checkSession();
453
			validateToken('admin-pms');
454
455
			// Some cleaning...
456
			$isActive = max($this->_req->getPost('active', 'intval', 0), 1);
457
			$isRepeatable = max($this->_req->getPost('repeatable', 'intval', 0), 1);
458
			$allowPartial = max($this->_req->getPost('allow_partial', 'intval', 0), 1);
459
			$reminder = max($this->_req->getPost('reminder', 'intval', 0), 1);
460
			$emailComplete = strlen($this->_req->post->emailcomplete) > 10 ? trim($this->_req->post->emailcomplete) : '';
461
462
			// Is this a fixed one?
463
			if ($this->_req->post->duration_type === 'fixed')
464
			{
465
				// Clean the span.
466
				$span = $this->_req->post->span_value . $this->_req->post->span_unit;
467
468
				// Sort out the cost.
469
				$cost = array('fixed' => sprintf('%01.2f', strtr($this->_req->post->cost, ',', '.')));
470
471
				// There needs to be something.
472
				if (empty($this->_req->post->span_value) || empty($this->_req->post->cost))
473
				{
474
					throw new Exception('paid_no_cost_value');
475
				}
476
			}
477
			// Flexible is harder but more fun ;)
478
			else
479
			{
480
				$span = 'F';
481
482
				$cost = array(
483
					'day' => sprintf('%01.2f', strtr($this->_req->post->cost_day, ',', '.')),
484
					'week' => sprintf('%01.2f', strtr($this->_req->post->cost_week, ',', '.')),
485
					'month' => sprintf('%01.2f', strtr($this->_req->post->cost_month, ',', '.')),
486
					'year' => sprintf('%01.2f', strtr($this->_req->post->cost_year, ',', '.')),
487
				);
488
489
				if (empty($this->_req->post->cost_day) && empty($this->_req->post->cost_week) && empty($this->_req->post->cost_month) && empty($this->_req->post->cost_year))
490
				{
491
					throw new Exception('paid_all_freq_blank');
492
				}
493
			}
494
495
			$cost = serialize($cost);
496
497
			// Yep, time to do additional groups.
498
			$addGroups = array();
499
			if (!empty($this->_req->post->addgroup))
500
			{
501
				foreach ($this->_req->post->addgroup as $id => $dummy)
502
				{
503
					$addGroups[] = (int) $id;
504
				}
505
			}
506
507
			$addGroups = implode(',', $addGroups);
508
509
			// Is it new?!
510
			if ($context['action_type'] === 'add')
511
			{
512
				$insert = array(
513
					'name' => $this->_req->post->name,
514
					'desc' => $this->_req->post->desc,
515
					'isActive' => $isActive,
516
					'span' => $span,
517
					'cost' => $cost,
518
					'prim_group' => $this->_req->post->prim_group,
519
					'addgroups' => $addGroups,
520
					'isRepeatable' => $isRepeatable,
521
					'allowpartial' => $allowPartial,
522
					'emailComplete' => $emailComplete,
523
					'reminder' => $reminder,
524
				);
525
526
				$sub_id = insertSubscription($insert);
527
			}
528
			// Otherwise must be editing.
529
			else
530
			{
531
				$ignore_active = countActiveSubscriptions($context['sub_id']);
532
533
				$update = array(
534
					'is_active' => $isActive,
535
					'id_group' => empty($this->_req->post->prim_group) ? 0 : $this->_req->post->prim_group,
536
					'repeatable' => $isRepeatable,
537
					'allow_partial' => $allowPartial,
538
					'reminder' => $reminder,
539
					'current_subscription' => $context['sub_id'],
540
					'name' => $this->_req->post->name,
541
					'desc' => $this->_req->post->desc,
542
					'length' => $span,
543
					'cost' => $cost,
544
					'additional_groups' => $addGroups === '' || $addGroups === '0' ? '' : $addGroups,
545
					'email_complete' => $emailComplete,
546
				);
547
548
				updateSubscription($update, $ignore_active);
549
			}
550
551
			call_integration_hook('integrate_save_subscription', array(($context['action_type'] === 'add' ? $sub_id : $context['sub_id']), $this->_req->post->name, $this->_req->post->desc, $isActive, $span, $cost, $this->_req->post->prim_group, $addGroups, $isRepeatable, $allowPartial, $emailComplete, $reminder));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $sub_id does not seem to be defined for all execution paths leading up to this point.
Loading history...
552
553
			redirectexit('action=admin;area=paidsubscribe;view');
554
		}
555
556
		// Defaults.
557
		if ($context['action_type'] === 'add')
558
		{
559
			$context['sub'] = array(
560
				'name' => '',
561
				'desc' => '',
562
				'cost' => array(
563
					'fixed' => 0,
564
				),
565
				'span' => array(
566
					'value' => '',
567
					'unit' => 'D',
568
				),
569
				'prim_group' => 0,
570
				'add_groups' => array(),
571
				'active' => 1,
572
				'repeatable' => 1,
573
				'allow_partial' => 0,
574
				'duration' => 'fixed',
575
				'email_complete' => '',
576
				'reminder' => 0,
577
			);
578
		}
579
		// Otherwise load up all the details.
580
		else
581
		{
582
			$context['sub'] = getSubscriptionDetails($context['sub_id']);
583
584
			// Does this have members who are active?
585
			$context['disable_groups'] = countActiveSubscriptions($context['sub_id']);
586
		}
587
588
		// Load up all the groups.
589
		require_once(SUBSDIR . '/Membergroups.subs.php');
590
		$context['groups'] = getBasicMembergroupData(array('permission'));
591
592
		// This always happens.
593
		createToken($context['action_type'] === 'delete' ? 'admin-pmsd' : 'admin-pms');
594
	}
595
596
	/**
597
	 * Edit or add a user subscription.
598
	 *
599
	 * - Accessed from ?action=admin;area=paidsubscribe;sa=modifyuser
600
	 */
601
	public function action_modifyuser()
602
	{
603
		global $context, $txt, $modSettings;
604
605
		require_once(SUBSDIR . '/PaidSubscriptions.subs.php');
606
		loadSubscriptions();
607
608
		$context['log_id'] = $this->_req->getQuery('lid', 'intval', 0);
609
		$context['sub_id'] = $this->_req->getQuery('sid', 'intval', 0);
610
		$context['action_type'] = $context['log_id'] ? 'edit' : 'add';
611
612
		// Setup the template.
613
		$context['sub_template'] = 'modify_user_subscription';
614
		$context['page_title'] = $txt[$context['action_type'] . '_subscriber'];
615
		loadJavascriptFile('suggest.js', array('defer' => true));
616
617
		// If we haven't been passed the subscription ID get it.
618
		if ($context['log_id'] && !$context['sub_id'])
619
		{
620
			$context['sub_id'] = validateSubscriptionID($context['log_id']);
621
		}
622
623
		if (!isset($context['subscriptions'][$context['sub_id']]))
624
		{
625
			throw new Exception('no_access', false);
626
		}
627
628
		$context['current_subscription'] = $context['subscriptions'][$context['sub_id']];
629
630
		// Searching?
631
		if (isset($this->_req->post->ssearch))
632
		{
633
			return $this->action_viewsub();
634
		}
635
636
		// Saving?
637
		if (isset($this->_req->post->save_sub))
638
		{
639
			checkSession();
640
641
			// Work out the dates...
642
			$starttime = mktime($this->_req->post->hour, $this->_req->post->minute, 0, $this->_req->post->month, $this->_req->post->day, $this->_req->post->year);
643
			$endtime = mktime($this->_req->post->hourend, $this->_req->post->minuteend, 0, $this->_req->post->monthend, $this->_req->post->dayend, $this->_req->post->yearend);
644
645
			// Status.
646
			$status = $this->_req->post->status;
647
648
			// New one?
649
			if (empty($context['log_id']))
650
			{
651
				// Find the user...
652
				require_once(SUBSDIR . '/Members.subs.php');
653
				$member = getMemberByName($this->_req->post->name);
654
655
				if (empty($member))
656
				{
657
					throw new Exception('error_member_not_found');
658
				}
659
660
				if (alreadySubscribed($context['sub_id'], $member['id_member']))
661
				{
662
					throw new Exception('member_already_subscribed');
663
				}
664
665
				// Actually put the subscription in place.
666
				if ($status == 1)
667
				{
668
					addSubscription($context['sub_id'], $member['id_member'], 0, $starttime, $endtime);
669
				}
670
				else
671
				{
672
					$details = array(
673
						'id_subscribe' => $context['sub_id'],
674
						'id_member' => $member['id_member'],
675
						'id_group' => $member['id_group'],
676
						'start_time' => $starttime,
677
						'end_time' => $endtime,
678
						'status' => $status,
679
						'pending_details' => '',
680
					);
681
682
					logSubscription($details);
683
				}
684
			}
685
			// Updating.
686
			else
687
			{
688
				$subscription_status = getSubscriptionStatus($context['log_id']);
689
690
				// Pick the right permission stuff depending on what the status is changing from/to.
691
				if ($subscription_status['old_status'] == 1 && $status != 1)
692
				{
693
					removeSubscription($context['sub_id'], $subscription_status['id_member']);
694
				}
695
				elseif ($status == 1 && $subscription_status['old_status'] != 1)
696
				{
697
					addSubscription($context['sub_id'], $subscription_status['id_member'], 0, $starttime, $endtime);
698
				}
699
				else
700
				{
701
					$item = array(
702
						'start_time' => $starttime,
703
						'end_time' => $endtime,
704
						'status' => $status,
705
						'current_log_item' => $context['log_id']
706
					);
707
					updateSubscriptionItem($item);
708
				}
709
			}
710
711
			// Done - redirect...
712
			redirectexit('action=admin;area=paidsubscribe;sa=viewsub;sid=' . $context['sub_id']);
713
		}
714
		elseif (isset($this->_req->post->delete) || isset($this->_req->post->finished))
715
		{
716
			checkSession();
717
718
			// Do the actual deletes!
719
			if (!empty($this->_req->post->delsub))
720
			{
721
				$toDelete = array();
722
				foreach ($this->_req->post->delsub as $id => $dummy)
723
				{
724
					$toDelete[] = (int) $id;
725
				}
726
727
				$deletes = prepareDeleteSubscriptions($toDelete);
728
729
				foreach ($deletes as $id_subscribe => $id_member)
730
				{
731
					removeSubscription($id_subscribe, $id_member, isset($this->_req->post->delete));
732
				}
733
			}
734
735
			redirectexit('action=admin;area=paidsubscribe;sa=viewsub;sid=' . $context['sub_id']);
736
		}
737
738
		// Default attributes.
739
		if ($context['action_type'] === 'add')
740
		{
741
			$context['sub'] = array(
742
				'id' => 0,
743
				'start' => array(
744
					'year' => (int) Util::strftime('%Y', time()),
745
					'month' => (int) Util::strftime('%m', time()),
746
					'day' => (int) Util::strftime('%d', time()),
747
					'hour' => (int) Util::strftime('%H', time()),
748
					'min' => (int) Util::strftime('%M', time()) < 10 ? '0' . (int) Util::strftime('%M', time()) : (int) Util::strftime('%M', time()),
749
					'last_day' => 0,
750
				),
751
				'end' => array(
752
					'year' => (int) Util::strftime('%Y', time()),
753
					'month' => (int) Util::strftime('%m', time()),
754
					'day' => (int) Util::strftime('%d', time()),
755
					'hour' => (int) Util::strftime('%H', time()),
756
					'min' => (int) Util::strftime('%M', time()) < 10 ? '0' . (int) Util::strftime('%M', time()) : (int) Util::strftime('%M', time()),
757
					'last_day' => 0,
758
				),
759
				'status' => 1,
760
			);
761
			$context['sub']['start']['last_day'] = (int) Util::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']));
762
			$context['sub']['end']['last_day'] = (int) Util::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']));
763
764
			if (isset($this->_req->query->uid))
765
			{
766
				require_once(SUBSDIR . '/Members.subs.php');
767
768
				// Get the latest activated member's display name.
769
				$result = getBasicMemberData((int) $this->_req->query->uid);
770
				$context['sub']['username'] = $result['real_name'];
771
			}
772
			else
773
			{
774
				$context['sub']['username'] = '';
775
			}
776
		}
777
		// Otherwise load the existing info.
778
		else
779
		{
780
			$row = getPendingSubscriptions($context['log_id']);
781
			if (empty($row))
782
			{
783
				throw new Exception('no_access', false);
784
			}
785
786
			// Any pending payments?
787
			$context['pending_payments'] = array();
788
			if (!empty($row['pending_details']))
789
			{
790
				$pending_details = Util::unserialize($row['pending_details']);
791
				foreach ($pending_details as $id => $pending)
792
				{
793
					// Only this type need be displayed.
794
					if ($pending[3] === 'payback')
795
					{
796
						// Work out what the options were.
797
						$costs = Util::unserialize($context['current_subscription']['real_cost']);
798
799
						if ($context['current_subscription']['real_length'] === 'F')
800
						{
801
							foreach ($costs as $duration => $cost)
802
							{
803
								if ($cost == 0)
804
								{
805
									continue;
806
								}
807
808
								if ($cost != $pending[1])
809
								{
810
									continue;
811
								}
812
813
								if ($duration != $pending[2])
814
								{
815
									continue;
816
								}
817
818
								$context['pending_payments'][$id] = array(
819
									'desc' => sprintf($modSettings['paid_currency_symbol'], $cost . '/' . $txt[$duration]),
820
								);
821
							}
822
						}
823
						elseif ($costs['fixed'] == $pending[1])
824
						{
825
							$context['pending_payments'][$id] = array(
826
								'desc' => sprintf($modSettings['paid_currency_symbol'], $costs['fixed']),
827
							);
828
						}
829
					}
830
				}
831
832
				// Check if we are adding/removing any.
833
				if (isset($this->_req->query->pending))
834
				{
835
					foreach ($pending_details as $id => $pending)
836
					{
837
						// Found the one to action?
838
						if ($this->_req->query->pending == $id && $pending[3] === 'payback' && isset($context['pending_payments'][$id]))
839
						{
840
							// Flexible?
841
							if (isset($this->_req->query->accept))
842
							{
843
								addSubscription($context['current_subscription']['id'], $row['id_member'], $context['current_subscription']['real_length'] === 'F' ? strtoupper(substr($pending[2], 0, 1)) : 0);
844
							}
845
846
							unset($pending_details[$id]);
847
848
							$new_details = serialize($pending_details);
849
850
							// Update the entry.
851
							updatePendingSubscription($context['log_id'], $new_details);
852
853
							// Reload
854
							redirectexit('action=admin;area=paidsubscribe;sa=modifyuser;lid=' . $context['log_id']);
855
						}
856
					}
857
				}
858
			}
859
860
			$context['sub_id'] = $row['id_subscribe'];
861
			$context['sub'] = array(
862
				'id' => 0,
863
				'start' => array(
864
					'year' => (int) Util::strftime('%Y', $row['start_time']),
865
					'month' => (int) Util::strftime('%m', $row['start_time']),
866
					'day' => (int) Util::strftime('%d', $row['start_time']),
867
					'hour' => (int) Util::strftime('%H', $row['start_time']),
868
					'min' => (int) Util::strftime('%M', $row['start_time']) < 10 ? '0' . (int) Util::strftime('%M', $row['start_time']) : (int) Util::strftime('%M', $row['start_time']),
869
					'last_day' => 0,
870
				),
871
				'end' => array(
872
					'year' => (int) Util::strftime('%Y', $row['end_time']),
873
					'month' => (int) Util::strftime('%m', $row['end_time']),
874
					'day' => (int) Util::strftime('%d', $row['end_time']),
875
					'hour' => (int) Util::strftime('%H', $row['end_time']),
876
					'min' => (int) Util::strftime('%M', $row['end_time']) < 10 ? '0' . (int) Util::strftime('%M', $row['end_time']) : (int) Util::strftime('%M', $row['end_time']),
877
					'last_day' => 0,
878
				),
879
				'status' => $row['status'],
880
				'username' => $row['username'],
881
			);
882
883
			$context['sub']['start']['last_day'] = (int) Util::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']));
884
			$context['sub']['end']['last_day'] = (int) Util::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']));
885
		}
886
	}
887
888
	/**
889
	 * View all the users subscribed to a particular subscription.
890
	 *
891
	 * What it does:
892
	 *
893
	 * - Requires the admin_forum permission.
894
	 * - Accessed from ?action=admin;area=paidsubscribe;sa=viewsub.
895
	 * - Subscription ID is required, in the form of $_GET['sid'].
896
	 *
897
	 * @event integrate_list_subscribed_users_list
898
	 */
899
	public function action_viewsub()
900
	{
901
		global $context, $txt;
902
903
		require_once(SUBSDIR . '/PaidSubscriptions.subs.php');
904
905
		// Setup the template.
906
		$context['page_title'] = $txt['viewing_users_subscribed'];
907
908
		// ID of the subscription.
909
		$context['sub_id'] = (int) $this->_req->query->sid;
910
911
		// Load the subscription information.
912
		$context['subscription'] = getSubscriptionDetails($context['sub_id']);
913
914
		// Are we searching for people?
915
		$search_string = isset($this->_req->post->ssearch) && !empty($this->_req->post->sub_search) ? ' AND COALESCE(mem.real_name, {string:guest}) LIKE {string:search}' : '';
916
		$search_vars = empty($this->_req->post->sub_search) ? array() : array('search' => '%' . $this->_req->post->sub_search . '%', 'guest' => $txt['guest']);
917
918
		$listOptions = array(
919
			'id' => 'subscribed_users_list',
920
			'title' => sprintf($txt['view_users_subscribed'], $context['subscription']['name']),
921
			'items_per_page' => 20,
922
			'base_href' => getUrl('admin', ['action' => 'admin', 'area' => 'paidsubscribe', 'sa' => 'viewsub', 'sid' => $context['sub_id']]),
923
			'default_sort_col' => 'name',
924
			'get_items' => array(
925
				'function' => fn($start, $items_per_page, $sort, $id_sub, $search_string, $search_vars) => $this->getSubscribedUsers($start, $items_per_page, $sort, $id_sub, $search_string, $search_vars),
926
				'params' => array(
927
					$context['sub_id'],
928
					$search_string,
929
					$search_vars,
930
				),
931
			),
932
			'get_count' => array(
933
				'function' => fn($id_sub, $search_string, $search_vars) => $this->getSubscribedUserCount($id_sub, $search_string, $search_vars),
934
				'params' => array(
935
					$context['sub_id'],
936
					$search_string,
937
					$search_vars,
938
				),
939
			),
940
			'no_items_label' => $txt['no_subscribers'],
941
			'columns' => array(
942
				'name' => array(
943
					'header' => array(
944
						'value' => $txt['who_member'],
945
						'style' => 'width: 20%;',
946
					),
947
					'data' => array(
948
						'function' => static function ($rowData) {
949
							global $txt;
950
							return $rowData['id_member'] == 0 ? $txt['guest'] : '<a href="' . getUrl('profile', ['action' => 'profile', 'u' => $rowData['id_member'], 'name' => $rowData['name']]) . '">' . $rowData['name'] . '</a>';
951
						},
952
					),
953
					'sort' => array(
954
						'default' => 'name',
955
						'reverse' => 'name DESC',
956
					),
957
				),
958
				'status' => array(
959
					'header' => array(
960
						'value' => $txt['paid_status'],
961
						'style' => 'width: 10%;',
962
					),
963
					'data' => array(
964
						'db_htmlsafe' => 'status_text',
965
					),
966
					'sort' => array(
967
						'default' => 'status',
968
						'reverse' => 'status DESC',
969
					),
970
				),
971
				'payments_pending' => array(
972
					'header' => array(
973
						'value' => $txt['paid_payments_pending'],
974
						'style' => 'width: 15%;',
975
					),
976
					'data' => array(
977
						'db_htmlsafe' => 'pending',
978
					),
979
					'sort' => array(
980
						'default' => 'payments_pending',
981
						'reverse' => 'payments_pending DESC',
982
					),
983
				),
984
				'start_time' => array(
985
					'header' => array(
986
						'value' => $txt['start_date'],
987
						'style' => 'width: 20%;',
988
					),
989
					'data' => array(
990
						'db_htmlsafe' => 'start_date',
991
						'class' => 'smalltext',
992
					),
993
					'sort' => array(
994
						'default' => 'start_time',
995
						'reverse' => 'start_time DESC',
996
					),
997
				),
998
				'end_time' => array(
999
					'header' => array(
1000
						'value' => $txt['end_date'],
1001
						'style' => 'width: 20%;',
1002
					),
1003
					'data' => array(
1004
						'db_htmlsafe' => 'end_date',
1005
						'class' => 'smalltext',
1006
					),
1007
					'sort' => array(
1008
						'default' => 'end_time',
1009
						'reverse' => 'end_time DESC',
1010
					),
1011
				),
1012
				'modify' => array(
1013
					'header' => array(
1014
						'style' => 'width: 10%;',
1015
						'class' => 'nowrap',
1016
						'value' => $txt['edit_subscriber'],
1017
					),
1018
					'data' => array(
1019
						'function' => static function ($rowData) {
1020
							global $txt;
1021
							return '<a href="' . getUrl('admin', ['action' => 'admin', 'area' => 'paidsubscribe', 'sa' => '=modifyuser', 'lid' => $rowData['id']]) . '">' . $txt['modify'] . '</a>';
1022
						},
1023
						'class' => 'centertext',
1024
					),
1025
				),
1026
				'delete' => array(
1027
					'header' => array(
1028
						'style' => 'width: 4%;',
1029
						'class' => 'centertext',
1030
					),
1031
					'data' => array(
1032
						'function' => static fn($rowData) => '<input type="checkbox" name="delsub[' . $rowData['id'] . ']" class="input_check" />',
1033
						'class' => 'centertext',
1034
					),
1035
				),
1036
			),
1037
			'form' => array(
1038
				'href' => getUrl('admin', ['action' => 'admin', 'area' => 'paidsubscribe', 'sa' => 'modifyuser', 'sid' => $context['sub_id']]),
1039
			),
1040
			'additional_rows' => array(
1041
				array(
1042
					'position' => 'below_table_data',
1043
					'value' => '
1044
						<input type="submit" name="add" value="' . $txt['add_subscriber'] . '" class="right_submit" />
1045
						<input type="submit" name="finished" value="' . $txt['complete_selected'] . '" onclick="return confirm(\'' . $txt['complete_are_sure'] . '\');" class="right_submit" />
1046
						<input type="submit" name="delete" value="' . $txt['delete_selected'] . '" onclick="return confirm(\'' . $txt['delete_are_sure'] . '\');" class="right_submit" />
1047
					',
1048
				),
1049
				array(
1050
					'position' => 'top_of_list',
1051
					'value' => '
1052
						<div class="flow_auto">
1053
							<input type="submit" name="ssearch" value="' . $txt['search_sub'] . '" class="right_submit" />
1054
							<input type="text" name="sub_search" value="" class="input_text floatright" />
1055
						</div>
1056
					',
1057
				),
1058
			),
1059
		);
1060
1061
		createList($listOptions);
1062
1063
		$context['sub_template'] = 'show_list';
1064
		$context['default_list'] = 'subscribed_users_list';
1065
1066
		return true;
1067
	}
1068
1069
	/**
1070
	 * Returns an array of subscription details and members for a specific subscription
1071
	 *
1072
	 * - Callback for createList()
1073
	 *
1074
	 * @param int $start The item to start with (for pagination purposes)
1075
	 * @param int $items_per_page The number of items to show per page
1076
	 * @param string $sort A string indicating how to sort the results
1077
	 * @param int $id_sub
1078
	 * @param string $search_string
1079
	 * @param array $search_vars
1080
	 *
1081
	 * @return array
1082
	 */
1083
	public function getSubscribedUsers($start, $items_per_page, $sort, $id_sub, $search_string, $search_vars)
1084
	{
1085
		return list_getSubscribedUsers($start, $items_per_page, $sort, $id_sub, $search_string, $search_vars);
1086
	}
1087
1088
	/**
1089
	 * Returns the number of subscribers to a specific subscription in the system
1090
	 *
1091
	 * - Callback for createList()
1092
	 *
1093
	 * @param int $id_sub
1094
	 * @param string $search_string
1095
	 * @param array $search_vars
1096
	 *
1097
	 * @return int
1098
	 */
1099
	public function getSubscribedUserCount($id_sub, $search_string, $search_vars)
1100
	{
1101
		return list_getSubscribedUserCount($id_sub, $search_string, $search_vars);
1102
	}
1103
}
1104