diff options
38 files changed, 1264 insertions, 263 deletions
diff --git a/phpBB/adm/style/acp_styles.html b/phpBB/adm/style/acp_styles.html index a36d15fe73..43c2f96a65 100644 --- a/phpBB/adm/style/acp_styles.html +++ b/phpBB/adm/style/acp_styles.html @@ -52,6 +52,10 @@ <dd><strong>{STYLE_PATH}</strong></dd> </dl> <dl> + <dt><label>{L_STYLE_VERSION}{L_COLON}</label></dt> + <dd><strong>{STYLE_VERSION}</strong></dd> + </dl> + <dl> <dt><label for="name">{L_COPYRIGHT}{L_COLON}</label></dt> <dd><strong>{STYLE_COPYRIGHT}</strong></dd> </dl> diff --git a/phpBB/assets/javascript/core.js b/phpBB/assets/javascript/core.js index f7ace80705..b079043396 100644 --- a/phpBB/assets/javascript/core.js +++ b/phpBB/assets/javascript/core.js @@ -33,21 +33,28 @@ phpbb.loadingIndicator = function() { if (!$loadingIndicator.is(':visible')) { $loadingIndicator.fadeIn(phpbb.alertTime); - // Wait fifteen seconds and display an error if nothing has been returned by then. + // Wait 60 seconds and display an error if nothing has been returned by then. phpbb.clearLoadingTimeout(); phpbbAlertTimer = setTimeout(function() { - var $alert = $('#phpbb_alert'); - - if ($loadingIndicator.is(':visible')) { - phpbb.alert($alert.attr('data-l-err'), $alert.attr('data-l-timeout-processing-req')); - } - }, 15000); + phpbb.showTimeoutMessage(); + }, 60000); } return $loadingIndicator; }; /** + * Show timeout message + */ +phpbb.showTimeoutMessage = function () { + var $alert = $('#phpbb_alert'); + + if ($loadingIndicator.is(':visible')) { + phpbb.alert($alert.attr('data-l-err'), $alert.attr('data-l-timeout-processing-req')); + } +}; + +/** * Clear loading alert timeout */ phpbb.clearLoadingTimeout = function() { diff --git a/phpBB/docs/events.md b/phpBB/docs/events.md index 2f28307c24..94090b19d1 100644 --- a/phpBB/docs/events.md +++ b/phpBB/docs/events.md @@ -711,6 +711,14 @@ forumlist_body_last_row_after * Since: 3.1.0-b2 * Purpose: Add content after the very last row of the forum list. +index_body_birthday_block_before +=== +* Locations: + + styles/prosilver/template/index_body.html + + styles/subsilver2/template/index_body.html +* Since: 3.1.11-RC1 +* Purpose: Add new statistic blocks before the Birthday block + index_body_block_birthday_append === * Locations: @@ -959,6 +967,20 @@ mcp_topic_postrow_post_details_before * Since: 3.1.10-RC1 * Purpose: Add content before post details in topic moderation +mcp_topic_postrow_post_subject_after +=== +* Locations: + + styles/prosilver/template/mcp_topic.html +* Since: 3.1.11-RC1 +* Purpose: Add content after post subject in topic moderation + +mcp_topic_postrow_post_subject_before +=== +* Locations: + + styles/prosilver/template/mcp_topic.html +* Since: 3.1.11-RC1 +* Purpose: Add content before post subject in topic moderation + mcp_topic_topic_title_after === * Locations: @@ -1963,6 +1985,13 @@ search_results_topic_before * Since: 3.1.0-b4 * Purpose: Add data before search result topics +search_results_topic_title_after +=== +* Locations: + + styles/prosilver/template/search_results.html +* Since: 3.1.11-RC1 +* Purpose: Add data after search results topic title + simple_footer_after === * Locations: diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index c8f6f426c6..5c3c7f30aa 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -26,7 +26,7 @@ if (!defined('IN_PHPBB')) class acp_board { var $u_action; - var $new_config = array(); + var $new_config; function main($id, $mode) { @@ -318,9 +318,9 @@ class acp_board 'title' => 'ACP_COOKIE_SETTINGS', 'vars' => array( 'legend1' => 'ACP_COOKIE_SETTINGS', - 'cookie_domain' => array('lang' => 'COOKIE_DOMAIN', 'validate' => 'string', 'type' => 'text::255', 'explain' => false), - 'cookie_name' => array('lang' => 'COOKIE_NAME', 'validate' => 'string', 'type' => 'text::16', 'explain' => false), - 'cookie_path' => array('lang' => 'COOKIE_PATH', 'validate' => 'string', 'type' => 'text::255', 'explain' => false), + 'cookie_domain' => array('lang' => 'COOKIE_DOMAIN', 'validate' => 'string', 'type' => 'text::255', 'explain' => true), + 'cookie_name' => array('lang' => 'COOKIE_NAME', 'validate' => 'string', 'type' => 'text::16', 'explain' => true), + 'cookie_path' => array('lang' => 'COOKIE_PATH', 'validate' => 'string', 'type' => 'text::255', 'explain' => true), 'cookie_secure' => array('lang' => 'COOKIE_SECURE', 'validate' => 'bool', 'type' => 'radio:disabled_enabled', 'explain' => true), ) ); @@ -454,6 +454,9 @@ class acp_board 'smtp_auth_method' => array('lang' => 'SMTP_AUTH_METHOD', 'validate' => 'string', 'type' => 'select', 'method' => 'mail_auth_select', 'explain' => true), 'smtp_username' => array('lang' => 'SMTP_USERNAME', 'validate' => 'string', 'type' => 'text:25:255', 'explain' => true), 'smtp_password' => array('lang' => 'SMTP_PASSWORD', 'validate' => 'string', 'type' => 'password:25:255', 'explain' => true), + 'smtp_verify_peer' => array('lang' => 'SMTP_VERIFY_PEER', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'smtp_verify_peer_name' => array('lang' => 'SMTP_VERIFY_PEER_NAME', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'smtp_allow_self_signed'=> array('lang' => 'SMTP_ALLOW_SELF_SIGNED','validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'legend3' => 'ACP_SUBMIT_CHANGES', ) @@ -482,7 +485,7 @@ class acp_board $user->add_lang($display_vars['lang']); } - $this->new_config = $config; + $this->new_config = clone $config; $cfg_array = (isset($_REQUEST['config'])) ? utf8_normalize_nfc(request_var('config', array('' => ''), true)) : $this->new_config; $error = array(); diff --git a/phpBB/includes/acp/acp_extensions.php b/phpBB/includes/acp/acp_extensions.php index 5a2ded91e2..f0348817c8 100644 --- a/phpBB/includes/acp/acp_extensions.php +++ b/phpBB/includes/acp/acp_extensions.php @@ -22,21 +22,23 @@ if (!defined('IN_PHPBB')) class acp_extensions { var $u_action; + var $tpl_name; + var $page_title; - private $db; private $config; private $template; private $user; private $cache; private $log; private $request; + private $phpbb_dispatcher; + private $ext_manager; function main() { // Start the page - global $config, $user, $template, $request, $phpbb_extension_manager, $db, $phpbb_root_path, $phpEx, $phpbb_log, $cache, $phpbb_dispatcher; + global $config, $user, $template, $request, $phpbb_extension_manager, $phpbb_root_path, $phpEx, $phpbb_log, $cache, $phpbb_dispatcher; - $this->db = $db; $this->config = $config; $this->template = $template; $this->user = $user; @@ -44,49 +46,57 @@ class acp_extensions $this->request = $request; $this->log = $phpbb_log; $this->phpbb_dispatcher = $phpbb_dispatcher; + $this->ext_manager = $phpbb_extension_manager; - $user->add_lang(array('install', 'acp/extensions', 'migrator')); + $this->user->add_lang(array('install', 'acp/extensions', 'migrator')); $this->page_title = 'ACP_EXTENSIONS'; - $action = $request->variable('action', 'list'); - $ext_name = $request->variable('ext_name', ''); + $action = $this->request->variable('action', 'list'); + $ext_name = $this->request->variable('ext_name', ''); // What is a safe limit of execution time? Half the max execution time should be safe. $safe_time_limit = (ini_get('max_execution_time') / 2); $start_time = time(); + // Cancel action + if ($this->request->is_set_post('cancel')) + { + $action = 'list'; + $ext_name = ''; + } + + if (in_array($action, array('enable', 'disable', 'delete_data')) && !check_link_hash($this->request->variable('hash', ''), $action . '.' . $ext_name)) + { + trigger_error('FORM_INVALID', E_USER_WARNING); + } + /** * Event to run a specific action on extension * - * @event core.acp_extensions_run_action - * @var string action Action to run + * @event core.acp_extensions_run_action_before + * @var string action Action to run; if the event completes execution of the action, should be set to 'none' * @var string u_action Url we are at * @var string ext_name Extension name from request * @var int safe_time_limit Safe limit of execution time * @var int start_time Start time + * @var string tpl_name Template file to load * @since 3.1.11-RC1 + * @changed 3.2.1-RC1 Renamed to core.acp_extensions_run_action_before, added tpl_name, added action 'none' */ $u_action = $this->u_action; - $vars = array('action', 'u_action', 'ext_name', 'safe_time_limit', 'start_time'); - extract($this->phpbb_dispatcher->trigger_event('core.acp_extensions_run_action', compact($vars))); - - // Cancel action - if ($request->is_set_post('cancel')) - { - $action = 'list'; - $ext_name = ''; - } + $tpl_name = ''; + $vars = array('action', 'u_action', 'ext_name', 'safe_time_limit', 'start_time', 'tpl_name'); + extract($this->phpbb_dispatcher->trigger_event('core.acp_extensions_run_action_before', compact($vars))); - if (in_array($action, array('enable', 'disable', 'delete_data')) && !check_link_hash($request->variable('hash', ''), $action . '.' . $ext_name)) - { - trigger_error('FORM_INVALID', E_USER_WARNING); - } + // In case they have been updated by the event + $this->u_action = $u_action; + $this->tpl_name = $tpl_name; // If they've specified an extension, let's load the metadata manager and validate it. if ($ext_name) { - $md_manager = new \phpbb\extension\metadata_manager($ext_name, $config, $phpbb_extension_manager, $template, $user, $phpbb_root_path); + $md_manager = $this->ext_manager->create_extension_metadata_manager($ext_name, $this->template); try { @@ -101,6 +111,10 @@ class acp_extensions // What are we doing? switch ($action) { + case 'none': + // Intentionally empty, used by extensions that execute additional actions in the prior event + break; + case 'set_config_version_check_force_unstable': $force_unstable = $this->request->variable('force_unstable', false); @@ -110,12 +124,12 @@ class acp_extensions 'force_unstable' => $force_unstable, )); - confirm_box(false, $user->lang('EXTENSION_FORCE_UNSTABLE_CONFIRM'), $s_hidden_fields); + confirm_box(false, $this->user->lang('EXTENSION_FORCE_UNSTABLE_CONFIRM'), $s_hidden_fields); } else { - $config->set('extension_force_unstable', false); - trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); + $this->config->set('extension_force_unstable', false); + trigger_error($this->user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); } break; @@ -123,17 +137,17 @@ class acp_extensions default: if (confirm_box(true)) { - $config->set('extension_force_unstable', true); - trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); + $this->config->set('extension_force_unstable', true); + trigger_error($this->user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); } - $this->list_enabled_exts($phpbb_extension_manager); - $this->list_disabled_exts($phpbb_extension_manager); - $this->list_available_exts($phpbb_extension_manager); + $this->list_enabled_exts(); + $this->list_disabled_exts(); + $this->list_available_exts(); $this->template->assign_vars(array( 'U_VERSIONCHECK_FORCE' => $this->u_action . '&action=list&versioncheck_force=1', - 'FORCE_UNSTABLE' => $config['extension_force_unstable'], + 'FORCE_UNSTABLE' => $this->config['extension_force_unstable'], 'U_ACTION' => $this->u_action, )); @@ -141,30 +155,29 @@ class acp_extensions break; case 'enable_pre': - if (!$md_manager->validate_dir()) + try { - trigger_error($user->lang['EXTENSION_DIR_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); + $md_manager->validate_enable(); } - - if (!$md_manager->validate_enable()) + catch (\phpbb\extension\exception $e) { - trigger_error($user->lang['EXTENSION_NOT_AVAILABLE'] . adm_back_link($this->u_action), E_USER_WARNING); + trigger_error($e . adm_back_link($this->u_action), E_USER_WARNING); } - $extension = $phpbb_extension_manager->get_extension($ext_name); + $extension = $this->ext_manager->get_extension($ext_name); if (!$extension->is_enableable()) { - trigger_error($user->lang['EXTENSION_NOT_ENABLEABLE'] . adm_back_link($this->u_action), E_USER_WARNING); + trigger_error($this->user->lang['EXTENSION_NOT_ENABLEABLE'] . adm_back_link($this->u_action), E_USER_WARNING); } - if ($phpbb_extension_manager->is_enabled($ext_name)) + if ($this->ext_manager->is_enabled($ext_name)) { redirect($this->u_action); } $this->tpl_name = 'acp_ext_enable'; - $template->assign_vars(array( + $this->template->assign_vars(array( 'PRE' => true, 'L_CONFIRM_MESSAGE' => $this->user->lang('EXTENSION_ENABLE_CONFIRM', $md_manager->get_metadata('display-name')), 'U_ENABLE' => $this->u_action . '&action=enable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('enable.' . $ext_name), @@ -172,57 +185,65 @@ class acp_extensions break; case 'enable': - if (!$md_manager->validate_dir()) + try { - trigger_error($user->lang['EXTENSION_DIR_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); + $md_manager->validate_enable(); } - - if (!$md_manager->validate_enable()) + catch (\phpbb\extension\exception $e) { - trigger_error($user->lang['EXTENSION_NOT_AVAILABLE'] . adm_back_link($this->u_action), E_USER_WARNING); + trigger_error($e . adm_back_link($this->u_action), E_USER_WARNING); } - $extension = $phpbb_extension_manager->get_extension($ext_name); + $extension = $this->ext_manager->get_extension($ext_name); if (!$extension->is_enableable()) { - trigger_error($user->lang['EXTENSION_NOT_ENABLEABLE'] . adm_back_link($this->u_action), E_USER_WARNING); + trigger_error($this->user->lang['EXTENSION_NOT_ENABLEABLE'] . adm_back_link($this->u_action), E_USER_WARNING); } try { - while ($phpbb_extension_manager->enable_step($ext_name)) + while ($this->ext_manager->enable_step($ext_name)) { // Are we approaching the time limit? If so we want to pause the update and continue after refreshing if ((time() - $start_time) >= $safe_time_limit) { - $template->assign_var('S_NEXT_STEP', true); + $this->template->assign_var('S_NEXT_STEP', true); meta_refresh(0, $this->u_action . '&action=enable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('enable.' . $ext_name)); } } - $this->log->add('admin', $user->data['user_id'], $user->ip, 'LOG_EXT_ENABLE', time(), array($ext_name)); + + // Update custom style for admin area + $this->template->set_custom_style(array( + array( + 'name' => 'adm', + 'ext_path' => 'adm/style/', + ), + ), array($phpbb_root_path . 'adm/style')); + + $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EXT_ENABLE', time(), array($ext_name)); } catch (\phpbb\db\migration\exception $e) { - $template->assign_var('MIGRATOR_ERROR', $e->getLocalisedMessage($user)); + $this->template->assign_var('MIGRATOR_ERROR', $e->getLocalisedMessage($this->user)); } $this->tpl_name = 'acp_ext_enable'; - $template->assign_vars(array( + $this->template->assign_vars(array( 'U_RETURN' => $this->u_action . '&action=list', )); break; case 'disable_pre': - if (!$phpbb_extension_manager->is_enabled($ext_name)) + if (!$this->ext_manager->is_enabled($ext_name)) { redirect($this->u_action); } $this->tpl_name = 'acp_ext_disable'; - $template->assign_vars(array( + $this->template->assign_vars(array( 'PRE' => true, 'L_CONFIRM_MESSAGE' => $this->user->lang('EXTENSION_DISABLE_CONFIRM', $md_manager->get_metadata('display-name')), 'U_DISABLE' => $this->u_action . '&action=disable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('disable.' . $ext_name), @@ -230,38 +251,38 @@ class acp_extensions break; case 'disable': - if (!$phpbb_extension_manager->is_enabled($ext_name)) + if (!$this->ext_manager->is_enabled($ext_name)) { redirect($this->u_action); } - while ($phpbb_extension_manager->disable_step($ext_name)) + while ($this->ext_manager->disable_step($ext_name)) { // Are we approaching the time limit? If so we want to pause the update and continue after refreshing if ((time() - $start_time) >= $safe_time_limit) { - $template->assign_var('S_NEXT_STEP', true); + $this->template->assign_var('S_NEXT_STEP', true); meta_refresh(0, $this->u_action . '&action=disable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('disable.' . $ext_name)); } } - $this->log->add('admin', $user->data['user_id'], $user->ip, 'LOG_EXT_DISABLE', time(), array($ext_name)); + $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EXT_DISABLE', time(), array($ext_name)); $this->tpl_name = 'acp_ext_disable'; - $template->assign_vars(array( + $this->template->assign_vars(array( 'U_RETURN' => $this->u_action . '&action=list', )); break; case 'delete_data_pre': - if ($phpbb_extension_manager->is_enabled($ext_name)) + if ($this->ext_manager->is_enabled($ext_name)) { redirect($this->u_action); } $this->tpl_name = 'acp_ext_delete_data'; - $template->assign_vars(array( + $this->template->assign_vars(array( 'PRE' => true, 'L_CONFIRM_MESSAGE' => $this->user->lang('EXTENSION_DELETE_DATA_CONFIRM', $md_manager->get_metadata('display-name')), 'U_PURGE' => $this->u_action . '&action=delete_data&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('delete_data.' . $ext_name), @@ -269,33 +290,33 @@ class acp_extensions break; case 'delete_data': - if ($phpbb_extension_manager->is_enabled($ext_name)) + if ($this->ext_manager->is_enabled($ext_name)) { redirect($this->u_action); } try { - while ($phpbb_extension_manager->purge_step($ext_name)) + while ($this->ext_manager->purge_step($ext_name)) { // Are we approaching the time limit? If so we want to pause the update and continue after refreshing if ((time() - $start_time) >= $safe_time_limit) { - $template->assign_var('S_NEXT_STEP', true); + $this->template->assign_var('S_NEXT_STEP', true); meta_refresh(0, $this->u_action . '&action=delete_data&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('delete_data.' . $ext_name)); } } - $this->log->add('admin', $user->data['user_id'], $user->ip, 'LOG_EXT_PURGE', time(), array($ext_name)); + $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EXT_PURGE', time(), array($ext_name)); } catch (\phpbb\db\migration\exception $e) { - $template->assign_var('MIGRATOR_ERROR', $e->getLocalisedMessage($user)); + $this->template->assign_var('MIGRATOR_ERROR', $e->getLocalisedMessage($this->user)); } $this->tpl_name = 'acp_ext_delete_data'; - $template->assign_vars(array( + $this->template->assign_vars(array( 'U_RETURN' => $this->u_action . '&action=list', )); break; @@ -306,28 +327,25 @@ class acp_extensions try { - $updates_available = $this->version_check($md_manager, $request->variable('versioncheck_force', false)); + $updates_available = $this->version_check($md_manager, $this->request->variable('versioncheck_force', false)); - $template->assign_vars(array( + $this->template->assign_vars(array( 'S_UP_TO_DATE' => empty($updates_available), 'S_VERSIONCHECK' => true, 'UP_TO_DATE_MSG' => $this->user->lang(empty($updates_available) ? 'UP_TO_DATE' : 'NOT_UP_TO_DATE', $md_manager->get_metadata('display-name')), )); - foreach ($updates_available as $branch => $version_data) - { - $template->assign_block_vars('updates_available', $version_data); - } + $this->template->assign_block_vars('updates_available', $updates_available); } catch (\RuntimeException $e) { - $template->assign_vars(array( + $this->template->assign_vars(array( 'S_VERSIONCHECK_STATUS' => $e->getCode(), - 'VERSIONCHECK_FAIL_REASON' => ($e->getMessage() !== $user->lang('VERSIONCHECK_FAIL')) ? $e->getMessage() : '', + 'VERSIONCHECK_FAIL_REASON' => ($e->getMessage() !== $this->user->lang('VERSIONCHECK_FAIL')) ? $e->getMessage() : '', )); } - $template->assign_vars(array( + $this->template->assign_vars(array( 'U_BACK' => $this->u_action . '&action=list', 'U_VERSIONCHECK_FORCE' => $this->u_action . '&action=details&versioncheck_force=1&ext_name=' . urlencode($md_manager->get_metadata('name')), )); @@ -335,21 +353,41 @@ class acp_extensions $this->tpl_name = 'acp_ext_details'; break; } + + /** + * Event to run after a specific action on extension has completed + * + * @event core.acp_extensions_run_action_after + * @var string action Action that has run + * @var string u_action Url we are at + * @var string ext_name Extension name from request + * @var int safe_time_limit Safe limit of execution time + * @var int start_time Start time + * @var string tpl_name Template file to load + * @since 3.1.11-RC1 + */ + $u_action = $this->u_action; + $tpl_name = $this->tpl_name; + $vars = array('action', 'u_action', 'ext_name', 'safe_time_limit', 'start_time', 'tpl_name'); + extract($this->phpbb_dispatcher->trigger_event('core.acp_extensions_run_action_after', compact($vars))); + + // In case they have been updated by the event + $this->u_action = $u_action; + $this->tpl_name = $tpl_name; } /** * Lists all the enabled extensions and dumps to the template * - * @param $phpbb_extension_manager An instance of the extension manager * @return null */ - public function list_enabled_exts(\phpbb\extension\manager $phpbb_extension_manager) + public function list_enabled_exts() { $enabled_extension_meta_data = array(); - foreach ($phpbb_extension_manager->all_enabled() as $name => $location) + foreach ($this->ext_manager->all_enabled() as $name => $location) { - $md_manager = $phpbb_extension_manager->create_extension_metadata_manager($name, $this->template); + $md_manager = $this->ext_manager->create_extension_metadata_manager($name, $this->template); try { @@ -397,16 +435,15 @@ class acp_extensions /** * Lists all the disabled extensions and dumps to the template * - * @param $phpbb_extension_manager An instance of the extension manager * @return null */ - public function list_disabled_exts(\phpbb\extension\manager $phpbb_extension_manager) + public function list_disabled_exts() { $disabled_extension_meta_data = array(); - foreach ($phpbb_extension_manager->all_disabled() as $name => $location) + foreach ($this->ext_manager->all_disabled() as $name => $location) { - $md_manager = $phpbb_extension_manager->create_extension_metadata_manager($name, $this->template); + $md_manager = $this->ext_manager->create_extension_metadata_manager($name, $this->template); try { @@ -455,18 +492,17 @@ class acp_extensions /** * Lists all the available extensions and dumps to the template * - * @param $phpbb_extension_manager An instance of the extension manager * @return null */ - public function list_available_exts(\phpbb\extension\manager $phpbb_extension_manager) + public function list_available_exts() { - $uninstalled = array_diff_key($phpbb_extension_manager->all_available(), $phpbb_extension_manager->all_configured()); + $uninstalled = array_diff_key($this->ext_manager->all_available(), $this->ext_manager->all_configured()); $available_extension_meta_data = array(); foreach ($uninstalled as $name => $location) { - $md_manager = $phpbb_extension_manager->create_extension_metadata_manager($name, $this->template); + $md_manager = $this->ext_manager->create_extension_metadata_manager($name, $this->template); try { @@ -535,7 +571,7 @@ class acp_extensions * @param \phpbb\extension\metadata_manager $md_manager The metadata manager for the version to check. * @param bool $force_update Ignores cached data. Defaults to false. * @param bool $force_cache Force the use of the cache. Override $force_update. - * @return string + * @return array * @throws RuntimeException */ protected function version_check(\phpbb\extension\metadata_manager $md_manager, $force_update = false, $force_cache = false) @@ -554,7 +590,7 @@ class acp_extensions $version_helper->set_file_location($version_check['host'], $version_check['directory'], $version_check['filename'], isset($version_check['ssl']) ? $version_check['ssl'] : false); $version_helper->force_stability($this->config['extension_force_unstable'] ? 'unstable' : null); - return $updates = $version_helper->get_suggested_updates($force_update, $force_cache); + return $version_helper->get_ext_update_on_branch($force_update, $force_cache); } /** diff --git a/phpBB/includes/acp/acp_styles.php b/phpBB/includes/acp/acp_styles.php index 5181b87ecb..c29fb062d8 100644 --- a/phpBB/includes/acp/acp_styles.php +++ b/phpBB/includes/acp/acp_styles.php @@ -433,6 +433,9 @@ class acp_styles trigger_error($this->user->lang['NO_MATCHING_STYLES_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); } + // Read style configuration file + $style_cfg = $this->read_style_cfg($style['style_path']); + // Find all available parent styles $list = $this->find_possible_parents($styles, $id); @@ -579,6 +582,7 @@ class acp_styles 'STYLE_ID' => $style['style_id'], 'STYLE_NAME' => htmlspecialchars($style['style_name']), 'STYLE_PATH' => htmlspecialchars($style['style_path']), + 'STYLE_VERSION' => htmlspecialchars($style_cfg['style_version']), 'STYLE_COPYRIGHT' => strip_tags($style['style_copyright']), 'STYLE_PARENT' => $style['style_parent_id'], 'S_STYLE_ACTIVE' => $style['style_active'], diff --git a/phpBB/includes/acp/acp_update.php b/phpBB/includes/acp/acp_update.php index 51ff4870f2..cee2ce222e 100644 --- a/phpBB/includes/acp/acp_update.php +++ b/phpBB/includes/acp/acp_update.php @@ -51,10 +51,7 @@ class acp_update $updates_available = array(); } - foreach ($updates_available as $branch => $version_data) - { - $template->assign_block_vars('updates_available', $version_data); - } + $template->assign_block_vars('updates_available', $updates_available); $update_link = append_sid($phpbb_root_path . 'install/'); diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php index f141637fb9..a6e4cb0679 100644 --- a/phpBB/includes/functions_messenger.php +++ b/phpBB/includes/functions_messenger.php @@ -1046,7 +1046,18 @@ function smtpmail($addresses, $subject, $message, &$err_msg, $headers = false) } $collector = new \phpbb\error_collector; $collector->install(); - $smtp->socket = fsockopen($config['smtp_host'], $config['smtp_port'], $errno, $errstr, 20); + + $options = array(); + $verify_peer = (bool) $config['smtp_verify_peer']; + $verify_peer_name = (bool) $config['smtp_verify_peer_name']; + $allow_self_signed = (bool) $config['smtp_allow_self_signed']; + $remote_socket = $config['smtp_host'] . ':' . $config['smtp_port']; + + // Set ssl context options, see http://php.net/manual/en/context.ssl.php + $options['ssl'] = array('verify_peer' => $verify_peer, 'verify_peer_name' => $verify_peer_name, 'allow_self_signed' => $allow_self_signed); + $socket_context = stream_context_create($options); + + $smtp->socket = stream_socket_client($remote_socket, $errno, $errstr, 20, STREAM_CLIENT_CONNECT, $socket_context); $collector->uninstall(); $error_contents = $collector->format_errors(); diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index ba367e5eeb..32b0149701 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -1315,7 +1315,7 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id */ function delete_post($forum_id, $topic_id, $post_id, &$data, $is_soft = false, $softdelete_reason = '') { - global $db, $user, $auth, $phpbb_container; + global $db, $user, $auth, $phpbb_container, $phpbb_dispatcher; global $config, $phpEx, $phpbb_root_path; // Specify our post mode @@ -1566,6 +1566,34 @@ function delete_post($forum_id, $topic_id, $post_id, &$data, $is_soft = false, $ sync('topic_reported', 'topic_id', array($topic_id)); } + /** + * This event is used for performing actions directly after a post or topic + * has been deleted. + * + * @event core.delete_post_after + * @var int forum_id Post forum ID + * @var int topic_id Post topic ID + * @var int post_id Post ID + * @var array data Post data + * @var bool is_soft Soft delete flag + * @var string softdelete_reason Soft delete reason + * @var string post_mode delete_topic, delete_first_post, delete_last_post or delete + * @var mixed next_post_id Next post ID in the topic (post ID or false) + * + * @since 3.1.11-RC1 + */ + $vars = array( + 'forum_id', + 'topic_id', + 'post_id', + 'data', + 'is_soft', + 'softdelete_reason', + 'post_mode', + 'next_post_id', + ); + extract($phpbb_dispatcher->trigger_event('core.delete_post_after', compact($vars))); + return $next_post_id; } diff --git a/phpBB/includes/mcp/mcp_post.php b/phpBB/includes/mcp/mcp_post.php index 2dcfcd608b..b5f2bf4f02 100644 --- a/phpBB/includes/mcp/mcp_post.php +++ b/phpBB/includes/mcp/mcp_post.php @@ -24,8 +24,8 @@ if (!defined('IN_PHPBB')) */ function mcp_post_details($id, $mode, $action) { - global $phpEx, $phpbb_root_path, $config; - global $template, $db, $user, $auth, $cache; + global $phpEx, $phpbb_root_path, $config, $request; + global $template, $db, $user, $auth, $cache, $phpbb_container; global $phpbb_dispatcher; $user->add_lang('posting'); @@ -355,7 +355,11 @@ function mcp_post_details($id, $mode, $action) // Get IP if ($auth->acl_get('m_info', $post_info['forum_id'])) { - $rdns_ip_num = request_var('rdns', ''); + /** @var \phpbb\pagination $pagination */ + $pagination = $phpbb_container->get('pagination'); + + $rdns_ip_num = $request->variable('rdns', ''); + $start_users = $request->variable('start_users', 0); if ($rdns_ip_num != 'all') { @@ -364,23 +368,46 @@ function mcp_post_details($id, $mode, $action) ); } + $num_users = false; + if ($start_users) + { + $num_users = phpbb_get_num_posters_for_ip($db, $post_info['poster_ip']); + $start_users = $pagination->validate_start($start_users, $config['posts_per_page'], $num_users); + } + // Get other users who've posted under this IP $sql = 'SELECT poster_id, COUNT(poster_id) as postings FROM ' . POSTS_TABLE . " WHERE poster_ip = '" . $db->sql_escape($post_info['poster_ip']) . "' + AND poster_id <> " . (int) $post_info['poster_id'] . " GROUP BY poster_id - ORDER BY postings DESC"; - $result = $db->sql_query($sql); + ORDER BY postings DESC, poster_id ASC"; + $result = $db->sql_query_limit($sql, $config['posts_per_page'], $start_users); + $page_users = 0; while ($row = $db->sql_fetchrow($result)) { - // Fill the user select list with users who have posted under this IP - if ($row['poster_id'] != $post_info['poster_id']) + $page_users++; + $users_ary[$row['poster_id']] = $row; + } + $db->sql_freeresult($result); + + if ($page_users == $config['posts_per_page'] || $start_users) + { + if ($num_users === false) { - $users_ary[$row['poster_id']] = $row; + $num_users = phpbb_get_num_posters_for_ip($db, $post_info['poster_ip']); } + + $pagination->generate_template_pagination( + $url . '&i=main&mode=post_details', + 'pagination', + 'start_users', + $num_users, + $config['posts_per_page'], + $start_users + ); } - $db->sql_freeresult($result); if (sizeof($users_ary)) { @@ -415,16 +442,26 @@ function mcp_post_details($id, $mode, $action) // A compound index on poster_id, poster_ip (posts table) would help speed up this query a lot, // but the extra size is only valuable if there are persons having more than a thousands posts. // This is better left to the really really big forums. + $start_ips = $request->variable('start_ips', 0); + + $num_ips = false; + if ($start_ips) + { + $num_ips = phpbb_get_num_ips_for_poster($db, $post_info['poster_id']); + $start_ips = $pagination->validate_start($start_ips, $config['posts_per_page'], $num_ips); + } $sql = 'SELECT poster_ip, COUNT(poster_ip) AS postings FROM ' . POSTS_TABLE . ' WHERE poster_id = ' . $post_info['poster_id'] . " GROUP BY poster_ip - ORDER BY postings DESC"; - $result = $db->sql_query($sql); + ORDER BY postings DESC, poster_ip ASC"; + $result = $db->sql_query_limit($sql, $config['posts_per_page'], $start_ips); + $page_ips = 0; while ($row = $db->sql_fetchrow($result)) { + $page_ips++; $hostname = (($rdns_ip_num == $row['poster_ip'] || $rdns_ip_num == 'all') && $row['poster_ip']) ? @gethostbyaddr($row['poster_ip']) : ''; $template->assign_block_vars('iprow', array( @@ -439,6 +476,23 @@ function mcp_post_details($id, $mode, $action) } $db->sql_freeresult($result); + if ($page_ips == $config['posts_per_page'] || $start_ips) + { + if ($num_ips === false) + { + $num_ips = phpbb_get_num_ips_for_poster($db, $post_info['poster_id']); + } + + $pagination->generate_template_pagination( + $url . '&i=main&mode=post_details', + 'pagination_ips', + 'start_ips', + $num_ips, + $config['posts_per_page'], + $start_ips + ); + } + $user_select = ''; if (sizeof($usernames_ary)) @@ -457,6 +511,44 @@ function mcp_post_details($id, $mode, $action) } /** + * Get the number of posters for a given ip + * + * @param \phpbb\db\driver\driver_interface $db DBAL interface + * @param string $poster_ip IP + * @return int Number of posters + */ +function phpbb_get_num_posters_for_ip(\phpbb\db\driver\driver_interface $db, $poster_ip) +{ + $sql = 'SELECT COUNT(DISTINCT poster_id) as num_users + FROM ' . POSTS_TABLE . " + WHERE poster_ip = '" . $db->sql_escape($poster_ip) . "'"; + $result = $db->sql_query($sql); + $num_users = (int) $db->sql_fetchfield('num_users'); + $db->sql_freeresult($result); + + return $num_users; +} + +/** + * Get the number of ips for a given poster + * + * @param \phpbb\db\driver\driver_interface $db + * @param int $poster_id Poster user ID + * @return int Number of IPs for given poster + */ +function phpbb_get_num_ips_for_poster(\phpbb\db\driver\driver_interface $db, $poster_id) +{ + $sql = 'SELECT COUNT(DISTINCT poster_ip) as num_ips + FROM ' . POSTS_TABLE . ' + WHERE poster_id = ' . (int) $poster_id; + $result = $db->sql_query($sql); + $num_ips = (int) $db->sql_fetchfield('num_ips'); + $db->sql_freeresult($result); + + return $num_ips; +} + +/** * Change a post's poster */ function change_poster(&$post_info, $userdata) diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index 2217f8fdeb..7dbe7787cb 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -407,6 +407,7 @@ function mcp_topic_view($id, $mode, $action) function split_topic($action, $topic_id, $to_forum_id, $subject) { global $db, $template, $user, $phpEx, $phpbb_root_path, $auth, $config; + global $phpbb_dispatcher; $post_id_list = request_var('post_id_list', array(0)); $forum_id = request_var('forum_id', 0); @@ -567,6 +568,47 @@ function split_topic($action, $topic_id, $to_forum_id, $subject) WHERE post_id = {$post_id_list[0]}"; $db->sql_query($sql); + // Grab data for first post in split topic + $sql_array = array( + 'SELECT' => 'p.post_id, p.forum_id, p.poster_id, p.post_text, f.enable_indexing', + 'FROM' => array( + POSTS_TABLE => 'p', + ), + 'LEFT_JOIN' => array( + array( + 'FROM' => array(FORUMS_TABLE => 'f'), + 'ON' => 'p.forum_id = f.forum_id', + ) + ), + 'WHERE' => "post_id = {$post_id_list[0]}", + ); + $sql = $db->sql_build_query('SELECT', $sql_array); + $result = $db->sql_query($sql); + $first_post_data = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + // Index first post as if it were edited + if ($first_post_data['enable_indexing']) + { + // Select the search method and do some additional checks to ensure it can actually be utilised + $search_type = $config['search_type']; + + if (!class_exists($search_type)) + { + trigger_error('NO_SUCH_SEARCH_MODULE'); + } + + $error = false; + $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher); + + if ($error) + { + trigger_error($error); + } + + $search->index('edit', $first_post_data['post_id'], $first_post_data['post_text'], $subject, $first_post_data['poster_id'], $first_post_data['forum_id']); + } + // Copy topic subscriptions to new topic $sql = 'SELECT user_id, notify_status FROM ' . TOPICS_WATCH_TABLE . ' diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php index d365e8b489..4906eec1bb 100644 --- a/phpBB/includes/ucp/ucp_pm_compose.php +++ b/phpBB/includes/ucp/ucp_pm_compose.php @@ -450,6 +450,17 @@ function compose_pm($id, $mode, $action, $user_folders = array()) $message_attachment = 0; $message_text = $message_subject = ''; + /** + * Predefine message text and subject + * + * @event core.ucp_pm_compose_predefined_message + * @var string message_text Message text + * @var string message_subject Messate subject + * @since 3.1.11-RC1 + */ + $vars = array('message_text', 'message_subject'); + extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_predefined_message', compact($vars))); + if ($to_user_id && $to_user_id != ANONYMOUS && $action == 'post') { $address_list['u'][$to_user_id] = 'to'; diff --git a/phpBB/language/en/acp/attachments.php b/phpBB/language/en/acp/attachments.php index 7d3d93d693..750f2f8d61 100644 --- a/phpBB/language/en/acp/attachments.php +++ b/phpBB/language/en/acp/attachments.php @@ -125,7 +125,7 @@ $lang = array_merge($lang, array( 'MAX_EXTGROUP_FILESIZE' => 'Maximum file size', 'MAX_IMAGE_SIZE' => 'Maximum image dimensions', 'MAX_IMAGE_SIZE_EXPLAIN' => 'Maximum size of image attachments. Set both values to 0px by 0px to disable dimension checking.', - 'MAX_THUMB_WIDTH' => 'Maximum thumbnail width in pixel', + 'MAX_THUMB_WIDTH' => 'Maximum thumbnail width/height in pixel', 'MAX_THUMB_WIDTH_EXPLAIN' => 'A generated thumbnail will not exceed the width set here.', 'MIN_THUMB_FILESIZE' => 'Minimum thumbnail file size', 'MIN_THUMB_FILESIZE_EXPLAIN' => 'Do not create a thumbnail for images smaller than this.', diff --git a/phpBB/language/en/acp/board.php b/phpBB/language/en/acp/board.php index 8b4db6a061..1e77af14b1 100644 --- a/phpBB/language/en/acp/board.php +++ b/phpBB/language/en/acp/board.php @@ -345,11 +345,14 @@ $lang = array_merge($lang, array( // Cookie Settings $lang = array_merge($lang, array( - 'ACP_COOKIE_SETTINGS_EXPLAIN' => 'These details define the data used to send cookies to your users browsers. In most cases the default values for the cookie settings should be sufficient. If you do need to change any do so with care, incorrect settings can prevent users logging in.', + 'ACP_COOKIE_SETTINGS_EXPLAIN' => 'These details define the data used to send cookies to your users browsers. In most cases the default values for the cookie settings should be sufficient. If you do need to change any do so with care, incorrect settings can prevent users logging in. If you have problems with users staying logging in to your board, visit the <b><a href="https://www.phpbb.com/support/go/cookie-settings/">phpBB.com Knowledge Base - Fixing incorrect cookie settings</a></b>.', 'COOKIE_DOMAIN' => 'Cookie domain', + 'COOKIE_DOMAIN_EXPLAIN' => 'In most cases the cookie domain is optional. Leave it blank if you are unsure.<br /><br /> In the case where you have a board integrated with other software or have multiple domains, then to determine the cookie domain you need to do the following. If you have something like <i>example.com</i> and <i>forums.example.com</i>, or perhaps <i>forums.example.com</i> and <i>blog.example.com</i>. Remove the subdomains until you find the common domain, <i>example.com</i>. Now add a dot in front of the common domain and you would enter .example.com (note the dot at the beginning).', 'COOKIE_NAME' => 'Cookie name', + 'COOKIE_NAME_EXPLAIN' => 'This can be anything what you want, make it original. Whenever the cookie settings are changed the name of the cookie should be changed.', 'COOKIE_PATH' => 'Cookie path', + 'COOKIE_PATH_EXPLAIN' => 'Note that this is always a slash, it does not matter what your board URL is.', 'COOKIE_SECURE' => 'Cookie secure', 'COOKIE_SECURE_EXPLAIN' => 'If your server is running via SSL set this to enabled else leave as disabled. Having this enabled and not running via SSL will result in server errors during redirects.', 'ONLINE_LENGTH' => 'View online time span', @@ -558,6 +561,8 @@ $lang = array_merge($lang, array( 'EMAIL_SIG_EXPLAIN' => 'This text will be attached to all emails the board sends.', 'ENABLE_EMAIL' => 'Enable board-wide emails', 'ENABLE_EMAIL_EXPLAIN' => 'If this is set to disabled no emails will be sent by the board at all. <em>Note the user and admin account activation settings require this setting to be enabled. If currently using “user” or “admin” activation in the activation settings, disabling this setting will disable registration.</em>', + 'SMTP_ALLOW_SELF_SIGNED' => 'Allow self-signed SSL certificates', + 'SMTP_ALLOW_SELF_SIGNED_EXPLAIN'=> 'Allow connections to SMTP server with self-signed SSL certificate.<em><strong>Warning:</strong> Allowing self-signed SSL certificates may cause security implications.</em>', 'SMTP_AUTH_METHOD' => 'Authentication method for SMTP', 'SMTP_AUTH_METHOD_EXPLAIN' => 'Only used if a username/password is set, ask your provider if you are unsure which method to use.', 'SMTP_CRAM_MD5' => 'CRAM-MD5', @@ -574,6 +579,11 @@ $lang = array_merge($lang, array( 'SMTP_SETTINGS' => 'SMTP settings', 'SMTP_USERNAME' => 'SMTP username', 'SMTP_USERNAME_EXPLAIN' => 'Only enter a username if your SMTP server requires it.', + 'SMTP_VERIFY_PEER' => 'Verify SSL certificate', + 'SMTP_VERIFY_PEER_EXPLAIN' => 'Require verification of SSL certificate used by SMTP server.<em><strong>Warning:</strong> Connecting peers with unverified SSL certificates may cause security implications.</em>', + 'SMTP_VERIFY_PEER_NAME' => 'Verify SMTP peer name', + 'SMTP_VERIFY_PEER_NAME_EXPLAIN' => 'Require verification of peer name for SMTP servers using SSL / TLS connections.<em><strong>Warning:</strong> Connecting to unverified peers may cause security implications.</em>', + 'USE_SMTP' => 'Use SMTP server for email', 'USE_SMTP_EXPLAIN' => 'Select “Yes” if you want or have to send email via a named server instead of the local mail function.', )); diff --git a/phpBB/language/en/acp/styles.php b/phpBB/language/en/acp/styles.php index 0d91eb3704..9293d67ecc 100644 --- a/phpBB/language/en/acp/styles.php +++ b/phpBB/language/en/acp/styles.php @@ -81,6 +81,7 @@ $lang = array_merge($lang, array( 'STYLE_UNINSTALL_DEPENDENT' => 'Style "%s" cannot be uninstalled because it has one or more child styles.', 'STYLE_UNINSTALLED' => 'Style "%s" uninstalled successfully.', 'STYLE_USED_BY' => 'Used by (including robots)', + 'STYLE_VERSION' => 'Style version', 'UNINSTALL_DEFAULT' => 'You cannot uninstall the default style.', diff --git a/phpBB/phpbb/cache/driver/memcached.php b/phpBB/phpbb/cache/driver/memcached.php new file mode 100644 index 0000000000..105e763af4 --- /dev/null +++ b/phpBB/phpbb/cache/driver/memcached.php @@ -0,0 +1,134 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\cache\driver; + +if (!defined('PHPBB_ACM_MEMCACHED_PORT')) +{ + define('PHPBB_ACM_MEMCACHED_PORT', 11211); +} + +if (!defined('PHPBB_ACM_MEMCACHED_COMPRESS')) +{ + define('PHPBB_ACM_MEMCACHED_COMPRESS', true); +} + +if (!defined('PHPBB_ACM_MEMCACHED_HOST')) +{ + define('PHPBB_ACM_MEMCACHED_HOST', 'localhost'); +} + +if (!defined('PHPBB_ACM_MEMCACHED')) +{ + //can define multiple servers with host1/port1,host2/port2 format + define('PHPBB_ACM_MEMCACHED', PHPBB_ACM_MEMCACHED_HOST . '/' . PHPBB_ACM_MEMCACHED_PORT); +} + +/** +* ACM for Memcached +*/ +class memcached extends \phpbb\cache\driver\memory +{ + /** @var string Extension to use */ + protected $extension = 'memcached'; + + /** @var \Memcached Memcached class */ + protected $memcached; + + /** @var int Flags */ + protected $flags = 0; + + /** + * Memcached constructor + */ + public function __construct() + { + // Call the parent constructor + parent::__construct(); + + $this->memcached = new \Memcached(); + $this->memcached->setOption(\Memcached::OPT_BINARY_PROTOCOL, true); + // Memcached defaults to using compression, disable if we don't want + // to use it + if (!PHPBB_ACM_MEMCACHED_COMPRESS) + { + $this->memcached->setOption(\Memcached::OPT_COMPRESSION, false); + } + + foreach (explode(',', PHPBB_ACM_MEMCACHE) as $u) + { + $parts = explode('/', $u); + $this->memcached->addServer(trim($parts[0]), trim($parts[1])); + } + } + + /** + * {@inheritDoc} + */ + public function unload() + { + parent::unload(); + + unset($this->memcached); + } + + /** + * {@inheritDoc} + */ + public function purge() + { + $this->memcached->flush(); + + parent::purge(); + } + + /** + * Fetch an item from the cache + * + * @param string $var Cache key + * + * @return mixed Cached data + */ + protected function _read($var) + { + return $this->memcached->get($this->key_prefix . $var); + } + + /** + * Store data in the cache + * + * @param string $var Cache key + * @param mixed $data Data to store + * @param int $ttl Time-to-live of cached data + * @return bool True if the operation succeeded + */ + protected function _write($var, $data, $ttl = 2592000) + { + if (!$this->memcached->replace($this->key_prefix . $var, $data, $ttl)) + { + return $this->memcached->set($this->key_prefix . $var, $data, $ttl); + } + return true; + } + + /** + * Remove an item from the cache + * + * @param string $var Cache key + * @return bool True if the operation succeeded + */ + protected function _delete($var) + { + return $this->memcached->delete($this->key_prefix . $var); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/add_latest_topics_index.php b/phpBB/phpbb/db/migration/data/v31x/add_latest_topics_index.php new file mode 100644 index 0000000000..fa2899e348 --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/add_latest_topics_index.php @@ -0,0 +1,51 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\db\migration\data\v31x; + +class add_latest_topics_index extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array( + '\phpbb\db\migration\data\v31x\v3110', + ); + } + + public function update_schema() + { + return array( + 'add_index' => array( + $this->table_prefix . 'topics' => array( + 'latest_topics' => array( + 'forum_id', + 'topic_last_post_time', + 'topic_last_post_id', + 'topic_moved_id', + ), + ), + ), + ); + } + + public function revert_schema() + { + return array( + 'drop_keys' => array( + $this->table_prefix . 'topics' => array( + 'latest_topics', + ), + ), + ); + } +} diff --git a/phpBB/phpbb/db/migration/data/v31x/add_smtp_ssl_context_config_options.php b/phpBB/phpbb/db/migration/data/v31x/add_smtp_ssl_context_config_options.php new file mode 100644 index 0000000000..92051dc3ca --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v31x/add_smtp_ssl_context_config_options.php @@ -0,0 +1,32 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\db\migration\data\v31x; + +class add_smtp_ssl_context_config_options extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return array('\phpbb\db\migration\data\v31x\v3110'); + } + + public function update_data() + { + return array( + // See http://php.net/manual/en/context.ssl.php + array('config.add', array('smtp_verify_peer', 1)), + array('config.add', array('smtp_verify_peer_name', 1)), + array('config.add', array('smtp_allow_self_signed', 0)), + ); + } +} diff --git a/phpBB/phpbb/extension/manager.php b/phpBB/phpbb/extension/manager.php index 76f0e3558e..e7e5f83c23 100644 --- a/phpBB/phpbb/extension/manager.php +++ b/phpBB/phpbb/extension/manager.php @@ -149,10 +149,10 @@ class manager * Instantiates the metadata manager for the extension with the given name * * @param string $name The extension name - * @param \phpbb\template\template $template The template manager + * @param \phpbb\template\template $template The template manager or null * @return \phpbb\extension\metadata_manager Instance of the metadata manager */ - public function create_extension_metadata_manager($name, \phpbb\template\template $template) + public function create_extension_metadata_manager($name, \phpbb\template\template $template = null) { return new \phpbb\extension\metadata_manager($name, $this->config, $this, $template, $this->user, $this->phpbb_root_path); } @@ -433,25 +433,11 @@ class manager if ($file_info->isFile() && $file_info->getFilename() == 'composer.json') { $ext_name = $iterator->getInnerIterator()->getSubPath(); - $composer_file = $iterator->getPath() . '/composer.json'; - - // Ignore the extension if there is no composer.json. - if (!is_readable($composer_file) || !($ext_info = file_get_contents($composer_file))) - { - continue; - } - - $ext_info = json_decode($ext_info, true); $ext_name = str_replace(DIRECTORY_SEPARATOR, '/', $ext_name); - - // Ignore the extension if directory depth is not correct or if the directory structure - // does not match the name value specified in composer.json. - if (substr_count($ext_name, '/') !== 1 || !isset($ext_info['name']) || $ext_name != $ext_info['name']) + if ($this->is_available($ext_name)) { - continue; + $available[$ext_name] = $this->phpbb_root_path . 'ext/' . $ext_name . '/'; } - - $available[$ext_name] = $this->phpbb_root_path . 'ext/' . $ext_name . '/'; } } ksort($available); @@ -524,7 +510,15 @@ class manager */ public function is_available($name) { - return file_exists($this->get_extension_path($name, true)); + $md_manager = $this->create_extension_metadata_manager($name); + try + { + return $md_manager->get_metadata('all') && $md_manager->validate_enable(); + } + catch (\phpbb\extension\exception $e) + { + return false; + } } /** diff --git a/phpBB/phpbb/extension/metadata_manager.php b/phpBB/phpbb/extension/metadata_manager.php index 107907609b..a09f07bed2 100644 --- a/phpBB/phpbb/extension/metadata_manager.php +++ b/phpBB/phpbb/extension/metadata_manager.php @@ -66,17 +66,18 @@ class metadata_manager */ protected $metadata_file; + // @codingStandardsIgnoreStart /** * Creates the metadata manager * * @param string $ext_name Name (including vendor) of the extension * @param \phpbb\config\config $config phpBB Config instance * @param \phpbb\extension\manager $extension_manager An instance of the phpBB extension manager - * @param \phpbb\template\template $template phpBB Template instance + * @param \phpbb\template\template $template phpBB Template instance or null * @param \phpbb\user $user User instance * @param string $phpbb_root_path Path to the phpbb includes directory. */ - public function __construct($ext_name, \phpbb\config\config $config, \phpbb\extension\manager $extension_manager, \phpbb\template\template $template, \phpbb\user $user, $phpbb_root_path) + public function __construct($ext_name, \phpbb\config\config $config, \phpbb\extension\manager $extension_manager, \phpbb\template\template $template = null, \phpbb\user $user, $phpbb_root_path) { $this->config = $config; $this->extension_manager = $extension_manager; @@ -88,6 +89,7 @@ class metadata_manager $this->metadata = array(); $this->metadata_file = ''; } + // @codingStandardsIgnoreEnd /** * Processes and gets the metadata requested @@ -97,51 +99,38 @@ class metadata_manager */ public function get_metadata($element = 'all') { - $this->set_metadata_file(); - - // Fetch the metadata - $this->fetch_metadata(); - - // Clean the metadata - $this->clean_metadata_array(); + // Fetch and clean the metadata if not done yet + if ($this->metadata_file === '') + { + $this->fetch_metadata_from_file(); + } switch ($element) { case 'all': default: - // Validate the metadata - if (!$this->validate()) - { - return false; - } - + $this->validate(); return $this->metadata; break; case 'version': case 'name': - return ($this->validate($element)) ? $this->metadata[$element] : false; + $this->validate($element); + return $this->metadata[$element]; break; case 'display-name': - if (isset($this->metadata['extra']['display-name'])) - { - return $this->metadata['extra']['display-name']; - } - else - { - return ($this->validate('name')) ? $this->metadata['name'] : false; - } + return (isset($this->metadata['extra']['display-name'])) ? $this->metadata['extra']['display-name'] : $this->get_metadata('name'); break; } } /** - * Sets the filepath of the metadata file + * Sets the path of the metadata file, gets its contents and cleans loaded file * * @throws \phpbb\extension\exception */ - private function set_metadata_file() + private function fetch_metadata_from_file() { $ext_filepath = $this->extension_manager->get_extension_path($this->ext_name); $metadata_filepath = $this->phpbb_root_path . $ext_filepath . 'composer.json'; @@ -152,37 +141,19 @@ class metadata_manager { throw new \phpbb\extension\exception($this->user->lang('FILE_NOT_FOUND', $this->metadata_file)); } - } - /** - * Gets the contents of the composer.json file - * - * @return bool True if success, throws an exception on failure - * @throws \phpbb\extension\exception - */ - private function fetch_metadata() - { - if (!file_exists($this->metadata_file)) + if (!($file_contents = file_get_contents($this->metadata_file))) { - throw new \phpbb\extension\exception($this->user->lang('FILE_NOT_FOUND', $this->metadata_file)); + throw new \phpbb\extension\exception($this->user->lang('FILE_CONTENT_ERR', $this->metadata_file)); } - else - { - if (!($file_contents = file_get_contents($this->metadata_file))) - { - throw new \phpbb\extension\exception($this->user->lang('FILE_CONTENT_ERR', $this->metadata_file)); - } - - if (($metadata = json_decode($file_contents, true)) === null) - { - throw new \phpbb\extension\exception($this->user->lang('FILE_JSON_DECODE_ERR', $this->metadata_file)); - } - array_walk_recursive($metadata, array($this, 'sanitize_json')); - $this->metadata = $metadata; - - return true; + if (($metadata = json_decode($file_contents, true)) === null) + { + throw new \phpbb\extension\exception($this->user->lang('FILE_JSON_DECODE_ERR', $this->metadata_file)); } + + array_walk_recursive($metadata, array($this, 'sanitize_json')); + $this->metadata = $metadata; } /** @@ -197,16 +168,6 @@ class metadata_manager } /** - * This array handles the cleaning of the array - * - * @return array Contains the cleaned metadata array - */ - private function clean_metadata_array() - { - return $this->metadata; - } - - /** * Validate fields * * @param string $name ("all" for display and enable validation @@ -228,23 +189,8 @@ class metadata_manager switch ($name) { case 'all': - $this->validate('display'); - - if (!$this->validate_dir()) - { - throw new \phpbb\extension\exception($this->user->lang('EXTENSION_DIR_INVALID')); - } - - if (!$this->validate_require_phpbb()) - { - throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', 'soft-require')); - } - - if (!$this->validate_require_php()) - { - throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', 'require php')); - } - break; + $this->validate_enable(); + // no break case 'display': foreach ($fields as $field => $data) @@ -301,40 +247,43 @@ class metadata_manager /** * This array handles the verification that this extension can be enabled on this board * - * @return bool True if validation succeeded, False if failed + * @return bool True if validation succeeded, throws an exception if invalid + * @throws \phpbb\extension\exception */ public function validate_enable() { // Check for valid directory & phpBB, PHP versions - if (!$this->validate_dir() || !$this->validate_require_phpbb() || !$this->validate_require_php()) - { - return false; - } - - return true; + return $this->validate_dir() && $this->validate_require_phpbb() && $this->validate_require_php(); } /** * Validates the most basic directory structure to ensure it follows <vendor>/<ext> convention. * - * @return boolean True when passes validation + * @return boolean True when passes validation, throws an exception if invalid + * @throws \phpbb\extension\exception */ public function validate_dir() { - return (substr_count($this->ext_name, '/') === 1 && $this->ext_name == $this->get_metadata('name')); + if (substr_count($this->ext_name, '/') !== 1 || $this->ext_name != $this->get_metadata('name')) + { + throw new \phpbb\extension\exception($this->user->lang('EXTENSION_DIR_INVALID')); + } + + return true; } /** * Validates the contents of the phpbb requirement field * - * @return boolean True when passes validation + * @return boolean True when passes validation, throws an exception if invalid + * @throws \phpbb\extension\exception */ public function validate_require_phpbb() { if (!isset($this->metadata['extra']['soft-require']['phpbb/phpbb'])) { - return false; + throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', 'soft-require')); } return true; @@ -343,13 +292,14 @@ class metadata_manager /** * Validates the contents of the php requirement field * - * @return boolean True when passes validation + * @return boolean True when passes validation, throws an exception if invalid + * @throws \phpbb\extension\exception */ public function validate_require_php() { if (!isset($this->metadata['require']['php'])) { - return false; + throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', 'require php')); } return true; @@ -372,10 +322,10 @@ class metadata_manager 'META_LICENSE' => $this->metadata['license'], 'META_REQUIRE_PHP' => (isset($this->metadata['require']['php'])) ? $this->metadata['require']['php'] : '', - 'META_REQUIRE_PHP_FAIL' => !$this->validate_require_php(), + 'META_REQUIRE_PHP_FAIL' => (isset($this->metadata['require']['php'])) ? false : true, 'META_REQUIRE_PHPBB' => (isset($this->metadata['extra']['soft-require']['phpbb/phpbb'])) ? $this->metadata['extra']['soft-require']['phpbb/phpbb'] : '', - 'META_REQUIRE_PHPBB_FAIL' => !$this->validate_require_phpbb(), + 'META_REQUIRE_PHPBB_FAIL' => (isset($this->metadata['extra']['soft-require']['phpbb/phpbb'])) ? false : true, 'META_DISPLAY_NAME' => (isset($this->metadata['extra']['display-name'])) ? $this->metadata['extra']['display-name'] : '', )); diff --git a/phpBB/phpbb/profilefields/type/type_date.php b/phpBB/phpbb/profilefields/type/type_date.php index 90ac9a6703..63a0c79a3d 100644 --- a/phpBB/phpbb/profilefields/type/type_date.php +++ b/phpBB/phpbb/profilefields/type/type_date.php @@ -264,7 +264,7 @@ class type_date extends type_base } $profile_row['s_year_options'] = '<option value="0"' . ((!$year) ? ' selected="selected"' : '') . '>--</option>'; - for ($i = $now['year'] - 100; $i <= $now['year'] + 100; $i++) + for ($i = 1901; $i <= $now['year'] + 50; $i++) { $profile_row['s_year_options'] .= '<option value="' . $i . '"' . (($i == $year) ? ' selected="selected"' : '') . ">$i</option>"; } diff --git a/phpBB/phpbb/request/request.php b/phpBB/phpbb/request/request.php index 4cac6fbaea..00ff9064cb 100644 --- a/phpBB/phpbb/request/request.php +++ b/phpBB/phpbb/request/request.php @@ -169,12 +169,6 @@ class request implements \phpbb\request\request_interface $GLOBALS[$this->super_globals[$super_global]][$var_name] = $value; } } - - if (!$this->super_globals_disabled()) - { - unset($GLOBALS[$this->super_globals[$super_global]][$var_name]); - $GLOBALS[$this->super_globals[$super_global]][$var_name] = $value; - } } /** diff --git a/phpBB/phpbb/version_helper.php b/phpBB/phpbb/version_helper.php index 135d390584..9dc5a2e7c9 100644 --- a/phpBB/phpbb/version_helper.php +++ b/phpBB/phpbb/version_helper.php @@ -184,7 +184,7 @@ class version_helper $self = $this; $current_version = $this->current_version; - // Filter out any versions less than to the current version + // Filter out any versions less than the current version $versions = array_filter($versions, function($data) use ($self, $current_version) { return $self->compare($data['current'], $current_version, '>='); }); @@ -218,7 +218,7 @@ class version_helper $self = $this; $current_version = $this->current_version; - // Filter out any versions less than to the current version + // Filter out any versions less than the current version $versions = array_filter($versions, function($data) use ($self, $current_version) { return $self->compare($data['current'], $current_version, '>='); }); @@ -244,11 +244,74 @@ class version_helper } /** + * Gets the latest extension update for the current phpBB branch the user is on + * Will suggest versions from newer branches when EoL has been reached + * and/or version from newer branch is needed for having all known security + * issues fixed. + * + * @param bool $force_update Ignores cached data. Defaults to false. + * @param bool $force_cache Force the use of the cache. Override $force_update. + * @return array Version info or empty array if there are no updates + * @throws \RuntimeException + */ + public function get_ext_update_on_branch($force_update = false, $force_cache = false) + { + $versions = $this->get_versions_matching_stability($force_update, $force_cache); + + $self = $this; + $current_version = $this->current_version; + + // Get current phpBB branch from version, e.g.: 3.2 + preg_match('/^(\d+\.\d+).*$/', $this->config['version'], $matches); + $current_branch = $matches[1]; + + // Filter out any versions less than the current version + $versions = array_filter($versions, function($data) use ($self, $current_version) { + return $self->compare($data['current'], $current_version, '>='); + }); + + // Filter out any phpbb branches less than the current version + $branches = array_filter(array_keys($versions), function($branch) use ($self, $current_branch) { + return $self->compare($branch, $current_branch, '>='); + }); + if (!empty($branches)) + { + $versions = array_intersect_key($versions, array_flip($branches)); + } + else + { + // If branches are empty, it means the current phpBB branch is newer than any branch the + // extension was validated against. Reverse sort the versions array so we get the newest + // validated release available. + krsort($versions); + } + + // Get the first available version from the previous list. + $update_info = array_reduce($versions, function($value, $data) use ($self, $current_version) { + if ($value === null && $self->compare($data['current'], $current_version, '>=')) + { + if (!$data['eol'] && (!$data['security'] || $self->compare($data['security'], $data['current'], '<='))) + { + return $self->compare($data['current'], $current_version, '>') ? $data : array(); + } + else + { + return null; + } + } + + return $value; + }); + + return $update_info === null ? array() : $update_info; + } + + /** * Obtains the latest version information * * @param bool $force_update Ignores cached data. Defaults to false. * @param bool $force_cache Force the use of the cache. Override $force_update. - * @return string + * @return array * @throws \RuntimeException */ public function get_suggested_updates($force_update = false, $force_cache = false) @@ -269,7 +332,7 @@ class version_helper * * @param bool $force_update Ignores cached data. Defaults to false. * @param bool $force_cache Force the use of the cache. Override $force_update. - * @return string Version info + * @return array Version info * @throws \RuntimeException */ public function get_versions_matching_stability($force_update = false, $force_cache = false) @@ -289,7 +352,7 @@ class version_helper * * @param bool $force_update Ignores cached data. Defaults to false. * @param bool $force_cache Force the use of the cache. Override $force_update. - * @return string Version info, includes stable and unstable data + * @return array Version info, includes stable and unstable data * @throws \RuntimeException */ public function get_versions($force_update = false, $force_cache = false) diff --git a/phpBB/styles/prosilver/template/bbcode.html b/phpBB/styles/prosilver/template/bbcode.html index 3e38d13a32..49bcd56945 100644 --- a/phpBB/styles/prosilver/template/bbcode.html +++ b/phpBB/styles/prosilver/template/bbcode.html @@ -18,13 +18,13 @@ <!-- BEGIN inline_attachment_open --><div class="inline-attachment"><!-- END inline_attachment_open --> <!-- BEGIN inline_attachment_close --></div><!-- END inline_attachment_close --> -<!-- BEGIN b_open --><strong><!-- END b_open --> +<!-- BEGIN b_open --><strong class="text-strong"><!-- END b_open --> <!-- BEGIN b_close --></strong><!-- END b_close --> <!-- BEGIN u_open --><span style="text-decoration: underline"><!-- END u_open --> <!-- BEGIN u_close --></span><!-- END u_close --> -<!-- BEGIN i_open --><em><!-- END i_open --> +<!-- BEGIN i_open --><em class="text-italics"><!-- END i_open --> <!-- BEGIN i_close --></em><!-- END i_close --> <!-- BEGIN color --><span style="color: {COLOR}">{TEXT}</span><!-- END color --> diff --git a/phpBB/styles/prosilver/template/index_body.html b/phpBB/styles/prosilver/template/index_body.html index ec5bf35476..b4febd1d49 100644 --- a/phpBB/styles/prosilver/template/index_body.html +++ b/phpBB/styles/prosilver/template/index_body.html @@ -47,6 +47,8 @@ </div> <!-- ENDIF --> +<!-- EVENT index_body_birthday_block_before --> + <!-- IF S_DISPLAY_BIRTHDAY_LIST --> <div class="stat-block birthday-list"> <h3>{L_BIRTHDAYS}</h3> diff --git a/phpBB/styles/prosilver/template/mcp_post.html b/phpBB/styles/prosilver/template/mcp_post.html index e5777d206a..5acdcef859 100644 --- a/phpBB/styles/prosilver/template/mcp_post.html +++ b/phpBB/styles/prosilver/template/mcp_post.html @@ -294,6 +294,14 @@ </tbody> </table> + <div class="pagination"> + <!-- INCLUDE pagination.html --> + </div> + </div> + </div> + + <div class="panel"> + <div class="inner"> <table class="table1"> <thead> <tr> @@ -315,7 +323,27 @@ </tbody> </table> - <p><a href="{U_LOOKUP_ALL}#ip">{L_LOOKUP_ALL}</a></p> + <div class="buttons"> + <p><a href="{U_LOOKUP_ALL}#ip">{L_LOOKUP_ALL}</a></p> + </div> + + <div class="pagination"> + <ul> + <!-- BEGIN pagination_ips --> + <!-- IF pagination_ips.S_IS_PREV --> + <li class="previous"><a href="{pagination_ips.PAGE_URL}" rel="prev" role="button">{L_PREVIOUS}</a></li> + <!-- ELSEIF pagination_ips.S_IS_CURRENT --> + <li class="active"><span>{pagination_ips.PAGE_NUMBER}</span></li> + <!-- ELSEIF pagination_ips.S_IS_ELLIPSIS --> + <li class="ellipsis" role="separator"><span>{L_ELLIPSIS}</span></li> + <!-- ELSEIF pagination_ips.S_IS_NEXT --> + <li class="next"><a href="{pagination_ips.PAGE_URL}" rel="next" role="button">{L_NEXT}</a></li> + <!-- ELSE --> + <li><a href="{pagination_ips.PAGE_URL}" role="button">{pagination_ips.PAGE_NUMBER}</a></li> + <!-- ENDIF --> + <!-- END pagination_ips --> + </ul> + </div> </div> </div> diff --git a/phpBB/styles/prosilver/template/mcp_topic.html b/phpBB/styles/prosilver/template/mcp_topic.html index 22d837b3d1..af4b63265f 100644 --- a/phpBB/styles/prosilver/template/mcp_topic.html +++ b/phpBB/styles/prosilver/template/mcp_topic.html @@ -111,7 +111,9 @@ </li> </ul> + <!-- EVENT mcp_topic_postrow_post_subject_before --> <h3><a href="{postrow.U_POST_DETAILS}">{postrow.POST_SUBJECT}</a></h3> + <!-- EVENT mcp_topic_postrow_post_subject_after --> <!-- EVENT mcp_topic_postrow_post_details_before --> <p class="author"><a href="#pr{postrow.POST_ID}">{postrow.MINI_POST_IMG}</a> {L_POSTED} {postrow.POST_DATE} {L_POST_BY_AUTHOR} <strong>{postrow.POST_AUTHOR_FULL}</strong><!-- IF postrow.U_MCP_DETAILS --> [ <a href="{postrow.U_MCP_DETAILS}">{L_POST_DETAILS}</a> ]<!-- ENDIF --></p> diff --git a/phpBB/styles/prosilver/template/search_results.html b/phpBB/styles/prosilver/template/search_results.html index 4365482314..4c83e95a1b 100644 --- a/phpBB/styles/prosilver/template/search_results.html +++ b/phpBB/styles/prosilver/template/search_results.html @@ -137,6 +137,7 @@ <dd class="search-result-date">{searchresults.POST_DATE}</dd> <dd>{L_FORUM}{L_COLON} <a href="{searchresults.U_VIEW_FORUM}">{searchresults.FORUM_TITLE}</a></dd> <dd>{L_TOPIC}{L_COLON} <a href="{searchresults.U_VIEW_TOPIC}">{searchresults.TOPIC_TITLE}</a></dd> + <!-- EVENT search_results_topic_title_after --> <dd>{L_REPLIES}{L_COLON} <strong>{searchresults.TOPIC_REPLIES}</strong></dd> <dd>{L_VIEWS}{L_COLON} <strong>{searchresults.TOPIC_VIEWS}</strong></dd> <!-- EVENT search_results_postprofile_after --> diff --git a/phpBB/styles/prosilver/theme/common.css b/phpBB/styles/prosilver/theme/common.css index 0ac7a45a23..df923aa948 100644 --- a/phpBB/styles/prosilver/theme/common.css +++ b/phpBB/styles/prosilver/theme/common.css @@ -146,10 +146,18 @@ b, strong { font-weight: bold; } +.text-strong { + font-weight: bold; +} + i, em { font-style: italic; } +.text-italics { + font-style: italic; +} + u { text-decoration: underline; } diff --git a/phpBB/styles/prosilver/theme/forms.css b/phpBB/styles/prosilver/theme/forms.css index 777f011c35..235c230ed4 100644 --- a/phpBB/styles/prosilver/theme/forms.css +++ b/phpBB/styles/prosilver/theme/forms.css @@ -288,7 +288,7 @@ textarea.inputbox { } input[type="number"] { - -moz-padding-end: inherit; + -moz-padding-end: 0; } input[type="search"] { diff --git a/phpBB/styles/subsilver2/template/index_body.html b/phpBB/styles/subsilver2/template/index_body.html index c0a8d5fd57..de1523b11c 100644 --- a/phpBB/styles/subsilver2/template/index_body.html +++ b/phpBB/styles/subsilver2/template/index_body.html @@ -66,6 +66,8 @@ </table> <!-- ENDIF --> +<!-- EVENT index_body_birthday_block_before --> + <!-- IF S_DISPLAY_BIRTHDAY_LIST --> <br clear="all" /> diff --git a/phpBB/ucp.php b/phpBB/ucp.php index 8c74ca1f3c..5cd602bab5 100644 --- a/phpBB/ucp.php +++ b/phpBB/ucp.php @@ -237,6 +237,19 @@ switch ($mode) add_log('admin', 'LOG_ACL_TRANSFER_PERMISSIONS', $user_row['username']); $message = sprintf($user->lang['PERMISSIONS_TRANSFERRED'], $user_row['username']) . '<br /><br />' . sprintf($user->lang['RETURN_INDEX'], '<a href="' . append_sid("{$phpbb_root_path}index.$phpEx") . '">', '</a>'); + + /** + * Event to run code after permissions are switched + * + * @event core.ucp_switch_permissions + * @var int user_id User ID to switch permission to + * @var array user_row User data + * @var string message Success message + * @since 3.1.11-RC1 + */ + $vars = array('user_id', 'user_row', 'message'); + extract($phpbb_dispatcher->trigger_event('core.ucp_switch_permissions', compact($vars))); + trigger_error($message); break; @@ -260,6 +273,18 @@ switch ($mode) add_log('admin', 'LOG_ACL_RESTORE_PERMISSIONS', $username); $message = $user->lang['PERMISSIONS_RESTORED'] . '<br /><br />' . sprintf($user->lang['RETURN_INDEX'], '<a href="' . append_sid("{$phpbb_root_path}index.$phpEx") . '">', '</a>'); + + /** + * Event to run code after permissions are restored + * + * @event core.ucp_restore_permissions + * @var string username User name + * @var string message Success message + * @since 3.1.11-RC1 + */ + $vars = array('username', 'message'); + extract($phpbb_dispatcher->trigger_event('core.ucp_restore_permissions', compact($vars))); + trigger_error($message); break; diff --git a/phpBB/viewforum.php b/phpBB/viewforum.php index 1938c25fed..5c51975150 100644 --- a/phpBB/viewforum.php +++ b/phpBB/viewforum.php @@ -146,6 +146,13 @@ else } } +// Is a forum specific topic count required? +if ($forum_data['forum_topics_per_page']) +{ + $config['topics_per_page'] = $forum_data['forum_topics_per_page']; +} + +/* @var $phpbb_content_visibility \phpbb\content_visibility */ $phpbb_content_visibility = $phpbb_container->get('content.visibility'); // Dump out the page header and load viewforum template @@ -209,12 +216,6 @@ if ($mark_read == 'topics') trigger_error($user->lang['TOPICS_MARKED'] . '<br /><br />' . sprintf($user->lang['RETURN_FORUM'], '<a href="' . $redirect_url . '">', '</a>')); } -// Is a forum specific topic count required? -if ($forum_data['forum_topics_per_page']) -{ - $config['topics_per_page'] = $forum_data['forum_topics_per_page']; -} - // Do the forum Prune thang - cron type job ... if (!$config['use_system_cron']) { diff --git a/tests/functional/visibility_softdelete_test.php b/tests/functional/visibility_softdelete_test.php index 39efc99a35..6450c00c1e 100644 --- a/tests/functional/visibility_softdelete_test.php +++ b/tests/functional/visibility_softdelete_test.php @@ -564,7 +564,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_ $this->assertContainsLang('SPLIT_TOPIC_EXPLAIN', $crawler->text()); $form = $crawler->selectButton('Submit')->form(array( - 'subject' => 'Soft Delete Topic #2', + 'subject' => 'Soft Delete Topic #2 with bang', )); $form['to_forum_id']->select($this->data['forums']['Soft Delete #2']); $form['post_id_list'][1]->tick(); @@ -597,6 +597,11 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_ 'forum_topics_softdeleted' => 1, 'forum_last_post_id' => 0, ), 'after restoring #2'); + + // Assert new topic title is indexed as well + $this->add_lang('search'); + self::request('GET', "search.php?keywords=bang&sid={$this->sid}"); + $this->assertContains(sprintf($this->lang['FOUND_SEARCH_MATCHES'][1], 1), self::get_content()); } public function test_move_topic_back() @@ -609,7 +614,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_ ), 'topics' => array( 'Soft Delete Topic #1', - 'Soft Delete Topic #2', + 'Soft Delete Topic #2 with bang', ), 'posts' => array( 'Soft Delete Topic #1', @@ -618,7 +623,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_ ), )); - $crawler = $this->get_quickmod_page($this->data['topics']['Soft Delete Topic #2'], 'MOVE_TOPIC'); + $crawler = $this->get_quickmod_page($this->data['topics']['Soft Delete Topic #2 with bang'], 'MOVE_TOPIC'); $form = $crawler->selectButton('Yes')->form(); $form['to_forum_id']->select($this->data['forums']['Soft Delete #1']); $crawler = self::submit($form); @@ -644,7 +649,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_ ), 'topics' => array( 'Soft Delete Topic #1', - 'Soft Delete Topic #2', + 'Soft Delete Topic #2 with bang', ), 'posts' => array( 'Soft Delete Topic #1', @@ -664,7 +669,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_ ), 'before merging #1'); $this->add_lang('viewtopic'); - $crawler = self::request('GET', "viewtopic.php?t={$this->data['topics']['Soft Delete Topic #2']}&sid={$this->sid}"); + $crawler = self::request('GET', "viewtopic.php?t={$this->data['topics']['Soft Delete Topic #2 with bang']}&sid={$this->sid}"); $bookmark_tag = $crawler->filter('a.bookmark-link'); $this->assertContainsLang('BOOKMARK_TOPIC', $bookmark_tag->text()); @@ -673,10 +678,10 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_ $this->assertContainsLang('BOOKMARK_ADDED', $crawler_bookmark->text()); $this->add_lang('mcp'); - $crawler = $this->get_quickmod_page($this->data['topics']['Soft Delete Topic #2'], 'MERGE_TOPIC', $crawler); + $crawler = $this->get_quickmod_page($this->data['topics']['Soft Delete Topic #2 with bang'], 'MERGE_TOPIC', $crawler); $this->assertContainsLang('SELECT_MERGE', $crawler->text()); - $crawler = self::request('GET', "mcp.php?f={$this->data['forums']['Soft Delete #1']}&t={$this->data['topics']['Soft Delete Topic #2']}&i=main&mode=forum_view&action=merge_topic&to_topic_id={$this->data['topics']['Soft Delete Topic #1']}"); + $crawler = self::request('GET', "mcp.php?f={$this->data['forums']['Soft Delete #1']}&t={$this->data['topics']['Soft Delete Topic #2 with bang']}&i=main&mode=forum_view&action=merge_topic&to_topic_id={$this->data['topics']['Soft Delete Topic #1']}"); $this->assertContainsLang('MERGE_TOPICS_CONFIRM', $crawler->text()); $form = $crawler->selectButton('Yes')->form(); diff --git a/tests/mcp/fixtures/post_ip.xml b/tests/mcp/fixtures/post_ip.xml new file mode 100644 index 0000000000..fad2193396 --- /dev/null +++ b/tests/mcp/fixtures/post_ip.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_posts"> + <column>post_id</column> + <column>poster_id</column> + <column>post_edit_user</column> + <column>post_delete_user</column> + <column>post_username</column> + <column>topic_id</column> + <column>forum_id</column> + <column>post_visibility</column> + <column>post_time</column> + <column>post_text</column> + <column>post_reported</column> + <column>poster_ip</column> + <row> + <value>1</value> + <value>2</value> + <value>2</value> + <value>2</value> + <value></value> + <value>1</value> + <value>1</value> + <value>1</value> + <value>1</value> + <value></value> + <value>1</value> + <value>127.0.0.1</value> + </row> + <row> + <value>2</value> + <value>1</value> + <value>1</value> + <value>1</value> + <value>Other</value> + <value>2</value> + <value>2</value> + <value>1</value> + <value>1</value> + <value></value> + <value>1</value> + <value>127.0.0.2</value> + </row> + <row> + <value>3</value> + <value>2</value> + <value>2</value> + <value>2</value> + <value></value> + <value>3</value> + <value>3</value> + <value>1</value> + <value>1</value> + <value></value> + <value>1</value> + <value>127.0.0.3</value> + </row> + <row> + <value>4</value> + <value>1</value> + <value>1</value> + <value>1</value> + <value>Other</value> + <value>4</value> + <value>4</value> + <value>1</value> + <value>1</value> + <value></value> + <value>1</value> + <value>127.0.0.1</value> + </row> + </table> +</dataset> diff --git a/tests/mcp/post_ip_test.php b/tests/mcp/post_ip_test.php new file mode 100644 index 0000000000..72a9f62774 --- /dev/null +++ b/tests/mcp/post_ip_test.php @@ -0,0 +1,67 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +require_once dirname(__FILE__) . '/../../phpBB/includes/mcp/mcp_post.php'; + +class phpbb_mcp_post_ip_test extends phpbb_database_test_case +{ + /** @var \phpbb\db\driver\driver_interface */ + protected $db; + + public function getDataSet() + { + return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/post_ip.xml'); + } + + protected function setUp() + { + parent::setUp(); + + $this->db = $this->new_dbal(); + } + + public function data_get_num_ips() + { + return array( + array(2, 1), + array(2, 2), + array(0, 3), + ); + } + + /** + * @dataProvider data_get_num_ips + */ + public function test_get_num_ips($expected, $poster_id) + { + $this->assertSame($expected, phpbb_get_num_ips_for_poster($this->db, $poster_id)); + } + + public function data_get_num_posters() + { + return array( + array(2, '127.0.0.1'), + array(1, '127.0.0.2'), + array(1, '127.0.0.3'), + array(0, '127.0.0.4'), + ); + } + + /** + * @dataProvider data_get_num_posters + */ + public function test_get_num_posters($expected, $ip) + { + $this->assertSame($expected, phpbb_get_num_posters_for_ip($this->db, $ip)); + } +} diff --git a/tests/mock/extension_manager.php b/tests/mock/extension_manager.php index 3b759fbbc2..94268159a8 100644 --- a/tests/mock/extension_manager.php +++ b/tests/mock/extension_manager.php @@ -20,5 +20,7 @@ class phpbb_mock_extension_manager extends \phpbb\extension\manager $this->extensions = $extensions; $this->filesystem = new \phpbb\filesystem(); $this->container = $container; + $this->config = new \phpbb\config\config(array()); + $this->user = new \phpbb\user('\phpbb\datetime'); } } diff --git a/tests/version/version_test.php b/tests/version/version_test.php index 54237f2059..0ed0fcb589 100644 --- a/tests/version/version_test.php +++ b/tests/version/version_test.php @@ -532,4 +532,296 @@ class phpbb_version_helper_test extends phpbb_test_case $this->assertSame($expected, $version_helper->get_update_on_branch()); } + + public function get_ext_update_on_branch_data() + { + return array( + // Single branch, check version for current branch + array( + '3.1.0', + '1.0.0', + array( + '3.1' => array( + 'current' => '1.0.1', + ), + ), + array( + 'current' => '1.0.1', + ), + ), + array( + '3.1.0', + '1.0.1', + array( + '3.1' => array( + 'current' => '1.0.1', + ), + ), + array(), + ), + array( + '3.2.0', + '1.0.0', + array( + '3.2' => array( + 'current' => '1.1.1', + ), + ), + array( + 'current' => '1.1.1', + ), + ), + array( + '3.2.0', + '1.1.1', + array( + '3.2' => array( + 'current' => '1.1.1', + ), + ), + array(), + ), + // Single branch, check for newest version when branches don't match up + array( + '3.1.0', + '1.0.0', + array( + '3.2' => array( + 'current' => '1.1.1', + ), + ), + array( + 'current' => '1.1.1', + ), + ), + array( + '3.1.0', + '1.1.1', + array( + '3.2' => array( + 'current' => '1.1.1', + ), + ), + array(), + ), + array( + '3.2.0', + '1.0.0', + array( + '3.1' => array( + 'current' => '1.0.1', + ), + ), + array( + 'current' => '1.0.1', + ), + ), + array( + '3.2.0', + '1.0.1', + array( + '3.1' => array( + 'current' => '1.0.1', + ), + ), + array(), + ), + array( + '3.3.0', + '1.0.0', + array( + '3.2' => array( + 'current' => '1.1.1', + ), + ), + array( + 'current' => '1.1.1', + ), + ), + array( + '3.3.0', + '1.1.1', + array( + '3.2' => array( + 'current' => '1.1.1', + ), + ), + array(), + ), + // Multiple branches, check version for current branch + array( + '3.1.0', + '1.0.0', + array( + '3.1' => array( + 'current' => '1.0.1', + ), + '3.2' => array( + 'current' => '1.1.1', + ), + ), + array( + 'current' => '1.0.1', + ), + ), + array( + '3.1.0', + '1.0.1', + array( + '3.1' => array( + 'current' => '1.0.1', + ), + '3.2' => array( + 'current' => '1.1.1', + ), + ), + array(), + ), + array( + '3.1.0', + '1.1.1', + array( + '3.1' => array( + 'current' => '1.0.1', + ), + '3.2' => array( + 'current' => '1.1.1', + ), + ), + array(), + ), + array( + '3.2.0', + '1.0.0', + array( + '3.1' => array( + 'current' => '1.0.1', + ), + '3.2' => array( + 'current' => '1.1.1', + ), + ), + array( + 'current' => '1.1.1', + ), + ), + array( + '3.2.0', + '1.0.1', + array( + '3.1' => array( + 'current' => '1.0.1', + ), + '3.2' => array( + 'current' => '1.1.1', + ), + ), + array( + 'current' => '1.1.1', + ), + ), + array( + '3.2.0', + '1.1.1', + array( + '3.1' => array( + 'current' => '1.0.1', + ), + '3.2' => array( + 'current' => '1.1.1', + ), + ), + array(), + ), + // Multiple branches, check for newest version when branches don't match up + array( + '3.3.0', + '1.0.0', + array( + '3.1' => array( + 'current' => '1.0.1', + ), + '3.2' => array( + 'current' => '1.1.1', + ), + ), + array( + 'current' => '1.1.1', + ), + ), + array( + '3.3.0', + '1.0.1', + array( + '3.1' => array( + 'current' => '1.0.1', + ), + '3.2' => array( + 'current' => '1.1.1', + ), + ), + array( + 'current' => '1.1.1', + ), + ), + array( + '3.3.0', + '1.1.0', + array( + '3.1' => array( + 'current' => '1.0.1', + ), + '3.2' => array( + 'current' => '1.1.1', + ), + ), + array( + 'current' => '1.1.1', + ), + ), + array( + '3.3.0', + '1.1.1', + array( + '3.1' => array( + 'current' => '1.0.1', + ), + '3.2' => array( + 'current' => '1.1.1', + ), + ), + array(), + ), + ); + } + + /** + * @dataProvider get_ext_update_on_branch_data + */ + public function test_get_ext_update_on_branch($phpbb_version, $ext_version, $versions, $expected) + { + $version_helper = $this + ->getMockBuilder('\phpbb\version_helper') + ->setMethods(array( + 'get_versions_matching_stability', + )) + ->setConstructorArgs(array( + $this->cache, + new \phpbb\config\config(array( + 'version' => $phpbb_version, + )), + new \phpbb\file_downloader(), + new \phpbb\user('\phpbb\datetime'), + )) + ->getMock() + ; + + $version_helper->expects($this->any()) + ->method('get_versions_matching_stability') + ->will($this->returnValue($versions)); + + $version_helper->set_current_version($ext_version); + + $this->assertSame($expected, $version_helper->get_ext_update_on_branch()); + } } |