Merge remote-tracking branch 'unknownbliss/ticket/10631' into develop

This commit is contained in:
David King 2012-09-01 16:38:47 -04:00
commit 7bf598954c
25 changed files with 1945 additions and 6 deletions

View file

@ -0,0 +1,97 @@
<!-- INCLUDE overall_header.html -->
<a name="maincontent"></a>
<a href="{U_BACK}" style="float: {S_CONTENT_FLOW_END};">&laquo; {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 -->

View file

@ -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 -->

View file

@ -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 -->

View file

@ -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 -->&nbsp;|&nbsp;<!-- 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 -->&nbsp;|&nbsp;<!-- ENDIF -->
<!-- END actions -->
</td>
</tr>
<!-- END disabled -->
<!-- ENDIF -->
</tbody>
</table>
<!-- INCLUDE overall_footer.html -->

View file

@ -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 -->

View file

@ -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;
}

View file

@ -83,6 +83,7 @@ services:
class: phpbb_extension_manager
arguments:
- @dbal.conn
- @config
- %tables.ext%
- %core.root_path%
- .%core.php_ext%

View file

@ -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 . '&amp;action=enable&amp;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 . '&amp;action=enable&amp;ext_name=' . urlencode($ext_name));
}
$this->tpl_name = 'acp_ext_enable';
$template->assign_vars(array(
'U_RETURN' => $this->u_action . '&amp;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 . '&amp;action=disable&amp;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 . '&amp;action=disable&amp;ext_name=' . urlencode($ext_name));
}
$this->tpl_name = 'acp_ext_disable';
$template->assign_vars(array(
'U_RETURN' => $this->u_action . '&amp;action=list',
));
break;
case 'purge_pre':
$this->tpl_name = 'acp_ext_purge';
$template->assign_vars(array(
'PRE' => true,
'U_PURGE' => $this->u_action . '&amp;action=purge&amp;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 . '&amp;action=purge&amp;ext_name=' . urlencode($ext_name));
}
$this->tpl_name = 'acp_ext_purge';
$template->assign_vars(array(
'U_RETURN' => $this->u_action . '&amp;action=list',
));
break;
case 'details':
// Output it to the template
$md_manager->output_template_data();
$template->assign_var('U_BACK', $this->u_action . '&amp;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 . '&amp;action=details&amp;ext_name=' . urlencode($name),
));
$this->output_actions('enabled', array(
'DISABLE' => $this->u_action . '&amp;action=disable_pre&amp;ext_name=' . urlencode($name),
'PURGE' => $this->u_action . '&amp;action=purge_pre&amp;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 . '&amp;action=details&amp;ext_name=' . urlencode($name),
));
$this->output_actions('disabled', array(
'ENABLE' => $this->u_action . '&amp;action=enable_pre&amp;ext_name=' . urlencode($name),
'PURGE' => $this->u_action . '&amp;action=purge_pre&amp;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 . '&amp;action=details&amp;ext_name=' . urlencode($name),
));
$this->output_actions('disabled', array(
'ENABLE' => $this->u_action . '&amp;action=enable_pre&amp;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,
));
}
}
}

View file

@ -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()
{
}
}

View file

@ -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();
}
}

View file

@ -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;
@ -120,6 +124,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.
*

View file

@ -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']) : '',
));
}
}
}

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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',

View file

@ -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&#39;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',
));

View file

@ -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'),

205
tests/extension/acp.php Normal file
View file

@ -0,0 +1,205 @@
<?php
/**
*
* @package testing
* @copyright (c) 2011 phpBB Group
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
*
*/
class acp_test extends phpbb_functional_test_case
{
static private $copied_files = array();
static private $helper;
/**
* This should only be called once before the tests are run.
* This is used to copy the extensions to the phpBB install
*/
static public function setUpBeforeClass()
{
global $phpbb_root_path;
parent::setUpBeforeClass();
self::$helper = new phpbb_test_case_helpers(self);
// First, move any extensions setup on the board to a temp directory
self::$copied_files = self::$helper->copy_dir($phpbb_root_path . 'ext/', $phpbb_root_path . 'store/temp_ext/');
// Then empty the ext/ directory on the board (for accurate test cases)
self::$helper->empty_dir($phpbb_root_path . 'ext/');
// Copy our ext/ files from the test case to the board
self::$copied_files = array_merge(self::$copied_files, self::$helper->copy_dir(dirname(__FILE__) . '/ext/', $phpbb_root_path . 'ext/'));
}
public function setUp()
{
parent::setUp();
$this->get_db();
// Clear the phpbb_ext table
$this->db->sql_query('DELETE FROM phpbb_ext');
// Insert our base data
$insert_rows = array(
array(
'ext_name' => 'foo',
'ext_active' => true,
'ext_state' => 'b:0;',
),
array(
'ext_name' => 'vendor/moo',
'ext_active' => false,
'ext_state' => 'b:0;',
),
// do not exist
array(
'ext_name' => 'test2',
'ext_active' => true,
'ext_state' => 'b:0;',
),
array(
'ext_name' => 'test3',
'ext_active' => false,
'ext_state' => 'b:0;',
),
);
$this->db->sql_multi_insert('phpbb_ext', $insert_rows);
$this->login();
$this->admin_login();
$this->add_lang('acp/extensions');
}
/**
* This should only be called once after the tests are run.
* This is used to remove the files copied to the phpBB install
*/
static public function tearDownAfterClass()
{
global $phpbb_root_path;
// Copy back the board installed extensions from the temp directory
self::$helper->copy_dir($phpbb_root_path . 'store/temp_ext/', $phpbb_root_path . 'ext/');
self::$copied_files[] = $phpbb_root_path . 'store/temp_ext/';
// Remove all of the files we copied around (from board ext -> temp_ext, from test ext -> board ext)
self::$helper->remove_files(self::$copied_files);
}
public function test_list()
{
$crawler = $this->request('GET', 'adm/index.php?i=acp_extensions&mode=main&sid=' . $this->sid);
$this->assertCount(1, $crawler->filter('.ext_enabled'));
$this->assertCount(4, $crawler->filter('.ext_disabled'));
$this->assertContains('phpBB Foo Extension', $crawler->filter('.ext_enabled')->eq(0)->text());
$this->assertContainsLang('PURGE', $crawler->filter('.ext_enabled')->eq(0)->text());
$this->assertContains('The "test2" extension is not valid.', $crawler->filter('.ext_disabled')->eq(0)->text());
$this->assertContains('The "test3" extension is not valid.', $crawler->filter('.ext_disabled')->eq(1)->text());
$this->assertContains('phpBB Moo Extension', $crawler->filter('.ext_disabled')->eq(2)->text());
$this->assertContainsLang('DETAILS', $crawler->filter('.ext_disabled')->eq(2)->text());
$this->assertContainsLang('ENABLE', $crawler->filter('.ext_disabled')->eq(2)->text());
$this->assertContainsLang('PURGE', $crawler->filter('.ext_disabled')->eq(2)->text());
$this->assertContains('The "bar" extension is not valid.', $crawler->filter('.ext_disabled')->eq(3)->text());
}
public function test_details()
{
$crawler = $this->request('GET', 'adm/index.php?i=acp_extensions&mode=main&action=details&ext_name=foo&sid=' . $this->sid);
$validation = array(
'DISPLAY_NAME' => 'phpBB Foo Extension',
'CLEAN_NAME' => 'foo/example',
'DESCRIPTION' => 'An example/sample extension to be used for testing purposes in phpBB Development.',
'VERSION' => '1.0.0',
'TIME' => '2012-02-15 01:01:01',
'LICENCE' => 'GPL-2.0',
'PHPBB_VERSION' => '3.1.0-dev',
'PHP_VERSION' => '>=5.3',
'AUTHOR_NAME' => 'Nathan Guse',
'AUTHOR_EMAIL' => 'email@phpbb.com',
'AUTHOR_HOMEPAGE' => 'http://lithiumstudios.org',
'AUTHOR_ROLE' => 'N/A',
);
for ($i = 0; $i < $crawler->filter('dl')->count(); $i++)
{
$text = $crawler->filter('dl')->eq($i)->text();
$match = false;
foreach ($validation as $language_key => $expected)
{
if (strpos($text, $this->lang($language_key)) === 0)
{
$match = true;
$this->assertContains($expected, $text);
}
}
if (!$match)
{
$this->fail('Unexpected field: "' . $text . '"');
}
}
}
public function test_enable_pre()
{
// Foo is already enabled (redirect to list)
$crawler = $this->request('GET', 'adm/index.php?i=acp_extensions&mode=main&action=enable_pre&ext_name=foo&sid=' . $this->sid);
$this->assertContainsLang('EXTENSION_NAME', $crawler->filter('html')->text());
$this->assertContainsLang('EXTENSION_OPTIONS', $crawler->filter('html')->text());
$this->assertContainsLang('EXTENSION_ACTIONS', $crawler->filter('html')->text());
$crawler = $this->request('GET', 'adm/index.php?i=acp_extensions&mode=main&action=enable_pre&ext_name=vendor%2Fmoo&sid=' . $this->sid);
$this->assertContainsLang('ENABLE_CONFIRM', $crawler->filter('html')->text());
}
public function test_disable_pre()
{
// Moo is not enabled (redirect to list)
$crawler = $this->request('GET', 'adm/index.php?i=acp_extensions&mode=main&action=disable_pre&ext_name=vendor%2Fmoo&sid=' . $this->sid);
$this->assertContainsLang('EXTENSION_NAME', $crawler->filter('html')->text());
$this->assertContainsLang('EXTENSION_OPTIONS', $crawler->filter('html')->text());
$this->assertContainsLang('EXTENSION_ACTIONS', $crawler->filter('html')->text());
$crawler = $this->request('GET', 'adm/index.php?i=acp_extensions&mode=main&action=disable_pre&ext_name=foo&sid=' . $this->sid);
$this->assertContainsLang('DISABLE_CONFIRM', $crawler->filter('html')->text());
}
public function test_purge_pre()
{
// test2 is not available (error)
$crawler = $this->request('GET', 'adm/index.php?i=acp_extensions&mode=main&action=purge_pre&ext_name=test2&sid=' . $this->sid);
$this->assertContains('The required file does not exist', $crawler->filter('html')->text());
$crawler = $this->request('GET', 'adm/index.php?i=acp_extensions&mode=main&action=purge_pre&ext_name=foo&sid=' . $this->sid);
$this->assertContainsLang('PURGE_CONFIRM', $crawler->filter('html')->text());
}
public function test_actions()
{
$crawler = $this->request('GET', 'adm/index.php?i=acp_extensions&mode=main&action=enable&ext_name=vendor%2Fmoo&sid=' . $this->sid);
$this->assertContainsLang('ENABLE_SUCCESS', $crawler->filter('html')->text());
$crawler = $this->request('GET', 'adm/index.php?i=acp_extensions&mode=main&action=disable&ext_name=vendor%2Fmoo&sid=' . $this->sid);
$this->assertContainsLang('DISABLE_SUCCESS', $crawler->filter('html')->text());
$crawler = $this->request('GET', 'adm/index.php?i=acp_extensions&mode=main&action=purge&ext_name=vendor%2Fmoo&sid=' . $this->sid);
$this->assertContainsLang('PURGE_SUCCESS', $crawler->filter('html')->text());
}
}

View file

@ -0,0 +1,22 @@
{
"name": "foo/example",
"type": "phpbb3-extension",
"description": "An example/sample extension to be used for testing purposes in phpBB Development.",
"version": "1.0.0",
"time": "2012-02-15 01:01:01",
"licence": "GPL-2.0",
"authors": [{
"name": "Nathan Guse",
"username": "EXreaction",
"email": "email@phpbb.com",
"homepage": "http://lithiumstudios.org",
"role": "N/A"
}],
"require": {
"php": ">=5.3",
"phpbb": "3.1.0-dev"
},
"extra": {
"display-name": "phpBB Foo Extension"
}
}

View file

@ -0,0 +1,22 @@
{
"name": "moo/example",
"type": "phpbb3-extension",
"description": "An example/sample extension to be used for testing purposes in phpBB Development.",
"version": "1.0.0",
"time": "2012-02-15 01:01:01",
"licence": "GNU GPL v2",
"authors": [{
"name": "Nathan Guse",
"username": "EXreaction",
"email": "email@phpbb.com",
"homepage": "http://lithiumstudios.org",
"role": "N/A"
}],
"require": {
"php": ">=5.3",
"phpbb": "3.1.0-dev"
},
"extra": {
"display-name": "phpBB Moo Extension"
}
}

View file

@ -27,6 +27,7 @@ class phpbb_extension_manager_test extends phpbb_database_test_case
$this->extension_manager = new phpbb_extension_manager(
$this->new_dbal(),
new phpbb_config(array()),
'phpbb_ext',
dirname(__FILE__) . '/',
'.php',
@ -90,6 +91,7 @@ class phpbb_extension_manager_test extends phpbb_database_test_case
{
$extension_manager = new phpbb_extension_manager(
$this->new_dbal(),
new phpbb_config(array()),
'phpbb_ext',
dirname(__FILE__) . '/',
'.php'

View file

@ -0,0 +1,430 @@
<?php
/**
*
* @package testing
* @copyright (c) 2011 phpBB Group
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
*
*/
class metadata_manager_test extends phpbb_database_test_case
{
protected $class_loader;
protected $extension_manager;
protected $cache;
protected $config;
protected $db;
protected $phpbb_root_path;
protected $phpEx;
protected $template;
protected $user;
public function getDataSet()
{
return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/extensions.xml');
}
protected function setUp()
{
parent::setUp();
$this->cache = new phpbb_mock_cache();
$this->config = new phpbb_config(array(
'version' => '3.1.0',
));
$this->db = $this->new_dbal();
$this->phpbb_root_path = dirname(__FILE__) . '/';
$this->phpEx = '.php';
$this->user = new phpbb_user();
$this->template = new phpbb_template(
$this->phpbb_root_path,
$this->phpEx,
$this->config,
$this->user,
new phpbb_style_resource_locator()
);
$this->extension_manager = new phpbb_extension_manager(
$this->db,
$this->config,
'phpbb_ext',
$this->phpbb_root_path,
$this->phpEx,
$this->cache
);
}
// Should fail from missing composer.json
public function test_bar()
{
$ext_name = 'bar';
$manager = $this->get_metadata_manager($ext_name);
try
{
$manager->get_metadata();
}
catch(phpbb_extension_exception $e){}
$this->assertEquals((string) $e, 'The required file does not exist: ' . $this->phpbb_root_path . $this->extension_manager->get_extension_path($ext_name) . 'composer.json');
}
// Should be the same as a direct json_decode of the composer.json file
public function test_foo()
{
$ext_name = 'foo';
$manager = $this->get_metadata_manager($ext_name);
try
{
$metadata = $manager->get_metadata();
}
catch(phpbb_extension_exception $e)
{
$this->fail($e);
}
$json = json_decode(file_get_contents($this->phpbb_root_path . 'ext/foo/composer.json'), true);
$this->assertEquals($metadata, $json);
}
public function test_validator_non_existant()
{
$ext_name = 'validator';
$manager = $this->get_metadata_manager($ext_name);
// Non-existant data
try
{
$manager->validate('name');
$this->fail('Exception not triggered');
}
catch(phpbb_extension_exception $e)
{
$this->assertEquals((string) $e, 'Required meta field \'name\' has not been set.');
}
try
{
$manager->validate('type');
$this->fail('Exception not triggered');
}
catch(phpbb_extension_exception $e)
{
$this->assertEquals((string) $e, 'Required meta field \'type\' has not been set.');
}
try
{
$manager->validate('licence');
$this->fail('Exception not triggered');
}
catch(phpbb_extension_exception $e)
{
$this->assertEquals((string) $e, 'Required meta field \'licence\' has not been set.');
}
try
{
$manager->validate('version');
$this->fail('Exception not triggered');
}
catch(phpbb_extension_exception $e)
{
$this->assertEquals((string) $e, 'Required meta field \'version\' has not been set.');
}
try
{
$manager->validate_authors();
$this->fail('Exception not triggered');
}
catch(phpbb_extension_exception $e)
{
$this->assertEquals((string) $e, 'Required meta field \'authors\' has not been set.');
}
$manager->merge_metadata(array(
'authors' => array(
array(),
),
));
try
{
$manager->validate_authors();
$this->fail('Exception not triggered');
}
catch(phpbb_extension_exception $e)
{
$this->assertEquals((string) $e, 'Required meta field \'author name\' has not been set.');
}
}
public function test_validator_invalid()
{
$ext_name = 'validator';
$manager = $this->get_metadata_manager($ext_name);
// Invalid data
$manager->set_metadata(array(
'name' => 'asdf',
'type' => 'asdf',
'licence' => '',
'version' => '',
));
try
{
$manager->validate('name');
$this->fail('Exception not triggered');
}
catch(phpbb_extension_exception $e)
{
$this->assertEquals((string) $e, 'Meta field \'name\' is invalid.');
}
try
{
$manager->validate('type');
$this->fail('Exception not triggered');
}
catch(phpbb_extension_exception $e)
{
$this->assertEquals((string) $e, 'Meta field \'type\' is invalid.');
}
try
{
$manager->validate('licence');
$this->fail('Exception not triggered');
}
catch(phpbb_extension_exception $e)
{
$this->assertEquals((string) $e, 'Meta field \'licence\' is invalid.');
}
try
{
$manager->validate('version');
$this->fail('Exception not triggered');
}
catch(phpbb_extension_exception $e)
{
$this->assertEquals((string) $e, 'Meta field \'version\' is invalid.');
}
}
public function test_validator_valid()
{
$ext_name = 'validator';
$manager = $this->get_metadata_manager($ext_name);
// Valid data
$manager->set_metadata(array(
'name' => 'test/foo',
'type' => 'phpbb3-extension',
'licence' => 'GPL v2',
'version' => '1.0.0',
));
try
{
$this->assertEquals(true, $manager->validate('enable'));
}
catch(phpbb_extension_exception $e)
{
$this->fail($e);
}
}
public function test_validator_requirements()
{
$ext_name = 'validator';
$manager = $this->get_metadata_manager($ext_name);
// Too high of requirements
$manager->merge_metadata(array(
'require' => array(
'php' => '10.0.0',
'phpbb' => '3.2.0', // config is set to 3.1.0
),
));
try
{
$this->assertEquals(false, $manager->validate_require_php());
$this->assertEquals(false, $manager->validate_require_phpbb());
}
catch(phpbb_extension_exception $e)
{
$this->fail($e);
}
// Too high of requirements
$manager->merge_metadata(array(
'require' => array(
'php' => '5.3.0',
'phpbb' => '3.1.0-beta', // config is set to 3.1.0
),
));
try
{
$this->assertEquals(true, $manager->validate_require_php());
$this->assertEquals(true, $manager->validate_require_phpbb());
}
catch(phpbb_extension_exception $e)
{
$this->fail($e);
}
// Too high of requirements
$manager->merge_metadata(array(
'require' => array(
'php' => '>' . phpversion(),
'phpbb' => '>3.1.0', // config is set to 3.1.0
),
));
try
{
$this->assertEquals(false, $manager->validate_require_php());
$this->assertEquals(false, $manager->validate_require_phpbb());
}
catch(phpbb_extension_exception $e)
{
$this->fail($e);
}
// Too high of current install
$manager->merge_metadata(array(
'require' => array(
'php' => '<' . phpversion(),
'phpbb' => '<3.1.0', // config is set to 3.1.0
),
));
try
{
$this->assertEquals(false, $manager->validate_require_php());
$this->assertEquals(false, $manager->validate_require_phpbb());
}
catch(phpbb_extension_exception $e)
{
$this->fail($e);
}
// Matching requirements
$manager->merge_metadata(array(
'require' => array(
'php' => phpversion(),
'phpbb' => '3.1.0', // config is set to 3.1.0
),
));
try
{
$this->assertEquals(true, $manager->validate_require_php());
$this->assertEquals(true, $manager->validate_require_phpbb());
}
catch(phpbb_extension_exception $e)
{
$this->fail($e);
}
// Matching requirements
$manager->merge_metadata(array(
'require' => array(
'php' => '>=' . phpversion(),
'phpbb' => '>=3.1.0', // config is set to 3.1.0
),
));
try
{
$this->assertEquals(true, $manager->validate_require_php());
$this->assertEquals(true, $manager->validate_require_phpbb());
}
catch(phpbb_extension_exception $e)
{
$this->fail($e);
}
// Matching requirements
$manager->merge_metadata(array(
'require' => array(
'php' => '<=' . phpversion(),
'phpbb' => '<=3.1.0', // config is set to 3.1.0
),
));
try
{
$this->assertEquals(true, $manager->validate_require_php());
$this->assertEquals(true, $manager->validate_require_phpbb());
}
catch(phpbb_extension_exception $e)
{
$this->fail($e);
}
}
/**
* Get an instance of the metadata manager
*
* @param string $ext_name
* @return phpbb_extension_metadata_manager_test
*/
private function get_metadata_manager($ext_name)
{
return new phpbb_extension_metadata_manager_test(
$ext_name,
$this->db,
$this->extension_manager,
$this->phpbb_root_path,
$this->phpEx,
$this->template,
$this->config
);
}
}
class phpbb_extension_metadata_manager_test extends phpbb_extension_metadata_manager
{
public function set_metadata($metadata)
{
$this->metadata = $metadata;
}
public function merge_metadata($metadata)
{
$this->metadata = array_merge($this->metadata, $metadata);
}
}

View file

@ -125,6 +125,7 @@ class phpbb_functional_test_case extends phpbb_test_case
{
$this->extension_manager = new phpbb_extension_manager(
$this->get_db(),
new phpbb_config(),
self::$config['table_prefix'] . 'ext',
$phpbb_root_path,
".$phpEx",
@ -251,6 +252,48 @@ class phpbb_functional_test_case extends phpbb_test_case
}
}
/**
* Login to the ACP
* You must run login() before calling this.
*/
protected function admin_login()
{
$this->add_lang('acp/common');
// Requires login first!
if (empty($this->sid))
{
$this->fail('$this->sid is empty. Make sure you call login() before admin_login()');
return;
}
$crawler = $this->request('GET', 'adm/index.php?sid=' . $this->sid);
$this->assertContains($this->lang('LOGIN_ADMIN_CONFIRM'), $crawler->filter('html')->text());
$form = $crawler->selectButton($this->lang('LOGIN'))->form();
foreach ($form->getValues() as $field => $value)
{
if (strpos($field, 'password_') === 0)
{
$login = $this->client->submit($form, array('username' => 'admin', $field => 'admin'));
$cookies = $this->cookieJar->all();
// The session id is stored in a cookie that ends with _sid - we assume there is only one such cookie
foreach ($cookies as $cookie);
{
if (substr($cookie->getName(), -4) == '_sid')
{
$this->sid = $cookie->getValue();
}
}
break;
}
}
}
protected function add_lang($lang_file)
{
if (is_array($lang_file))
@ -287,4 +330,16 @@ class phpbb_functional_test_case extends phpbb_test_case
return call_user_func_array('sprintf', $args);
}
/**
* assertContains for language strings
*
* @param string $needle Search string
* @param string $haystack Search this
* @param string $message Optional failure message
*/
public function assertContainsLang($needle, $haystack, $message = null)
{
$this->assertContains(html_entity_decode($this->lang($needle), ENT_QUOTES), $haystack, $message);
}
}

View file

@ -115,4 +115,112 @@ class phpbb_test_case_helpers
return $config;
}
/**
* Recursive directory copying function
*
* @param string $source
* @param string $dest
* @return array list of files copied
*/
public function copy_dir($source, $dest)
{
$source = (substr($source, -1) == '/') ? $source : $source . '/';
$dest = (substr($dest, -1) == '/') ? $dest : $dest . '/';
$copied_files = array();
if (!is_dir($dest))
{
$this->makedirs($dest);
}
$files = scandir($source);
foreach ($files as $file)
{
if ($file == '.' || $file == '..')
{
continue;
}
if (is_dir($source . $file))
{
$created_dir = false;
if (!is_dir($dest . $file))
{
$created_dir = true;
$this->makedirs($dest . $file);
}
$copied_files = array_merge($copied_files, self::copy_dir($source . $file, $dest . $file));
if ($created_dir)
{
$copied_files[] = $dest . $file;
}
}
else
{
if (!file_exists($dest . $file))
{
copy($source . $file, $dest . $file);
$copied_files[] = $dest . $file;
}
}
}
return $copied_files;
}
/**
* Remove files/directories that are listed in an array
* Designed for use with $this->copy_dir()
*
* @param array $file_list
*/
public function remove_files($file_list)
{
foreach ($file_list as $file)
{
if (is_dir($file))
{
rmdir($file);
}
else
{
unlink($file);
}
}
}
/**
* Empty directory (remove any subdirectories/files below)
*
* @param array $file_list
*/
public function empty_dir($path)
{
$path = (substr($path, -1) == '/') ? $path : $path . '/';
$files = scandir($path);
foreach ($files as $file)
{
if ($file == '.' || $file == '..')
{
continue;
}
if (is_dir($path . $file))
{
$this->empty_dir($path . $file);
rmdir($path . $file);
}
else
{
unlink($path . $file);
}
}
}
}