diff options
Diffstat (limited to 'phpBB')
-rw-r--r-- | phpBB/adm/style/acp_ext_details.html | 97 | ||||
-rw-r--r-- | phpBB/adm/style/acp_ext_disable.html | 34 | ||||
-rw-r--r-- | phpBB/adm/style/acp_ext_enable.html | 34 | ||||
-rw-r--r-- | phpBB/adm/style/acp_ext_list.html | 61 | ||||
-rw-r--r-- | phpBB/adm/style/acp_ext_purge.html | 34 | ||||
-rw-r--r-- | phpBB/adm/style/admin.css | 10 | ||||
-rw-r--r-- | phpBB/config/services.yml | 1 | ||||
-rw-r--r-- | phpBB/includes/acp/acp_extensions.php | 303 | ||||
-rw-r--r-- | phpBB/includes/acp/info/acp_extensions.php | 34 | ||||
-rw-r--r-- | phpBB/includes/extension/exception.php | 27 | ||||
-rw-r--r-- | phpBB/includes/extension/manager.php | 18 | ||||
-rw-r--r-- | phpBB/includes/extension/metadata_manager.php | 338 | ||||
-rw-r--r-- | phpBB/install/database_update.php | 4 | ||||
-rw-r--r-- | phpBB/install/install_install.php | 6 | ||||
-rw-r--r-- | phpBB/install/schemas/schema_data.sql | 1 | ||||
-rw-r--r-- | phpBB/language/en/acp/common.php | 1 | ||||
-rw-r--r-- | phpBB/language/en/acp/extensions.php | 103 | ||||
-rw-r--r-- | phpBB/language/en/acp/permissions_phpbb.php | 1 |
18 files changed, 1101 insertions, 6 deletions
diff --git a/phpBB/adm/style/acp_ext_details.html b/phpBB/adm/style/acp_ext_details.html new file mode 100644 index 0000000000..e7532691ad --- /dev/null +++ b/phpBB/adm/style/acp_ext_details.html @@ -0,0 +1,97 @@ +<!-- INCLUDE overall_header.html --> + +<a name="maincontent"></a> + + <a href="{U_BACK}" style="float: {S_CONTENT_FLOW_END};">« {L_BACK}</a> + + <h1>{L_EXTENSIONS_ADMIN}</h1> + + <fieldset> + <legend>{L_EXT_DETAILS}</legend> + <!-- IF META_DISPLAY_NAME --> + <dl> + <dt><label for="meta_display_name">{L_DISPLAY_NAME}:</label></dt> + <dd><strong id="meta_display_name">{META_DISPLAY_NAME}</strong></dd> + </dl> + <!-- ENDIF --> + <dl> + <dt><label for="meta_name">{L_CLEAN_NAME}:</label></dt> + <dd><strong id="meta_name">{META_NAME}</strong></dd> + </dl> + <!-- IF META_DESCRIPTION --> + <dl> + <dt><label for="meta_description">{L_DESCRIPTION}:</label></dt> + <dd><p id="meta_description">{META_DESCRIPTION}</p></dd> + </dl> + <!-- ENDIF --> + <dl> + <dt><label for="meta_version">{L_VERSION}:</label></dt> + <dd><p id="meta_version">{META_VERSION}</p></dd> + </dl> + <!-- IF META_HOMEPAGE --> + <dl> + <dt><label for="meta_homepage">{L_HOMEPAGE}:</label></dt> + <dd><p id="meta_homepage">{META_HOMEPAGE}</p></dd> + </dl> + <!-- ENDIF --> + <!-- IF META_TIME --> + <dl> + <dt><label for="meta_time">{L_TIME}:</label></dt> + <dd><p id="meta_time">{META_TIME}</p></dd> + </dl> + <!-- ENDIF --> + <dl> + <dt><label for="meta_license">{L_LICENCE}:</label></dt> + <dd><p id="meta_license">{META_LICENCE}</p></dd> + </dl> + </fieldset> + + <!-- IF META_REQUIRE_PHPBB || META_REQUIRE_PHP --> + <fieldset> + <legend>{L_REQUIREMENTS}</legend> + <!-- IF META_REQUIRE_PHPBB --> + <dl<!-- IF META_REQUIRE_PHPBB_FAIL --> class="requirements_not_met"<!-- ENDIF -->> + <dt><label for="require_phpbb">{L_PHPBB_VERSION}:</label></dt> + <dd><p id="require_phpbb">{META_REQUIRE_PHPBB}</p></dd> + </dl> + <!-- ENDIF --> + <!-- IF META_REQUIRE_PHP --> + <dl<!-- IF META_REQUIRE_PHP_FAIL --> class="requirements_not_met"<!-- ENDIF -->> + <dt><label for="require_php">{L_PHP_VERSION}:</label></dt> + <dd><p id="require_php">{META_REQUIRE_PHP}</p></dd> + </dl> + <!-- ENDIF --> + </fieldset> + <!-- ENDIF --> + + <fieldset> + <legend>{L_AUTHOR_INFORMATION}</legend> + <!-- BEGIN meta_authors --> + <fieldset> + <dl> + <dt><label for="meta_author_name">{L_AUTHOR_NAME}:</label></dt> + <dd><strong id="meta_author_name">{meta_authors.AUTHOR_NAME}</strong></dd> + </dl> + <!-- IF meta_authors.AUTHOR_EMAIL --> + <dl> + <dt><label for="meta_author_email">{L_AUTHOR_EMAIL}:</label></dt> + <dd><strong id="meta_author_email"><a href="mailto:{meta_authors.AUTHOR_EMAIL}">{meta_authors.AUTHOR_EMAIL}</a></strong></dd> + </dl> + <!-- ENDIF --> + <!-- IF meta_authors.AUTHOR_HOMEPAGE --> + <dl> + <dt><label for="meta_author_url">{L_AUTHOR_HOMEPAGE}:</label></dt> + <dd><strong id="meta_author_url"><a href="{meta_authors.AUTHOR_HOMEPAGE}">{meta_authors.AUTHOR_HOMEPAGE}</a></strong></dd> + </dl> + <!-- ENDIF --> + <!-- IF meta_authors.AUTHOR_ROLE --> + <dl> + <dt><label for="author_role">{L_AUTHOR_ROLE}:</label></dt> + <dd><strong id="meta_author_role">{meta_authors.AUTHOR_ROLE}</strong></dd> + </dl> + <!-- ENDIF --> + </fieldset> + <!-- END meta_authors --> + </fieldset> + +<!-- INCLUDE overall_footer.html --> diff --git a/phpBB/adm/style/acp_ext_disable.html b/phpBB/adm/style/acp_ext_disable.html new file mode 100644 index 0000000000..7dc3f6ec97 --- /dev/null +++ b/phpBB/adm/style/acp_ext_disable.html @@ -0,0 +1,34 @@ +<!-- INCLUDE overall_header.html --> + + <a name="maincontent"></a> + + <h1>{L_EXTENSIONS_ADMIN}</h1> + + <p>{L_EXTENSIONS_EXPLAIN}</p> + <p>{L_DISABLE_EXPLAIN}</p> + + <!-- IF PRE --> + <div class="errorbox"> + <p>{L_DISABLE_CONFIRM}</p> + </div> + + <form id="acp_extensions" method="post" action="{U_DISABLE}"> + <fieldset class="submit-buttons"> + <legend>{L_DISABLE}</legend> + <input class="button1" type="submit" name="disable" value="{L_DISABLE}" /> + <input class="button2" type="submit" name="cancel" value="{L_CANCEL}" /> + </fieldset> + </form> + <!-- ELSEIF S_NEXT_STEP --> + <div class="errorbox"> + <p>{L_DISABLE_IN_PROGRESS}</p> + </div> + <!-- ELSE --> + <div class="successbox"> + <p>{L_DISABLE_SUCCESS}</p> + <br /> + <p><a href="{U_RETURN}">{L_RETURN}</a></p> + </div> + <!-- ENDIF --> + +<!-- INCLUDE overall_footer.html --> diff --git a/phpBB/adm/style/acp_ext_enable.html b/phpBB/adm/style/acp_ext_enable.html new file mode 100644 index 0000000000..3f7be2c847 --- /dev/null +++ b/phpBB/adm/style/acp_ext_enable.html @@ -0,0 +1,34 @@ +<!-- INCLUDE overall_header.html --> + + <a name="maincontent"></a> + + <h1>{L_EXTENSIONS_ADMIN}</h1> + + <p>{L_EXTENSIONS_EXPLAIN}</p> + <p>{L_ENABLE_EXPLAIN}</p> + + <!-- IF PRE --> + <div class="errorbox"> + <p>{L_ENABLE_CONFIRM}</p> + </div> + + <form id="acp_extensions" method="post" action="{U_ENABLE}"> + <fieldset class="submit-buttons"> + <legend>{L_ENABLE}</legend> + <input class="button1" type="submit" name="enable" value="{L_ENABLE}" /> + <input class="button2" type="submit" name="cancel" value="{L_CANCEL}" /> + </fieldset> + </form> + <!-- ELSEIF S_NEXT_STEP --> + <div class="errorbox"> + <p>{L_ENABLE_IN_PROGRESS}</p> + </div> + <!-- ELSE --> + <div class="successbox"> + <p>{L_ENABLE_SUCCESS}</p> + <br /> + <p><a href="{U_RETURN}">{L_RETURN}</a></p> + </div> + <!-- ENDIF --> + +<!-- INCLUDE overall_footer.html --> diff --git a/phpBB/adm/style/acp_ext_list.html b/phpBB/adm/style/acp_ext_list.html new file mode 100644 index 0000000000..53de0b4d12 --- /dev/null +++ b/phpBB/adm/style/acp_ext_list.html @@ -0,0 +1,61 @@ +<!-- INCLUDE overall_header.html --> + +<a name="maincontent"></a> + + <h1>{L_EXTENSIONS_ADMIN}</h1> + + <p>{L_EXTENSIONS_EXPLAIN}</p> + + <table cellspacing="1"> + <col class="row1" ><col class="row2" ><col class="row2" > + <thead> + <tr> + <th>{L_EXTENSION_NAME}</th> + <th>{L_EXTENSION_OPTIONS}</th> + <th>{L_EXTENSION_ACTIONS}</th> + </tr> + </thead> + <tbody> + <!-- IF .enabled --> + <tr> + <td class="row3" colspan="3"> + <strong>{L_ENABLED} {L_EXTENSIONS}</strong> + </td> + </tr> + <!-- BEGIN enabled --> + <tr class="ext_enabled"> + <td><strong>{enabled.META_DISPLAY_NAME}</strong></a></td> + <td style="text-align: center;"><a href="{enabled.U_DETAILS}">{L_DETAILS}</a></td> + <td style="text-align: center;"> + <!-- BEGIN actions --> + <a href="{enabled.actions.U_ACTION}" alt="{enabled.actions.L_ACTION}">{enabled.actions.L_ACTION}</a> + <!-- IF not enabled.actions.S_LAST_ROW --> | <!-- ENDIF --> + <!-- END actions --> + </td> + </tr> + <!-- END enabled --> + <!-- ENDIF --> + + <!-- IF .disabled --> + <tr> + <td class="row3" colspan="3"><strong>{L_DISABLED} {L_EXTENSIONS}</strong></td> + </tr> + <!-- BEGIN disabled --> + <tr class="ext_disabled"> + <td><strong>{disabled.META_DISPLAY_NAME}</strong></a></td> + <td style="text-align: center;"> + <!-- IF disabled.U_DETAILS --><a href="{disabled.U_DETAILS}">{L_DETAILS}</a><!-- ENDIF --> + </td> + <td style="text-align: center;"> + <!-- BEGIN actions --> + <a href="{disabled.actions.U_ACTION}" alt="{disabled.actions.L_ACTION}">{disabled.actions.L_ACTION}</a> + <!-- IF not disabled.actions.S_LAST_ROW --> | <!-- ENDIF --> + <!-- END actions --> + </td> + </tr> + <!-- END disabled --> + <!-- ENDIF --> + </tbody> + </table> + +<!-- INCLUDE overall_footer.html --> diff --git a/phpBB/adm/style/acp_ext_purge.html b/phpBB/adm/style/acp_ext_purge.html new file mode 100644 index 0000000000..00a58721cb --- /dev/null +++ b/phpBB/adm/style/acp_ext_purge.html @@ -0,0 +1,34 @@ +<!-- INCLUDE overall_header.html --> + + <a name="maincontent"></a> + + <h1>{L_EXTENSIONS_ADMIN}</h1> + + <p>{L_EXTENSIONS_EXPLAIN}</p> + <p>{L_PURGE_EXPLAIN}</p> + + <!-- IF PRE --> + <div class="errorbox"> + <p>{L_PURGE_CONFIRM}</p> + </div> + + <form id="acp_extensions" method="post" action="{U_PURGE}"> + <fieldset class="submit-buttons"> + <legend>{L_PURGE}</legend> + <input class="button1" type="submit" name="purge" value="{L_PURGE}" /> + <input class="button2" type="submit" name="cancel" value="{L_CANCEL}" /> + </fieldset> + </form> + <!-- ELSEIF S_NEXT_STEP --> + <div class="errorbox"> + <p>{L_PURGE_IN_PROGRESS}</p> + </div> + <!-- ELSE --> + <div class="successbox"> + <p>{L_PURGE_SUCCESS}</p> + <br /> + <p><a href="{U_RETURN}">{L_RETURN}</a></p> + </div> + <!-- ENDIF --> + +<!-- INCLUDE overall_footer.html --> diff --git a/phpBB/adm/style/admin.css b/phpBB/adm/style/admin.css index 08613de0dd..585707600d 100644 --- a/phpBB/adm/style/admin.css +++ b/phpBB/adm/style/admin.css @@ -1718,3 +1718,13 @@ fieldset.permissions .padding { .phpinfo td, .phpinfo th, .phpinfo h2, .phpinfo h1 { text-align: left; } + +.requirements_not_met { + padding: 5px; + background-color: #BC2A4D; +} + +.requirements_not_met dt label, .requirements_not_met dd p { + color: #FFFFFF; + font-size: 1.4em; +}
\ No newline at end of file diff --git a/phpBB/config/services.yml b/phpBB/config/services.yml index 84de37c28c..133a43b77e 100644 --- a/phpBB/config/services.yml +++ b/phpBB/config/services.yml @@ -83,6 +83,7 @@ services: class: phpbb_extension_manager arguments: - @dbal.conn + - @config - %tables.ext% - %core.root_path% - .%core.php_ext% diff --git a/phpBB/includes/acp/acp_extensions.php b/phpBB/includes/acp/acp_extensions.php new file mode 100644 index 0000000000..a0bcf62ecc --- /dev/null +++ b/phpBB/includes/acp/acp_extensions.php @@ -0,0 +1,303 @@ +<?php +/** +* +* @package acp +* @copyright (c) 2012 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* @package acp +*/ +class acp_extensions +{ + var $u_action; + + private $db; + private $config; + private $template; + private $user; + + function main() + { + // Start the page + global $config, $user, $template, $request, $phpbb_extension_manager, $db, $phpbb_root_path, $phpEx; + + $this->db = $db; + $this->config = $config; + $this->template = $template; + $this->user = $user; + + $user->add_lang(array('install', 'acp/extensions')); + + $this->page_title = 'ACP_EXTENSIONS'; + + $action = $request->variable('action', 'list'); + $ext_name = $request->variable('ext_name', ''); + + // Cancel action + if ($request->is_set_post('cancel')) + { + $action = 'list'; + $ext_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, $db, $phpbb_extension_manager, $phpbb_root_path, ".$phpEx", $template, $config); + + try + { + $md_manager->get_metadata('all'); + } + catch(phpbb_extension_exception $e) + { + trigger_error($e); + } + } + + // What are we doing? + switch ($action) + { + case 'list': + default: + $this->list_enabled_exts($phpbb_extension_manager); + $this->list_disabled_exts($phpbb_extension_manager); + $this->list_available_exts($phpbb_extension_manager); + + $this->tpl_name = 'acp_ext_list'; + break; + + case 'enable_pre': + if (!$md_manager->validate_enable()) + { + trigger_error($user->lang['EXTENSION_NOT_AVAILABLE'] . adm_back_link($this->u_action)); + } + + if ($phpbb_extension_manager->enabled($ext_name)) + { + redirect($this->u_action); + } + + $this->tpl_name = 'acp_ext_enable'; + + $template->assign_vars(array( + 'PRE' => true, + 'U_ENABLE' => $this->u_action . '&action=enable&ext_name=' . urlencode($ext_name), + )); + break; + + case 'enable': + if (!$md_manager->validate_enable()) + { + trigger_error($user->lang['EXTENSION_NOT_AVAILABLE'] . adm_back_link($this->u_action)); + } + + if ($phpbb_extension_manager->enable_step($ext_name)) + { + $template->assign_var('S_NEXT_STEP', true); + + meta_refresh(0, $this->u_action . '&action=enable&ext_name=' . urlencode($ext_name)); + } + + $this->tpl_name = 'acp_ext_enable'; + + $template->assign_vars(array( + 'U_RETURN' => $this->u_action . '&action=list', + )); + break; + + case 'disable_pre': + if (!$phpbb_extension_manager->enabled($ext_name)) + { + redirect($this->u_action); + } + + $this->tpl_name = 'acp_ext_disable'; + + $template->assign_vars(array( + 'PRE' => true, + 'U_DISABLE' => $this->u_action . '&action=disable&ext_name=' . urlencode($ext_name), + )); + break; + + case 'disable': + if ($phpbb_extension_manager->disable_step($ext_name)) + { + $template->assign_var('S_NEXT_STEP', true); + + meta_refresh(0, $this->u_action . '&action=disable&ext_name=' . urlencode($ext_name)); + } + + $this->tpl_name = 'acp_ext_disable'; + + $template->assign_vars(array( + 'U_RETURN' => $this->u_action . '&action=list', + )); + break; + + case 'purge_pre': + $this->tpl_name = 'acp_ext_purge'; + + $template->assign_vars(array( + 'PRE' => true, + 'U_PURGE' => $this->u_action . '&action=purge&ext_name=' . urlencode($ext_name), + )); + break; + + case 'purge': + if ($phpbb_extension_manager->purge_step($ext_name)) + { + $template->assign_var('S_NEXT_STEP', true); + + meta_refresh(0, $this->u_action . '&action=purge&ext_name=' . urlencode($ext_name)); + } + + $this->tpl_name = 'acp_ext_purge'; + + $template->assign_vars(array( + 'U_RETURN' => $this->u_action . '&action=list', + )); + break; + + case 'details': + // Output it to the template + $md_manager->output_template_data(); + + $template->assign_var('U_BACK', $this->u_action . '&action=list'); + + $this->tpl_name = 'acp_ext_details'; + break; + } + } + + /** + * 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) + { + foreach ($phpbb_extension_manager->all_enabled() as $name => $location) + { + $md_manager = $phpbb_extension_manager->create_extension_metadata_manager($name, $this->template); + + try + { + $this->template->assign_block_vars('enabled', array( + 'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'), + + 'U_DETAILS' => $this->u_action . '&action=details&ext_name=' . urlencode($name), + )); + + $this->output_actions('enabled', array( + 'DISABLE' => $this->u_action . '&action=disable_pre&ext_name=' . urlencode($name), + 'PURGE' => $this->u_action . '&action=purge_pre&ext_name=' . urlencode($name), + )); + } + catch(phpbb_extension_exception $e) + { + $this->template->assign_block_vars('disabled', array( + 'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $e), + )); + } + } + } + + /** + * 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) + { + foreach ($phpbb_extension_manager->all_disabled() as $name => $location) + { + $md_manager = $phpbb_extension_manager->create_extension_metadata_manager($name, $this->template); + + try + { + $this->template->assign_block_vars('disabled', array( + 'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'), + + 'U_DETAILS' => $this->u_action . '&action=details&ext_name=' . urlencode($name), + )); + + $this->output_actions('disabled', array( + 'ENABLE' => $this->u_action . '&action=enable_pre&ext_name=' . urlencode($name), + 'PURGE' => $this->u_action . '&action=purge_pre&ext_name=' . urlencode($name), + )); + } + catch(phpbb_extension_exception $e) + { + $this->template->assign_block_vars('disabled', array( + 'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $e), + )); + } + } + } + + /** + * 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) + { + $uninstalled = array_diff_key($phpbb_extension_manager->all_available(), $phpbb_extension_manager->all_configured()); + + foreach ($uninstalled as $name => $location) + { + $md_manager = $phpbb_extension_manager->create_extension_metadata_manager($name, $this->template); + + try + { + $this->template->assign_block_vars('disabled', array( + 'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'), + + 'U_DETAILS' => $this->u_action . '&action=details&ext_name=' . urlencode($name), + )); + + $this->output_actions('disabled', array( + 'ENABLE' => $this->u_action . '&action=enable_pre&ext_name=' . urlencode($name), + )); + } + catch(phpbb_extension_exception $e) + { + $this->template->assign_block_vars('disabled', array( + 'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $e), + )); + } + } + } + + /** + * Output actions to a block + * + * @param string $block + * @param array $actions + */ + private function output_actions($block, $actions) + { + foreach ($actions as $lang => $url) + { + $this->template->assign_block_vars($block . '.actions', array( + 'L_ACTION' => $this->user->lang($lang), + 'U_ACTION' => $url, + )); + } + } +} diff --git a/phpBB/includes/acp/info/acp_extensions.php b/phpBB/includes/acp/info/acp_extensions.php new file mode 100644 index 0000000000..f5953fb1dd --- /dev/null +++ b/phpBB/includes/acp/info/acp_extensions.php @@ -0,0 +1,34 @@ +<?php +/** +* +* @package acp +* @copyright (c) 2012 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @package module_install +*/ +class acp_extensions_info +{ + function module() + { + return array( + 'filename' => 'acp_extensions', + 'title' => 'ACP_EXTENSIONS', + 'version' => '1.0.0', + 'modes' => array( + 'main' => array('title' => 'ACP_EXTENSIONS', 'auth' => 'acl_a_extensions', 'cat' => array('ACP_GENERAL_TASKS')), + ), + ); + } + + function install() + { + } + + function uninstall() + { + } +} diff --git a/phpBB/includes/extension/exception.php b/phpBB/includes/extension/exception.php new file mode 100644 index 0000000000..e08a8912ea --- /dev/null +++ b/phpBB/includes/extension/exception.php @@ -0,0 +1,27 @@ +<?php +/** +* +* @package extension +* @copyright (c) 2012 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** + * Exception class for metadata + */ +class phpbb_extension_exception extends UnexpectedValueException +{ + public function __toString() + { + return $this->getMessage(); + } +}
\ No newline at end of file diff --git a/phpBB/includes/extension/manager.php b/phpBB/includes/extension/manager.php index 86d8fab64b..9a518c215f 100644 --- a/phpBB/includes/extension/manager.php +++ b/phpBB/includes/extension/manager.php @@ -22,6 +22,8 @@ if (!defined('IN_PHPBB')) */ class phpbb_extension_manager { + protected $db; + protected $config; protected $cache; protected $php_ext; protected $extensions; @@ -33,16 +35,18 @@ class phpbb_extension_manager * Creates a manager and loads information from database * * @param dbal $db A database connection + * @param phpbb_config $config phpbb_config * @param string $extension_table The name of the table holding extensions * @param string $phpbb_root_path Path to the phpbb includes directory. * @param string $php_ext php file extension * @param phpbb_cache_driver_interface $cache A cache instance or null * @param string $cache_name The name of the cache variable, defaults to _ext */ - public function __construct(dbal $db, $extension_table, $phpbb_root_path, $php_ext = '.php', phpbb_cache_driver_interface $cache = null, $cache_name = '_ext') + public function __construct(dbal $db, phpbb_config $config, $extension_table, $phpbb_root_path, $php_ext = '.php', phpbb_cache_driver_interface $cache = null, $cache_name = '_ext') { $this->phpbb_root_path = $phpbb_root_path; $this->db = $db; + $this->config = $config; $this->cache = $cache; $this->php_ext = $php_ext; $this->extension_table = $extension_table; @@ -121,6 +125,18 @@ class phpbb_extension_manager } /** + * Instantiates the metadata manager for the extension with the given name + * + * @param string $name The extension name + * @param string $template The template manager + * @return phpbb_extension_metadata_manager Instance of the metadata manager + */ + public function create_extension_metadata_manager($name, phpbb_template $template) + { + return new phpbb_extension_metadata_manager($name, $this->db, $this, $this->phpbb_root_path, $this->php_ext, $template, $this->config); + } + + /** * Runs a step of the extension enabling process. * * Allows the exentension to enable in a long running script that works diff --git a/phpBB/includes/extension/metadata_manager.php b/phpBB/includes/extension/metadata_manager.php new file mode 100644 index 0000000000..ea85bd3c4e --- /dev/null +++ b/phpBB/includes/extension/metadata_manager.php @@ -0,0 +1,338 @@ +<?php +/** +* +* @package extension +* @copyright (c) 2012 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* The extension metadata manager validates and gets meta-data for extensions +* +* @package extension +*/ +class phpbb_extension_metadata_manager +{ + protected $phpEx; + protected $extension_manager; + protected $db; + protected $phpbb_root_path; + protected $template; + protected $ext_name; + protected $metadata; + protected $metadata_file; + + /** + * Creates the metadata manager + * + * @param dbal $db A database connection + * @param string $extension_manager An instance of the phpbb extension manager + * @param string $phpbb_root_path Path to the phpbb includes directory. + * @param string $phpEx php file extension + */ + public function __construct($ext_name, dbal $db, phpbb_extension_manager $extension_manager, $phpbb_root_path, $phpEx = '.php', phpbb_template $template, phpbb_config $config) + { + $this->phpbb_root_path = $phpbb_root_path; + $this->db = $db; + $this->config = $config; + $this->phpEx = $phpEx; + $this->template = $template; + $this->extension_manager = $extension_manager; + $this->ext_name = $ext_name; + $this->metadata = array(); + $this->metadata_file = ''; + } + + /** + * Processes and gets the metadata requested + * + * @param string $element All for all metadata that it has and is valid, otherwise specify which section you want by its shorthand term. + * @return array Contains all of the requested metadata, throws an exception on failure + */ + public function get_metadata($element = 'all') + { + $this->set_metadata_file(); + + // Fetch the metadata + $this->fetch_metadata(); + + // Clean the metadata + $this->clean_metadata_array(); + + switch ($element) + { + case 'all': + default: + // Validate the metadata + if (!$this->validate()) + { + return false; + } + + return $this->metadata; + break; + + case 'name': + return ($this->validate('name')) ? $this->metadata['name'] : false; + 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; + } + break; + } + } + + /** + * Sets the filepath of the metadata file + * + * @return boolean Set to true if it exists, throws an exception on failure + */ + private function set_metadata_file() + { + $ext_filepath = $this->extension_manager->get_extension_path($this->ext_name); + $metadata_filepath = $this->phpbb_root_path . $ext_filepath . 'composer.json'; + + $this->metadata_file = $metadata_filepath; + + if (!file_exists($this->metadata_file)) + { + throw new phpbb_extension_exception('The required file does not exist: ' . $this->metadata_file); + } + } + + /** + * Gets the contents of the composer.json file + * + * @return bool True if success, throws an exception on failure + */ + private function fetch_metadata() + { + if (!file_exists($this->metadata_file)) + { + throw new phpbb_extension_exception('The required file does not exist: ' . $this->metadata_file); + } + else + { + if (!($file_contents = file_get_contents($this->metadata_file))) + { + throw new phpbb_extension_exception('file_get_contents failed on ' . $this->metadata_file); + } + + if (($metadata = json_decode($file_contents, true)) === NULL) + { + throw new phpbb_extension_exception('json_decode failed on ' . $this->metadata_file); + } + + $this->metadata = $metadata; + + return true; + } + } + + /** + * 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 + * "display" for name, type, and authors + * "name", "type") + * @return Bool True if valid, throws an exception if invalid + */ + public function validate($name = 'display') + { + // Basic fields + $fields = array( + 'name' => '#^[a-zA-Z0-9_\x7f-\xff]{2,}/[a-zA-Z0-9_\x7f-\xff]{2,}$#', + 'type' => '#^phpbb3-extension$#', + 'licence' => '#.+#', + 'version' => '#.+#', + ); + + switch ($name) + { + case 'all': + $this->validate('display'); + + $this->validate_enable(); + break; + + case 'display': + foreach ($fields as $field => $data) + { + $this->validate($field); + } + + $this->validate_authors(); + break; + + default: + if (isset($fields[$name])) + { + if (!isset($this->metadata[$name])) + { + throw new phpbb_extension_exception("Required meta field '$name' has not been set."); + } + + if (!preg_match($fields[$name], $this->metadata[$name])) + { + throw new phpbb_extension_exception("Meta field '$name' is invalid."); + } + } + break; + } + + return true; + } + + /** + * Validates the contents of the authors field + * + * @return boolean True when passes validation, throws exception if invalid + */ + public function validate_authors() + { + if (empty($this->metadata['authors'])) + { + throw new phpbb_extension_exception("Required meta field 'authors' has not been set."); + } + + foreach ($this->metadata['authors'] as $author) + { + if (!isset($author['name'])) + { + throw new phpbb_extension_exception("Required meta field 'author name' has not been set."); + } + } + + return true; + } + + /** + * This array handles the verification that this extension can be enabled on this board + * + * @return bool True if validation succeeded, False if failed + */ + public function validate_enable() + { + // Check for phpBB, PHP versions + if (!$this->validate_require_phpbb() || !$this->validate_require_php()) + { + return false; + } + + return true; + } + + + /** + * Validates the contents of the phpbb requirement field + * + * @return boolean True when passes validation + */ + public function validate_require_phpbb() + { + if (!isset($this->metadata['require']['phpbb'])) + { + return true; + } + + return $this->_validate_version($this->metadata['require']['phpbb'], $this->config['version']); + } + + /** + * Validates the contents of the php requirement field + * + * @return boolean True when passes validation + */ + public function validate_require_php() + { + if (!isset($this->metadata['require']['php'])) + { + return true; + } + + return $this->_validate_version($this->metadata['require']['php'], phpversion()); + } + + /** + * Version validation helper + * + * @param string $string The string for comparing to a version + * @param string $current_version The version to compare to + * @return bool True/False if meets version requirements + */ + private function _validate_version($string, $current_version) + { + // Allow them to specify their own comparison operator (ex: <3.1.2, >=3.1.0) + $comparison_matches = false; + preg_match('#[=<>]+#', $string, $comparison_matches); + + if (!empty($comparison_matches)) + { + return version_compare($current_version, str_replace(array($comparison_matches[0], ' '), '', $string), $comparison_matches[0]); + } + + return version_compare($current_version, $string, '>='); + } + + /** + * Outputs the metadata into the template + * + * @return null + */ + public function output_template_data() + { + $this->template->assign_vars(array( + 'META_NAME' => htmlspecialchars($this->metadata['name']), + 'META_TYPE' => htmlspecialchars($this->metadata['type']), + 'META_DESCRIPTION' => (isset($this->metadata['description'])) ? htmlspecialchars($this->metadata['description']) : '', + 'META_HOMEPAGE' => (isset($this->metadata['homepage'])) ? $this->metadata['homepage'] : '', + 'META_VERSION' => (isset($this->metadata['version'])) ? htmlspecialchars($this->metadata['version']) : '', + 'META_TIME' => (isset($this->metadata['time'])) ? htmlspecialchars($this->metadata['time']) : '', + 'META_LICENCE' => htmlspecialchars($this->metadata['licence']), + + 'META_REQUIRE_PHP' => (isset($this->metadata['require']['php'])) ? htmlspecialchars($this->metadata['require']['php']) : '', + 'META_REQUIRE_PHP_FAIL' => !$this->validate_require_php(), + + 'META_REQUIRE_PHPBB' => (isset($this->metadata['require']['phpbb'])) ? htmlspecialchars($this->metadata['require']['phpbb']) : '', + 'META_REQUIRE_PHPBB_FAIL' => !$this->validate_require_phpbb(), + + 'META_DISPLAY_NAME' => (isset($this->metadata['extra']['display-name'])) ? htmlspecialchars($this->metadata['extra']['display-name']) : '', + )); + + foreach ($this->metadata['authors'] as $author) + { + $this->template->assign_block_vars('meta_authors', array( + 'AUTHOR_NAME' => htmlspecialchars($author['name']), + 'AUTHOR_EMAIL' => (isset($author['email'])) ? $author['email'] : '', + 'AUTHOR_HOMEPAGE' => (isset($author['homepage'])) ? $author['homepage'] : '', + 'AUTHOR_ROLE' => (isset($author['role'])) ? htmlspecialchars($author['role']) : '', + )); + } + } +} diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 502b3bb1a4..0b470ced26 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -683,12 +683,12 @@ function _write_result($no_updates, $errored, $error_ary) function _add_modules($modules_to_install) { - global $phpbb_root_path, $phpEx, $db, $phpbb_extension_manager; + global $phpbb_root_path, $phpEx, $db, $phpbb_extension_manager, $config; // modules require an extension manager if (empty($phpbb_extension_manager)) { - $phpbb_extension_manager = new phpbb_extension_manager($db, EXT_TABLE, $phpbb_root_path, ".$phpEx"); + $phpbb_extension_manager = new phpbb_extension_manager($db, $config, EXT_TABLE, $phpbb_root_path, ".$phpEx"); } include_once($phpbb_root_path . 'includes/acp/acp_modules.' . $phpEx); diff --git a/phpBB/install/install_install.php b/phpBB/install/install_install.php index 23593ee51f..9162d5ab60 100644 --- a/phpBB/install/install_install.php +++ b/phpBB/install/install_install.php @@ -250,7 +250,7 @@ class install_install extends module 'S_EXPLAIN' => true, 'S_LEGEND' => false, )); - + // Check for php json support if (@extension_loaded('json')) { @@ -1481,12 +1481,12 @@ class install_install extends module */ function add_modules($mode, $sub) { - global $db, $lang, $phpbb_root_path, $phpEx, $phpbb_extension_manager; + global $db, $lang, $phpbb_root_path, $phpEx, $phpbb_extension_manager, $config; // modules require an extension manager if (empty($phpbb_extension_manager)) { - $phpbb_extension_manager = new phpbb_extension_manager($db, EXT_TABLE, $phpbb_root_path, ".$phpEx"); + $phpbb_extension_manager = new phpbb_extension_manager($db, $config, EXT_TABLE, $phpbb_root_path, ".$phpEx"); } include_once($phpbb_root_path . 'includes/acp/acp_modules.' . $phpEx); diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql index ea7864bd4c..ae7b9fcba3 100644 --- a/phpBB/install/schemas/schema_data.sql +++ b/phpBB/install/schemas/schema_data.sql @@ -345,6 +345,7 @@ INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('a_board', 1); INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('a_bots', 1); INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('a_clearlogs', 1); INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('a_email', 1); +INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('a_extensions', 1); INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('a_fauth', 1); INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('a_forum', 1); INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('a_forumadd', 1); diff --git a/phpBB/language/en/acp/common.php b/phpBB/language/en/acp/common.php index 04df897dba..5eb10d50b3 100644 --- a/phpBB/language/en/acp/common.php +++ b/phpBB/language/en/acp/common.php @@ -81,6 +81,7 @@ $lang = array_merge($lang, array( 'ACP_EMAIL_SETTINGS' => 'Email settings', 'ACP_EXTENSION_GROUPS' => 'Manage extension groups', + 'ACP_EXTENSIONS' => 'Manage board extensions', 'ACP_FORUM_BASED_PERMISSIONS' => 'Forum based permissions', 'ACP_FORUM_LOGS' => 'Forum logs', diff --git a/phpBB/language/en/acp/extensions.php b/phpBB/language/en/acp/extensions.php new file mode 100644 index 0000000000..0adaff10c8 --- /dev/null +++ b/phpBB/language/en/acp/extensions.php @@ -0,0 +1,103 @@ +<?php +/** +* +* acp_extensions [English] +* +* @package language +* @copyright (c) 2012 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License +* +*/ +/** +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* DO NOT CHANGE +*/ +if (empty($lang) || !is_array($lang)) +{ + $lang = array(); +} + +// DEVELOPERS PLEASE NOTE +// +// Placeholders can now contain order information, e.g. instead of +// 'Page %s of %s' you can (and should) write 'Page %1$s of %2$s', this allows +// translators to re-order the output of data while ensuring it remains correct +// +// You do not need this where single placeholders are used, e.g. 'Message %d' is fine +// equally where a string contains only two placeholders which are used to wrap text +// in a url you again do not need to specify an order e.g., 'Click %sHERE%s' is fine + + +$lang = array_merge($lang, array( + 'EXTENSION' => 'Extension', + 'EXTENSIONS' => 'Extensions', + 'EXTENSIONS_ADMIN' => 'Extensions Manager', + 'EXTENSIONS_EXPLAIN' => 'The Extensions Manager is a tool in your phpBB Board which allows you to manage all of your extensions statuses and view information about them.', + 'EXTENSION_INVALID_LIST' => 'The "%s" extension is not valid.<br /><p>%s</p>', + 'EXTENSION_NOT_AVAILABLE' => 'The selected extension is not available for this board, please verify your phpBB and PHP versions are allowed (see the details page).', + + 'DETAILS' => 'Details', + + 'AVAILABLE' => 'Available', + 'ENABLED' => 'Enabled', + 'DISABLED' => 'Disabled', + 'PURGED' => 'Purged', + 'UPLOADED' => 'Uploaded', + + 'ENABLE' => 'Enable', + 'DISABLE' => 'Disable', + 'PURGE' => 'Purge', + + 'ENABLE_EXPLAIN' => 'Enabling an extension allows you to use it on your board.', + 'DISABLE_EXPLAIN' => 'Disabling an extension retains its files and settings but removes any functionality added by the extension.', + 'PURGE_EXPLAIN' => 'Purging an extension clears an extensions data while retaining its files.', + 'DELETE_EXPLAIN' => 'Deleting an extension removes all of its files and settings. Log entries will remain, although any language variables added by the extension will not be available.', + + 'DISABLE_IN_PROGRESS' => 'The extension is currently being disabled, please do not leave this page or refresh until it is completed.', + 'ENABLE_IN_PROGRESS' => 'The extension is currently being installed, please do not leave this page or refresh until it is completed.', + 'PURGE_IN_PROGRESS' => 'The extension is currently being purged, please do not leave this page or refresh until it is completed.', + 'ENABLE_SUCCESS' => 'The extension was enabled successfully', + 'DISABLE_SUCCESS' => 'The extension was disabled successfully', + 'PURGE_SUCCESS' => 'The extension was purged successfully', + + 'ENABLE_FAIL' => 'The extension could not be enabled', + 'DISABLE_FAIL' => 'The extension could not be disabled', + 'PURGE_FAIL' => 'The extension could not be purged', + + 'EXTENSION_NAME' => 'Extension Name', + 'EXTENSION_ACTIONS' => 'Actions', + 'EXTENSION_OPTIONS' => 'Options', + + 'ENABLE_CONFIRM' => 'Are you sure that you wish to enable this extension?', + 'DISABLE_CONFIRM' => 'Are you sure that you wish to disable this extension?', + 'PURGE_CONFIRM' => 'Are you sure that you wish to purge this extension's data? This will remove all settings stored for this extension and cannot be undone!', + + 'WARNING' => 'Warning', + 'RETURN' => 'Return', + + 'EXT_DETAILS' => 'Extension Details', + 'DISPLAY_NAME' => 'Display Name', + 'CLEAN_NAME' => 'Clean Name', + 'TYPE' => 'Type', + 'DESCRIPTION' => 'Description', + 'VERSION' => 'Version', + 'HOMEPAGE' => 'Homepage', + 'PATH' => 'File Path', + 'TIME' => 'Release Time', + 'LICENCE' => 'Licence', + + 'REQUIREMENTS' => 'Requirements', + 'PHPBB_VERSION' => 'phpBB Version', + 'PHP_VERSION' => 'PHP Version', + 'AUTHOR_INFORMATION' => 'Author Information', + 'AUTHOR_NAME' => 'Name', + 'AUTHOR_EMAIL' => 'Email', + 'AUTHOR_HOMEPAGE' => 'Homepage', + 'AUTHOR_ROLE' => 'Role', +)); diff --git a/phpBB/language/en/acp/permissions_phpbb.php b/phpBB/language/en/acp/permissions_phpbb.php index 17649693fa..bb068e625f 100644 --- a/phpBB/language/en/acp/permissions_phpbb.php +++ b/phpBB/language/en/acp/permissions_phpbb.php @@ -226,6 +226,7 @@ $lang = array_merge($lang, array( 'acl_a_switchperm' => array('lang' => 'Can use others permissions', 'cat' => 'permissions'), 'acl_a_styles' => array('lang' => 'Can manage styles', 'cat' => 'misc'), + 'acl_a_extensions' => array('lang' => 'Can manage extensions', 'cat' => 'misc'), 'acl_a_viewlogs' => array('lang' => 'Can view logs', 'cat' => 'misc'), 'acl_a_clearlogs' => array('lang' => 'Can clear logs', 'cat' => 'misc'), 'acl_a_modules' => array('lang' => 'Can manage modules', 'cat' => 'misc'), |