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