Completed
Pull Request — master (#52)
by Jakub
09:42
created

admin_controller::error()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
/**
3
 *
4
 * Advertisement management. An extension for the phpBB Forum Software package.
5
 *
6
 * @copyright (c) 2017 phpBB Limited <https://www.phpbb.com>
7
 * @license GNU General Public License, version 2 (GPL-2.0)
8
 *
9
 */
10
11
namespace phpbb\ads\controller;
12
13
/**
14
* Admin controller
15
*/
16
class admin_controller
17
{
18
	const MAX_NAME_LENGTH = 255;
19
	const DATE_FORMAT = 'Y-m-d';
20
	const DEFAULT_PRIORITY = 5;
21
22
	/** @var \phpbb\template\template */
23
	protected $template;
24
25
	/** @var \phpbb\user */
26
	protected $user;
27
28
	/** @var \phpbb\request\request */
29
	protected $request;
30
31
	/** @var \phpbb\ads\ad\manager */
32
	protected $manager;
33
34
	/** @var \phpbb\ads\location\manager */
35
	protected $location_manager;
36
37
	/** @var \phpbb\log\log */
38
	protected $log;
39
40
	/** @var \phpbb\config\db_text */
41
	protected $config_text;
42
43
	/** @var \phpbb\config\config */
44
	protected $config;
45
46
	/** @var \phpbb\files\upload */
47
	protected $files_upload;
48
49
	/** @var string php_ext */
50
	protected $php_ext;
51
52
	/** @var string ext_path */
53
	protected $ext_path;
54
55
	/** @var string Custom form action */
56
	protected $u_action;
57
58
	/** @var array Form validation errors */
59
	protected $errors = array();
60
61
	/**
62
	* Constructor
63
	*
64
	* @param \phpbb\template\template				$template			Template object
65
	* @param \phpbb\user							$user				User object
66
	* @param \phpbb\request\request					$request			Request object
67
	* @param \phpbb\ads\ad\manager					$manager			Advertisement manager object
68
	* @param \phpbb\ads\location\manager			$location_manager	Template location manager object
69
	* @param \phpbb\log\log							$log				The phpBB log system
70
	* @param \phpbb\config\db_text					$config_text		Config text object
71
	* @param \phpbb\config\config					$config				Config object
72
	* @param \phpbb\files\upload					$files_upload		Files upload object
73
	* @param string									$php_ext			PHP extension
74
	* @param string									$ext_path			Path to this extension
75
	*/
76
	public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\request\request $request, \phpbb\ads\ad\manager $manager, \phpbb\ads\location\manager $location_manager, \phpbb\log\log $log, \phpbb\config\db_text $config_text, \phpbb\config\config $config, \phpbb\files\upload $files_upload, $php_ext, $ext_path)
77
	{
78
		$this->template = $template;
79
		$this->user = $user;
80
		$this->request = $request;
81
		$this->manager = $manager;
82
		$this->location_manager = $location_manager;
83
		$this->log = $log;
84
		$this->config_text = $config_text;
85
		$this->config = $config;
86
		$this->files_upload = $files_upload;
87
		$this->php_ext = $php_ext;
88
		$this->ext_path = $ext_path;
89
	}
90
91
	/**
92
	* Process user request for manage mode
93
	*
94
	* @return void
95
	*/
96
	public function mode_manage()
97
	{
98
		$this->setup();
99
100
		// Trigger specific action
101
		$action = $this->request->variable('action', '');
102
		if (in_array($action, array('add', 'edit', 'enable', 'disable', 'delete')))
103
		{
104
			$this->{'action_' . $action}();
105
		}
106
107
		// Otherwise default to this
108
		$this->list_ads();
109
	}
110
111
	/**
112
	* Process user request for settings mode
113
	*
114
	* @return void
115
	*/
116
	public function mode_settings()
117
	{
118
		$this->setup();
119
120
		add_form_key('phpbb/ads/settings');
121
		if ($this->request->is_set_post('submit'))
122
		{
123
			// Validate form key
124
			if (!check_form_key('phpbb/ads/settings'))
125
			{
126
				$this->errors[] = $this->user->lang('FORM_INVALID');
127
			}
128
129
			if (empty($this->errors))
130
			{
131
				$this->config->set('phpbb_ads_adblocker_message', $this->request->variable('adblocker_message', 0));
132
				$this->config->set('phpbb_ads_enable_views', $this->request->variable('enable_views', 0));
133
				$this->config->set('phpbb_ads_enable_clicks', $this->request->variable('enable_clicks', 0));
134
				$this->config_text->set('phpbb_ads_hide_groups', json_encode($this->request->variable('hide_groups', array(0))));
135
136
				$this->success('ACP_AD_SETTINGS_SAVED');
137
			}
138
139
			$this->template->assign_vars(array(
140
				'S_ERROR'		=> (bool) count($this->errors),
141
				'ERROR_MSG'		=> count($this->errors) ? implode('<br />', $this->errors) : '',
142
			));
143
		}
144
145
		$hide_groups = json_decode($this->config_text->get('phpbb_ads_hide_groups'), true);
146
		$groups = $this->manager->load_groups();
147
		foreach ($groups as $group)
148
		{
149
			$group_name = ($group['group_type'] == GROUP_SPECIAL) ? $this->user->lang('G_' . $group['group_name']) : $group['group_name'];
150
151
			$this->template->assign_block_vars('groups', array(
152
				'ID'			=> $group['group_id'],
153
				'NAME'			=> $group_name,
154
				'S_SELECTED'	=> in_array($group['group_id'], $hide_groups),
155
			));
156
		}
157
158
		$this->template->assign_vars(array(
159
			'U_ACTION'			=> $this->u_action,
160
			'ADBLOCKER_MESSAGE'	=> $this->config['phpbb_ads_adblocker_message'],
161
			'ENABLE_VIEWS'		=> $this->config['phpbb_ads_enable_views'],
162
			'ENABLE_CLICKS'		=> $this->config['phpbb_ads_enable_clicks'],
163
		));
164
	}
165
166
	/**
167
	* Set page url
168
	*
169
	* @param string $u_action Custom form action
170
	* @return void
171
	*/
172
	public function set_page_url($u_action)
173
	{
174
		$this->u_action = $u_action;
175
	}
176
177
	/**
178
	* Get ACP page title for Ads module
179
	*
180
	* @return string	Language string for Ads ACP module
181
	*/
182
	public function get_page_title()
183
	{
184
		return $this->user->lang('ACP_PHPBB_ADS_TITLE');
185
	}
186
187
	/**
188
	* Add an advertisement
189
	*
190
	* @return void
191
	*/
192
	public function action_add()
193
	{
194
		$preview = $this->request->is_set_post('preview');
195
		$submit = $this->request->is_set_post('submit');
196
		$upload_banner = $this->request->is_set_post('upload_banner');
197
198
		add_form_key('phpbb/ads/add');
199
		if ($preview || $submit || $upload_banner)
200
		{
201
			$data = $this->get_form_data('phpbb/ads/add');
202
203 View Code Duplication
			if ($preview)
204
			{
205
				$this->ad_preview($data['ad_code']);
206
			}
207
			else if ($upload_banner)
208
			{
209
				$data['ad_code'] = $this->process_banner_upload($data['ad_code']);
210
			}
211
			else if (empty($this->errors))
212
			{
213
				$ad_id = $this->manager->insert_ad($data);
214
				$this->manager->insert_ad_locations($ad_id, $data['ad_locations']);
215
216
				$this->log('ADD', $data['ad_name']);
217
218
				$this->success('ACP_AD_ADD_SUCCESS');
219
			}
220
221
			$this->assign_locations($data);
222
			$this->assign_form_data($data);
223
		}
224
		else
225
		{
226
			$this->assign_locations();
227
		}
228
229
		// Set output vars for display in the template
230
		$this->template->assign_vars(array(
231
			'S_ADD_AD'				=> true,
232
			'U_BACK'				=> $this->u_action,
233
			'U_ACTION'				=> "{$this->u_action}&amp;action=add",
234
			'PICKER_DATE_FORMAT'	=> self::DATE_FORMAT,
235
		));
236
	}
237
238
	/**
239
	* Edit an advertisement
240
	*
241
	* @return void
242
	*/
243
	public function action_edit()
244
	{
245
		$ad_id = $this->request->variable('id', 0);
246
		$preview = $this->request->is_set_post('preview');
247
		$submit = $this->request->is_set_post('submit');
248
		$upload_banner = $this->request->is_set_post('upload_banner');
249
250
		add_form_key('phpbb/ads/edit/' . $ad_id);
251
		if ($preview || $submit || $upload_banner)
252
		{
253
			$data = $this->get_form_data('phpbb/ads/edit/' . $ad_id);
254
255
			if ($preview)
256
			{
257
				$this->ad_preview($data['ad_code']);
258
			}
259 View Code Duplication
			else if ($upload_banner)
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
260
			{
261
				$data['ad_code'] = $this->process_banner_upload($data['ad_code']);
262
			}
263
			else if (empty($this->errors))
264
			{
265
				$success = $this->manager->update_ad($ad_id, $data);
266
267
				if ($success)
268
				{
269
					// Only insert new ad locations to DB when ad exists
270
					$this->manager->delete_ad_locations($ad_id);
271
					$this->manager->insert_ad_locations($ad_id, $data['ad_locations']);
272
273
					$this->log('EDIT', $data['ad_name']);
274
275
					$this->success('ACP_AD_EDIT_SUCCESS');
276
				}
277
				$this->error('ACP_AD_DOES_NOT_EXIST');
278
			}
279
		}
280
		else
281
		{
282
			// Load ad data
283
			$data = $this->manager->get_ad($ad_id);
284
			if (empty($data))
285
			{
286
				$this->error('ACP_AD_DOES_NOT_EXIST');
287
			}
288
289
			// Load ad template locations
290
			$data['ad_locations'] = $this->manager->get_ad_locations($ad_id);
291
		}
292
293
		// Set output vars for display in the template
294
		$this->template->assign_vars(array(
295
			'S_EDIT_AD'				=> true,
296
			'EDIT_ID'				=> $ad_id,
297
			'U_BACK'				=> $this->u_action,
298
			'U_ACTION'				=> "{$this->u_action}&amp;action=edit&amp;id=" . $ad_id,
299
			'PICKER_DATE_FORMAT'	=> self::DATE_FORMAT,
300
		));
301
		$this->assign_locations($data);
302
		$this->assign_form_data($data);
303
	}
304
305
	/**
306
	* Enable an advertisement
307
	*
308
	* @return void
309
	*/
310
	public function action_enable()
311
	{
312
		$this->ad_enable(true);
313
	}
314
315
	/**
316
	* Disable an advertisement
317
	*
318
	* @return void
319
	*/
320
	public function action_disable()
321
	{
322
		$this->ad_enable(false);
323
	}
324
325
	/**
326
	* Delete an advertisement
327
	*
328
	* @return void
329
	*/
330
	public function action_delete()
331
	{
332
		$ad_id = $this->request->variable('id', 0);
333
		if ($ad_id)
334
		{
335
			if (confirm_box(true))
336
			{
337
				// Get ad data so that we can log ad name
338
				$ad_data = $this->manager->get_ad($ad_id);
339
340
				// Delete ad and it's template locations
341
				$this->manager->delete_ad_locations($ad_id);
342
				$success = $this->manager->delete_ad($ad_id);
343
344
				// Only notify user on error or if not ajax
345
				if (!$success)
346
				{
347
					$this->error('ACP_AD_DELETE_ERRORED');
348
				}
349
				else
350
				{
351
					$this->log('DELETE', $ad_data['ad_name']);
352
353
					if (!$this->request->is_ajax())
354
					{
355
						$this->success('ACP_AD_DELETE_SUCCESS');
356
					}
357
				}
358
			}
359
			else
360
			{
361
				confirm_box(false, $this->user->lang('CONFIRM_OPERATION'), build_hidden_fields(array(
362
					'id'		=> $ad_id,
363
					'i'			=> $this->request->variable('i', ''),
364
					'mode'		=> $this->request->variable('mode', ''),
365
					'action'	=> 'delete'
366
				)));
367
			}
368
		}
369
	}
370
371
	/**
372
	* Display the ads
373
	*
374
	* @return void
375
	*/
376
	public function list_ads()
377
	{
378
		foreach ($this->manager->get_all_ads() as $row)
379
		{
380
			$ad_enabled = (int) $row['ad_enabled'];
381
			$ad_end_date = (int) $row['ad_end_date'];
382
			$ad_expired = $ad_end_date > 0 && $ad_end_date < time();
383
			if ($ad_expired && $ad_enabled)
384
			{
385
				$ad_enabled = 0;
386
				$this->manager->update_ad($row['ad_id'], array('ad_enabled' => 0));
387
			}
388
389
			$this->template->assign_block_vars('ads', array(
390
				'NAME'					=> $row['ad_name'],
391
				'END_DATE'				=> $ad_end_date ? $this->user->format_date($ad_end_date, self::DATE_FORMAT) : '',
392
				'VIEWS'					=> $row['ad_views'],
393
				'CLICKS'				=> $row['ad_clicks'],
394
				'VIEWS_LIMIT'			=> $row['ad_views_limit'],
395
				'CLICKS_LIMIT'			=> $row['ad_clicks_limit'],
396
				'S_END_DATE_EXPIRED'	=> $ad_expired,
397
				'S_ENABLED'				=> $ad_enabled,
398
				'U_ENABLE'				=> $this->u_action . '&amp;action=' . ($ad_enabled ? 'disable' : 'enable') . '&amp;id=' . $row['ad_id'],
399
				'U_EDIT'				=> $this->u_action . '&amp;action=edit&amp;id=' . $row['ad_id'],
400
				'U_DELETE'				=> $this->u_action . '&amp;action=delete&amp;id=' . $row['ad_id'],
401
			));
402
		}
403
404
		// Set output vars for display in the template
405
		$this->template->assign_vars(array(
406
			'U_ACTION_ADD'		=> $this->u_action . '&amp;action=add',
407
			'S_VIEWS_ENABLED'	=> $this->config['phpbb_ads_enable_views'],
408
			'S_CLICKS_ENABLED'	=> $this->config['phpbb_ads_enable_clicks'],
409
		));
410
	}
411
412
	/**
413
	* Perform general tasks
414
	*
415
	* @return void
416
	*/
417
	protected function setup()
418
	{
419
		$this->user->add_lang('posting'); // Used by process_banner_upload() file errors
420
		$this->user->add_lang_ext('phpbb/ads', 'acp');
421
422
		$this->template->assign_var('S_PHPBB_ADS', true);
423
	}
424
425
	/**
426
	* Enable/disable an advertisement
427
	*
428
	* @param	bool	$enable	Enable or disable the advertisement?
429
	* @return void
430
	*/
431
	protected function ad_enable($enable)
432
	{
433
		$ad_id = $this->request->variable('id', 0);
434
435
		$success = $this->manager->update_ad($ad_id, array(
436
			'ad_enabled'	=> (int) $enable,
437
		));
438
439
		// If AJAX was used, show user a result message
440
		if ($this->request->is_ajax())
441
		{
442
			$json_response = new \phpbb\json_response;
443
			$json_response->send(array(
444
				'text'	=> $this->user->lang($enable ? 'ENABLED' : 'DISABLED'),
445
				'title'	=> $this->user->lang('AD_ENABLE_TITLE', (int) $enable),
446
			));
447
		}
448
449
		// Otherwise, show traditional infobox
450
		if ($success)
451
		{
452
			$this->success($enable ? 'ACP_AD_ENABLE_SUCCESS' : 'ACP_AD_DISABLE_SUCCESS');
453
		}
454
		else
455
		{
456
			$this->error($enable ? 'ACP_AD_ENABLE_ERRORED' : 'ACP_AD_DISABLE_ERRORED');
457
		}
458
	}
459
460
	/**
461
	 * Upload image and return updated ad code or <img> of new banner when using ajax.
462
	 *
463
	 * @param	 string	 $ad_code	 Current ad code
464
	 * @return	 mixed	 JsonResponse when request is ajax or updated ad code otherwise.
465
	 */
466
	protected function process_banner_upload($ad_code)
467
	{
468
		// Set file restrictions
469
		$this->files_upload->reset_vars();
470
		$this->files_upload->set_allowed_extensions(array('gif', 'jpg', 'jpeg', 'png'));
471
472
		// Upload file
473
		$file = $this->files_upload->handle_upload('files.types.form', 'banner');
474
		$file->clean_filename('unique_ext');
475
		$file->move_file('images/phpbb_ads');
476
477
		// Problem with uploading
478
		if (sizeof($file->error))
479
		{
480
			$file->remove();
481
			if ($this->request->is_ajax())
482
			{
483
				$json_response = new \phpbb\json_response;
484
				$json_response->send(array(
485
					'success'	=> false,
486
					'title'		=> $this->user->lang('INFORMATION'),
487
					'text'		=> implode(',', $file->error),
488
				));
489
			}
490
			else
491
			{
492
				$this->errors[] = implode(',', $file->error);
493
			}
494
		}
495
		else
496
		{
497
			$banner_html = '<img src="' . generate_board_url() . '/images/phpbb_ads/' . $file->get('realname') . '" />';
498
499
			if ($this->request->is_ajax())
500
			{
501
				$json_response = new \phpbb\json_response;
502
				$json_response->send(array(
503
					'success'	=> true,
504
					'text'		=> $banner_html,
505
				));
506
			}
507
508
			return $ad_code . "\n\n" . $banner_html;
509
		}
510
511
		return $ad_code;
512
	}
513
514
	/**
515
	* Get admin form data.
516
	*
517
	* @param	string	$form_name	The form name.
518
	* @return	array	Form data
519
	*/
520
	protected function get_form_data($form_name)
521
	{
522
		$data = array(
523
			'ad_name'			=> $this->request->variable('ad_name', '', true),
524
			'ad_note'			=> $this->request->variable('ad_note', '', true),
525
			'ad_code'			=> $this->request->variable('ad_code', '', true),
526
			'ad_enabled'		=> $this->request->variable('ad_enabled', 0),
527
			'ad_locations'		=> $this->request->variable('ad_locations', array('')),
528
			'ad_end_date'		=> $this->request->variable('ad_end_date', ''),
529
			'ad_priority'		=> $this->request->variable('ad_priority', self::DEFAULT_PRIORITY),
530
			'ad_views_limit'	=> $this->request->variable('ad_views_limit', 0),
531
			'ad_clicks_limit'	=> $this->request->variable('ad_clicks_limit', 0),
532
		);
533
534
		// Validate form key
535
		if (!check_form_key($form_name))
536
		{
537
			$this->errors[] = $this->user->lang('FORM_INVALID');
538
		}
539
540
		// Validate ad name
541
		if ($data['ad_name'] === '')
542
		{
543
			$this->errors[] = $this->user->lang('AD_NAME_REQUIRED');
544
		}
545
		if (truncate_string($data['ad_name'], self::MAX_NAME_LENGTH) !== $data['ad_name'])
546
		{
547
			$this->errors[] = $this->user->lang('AD_NAME_TOO_LONG', self::MAX_NAME_LENGTH);
548
		}
549
550
		// Validate ad end date
551
		if (preg_match('#^\d{4}\-\d{2}\-\d{2}$#', $data['ad_end_date']))
552
		{
553
			$data['ad_end_date'] = (int) $this->user->get_timestamp_from_format(self::DATE_FORMAT, $data['ad_end_date']);
554
555
			if ($data['ad_end_date'] < time())
556
			{
557
				$this->errors[] = $this->user->lang('AD_END_DATE_INVALID');
558
			}
559
		}
560
		else if ($data['ad_end_date'] !== '')
561
		{
562
			$this->errors[] = $this->user->lang('AD_END_DATE_INVALID');
563
		}
564
		else
565
		{
566
			$data['ad_end_date'] = 0;
567
		}
568
569
		// Validate ad priority
570
		if ($data['ad_priority'] < 1 || $data['ad_priority'] > 10)
571
		{
572
			$this->errors[] = $this->user->lang('AD_PRIORITY_INVALID');
573
		}
574
575
		// Validate ad views limit
576
		if ($data['ad_views_limit'] < 0)
577
		{
578
			$this->errors[] = $this->user->lang('AD_VIEWS_LIMIT_INVALID');
579
		}
580
581
		// Validate ad clicks limit
582
		if ($data['ad_clicks_limit'] < 0)
583
		{
584
			$this->errors[] = $this->user->lang('AD_CLICKS_LIMIT_INVALID');
585
		}
586
587
		return $data;
588
	}
589
590
	/**
591
	* Assign form data to the template.
592
	*
593
	* @param	array	$data	The form data.
594
	* @return void
595
	*/
596
	protected function assign_form_data($data)
597
	{
598
		$this->template->assign_vars(array(
599
			'S_ERROR'		=> (bool) count($this->errors),
600
			'ERROR_MSG'		=> count($this->errors) ? implode('<br />', $this->errors) : '',
601
602
			'AD_NAME'			=> $data['ad_name'],
603
			'AD_NOTE'			=> $data['ad_note'],
604
			'AD_CODE'			=> $data['ad_code'],
605
			'AD_ENABLED'		=> $data['ad_enabled'],
606
			'AD_END_DATE'		=> $this->prepare_end_date($data['ad_end_date']),
607
			'AD_PRIORITY'		=> $data['ad_priority'],
608
			'AD_VIEWS_LIMIT'	=> $data['ad_views_limit'],
609
			'AD_CLICKS_LIMIT'	=> $data['ad_clicks_limit'],
610
		));
611
	}
612
613
	/**
614
	* Prepare end date for display
615
	*
616
	* @param	mixed	$end_date	End date.
617
	* @return	string	End date prepared for display.
618
	*/
619
	protected function prepare_end_date($end_date)
620
	{
621
		if (empty($end_date))
622
		{
623
			return '';
624
		}
625
626
		if (is_numeric($end_date))
627
		{
628
			return $this->user->format_date($end_date, self::DATE_FORMAT);
629
		}
630
631
		return (string) $end_date;
632
	}
633
634
	/**
635
	* Assign template locations data to the template.
636
	*
637
	* @param	mixed	$data	The form data or nothing.
638
	* @return	void
639
	*/
640
	protected function assign_locations($data = false)
641
	{
642
		foreach ($this->location_manager->get_all_locations() as $location_id => $location_data)
643
		{
644
			$this->template->assign_block_vars('ad_locations', array(
645
				'LOCATION_ID'	=> $location_id,
646
				'LOCATION_DESC'	=> $location_data['desc'],
647
				'LOCATION_NAME'	=> $location_data['name'],
648
				'S_SELECTED'	=> $data ? in_array($location_id, $data['ad_locations']) : false,
649
			));
650
		}
651
	}
652
653
	/**
654
	* Prepare advertisement preview
655
	*
656
	* @param	string	$code	Ad code to preview
657
	* @return	void
658
	*/
659
	protected function ad_preview($code)
660
	{
661
		$this->template->assign_var('PREVIEW', htmlspecialchars_decode($code));
662
	}
663
664
	/**
665
	* Print success message.
666
	*
667
	* It takes arguments in the form of a language key, followed by language substitution values.
668
	*/
669
	protected function success()
670
	{
671
		trigger_error(call_user_func_array(array($this->user, 'lang'), func_get_args()) . adm_back_link($this->u_action));
672
	}
673
674
	/**
675
	* Print error message.
676
	*
677
	* It takes arguments in the form of a language key, followed by language substitution values.
678
	*/
679
	protected function error()
680
	{
681
		trigger_error(call_user_func_array(array($this->user, 'lang'), func_get_args()) . adm_back_link($this->u_action), E_USER_WARNING);
682
	}
683
684
	/**
685
	* Log action
686
	*
687
	* @param	string	$action		Performed action in uppercase
688
	* @param	string	$ad_name	Advertisement name
689
	* @return	void
690
	*/
691
	protected function log($action, $ad_name)
692
	{
693
		$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'ACP_PHPBB_ADS_' . $action . '_LOG', time(), array($ad_name));
694
	}
695
}
696