diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0c74f35..be277cc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -127,6 +127,8 @@ jobs: db: "mysql:5.7" - php: '8.3' db: "mysql:5.7" + - php: '8.4' + db: "mysql:5.7" name: PHP ${{ matrix.php }} - ${{ matrix.db_alias != '' && matrix.db_alias || matrix.db }} @@ -270,6 +272,8 @@ jobs: db: "postgres:14" - php: '8.3' db: "postgres:14" + - php: '8.4' + db: "postgres:14" name: PHP ${{ matrix.php }} - ${{ matrix.db }} diff --git a/adm/style/settings_add_edit.html b/adm/style/settings_add_edit.html index 3ba82cd..18c7b68 100644 --- a/adm/style/settings_add_edit.html +++ b/adm/style/settings_add_edit.html @@ -30,13 +30,6 @@

{{ lang('WARNING') }}

-
-
-
- - -
-
@@ -50,6 +43,19 @@

{{ lang('WARNING') }}

+
+

{{ lang('BOARD_ANNOUNCEMENTS_LOCATIONS_EXPLAIN') }}
+
+ +
+
+ {% if BOARD_ANNOUNCEMENTS_PREVIEW %} diff --git a/adm/style/settings_list.html b/adm/style/settings_list.html index 8ac2861..1e1ede1 100644 --- a/adm/style/settings_list.html +++ b/adm/style/settings_list.html @@ -41,7 +41,21 @@

{{ lang('BOARD_ANNOUNCEMENTS_SETTINGS') }}

{% for ba in announcements %} {{ ba.DESCRIPTION }} - {{ ba.INDEX_ONLY ? lang('INDEX') : lang('BOARD_ANNOUNCEMENTS_EVERYWHERE') }} + + {% if ba.LOCATIONS is empty %} + {{ lang('BOARD_ANNOUNCEMENTS_EVERYWHERE') }} + {% else %} + {% set has_index = constant('\\phpbb\\boardannouncements\\ext::INDEX_ONLY') in ba.LOCATIONS %} + {% set has_forums = ba.LOCATIONS|filter(v => v > 0)|length > 0 %} + {% if has_index and has_forums %} + {{ lang('BOARD_ANNOUNCEMENTS_INDEX_PAGE') }}, {{ lang('BOARD_ANNOUNCEMENTS_FORUMS') }} + {% elseif has_index %} + {{ lang('BOARD_ANNOUNCEMENTS_INDEX_PAGE') }} + {% elseif has_forums %} + {{ lang('BOARD_ANNOUNCEMENTS_FORUMS') }} + {% endif %} + {% endif %} + {% if ba.USERS == constant('\\phpbb\\boardannouncements\\ext::ALL') %} {{ lang('BOARD_ANNOUNCEMENTS_EVERYONE') }} {% elseif ba.USERS == constant('\\phpbb\\boardannouncements\\ext::MEMBERS') %} diff --git a/config/services.yml b/config/services.yml index 176fd24..b428347 100644 --- a/config/services.yml +++ b/config/services.yml @@ -7,6 +7,7 @@ services: class: phpbb\boardannouncements\event\listener arguments: - '@phpbb.boardannouncements.manager' + - '@auth' - '@config' - '@controller.helper' - '@language' diff --git a/controller/acp_controller.php b/controller/acp_controller.php index a6ba334..3e4e329 100644 --- a/controller/acp_controller.php +++ b/controller/acp_controller.php @@ -137,12 +137,12 @@ protected function list_announcements() $this->template->assign_block_vars('announcements' , [ 'DESCRIPTION' => $row['announcement_description'], - 'INDEX_ONLY' => $row['announcement_indexonly'], 'USERS' => $row['announcement_users'], 'CREATED_DATE' => $row['announcement_timestamp'], 'EXPIRY_DATE' => $row['announcement_expiry'], 'S_EXPIRED' => $expired, 'S_ENABLED' => $enabled, + 'LOCATIONS' => $this->manager->decode_json($row['announcement_locations']), 'U_EDIT' => $this->u_action . '&action=add&id=' . $row['announcement_id'], 'U_DELETE' => $this->u_action . '&action=delete&id=' . $row['announcement_id'], 'U_MOVE_UP' => $this->u_action . '&action=move&id=' . $row['announcement_id'] . '&dir=up&hash=' . generate_link_hash('up' . $row['announcement_id']), @@ -206,7 +206,7 @@ protected function action_add() $data['announcement_bgcolor'] = $this->request->variable('board_announcements_bgcolor', '', true); $data['announcement_enabled'] = $this->request->variable('board_announcements_enabled', true); $data['announcement_users'] = $this->request->variable('board_announcements_users', ext::ALL); - $data['announcement_indexonly'] = $this->request->variable('board_announcements_index_only', false); + $data['announcement_locations'] = $this->request->variable('board_announcements_locations', [0]); $data['announcement_dismissable'] = $this->request->variable('board_announcements_dismiss', true); $data['announcement_expiry'] = $this->request->variable('board_announcements_expiry', ''); @@ -229,6 +229,9 @@ protected function action_add() $data['announcement_expiry'] = 0; } + // Locations array should be json encoded for storage in the DB + $data['announcement_locations'] = json_encode($data['announcement_locations']); + // Prepare announcement text for storage generate_text_for_storage( $data['announcement_text'], @@ -269,7 +272,6 @@ protected function action_add() $this->template->assign_vars([ 'ERRORS' => implode('
', $errors), 'BOARD_ANNOUNCEMENTS_ENABLED' => $data['announcement_enabled'], - 'BOARD_ANNOUNCEMENTS_INDEX_ONLY'=> $data['announcement_indexonly'], 'BOARD_ANNOUNCEMENTS_DISMISS' => $data['announcement_dismissable'], 'BOARD_ANNOUNCEMENTS_DESC' => $data['announcement_description'], 'BOARD_ANNOUNCEMENTS_TEXT' => $announcement_text_edit['text'], @@ -277,6 +279,8 @@ protected function action_add() 'BOARD_ANNOUNCEMENTS_EXPIRY' => $data['announcement_expiry'] ? $this->user->format_date($data['announcement_expiry'], ext::DATE_FORMAT) : '', 'BOARD_ANNOUNCEMENTS_BGCOLOR' => $data['announcement_bgcolor'], + 'BOARD_ANNOUNCEMENTS_LOCATIONS' => $this->get_location_options($data['announcement_locations']), + 'S_BOARD_ANNOUNCEMENTS_USERS' => build_select([ ext::ALL => 'BOARD_ANNOUNCEMENTS_EVERYONE', ext::MEMBERS => 'G_REGISTERED', @@ -443,4 +447,29 @@ protected function log_change($msg, $params) { $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, $msg, time(), [$params]); } + + /** + * Get an array of available locations for the announcement + * + * @param string $locations + * @return array + */ + protected function get_location_options($locations) + { + $selected = !empty($locations) ? $this->manager->decode_json($locations) : []; + + $forum_list = make_forum_select($selected, false, false, false, false, false, true); + + // Add the index page to the list + $forum_list[ext::INDEX_ONLY] = [ + 'padding' => '', + 'selected' => in_array(ext::INDEX_ONLY, $selected), + 'forum_id' => ext::INDEX_ONLY, + 'forum_name' => $this->language->lang('BOARD_ANNOUNCEMENTS_INDEX_PAGE') + ]; + + ksort($forum_list); + + return $forum_list; + } } diff --git a/event/listener.php b/event/listener.php index 9023ac0..166357f 100644 --- a/event/listener.php +++ b/event/listener.php @@ -10,6 +10,8 @@ namespace phpbb\boardannouncements\event; +use phpbb\auth\auth; +use phpbb\boardannouncements\ext; use phpbb\boardannouncements\manager\manager; use phpbb\config\config; use phpbb\controller\helper; @@ -27,6 +29,9 @@ class listener implements EventSubscriberInterface /** @var manager $manager */ protected $manager; + /** @var auth $auth */ + protected $auth; + /** @var config $config */ protected $config; @@ -48,10 +53,20 @@ class listener implements EventSubscriberInterface /** @var string $php_ext */ protected $php_ext; + /** @var array $protected_forums*/ + protected $protected_forums; + + /** @var int $location */ + protected $location; + + /** @var bool|mixed $permission */ + protected $permission; + /** * Constructor * - * @param manager $manager + * @param manager $manager Board announcements manager object + * @param auth $auth Auth object * @param config $config Config object * @param helper $controller_helper Controller helper object * @param language $language Language object @@ -61,9 +76,10 @@ class listener implements EventSubscriberInterface * @param string $php_ext PHP extension * @access public */ - public function __construct(manager $manager, config $config, helper $controller_helper, language $language, request $request, template $template, user $user, $php_ext) + public function __construct(manager $manager, auth $auth, config $config, helper $controller_helper, language $language, request $request, template $template, user $user, $php_ext) { $this->manager = $manager; + $this->auth = $auth; $this->config = $config; $this->controller_helper = $controller_helper; $this->language = $language; @@ -108,14 +124,19 @@ public function display_board_announcements() foreach ($board_announcements_data as $data) { - // Do not continue if announcements are only displayed on the board index, and the user is not currently viewing the board index - if ($data['announcement_indexonly'] && $this->user->page['page_name'] !== "index.$this->php_ext") + $locations = $this->manager->decode_json($data['announcement_locations']); + + // Do not include announcement if user is in a location where it shouldn't be visible + if (!empty($locations) && ($this->location_not_in($locations) || $this->is_protected() || $this->no_permission())) { continue; } - // Do not continue if announcement has been dismissed - if ($this->request->variable($this->config['cookie_name'] . '_ba_' . $data['announcement_id'], '', true, \phpbb\request\request_interface::COOKIE) == $data['announcement_timestamp']) + $cookie_name = $this->config['cookie_name'] . '_ba_' . $data['announcement_id']; + $announcement_dismissed = $this->request->variable($cookie_name, '', true, \phpbb\request\request_interface::COOKIE) == $data['announcement_timestamp']; + + // Do not include announcement if it has been dismissed + if ($announcement_dismissed) { continue; } @@ -133,4 +154,60 @@ public function display_board_announcements() ]); } } + + /** + * Get the current location, board index or a forum_id + * + * @return int + */ + protected function get_current_location() + { + if (!isset($this->location)) + { + $this->location = $this->user->page['page_name'] === "index.$this->php_ext" ? ext::INDEX_ONLY : $this->request->variable('f', 0); + } + + return $this->location; + } + + /** + * Is the current location not in the announcement's array of allowed locations? + * + * @param array|string $locations An array of locations + * @return bool + */ + protected function location_not_in($locations) + { + return !in_array($this->get_current_location(), $locations); + } + + /** + * Is the current page a password protected forum? + * + * @return bool + */ + protected function is_protected() + { + if (!isset($this->protected_forums)) + { + $this->protected_forums = $this->user->get_passworded_forums(); + } + + return $this->get_current_location() > 0 && !empty($this->protected_forums) && in_array($this->get_current_location(), $this->protected_forums); + } + + /** + * Is the current page a forum not accessible to the current user? + * + * @return bool + */ + protected function no_permission() + { + if (!isset($this->permission)) + { + $this->permission = $this->auth->acl_get('f_read', $this->get_current_location()); + } + + return $this->get_current_location() > 0 && !$this->permission; + } } diff --git a/ext.php b/ext.php index 7d3c768..ad76b48 100644 --- a/ext.php +++ b/ext.php @@ -15,6 +15,7 @@ */ class ext extends \phpbb\extension\base { + public const INDEX_ONLY = -1; public const ALL = 0; public const MEMBERS = 1; public const GUESTS = 2; diff --git a/language/en/boardannouncements_acp.php b/language/en/boardannouncements_acp.php index 93e4ef1..898f70c 100644 --- a/language/en/boardannouncements_acp.php +++ b/language/en/boardannouncements_acp.php @@ -43,22 +43,23 @@ 'BOARD_ANNOUNCEMENTS_ENABLE_ALL' => 'Enable board announcements', - 'BOARD_ANNOUNCEMENTS_OPTIONS' => 'Announcement options', + 'BOARD_ANNOUNCEMENTS_OPTIONS' => 'Board announcement options', 'BOARD_ANNOUNCEMENTS_DESC' => 'Description', 'BOARD_ANNOUNCEMENTS_DESC_EXPLAIN' => 'A short description for this announcement. This will only be visible here in the ACP to help identify this announcement.', - 'BOARD_ANNOUNCEMENTS_ENABLE' => 'Display this board announcement', - 'BOARD_ANNOUNCEMENTS_INDEX_ONLY' => 'Display on board index only', - 'BOARD_ANNOUNCEMENTS_USERS' => 'Who can view this board announcement', - 'BOARD_ANNOUNCEMENTS_DISMISS' => 'Allow users to dismiss this board announcement', + 'BOARD_ANNOUNCEMENTS_ENABLE' => 'Display this announcement', + 'BOARD_ANNOUNCEMENTS_USERS' => 'Who can view this announcement', + 'BOARD_ANNOUNCEMENTS_DISMISS' => 'Allow users to dismiss this announcement', + 'BOARD_ANNOUNCEMENTS_LOCATIONS' => 'Limit where this announcement should be displayed', + 'BOARD_ANNOUNCEMENTS_LOCATIONS_EXPLAIN' => 'Select one or more locations to display the announcement. To display it everywhere, leave the selection empty. Use Command (Mac) or Control (Windows) click to select multiple locations.', 'BOARD_ANNOUNCEMENTS_EVERYONE' => 'Everyone', - 'BOARD_ANNOUNCEMENTS_BGCOLOR' => 'Board announcement background color', + 'BOARD_ANNOUNCEMENTS_BGCOLOR' => 'Background color', 'BOARD_ANNOUNCEMENTS_BGCOLOR_EXPLAIN' => 'You can change the background color of the announcement using a hex code (e.g: FFFF80). Leave this field blank to use the default color.', - 'BOARD_ANNOUNCEMENTS_EXPIRY' => 'Board announcement expiration date', + 'BOARD_ANNOUNCEMENTS_EXPIRY' => 'Expiration date', 'BOARD_ANNOUNCEMENTS_EXPIRY_EXPLAIN' => 'Set the date the announcement will expire and become disabled. Leave this field blank if you do not want the announcement to expire.', 'BOARD_ANNOUNCEMENTS_EXPIRY_INVALID' => 'The expiration date was invalid or has already expired.', @@ -77,6 +78,8 @@ 'BOARD_ANNOUNCEMENTS_TH_EXPIRED' => 'Expired', 'BOARD_ANNOUNCEMENTS_EVERYWHERE' => 'Everywhere', + 'BOARD_ANNOUNCEMENTS_INDEX_PAGE' => 'Board Index', + 'BOARD_ANNOUNCEMENTS_FORUMS' => 'Selected Forums', 'BOARD_ANNOUNCEMENTS_EMPTY' => 'There are no board announcements to display', 'BOARD_ANNOUNCEMENTS_ADD' => 'Create Announcement', diff --git a/manager/manager.php b/manager/manager.php index 267d8d4..d34f2c3 100644 --- a/manager/manager.php +++ b/manager/manager.php @@ -189,6 +189,18 @@ public function close_announcement($id, $user_id) return (bool) $this->nestedset->insert_tracked_item($id, ['user_id' => (int) $user_id]); } + /** + * Decode JSON data + * + * @param string $data + * @return mixed decoded json data or original data if not valid json + */ + public function decode_json($data) + { + $result = json_decode($data, true); + return json_last_error() === JSON_ERROR_NONE ? $result : $data; + } + /** * Filter members only announcements * @@ -245,7 +257,7 @@ public function announcement_columns() 'announcement_description' => '', 'announcement_bgcolor' => '', 'announcement_enabled' => true, - 'announcement_indexonly' => false, + 'announcement_locations' => '', 'announcement_dismissable' => true, 'announcement_users' => \phpbb\boardannouncements\ext::ALL, 'announcement_timestamp' => 0, diff --git a/migrations/v10x/m12_locations.php b/migrations/v10x/m12_locations.php new file mode 100644 index 0000000..7c0c978 --- /dev/null +++ b/migrations/v10x/m12_locations.php @@ -0,0 +1,65 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + */ + +namespace phpbb\boardannouncements\migrations\v10x; + +/** + * Migration stage 12: Add option for locations where announcement can be displayed + */ +class m12_locations extends \phpbb\db\migration\migration +{ + /** + * {@inheritdoc} + */ + public static function depends_on() + { + return [ + '\phpbb\boardannouncements\migrations\v10x\m9_schema_update', + '\phpbb\boardannouncements\migrations\v10x\m10_update_data', + '\phpbb\boardannouncements\migrations\v10x\m11_schema_removal', + ]; + } + + /** + * {@inheritdoc} + */ + public function effectively_installed() + { + return $this->db_tools->sql_column_exists($this->table_prefix . 'board_announcements', 'announcement_locations'); + } + + /** + * {@inheritdoc} + */ + public function update_schema() + { + return [ + 'add_columns' => [ + $this->table_prefix . 'board_announcements' => [ + 'announcement_locations' => ['TEXT', ''], + ], + ], + ]; + } + + /** + * {@inheritdoc} + */ + public function revert_schema() + { + return [ + 'drop_columns' => [ + $this->table_prefix . 'board_announcements' => [ + 'announcement_locations', + ], + ], + ]; + } +} diff --git a/migrations/v10x/m13_locations_data.php b/migrations/v10x/m13_locations_data.php new file mode 100644 index 0000000..5413322 --- /dev/null +++ b/migrations/v10x/m13_locations_data.php @@ -0,0 +1,103 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + */ + +namespace phpbb\boardannouncements\migrations\v10x; + +use phpbb\boardannouncements\ext; +use phpbb\boardannouncements\manager\nestedset; + +/** + * Migration stage 13: Migrate existing index only data to location data + */ +class m13_locations_data extends \phpbb\db\migration\container_aware_migration +{ + /** + * {@inheritdoc} + */ + public static function depends_on() + { + return [ + '\phpbb\boardannouncements\migrations\v10x\m12_locations', + ]; + } + + /** + * {@inheritdoc} + */ + public function effectively_installed() + { + $sql = 'SELECT announcement_id + FROM ' . $this->table_prefix . "board_announcements + WHERE announcement_locations != ''"; + $result = $this->db->sql_query_limit($sql, 1); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + return $row !== false; + } + + /** + * {@inheritdoc} + */ + public function update_data() + { + return [ + ['custom', [[$this, 'copy_locations']]], + ]; + } + + /** + * Copy values of announcement_indexonly to announcement_locations + * for existing announcements. New values should be -1 for index only, + * empty string for everywhere (all other integers will be for forums). + * + * @return void + */ + public function copy_locations() + { + $sql = 'SELECT announcement_id, announcement_indexonly + FROM ' . $this->table_prefix . 'board_announcements'; + $result = $this->db->sql_query($sql); + $rows = $this->db->sql_fetchrowset($result); + $this->db->sql_freeresult($result); + + if (!empty($rows)) + { + $this->db->sql_transaction('begin'); + + foreach ($rows as $row) + { + $this->get_nestedset()->update_item($row['announcement_id'], [ + 'announcement_locations' => $row['announcement_indexonly'] ? json_encode([ext::INDEX_ONLY]) : '' + ]); + } + + $this->db->sql_transaction('commit'); + } + } + + /** + * Get the board announcements nested set object + * + * @return nestedset + */ + protected function get_nestedset() + { + /** @var \phpbb\db\driver\driver_interface $db */ + $db = $this->container->get('dbal.conn'); + + return new nestedset( + $db, + new \phpbb\lock\db('boardannouncements.table_lock.board_announcements_table', $this->config, $db), + $this->table_prefix . 'board_announcements', + $this->table_prefix . 'board_announcements_track' + ); + } +} diff --git a/migrations/v10x/m14_schema_removal.php b/migrations/v10x/m14_schema_removal.php new file mode 100644 index 0000000..2ea1bf3 --- /dev/null +++ b/migrations/v10x/m14_schema_removal.php @@ -0,0 +1,64 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + */ + +namespace phpbb\boardannouncements\migrations\v10x; + +/** + * Migration stage 14: Remove old board announcement schema from tables + */ +class m14_schema_removal extends \phpbb\db\migration\migration +{ + /** + * {@inheritdoc} + */ + public static function depends_on() + { + return [ + '\phpbb\boardannouncements\migrations\v10x\m12_locations', + '\phpbb\boardannouncements\migrations\v10x\m13_locations_data', + ]; + } + + /** + * {@inheritdoc} + */ + public function effectively_installed() + { + return !$this->db_tools->sql_column_exists($this->table_prefix . 'board_announcements', 'announcement_indexonly'); + } + + /** + * {@inheritdoc} + */ + public function update_schema() + { + return [ + 'drop_columns' => [ + $this->table_prefix . 'board_announcements' => [ + 'announcement_indexonly', + ], + ], + ]; + } + + /** + * {@inheritdoc} + */ + public function revert_schema() + { + return [ + 'add_columns' => [ + $this->table_prefix . 'board_announcements' => [ + 'announcement_indexonly' => ['VCHAR:255', ''], + ], + ], + ]; + } +} diff --git a/tests/controller/acp_controller_test.php b/tests/controller/acp_controller_test.php index 4acf60d..1ce3ea1 100644 --- a/tests/controller/acp_controller_test.php +++ b/tests/controller/acp_controller_test.php @@ -198,7 +198,7 @@ public function test_list_announcements() 'announcement_enabled' => 1, 'announcement_timestamp' => 734284394, 'announcement_expiry' => 0, - 'announcement_indexonly' => 0, + 'announcement_locations' => '', 'announcement_users' => 0, ], [ @@ -207,7 +207,7 @@ public function test_list_announcements() 'announcement_enabled' => 1, 'announcement_timestamp' => 797442794, 'announcement_expiry' => 0, - 'announcement_indexonly' => 0, + 'announcement_locations' => '[-1,1]', 'announcement_users' => 0, ], [ @@ -216,7 +216,7 @@ public function test_list_announcements() 'announcement_enabled' => 1, 'announcement_timestamp' => 681493994, 'announcement_expiry' => 1644162794, - 'announcement_indexonly' => 0, + 'announcement_locations' => '[]', 'announcement_users' => 0, ], ]; @@ -262,7 +262,7 @@ public function action_add_data() 'announcement_description' => 'Announcement 1', 'announcement_bgcolor' => '', 'announcement_enabled' => true, - 'announcement_indexonly' => false, + 'announcement_locations' => '', 'announcement_dismissable' => true, 'announcement_users' => \phpbb\boardannouncements\ext::ALL, 'announcement_timestamp' => '', @@ -277,7 +277,7 @@ public function action_add_data() 'announcement_description' => 'Announcement 2', 'announcement_bgcolor' => '', 'announcement_enabled' => true, - 'announcement_indexonly' => false, + 'announcement_locations' => '', 'announcement_dismissable' => true, 'announcement_users' => \phpbb\boardannouncements\ext::ALL, 'announcement_timestamp' => '', @@ -321,7 +321,7 @@ public function test_action_add($id, $data) 'announcement_description' => '', 'announcement_bgcolor' => '', 'announcement_enabled' => true, - 'announcement_indexonly' => false, + 'announcement_locations' => '', 'announcement_dismissable' => true, 'announcement_users' => \phpbb\boardannouncements\ext::ALL, 'announcement_timestamp' => 0, @@ -350,15 +350,15 @@ public function test_action_add($id, $data) public function action_add_submit_data() { return [ - [0, ['add', 0, 'Announcement Text 0', 'Announcement Description 0', 'ffffff', true, 0, false, true, '', false, false, false], false, true, true, false], // submit - [1, ['add', 1, 'Announcement Text 1', 'Announcement Description 1', 'ffffff', true, 0, false, true, '', false, false, false], false, true, true, false], // submit - [0, ['add', 0, 'Announcement Text 0', 'Announcement Description 0', 'ffffff', true, 0, false, true, '', false, false, false], false, true, false, true], // submit, bad form - [0, ['add', 0, '', 'Announcement Description 0', 'ffffff', true, 0, false, true, '', false, false, false], false, true, true, true], // submit, bad text - [0, ['add', 0, 'Announcement Text 0', 'Announcement Description 0', 'ffffff', true, 0, false, true, 'foo', false, false, false], false, true, true, true], // submit, bad expiry - [0, ['add', 0, 'Announcement Text 0', 'Announcement Description 0', 'ffffff', true, 0, false, true, '', false, false, false], true, false, true, null], // preview - [0, ['add', 0, 'Announcement Text 0', 'Announcement Description 0', 'ffffff', true, 0, false, true, '', false, false, false], true, false, false, null], // preview, bad form - [1, ['add', 1, 'Announcement Text 1', 'Announcement Description 1', 'ffffff', true, 0, false, true, '', false, false, false], true, false, true, null], // preview - [1, ['add', 1, 'Announcement Text 1', 'Announcement Description 1', 'ffffff', true, 0, false, true, '', false, false, false], true, false, false, null], // preview, bad form + [0, ['add', 0, 'Announcement Text 0', 'Announcement Description 0', 'ffffff', true, 0, [''], true, '', false, false, false], false, true, true, false], // submit + [1, ['add', 1, 'Announcement Text 1', 'Announcement Description 1', 'ffffff', true, 0, [''], true, '', false, false, false], false, true, true, false], // submit + [0, ['add', 0, 'Announcement Text 0', 'Announcement Description 0', 'ffffff', true, 0, [''], true, '', false, false, false], false, true, false, true], // submit, bad form + [0, ['add', 0, '', 'Announcement Description 0', 'ffffff', true, 0, [''], true, '', false, false, false], false, true, true, true], // submit, bad text + [0, ['add', 0, 'Announcement Text 0', 'Announcement Description 0', 'ffffff', true, 0, [''], true, 'foo', false, false, false], false, true, true, true], // submit, bad expiry + [0, ['add', 0, 'Announcement Text 0', 'Announcement Description 0', 'ffffff', true, 0, [''], true, '', false, false, false], true, false, true, null], // preview + [0, ['add', 0, 'Announcement Text 0', 'Announcement Description 0', 'ffffff', true, 0, [''], true, '', false, false, false], true, false, false, null], // preview, bad form + [1, ['add', 1, 'Announcement Text 1', 'Announcement Description 1', 'ffffff', true, 0, [''], true, '', false, false, false], true, false, true, null], // preview + [1, ['add', 1, 'Announcement Text 1', 'Announcement Description 1', 'ffffff', true, 0, [''], true, '', false, false, false], true, false, false, null], // preview, bad form ]; } @@ -397,7 +397,7 @@ public function test_action_add_submit($id, $form, $preview, $submit, $valid_for ['board_announcements_bgcolor', ''], ['board_announcements_enabled', true], ['board_announcements_users', 0], - ['board_announcements_index_only', false], + ['board_announcements_locations', [0]], ['board_announcements_dismiss', true], ['board_announcements_expiry', ''], ['disable_bbcode', false], @@ -412,6 +412,10 @@ public function test_action_add_submit($id, $form, $preview, $submit, $valid_for ->withConsecutive(['submit'], ['preview']) ->willReturnOnConsecutiveCalls($submit, $preview); + $this->manager->expects($submit && !$errors ? self::never() : self::once()) + ->method('decode_json') + ->willReturn([]); + $this->manager->expects(self::once()) ->method('announcement_columns') ->willReturn([]); @@ -673,3 +677,11 @@ function display_custom_bbcodes() function build_select() { } + +/** + * Mock make_forum_select() + * Note: use the same namespace as the acp_controller + */ +function make_forum_select() +{ +} diff --git a/tests/event/listener_test.php b/tests/event/listener_test.php index dac9212..b666267 100644 --- a/tests/event/listener_test.php +++ b/tests/event/listener_test.php @@ -26,6 +26,9 @@ protected static function setup_extensions() /** @var \phpbb\boardannouncements\event\listener */ protected $listener; + /** @var \phpbb_mock_notifications_auth */ + protected $auth; + /** @var \phpbb\config\config */ protected $config; @@ -128,6 +131,7 @@ protected function set_listener() { $this->listener = new \phpbb\boardannouncements\event\listener( $this->manager, + $this->auth, $this->config, $this->controller_helper, $this->language, @@ -250,6 +254,13 @@ public function test_display_board_announcements($user_id, $page, $enabled, $exp ->method('assign_block_vars') ->withConsecutive(...$expected); + $this->request->expects(self::atMost(10)) + ->method('variable') + ->willReturnMap([ + ['f', 0, false, \phpbb\request\request_interface::REQUEST, 0], + ['_ba_1', '', false, \phpbb\request\request_interface::COOKIE, ''], + ]); + $dispatcher = new \phpbb\event\dispatcher(); $dispatcher->addListener('core.page_header_after', [$this->listener, 'display_board_announcements']); $dispatcher->trigger_event('core.page_header_after'); diff --git a/tests/fixtures/board_announcements.xml b/tests/fixtures/board_announcements.xml index d6488b2..c9fe2c2 100644 --- a/tests/fixtures/board_announcements.xml +++ b/tests/fixtures/board_announcements.xml @@ -6,7 +6,7 @@ announcement_description announcement_bgcolor announcement_enabled - announcement_indexonly + announcement_locations announcement_dismissable announcement_users announcement_timestamp @@ -24,7 +24,7 @@ ANNOUNCEMENT 1 1 - 1 + [-1] 1 0 1586466410 @@ -43,7 +43,7 @@ ANNOUNCEMENT 2 ffffff 1 - 0 + 1 1 1586466510 @@ -62,7 +62,7 @@ ANNOUNCEMENT 3 000000 1 - 0 + 1 2 1586466610 @@ -81,7 +81,7 @@ ANNOUNCEMENT 4 1 - 0 + 0 0 1586466710 @@ -100,7 +100,7 @@ ANNOUNCEMENT 5 0 - 0 + [] 0 0 1586466810 diff --git a/tests/functional/announcement_test.php b/tests/functional/announcement_test.php index 5b743cb..6aa00fc 100644 --- a/tests/functional/announcement_test.php +++ b/tests/functional/announcement_test.php @@ -10,6 +10,8 @@ namespace phpbb\boardannouncements\tests\functional; +use phpbb\boardannouncements\ext; + /** * @group functional */ @@ -54,30 +56,25 @@ public function test_set_acp_settings() // Test that our settings fields are found $this->assertContainsLang('BOARD_ANNOUNCEMENTS_ENABLE', $crawler->text()); - $this->assertContainsLang('BOARD_ANNOUNCEMENTS_INDEX_ONLY', $crawler->text()); $this->assertContainsLang('BOARD_ANNOUNCEMENTS_DISMISS', $crawler->text()); $this->assertContainsLang('BOARD_ANNOUNCEMENTS_USERS', $crawler->text()); + $this->assertContainsLang('BOARD_ANNOUNCEMENTS_LOCATIONS', $crawler->text()); $this->assertContainsLang('BOARD_ANNOUNCEMENTS_DESC', $crawler->text()); $this->assertContainsLang('BOARD_ANNOUNCEMENTS_EXPIRY', $crawler->text()); $this->assertContainsLang('BOARD_ANNOUNCEMENTS_BGCOLOR', $crawler->text()); $this->assertContainsLang('BOARD_ANNOUNCEMENTS_TEXT', $crawler->text()); - // Set some form values - $form = $crawler->selectButton($this->lang('SUBMIT'))->form(); $values = [ 'board_announcements_enabled' => true, - 'board_announcements_index_only' => true, 'board_announcements_users' => 0, 'board_announcements_dismiss' => true, + 'board_announcements_locations' => [ext::INDEX_ONLY], 'board_announcements_bgcolor' => 'ff0000', 'board_announcements_description' => 'Test announcement', 'board_announcements_text' => 'This is a board announcement test.', ]; - $form->setValues($values); - // Submit form and test success - $crawler = self::submit($form); - $this->assertContainsLang('BOARD_ANNOUNCEMENTS_UPDATED', $crawler->text()); + $this->create_announcement($values); // Confirm the log entry has been added correctly $crawler = self::request('GET', 'adm/index.php?i=acp_logs&mode=admin&sid=' . $this->sid); @@ -184,6 +181,79 @@ public function test_acp_editing() $this->assertContainsLang('BOARD_ANNOUNCEMENTS_EMPTY', $crawler->text()); } + /** + * Test announcements only show at locations where they are assigned + */ + public function test_locations() + { + $this->login(); + $this->admin_login(); + + // show everywhere + $everywhere_id = $this->create_announcement([ + 'board_announcements_locations' => [], + 'board_announcements_description' => 'Everywhere announcement', + 'board_announcements_text' => 'Everywhere announcement', + ]); + + // show index only + $index_id = $this->create_announcement([ + 'board_announcements_locations' => [ext::INDEX_ONLY], + 'board_announcements_description' => 'Board index announcement', + 'board_announcements_text' => 'Board index announcement', + ]); + + // show in forum 2 only + $forum_id = $this->create_announcement([ + 'board_announcements_locations' => [2], + 'board_announcements_description' => 'Forum announcement', + 'board_announcements_text' => 'Forum announcement', + ]); + + // show in forum 2 and index + $index_forum_id = $this->create_announcement([ + 'board_announcements_locations' => [ext::INDEX_ONLY, 2], + 'board_announcements_description' => 'Forum and Index announcement', + 'board_announcements_text' => 'Forum and Index announcement', + ]); + + // Test board index - see everywhere, index and index+forum + $crawler = self::request('GET', 'index.php?sid=' . $this->sid); + self::assertCount(1, $crawler->filter('#phpbb_announcement_' . $everywhere_id)); + self::assertCount(1, $crawler->filter('#phpbb_announcement_' . $index_id)); + self::assertCount(0, $crawler->filter('#phpbb_announcement_' . $forum_id)); + self::assertCount(1, $crawler->filter('#phpbb_announcement_' . $index_forum_id)); + self::assertStringContainsString('Everywhere announcement', $crawler->filter('#phpbb_announcement_' . $everywhere_id)->text()); + self::assertStringContainsString('Board index announcement', $crawler->filter('#phpbb_announcement_' . $index_id)->text()); + self::assertStringContainsString('Forum and Index announcement', $crawler->filter('#phpbb_announcement_' . $index_forum_id)->text()); + + // Test forum 2 page - see everywhere, forum and index+forum + $crawler = self::request('GET', 'viewforum.php?f=2&sid=' . $this->sid); + self::assertCount(1, $crawler->filter('#phpbb_announcement_' . $everywhere_id)); + self::assertCount(0, $crawler->filter('#phpbb_announcement_' . $index_id)); + self::assertCount(1, $crawler->filter('#phpbb_announcement_' . $forum_id)); + self::assertCount(1, $crawler->filter('#phpbb_announcement_' . $index_forum_id)); + self::assertStringContainsString('Everywhere announcement', $crawler->filter('#phpbb_announcement_' . $everywhere_id)->text()); + self::assertStringContainsString('Forum announcement', $crawler->filter('#phpbb_announcement_' . $forum_id)->text()); + self::assertStringContainsString('Forum and Index announcement', $crawler->filter('#phpbb_announcement_' . $index_forum_id)->text()); + + // Test forum 1 page - see everywhere + $crawler = self::request('GET', 'viewforum.php?f=1&sid=' . $this->sid); + self::assertCount(1, $crawler->filter('#phpbb_announcement_' . $everywhere_id)); + self::assertCount(0, $crawler->filter('#phpbb_announcement_' . $index_id)); + self::assertCount(0, $crawler->filter('#phpbb_announcement_' . $forum_id)); + self::assertCount(0, $crawler->filter('#phpbb_announcement_' . $index_forum_id)); + self::assertStringContainsString('Everywhere announcement', $crawler->filter('#phpbb_announcement_' . $everywhere_id)->text()); + + // Test FAQ page - see everywhere + $crawler = self::request('GET', 'viewonline.php?sid=' . $this->sid); + self::assertCount(1, $crawler->filter('#phpbb_announcement_' . $everywhere_id)); + self::assertCount(0, $crawler->filter('#phpbb_announcement_' . $index_id)); + self::assertCount(0, $crawler->filter('#phpbb_announcement_' . $forum_id)); + self::assertCount(0, $crawler->filter('#phpbb_announcement_' . $index_forum_id)); + self::assertStringContainsString('Everywhere announcement', $crawler->filter('#phpbb_announcement_' . $everywhere_id)->text()); + } + /** * Get the board announcements ACP page link to crawl * @@ -196,6 +266,40 @@ protected function get_acp_page($action = '', $id = 0) return 'adm/index.php?i=\phpbb\boardannouncements\acp\board_announcements_module&mode=settings' . ($action ? "&action=$action" : '') . ($id ? "&id=$id" : '') . "&sid=$this->sid"; } + /** + * Create an announcement + * + * @param array $data + * @return int count of announcements created + */ + protected function create_announcement($data) + { + static $counter = 0; + + // Load Add page + $crawler = self::request('GET', $this->get_acp_page('add')); + + // Set some form values + $form = $crawler->selectButton($this->lang('SUBMIT'))->form(); + $values = array_merge([ + 'board_announcements_enabled' => true, + 'board_announcements_dismiss' => false, + 'board_announcements_users' => 0, + 'board_announcements_locations' => [], + 'board_announcements_bgcolor' => 'ff0000', + 'board_announcements_expiry' => '', + 'board_announcements_description' => 'Test announcement', + 'board_announcements_text' => 'This is a board announcement test.', + ], $data); + $form->setValues($values); + + // Submit form and test success + $crawler = self::submit($form); + $this->assertContainsLang('BOARD_ANNOUNCEMENTS_UPDATED', $crawler->text()); + + return ++$counter; + } + /** * Create a link hash for the user 'admin' * diff --git a/tests/manager/manager_get_expired_announcements_test.php b/tests/manager/manager_get_expired_announcements_test.php index d50f03d..bbf8603 100644 --- a/tests/manager/manager_get_expired_announcements_test.php +++ b/tests/manager/manager_get_expired_announcements_test.php @@ -29,7 +29,7 @@ public function data_get_expired_announcements() 'announcement_description' => 'ANNOUNCEMENT 4', 'announcement_bgcolor' => '', 'announcement_enabled' => 1, - 'announcement_indexonly' => 0, + 'announcement_locations' => '', 'announcement_dismissable' => 0, 'announcement_users' => \phpbb\boardannouncements\ext::ALL, 'announcement_timestamp' => 1586466710, diff --git a/tests/manager/manager_save_announcement_test.php b/tests/manager/manager_save_announcement_test.php index 0e49a75..d09e5b7 100644 --- a/tests/manager/manager_save_announcement_test.php +++ b/tests/manager/manager_save_announcement_test.php @@ -25,7 +25,7 @@ public function data_save_announcement() 'announcement_description' => 'ANNOUNCEMENT 6', 'announcement_bgcolor' => '', 'announcement_enabled' => 1, - 'announcement_indexonly' => 1, + 'announcement_locations' => json_encode([1,2,3]), 'announcement_dismissable' => 1, 'announcement_users' => 0, 'announcement_timestamp' => time(), diff --git a/tests/manager/manager_update_announcement_test.php b/tests/manager/manager_update_announcement_test.php index 5f86de9..bb2ddb5 100644 --- a/tests/manager/manager_update_announcement_test.php +++ b/tests/manager/manager_update_announcement_test.php @@ -25,7 +25,7 @@ public function data_update_announcement() 'announcement_description' => 'ANNOUNCEMENT 1 Updated', 'announcement_bgcolor' => 'cccccc', 'announcement_enabled' => 0, - 'announcement_indexonly' => 0, + 'announcement_locations' => json_encode(''), 'announcement_dismissable' => 0, 'announcement_users' => 1, 'announcement_timestamp' => time(),