Ajout d'une extension

This commit is contained in:
Gauvain Boiché
2020-04-04 18:27:27 +02:00
parent c3ed8cc1c1
commit 3a964fe237
387 changed files with 58921 additions and 0 deletions

View File

@@ -0,0 +1,295 @@
<?php
/**
*
* phpBB Studio - Advanced Shop System. An extension for the phpBB Forum Software package.
*
* @copyright (c) 2019, phpBB Studio, https://www.phpbbstudio.com
* @license GNU General Public License, version 2 (GPL-2.0)
*
*/
namespace phpbbstudio\ass\controller;
use phpbb\exception\runtime_exception;
/**
* phpBB Studio - Advanced Shop System: ACP Files controller
*/
class acp_files_controller
{
/** @var \phpbb\cache\driver\driver_interface */
protected $cache;
/** @var \phpbb\config\config */
protected $config;
/** @var \phpbbstudio\ass\helper\files */
protected $files;
/** @var \phpbb\language\language */
protected $language;
/** @var \phpbb\request\request */
protected $request;
/** @var \phpbb\template\template */
protected $template;
/** @var \phpbb\user */
protected $user;
/** @var string Custom form action */
protected $u_action;
/**
* Constructor.
*
* @param \phpbb\cache\driver\driver_interface $cache Cache driver object
* @param \phpbb\config\config $config Config object
* @param \phpbbstudio\ass\helper\files $files Files object
* @param \phpbb\language\language $language Language object
* @param \phpbb\request\request $request Request object
* @param \phpbb\template\template $template Template object
* @param \phpbb\user $user User object
* @return void
* @access public
*/
public function __construct(
\phpbb\cache\driver\driver_interface $cache,
\phpbb\config\config $config,
\phpbbstudio\ass\helper\files $files,
\phpbb\language\language $language,
\phpbb\request\request $request,
\phpbb\template\template $template,
\phpbb\user $user
)
{
$this->cache = $cache;
$this->config = $config;
$this->files = $files;
$this->language = $language;
$this->request = $request;
$this->template = $template;
$this->user = $user;
}
/**
* Handle and display the "Files" ACP mode.
*
* @return void
* @access public
*/
public function files()
{
$this->language->add_lang(['ass_acp_files', 'ass_acp_common', 'ass_common'], 'phpbbstudio/ass');
$this->language->add_lang('posting');
$mode = $this->request->variable('m', '', true);
$action = $this->request->variable('action', '', true);
$directory = $this->request->variable('dir', '', true);
$item_file = $this->request->variable('file', '', true);
$item_img = $this->request->variable('image', '', true);
$img_input = $this->request->variable('input', '', true);
$s_item_img = $this->request->is_set('image');
$img_value = $item_img ? $item_img : ($s_item_img ? true : '');
switch ($mode)
{
case 'images':
case 'files':
$this->files->set_mode($mode);
$json_response = new \phpbb\json_response;
$form_key = 'ass_files';
add_form_key($form_key);
switch ($action)
{
case 'add_dir':
if (!check_form_key($form_key))
{
trigger_error($this->language->lang('FORM_INVALID') . adm_back_link($this->get_file_action($mode, $directory), E_USER_WARNING));
}
$folder = $this->request->variable('folder', '', true);
$refresh = str_replace('&amp;', '&', $this->get_file_action($mode, $directory));
try
{
$this->files->add($directory, $folder);
}
catch (runtime_exception $e)
{
trigger_error($this->language->lang_array($e->getMessage(), array_merge([$this->language->lang('ASS_FOLDER')], $e->get_parameters())) . adm_back_link($refresh), E_USER_WARNING);
}
if ($this->config['ass_purge_cache'])
{
$this->cache->purge();
}
if ($this->request->is_ajax())
{
$json_response->send(['REFRESH_DATA' => ['url' => $refresh, 'time' => 0]]);
}
redirect($refresh);
break;
case 'add_file':
if (!check_form_key($form_key))
{
trigger_error($this->language->lang('FORM_INVALID') . adm_back_link($this->get_file_action($mode, $directory)), E_USER_WARNING);
}
$refresh = str_replace('&amp;', '&', $this->get_file_action($mode, $directory));
try
{
$this->files->upload($directory, 'file');
}
catch (runtime_exception $e)
{
trigger_error($this->language->lang_array($e->getMessage(), array_merge([$this->language->lang('ASS_FILENAME')], $e->get_parameters())) . adm_back_link($refresh), E_USER_WARNING);
}
if ($this->config['ass_purge_cache'])
{
$this->cache->purge();
}
redirect($refresh);
break;
case 'delete_dir':
case 'delete_file':
$type = $action === 'delete_dir' ? 'FOLDER' : 'FILE';
if (confirm_box(true))
{
$this->files->delete($directory);
if ($this->config['ass_purge_cache'])
{
$this->cache->purge();
}
trigger_error("ASS_{$type}_DELETE_SUCCESS");
}
else
{
confirm_box(false, "ASS_{$type}_DELETE", '');
}
break;
case 'select_file':
if (($item_img || $item_file) && !$this->request->is_set('dir'))
{
$directory = pathinfo($item_img, PATHINFO_DIRNAME);
$directory = $directory === '.' ? '' : $directory;
}
$this->template->assign_vars([
'S_FILE_SELECT' => $s_item_img ? $img_input : 'file',
]);
break;
}
$files = $this->files->view($directory);
foreach ($files['folders'] as $folder)
{
$file_time = $this->files->get_file_time($directory, $folder);
$this->template->assign_block_vars('ass_folders', [
'NAME' => $folder,
'TIME' => $file_time ? $this->user->format_date($file_time) : '',
'U_DELETE' => $this->get_file_action($mode, ($directory ? $directory . '%2F' : '') . $folder, 'delete_dir'),
'U_VIEW' => $this->get_file_action($mode, ($directory ? $directory . '%2F' : '') . $folder, $action, $img_value, $item_file, $img_input),
]);
}
foreach ($files['files'] as $file)
{
$dir_file = $directory ? $directory . '/' . $file : $file;
$file_size = $this->files->get_file_size($directory, $file);
$file_time = $this->files->get_file_time($directory, $file);
$this->template->assign_block_vars('ass_files', [
'NAME' => $file,
'ICON' => $this->files->get_file_icon($file),
'IMG' => $this->files->get_path($directory, true, $file),
'SIZE' => $file_size ? get_formatted_filesize($file_size) : '',
'TIME' => $file_time ? $this->user->format_date($file_time) : '',
'VALUE' => $dir_file,
'S_SELECTED' => $s_item_img ? $dir_file === $item_img : $dir_file === $item_file,
'U_DELETE' => $this->get_file_action($mode, ($directory ? $directory . '%2F' : '') . $file, 'delete_file'),
]);
}
$directories = array_filter(explode('/', $directory));
$this->template->assign_vars([
'DIRECTORIES' => $directories,
'S_FILE_MODE' => $mode,
'U_ACTION' => $this->get_file_action($mode, '', $action, $img_value, $item_file, $img_input),
'U_ACTION_FORM' => $this->get_file_action($mode, implode('%2F', $directories), $action),
'U_BACK' => $this->u_action,
]);
break;
default:
$this->template->assign_vars([
'ALLOWED_EXTS' => $mode === 'images' ? implode(',', $this->files->get_extensions()) : '',
'S_FILE_INDEX' => true,
'U_FILE_FILES' => $this->get_file_action('files'),
'U_FILE_IMAGES' => $this->get_file_action('images'),
]);
break;
}
}
/**
* Get a custom form action for the "files" mode.
*
* @param string $mode The file mode (images|files)
* @param string $directory The file directory
* @param string $action The action
* @param string $image The image name
* @param string $file The file name
* @param string $input The input field name
* @return string The custom form action
* @access protected
*/
protected function get_file_action($mode, $directory = '', $action = '', $image = '', $file = '', $input = '')
{
$mode = $mode ? "&m={$mode}" : '';
$action = $action ? "&action={$action}" : '';
$directory = $directory ? "&dir={$directory}" : '';
$file = $file ? "&file={$file}" : '';
$input = $input ? "&input={$input}" : '';
$image = $image === true ? '&image=' : ($image ? "&image={$image}" : '');
return "{$this->u_action}{$mode}{$directory}{$action}{$image}{$file}{$input}";
}
/**
* Set custom form action.
*
* @param string $u_action Custom form action
* @return self $this This controller for chaining calls
* @access public
*/
public function set_page_url($u_action)
{
$this->u_action = $u_action;
return $this;
}
}

View File

@@ -0,0 +1,604 @@
<?php
/**
*
* phpBB Studio - Advanced Shop System. An extension for the phpBB Forum Software package.
*
* @copyright (c) 2019, phpBB Studio, https://www.phpbbstudio.com
* @license GNU General Public License, version 2 (GPL-2.0)
*
*/
namespace phpbbstudio\ass\controller;
use phpbbstudio\ass\entity\item;
use phpbbstudio\ass\entity\category;
/**
* phpBB Studio - Advanced Shop System: ACP Inventory controller
*/
class acp_inventory_controller
{
/** @var \phpbb\db\driver\driver_interface */
protected $db;
/** @var \phpbb\group\helper */
protected $group_helper;
/** @var \phpbb\language\language */
protected $language;
/** @var \phpbb\log\log */
protected $log;
/** @var \phpbbstudio\ass\notification\notification */
protected $notification;
/** @var \phpbbstudio\ass\operator\category */
protected $operator_cat;
/** @var \phpbbstudio\ass\operator\item */
protected $operator_item;
/** @var \phpbb\request\request */
protected $request;
/** @var \phpbb\template\template */
protected $template;
/** @var \phpbb\user */
protected $user;
/** @var string Groups table */
protected $groups_table;
/** @var string Users table */
protected $users_table;
/** @var string Usergroup table */
protected $user_group_table;
/** @var string Inventory table */
protected $inventory_table;
/** @var string phpBB root path */
protected $root_path;
/** @var string php File extension */
protected $php_ext;
/** @var string Custom form action */
protected $u_action;
public function __construct(
\phpbb\db\driver\driver_interface $db,
\phpbb\group\helper $group_helper,
\phpbb\language\language $language,
\phpbb\log\log $log,
\phpbbstudio\ass\notification\notification $notification,
\phpbbstudio\ass\operator\category $operator_cat,
\phpbbstudio\ass\operator\item $operator_item,
\phpbb\request\request $request,
\phpbb\template\template $template,
\phpbb\user $user,
$groups_table,
$users_table,
$user_group_table,
$inventory_table,
$root_path,
$php_ext
)
{
$this->db = $db;
$this->group_helper = $group_helper;
$this->language = $language;
$this->log = $log;
$this->notification = $notification;
$this->operator_cat = $operator_cat;
$this->operator_item = $operator_item;
$this->request = $request;
$this->template = $template;
$this->user = $user;
$this->groups_table = $groups_table;
$this->users_table = $users_table;
$this->user_group_table = $user_group_table;
$this->inventory_table = $inventory_table;
$this->root_path = $root_path;
$this->php_ext = $php_ext;
}
/**
* Handle and display the "Inventory" ACP mode.
*
* @return void
* @access public
*/
public function inventory()
{
$this->language->add_lang(['ass_acp_common', 'ass_common'], 'phpbbstudio/ass');
$type = $this->request->variable('type', '', true);
$submit = $this->request->is_set_post('submit');
$errors = [];
$form_key = 'ass_inventory';
add_form_key($form_key);
switch ($type)
{
case 'global';
$action = $this->request->variable('action', 'add', true);
$item_ids = $this->request->variable('items', [0]);
$group_ids = $this->request->variable('groups', [0]);
$usernames = $this->request->variable('usernames', '', true);
$items = [];
/** @var category $category */
foreach ($this->operator_cat->get_categories() as $category)
{
$this->template->assign_block_vars('categories', array_merge([
'S_INACTIVE' => !$category->get_active(),
], $this->operator_cat->get_variables($category)));
$items += $category_items = $this->operator_item->get_items($category->get_id());
/** @var item $item */
foreach ($category_items as $item)
{
$this->template->assign_block_vars('categories.items', array_merge([
'S_INACTIVE' => !$item->get_active(),
'S_SELECTED' => in_array($item->get_id(), $item_ids),
], $this->operator_item->get_variables($item)));
}
}
if ($submit)
{
if (!check_form_key($form_key))
{
$errors[] = 'FORM_INVALID';
}
if (!in_array($action, ['add', 'delete']))
{
$errors[] = 'NO_ACTION';
}
if (empty($item_ids))
{
$errors[] = 'ACP_ASS_NO_ITEMS_SELECTED';
}
$user_ids = [];
$usernames_array = array_filter(explode("\n", $usernames));
if (empty($usernames_array) && empty($group_ids))
{
$this->language->add_lang('acp/permissions');
$errors[] = 'NO_USER_GROUP_SELECTED';
}
if (!empty($usernames_array))
{
$this->get_ids_from_usernames($usernames_array, $user_ids, $errors);
}
if (!empty($group_ids))
{
$this->get_ids_from_groups($group_ids, $user_ids);
}
if (empty($errors) && empty($user_ids))
{
$errors[] = 'NO_GROUP_MEMBERS';
}
if (empty($errors))
{
$user_ids = array_unique($user_ids);
$this->update_inventory($action, $user_ids, $item_ids);
$count_items = count($item_ids);
$count_users = count($user_ids);
$item_names = [];
foreach ($item_ids as $item_id)
{
$item_names[] = $items[$item_id]->get_title();
}
$l_action = 'ACP_ASS_INVENTORY_' . utf8_strtoupper($action);
$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, "LOG_{$l_action}", time(), [$count_items, implode(', ', $item_names), $count_users, implode(', ', $usernames_array)]);
$message = $this->language->lang("{$l_action}_SUCCESS", $count_items);
$message .= '<br>&raquo; ' . $this->language->lang('ACP_ASS_AMOUNT_ITEMS') . $this->language->lang('COLON') . ' ' . $count_items;
$message .= '<br>&raquo; ' . $this->language->lang('ACP_ASS_AMOUNT_USERS') . $this->language->lang('COLON') . ' ' . $count_users;
$message .= adm_back_link($this->u_action);
trigger_error($message);
}
}
$sql = 'SELECT group_id, group_name, group_type
FROM ' . $this->groups_table . "
WHERE group_name <> 'BOTS'
AND group_name <> 'GUESTS'
ORDER BY group_type DESC, group_name ASC";
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
$this->template->assign_block_vars('groups', [
'ID' => (int) $row['group_id'],
'NAME' => $this->group_helper->get_name($row['group_name']),
'S_SELECTED' => in_array((int) $row['group_id'], $group_ids),
'S_SPECIAL' => GROUP_SPECIAL === (int) $row['group_type'],
]);
}
$this->db->sql_freeresult($result);
$this->template->assign_vars([
'USERNAMES' => $usernames,
'S_ADD' => $action === 'add',
'U_FIND_USER' => append_sid("{$this->root_path}memberlist.{$this->php_ext}", [
'mode' => 'searchuser',
'form' => 'ass_inventory',
'field' => 'usernames',
]),
]);
break;
case 'manage':
$action = $this->request->variable('action', '', true);
$username = $this->request->variable('username', '', true);
$user_id = $this->request->variable('u', 0);
$item_ids = $this->request->variable('items', [0]);
if (empty($username) && empty($user_id))
{
$this->template->assign_var('U_FIND_USER', append_sid("{$this->root_path}memberlist.{$this->php_ext}", [
'mode' => 'searchuser',
'form' => 'ass_inventory',
'field' => 'username',
'select_single' => true,
]));
}
else
{
if (empty($user_id))
{
$user_ids = [];
$this->get_ids_from_usernames([$username], $user_ids, $errors);
if (empty($user_ids))
{
trigger_error($this->language->lang('NO_USER') . adm_back_link($this->u_action . "&type={$type}"), E_USER_WARNING);
}
$user_id = (int) reset($user_ids);
}
$rowset = [];
$sql = 'SELECT i.*, u.username as gifter_name, u.user_colour as gifter_colour
FROM ' . $this->inventory_table . ' i
LEFT JOIN ' . $this->users_table . ' u
ON i.gifter_id = u.user_id
WHERE i.user_id = ' . (int) $user_id;
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
$rowset[(int) $row['item_id']] = $row;
}
$this->db->sql_freeresult($result);
$inventory = [
'categories' => array_column($rowset, 'category_id'),
'items' => array_keys($rowset),
];
$items = [];
$categories = $this->operator_cat->get_categories();
/** @var category $category */
foreach ($categories as $category)
{
$this->template->assign_block_vars('categories', array_merge([
'S_INACTIVE' => !$category->get_active(),
'S_INVENTORY' => in_array($category->get_id(), $inventory['categories']),
], $this->operator_cat->get_variables($category)));
$items += $category_items = $this->operator_item->get_items($category->get_id());
/** @var item $item */
foreach ($category_items as $item)
{
$variables = array_merge([
'S_INACTIVE' => !$item->get_active(),
'S_INVENTORY' => in_array($item->get_id(), $inventory['items']),
'S_SELECTED' => in_array($item->get_id(), $item_ids),
], $this->operator_item->get_variables($item));
if ($variables['S_INVENTORY'])
{
$row = $rowset[$item->get_id()];
$variables = array_merge($variables, [
'GIFTER' => $row['gifter_id'] ? get_username_string('full', $row['gifter_id'], $row['gifter_name'], $row['gifter_colour']) : '',
'PURCHASE_TIME' => $this->user->format_date($row['purchase_time']),
'USE_TIME' => $row['use_time'] ? $this->user->format_date($row['use_time']) : $this->language->lang('NEVER'),
'USE_COUNT' => (int) $row['use_count'],
]);
}
$this->template->assign_block_vars('categories.items', $variables);
}
}
$u_back = $this->u_action . "&type={$type}&u={$user_id}";
if ($action === 'delete')
{
$item_id = $this->request->variable('iid', 0);
if (confirm_box(true))
{
$this->update_inventory($action, [$user_id], [$item_id]);
if (empty($username))
{
$username = $this->get_username($user_id);
}
$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_ACP_ASS_INVENTORY_DELETE_USER', time(), [$items[$item_id]->get_title(), $username]);
trigger_error($this->language->lang('ASS_DELETE_SUCCESS') . adm_back_link($u_back));
}
else
{
confirm_box(false, 'ASS_DELETE', '');
redirect($u_back);
}
}
if ($submit)
{
if (!check_form_key($form_key))
{
$errors[] = 'FORM_INVALID';
}
if (empty($item_ids))
{
$errors[] = 'ACP_ASS_NO_ITEMS_SELECTED';
}
if (empty($errors))
{
$this->update_inventory('add', [$user_id], $item_ids);
if (empty($username))
{
$username = $this->get_username($user_id);
}
$count_items = count($item_ids);
$item_names = [];
foreach ($item_ids as $item_id)
{
$item_names[] = $items[$item_id]->get_title();
}
$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_ACP_ASS_INVENTORY_ADD_USER', time(), [$count_items, implode(', ', $item_names), $username]);
trigger_error($this->language->lang('ACP_ASS_INVENTORY_ADD_SUCCESS', $count_items) . adm_back_link($u_back));
}
}
$this->template->assign_vars([
'ASS_USERNAME' => $username,
'U_DELETE' => $this->u_action . "&type={$type}&u={$user_id}&action=delete&iid=",
]);
}
break;
default:
$this->template->assign_vars([
'U_GLOBAL' => $this->u_action . '&amp;type=global',
'U_MANAGE' => $this->u_action . '&amp;type=manage',
]);
break;
}
$this->template->assign_vars([
'ERRORS' => $errors,
'S_TYPE' => $type,
'U_ACTION' => $this->u_action . ($type ? "&type={$type}" : ''),
'U_BACK' => $this->u_action,
]);
}
/**
* Update users' inventories.
*
* @param string $action The action to perform (add|delete)
* @param array $user_ids The user identifiers
* @param array $item_ids The item identifiers
* @return void
* @access protected
*/
protected function update_inventory($action, array $user_ids, array $item_ids)
{
switch ($action)
{
case 'add':
$owned = [];
$stack = [];
$sql = 'SELECT item_id, user_id
FROM ' . $this->inventory_table . '
WHERE ' . $this->db->sql_in_set('item_id', $item_ids) . '
AND ' . $this->db->sql_in_set('user_id', $user_ids);
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
$item_id = (int) $row['item_id'];
$user_id = (int) $row['user_id'];
$owned[$item_id][] = $user_id;
$stack[$user_id][$item_id][] = $item_id;
}
$this->db->sql_freeresult($result);
$items = $this->operator_item->get_items_by_id($item_ids);
foreach ($item_ids as $item_id)
{
/** @var item $item */
$item = $items[$item_id];
$users = !empty($owned[$item_id]) && !$item->get_stack() ? array_diff($user_ids, $owned[$item_id]) : $user_ids;
foreach ($users as $user_id)
{
$sql = 'INSERT INTO ' . $this->inventory_table . ' ' . $this->db->sql_build_array('INSERT', [
'category_id' => $item->get_category(),
'item_id' => $item->get_id(),
'user_id' => $user_id,
'gifter_id' => (int) $this->user->data['user_id'],
'purchase_time' => time(),
'purchase_price' => 0.00,
]);
$this->db->sql_query($sql);
$index = !empty($stack[$user_id][$item_id]) ? count($stack[$user_id][$item_id]) : 0;
$index = $index + 1;
$this->notification->gift($item, $user_id, $this->db->sql_nextid(), $index);
}
}
break;
case 'delete':
$sql = 'DELETE FROM ' . $this->inventory_table . '
WHERE ' . $this->db->sql_in_set('item_id', $item_ids) . '
AND ' . $this->db->sql_in_set('user_id', $user_ids);
$this->db->sql_query($sql);
break;
}
}
/**
* Get user identifiers from usernames.
*
* @param array $usernames The usernames
* @param array $user_ids The user identifiers
* @param array $errors The errors
* @return void
* @access protected
*/
protected function get_ids_from_usernames(array $usernames, array &$user_ids, array &$errors)
{
$usernames_clean = [];
$usernames_found = [];
foreach ($usernames as $username)
{
$usernames_clean[$username] = utf8_clean_string($username);
}
$sql = 'SELECT user_id, username_clean
FROM ' . $this->users_table . '
WHERE ' . $this->db->sql_in_set('username_clean', $usernames_clean);
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
$usernames_found[] = $row['username_clean'];
$user_ids[] = (int) $row['user_id'];
}
$this->db->sql_freeresult($result);
$usernames_not_found = array_diff($usernames_clean, $usernames_found);
if (!empty($usernames_not_found))
{
$errors[] = count($usernames_not_found) > 1 ? 'NO_USERS' : 'NO_USER';
$not_found = array_intersect($usernames_clean, $usernames_not_found);
$not_found = array_flip($not_found);
foreach ($not_found as $username)
{
$errors[] = '&raquo; ' . $username;
}
}
}
/**
* Get user identifiers from group identifiers.
*
* @param array $group_ids The group identifiers
* @param array $user_ids The user identifiers
* @return void
* @access protected
*/
protected function get_ids_from_groups(array $group_ids, array &$user_ids)
{
$sql = 'SELECT user_id
FROM ' . $this->user_group_table . '
WHERE user_pending <> 1
AND ' . $this->db->sql_in_set('group_id', $group_ids);
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
$user_ids[] = (int) $row['user_id'];
}
$this->db->sql_freeresult($result);
}
/**
* Get a username from user identifier.
*
* @param int $user_id The user identifier
* @return string The username
* @access protected
*/
protected function get_username($user_id)
{
$sql = 'SELECT username
FROM ' . $this->users_table . '
WHERE user_id = ' . (int) $user_id;
$result = $this->db->sql_query_limit($sql, 1);
$username = $this->db->sql_fetchfield('username');
$this->db->sql_freeresult($result);
return (string) $username;
}
/**
* Set custom form action.
*
* @param string $u_action Custom form action
* @return self $this This controller for chaining calls
* @access public
*/
public function set_page_url($u_action)
{
$this->u_action = $u_action;
return $this;
}
}

View File

@@ -0,0 +1,703 @@
<?php
/**
*
* phpBB Studio - Advanced Shop System. An extension for the phpBB Forum Software package.
*
* @copyright (c) 2019, phpBB Studio, https://www.phpbbstudio.com
* @license GNU General Public License, version 2 (GPL-2.0)
*
*/
namespace phpbbstudio\ass\controller;
use phpbb\exception\runtime_exception;
use phpbbstudio\ass\entity\category;
use phpbbstudio\ass\entity\item;
use phpbbstudio\ass\items\type\item_type;
/**
* phpBB Studio - Advanced Shop System: ACP Items controller
*/
class acp_items_controller
{
/** @var \phpbb\cache\driver\driver_interface */
protected $cache;
/** @var \phpbbstudio\ass\items\manager */
protected $items_manager;
/** @var \phpbb\language\language */
protected $language;
/** @var \phpbb\log\log */
protected $log;
/** @var \phpbbstudio\ass\operator\category */
protected $operator_cat;
/** @var \phpbbstudio\ass\operator\inventory */
protected $operator_inv;
/** @var \phpbbstudio\ass\operator\item */
protected $operator_item;
/** @var \phpbb\request\request */
protected $request;
/** @var \phpbb\template\template */
protected $template;
/** @var \phpbbstudio\ass\helper\time */
protected $time;
/** @var \phpbb\user */
protected $user;
/** @var string phpBB admin path */
protected $admin_path;
/** @var string phpBB root path */
protected $root_path;
/** @var string php File extension */
protected $php_ext;
/** @var string Custom form action */
protected $u_action;
/**
* Constructor.
*
* @param \phpbb\cache\driver\driver_interface $cache Cache object
* @param \phpbbstudio\ass\items\manager $items_manager Items manager object
* @param \phpbb\language\language $language Language object
* @param \phpbb\log\log $log Log object
* @param \phpbbstudio\ass\operator\category $operator_cat Category operator object
* @param \phpbbstudio\ass\operator\inventory $operator_inv Inventory operator object
* @param \phpbbstudio\ass\operator\item $operator_item Item operator object
* @param \phpbb\request\request $request Request object
* @param \phpbb\template\template $template Template object
* @param \phpbbstudio\ass\helper\time $time Time helper object
* @param \phpbb\user $user User object
* @param string $admin_path phpBB admin path
* @param string $root_path phpBB root path
* @param string $php_ext php File extension
* @return void
* @access public
*/
public function __construct(
\phpbb\cache\driver\driver_interface $cache,
\phpbbstudio\ass\items\manager $items_manager,
\phpbb\language\language $language,
\phpbb\log\log $log,
\phpbbstudio\ass\operator\category $operator_cat,
\phpbbstudio\ass\operator\inventory $operator_inv,
\phpbbstudio\ass\operator\item $operator_item,
\phpbb\request\request $request,
\phpbb\template\template $template,
\phpbbstudio\ass\helper\time $time,
\phpbb\user $user,
$admin_path,
$root_path,
$php_ext
)
{
$this->cache = $cache;
$this->items_manager = $items_manager;
$this->language = $language;
$this->log = $log;
$this->operator_cat = $operator_cat;
$this->operator_inv = $operator_inv;
$this->operator_item = $operator_item;
$this->request = $request;
$this->template = $template;
$this->time = $time;
$this->user = $user;
$this->admin_path = $root_path . $admin_path;
$this->root_path = $root_path;
$this->php_ext = $php_ext;
}
/**
* Handle and display the "Items" ACP mode.
*
* @return void
* @access public
*/
public function items()
{
$this->language->add_lang(['ass_acp_common', 'ass_common'], 'phpbbstudio/ass');
$action = $this->request->variable('action', '', true);
$item_id = $this->request->variable('iid', 0);
$category_id = $this->request->variable('cid', 0);
$s_items = ($item_id || ($category_id && strpos($action, 'cat_') !== 0));
switch ($action)
{
case 'move':
$id = $this->request->variable('id', 0);
$order = $this->request->variable('order', 0) + 1;
$s_items ? $this->operator_item->move($id, $order) : $this->operator_cat->move($id, $order);
break;
case 'resolve':
$item = $this->operator_item->get_entity()->load($item_id);
$category = $this->operator_cat->get_entity()->load($item->get_category());
if (confirm_box(true))
{
$item->set_conflict(false)
->save();
$category->set_conflicts($category->get_conflicts() - 1)
->save();
$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_ACP_ASS_ITEM_RESOLVED', time(), [$item->get_title()]);
if ($this->request->is_ajax())
{
$json_response = new \phpbb\json_response;
$json_response->send([
'MESSAGE_TITLE' => $this->language->lang('INFORMATION'),
'MESSAGE_TEXT' => $this->language->lang('ACP_ASS_ITEM_RESOLVE_SUCCESS')
]);
}
trigger_error($this->language->lang('ACP_ASS_ITEM_RESOLVE_SUCCESS') . adm_back_link($this->u_action . '&amp;iid=' . $item->get_id()));
}
else
{
confirm_box(false, 'ACP_ASS_ITEM_RESOLVE', '');
redirect($this->u_action . '&amp;iid=' . $item->get_id());
}
break;
case 'type':
$json_response = new \phpbb\json_response;
$type = $this->items_manager->get_type($this->request->variable('type', '', true));
if ($type !== null)
{
$data = $item_id ? $this->operator_item->get_entity()->load($item_id)->get_data() : [];
$this->template->set_filenames(['type' => $type->get_acp_template($data)]);
$this->template->assign_var('U_ACTION', $this->u_action);
try
{
$body = $this->template->assign_display('type');
$json_response->send([
'success' => true,
'body' => $body,
]);
}
/** @noinspection PhpRedundantCatchClauseInspection */
catch (\Twig\Error\Error $e)
{
$json_response->send([
'error' => true,
'MESSAGE_TEXT' => $e->getMessage(),
'MESSAGE_TITLE' => $this->language->lang('INFORMATION'),
]);
}
}
else
{
$json_response->send([
'error' => true,
'MESSAGE_TEXT' => $this->language->lang('ASS_ITEM_TYPE_NOT_EXIST'),
'MESSAGE_TITLE' => $this->language->lang('INFORMATION'),
]);
}
break;
case 'cat_delete':
case 'delete':
$s_item = $action === 'delete';
$item = $s_item ? $this->operator_item->get_entity()->load($item_id) : null;
$category = $this->operator_cat->get_entity()->load($s_item ? $item->get_category() : $category_id);
$l_mode = $s_item ? 'ITEM' : 'CATEGORY';
$u_mode = $this->u_action . ($s_item ? "&cid={$item->get_category()}" : '');
if ($s_item)
{
$type = $this->items_manager->get_type($item->get_type());
if ($type !== null && $type->is_admin_authed() === false)
{
trigger_error($this->language->lang('ACP_ASS_ITEM_TYPE_NO_AUTH'), E_USER_WARNING);
}
}
if (confirm_box(true))
{
if (!$s_item)
{
$this->operator_cat->delete_category($category_id);
}
$this->operator_item->delete_items($category_id, $item_id);
$this->operator_inv->delete_items($category_id, $item_id);
$log_title = $s_item ? $item->get_title() : $category->get_title();
$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, "LOG_ACP_ASS_{$l_mode}_DELETED", false, [$log_title]);
$message = $this->language->lang("ACP_ASS_{$l_mode}_DELETE_SUCCESS");
if (!$this->request->is_ajax())
{
$message .= adm_back_link($u_mode);
}
trigger_error($message);
}
else
{
confirm_box(false, "ACP_ASS_{$l_mode}_DELETE", build_hidden_fields([
'action' => $action,
'cid' => $category_id,
'iid' => $item_id,
]));
redirect($u_mode);
}
break;
case 'cat_add':
case 'cat_edit':
case 'add':
case 'copy':
case 'edit':
$s_edit = in_array($action, ['edit', 'cat_edit']);
$s_item = in_array($action, ['add', 'copy', 'edit']);
$entity = $s_item ? $this->operator_item->get_entity() : $this->operator_cat->get_entity();
if ($s_edit)
{
try
{
$entity->load(($s_item ? $item_id : $category_id));
}
catch (runtime_exception $e)
{
$message = $this->language->lang($e->getMessage(), $this->language->lang($s_item ? 'ASS_ITEM' : 'ASS_CATEGORY'));
trigger_error($message . adm_back_link($this->u_action), E_USER_WARNING);
}
}
else if ($s_item)
{
// Copy an item
if ($action === 'copy')
{
$data = $this->operator_item->get_items_by_id([$item_id], false);
if (empty($data[0]))
{
$message = $this->language->lang('ASS_ERROR_NOT_FOUND', $this->language->lang('ASS_ITEM'));
trigger_error($message . adm_back_link($this->u_action), E_USER_WARNING);
}
$data = array_diff_key($data[0], array_flip([
'item_id',
'item_title',
'item_slug',
'item_purchases',
'item_stock',
'item_create_time',
'item_edit_time',
'item_conflict',
'category_slug',
]));
$entity->import($data);
$action = 'add';
$item_id = 0;
$category_id = $entity->get_category();
}
else
{
$entity->set_category($category_id);
}
}
if ($s_item && $s_edit)
{
$type = $this->items_manager->get_type($entity->get_type());
if ($type !== null && $type->is_admin_authed() === false)
{
$message = $this->language->lang('ACP_ASS_ITEM_TYPE_NO_AUTH');
$u_back = $this->u_action . ($entity->get_category() ? '&cid=' . $entity->get_category() : '');
trigger_error($message . adm_back_link($u_back), E_USER_WARNING);
}
}
$this->add_edit_data($entity, $s_item);
$this->template->assign_vars([
'S_ASS_ADD' => !$s_edit,
'S_ASS_EDIT' => $s_edit,
]);
break;
}
if ($s_items)
{
/** @var item $entity */
foreach ($this->operator_item->get_items($category_id) as $entity)
{
/** @var item_type $type */
$type = $this->items_manager->get_type($entity->get_type());
$s_auth = $type !== null ? $type->is_admin_authed() : true;
$this->template->assign_block_vars('ass_items', [
'ID' => $entity->get_id(),
'TITLE' => $entity->get_title(),
'SLUG' => $entity->get_slug(),
'ICON' => $entity->get_icon(),
'CONFLICT' => $entity->get_conflict(),
'S_ACTIVE' => $entity->get_active(),
'S_AVAILABLE' => $this->operator_item->is_available($entity),
'S_AUTH' => $s_auth,
'U_DELETE' => $s_auth ? "{$this->u_action}&amp;action=delete&iid={$entity->get_id()}" : '',
'U_COPY' => $s_auth ? "{$this->u_action}&amp;action=copy&iid={$entity->get_id()}" : '',
'U_EDIT' => $s_auth ? "{$this->u_action}&amp;action=edit&iid={$entity->get_id()}" : '',
]);
}
}
else
{
/** @var category $entity */
foreach ($this->operator_cat->get_categories() as $entity)
{
$this->template->assign_block_vars('ass_categories', [
'ID' => $entity->get_id(),
'TITLE' => $entity->get_title(),
'SLUG' => $entity->get_slug(),
'ICON' => $entity->get_icon(),
'CONFLICT' => $entity->get_conflicts(),
'S_ACTIVE' => $entity->get_active(),
'S_AUTH' => true,
'U_DELETE' => "{$this->u_action}&amp;action=cat_delete&cid={$entity->get_id()}",
'U_EDIT' => "{$this->u_action}&amp;action=cat_edit&cid={$entity->get_id()}",
'U_VIEW' => "{$this->u_action}&amp;cid={$entity->get_id()}",
]);
}
}
$this->template->assign_vars([
'S_ITEMS' => $s_items,
'U_ACTION' => $this->u_action . ($action ? "&amp;action=$action" : '') . ($category_id ? "&amp;cid=$category_id" : '') . ($item_id ? "&amp;iid=$item_id" : ''),
'U_ASS_ADD' => $this->u_action . '&amp;action=' . ($s_items ? 'add' : 'cat_add') . ($category_id ? "&amp;cid=$category_id" : ''),
'U_BACK' => $this->u_action,
]);
}
/**
* Handle adding and editing an entity.
*
* @param item|category $entity The entity
* @param bool $s_item Whether it's an item or a category
* @return void
* @access protected
*/
protected function add_edit_data($entity, $s_item)
{
$errors = [];
$submit = $this->request->is_set_post('submit');
$s_edit = (bool) $entity->get_id();
$l_mode = $s_item ? 'ITEM' : 'CATEGORY';
$form_key = 'add_edit_categories';
add_form_key($form_key);
$data = [
'active' => $this->request->variable('active', false),
'title' => $this->request->variable('title', '', true),
'slug' => $this->request->variable('slug', '', true),
'icon' => $this->request->variable('icon', '', true),
'desc' => $this->request->variable('desc', '', true),
];
if ($s_item)
{
$data += [
'type' => $this->request->variable('type', '', true),
'price' => $this->request->variable('price', 0.00),
'stock_unlimited' => $this->request->variable('stock_unlimited', false),
'stock' => $this->request->variable('stock', 0),
'stock_threshold' => $this->request->variable('stock_threshold', 0),
'gift' => $this->request->variable('gift', false),
'gift_only' => $this->request->variable('gift_only', false),
'gift_type' => $this->request->variable('gift_type', false),
'gift_percentage' => $this->request->variable('gift_percentage', 0),
'gift_price' => $this->request->variable('gift_price', 0.00),
'sale_price' => $this->request->variable('sale_price', 0.00),
'sale_start' => $this->request->variable('sale_start', ''),
'sale_until' => $this->request->variable('sale_until', ''),
'featured_start' => $this->request->variable('featured_start', ''),
'featured_until' => $this->request->variable('featured_until', ''),
'available_start' => $this->request->variable('available_start', ''),
'available_until' => $this->request->variable('available_until', ''),
'count' => $this->request->variable('count', 0),
'stack' => $this->request->variable('stack', 1),
'refund_string' => $this->request->variable('refund_string', '', true),
'expire_string' => $this->request->variable('expire_string', '', true),
'delete_string' => $this->request->variable('delete_string', '', true),
'background' => $this->request->variable('background', '', true),
'images' => $this->request->variable('images', [''], true),
'related_enabled' => $this->request->variable('related_enabled', false),
'related_items' => $this->request->variable('related_items', [0]),
];
$post_variables = $this->request->get_super_global(\phpbb\request\request_interface::POST);
$data['data'] = isset($post_variables['data']) ? $this->request->escape($post_variables['data'], true) : [];
}
if ($submit)
{
if (!check_form_key($form_key))
{
$errors[] = $this->language->lang('FORM_INVALID');
}
foreach ($data as $key => $value)
{
try
{
$entity->{"set_{$key}"}($value);
if ($key === 'slug' && $value !== $entity->get_slug())
{
$s_purge = true;
}
}
catch (runtime_exception $e)
{
$errors[] = $this->get_error_message($e, $l_mode);
}
}
if ($s_item)
{
$type = $this->items_manager->get_type($entity->get_type());
if ($type === null)
{
$errors[] = $this->language->lang('ASS_ITEM_TYPE_NOT_EXIST');
}
else
{
$errors += (array) $type->validate_acp_data($entity->get_data());
}
}
if (empty($errors))
{
$function = $s_edit ? 'save' : 'insert';
$message = $s_edit ? "ACP_ASS_{$l_mode}_EDIT_SUCCESS" : "ACP_ASS_{$l_mode}_ADD_SUCCESS";
$action = $s_edit ? "LOG_ACP_ASS_{$l_mode}_EDITED" : "LOG_ACP_ASS_{$l_mode}_ADDED";
try
{
$entity->$function();
$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, $action, false, [$entity->get_title()]);
if (!empty($s_purge))
{
$this->cache->purge();
}
$return = $this->u_action . ($s_item ? "&amp;cid={$entity->get_category()}" : '');
meta_refresh(3, $return);
trigger_error($this->language->lang($message) . adm_back_link($return));
}
catch (runtime_exception $e)
{
$errors[] = $this->get_error_message($e, $l_mode);
}
}
}
$this->generate_bbcodes();
if ($s_item)
{
$type = $this->items_manager->get_type($entity->get_type());
$this->items_manager->set_types_for_select($entity->get_type());
$this->template->assign_vars($this->operator_item->get_variables($entity, 'ITEM_', false));
$this->template->assign_vars([
'ITEM_HELP_DATA' => $this->get_help_data(array_keys($data), $s_edit),
'T_ITEM_TEMPLATE' => $type !== null ? $type->get_acp_template($entity->get_data()) : '',
'U_ITEM_IMAGE' => $this->u_action . '&amp;m=images&amp;action=select_file&amp;image=',
'U_ITEM_RESOLVE' => $this->u_action . '&amp;iid=' . $entity->get_id() . '&amp;action=resolve',
'U_ITEM_TYPE' => $this->u_action . '&amp;iid=' . $entity->get_id() . '&amp;action=type',
'U_ITEM_ERROR_LOG' => append_sid("{$this->admin_path}index.{$this->php_ext}", [
'i' => 'acp_logs',
'mode' => 'admin',
'keywords' => urlencode(htmlspecialchars_decode($entity->get_title())),
]),
]);
$this->set_related_items_for_select($entity->get_id(), $entity->get_related_items());
if ($s_edit && !$submit && $type === null)
{
$errors[] = $this->language->lang('ASS_ITEM_TYPE_NOT_EXIST');
}
}
else
{
$this->template->assign_vars($this->operator_cat->get_variables($entity, 'CATEGORY_', false));
}
$this->template->assign_vars([
'ASS_ERRORS' => $errors,
'DATE_FORMAT' => $this->time->get_format(),
'TIMEZONE' => $this->time->get_timezone(),
]);
}
/**
* Generate BBCodes for a textarea editor.
*
* @return void
* @access protected
*/
protected function generate_bbcodes()
{
include_once $this->root_path . 'includes/functions_display.' . $this->php_ext;
$this->language->add_lang('posting');
display_custom_bbcodes();
$this->template->assign_vars([
'S_BBCODE_IMG' => true,
'S_BBCODE_QUOTE' => true,
'S_BBCODE_FLASH' => true,
'S_LINKS_ALLOWED' => true,
]);
}
/**
* Get a localised error message from a thrown exception.
*
* @param runtime_exception $e The thrown exception
* @param string $mode The mode (ITEM|CATEGORY)
* @return string The localised error message.
* @access protected
*/
protected function get_error_message(runtime_exception $e, $mode)
{
$params = $e->get_parameters();
$field = array_shift($params);
$field = $field ? "ACP_ASS_{$mode}_{$field}" : "ASS_{$mode}";
$params = array_merge([$this->language->lang($field)], $params);
return $this->language->lang_array($e->getMessage(), $params);
}
/**
* The item's data keys.
*
* @param array $data Item's data keys
* @param bool $s_edit Whether or not the item is being edited
* @return array Item help data values
* @access protected
*/
protected function get_help_data(array $data, $s_edit)
{
$this->language->add_lang('ass_acp_help', 'phpbbstudio/ass');
$data = array_filter($data, function($value) {
return $value !== 'data' && strpos($value, '_until') === false;
});
if ($s_edit)
{
$data = array_merge($data, ['dates', 'states', 'stock_info', 'sale_info']);
}
return $data;
}
/**
* Assign categories and items to the template for the related items selection.
*
* @param int $item_id The item identifiers
* @param array $item_ids The related items identifiers
* @return void
* @access protected
*/
protected function set_related_items_for_select($item_id, array $item_ids)
{
/** @var category $category */
foreach ($this->operator_cat->get_categories() as $category)
{
$this->template->assign_block_vars('categories', array_merge([
'S_INACTIVE' => !$category->get_active(),
], $this->operator_cat->get_variables($category)));
/** @var item $item */
foreach ($this->operator_item->get_items($category->get_id()) as $item)
{
if ($item->get_id() === $item_id)
{
continue;
}
$this->template->assign_block_vars('categories.items', array_merge([
'S_INACTIVE' => !$item->get_active(),
'S_SELECTED' => in_array($item->get_id(), $item_ids),
], $this->operator_item->get_variables($item)));
}
}
}
/**
* Set custom form action.
*
* @param string $u_action Custom form action
* @return self $this This controller for chaining calls
* @access public
*/
public function set_page_url($u_action)
{
$this->u_action = $u_action;
return $this;
}
}

View File

@@ -0,0 +1,246 @@
<?php
/**
*
* phpBB Studio - Advanced Shop System. An extension for the phpBB Forum Software package.
*
* @copyright (c) 2019, phpBB Studio, https://www.phpbbstudio.com
* @license GNU General Public License, version 2 (GPL-2.0)
*
*/
namespace phpbbstudio\ass\controller;
use phpbbstudio\ass\entity\category;
use phpbbstudio\ass\entity\item;
use phpbbstudio\ass\items\type\item_type;
/**
* phpBB Studio - Advanced Shop System: ACP Logs controller
*/
class acp_logs_controller
{
/** @var \phpbb\config\config */
protected $config;
/** @var \phpbbstudio\ass\items\manager */
protected $items_manager;
/** @var \phpbb\language\language */
protected $language;
/** @var \phpbbstudio\ass\helper\log */
protected $log;
/** @var \phpbb\log\log */
protected $log_phpbb;
/** @var \phpbbstudio\ass\operator\category */
protected $operator_cat;
/** @var \phpbbstudio\ass\operator\item */
protected $operator_item;
/** @var \phpbb\pagination */
protected $pagination;
/** @var \phpbb\request\request */
protected $request;
/** @var \phpbb\template\template */
protected $template;
/** @var \phpbb\user */
protected $user;
/** @var string Custom form action */
protected $u_action;
/**
* Constructor.
*
* @param \phpbb\config\config $config Config object
* @param \phpbbstudio\ass\items\manager $items_manager Items manager object
* @param \phpbb\language\language $language Language object
* @param \phpbbstudio\ass\helper\log $log Log helper object
* @param \phpbb\log\log $log_phpbb Log object
* @param \phpbbstudio\ass\operator\category $operator_cat Category operator object
* @param \phpbbstudio\ass\operator\item $operator_item Item operator object
* @param \phpbb\pagination $pagination Pagination object
* @param \phpbb\request\request $request Request object
* @param \phpbb\template\template $template Template object
* @param \phpbb\user $user User object
* @return void
* @access public
*/
public function __construct(
\phpbb\config\config $config,
\phpbbstudio\ass\items\manager $items_manager,
\phpbb\language\language $language,
\phpbbstudio\ass\helper\log $log,
\phpbb\log\log $log_phpbb,
\phpbbstudio\ass\operator\category $operator_cat,
\phpbbstudio\ass\operator\item $operator_item,
\phpbb\pagination $pagination,
\phpbb\request\request $request,
\phpbb\template\template $template,
\phpbb\user $user
)
{
$this->config = $config;
$this->items_manager = $items_manager;
$this->language = $language;
$this->log = $log;
$this->log_phpbb = $log_phpbb;
$this->operator_cat = $operator_cat;
$this->operator_item = $operator_item;
$this->pagination = $pagination;
$this->request = $request;
$this->template = $template;
$this->user = $user;
}
/**
* Handle and display the "Logs" ACP mode.
*
* @return void
* @access public
*/
public function logs()
{
$this->language->add_lang(['ass_acp_common', 'ass_common'], 'phpbbstudio/ass');
$show_array = [
'all' => ['title' => 'ASS_ALL', 'sql' => ''],
'use' => ['title' => 'ASS_USAGES', 'sql' => 'l.item_purchase = 0'],
'buy' => ['title' => 'ASS_PURCHASES', 'sql' => 'l.item_purchase = 1 AND l.recipient_id = 0'],
'given' => ['title' => 'ASS_GIFTS_GIVEN', 'sql' => 'l.item_purchase = 1 AND l.recipient_id <> 0'],
];
$sort_array = [
'time' => ['title' => 'TIME', 'sql' => 'l.log_time'],
'price' => ['title' => 'ASS_ITEM_PRICE', 'sql' => 'l.points_sum'],
'item' => ['title' => 'ASS_ITEM_TITLE', 'sql' => 'i.item_title'],
'category' => ['title' => 'ASS_CATEGORY_TITLE', 'sql' => 'c.category_title'],
'recipient' => ['title' => 'ASS_RECIPIENT_NAME', 'sql' => 'recipient_name'],
];
$dir_array = [
'desc' => ['title' => 'DESCENDING', 'sql' => 'DESC'],
'asc' => ['title' => 'ASCENDING', 'sql' => 'ASC'],
];
$page = $this->request->variable('page', 1);
$show = $this->request->variable('display', 'all', true);
$sort = $this->request->variable('sort', 'time', true);
$dir = $this->request->variable('direction', 'desc', true);
$show = in_array($show, array_keys($show_array)) ? $show : 'all';
$sort = in_array($sort, array_keys($sort_array)) ? $sort : 'time';
$dir = in_array($dir, array_keys($dir_array)) ? $dir : 'desc';
$delete_mark = $this->request->variable('del_marked', false, false, \phpbb\request\request_interface::POST);
$delete_all = $this->request->variable('del_all', false, false, \phpbb\request\request_interface::POST);
$marked = $this->request->variable('mark', [0]);
$log_action = $this->u_action . "&display={$show}&sort={$sort}&direction={$dir}";
if (($delete_mark || $delete_all))
{
if (confirm_box(true))
{
$this->log->delete($delete_all, $marked);
$l_delete = $delete_all ? 'ALL' : (count($marked) > 1 ? 'ENTRIES' : 'ENTRY');
$this->log_phpbb->add('admin', $this->user->data['user_id'], $this->user->ip, "LOG_ACP_ASS_LOG_DELETED_{$l_delete}");
trigger_error($this->language->lang("ACP_ASS_LOG_DELETED_{$l_delete}") . adm_back_link($log_action . "&page{$page}"));
}
else
{
confirm_box(false, $this->language->lang('CONFIRM_OPERATION'), build_hidden_fields([
'del_marked' => $delete_mark,
'del_all' => $delete_all,
'mark' => $marked,
]));
redirect($log_action . "&page{$page}");
}
}
$sql_where = $show_array[$show]['sql'];
$sql_order = $sort_array[$sort]['sql'];
$sql_dir = $dir_array[$dir]['sql'];
$limit = (int) $this->config['ass_logs_per_page'];
$start = ($page - 1) * $limit;
$total = $this->log->get_user_logs_count($sql_where);
$rowset = $this->log->get_user_logs($sql_where, $sql_order, $sql_dir, $limit, $start);
$categories = $this->operator_cat->get_categories_by_id(array_column($rowset, 'category_id'));
$items = $this->operator_item->get_items_by_id(array_column($rowset, 'item_id'));
foreach ($rowset as $row)
{
$category_id = (int) $row['category_id'];
$item_id = (int) $row['item_id'];
/** @var category $category */
$category = !empty($categories[$category_id]) ? $categories[$category_id] : null;
/** @var item $item */
$item = !empty($items[$item_id]) ? $items[$item_id] : null;
/** @var item_type $type */
$type = $item ? $this->items_manager->get_type($item->get_type()) : null;
$this->template->assign_block_vars('ass_logs', [
'CATEGORY_TITLE' => $category ? $category->get_title() : $this->language->lang('ASS_UNAVAILABLE_CATEGORY'),
'ITEM_TITLE' => $item ? $item->get_title() : $this->language->lang('ASS_UNAVAILABLE_ITEM'),
'LOG_ACTION' => $type ? $this->language->lang($type->get_language('log')) : $this->language->lang('ASS_UNAVAILABLE_' . (!$item ? 'ITEM' : 'TYPE')),
'LOG_ID' => $row['log_id'],
'LOG_IP' => $row['log_ip'],
'LOG_TIME' => $this->user->format_date($row['log_time']),
'POINTS_NEW' => $row['points_new'],
'POINTS_OLD' => $row['points_old'],
'POINTS_SUM' => -$row['points_sum'],
'RECIPIENT' => $row['recipient_id'] ? get_username_string('full', $row['recipient_id'], $row['recipient_name'], $row['recipient_colour']) : '',
'USER' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']),
'S_PURCHASE' => $row['item_purchase'],
'S_GIFT_RECEIVE' => $row['recipient_id'] != 0,
]);
}
$this->pagination->generate_template_pagination($log_action, 'pagination', 'page', $total, $limit, $start);
$this->template->assign_vars([
'SORT_DISPLAY' => $show,
'SORT_DISPLAY_ARRAY' => $show_array,
'SORT_SORT' => $sort,
'SORT_SORT_ARRAY' => $sort_array,
'SORT_DIR' => $dir,
'SORT_DIR_ARRAY' => $dir_array,
'TOTAL_LOGS' => $this->language->lang('TOTAL_LOGS', $total),
'U_ACTION' => $this->u_action,
]);
}
/**
* Set custom form action.
*
* @param string $u_action Custom form action
* @return self $this This controller for chaining calls
* @access public
*/
public function set_page_url($u_action)
{
$this->u_action = $u_action;
return $this;
}
}

View File

@@ -0,0 +1,444 @@
<?php
/**
*
* phpBB Studio - Advanced Shop System. An extension for the phpBB Forum Software package.
*
* @copyright (c) 2019, phpBB Studio, https://www.phpbbstudio.com
* @license GNU General Public License, version 2 (GPL-2.0)
*
*/
namespace phpbbstudio\ass\controller;
/**
* phpBB Studio - Advanced Shop System: ACP Overview controller
*/
class acp_overview_controller
{
/** @var \phpbb\config\config */
protected $config;
/** @var \phpbb\config\db_text */
protected $config_text;
/** @var \phpbb\db\driver\driver_interface */
protected $db;
/** @var \phpbb\language\language */
protected $language;
/** @var \phpbbstudio\ass\operator\item */
protected $operator_item;
/** @var \phpbb\textformatter\s9e\parser */
protected $parser;
/** @var \phpbb\textformatter\s9e\renderer */
protected $renderer;
/** @var \phpbb\request\request */
protected $request;
/** @var \phpbb\template\template */
protected $template;
/** @var \phpbb\user_loader */
protected $user_loader;
/** @var \phpbb\textformatter\s9e\utils */
protected $utils;
/** @var string Categories table */
protected $categories_table;
/** @var string Items table */
protected $items_table;
/** @var string Logs table */
protected $logs_table;
/** @var string Custom form action */
protected $u_action;
/**
* Constructor.
*
* @param \phpbb\config\config $config Config object
* @param \phpbb\config\db_text $config_text Config text object
* @param \phpbb\db\driver\driver_interface $db Database object
* @param \phpbb\language\language $language Language object
* @param \phpbbstudio\ass\operator\item $operator_item Item operator object
* @param \phpbb\textformatter\s9e\parser $parser Text formatter parser object
* @param \phpbb\textformatter\s9e\renderer $renderer Text formatter renderer object
* @param \phpbb\request\request $request Request object
* @param \phpbb\template\template $template Template object
* @param \phpbb\user_loader $user_loader User loader object
* @param \phpbb\textformatter\s9e\utils $utils Text formatter utilities object
* @param string $categories_table Categories table
* @param string $items_table Items table
* @param string $logs_table Logs table
* @return void
* @access public
*/
public function __construct(
\phpbb\config\config $config,
\phpbb\config\db_text $config_text,
\phpbb\db\driver\driver_interface $db,
\phpbb\language\language $language,
\phpbbstudio\ass\operator\item $operator_item,
\phpbb\textformatter\s9e\parser $parser,
\phpbb\textformatter\s9e\renderer $renderer,
\phpbb\request\request $request,
\phpbb\template\template $template,
\phpbb\user_loader $user_loader,
\phpbb\textformatter\s9e\utils $utils,
$categories_table,
$items_table,
$logs_table
)
{
$this->config = $config;
$this->config_text = $config_text;
$this->db = $db;
$this->language = $language;
$this->operator_item = $operator_item;
$this->parser = $parser;
$this->renderer = $renderer;
$this->request = $request;
$this->template = $template;
$this->user_loader = $user_loader;
$this->utils = $utils;
$this->categories_table = $categories_table;
$this->items_table = $items_table;
$this->logs_table = $logs_table;
}
/**
* Handle and display the "Overview" ACP mode.
*
* @return void
* @access public
*/
public function overview()
{
$this->language->add_lang(['ass_acp_common', 'ass_common'], 'phpbbstudio/ass');
$action = $this->request->variable('action', '', true);
$submit = $this->request->is_set_post('submit');
$notes = $this->config_text->get('ass_admin_notes');
if ($action === 'notes')
{
if ($submit)
{
$notes = $this->parser->parse($this->request->variable('notes', '', true));
$this->config_text->set('ass_admin_notes', $notes);
}
else
{
$this->template->assign_vars([
'NOTES_EDIT' => $this->utils->unparse($notes),
'S_NOTES' => true,
]);
}
}
$item_modes = [
'featured', 'featured_coming', 'sale', 'sale_coming',
'low_stock', 'low_sellers', 'top_sellers', 'recent',
];
foreach ($item_modes as $mode)
{
$items = $this->get_items($mode);
foreach ($items as $item)
{
$this->template->assign_block_vars($mode, $this->operator_item->get_variables($item));
}
}
foreach ($this->get_recent() as $row)
{
$item = $this->operator_item->get_entity()->import($row);
$this->template->assign_block_vars('purchases', array_merge(
$this->operator_item->get_variables($item),
['PURCHASE_TIME' => (int) $row['log_time']]
));
}
$buyers = $this->get_users('buyers');
$gifters = $this->get_users('gifters');
$spenders = $this->get_users('spenders');
$this->user_loader->load_users(array_merge(array_keys($buyers), array_keys($gifters), array_keys($spenders)));
$users = [
'buyers' => $buyers,
'gifters' => $gifters,
'spenders' => $spenders,
];
foreach ($users as $user_mode => $users_array)
{
foreach ($users_array as $user_id => $count)
{
$this->template->assign_block_vars($user_mode, [
'NAME' => $this->user_loader->get_username($user_id, 'full'),
'AVATAR' => $this->user_loader->get_avatar($user_id),
'COUNT' => $count,
]);
}
}
$this->template->assign_vars([
'COUNTS' => $this->get_counts(),
'NOTES' => $notes ? $this->renderer->render(htmlspecialchars_decode($notes, ENT_COMPAT)) : '',
'GIFTING_ENABLED' => (bool) $this->config['ass_gift_enabled'],
'NO_IMAGE_ICON' => (string) $this->config['ass_no_image_icon'],
'SHOP_ACTIVE' => (bool) $this->config['ass_active'],
'SHOP_ENABLED' => (bool) $this->config['ass_enabled'],
'U_ACTION' => $this->u_action,
'U_NOTES' => $this->u_action . '&action=notes',
]);
}
/**
* Get items for a specific mode.
*
* @param string $mode The item mode (featured|sale|etc..)
* @return array Item entities
* @access protected
*/
protected function get_items($mode)
{
$sql_array = [
'SELECT' => 'i.*',
'FROM' => [$this->items_table => 'i'],
'WHERE' => $this->get_sql_where($mode),
'ORDER_BY' => $this->get_sql_order($mode),
];
$sql = $this->db->sql_build_query('SELECT', $sql_array);
$result = $this->db->sql_query_limit($sql, 5);
$rowset = $this->db->sql_fetchrowset($result);
$this->db->sql_freeresult($result);
return $this->operator_item->get_entities($rowset);
}
/**
* Get recent items.
*
* @return array Item entities
* @access protected
*/
protected function get_recent()
{
$sql = 'SELECT i.*, l.log_time
FROM ' . $this->logs_table . ' l,
' . $this->items_table . ' i
WHERE i.item_id = l.item_id
AND l.item_purchase = 1
ORDER BY l.log_time DESC';
$result = $this->db->sql_query_limit($sql, 5);
$rowset = $this->db->sql_fetchrowset($result);
$this->db->sql_freeresult($result);
return (array) $rowset;
}
/**
* Get users for a specific mode.
*
* @param string $mode The mode (buyers|gifters|spenders)
* @return array User rows
* @access protected
*/
protected function get_users($mode)
{
$users = [];
switch ($mode)
{
case 'buyers':
$select = 'COUNT(log_id)';
$where = ' WHERE recipient_id = 0';
break;
case 'gifters':
$select = 'COUNT(log_id)';
$where = ' WHERE recipient_id <> 0';
break;
case 'spenders':
default:
$select = 'SUM(points_sum)';
$where = '';
break;
}
$sql = 'SELECT ' . $select . ' as count, user_id
FROM ' . $this->logs_table . $where . '
GROUP BY user_id
ORDER BY count DESC';
$result = $this->db->sql_query_limit($sql, 5);
while ($row = $this->db->sql_fetchrow($result))
{
$users[(int) $row['user_id']] = $row['count'];
}
$this->db->sql_freeresult($result);
return (array) $users;
}
/**
* Get counts for various things.
*
* @return array Array of counts
* @access protected
*/
protected function get_counts()
{
$counts = [
'categories' => (int) $this->db->get_row_count($this->categories_table),
'items' => (int) $this->db->get_row_count($this->items_table),
];
$sql = 'SELECT COUNT(i.item_id) as count
FROM ' . $this->items_table . ' i
WHERE ' . $this->get_sql_where('featured');
$result = $this->db->sql_query_limit($sql , 1);
$counts['featured'] = (int) $this->db->sql_fetchfield('count');
$this->db->sql_freeresult($result);
$sql = 'SELECT COUNT(i.item_id) as count
FROM ' . $this->items_table . ' i
WHERE ' . $this->get_sql_where('sale');
$result = $this->db->sql_query_limit($sql , 1);
$counts['sale'] = (int) $this->db->sql_fetchfield('count');
$this->db->sql_freeresult($result);
$sql = 'SELECT SUM(item_purchases) as count
FROM ' . $this->items_table;
$result = $this->db->sql_query_limit($sql , 1);
$counts['purchases'] = (int) $this->db->sql_fetchfield('count');
$this->db->sql_freeresult($result);
$sql = 'SELECT SUM(points_sum) as count
FROM ' . $this->logs_table;
$result = $this->db->sql_query_limit($sql , 1);
$counts['spent'] = (double) $this->db->sql_fetchfield('count');
$this->db->sql_freeresult($result);
$sql = 'SELECT COUNT(item_conflict) as count
FROM ' . $this->items_table . '
WHERE item_conflict = 1';
$result = $this->db->sql_query_limit($sql , 1);
$counts['errors'] = (double) $this->db->sql_fetchfield('count');
$this->db->sql_freeresult($result);
return $counts;
}
/**
* Get the SQL WHERE statement for a specific mode
*
* @param string $mode
* @return string
* @access protected
*/
protected function get_sql_where($mode)
{
switch ($mode)
{
case 'low_stock':
return 'i.item_stock_unlimited <> 1';
case 'featured':
return 'i.item_sale_start < ' . time() . '
AND i.item_featured_start <> 0
AND i.item_featured_until <> 0
AND (' . time() . ' BETWEEN i.item_featured_start AND i.item_featured_until)';
case 'featured_coming':
return 'i.item_featured_start <> 0
AND i.item_featured_until <> 0
AND i.item_featured_start > ' . time();
case 'sale':
return 'i.item_featured_start < ' . time() . '
AND i.item_sale_start <> 0
AND i.item_sale_until <> 0
AND (' . time() . ' BETWEEN i.item_sale_start AND item_sale_until)';
case 'sale_coming':
return 'i.item_sale_start <> 0
AND i.item_sale_until <> 0
AND i.item_sale_start > ' . time();
default:
return '';
}
}
/**
* Get the SQL ORDER BY statement for a specific mode.
*
* @param string $mode
* @return string
* @access protected
*/
protected function get_sql_order($mode)
{
switch ($mode)
{
case 'low_stock':
return 'i.item_stock ASC, i.item_title ASC';
case 'low_sellers':
return 'i.item_purchases ASC, i.item_title ASC';
case 'top_sellers':
return 'i.item_purchases DESC, i.item_title ASC';
case 'recent':
return 'i.item_create_time DESC';
case 'featured':
return 'i.item_featured_until ASC, i.item_title ASC';
case 'featured_coming':
return 'i.item_featured_start ASC, i.item_title ASC';
case 'sale':
return 'i.item_sale_until ASC, i.item_title ASC';
case 'sale_coming':
return 'i.item_sale_start ASC, i.item_title ASC';
default:
return 'i.item_title ASC';
}
}
/**
* Set custom form action.
*
* @param string $u_action Custom form action
* @return self $this This controller for chaining calls
* @access public
*/
public function set_page_url($u_action)
{
$this->u_action = $u_action;
return $this;
}
}

View File

@@ -0,0 +1,341 @@
<?php
/**
*
* phpBB Studio - Advanced Shop System. An extension for the phpBB Forum Software package.
*
* @copyright (c) 2019, phpBB Studio, https://www.phpbbstudio.com
* @license GNU General Public License, version 2 (GPL-2.0)
*
*/
namespace phpbbstudio\ass\controller;
/**
* phpBB Studio - Advanced Shop System: ACP Settings controller
*/
class acp_settings_controller
{
/** @var \phpbbstudio\aps\core\functions */
protected $aps_functions;
/** @var \phpbb\config\config */
protected $config;
/** @var \phpbb\config\db_text */
protected $config_text;
/** @var \phpbb\language\language */
protected $language;
/** @var \phpbb\log\log */
protected $log;
/** @var \phpbb\textformatter\s9e\parser */
protected $parser;
/** @var \phpbb\request\request */
protected $request;
/** @var \phpbb\template\template */
protected $template;
/** @var \phpbb\user */
protected $user;
/** @var \phpbb\textformatter\s9e\utils */
protected $utils;
/** @var string phpBB root path */
protected $root_path;
/** @var string php File extension */
protected $php_ext;
/** @var string Custom form action */
protected $u_action;
/**
* Constructor.
*
* @param \phpbbstudio\aps\core\functions $aps_functions APS Functions object
* @param \phpbb\config\config $config Config object
* @param \phpbb\config\db_text $config_text Config text object
* @param \phpbb\language\language $language Language object
* @param \phpbb\log\log $log Log object
* @param \phpbb\textformatter\s9e\parser $parser Text formatter parser object
* @param \phpbb\request\request $request Request object
* @param \phpbb\template\template $template Template object
* @param \phpbb\user $user User object
* @param \phpbb\textformatter\s9e\utils $utils Text formatter utilities object
* @param string $root_path phpBB root path
* @param string $php_ext php File extension
* @return void
* @access public
*/
public function __construct(
\phpbbstudio\aps\core\functions $aps_functions,
\phpbb\config\config $config,
\phpbb\config\db_text $config_text,
\phpbb\language\language $language,
\phpbb\log\log $log,
\phpbb\textformatter\s9e\parser $parser,
\phpbb\request\request $request,
\phpbb\template\template $template,
\phpbb\user $user,
\phpbb\textformatter\s9e\utils $utils,
$root_path,
$php_ext
)
{
$this->aps_functions = $aps_functions;
$this->config = $config;
$this->config_text = $config_text;
$this->language = $language;
$this->log = $log;
$this->parser = $parser;
$this->request = $request;
$this->template = $template;
$this->user = $user;
$this->utils = $utils;
$this->root_path = $root_path;
$this->php_ext = $php_ext;
}
/**
* Handle and display the "Settings" ACP mode.
*
* @return void
* @access public
*/
public function settings()
{
$this->language->add_lang(['ass_acp_common', 'ass_common'], 'phpbbstudio/ass');
$errors = [];
$submit = $this->request->is_set_post('submit');
$form_key = 'shop_settings';
add_form_key($form_key);
if ($submit)
{
if (!check_form_key($form_key))
{
$errors[] = $this->language->lang('FORM_INVALID');
}
}
if ($this->request->variable('action', '', true) === 'locations')
{
$this->link_locations();
}
$banner_sizes = ['small', 'tiny'];
$banner_colours = ['blue', 'red', 'green', 'orange', 'aqua', 'yellow', 'pink', 'violet', 'purple', 'gold', 'silver', 'bronze'];
$icon_colours = ['blue', 'red', 'green', 'orange', 'aqua', 'yellow', 'pink', 'violet', 'purple', 'gold', 'silver', 'bronze',
'bluegray', 'gray', 'lightgray', 'black', 'white', 'lighten', 'darken'];
$panels = [
'featured' => ['limit' => ['min' => 0, 'max' => 10], 'order' => ['min' => 1, 'max' => 6], 'width' => ['min' => 4, 'max' => 6]],
'sale' => ['limit' => ['min' => 0, 'max' => 10], 'order' => ['min' => 1, 'max' => 6], 'width' => ['min' => 4, 'max' => 6]],
'featured_sale' => ['limit' => ['min' => 0, 'max' => 4], 'order' => ['min' => 1, 'max' => 6], 'width' => ['min' => 4, 'max' => 6]],
'random' => ['limit' => ['min' => 0, 'max' => 20], 'order' => ['min' => 1, 'max' => 6], 'width' => ['min' => 3, 'max' => 4]],
'recent' => ['limit' => ['min' => 0, 'max' => 10], 'order' => ['min' => 1, 'max' => 6], 'width' => ['min' => 4, 'max' => 6]],
'limited' => ['limit' => ['min' => 0, 'max' => 10], 'order' => ['min' => 1, 'max' => 6], 'width' => ['min' => 4, 'max' => 6]],
];
$options = ['banner_size', 'banner_colour', 'icon_colour', 'icon', 'limit', 'order', 'width'];
$settings = [
'int' => ['enabled', 'active', 'gift_enabled', 'deactivate_conflicts', 'purge_cache', 'items_per_page', 'logs_per_page', 'carousel_arrows', 'carousel_dots', 'carousel_fade', 'carousel_play', 'carousel_play_speed', 'carousel_speed'],
'string' => ['shop_icon', 'inventory_icon', 'no_image_icon', 'gift_icon'],
];
// General settings
foreach ($settings as $type => $data)
{
foreach ($data as $name)
{
$config_name = "ass_{$name}";
$default = $this->config[$config_name];
settype($default, $type);
$this->template->assign_var(utf8_strtoupper($name), $default);
if ($submit && empty($errors))
{
$value = $this->request->variable($name, '', $type === 'string');
if ($value !== $default)
{
$this->config->set($config_name, $value);
}
}
}
}
// Panel settings
$variables = [];
foreach ($panels as $panel => $data)
{
foreach ($options as $option)
{
$name = "{$panel}_{$option}";
$config_name = "ass_panel_{$name}";
$default = $this->config[$config_name];
$variables[utf8_strtoupper($option)][$panel] = $default;
if ($submit && empty($errors))
{
$value = $this->request->variable($name, $default);
if (isset($data[$option]))
{
if ($value < $data[$option]['min'])
{
$field = $this->language->lang('ACP_ASS_PANEL_' . utf8_strtoupper($panel));
$field .= $this->language->lang('COLON');
$field .= ' ' . $this->language->lang('ACP_ASS_PANEL_' . utf8_strtoupper($option));
$errors[] = $this->language->lang('ASS_ERROR_TOO_LOW', $field, $data[$option]['min'], $value);
continue;
}
if ($value > $data[$option]['max'])
{
$field = $this->language->lang('ACP_ASS_PANEL_' . utf8_strtoupper($panel));
$field .= $this->language->lang('COLON');
$field .= ' ' . $this->language->lang('ACP_ASS_PANEL_' . utf8_strtoupper($option));
$errors[] = $this->language->lang('ASS_ERROR_TOO_HIGH', $field, $data[$option]['max'], $value);
continue;
}
}
if ($value != $default)
{
$this->config->set($config_name, $value);
}
}
}
}
uksort($panels, function($a, $b)
{
if ($this->config["ass_panel_{$a}_order"] == $this->config["ass_panel_{$b}_order"])
{
return 0;
}
return $this->config["ass_panel_{$a}_order"] < $this->config["ass_panel_{$b}_order"] ? -1 : 1;
});
if ($submit && empty($errors))
{
$message = $this->request->variable('inactive_desc', '', true);
$message = $this->parser->parse($message);
$this->config_text->set('ass_inactive_desc', $message);
meta_refresh(3, $this->u_action);
trigger_error($this->language->lang('CONFIG_UPDATED') . adm_back_link($this->u_action));
}
$message = $this->config_text->get('ass_inactive_desc');
$message = $this->utils->unparse($message);
$this->generate_bbcodes();
$this->template->assign_vars(array_merge($variables, [
'ERRORS' => $errors,
'INACTIVE_DESC' => $message,
'SHOP_BLOCKS' => $panels,
'SHOP_ICON_COLOURS' => $icon_colours,
'SHOP_BANNER_COLOURS' => $banner_colours,
'SHOP_BANNER_SIZES' => $banner_sizes,
'U_ACTION' => $this->u_action,
'U_LOCATIONS' => $this->u_action . '&action=locations',
]));
}
/**
* Generate BBCodes for a textarea editor.
*
* @return void
* @access protected
*/
protected function generate_bbcodes()
{
include_once $this->root_path . 'includes/functions_display.' . $this->php_ext;
$this->language->add_lang('posting');
display_custom_bbcodes();
$this->template->assign_vars([
'S_BBCODE_IMG' => true,
'S_BBCODE_QUOTE' => true,
'S_BBCODE_FLASH' => true,
'S_LINKS_ALLOWED' => true,
]);
}
/**
* Handles the link locations from the settings page.
*
* @return void
* @access protected
*/
protected function link_locations()
{
$this->language->add_lang('aps_acp_common', 'phpbbstudio/aps');
$locations = $this->aps_functions->get_link_locations('ass_link_locations');
$variables = ['S_ASS_LOCATIONS' => true];
foreach ($locations as $location => $status)
{
$variables[$location] = (bool) $status;
}
$this->template->assign_vars($variables);
if ($this->request->is_set_post('submit_locations'))
{
$links = [];
foreach (array_keys($locations) as $location)
{
$links[$location] = $this->request->variable((string) $location, false);
}
$this->aps_functions->set_link_locations($links, 'ass_link_locations');
$this->log->add('admin', $this->user->data['user_id'], $this->user->data['user_ip'], 'LOG_ACP_ASS_LOCATIONS');
trigger_error($this->language->lang('ACP_APS_LOCATIONS_SUCCESS') . adm_back_link($this->u_action));
}
}
/**
* Set custom form action.
*
* @param string $u_action Custom form action
* @return self $this This controller for chaining calls
* @access public
*/
public function set_page_url($u_action)
{
$this->u_action = $u_action;
return $this;
}
}

View File

@@ -0,0 +1,968 @@
<?php
/**
*
* phpBB Studio - Advanced Shop System. An extension for the phpBB Forum Software package.
*
* @copyright (c) 2019, phpBB Studio, https://www.phpbbstudio.com
* @license GNU General Public License, version 2 (GPL-2.0)
*
*/
namespace phpbbstudio\ass\controller;
use phpbbstudio\ass\entity\item;
use phpbbstudio\ass\entity\category;
use phpbbstudio\ass\exceptions\shop_exception;
use phpbbstudio\ass\exceptions\shop_item_exception;
use phpbbstudio\ass\items\type\item_type;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
/**
* phpBB Studio - Advanced Shop System: Inventory controller
*/
class inventory_controller
{
/** @var \phpbbstudio\aps\points\distributor */
protected $aps_distributor;
/** @var \phpbbstudio\aps\core\functions */
protected $aps_functions;
/** @var \phpbb\auth\auth */
protected $auth;
/** @var \phpbb\config\config */
protected $config;
/** @var \phpbbstudio\ass\helper\controller */
protected $controller;
/** @var \phpbb\controller\helper */
protected $helper;
/** @var \phpbbstudio\ass\items\manager */
protected $items_manager;
/** @var \phpbb\language\language */
protected $language;
/** @var \phpbbstudio\ass\helper\log */
protected $log;
/** @var \phpbb\log\log */
protected $log_phpbb;
/** @var \phpbbstudio\ass\operator\category */
protected $operator_cat;
/** @var \phpbbstudio\ass\operator\inventory */
protected $operator_inv;
/** @var \phpbbstudio\ass\operator\item */
protected $operator_item;
/** @var \phpbbstudio\ass\notification\notification */
protected $notification;
/** @var \phpbb\pagination */
protected $pagination;
/** @var \phpbb\request\request */
protected $request;
/** @var \phpbbstudio\ass\helper\router */
protected $router;
/** @var \phpbb\template\template */
protected $template;
/** @var \phpbbstudio\ass\helper\time */
protected $time;
/** @var \phpbb\user */
protected $user;
/** @var \phpbb\user_loader */
protected $user_loader;
/**
* Constructor.
*
* @param \phpbbstudio\aps\points\distributor $aps_distributor APS Distributor object
* @param \phpbbstudio\aps\core\functions $aps_functions APS Functions object
* @param \phpbb\auth\auth $auth Auth object
* @param \phpbb\config\config $config Config object
* @param \phpbbstudio\ass\helper\controller $controller ASS Controller helper object
* @param \phpbb\controller\helper $helper Controller helper object
* @param \phpbbstudio\ass\items\manager $items_manager Items manager object
* @param \phpbb\language\language $language Language object
* @param \phpbbstudio\ass\helper\log $log Log helper object
* @param \phpbb\log\log $log_phpbb Log object
* @param \phpbbstudio\ass\operator\category $operator_cat Category operator object
* @param \phpbbstudio\ass\operator\inventory $operator_inv Inventory operator object
* @param \phpbbstudio\ass\operator\item $operator_item Item operator object
* @param \phpbbstudio\ass\notification\notification $notification Notification helper object
* @param \phpbb\pagination $pagination Pagination object
* @param \phpbb\request\request $request Request object
* @param \phpbbstudio\ass\helper\router $router Router helper object
* @param \phpbb\template\template $template Template object
* @param \phpbbstudio\ass\helper\time $time Time helper object
* @param \phpbb\user $user User object
* @param \phpbb\user_loader $user_loader User loader object
* @return void
* @access public
*/
public function __construct(
\phpbbstudio\aps\points\distributor $aps_distributor,
\phpbbstudio\aps\core\functions $aps_functions,
\phpbb\auth\auth $auth,
\phpbb\config\config $config,
\phpbbstudio\ass\helper\controller $controller,
\phpbb\controller\helper $helper,
\phpbbstudio\ass\items\manager $items_manager,
\phpbb\language\language $language,
\phpbbstudio\ass\helper\log $log,
\phpbb\log\log $log_phpbb,
\phpbbstudio\ass\operator\category $operator_cat,
\phpbbstudio\ass\operator\inventory $operator_inv,
\phpbbstudio\ass\operator\item $operator_item,
\phpbbstudio\ass\notification\notification $notification,
\phpbb\pagination $pagination,
\phpbb\request\request $request,
\phpbbstudio\ass\helper\router $router,
\phpbb\template\template $template,
\phpbbstudio\ass\helper\time $time,
\phpbb\user $user,
\phpbb\user_loader $user_loader
)
{
$this->aps_distributor = $aps_distributor;
$this->aps_functions = $aps_functions;
$this->auth = $auth;
$this->config = $config;
$this->controller = $controller;
$this->helper = $helper;
$this->items_manager = $items_manager;
$this->language = $language;
$this->log = $log;
$this->log_phpbb = $log_phpbb;
$this->operator_cat = $operator_cat;
$this->operator_inv = $operator_inv;
$this->operator_item = $operator_item;
$this->notification = $notification;
$this->pagination = $pagination;
$this->request = $request;
$this->router = $router;
$this->template = $template;
$this->time = $time;
$this->user = $user;
$this->user_loader = $user_loader;
}
/**
* Handle the purchase/gift action.
*
* @param string $category_slug The category slug
* @param string $item_slug The item slug
* @param bool $purchase Whether it's a purchase or a gift
* @return Response
* @access public
*/
public function purchase($category_slug, $item_slug, $purchase)
{
$this->controller->check_shop();
if (!$this->user->data['is_registered'])
{
throw new shop_exception(401, 'ASS_ERROR_NOT_AUTH_PURCHASE');
}
$category = $this->operator_cat->load_entity($category_slug);
$item = $this->operator_item->load_entity($item_slug, $category->get_slug(), $category->get_id());
$this->template->assign_vars($this->operator_item->get_variables($item));
if ($purchase && !$this->auth->acl_get('u_ass_can_purchase'))
{
throw new shop_exception(403, 'ASS_ERROR_NOT_AUTH_PURCHASE');
}
if (!$this->operator_item->is_available($item))
{
throw new shop_exception(410, 'ASS_ERROR_NOT_AVAILABLE');
}
if (!$purchase)
{
if (!$this->auth->acl_get('u_ass_can_gift'))
{
throw new shop_exception(403, 'ASS_ERROR_NOT_AUTH_GIFT');
}
if (!$item->get_gift())
{
throw new shop_exception(400, 'ASS_ERROR_NOT_GIFTABLE');
}
}
if (!$this->operator_inv->check_price($item, $purchase))
{
throw new shop_exception(400, 'ASS_ERROR_NOT_ENOUGH_POINTS', [$this->aps_functions->get_name()]);
}
if (!$item->get_stock() && !$item->get_stock_unlimited())
{
throw new shop_exception(400, 'ASS_ERROR_OUT_OF_STOCK');
}
$stack = 0;
$user_id = 0;
$username = '';
if (confirm_box(true) && !$purchase)
{
$username = $this->request->variable('username', '', true);
$user_id = (int) $this->user_loader->load_user_by_username($username);
$user2 = $this->user_loader->get_user($user_id);
if ($user_id === ANONYMOUS)
{
throw new shop_exception(404, 'NO_USER');
}
if ($user_id === (int) $this->user->data['user_id'])
{
throw new shop_exception(403, 'ASS_ERROR_NOT_GIFT_SELF');
}
$auth2 = new \phpbb\auth\auth;
$auth2->acl($user2);
if (!$auth2->acl_get('u_ass_can_receive_gift'))
{
throw new shop_exception(403, 'ASS_ERROR_NOT_AUTH_RECEIVE');
}
$username = $this->user_loader->get_username($user_id, 'no_profile');
}
if ($purchase || (confirm_box(true) && !$purchase))
{
$stack = $this->operator_inv->get_inventory_stack($item, $user_id);
if ($stack >= $item->get_stack())
{
$message = $purchase ? 'ASS_ERROR_STACK_LIMIT' : 'ASS_ERROR_STACK_LIMIT_USER';
$params = $purchase ? [] : [$username];
throw new shop_exception(409, $message, $params);
}
$auth = !empty($auth2) ? $auth2 : $this->auth;
if ($stack && !$auth->acl_get('u_ass_can_stack'))
{
$message = $purchase ? 'ASS_ERROR_STACK_NO_AUTH' : 'ASS_ERROR_STACK_NO_AUTH_USER';
$params = $purchase ? [] : [$username];
throw new shop_exception(409, $message, $params);
}
}
if (!$this->request->is_ajax())
{
$this->controller->create_shop('shop', $category, $item);
}
$l_mode = $purchase ? 'ASS_PURCHASE' : 'ASS_GIFT';
$this->template->assign_vars([
'ASS_ITEM_STACK' => $stack,
'ASS_PURCHASE_PRICE' => $this->operator_inv->get_price($item, $purchase),
'S_ASS_PURCHASE' => $purchase,
]);
if (confirm_box(true))
{
$points_new = $this->operator_inv->add_purchase($item, $user_id, $purchase);
$inventory_id = $this->operator_inv->get_purchase_id();
$item->set_purchases($item->get_purchases() + 1)
->set_stock($item->get_stock() - (int) !$item->get_stock_unlimited())
->save();
if ($item->get_stock() === $item->get_stock_threshold() && !$item->get_stock_unlimited())
{
$this->notification->low_stock($item);
}
if (!$purchase)
{
$this->notification->gift($item, $user_id, $inventory_id, $stack + 1);
if ($this->config['allow_privmsg'] && $this->auth->acl_get('u_sendpm'))
{
$u_pm = $this->router->regular('ucp', [
'i' => 'pm',
'mode' => 'compose',
'u' => $user_id,
], true, $this->request->is_ajax());
}
}
$this->log->add($item, true, $this->operator_inv->get_price($item), $user_id);
$this->template->assign_vars([
'NEW_USER_POINTS' => $points_new,
'RECIPIENT_NAME' => $username,
'U_SEND_PM' => !empty($u_pm) ? $u_pm : '',
]);
if ($this->request->is_ajax())
{
$this->template->set_filenames([
'body' => 'ass_purchase_ajax.html',
]);
$this->template->assign_var('S_PURCHASE_SUCCESS', true);
return new JsonResponse([
'MESSAGE_TITLE' => $this->language->lang($l_mode),
'MESSAGE_TEXT' => $this->template->assign_display('body'),
'id' => $item->get_id(),
'points' => $this->aps_functions->display_points($points_new, false),
'stock' => !$item->get_stock_unlimited() ? $item->get_stock() : false,
]);
}
else
{
return $this->helper->render('ass_purchase.html', $this->language->lang($l_mode));
}
}
else
{
$ajax = $this->request->is_ajax() ? '_ajax' : '';
$body = "ass_purchase{$ajax}.html";
confirm_box(false, $l_mode, '', $body, $this->helper->get_current_url());
return new RedirectResponse($this->router->item($category->get_slug(), $item->get_slug()));
}
}
/**
* Display the inventory and handle any actions.
*
* @param string $category_slug The category slug
* @param string $item_slug The item slug
* @param int $index The item index
* @param string $action The action
* @return Response
* @access public
*/
public function inventory($category_slug, $item_slug, $index, $action)
{
$index0 = (int) $index - 1;
$this->controller->check_shop();
$this->operator_inv->clean_inventory();
$category = $category_slug ? $this->operator_cat->load_entity($category_slug) : null;
$item = $item_slug ? $this->operator_item->load_entity($item_slug, $category->get_slug(), $category->get_id()) : null;
$s_category = $category !== null;
$s_item = $item !== null;
$inventory = $this->operator_inv->get_inventory($category);
$cat_ids = array_column($inventory, 'category_id');
$item_ids = array_column($inventory, 'item_id', 'inventory_id');
$categories = $this->operator_cat->get_categories_by_id($cat_ids);
$items = $this->operator_item->get_items_by_id($item_ids);
$variables = [];
$item_map = [];
foreach ($item_ids as $inventory_id => $item_id)
{
$item_map[$item_id] = array_keys($item_ids, $item_id);
}
if ($s_item && !in_array($item->get_id(), array_keys($items)))
{
throw new shop_exception(404, 'ASS_ERROR_NOT_OWNED');
}
$this->controller->create_shop('inventory', $category);
if ($s_category && $s_item && !empty($action))
{
$type = $this->items_manager->get_type($item->get_type());
if ($type === null)
{
$this->log_phpbb->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_ACP_ASS_ITEM_TYPE_ERROR', time(), [$category->get_title(), $item->get_title()]);
throw new shop_item_exception(404, 'ASS_ITEM_TYPE_NOT_EXIST');
}
$row = $this->operator_inv->get_inventory_item($item, $index0);
switch ($action)
{
case 'activate':
$type->set_category($category);
$type->set_item($item);
if (confirm_box(true))
{
try
{
$success = $type->activate($item->get_data());
}
catch (shop_item_exception $e)
{
$this->log_phpbb->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_ACP_ASS_ITEM_TYPE_ERROR', time(), [$category->get_title(), $item->get_title()]);
if (!$item->get_conflict())
{
if ($this->config['ass_deactivate_conflicts'])
{
$item->set_active(false);
}
$item->set_conflict(true)
->save();
$category->set_conflicts($category->get_conflicts() + 1)
->save();
}
throw $e;
}
$message = !empty($success) ? $this->language->lang($type->get_language('success')) : 'Some error message';
$title = !empty($success) ? $this->language->lang($type->get_language('title')) : $this->language->lang('INFORMATION');
$count = (int) $row['use_count'];
if (!empty($success) && empty($success['file']))
{
$count++;
}
$limit = $item->get_count() && $item->get_count() === $count;
$delete = !$item->get_delete_seconds() && $limit;
$file = !empty($success['file']) ? $success['file'] : false;
if ($file)
{
$limit = $item->get_count() && $item->get_count() === ($count + 1);
$delete = !$item->get_delete_seconds() && $limit;
$u_file = $this->router->inventory($item->get_category_slug(), $item->get_slug(), $index, 'download', ['hash' => generate_link_hash($file)]);
}
else if (!empty($success))
{
$data = [
'use_count' => $count,
'use_time' => time(),
];
$delete
? $this->operator_inv->delete($row['inventory_id'])
: $this->operator_inv->activated($row['inventory_id'], $data);
$data['use_time'] = $this->user->format_date($data['use_time']);
$this->log->add($item, false);
}
if ($this->request->is_ajax())
{
if ($delete)
{
$inventory_ids = $item_map[$item->get_id()];
unset($inventory_ids[array_search($row['inventory_id'], $inventory_ids)]);
if (!empty($inventory_ids))
{
$inventory_ids = array_values($inventory_ids);
// Get the first inventory row
$row = $inventory[$inventory_ids[0]];
$stack = $this->get_stack_info($inventory_ids, $index0);
$vars = $this->get_inventory_variables($category, $item, $row, $stack);
if (!empty($vars['BACKGROUND_SRC']))
{
// Fix the incorrect web root path
$vars['BACKGROUND_SRC'] = $this->operator_item->get_absolute_background_path($vars['BACKGROUND_SRC']);
}
$this->template->set_filenames(['item' => '@phpbbstudio_ass/ass_item_inventory.html']);
$this->template->assign_vars(['item' => $vars]);
$next_item = $this->template->assign_display('item');
}
}
return new JsonResponse([
'MESSAGE_TITLE' => $title,
'MESSAGE_TEXT' => $message,
'success' => $success,
'delete' => $delete,
'limit' => $limit ? $this->language->lang('ASS_ITEM_USE_REACHED') : false,
'id' => $item->get_id(),
'data' => !empty($data) ? $data : false,
'file' => !empty($u_file) ? $u_file . '&force=1' : false,
'item' => !empty($next_item) ? $next_item : false,
'index' => $index,
]);
}
else
{
if (!empty($u_file))
{
return new RedirectResponse($u_file);
}
return $this->helper->message($message);
}
}
else
{
confirm_box(false, $type->get_language(), '', $type->get_confirm_template($item->get_data()), $this->helper->get_current_url());
return new RedirectResponse($this->router->inventory($item->get_category_slug(), $item->get_slug(), $index));
}
break;
case 'download':
$hash = $this->request->variable('hash', '', true);
$data = $type->activate($item->get_data());
if (empty($data['file']))
{
break;
}
$file = $data['file'];
if (check_link_hash($hash, $file) && $this->request->is_set('force', \phpbb\request\request_interface::GET))
{
$count = (int) $row['use_count'] + 1;
$limit = $item->get_count() && $item->get_count() === $count;
$delete = !$item->get_delete_seconds() && $limit;
$data = [
'use_count' => $count,
'use_time' => time(),
];
$delete
? $this->operator_inv->delete($row['inventory_id'])
: $this->operator_inv->activated($row['inventory_id'], $data);
$data['use_time'] = $this->user->format_date($data['use_time']);
$this->log->add($item, false);
return $this->download($file);
}
else if ($this->request->is_set('hash', \phpbb\request\request_interface::GET))
{
$u_file = $this->router->inventory($item->get_category_slug(), $item->get_slug(), $index, 'download', ['hash' => $hash, 'force' => true]);
$this->template->assign_var('U_DOWNLOAD_FILE', $u_file);
}
break;
case 'delete':
case 'refund':
$l_action = 'ASS_' . utf8_strtoupper($action);
if (confirm_box(true))
{
if ($action === 'refund')
{
if (!empty($row['use_count']))
{
throw new shop_exception(403, 'ASS_ERROR_NOT_REFUND');
}
$points = $this->aps_functions->equate_points($this->user->data['user_points'], $row['purchase_price']);
$points = $this->aps_functions->boundaries($points);
$points = $this->aps_functions->format_points($points);
$this->aps_distributor->update_points($points);
$item->set_purchases($item->get_purchases() - 1)
->set_stock($item->get_stock() + (int) !$item->get_stock_unlimited())
->save();
}
$this->operator_inv->delete($row['inventory_id']);
if ($this->request->is_ajax())
{
$inventory_ids = $item_map[$item->get_id()];
unset($inventory_ids[array_search($row['inventory_id'], $inventory_ids)]);
if (!empty($inventory_ids))
{
$inventory_ids = array_values($inventory_ids);
// Get the first inventory row
$row = $inventory[$inventory_ids[0]];
$stack = $this->get_stack_info($inventory_ids, $index0);
$vars = $this->get_inventory_variables($category, $item, $row, $stack);
if (!empty($vars['BACKGROUND_SRC']))
{
// Fix the incorrect web root path
$vars['BACKGROUND_SRC'] = $this->operator_item->get_absolute_background_path($vars['BACKGROUND_SRC']);
}
$this->template->set_filenames(['item' => '@phpbbstudio_ass/ass_item_inventory.html']);
$this->template->assign_vars(['item' => $vars]);
$next_item = $this->template->assign_display('item');
}
return new JsonResponse([
'MESSAGE_TITLE' => $this->language->lang($l_action),
'MESSAGE_TEXT' => $this->language->lang($l_action . '_SUCCESS'),
'id' => $item->get_id(),
'item' => !empty($next_item) ? $next_item : false,
'index' => $index,
]);
}
else
{
return $this->helper->message($l_action . '_SUCCESS');
}
}
else
{
$body = $this->request->is_ajax() ? '@phpbbstudio_ass/ass_confirm_body.html' : 'confirm_body.html';
confirm_box(false, $l_action, '', $body, $this->helper->get_current_url());
return new RedirectResponse($this->helper->route('phpbbstudio_ass_inventory'));
}
break;
}
}
$counts = [
'expire' => 0,
'gifts' => 0,
'total' => 0,
];
/** @var category $cat */
foreach ($categories as $cat)
{
$this->template->assign_block_vars('ass_categories', $this->operator_cat->get_variables($cat));
/** @var item $it */
foreach ($items as $it)
{
if ($it->get_category() === $cat->get_id())
{
$inventory_ids = $item_map[$it->get_id()];
$inventory_id = $inventory_ids[0];
$s_this_item = $s_item && $item->get_id() === $it->get_id();
if ($s_this_item)
{
if (isset($inventory_ids[$index0]))
{
$inventory_id = $inventory_ids[$index0];
}
else
{
throw new shop_exception(404, 'ASS_ERROR_NOT_OWNED_STACK');
}
}
// Get the first inventory row
$row = $inventory[$inventory_id];
$stack = $this->get_stack_info($inventory_ids, $index0);
$vars = $this->get_inventory_variables($cat, $it, $row, $stack, $index, $counts);
$this->template->assign_block_vars('ass_categories.items', $vars);
if (empty($variables) && $s_this_item)
{
$variables = $vars;
}
}
}
}
if (!empty($variables['S_TYPE_ERROR']))
{
$this->log_phpbb->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_ACP_ASS_ITEM_TYPE_ERROR', time(), [$category->get_title(), $item->get_title()]);
}
$this->template->assign_vars([
'ITEM_INFO' => $variables,
'COUNT_EXPIRE' => $counts['expire'],
'COUNT_GIFTS' => $counts['gifts'],
'COUNT_TOTAL' => $counts['total'],
'S_IS_GIFT' => $action === 'gift',
'T_SHOP_ICON' => $s_category ? $category->get_icon() : $this->config['ass_inventory_icon'],
'L_VIEW_SHOP' => $s_category ? $category->get_title() : $this->language->lang('ASS_SHOP_INDEX'),
'U_VIEW_SHOP' => $s_category ? $this->router->category($category->get_slug()) : $this->helper->route('phpbbstudio_ass_shop'),
]);
return $this->helper->render('ass_inventory.html', $this->language->lang('ASS_INVENTORY'));
}
/**
* Display the history page.
*
* @param int $page The page number
* @return Response
* @access public
*/
public function history($page)
{
$this->controller->check_shop();
$this->controller->create_shop_crumbs('history');
$points_name = $this->aps_functions->get_name();
$points_new = $this->language->lang('ASS_POINTS_NEW', $points_name);
$points_old = $this->language->lang('ASS_POINTS_OLD', $points_name);
$show_array = [
'all' => ['title' => 'ASS_ALL', 'sql' => ''],
'use' => ['title' => 'ASS_USAGES', 'sql' => 'l.item_purchase = 0'],
'buy' => ['title' => 'ASS_PURCHASES', 'sql' => 'l.item_purchase = 1'],
'given' => ['title' => 'ASS_GIFTS_GIVEN', 'sql' => 'l.item_purchase = 1 AND l.recipient_id <> 0'],
'received' => ['title' => 'ASS_GIFTS_RECEIVED', 'sql' => 'l.recipient_id = ' . (int) $this->user->data['user_id']],
];
$sort_array = [
'time' => ['title' => 'TIME', 'sql' => 'l.log_time'],
'old' => ['title' => $points_old, 'sql' => 'l.points_old'],
'new' => ['title' => $points_new, 'sql' => 'l.points_new'],
'price' => ['title' => 'ASS_ITEM_PRICE', 'sql' => 'l.points_sum'],
'item' => ['title' => 'ASS_ITEM_TITLE', 'sql' => 'i.item_title'],
'category' => ['title' => 'ASS_CATEGORY_TITLE', 'sql' => 'c.category_title'],
'recipient' => ['title' => 'ASS_RECIPIENT_NAME', 'sql' => 'recipient_name'],
];
$dir_array = [
'desc' => ['title' => 'DESCENDING', 'sql' => 'DESC'],
'asc' => ['title' => 'ASCENDING', 'sql' => 'ASC'],
];
$show = $this->request->variable('display', 'all', true, \phpbb\request\request_interface::GET);
$sort = $this->request->variable('sort', 'time', true, \phpbb\request\request_interface::GET);
$dir = $this->request->variable('direction', 'desc', true, \phpbb\request\request_interface::GET);
$show = in_array($show, array_keys($show_array)) ? $show : 'all';
$sort = in_array($sort, array_keys($sort_array)) ? $sort : 'time';
$dir = in_array($dir, array_keys($dir_array)) ? $dir : 'desc';
$sql_where = $show_array[$show]['sql'];
$sql_order = $sort_array[$sort]['sql'];
$sql_dir = $dir_array[$dir]['sql'];
$limit = (int) $this->config['ass_logs_per_page'];
$start = ($page - 1) * $limit;
$total = $this->log->get_user_logs_count($sql_where, $this->user->data['user_id']);
$rowset = $this->log->get_user_logs($sql_where, $sql_order, $sql_dir, $limit, $start, $this->user->data['user_id']);
$categories = $this->operator_cat->get_categories_by_id(array_column($rowset, 'category_id'));
$items = $this->operator_item->get_items_by_id(array_column($rowset, 'item_id'));
foreach ($rowset as $row)
{
$category_id = (int) $row['category_id'];
$item_id = (int) $row['item_id'];
/** @var category $category */
$category = !empty($categories[$category_id]) ? $categories[$category_id] : null;
/** @var item $item */
$item = !empty($items[$item_id]) ? $items[$item_id] : null;
/** @var item_type $type */
$type = $item ? $this->items_manager->get_type($item->get_type()) : null;
$this->template->assign_block_vars('ass_logs', [
'CATEGORY_TITLE' => $category ? $category->get_title() : $this->language->lang('ASS_UNAVAILABLE_CATEGORY'),
'ITEM_TITLE' => $item ? $item->get_title() : $this->language->lang('ASS_UNAVAILABLE_ITEM'),
'LOG_ACTION' => $type ? $this->language->lang($type->get_language('log')) : $this->language->lang('ASS_UNAVAILABLE_' . (!$item ? 'ITEM' : 'TYPE')),
'LOG_ID' => $row['log_id'],
'LOG_IP' => $row['log_ip'],
'LOG_TIME' => $this->user->format_date($row['log_time']),
'POINTS_NEW' => $row['points_new'],
'POINTS_OLD' => $row['points_old'],
'POINTS_SUM' => -$row['points_sum'],
'RECIPIENT' => $row['recipient_id'] ? get_username_string('full', $row['recipient_id'], $row['recipient_name'], $row['recipient_colour']) : '',
'USER' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']),
'S_PURCHASE' => $row['item_purchase'],
'S_GIFT_RECEIVE' => $row['recipient_id'] == $this->user->data['user_id'],
'U_CATEGORY' => $category ? $this->router->category($category->get_slug()) : '',
'U_ITEM' => $item ? $this->router->item($item->get_category_slug(), $item->get_slug()) : '',
]);
}
$this->pagination->generate_template_pagination([
'routes' => ['phpbbstudio_ass_history', 'phpbbstudio_ass_history_pagination'],
'params' => ['display' => $show, 'sort' => $sort, 'direction' => $dir],
], 'shop_pagination', 'page', $total, $limit, $start);
$this->template->assign_vars([
'SORT_DISPLAY' => $show,
'SORT_DISPLAY_ARRAY' => $show_array,
'SORT_SORT' => $sort,
'SORT_SORT_ARRAY' => $sort_array,
'SORT_DIR' => $dir,
'SORT_DIR_ARRAY' => $dir_array,
'TOTAL_LOGS' => $this->language->lang('TOTAL_LOGS', $total),
'S_ASS_INVENTORY' => true,
]);
return $this->helper->render('ass_history.html', $this->language->lang('ASS_INVENTORY'));
}
/**
* Create a download response for a specific file.
*
* @param string $file The file name
* @return Response
* @access protected
*/
protected function download($file)
{
$response = new Response($file);
$response->headers->set('Content-type', 'application/octet-stream');
$response->headers->set('Content-Disposition', 'attachment; filename="' . basename($file) . '";');
$response->headers->set('Content-length', filesize($file));
$response->sendHeaders();
$response->setContent(readfile($file));
return $response;
}
/**
* Get an inventory item's template variables.
*
* @param category $category The category entity
* @param item $item The item entity
* @param array $row The inventory row
* @param array $stack The item stack information
* @param int $index The item index
* @param array $counts The inventory overview counts
* @return array The inventory item template variables
* @access protected
*/
protected function get_inventory_variables(category $category, item $item, array $row, array $stack, $index = 1, array &$counts = [])
{
/** @var item_type $type */
$type = $this->items_manager->get_type($item->get_type());
$s_type = $type !== null;
if ($s_type)
{
$type->set_category($category);
$type->set_item($item);
}
$s_has_expired = $this->time->has_expired($row['purchase_time'], $item->get_expire_seconds());
$s_will_expire = $this->time->will_expire($row['purchase_time'], $item->get_expire_seconds());
if (!empty($counts))
{
$counts = [
'expire' => !$s_has_expired && $s_will_expire ? $counts['expire'] + 1 : $counts['expire'],
'gifts' => $row['gifter_id'] ? $counts['gifts'] + 1 : $counts['gifts'],
'total' => $counts['total'] + $stack['count'],
];
}
return array_merge($this->operator_item->get_variables($item, '', true, $index), [
'ACTIVATE' => $s_type ? $this->language->lang($type->get_language('action')) : '',
'GIFTER_NAME' => $row['gifter_id'] ? get_username_string('full', $row['gifter_id'], $row['gifter_name'], $row['gifter_colour']) : '',
'PURCHASE_UNIX' => (int) $row['purchase_time'],
'STACK_COUNT' => (int) $stack['count'],
'USE_COUNT' => (int) $row['use_count'],
'USE_UNIX' => (int) $row['use_time'],
'S_AJAX' => $s_type ? $type->get_confirm_ajax() : '',
'S_GIFTED' => !empty($row['gifter_id']),
'S_LIMIT' => $item->get_count() && (int) $row['use_count'] >= $item->get_count(),
'S_REFUND' => $item->get_refund_seconds() && !$row['use_count'] ? (int) $row['purchase_time'] + $item->get_refund_seconds() > time() : false,
'S_HAS_EXPIRED' => $s_has_expired,
'S_WILL_EXPIRE' => $s_will_expire,
'S_TYPE_ERROR' => !$s_type,
'U_STACK_NEXT' => $stack['next'] ? $this->router->inventory($item->get_category_slug(), $item->get_slug(), $stack['next']) : '',
'U_STACK_PREV' => $stack['prev'] ? $this->router->inventory($item->get_category_slug(), $item->get_slug(), $stack['prev']) : '',
]);
}
/**
* Calculate an inventory item's stacking information.
*
* @param array $array The inventory identifiers
* @param int $index The current index (0 based)
* @return array The stacking information
* @access protected
*/
protected function get_stack_info(array $array, $index)
{
// The amount of inventory items for this specific item
$count = count($array);
// Whether or not the current item index is the first or the last
$prev = $index !== 0 ? $index - 1 : false;
$next = $index < ($count - 1) ? $index + 1 : false;
/**
* Because the array with inventory identifiers is 0-based,
* but we use a 1-based approach for routes,
* we have to increment the previous and next indices by 1.
*/
$prev = $prev !== false ? $prev + 1 : 0;
$next = $next !== false ? $next + 1 : 0;
return [
'count' => (int) $count,
'next' => (int) $next,
'prev' => (int) $prev,
];
}
}

View File

@@ -0,0 +1,333 @@
<?php
/**
*
* phpBB Studio - Advanced Shop System. An extension for the phpBB Forum Software package.
*
* @copyright (c) 2019, phpBB Studio, https://www.phpbbstudio.com
* @license GNU General Public License, version 2 (GPL-2.0)
*
*/
namespace phpbbstudio\ass\controller;
use phpbbstudio\ass\exceptions\shop_exception;
use Symfony\Component\HttpFoundation\Response;
/**
* phpBB Studio - Advanced Shop System: Shop controller
*/
class shop_controller
{
/** @var \phpbb\config\config */
protected $config;
/** @var \phpbbstudio\ass\helper\controller */
protected $controller;
/** @var \phpbb\db\driver\driver_interface */
protected $db;
/** @var \phpbb\controller\helper */
protected $helper;
/** @var \phpbbstudio\ass\items\manager */
protected $items_manager;
/** @var \phpbb\language\language */
protected $language;
/** @var \phpbbstudio\ass\operator\category */
protected $operator_cat;
/** @var \phpbbstudio\ass\operator\item */
protected $operator_item;
/** @var \phpbb\pagination */
protected $pagination;
/** @var \phpbb\request\request */
protected $request;
/** @var \phpbb\template\template */
protected $template;
/**
* Constructor.
*
* @param \phpbb\config\config $config Config object
* @param \phpbbstudio\ass\helper\controller $controller ASS Controller helper object
* @param \phpbb\db\driver\driver_interface $db Database object
* @param \phpbb\controller\helper $helper Controller helper object
* @param \phpbbstudio\ass\items\manager $items_manager Items manager object
* @param \phpbb\language\language $language Language object
* @param \phpbbstudio\ass\operator\category $operator_cat Category operator object
* @param \phpbbstudio\ass\operator\item $operator_item Item operator object
* @param \phpbb\pagination $pagination Pagination object
* @param \phpbb\request\request $request Request object
* @param \phpbb\template\template $template Template object
* @return void
* @access public
*/
public function __construct(
\phpbb\config\config $config,
\phpbbstudio\ass\helper\controller $controller,
\phpbb\db\driver\driver_interface $db,
\phpbb\controller\helper $helper,
\phpbbstudio\ass\items\manager $items_manager,
\phpbb\language\language $language,
\phpbbstudio\ass\operator\category $operator_cat,
\phpbbstudio\ass\operator\item $operator_item,
\phpbb\pagination $pagination,
\phpbb\request\request $request,
\phpbb\template\template $template
)
{
$this->config = $config;
$this->controller = $controller;
$this->db = $db;
$this->helper = $helper;
$this->items_manager = $items_manager;
$this->language = $language;
$this->operator_cat = $operator_cat;
$this->operator_item = $operator_item;
$this->pagination = $pagination;
$this->request = $request;
$this->template = $template;
}
/**
* Display the shop index.
*
* @return Response
* @access public
*/
public function shop()
{
$this->controller->check_shop();
$this->controller->create_shop('shop');
$this->controller->setup_carousel();
$this->controller->setup_panels();
$panels = [
'limited' => ['carousel' => true, 'title' => 'ASS_ITEMS_LIMITED'],
'recent' => ['carousel' => true, 'title' => 'ASS_ITEMS_RECENT'],
'sale' => ['carousel' => true, 'title' => 'ASS_SALE_ITEMS'],
'featured' => ['carousel' => true, 'title' => 'ASS_FEATURED_ITEMS'],
'featured_sale' => ['carousel' => false],
'random' => ['carousel' => false],
];
uksort($panels, function($a, $b)
{
if ($this->config["ass_panel_{$a}_order"] == $this->config["ass_panel_{$b}_order"])
{
return 0;
}
return $this->config["ass_panel_{$a}_order"] < $this->config["ass_panel_{$b}_order"] ? -1 : 1;
});
foreach (array_keys($panels) as $panel)
{
if ($this->config["ass_panel_{$panel}_limit"])
{
$this->operator_item->assign_specific_items($panel, $this->config["ass_panel_{$panel}_limit"]);
}
}
$this->template->assign_vars(['ass_panels' => $panels]);
return $this->helper->render('ass_shop.html', $this->language->lang('ASS_SHOP'));
}
/**
* Display a shop category.
*
* @param string $category_slug The category slug
* @param int $page The page number
* @return Response
* @access public
*/
public function category($category_slug, $page = 1)
{
$this->controller->check_shop();
$category = $this->operator_cat->load_entity($category_slug);
$this->controller->create_shop('shop', $category);
$this->controller->setup_panels();
$this->template->assign_vars($this->operator_cat->get_variables($category));
$sql_where = '';
$types = [0 => null];
$type_array = ['ASS_ALL'];
foreach($this->operator_item->get_item_types($category->get_id()) as $type)
{
$types[] = $type;
$type_array[] = $this->items_manager->get_type($type)->get_language('title');
}
$params_array = [
'above' => ['default' => '', 'sql' => 'i.item_price > {VALUE}'],
'below' => ['default' => '', 'sql' => 'i.item_price < {VALUE}'],
'gift' => ['default' => 0, 'sql' => 'i.item_gift = {VALUE}'],
'sale' => ['default' => 0, 'sql' => 'i.item_sale_start < ' . time() . ' AND i.item_sale_until < ' . time()],
'type' => ['default' => 0, 'sql' => 'i.item_type = {VALUE}'],
'title' => ['default' => '', 'sql' => $this->db->sql_lower_text('i.item_title') . ' {VALUE}', 'mb' => true],
];
$days_array = [
0 => 'ASS_ALL',
1 => '1_DAY',
7 => '7_DAYS',
14 => '2_WEEKS',
30 => '1_MONTH',
90 => '3_MONTHS',
180 => '6_MONTHS',
365 => '1_YEAR',
];
$sort_array = [
'order' => ['title' => 'ASS_ITEM_ORDER', 'sql' => 'i.item_order'],
'item' => ['title' => 'ASS_ITEM_TITLE', 'sql' => 'i.item_title'],
'price' => ['title' => 'ASS_ITEM_PRICE', 'sql' => 'i.item_price'],
'stock' => ['title' => 'ASS_ITEM_STOCK', 'sql' => 'i.item_stock'],
'time' => ['title' => 'ASS_ITEM_CREATE_TIME', 'sql' => 'i.item_create_time'],
];
$dir_array = [
'desc' => ['title' => 'DESCENDING', 'sql' => 'DESC'],
'asc' => ['title' => 'ASCENDING', 'sql' => 'ASC'],
];
$days = $this->request->variable('days', 0, false, \phpbb\request\request_interface::GET);
$sort = $this->request->variable('sort', 'order', true, \phpbb\request\request_interface::GET);
$dir = $this->request->variable('direction', 'asc', true, \phpbb\request\request_interface::GET);
$dir = in_array($dir, array_keys($dir_array)) ? $dir : 'asc';
$sort = in_array($sort, array_keys($sort_array)) ? $sort : 'order';
$days = in_array($days, array_keys($days_array)) ? $days : 0;
$time = $days * \phpbbstudio\ass\helper\time::DAY;
$params = [
'sort' => $sort,
'direction' => $dir,
];
if ($time)
{
$params['days'] = $days;
$sql_where .= ' AND i.item_create_time > ' . (time() - $time);
}
foreach ($params_array as $key => $param)
{
$value = $this->request->variable(
$key,
$params_array[$key]['default'],
!empty($params_array[$key]['mb']),
\phpbb\request\request_interface::GET
);
if (!empty($value))
{
$params[$key] = $value;
$value_sql = $value !== -1 ? $value : 0;
switch ($key)
{
case 'type':
if (in_array($value, array_keys($type_array)))
{
$value_sql = "'" . $types[$value] . "'";
}
break;
case 'title':
$value_sql = $this->db->sql_like_expression(utf8_strtolower($value_sql) . $this->db->get_any_char());
break;
}
$param_sql = str_replace('{VALUE}', $value_sql, $params_array[$key]['sql']);
$sql_where .= ' AND ' . $param_sql;
$this->template->assign_var('SORT_' . utf8_strtoupper($key), $value);
}
}
$sql_dir = $dir_array[$dir]['sql'];
$sql_order = $sort_array[$sort]['sql'];
$limit = (int) $this->config['ass_items_per_page'];
$start = ($page - 1) * $limit;
$total = $this->operator_item->get_item_count($category->get_id());
$items = $this->operator_item->get_items($category->get_id(), $sql_where, $sql_order, $sql_dir, true, $limit, $start);
foreach ($items as $item)
{
$this->template->assign_block_vars('ass_items', $this->operator_item->get_variables($item));
}
$this->pagination->generate_template_pagination([
'routes' => ['phpbbstudio_ass_category', 'phpbbstudio_ass_category_pagination'],
'params' => array_merge(['category_slug' => $category->get_slug()], $params),
], 'shop_pagination', 'page', $total, $limit, $start);
$this->template->assign_vars([
'ITEMS_COUNT' => $this->language->lang('ASS_ITEMS_COUNT', $total),
'SORT_DAYS' => $days,
'SORT_DAYS_ARRAY' => $days_array,
'SORT_DIR' => $dir,
'SORT_DIR_ARRAY' => $dir_array,
'SORT_SORT' => $sort,
'SORT_SORT_ARRAY' => $sort_array,
'SORT_TYPE_ARRAY' => $type_array,
'T_PANEL_SIZE' => $limit < 8 ? 6 : 3,
]);
return $this->helper->render('ass_category.html', $category->get_title());
}
/**
* Display a shop item.
*
* @param string $category_slug The category slug
* @param string $item_slug The item slug
* @return Response
* @access public
*/
public function item($category_slug, $item_slug)
{
$this->controller->check_shop();
$category = $this->operator_cat->load_entity($category_slug);
$item = $this->operator_item->load_entity($item_slug, $category->get_slug(), $category->get_id());
if (!$this->operator_item->is_available($item))
{
throw new shop_exception(410, 'ASS_ERROR_NOT_AVAILABLE');
}
$this->controller->create_shop('shop', $category, $item);
$this->controller->setup_carousel();
$this->controller->setup_panels();
if ($item->get_related_enabled())
{
$this->operator_item->assign_related_items($item);
}
$this->template->assign_vars($this->operator_item->get_variables($item));
return $this->helper->render('ass_item.html', $item->get_title());
}
}