Completed
Pull Request — develop (#26)
by Mario
03:10
created

admin_transactions_controller::get_valid_offset()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 2
eloc 2
nc 2
nop 0
1
<?php
2
/**
3
 *
4
 * PayPal Donation extension for the phpBB Forum Software package.
5
 *
6
 * @copyright (c) 2015 Skouat
7
 * @license GNU General Public License, version 2 (GPL-2.0)
8
 *
9
 */
10
11
namespace skouat\ppde\controller;
12
13
use Symfony\Component\DependencyInjection\ContainerInterface;
14
15
/**
16
 * @property ContainerInterface       container         The phpBB log system
17
 * @property string                   id_prefix_name    Prefix name for identifier in the URL
18
 * @property string                   lang_key_prefix   Prefix for the messages thrown by exceptions
19
 * @property \phpbb\log\log           log               The phpBB log system.
20
 * @property string                   module_name       Name of the module currently used
21
 * @property \phpbb\request\request   request           Request object.
22
 * @property bool                     submit            State of submit $_POST variable
23
 * @property \phpbb\template\template template          Template object
24
 * @property string                   u_action          Action URL
25
 * @property \phpbb\user              user              User object.
26
 */
27
class admin_transactions_controller extends admin_main
28
{
29
	protected $adm_relative_path;
30
	protected $auth;
31
	protected $db;
32
	protected $config;
33
	protected $entry_count;
34
	protected $last_page_offset;
35
	protected $phpbb_admin_path;
36
	protected $phpbb_root_path;
37
	protected $php_ext;
38
	protected $table_ppde_transactions;
39
	public $ppde_operator;
40
41
	/**
42
	 * Constructor
43
	 *
44
	 * @param \phpbb\auth\auth                    $auth                       Authentication object
45
	 * @param \phpbb\db\driver\driver_interface   $db                         Database object
46
	 * @param \phpbb\config\config                $config                     Config object
47
	 * @param ContainerInterface                  $container
48
	 * @param \phpbb\log\log                      $log                        The phpBB log system
49
	 * @param \skouat\ppde\operators\transactions $ppde_operator_transactions Operator object
50
	 * @param \phpbb\request\request              $request                    Request object
51
	 * @param \phpbb\template\template            $template                   Template object
52
	 * @param \phpbb\user                         $user                       User object.
53
	 * @param string                              $adm_relative_path          phpBB admin relative path
54
	 * @param string                              $phpbb_root_path            phpBB root path
55
	 * @param string                              $php_ext                    phpEx
56
	 * @param string                              $table_ppde_transactions    Name of the table used to store data
57
	 *
58
	 * @access public
59
	 */
60
	public function __construct(\phpbb\auth\auth $auth, \phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, ContainerInterface $container, \phpbb\log\log $log, \skouat\ppde\operators\transactions $ppde_operator_transactions, \phpbb\request\request $request, \phpbb\template\template $template, \phpbb\user $user, $adm_relative_path, $phpbb_root_path, $php_ext, $table_ppde_transactions)
61
	{
62
		$this->auth = $auth;
63
		$this->db = $db;
64
		$this->config = $config;
65
		$this->container = $container;
66
		$this->log = $log;
67
		$this->ppde_operator = $ppde_operator_transactions;
68
		$this->request = $request;
69
		$this->template = $template;
70
		$this->user = $user;
71
		$this->adm_relative_path = $adm_relative_path;
72
		$this->phpbb_admin_path = $phpbb_root_path . $adm_relative_path;
73
		$this->phpbb_root_path = $phpbb_root_path;
74
		$this->php_ext = $php_ext;
75
		$this->table_ppde_transactions = $table_ppde_transactions;
76
		parent::__construct(
77
			'transactions',
78
			'PPDE_DT',
79
			'transaction'
80
		);
81
	}
82
83
	/**
84
	 * Display the transactions list
85
	 *
86
	 * @param string $id     Module id
87
	 * @param string $mode   Module categorie
88
	 * @param string $action Action name
89
	 *
90
	 * @return null
91
	 * @access public
92
	 */
93
	public function display_transactions($id, $mode, $action)
94
	{
95
		// Set up general vars
96
		$start = $this->request->variable('start', 0);
97
		$deletemark = $this->request->is_set('delmarked');
98
		$deleteall = $this->request->is_set('delall');
99
		$marked = $this->request->variable('mark', array(0));
100
		// Sort keys
101
		$sort_days = $this->request->variable('st', 0);
102
		$sort_key = $this->request->variable('sk', 't');
103
		$sort_dir = $this->request->variable('sd', 'd');
104
105
		// Initiate an entity
106
		/** @type \skouat\ppde\entity\transactions $entity */
107
		$entity = $this->get_container_entity();
108
109
		// Delete entries if requested and able
110
		if (($deletemark || $deleteall) && $this->auth->acl_get('a_ppde_manage'))
111
		{
112
			if (confirm_box(true))
113
			{
114
				$where_sql = '';
115
116
				if ($deletemark && sizeof($marked))
117
				{
118
					$where_sql = $this->ppde_operator->build_marked_where_sql($marked);
119
				}
120
121
				if ($where_sql || $deleteall)
122
				{
123
					$entity->delete(0, '', $where_sql);
124
125
					$this->config->set('ppde_known_donors_count', $this->sql_query_update_stats('ppde_known_donors_count'), true);
126
					$this->config->set('ppde_anonymous_donors_count', $this->sql_query_update_stats('ppde_anonymous_donors_count'));
127
					$this->config->set('ppde_transactions_count', $this->sql_query_update_stats('ppde_transactions_count'), true);
128
129
					$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_' . $this->lang_key_prefix . '_PURGED', time());
130
				}
131
			}
132
			else
133
			{
134
				confirm_box(false, $this->user->lang['CONFIRM_OPERATION'], build_hidden_fields(array(
135
						'start'     => $start,
136
						'delmarked' => $deletemark,
137
						'delall'    => $deleteall,
138
						'mark'      => $marked,
139
						'st'        => $sort_days,
140
						'sk'        => $sort_key,
141
						'sd'        => $sort_dir,
142
						'i'         => $id,
143
						'mode'      => $mode,
144
						'action'    => $action))
145
				);
146
			}
147
		}
148
149
		$this->do_action($action);
150
151
		if (!$action)
152
		{
153
			/** @type \phpbb\pagination $pagination */
154
			$pagination = $this->container->get('pagination');
155
156
			// Sorting
157
			$limit_days = array(0 => $this->user->lang['ALL_ENTRIES'], 1 => $this->user->lang['1_DAY'], 7 => $this->user->lang['7_DAYS'], 14 => $this->user->lang['2_WEEKS'], 30 => $this->user->lang['1_MONTH'], 90 => $this->user->lang['3_MONTHS'], 180 => $this->user->lang['6_MONTHS'], 365 => $this->user->lang['1_YEAR']);
158
			$sort_by_text = array('txn' => $this->user->lang['PPDE_DT_SORT_TXN_ID'], 'u' => $this->user->lang['PPDE_DT_SORT_DONORS'], 'ipn' => $this->user->lang['PPDE_DT_SORT_IPN_STATUS'], 'ps' => $this->user->lang['PPDE_DT_SORT_PAYMENT_STATUS'], 't' => $this->user->lang['SORT_DATE']);
159
			$sort_by_sql = array('txn' => 'txn.txn_id', 'u' => 'u.username_clean', 'ipn' => 'txn.confirmed', 'ps' => 'txn.payment_status', 't' => 'txn.payment_date');
160
161
			$s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = '';
162
			gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param);
163
164
			// Define where and sort sql for use in displaying transactions
165
			$sql_where = ($sort_days) ? (time() - ($sort_days * 86400)) : 0;
166
			$sql_sort = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC');
167
168
			$keywords = utf8_normalize_nfc($this->request->variable('keywords', '', true));
169
			$keywords_param = !empty($keywords) ? '&amp;keywords=' . urlencode(htmlspecialchars_decode($keywords)) : '';
170
171
			// Grab log data
172
			$log_data = array();
173
			$log_count = 0;
174
175
			$this->view_txn_log($log_data, $log_count, $this->config['topics_per_page'], $start, $sql_where, $sql_sort, $keywords);
176
177
			$base_url = $this->u_action . '&amp;' . $u_sort_param . $keywords_param;
178
			$pagination->generate_template_pagination($base_url, 'pagination', 'start', $log_count, $this->config['topics_per_page'], $start);
179
180
			$this->template->assign_vars(array(
181
				'S_CLEARLOGS'  => $this->auth->acl_get('a_ppde_manage'),
182
				'S_KEYWORDS'   => $keywords,
183
				'S_LIMIT_DAYS' => $s_limit_days,
184
				'S_SORT_KEY'   => $s_sort_key,
185
				'S_SORT_DIR'   => $s_sort_dir,
186
				'S_TXN'        => $mode,
187
188
				'U_ACTION'     => $this->u_action . '&amp;' . $u_sort_param . $keywords_param . '&amp;start=' . $start,
189
			));
190
191
			foreach ($log_data as $row)
192
			{
193
				// Initiate vars to retrieve the 'payment_status' translation from the language key
194
				$payment_status_ary = $this->user->lang['PPDE_DT_PAYMENT_STATUS_VALUES'];
195
				$payment_status_name = strtolower($row['payment_status']);
196
197
				$this->template->assign_block_vars('log', array(
198
					'TNX_ID'           => $row['txn_id'],
199
					'USERNAME'         => $row['username_full'],
200
					'DATE'             => $this->user->format_date($row['payment_date']),
201
					'ID'               => $row['transaction_id'],
202
					'CONFIRMED'        => ($row['confirmed']) ? $this->user->lang['PPDE_DT_VERIFIED'] : $this->user->lang['PPDE_DT_UNVERIFIED'],
203
					'PAYMENT_STATUS'   => $payment_status_ary[$payment_status_name],
204
205
					'S_CONFIRMED'      => ($row['confirmed']) ? false : true,
206
					'S_PAYMENT_STATUS' => ($payment_status_name === 'completed') ? false : true,
207
				));
208
				unset($payment_status_name);
209
			}
210
		}
211
	}
212
213
	/**
214
	 * Do action regarding the value of $action
215
	 *
216
	 * @param $action
217
	 *
218
	 * @return null
219
	 * @access private
220
	 */
221
	private function do_action($action)
222
	{
223
		// Action: view
224
		if ($action == 'view')
225
		{
226
			// Request Identifier of the transaction
227
			$transaction_id = $this->request->variable('id', 0);
228
229
			// Initiate an entity
230
			/** @type \skouat\ppde\entity\currency $entity */
231
			$entity = $this->get_container_entity();
232
233
			// add field username to the table schema needed by entity->import()
234
			$additional_table_schema = array('item_username' => array('name' => 'username', 'type' => 'string'));
235
236
			// Grab transaction data
237
			$data_ary = $entity->get_data($this->ppde_operator->build_sql_data($transaction_id), $additional_table_schema);
238
239
			foreach ($data_ary as $data)
240
			{
241
				// Initiate vars to retrieve the 'payment_status' translation from the language key
242
				$payment_status_ary = $this->user->lang['PPDE_DT_PAYMENT_STATUS_VALUES'];
243
244
				$this->template->assign_vars(array(
245
					'S_CONVERT'      => ($data['settle_amount'] == 0 && empty($data['exchange_rate'])) ? false : true,
246
247
					'TXN_ID'         => $data['txn_id'],
248
249
					'BOARD_USERNAME' => $data['username'],
250
					'NAME'           => $data['first_name'] . ' ' . $data['last_name'],
251
					'PAYER_EMAIL'    => $data['payer_email'],
252
					'PAYER_ID'       => $data['payer_id'],
253
					'PAYER_STATUS'   => ($data['payer_status']) ? $this->user->lang['PPDE_DT_VERIFIED'] : $this->user->lang['PPDE_DT_UNVERIFIED'],
254
255
					'RECEIVER_EMAIL' => $data['receiver_email'],
256
					'RECEIVER_ID'    => $data['receiver_id'],
257
258
					'MC_GROSS'       => $data['mc_gross'] . ' ' . $data['mc_currency'],
259
					'MC_FEE'         => '-' . $data['mc_fee'] . ' ' . $data['mc_currency'],
260
					'MC_NET'         => $data['net_amount'] . ' ' . $data['mc_currency'],
261
262
					'CONVERT_FROM'   => '-' . $data['net_amount'] . ' ' . $data['mc_currency'],
263
					'SETTLE_AMOUNT'  => $data['settle_amount'] . ' ' . $data['settle_currency'],
264
					'EXCHANGE_RATE'  => '1 ' . $data['mc_currency'] . ' = ' . $data['exchange_rate'] . ' ' . $data['settle_currency'],
265
266
					'ITEM_NAME'      => $data['item_name'],
267
					'ITEM_NUMBER'    => $data['item_number'],
268
					'PAYMENT_DATE'   => $this->user->format_date($data['payment_date']),
269
					'PAYMENT_STATUS' => $payment_status_ary[strtolower($data['payment_status'])],
270
				));
271
			}
272
273
			$this->template->assign_vars(array(
274
				'U_ACTION' => $this->u_action,
275
				'U_BACK'   => $this->u_action,
276
277
				'S_VIEW'   => true,
278
			));
279
		}
280
	}
281
282
	/**
283
	 * View log
284
	 *
285
	 * @param array  &$log         The result array with the logs
286
	 * @param mixed  &$log_count   If $log_count is set to false, we will skip counting all entries in the
287
	 *                             database. Otherwise an integer with the number of total matching entries is returned.
288
	 * @param int    $limit        Limit the number of entries that are returned
289
	 * @param int    $offset       Offset when fetching the log entries, f.e. when paginating
290
	 * @param int    $limit_days
291
	 * @param string $sort_by      SQL order option, e.g. 'l.log_time DESC'
292
	 * @param string $keywords     Will only return log entries that have the keywords in log_operation or log_data
293
	 *
294
	 * @return int Returns the offset of the last valid page, if the specified offset was invalid
295
	 *                               (too high)
296
	 * @access private
297
	 */
298
	private function view_txn_log(&$log, &$log_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'txn.payment_date DESC', $keywords = '')
299
	{
300
		$count_logs = ($log_count !== false);
301
302
		$log = $this->get_logs($count_logs, $limit, $offset, $limit_days, $sort_by, $keywords);
303
		$log_count = $this->get_log_count();
304
305
		return $this->get_valid_offset();
306
	}
307
308
	/**
309
	 * @param bool   $count_logs
310
	 * @param int    $limit
311
	 * @param int    $offset
312
	 * @param int    $log_time
313
	 * @param string $sort_by
314
	 * @param string $keywords
315
	 *
316
	 * @return array $log
317
	 * @access private
318
	 */
319
	private function get_logs($count_logs = true, $limit = 0, $offset = 0, $log_time = 0, $sort_by = 'txn.payment_date DESC', $keywords = '')
320
	{
321
		$this->entry_count = 0;
322
		$this->last_page_offset = $offset;
323
		$url_ary = array();
324
325
		if ($this->get_container_entity()->is_in_admin() && $this->phpbb_admin_path)
326
		{
327
			$url_ary['profile_url'] = append_sid($this->phpbb_admin_path . 'index.' . $this->php_ext, 'i=users&amp;mode=overview');
328
			$url_ary['txn_url'] = append_sid($this->phpbb_admin_path . 'index.' . $this->php_ext, 'i=-skouat-ppde-acp-ppde_module&amp;mode=transactions');
329
330
		}
331
		else
332
		{
333
			$url_ary['profile_url'] = append_sid($this->phpbb_root_path . 'memberlist.' . $this->php_ext, 'mode=viewprofile');
334
			$url_ary['txn_url'] = '';
335
		}
336
337
		$get_logs_sql_ary = $this->ppde_operator->get_logs_sql_ary($keywords, $sort_by, $log_time);
338
339
		if ($count_logs)
340
		{
341
			$this->entry_count = $this->ppde_operator->query_sql_count($get_logs_sql_ary, 'txn.transaction_id');
342
343
			if ($this->entry_count == 0)
344
			{
345
				// Save the queries, because there are no logs to display
346
				$this->last_page_offset = 0;
347
348
				return array();
349
			}
350
351
			// Return the user to the last page that is valid
352
			while ($this->last_page_offset >= $this->entry_count)
353
			{
354
				$this->last_page_offset = max(0, $this->last_page_offset - $limit);
355
			}
356
		}
357
358
		return $this->ppde_operator->build_log_ary($get_logs_sql_ary, $url_ary, $limit, $this->last_page_offset);
359
	}
360
361
	/**
362
	 * {@inheritDoc}
363
	 */
364
	public function get_log_count()
365
	{
366
		return ($this->entry_count) ? $this->entry_count : 0;
367
	}
368
369
	/**
370
	 * {@inheritDoc}
371
	 */
372
	public function get_valid_offset()
373
	{
374
		return ($this->last_page_offset) ? $this->last_page_offset : 0;
375
	}
376
377
	/**
378
	 * Returns count result for updating stats
379
	 *
380
	 * @param string $config_name
381
	 *
382
	 * @return int
383
	 * @access public
384
	 */
385
	public function sql_query_update_stats($config_name)
386
	{
387
		if (!$this->config->offsetExists($config_name))
388
		{
389
			trigger_error($this->user->lang('EXCEPTION_INVALID_CONFIG_NAME', $config_name), E_USER_WARNING);
390
		}
391
392
		$this->db->sql_query($this->make_stats_sql_update($config_name));
393
394
		return (int) $this->db->sql_fetchfield('count_result');
395
	}
396
397
	/**
398
	 * Build SQL query for updating stats
399
	 *
400
	 * @param string $type
401
	 *
402
	 * @return string
403
	 * @access private
404
	 */
405
	private function make_stats_sql_update($type)
406
	{
407
		switch ($type)
408
		{
409
			case 'ppde_transactions_count':
410
				$sql = $this->make_stats_sql_select('txn_id');
411
				$sql .= " WHERE confirmed = 1 AND payment_status = 'Completed'";
412
413
				return $sql;
414
			case 'ppde_known_donors_count':
415
				$sql = $this->make_stats_sql_select('payer_id');
416
				$sql .= ' LEFT JOIN ' . USERS_TABLE . ' u
417
				 					ON txn.user_id = u.user_id
418
								WHERE u.user_type = ' . USER_NORMAL . ' OR u.user_type = ' . USER_FOUNDER;
419
420
				return $sql;
421
			case 'ppde_anonymous_donors_count':
422
				$sql = $this->make_stats_sql_select('payer_id');
423
				$sql .= ' WHERE txn.user_id = ' . ANONYMOUS;
424
425
				return $sql;
426
			default:
427
				return $this->make_stats_sql_select('txn_id');
428
		}
429
	}
430
431
	/**
432
	 * Make body of SQL query for stats calculation.
433
	 *
434
	 * @param string $field_name Name of the field
435
	 *
436
	 * @return string
437
	 * @access private
438
	 */
439
	private function make_stats_sql_select($field_name)
440
	{
441
		return 'SELECT COUNT(DISTINCT txn.' . $field_name . ') AS count_result
442
				FROM ' . $this->table_ppde_transactions . ' txn';
443
	}
444
}
445