diff --git a/phpBB/adm/style/admin.css b/phpBB/adm/style/admin.css
index 4bb9922d56..e1668bf70b 100644
--- a/phpBB/adm/style/admin.css
+++ b/phpBB/adm/style/admin.css
@@ -2471,7 +2471,7 @@ fieldset.permissions .padding {
.roles-options > .dropdown {
left: auto;
- top: 3em;
+ top: 3.2em;
width: 250px;
}
@@ -2489,7 +2489,7 @@ fieldset.permissions .padding {
border-radius: 3px;
padding: 4px;
width: 250px;
- display: block;
+ display: none;
background: url('../images/arrow_down.gif') no-repeat 245px .7em;
}
diff --git a/phpBB/adm/style/permission_mask.html b/phpBB/adm/style/permission_mask.html
index 347da3181e..017d29d832 100644
--- a/phpBB/adm/style/permission_mask.html
+++ b/phpBB/adm/style/permission_mask.html
@@ -39,18 +39,19 @@
- {% if role_options %}
+ {% if p_mask.f_mask.role_options %}
-
{% else %}
diff --git a/phpBB/adm/style/tooltip.js b/phpBB/adm/style/tooltip.js
index 68964034f0..65773ae14f 100644
--- a/phpBB/adm/style/tooltip.js
+++ b/phpBB/adm/style/tooltip.js
@@ -141,20 +141,43 @@ phpbb.positionTooltip = function ($element) {
*/
phpbb.prepareRolesDropdown = function () {
var $options = $('.roles-options li');
- var $rolesOptions = $options.closest('.roles-options');
- var $span = $rolesOptions.children('span');
+
+ // Display span and hide select
+ $('.roles-options > span').css('display', 'block');
+ $('.roles-options > select').hide();
+ $('.roles-options > input[type=hidden]').each(function () {
+ var $this = $(this);
+
+ if ($this.attr('data-name') && !$this.attr('name')) {
+ $this.attr('name', $this.attr('data-name'));
+ }
+ });
// Prepare highlighting of select options and settings update
$options.each(function () {
var $this = $(this);
+ var $rolesOptions = $this.closest('.roles-options');
+ var $span = $rolesOptions.children('span');
// Correctly show selected option
if (typeof $this.attr('data-selected') !== 'undefined') {
- $rolesOptions.closest('.roles-options')
+ $rolesOptions
.children('span')
.text($this.text())
.attr('data-default', $this.text())
.attr('data-default-val', $this.attr('data-id'));
+
+ // Save default text of drop down if there is no default set yet
+ if (typeof $span.attr('data-default') === 'undefined') {
+ $span.attr('data-default', $span.text());
+ }
+
+ // Prepare resetting drop down on form reset
+ $this.closest('form').on('reset', function () {
+ $span.text($span.attr('data-default'));
+ $rolesOptions.children('input[type=hidden]')
+ .val($span.attr('data-default-val'));
+ });
}
$this.on('mouseover', function () {
@@ -163,6 +186,7 @@ phpbb.prepareRolesDropdown = function () {
$this.addClass('roles-highlight');
}).on('click', function () {
var $this = $(this);
+ var $rolesOptions = $this.closest('.roles-options');
// Update settings
set_role_settings($this.attr('data-id'), $this.attr('data-target-id'));
@@ -178,19 +202,6 @@ phpbb.prepareRolesDropdown = function () {
$('body').trigger('click');
});
});
-
- // Save default text of drop down if there is no default set yet
- if (typeof $span.attr('data-default') === 'undefined') {
- $span.attr('data-default', $span.text());
- }
-
- // Prepare resetting drop down on form reset
- $options.closest('form').on('reset', function () {
- $span.text($span.attr('data-default'));
- $rolesOptions.children('input[type=hidden]')
- .val($span.attr('data-id'));
- });
-
};
// Run onload functions for RolesDropdown and tooltips
diff --git a/phpBB/includes/acp/auth.php b/phpBB/includes/acp/auth.php
index 11478842d7..b36b900396 100644
--- a/phpBB/includes/acp/auth.php
+++ b/phpBB/includes/acp/auth.php
@@ -466,8 +466,10 @@ class auth_admin extends \phpbb\auth\auth
// Build role dropdown options
$current_role_id = (isset($cur_roles[$ug_id][$forum_id])) ? $cur_roles[$ug_id][$forum_id] : 0;
- // Output current role id to template
- $template->assign_var('S_ROLE_ID', $current_role_id);
+ $role_options = array();
+
+ $s_role_options = '';
+ $current_role_id = (isset($cur_roles[$ug_id][$forum_id])) ? $cur_roles[$ug_id][$forum_id] : 0;
@reset($roles);
while (list($role_id, $role_row) = each($roles))
@@ -475,12 +477,20 @@ class auth_admin extends \phpbb\auth\auth
$role_description = (!empty($user->lang[$role_row['role_description']])) ? $user->lang[$role_row['role_description']] : nl2br($role_row['role_description']);
$role_name = (!empty($user->lang[$role_row['role_name']])) ? $user->lang[$role_row['role_name']] : $role_row['role_name'];
- $template->assign_block_vars('role_options', array(
+ $title = ($role_description) ? ' title="' . $role_description . '"' : '';
+ $s_role_options .= '';
+
+ $role_options[] = array(
'ID' => $role_id,
'ROLE_NAME' => $role_name,
'TITLE' => $role_description,
'SELECTED' => $role_id == $current_role_id,
- ));
+ );
+ }
+
+ if ($s_role_options)
+ {
+ $s_role_options = '' . $s_role_options;
}
if (!$current_role_id && $mode != 'view')
@@ -504,9 +514,13 @@ class auth_admin extends \phpbb\auth\auth
$template->assign_block_vars($tpl_pmask . '.' . $tpl_fmask, array(
'NAME' => $ug_names_ary[$ug_id],
'UG_ID' => $ug_id,
+ 'S_ROLE_OPTIONS' => $s_role_options,
'S_CUSTOM' => $s_custom_permissions,
- 'FORUM_ID' => $forum_id)
- );
+ 'FORUM_ID' => $forum_id,
+ 'S_ROLE_ID' => $current_role_id,
+ ));
+
+ $template->assign_block_vars_array($tpl_pmask . '.' . $tpl_fmask . '.role_options', $role_options);
$this->assign_cat_array($ug_array, $tpl_pmask . '.' . $tpl_fmask . '.' . $tpl_category, $tpl_mask, $ug_id, $forum_id, ($mode == 'view'), $show_trace);
@@ -551,8 +565,10 @@ class auth_admin extends \phpbb\auth\auth
// Build role dropdown options
$current_role_id = (isset($cur_roles[$ug_id][$forum_id])) ? $cur_roles[$ug_id][$forum_id] : 0;
- // Output current role id to template
- $template->assign_var('S_ROLE_ID', $current_role_id);
+ $role_options = array();
+
+ $current_role_id = (isset($cur_roles[$ug_id][$forum_id])) ? $cur_roles[$ug_id][$forum_id] : 0;
+ $s_role_options = '';
@reset($roles);
while (list($role_id, $role_row) = each($roles))
@@ -560,12 +576,20 @@ class auth_admin extends \phpbb\auth\auth
$role_description = (!empty($user->lang[$role_row['role_description']])) ? $user->lang[$role_row['role_description']] : nl2br($role_row['role_description']);
$role_name = (!empty($user->lang[$role_row['role_name']])) ? $user->lang[$role_row['role_name']] : $role_row['role_name'];
- $template->assign_block_vars('role_options', array(
+ $title = ($role_description) ? ' title="' . $role_description . '"' : '';
+ $s_role_options .= '';
+
+ $role_options[] = array(
'ID' => $role_id,
'ROLE_NAME' => $role_name,
'TITLE' => $role_description,
'SELECTED' => $role_id == $current_role_id,
- ));
+ );
+ }
+
+ if ($s_role_options)
+ {
+ $s_role_options = '' . $s_role_options;
}
if (!$current_role_id && $mode != 'view')
@@ -591,9 +615,12 @@ class auth_admin extends \phpbb\auth\auth
'PADDING' => ($forum_id == 0) ? '' : $forum_names_ary[$forum_id]['padding'],
'S_CUSTOM' => $s_custom_permissions,
'UG_ID' => $ug_id,
+ 'S_ROLE_OPTIONS' => $s_role_options,
'FORUM_ID' => $forum_id)
);
+ $template->assign_block_vars_array($tpl_pmask . '.' . $tpl_fmask . '.role_options', $role_options);
+
$this->assign_cat_array($forum_array, $tpl_pmask . '.' . $tpl_fmask . '.' . $tpl_category, $tpl_mask, $ug_id, $forum_id, ($mode == 'view'), $show_trace);
}
diff --git a/tests/functional/permission_roles_test.php b/tests/functional/permission_roles_test.php
new file mode 100644
index 0000000000..82d5be68c3
--- /dev/null
+++ b/tests/functional/permission_roles_test.php
@@ -0,0 +1,86 @@
+
+* @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 __DIR__ . '/../../phpBB/includes/functions.php';
+
+/**
+* @group functional
+*/
+class functional_permission_roles_test extends phpbb_functional_test_case
+{
+ public function data_permission_roles()
+ {
+ return array(
+ array(
+ array(0, 14),
+ array(17, 17),
+ array(
+ 'role[5][1]' => 14,
+ )
+ ),
+ array(
+ array(14, 14),
+ array(17, 17),
+ array(
+ 'role[5][1]' => 0,
+ )
+ ),
+ array(
+ array(0, 14),
+ array(17, 17)
+ ),
+ );
+ }
+ /**
+ * @dataProvider data_permission_roles
+ */
+ public function test_permission_roles($admin_roles, $guest_roles, $set_values = array())
+ {
+ $this->login();
+ $this->admin_login();
+ $this->add_lang('acp/permissions');
+ $crawler = self::request('GET', 'adm/index.php?i=acp_permissions&mode=setting_forum_local&sid=' . $this->sid);
+
+ // Select forums
+ $form = $crawler->filter('form[id=select_victim]')->form();
+ $form['forum_id']->setValue(array(1,2));
+ $crawler = self::$client->submit($form);
+
+ // Select administrators and guests
+ $groups_form = $crawler->filter('form[id=groups]')->form();
+ $groups_form['group_id']->setValue(array(1,5));
+
+ $crawler = self::submit($groups_form);
+ $form = $crawler->filter('form')->form();
+ $values = $form->getValues();
+
+ // Check default settings
+ $this->assertEquals($admin_roles[0], $values['role[5][1]']);
+ $this->assertEquals($admin_roles[1], $values['role[5][2]']);
+ $this->assertEquals($guest_roles[0], $values['role[1][1]']);
+ $this->assertEquals($guest_roles[1], $values['role[1][2]']);
+
+ // Set admin to full access on category
+ foreach ($set_values as $key => $value)
+ {
+ $form[$key]->setValue($value);
+ }
+
+ $form_values = $form->getValues();
+ $form_values['action[apply_all_permissions]'] = true;
+ $crawler = self::request('POST', 'adm/index.php?i=acp_permissions&mode=setting_forum_local&sid=' . $this->sid, $form_values);
+ $this->assertContainsLang('AUTH_UPDATED', $crawler->text());
+
+ $this->logout();
+ }
+}
diff --git a/tests/test_framework/phpbb_ui_test_case.php b/tests/test_framework/phpbb_ui_test_case.php
index 8b60096081..9bb89781a1 100644
--- a/tests/test_framework/phpbb_ui_test_case.php
+++ b/tests/test_framework/phpbb_ui_test_case.php
@@ -34,6 +34,18 @@ class phpbb_ui_test_case extends phpbb_test_case
static protected $install_success = false;
static protected $db;
+ /**
+ * Session ID for current test's session (each test makes its own)
+ * @var string
+ */
+ protected $sid;
+
+ /**
+ * Language array used by phpBB
+ * @var array
+ */
+ protected $lang = array();
+
static public function setUpBeforeClass()
{
parent::setUpBeforeClass();
@@ -87,6 +99,11 @@ class phpbb_ui_test_case extends phpbb_test_case
{
$this->fail('Installing phpBB has failed.');
}
+
+ // Clear the language array so that things
+ // that were added in other tests are gone
+ $this->lang = array();
+ $this->add_lang('common');
}
protected function tearDown()
@@ -258,4 +275,184 @@ class phpbb_ui_test_case extends phpbb_test_case
}
return self::$db;
}
+
+ protected function logout()
+ {
+ $this->add_lang('ucp');
+
+ if (empty($this->sid))
+ {
+ return;
+ }
+
+ $this->visit('ucp.php?sid=' . $this->sid . '&mode=logout');
+ $this->assertContains($this->lang('REGISTER'), self::$webDriver->getPageSource());
+ unset($this->sid);
+
+ }
+
+ /**
+ * Login to the ACP
+ * You must run login() before calling this.
+ */
+ protected function admin_login($username = 'admin')
+ {
+ $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;
+ }
+
+ self::$webDriver->manage()->deleteAllCookies();
+
+ $this->visit('adm/index.php?sid=' . $this->sid);
+ $this->assertContains($this->lang('LOGIN_ADMIN_CONFIRM'), self::$webDriver->getPageSource());
+
+ self::find_element('cssSelector', 'input[name=username]')->clear()->sendKeys($username);
+ self::find_element('cssSelector', 'input[type=password]')->sendKeys($username . $username);
+ self::find_element('cssSelector', 'input[name=login]')->click();
+ $this->assertContains($this->lang('ADMIN_PANEL'), $this->find_element('cssSelector', 'h1')->getText());
+
+ $cookies = self::$webDriver->manage()->getCookies();
+
+ // 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['name'], -4) == '_sid')
+ {
+ $this->sid = $cookie['value'];
+
+ break;
+ }
+ }
+
+ $this->assertNotEmpty($this->sid);
+ }
+
+ protected function add_lang($lang_file)
+ {
+ if (is_array($lang_file))
+ {
+ foreach ($lang_file as $file)
+ {
+ $this->add_lang($file);
+ }
+ }
+
+ $lang_path = __DIR__ . "/../../phpBB/language/en/$lang_file.php";
+
+ $lang = array();
+
+ if (file_exists($lang_path))
+ {
+ include($lang_path);
+ }
+
+ $this->lang = array_merge($this->lang, $lang);
+ }
+
+ protected function add_lang_ext($ext_name, $lang_file)
+ {
+ if (is_array($lang_file))
+ {
+ foreach ($lang_file as $file)
+ {
+ $this->add_lang_ext($ext_name, $file);
+ }
+
+ return;
+ }
+
+ $lang_path = __DIR__ . "/../../phpBB/ext/{$ext_name}/language/en/$lang_file.php";
+
+ $lang = array();
+
+ if (file_exists($lang_path))
+ {
+ include($lang_path);
+ }
+
+ $this->lang = array_merge($this->lang, $lang);
+ }
+
+ protected function lang()
+ {
+ $args = func_get_args();
+ $key = $args[0];
+
+ if (empty($this->lang[$key]))
+ {
+ throw new RuntimeException('Language key "' . $key . '" could not be found.');
+ }
+
+ $args[0] = $this->lang[$key];
+
+ 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);
+ }
+
+ /**
+ * assertNotContains for language strings
+ *
+ * @param string $needle Search string
+ * @param string $haystack Search this
+ * @param string $message Optional failure message
+ */
+ public function assertNotContainsLang($needle, $haystack, $message = null)
+ {
+ $this->assertNotContains(html_entity_decode($this->lang($needle), ENT_QUOTES), $haystack, $message);
+ }
+
+ protected function login($username = 'admin')
+ {
+ $this->add_lang('ucp');
+
+ $this->visit('ucp.php');
+ $this->assertContains($this->lang('LOGIN_EXPLAIN_UCP'), self::$webDriver->getPageSource());
+
+ self::find_element('cssSelector', 'input[name=username]')->sendKeys($username);
+ self::find_element('cssSelector', 'input[name=password]')->sendKeys($username . $username);
+ self::find_element('cssSelector', 'input[name=login]')->click();
+ $this->assertNotContains($this->lang('LOGIN'), $this->find_element('className', 'navbar')->getText());
+
+ $cookies = self::$webDriver->manage()->getCookies();
+
+ // 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['name'], -4) == '_sid')
+ {
+ $this->sid = $cookie['value'];
+ }
+ }
+
+ $this->assertNotEmpty($this->sid);
+ }
+
+ /**
+ * Take screenshot. Can be used for debug purposes.
+ *
+ * @throws Exception When screenshot can't be created
+ */
+ public function take_screenshot()
+ {
+ // Change the Path to your own settings
+ $screenshot = time() . ".png";
+
+ self::$webDriver->takeScreenshot($screenshot);
+ }
}
diff --git a/tests/ui/permission_roles_test.php b/tests/ui/permission_roles_test.php
new file mode 100644
index 0000000000..3501124fc1
--- /dev/null
+++ b/tests/ui/permission_roles_test.php
@@ -0,0 +1,90 @@
+
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+/**
+* @group ui
+*/
+class ui_permission_roles_test extends phpbb_ui_test_case
+{
+
+ public function test_permission_roles()
+ {
+ $this->login();
+ $this->admin_login();
+ $this->add_lang('acp/permissions');
+ $this->visit('adm/index.php?i=acp_permissions&mode=setting_forum_local&sid=' . $this->sid);
+
+ // Select forums
+ $elements = self::find_element('cssSelector', 'select#forum')
+ ->findElements(\Facebook\WebDriver\WebDriverBy::tagName('option'));
+
+ foreach ($elements as $element)
+ {
+ $element->click();
+ }
+ self::find_element('cssSelector', 'form#select_victim')
+ ->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('input[type=submit]'))
+ ->click();
+
+ // Select administrators and guests
+ $groups_form = self::find_element('cssSelector', 'form#groups');
+ $elements = $groups_form
+ ->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('select'))
+ ->findElements(\Facebook\WebDriver\WebDriverBy::tagName('option'));
+
+ foreach ($elements as $element)
+ {
+ if ($element->getText() === 'Administrators' || $element->getText() === 'Guests')
+ {
+ $element->click();
+ }
+ }
+ $groups_form->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('input[name=submit_edit_options]'))->click();
+
+ $first_fieldset = self::find_element('cssSelector', '#perm11');
+ $this->assertEquals('none', $first_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('div.dropdown'))->getCSSValue('display'));
+ $first_fieldset
+ ->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('span.dropdown-toggle'))
+ ->click();
+ $this->assertEquals('block', $first_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('div.dropdown'))->getCSSValue('display'));
+ $lis = $first_fieldset
+ ->findElements(\Facebook\WebDriver\WebDriverBy::cssSelector('ul > li'));
+
+ foreach ($lis as $li)
+ {
+ if ($li->getAttribute('data-id') == 18)
+ {
+ $li->click();
+
+ break;
+ }
+ }
+ $this->assertEquals('none', $first_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('div.dropdown'))->getCSSValue('display'));
+ $this->assertEquals(18, $first_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('input[type=hidden]'))->getAttribute('value'));
+ $this->assertEquals($this->lang('ROLE_FORUM_LIMITED'), $first_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('span.dropdown-toggle'))->getText());
+
+ // Check that admin settings didn't get changed
+ $second_fieldset = self::find_element('cssSelector', '#perm10');
+ $this->assertEquals('none', $second_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('div.dropdown'))->getCSSValue('display'));
+ // Full access = 14
+ $this->assertEquals(14, $second_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('input[type=hidden]'))->getAttribute('value'));
+ $this->assertEquals($this->lang('ROLE_FORUM_FULL'), $second_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('span.dropdown-toggle'))->getText());
+
+ // Check that category settings were not modified
+ $category_fieldset = self::find_element('cssSelector', '#perm00');
+ $this->assertEquals('none', $category_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('div.dropdown'))->getCSSValue('display'));
+ // No settings
+ $this->assertEquals('', $category_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('input[type=hidden]'))->getAttribute('value'));
+ $this->assertEquals($this->lang('NO_ROLE_ASSIGNED'), $category_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('span.dropdown-toggle'))->getText());
+ }
+}