diff --git a/adm/style/consentmanager_acp.html b/adm/style/consentmanager_acp.html
index edc2f3d..a345bdd 100644
--- a/adm/style/consentmanager_acp.html
+++ b/adm/style/consentmanager_acp.html
@@ -41,21 +41,8 @@
{{ lang('WARNING') }}
{{ lang('ACP_CONSENTMANAGER_INTEGRATIONS') }}
{{ lang('ACP_CONSENTMANAGER_INTEGRATIONS') ~ lang('COLON') }} {{ lang('ACP_CONSENTMANAGER_INTEGRATIONS_EXPLAIN') }}
- {{ lang('EXAMPLE') ~ lang('COLON') }}
-
-
-[
- {
- "id": "board.analytics",
- "category": "analytics",
- "label": "Board Analytics",
- "description": "Loads a simple analytics library after consent.",
- "src": "https://cdn.example.com/analytics.js",
- "async": true
- }
-]
-
-
+ {{ lang('EXAMPLE') ~ lang('COLON') }}
+ {{ CONSENTMANAGER_INTEGRATIONS_EXAMPLE }}
diff --git a/controller/acp_controller.php b/controller/acp_controller.php
index 8db9104..d3895b8 100644
--- a/controller/acp_controller.php
+++ b/controller/acp_controller.php
@@ -123,12 +123,12 @@ public function handle()
*/
public function handle_logs()
{
- add_form_key('phpbb_consentmanager_export');
+ add_form_key('phpbb_consentmanager_logs');
$form_data = $this->get_logs_form_data();
if ($this->request->is_set_post('download_csv'))
{
- $this->validate_form_key('phpbb_consentmanager_export');
+ $this->validate_form_key('phpbb_consentmanager_logs');
$errors = [];
$filters = $this->parse_export_filters($form_data, $errors);
@@ -144,6 +144,8 @@ public function handle_logs()
}
else if ($this->request->is_set_post('delete_logs'))
{
+ $this->validate_form_key('phpbb_consentmanager_logs');
+
$errors = [];
$filters = $this->parse_export_filters($form_data, $errors);
@@ -168,7 +170,7 @@ public function handle_logs()
build_hidden_fields(array_merge([
'mode' => 'export',
'delete_logs' => 1,
- ], $form_data))
+ ], $form_data, $this->get_current_form_token_fields()))
);
}
}
@@ -277,6 +279,19 @@ protected function get_logs_form_data()
];
}
+ protected function get_current_form_token_fields()
+ {
+ if (!$this->request->is_set_post('creation_time') || !$this->request->is_set_post('form_token'))
+ {
+ return [];
+ }
+
+ return [
+ 'creation_time' => $this->request->variable('creation_time', 0),
+ 'form_token' => $this->request->variable('form_token', ''),
+ ];
+ }
+
protected function assign_template_vars(array $errors = [])
{
$this->template->assign_vars(array_merge(
diff --git a/language/en/acp_consentmanager.php b/language/en/acp_consentmanager.php
index 4314b91..dc415b9 100644
--- a/language/en/acp_consentmanager.php
+++ b/language/en/acp_consentmanager.php
@@ -28,7 +28,9 @@
'ACP_CONSENTMANAGER_MEDIA' => 'Enable embedded media category',
'ACP_CONSENTMANAGER_MEDIA_EXPLAIN' => 'Allows videos, players, widgets, and other iframe-based external media to be loaded after consent.',
'ACP_CONSENTMANAGER_INTEGRATIONS' => 'ACP-managed integrations',
- 'ACP_CONSENTMANAGER_INTEGRATIONS_EXPLAIN' => 'Use this to add simple third-party analytics, marketing, or scripts directly from the ACP instead of through an extension. These entries appear in the consent UI and are only loaded after consent. Provide a JSON array of integrations. Each object must include: id , category , src . The id may only use letters, numbers, dots, underscores, colons, and hyphens. category must be necessary , analytics , or marketing . src must be a valid http, https, or relative script URL. Optional fields: label , description , async , defer .',
+ 'ACP_CONSENTMANAGER_INTEGRATIONS_EXPLAIN' => 'Use this to add simple third-party analytics, marketing, or scripts directly from the ACP instead of through an extension. These entries appear in the consent UI and are only loaded after consent. Provide a JSON array of integrations. Each object must include: id , category , src . The id may only use letters, numbers, dots, underscores, colons, and hyphens. The category must be necessary , analytics , or marketing . The src must be a valid http, https, or relative script URL. Optional fields: label , description , async , defer .',
+ 'ACP_CONSENTMANAGER_INTEGRATIONS_EXAMPLE_LABEL' => 'Example Analytics',
+ 'ACP_CONSENTMANAGER_INTEGRATIONS_EXAMPLE_DESC' => 'Loads a simple analytics library after consent.',
'ACP_CONSENTMANAGER_VERSION' => 'Current consent version',
'ACP_CONSENTMANAGER_VERSION_EXPLAIN' => 'Increase the version to force a fresh prompt for every visitor when the consent text or integrations materially change.',
'ACP_CONSENTMANAGER_FORCE_REPROMPT' => 'Force re-prompt',
diff --git a/service/acp_manager.php b/service/acp_manager.php
index a39148d..12d67e2 100644
--- a/service/acp_manager.php
+++ b/service/acp_manager.php
@@ -99,8 +99,9 @@ public function get_settings_template_data()
'S_CONSENTMANAGER_ANALYTICS' => (bool) $this->config['consentmanager_analytics_enabled'],
'S_CONSENTMANAGER_MARKETING' => (bool) $this->config['consentmanager_marketing_enabled'],
'S_CONSENTMANAGER_MEDIA' => (bool) $this->config['consentmanager_media_enabled'],
- 'CONSENTMANAGER_INTEGRATIONS' => $this->get_integrations_json(),
'CONSENTMANAGER_VERSION' => (int) $this->config['consentmanager_consent_version'],
+ 'CONSENTMANAGER_INTEGRATIONS' => $this->get_integrations_json(),
+ 'CONSENTMANAGER_INTEGRATIONS_EXAMPLE' => $this->get_integrations_example_json(),
];
}
@@ -368,6 +369,27 @@ protected function get_integrations_json()
return $pretty_json;
}
+ /**
+ * Return example ACP integrations JSON formatted for template output.
+ *
+ * @return string
+ */
+ protected function get_integrations_example_json()
+ {
+ $example = [[
+ 'id' => 'example.analytics',
+ 'category' => consent_manager_interface::ANALYTICS_CATEGORY,
+ 'label' => $this->language->lang('ACP_CONSENTMANAGER_INTEGRATIONS_EXAMPLE_LABEL'),
+ 'description' => $this->language->lang('ACP_CONSENTMANAGER_INTEGRATIONS_EXAMPLE_DESC'),
+ 'src' => 'https://cdn.example.com/analytics.js',
+ 'async' => true,
+ ]];
+
+ $json = json_encode($example, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
+
+ return $json === false ? '' : $json;
+ }
+
/**
* Build a WHERE clause for consent log queries.
*
diff --git a/service/consent_manager.php b/service/consent_manager.php
index 4ae3edc..8f2fbbb 100644
--- a/service/consent_manager.php
+++ b/service/consent_manager.php
@@ -188,9 +188,9 @@ public function get_frontend_template_data($log_url, $log_hash)
$vars = [
'S_CONSENTMANAGER_ENABLED' => $has_optional_categories,
- 'S_CONSENTMANAGER_ANALYTICS_ENABLED' => !empty($categories['analytics']['enabled']),
- 'S_CONSENTMANAGER_MARKETING_ENABLED' => !empty($categories['marketing']['enabled']),
- 'S_CONSENTMANAGER_MEDIA_ENABLED' => !empty($categories['media']['enabled']),
+ 'S_CONSENTMANAGER_ANALYTICS_ENABLED' => !empty($categories[self::ANALYTICS_CATEGORY]['enabled']),
+ 'S_CONSENTMANAGER_MARKETING_ENABLED' => !empty($categories[self::MARKETING_CATEGORY]['enabled']),
+ 'S_CONSENTMANAGER_MEDIA_ENABLED' => !empty($categories[self::MEDIA_CATEGORY]['enabled']),
'CONSENTMANAGER_PAYLOAD' => $has_optional_categories ? json_encode($payload, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) : '',
];
@@ -332,10 +332,10 @@ public function build_frontend_payload($log_url, $log_hash)
public function get_categories()
{
$lang_keys = [
- 'necessary' => ['CONSENTMANAGER_CATEGORY_NECESSARY', 'CONSENTMANAGER_CATEGORY_NECESSARY_EXPLAIN'],
- 'analytics' => ['CONSENTMANAGER_CATEGORY_ANALYTICS', 'CONSENTMANAGER_CATEGORY_ANALYTICS_EXPLAIN'],
- 'marketing' => ['CONSENTMANAGER_CATEGORY_MARKETING', 'CONSENTMANAGER_CATEGORY_MARKETING_EXPLAIN'],
- 'media' => ['CONSENTMANAGER_CATEGORY_MEDIA', 'CONSENTMANAGER_CATEGORY_MEDIA_EXPLAIN'],
+ self::NECESSARY_CATEGORY => ['CONSENTMANAGER_CATEGORY_NECESSARY', 'CONSENTMANAGER_CATEGORY_NECESSARY_EXPLAIN'],
+ self::ANALYTICS_CATEGORY => ['CONSENTMANAGER_CATEGORY_ANALYTICS', 'CONSENTMANAGER_CATEGORY_ANALYTICS_EXPLAIN'],
+ self::MARKETING_CATEGORY => ['CONSENTMANAGER_CATEGORY_MARKETING', 'CONSENTMANAGER_CATEGORY_MARKETING_EXPLAIN'],
+ self::MEDIA_CATEGORY => ['CONSENTMANAGER_CATEGORY_MEDIA', 'CONSENTMANAGER_CATEGORY_MEDIA_EXPLAIN'],
];
$categories = [];
@@ -519,12 +519,12 @@ public function normalize_integrations($input, array &$errors = [])
*/
public function normalize_categories(array $categories)
{
- $normalized = ['necessary'];
+ $normalized = [self::NECESSARY_CATEGORY];
foreach ($categories as $category)
{
$category = trim((string) $category);
- if ($category !== 'necessary' && $this->is_category_enabled($category))
+ if ($category !== self::NECESSARY_CATEGORY && $this->is_category_enabled($category))
{
$normalized[] = $category;
}
@@ -625,7 +625,7 @@ public function has_server_consent($category)
*/
public function is_supported_category($category)
{
- return in_array($category, ['necessary', 'analytics', 'marketing', 'media'], true);
+ return in_array($category, [self::NECESSARY_CATEGORY, self::ANALYTICS_CATEGORY, self::MARKETING_CATEGORY, self::MEDIA_CATEGORY], true);
}
/**
@@ -792,23 +792,23 @@ protected function get_frontend_payload_categories(array $categories)
protected function get_category_config()
{
return $this->category_config ?? ($this->category_config = [
- 'necessary' => [
- 'id' => 'necessary',
+ self::NECESSARY_CATEGORY => [
+ 'id' => self::NECESSARY_CATEGORY,
'required' => true,
'enabled' => true,
],
- 'analytics' => [
- 'id' => 'analytics',
+ self::ANALYTICS_CATEGORY => [
+ 'id' => self::ANALYTICS_CATEGORY,
'required' => false,
'enabled' => (bool) $this->config['consentmanager_analytics_enabled'],
],
- 'marketing' => [
- 'id' => 'marketing',
+ self::MARKETING_CATEGORY => [
+ 'id' => self::MARKETING_CATEGORY,
'required' => false,
'enabled' => (bool) $this->config['consentmanager_marketing_enabled'],
],
- 'media' => [
- 'id' => 'media',
+ self::MEDIA_CATEGORY => [
+ 'id' => self::MEDIA_CATEGORY,
'required' => false,
'enabled' => (bool) $this->config['consentmanager_media_enabled'],
],
diff --git a/service/consent_manager_interface.php b/service/consent_manager_interface.php
index da96d36..770b91a 100644
--- a/service/consent_manager_interface.php
+++ b/service/consent_manager_interface.php
@@ -12,6 +12,11 @@
interface consent_manager_interface
{
+ public const NECESSARY_CATEGORY = 'necessary';
+ public const ANALYTICS_CATEGORY = 'analytics';
+ public const MARKETING_CATEGORY = 'marketing';
+ public const MEDIA_CATEGORY = 'media';
+
/**
* Register a consent-aware service definition.
*
diff --git a/service/media_manager.php b/service/media_manager.php
index 9a4b3df..7651f85 100644
--- a/service/media_manager.php
+++ b/service/media_manager.php
@@ -15,7 +15,6 @@
class media_manager
{
- public const MEDIA_CATEGORY = 'media';
public const MEDIA_ALLOWED_PARAMETER = 'S_CONSENTMANAGER_MEDIA_ALLOWED';
public const XSL_NAMESPACE = 'http://www.w3.org/1999/XSL/Transform';
@@ -44,7 +43,7 @@ public function __construct(consent_manager_interface $consent_manager)
*/
public function configure_iframe_embeds(Configurator $configurator)
{
- if (!$this->consent_manager->is_category_enabled(self::MEDIA_CATEGORY))
+ if (!$this->consent_manager->is_category_enabled(consent_manager_interface::MEDIA_CATEGORY))
{
return;
}
@@ -81,7 +80,7 @@ public function configure_iframe_renderer($renderer)
{
$renderer->get_renderer()->setParameter(
self::MEDIA_ALLOWED_PARAMETER,
- $this->consent_manager->has_server_consent(self::MEDIA_CATEGORY) ? '1' : ''
+ $this->consent_manager->has_server_consent(consent_manager_interface::MEDIA_CATEGORY) ? '1' : ''
);
}
@@ -242,7 +241,7 @@ protected function wrap_media_root(\DOMDocument $dom, \DOMElement $media_root)
{
$container = $dom->createElement('span');
$container->setAttribute('data-consent-media-container', '1');
- $container->setAttribute('data-consent-category', self::MEDIA_CATEGORY);
+ $container->setAttribute('data-consent-category', consent_manager_interface::MEDIA_CATEGORY);
$placeholder = $dom->createElement('span');
$placeholder->setAttribute('data-consent-media-placeholder', '1');
diff --git a/tests/controller/acp_controller_test.php b/tests/controller/acp_controller_test.php
index cdee330..1f7e43a 100644
--- a/tests/controller/acp_controller_test.php
+++ b/tests/controller/acp_controller_test.php
@@ -14,6 +14,9 @@
class acp_controller_test extends \phpbb_test_case
{
+ protected const ACP_URL = 'adm.php?i=test';
+ protected const EXPORT_URL = 'adm.php?i=test&mode=export';
+
/** @var bool */
public static $valid_form = true;
@@ -41,6 +44,7 @@ class acp_controller_test extends \phpbb_test_case
protected function setUp(): void
{
parent::setUp();
+ $_POST = [];
global $phpbb_root_path, $phpEx;
@@ -74,7 +78,7 @@ protected function setUp(): void
self::$confirm_hidden_fields = null;
}
- protected function create_controller($request, $u_action = 'adm.php?i=test')
+ protected function create_controller($request, $u_action = self::ACP_URL)
{
global $phpbb_root_path, $phpEx;
$controller = new \phpbb\consentmanager\controller\acp_controller(
@@ -95,16 +99,18 @@ public function test_handle_assigns_existing_template_data()
->method('get_settings_template_data')
->willReturn([
'S_CONSENTMANAGER_ANALYTICS' => true,
+ 'CONSENTMANAGER_INTEGRATIONS_EXAMPLE' => '[{}]',
'CONSENTMANAGER_VERSION' => 1,
]);
$this->template->expects(self::once())
->method('assign_vars')
->with([
'S_CONSENTMANAGER_ANALYTICS' => true,
+ 'CONSENTMANAGER_INTEGRATIONS_EXAMPLE' => '[{}]',
'CONSENTMANAGER_VERSION' => 1,
'S_ERROR' => false,
'ERROR_MSG' => '',
- 'U_ACTION' => 'adm.php?i=test',
+ 'U_ACTION' => self::ACP_URL,
]);
$this->create_controller($this->create_request_mock())->handle();
@@ -134,7 +140,7 @@ public function test_handle_submit_validation_errors_reassigns_form_data()
$args = [self::callback(static function ($vars) {
return $vars['S_ERROR']
&& $vars['ERROR_MSG'] === 'Invalid integrations'
- && $vars['U_ACTION'] === 'adm.php?i=test'
+ && $vars['U_ACTION'] === self::ACP_URL
&& isset($vars['CONSENTMANAGER_VERSION']);
})];
@@ -185,25 +191,31 @@ public function test_handle_reset_consent_logs_and_triggers_success_notice()
$this->create_controller($this->create_request_mock(['reset_consent' => 1]))->handle();
}
- public function test_handle_rejects_invalid_form_key()
+ /**
+ * @dataProvider handle_invalid_form_key_data
+ */
+ public function test_handle_invalid_form_key($action, $manager_method, $log_action = null)
{
self::$valid_form = false;
- $this->acp_manager->expects(self::never())->method('save_settings');
+ $this->acp_manager->expects(self::never())->method($manager_method);
+
+ if ($log_action !== null)
+ {
+ $this->acp_manager->expects(self::never())->method('log_admin_action')->with($log_action);
+ }
+
$this->setExpectedTriggerError(E_USER_WARNING, $this->language->lang('FORM_INVALID'));
- $this->create_controller($this->create_request_mock(['submit' => 1]))->handle();
+ $this->create_controller($this->create_request_mock([$action => 1]))->handle();
}
- public function test_handle_reset_consent_rejects_invalid_form_key()
+ public function handle_invalid_form_key_data()
{
- self::$valid_form = false;
-
- $this->acp_manager->expects(self::never())->method('reset_consent_version');
- $this->acp_manager->expects(self::never())->method('log_admin_action')->with('LOG_CONSENTMANAGER_REPROMPT');
- $this->setExpectedTriggerError(E_USER_WARNING, $this->language->lang('FORM_INVALID'));
-
- $this->create_controller($this->create_request_mock(['reset_consent' => 1]))->handle();
+ return [
+ 'submit' => ['submit', 'save_settings'],
+ 'reset consent' => ['reset_consent', 'reset_consent_version', 'LOG_CONSENTMANAGER_REPROMPT'],
+ ];
}
public function test_handle_logs_export_shows_empty_form()
@@ -218,57 +230,67 @@ public function test_handle_logs_export_shows_empty_form()
'EXPORT_USERNAME' => '',
'EXPORT_CONSENT_VER' => 0,
'U_FIND_USERNAME' => 'u_find_username',
- 'U_ACTION' => 'adm.php?i=test&mode=export',
+ 'U_ACTION' => self::EXPORT_URL,
]);
- $this->create_controller($this->create_request_mock(), 'adm.php?i=test&mode=export')->handle_logs();
+ $this->create_controller($this->create_request_mock(), self::EXPORT_URL)->handle_logs();
}
- public function test_handle_logs_export_rejects_invalid_form_key()
+ /**
+ * @dataProvider handle_logs_invalid_form_key_data
+ */
+ public function test_handle_logs_invalid_form_key_before_processing(array $request_values, $confirm_result)
{
self::$valid_form = false;
+ self::$confirm_result = $confirm_result;
+ $this->acp_manager->expects(self::never())->method('stream_logs_csv');
+ $this->acp_manager->expects(self::never())->method('delete_logs');
+ $this->acp_manager->expects(self::never())->method('log_admin_action');
+ $this->acp_manager->expects(self::never())->method('get_user_id_by_username');
+ $this->acp_manager->expects(self::never())->method('parse_date_filter');
+ $this->template->expects(self::never())->method('assign_vars');
$this->setExpectedTriggerError(E_USER_WARNING, $this->language->lang('FORM_INVALID'));
- $this->create_controller($this->create_request_mock(['download_csv' => 1]), 'adm.php?i=test&mode=export')->handle_logs();
+ $this->create_controller($this->create_request_mock($request_values), self::EXPORT_URL)->handle_logs();
}
- public function test_handle_logs_delete_requests_confirmation_without_form_key_validation()
+ public function handle_logs_invalid_form_key_data()
{
- self::$valid_form = false;
- self::$confirm_result = false;
-
- $this->acp_manager->expects(self::never())->method('delete_logs');
- $this->acp_manager->expects(self::never())->method('log_admin_action');
- $this->acp_manager->expects(self::once())->method('get_user_id_by_username')->with('Alice')->willReturn(42);
- $this->acp_manager->method('parse_date_filter')
- ->willReturnOnConsecutiveCalls(1704067200, 1735689599);
- $this->template->expects(self::once())
- ->method('assign_vars')
- ->with([
- 'S_ERROR' => false,
- 'ERROR_MSG' => '',
- 'EXPORT_DATE_FROM' => '2024-01-01',
- 'EXPORT_DATE_TO' => '2024-12-31',
- 'EXPORT_USERNAME' => 'Alice',
- 'EXPORT_CONSENT_VER' => 2,
- 'U_FIND_USERNAME' => 'u_find_username',
- 'U_ACTION' => 'adm.php?i=test&mode=export',
- ]);
-
- $request = $this->create_request_mock([
- 'delete_logs' => 1,
- 'export_date_from' => '2024-01-01',
- 'export_date_to' => '2024-12-31',
- 'export_username' => 'Alice',
- 'export_consent_version' => 2,
- ]);
- $this->create_controller($request, 'adm.php?i=test&mode=export')->handle_logs();
-
- self::assertSame($this->language->lang('ACP_CONSENTMANAGER_DELETE_CONFIRM'), self::$confirm_title);
+ return [
+ 'download csv' => [
+ ['download_csv' => 1],
+ false,
+ ],
+ 'delete logs before confirmation' => [
+ [
+ 'delete_logs' => 1,
+ 'export_date_from' => '2024-01-01',
+ 'export_date_to' => '2024-12-31',
+ 'export_username' => 'Alice',
+ 'export_consent_version' => 2,
+ ],
+ false,
+ ],
+ 'delete logs after confirmation' => [
+ [
+ 'delete_logs' => 1,
+ 'export_date_from' => '2024-01-01',
+ 'export_date_to' => '2024-12-31',
+ 'export_username' => 'Alice',
+ 'export_consent_version' => 2,
+ 'creation_time' => 1234567890,
+ 'form_token' => 'form-token-value',
+ ],
+ true,
+ ],
+ ];
}
- public function test_handle_logs_delete_requests_confirmation_with_current_filters()
+ /**
+ * @dataProvider handle_logs_delete_confirmation_data
+ */
+ public function test_handle_logs_delete_requests_confirmation_with_current_filters(array $request_overrides, array $expected_token_fields)
{
self::$valid_form = true;
self::$confirm_result = false;
@@ -288,41 +310,65 @@ public function test_handle_logs_delete_requests_confirmation_with_current_filte
'EXPORT_USERNAME' => 'Alice',
'EXPORT_CONSENT_VER' => 2,
'U_FIND_USERNAME' => 'u_find_username',
- 'U_ACTION' => 'adm.php?i=test&mode=export',
+ 'U_ACTION' => self::EXPORT_URL,
]);
- $request = $this->create_request_mock([
+ $request = $this->create_request_mock(array_merge([
'delete_logs' => 1,
'export_date_from' => '2024-01-01',
'export_date_to' => '2024-12-31',
'export_username' => 'Alice',
'export_consent_version' => 2,
- ]);
- $this->create_controller($request, 'adm.php?i=test&mode=export')->handle_logs();
+ ], $request_overrides));
+ $this->create_controller($request, self::EXPORT_URL)->handle_logs();
self::assertSame($this->language->lang('ACP_CONSENTMANAGER_DELETE_CONFIRM'), self::$confirm_title);
- self::assertSame([
+ self::assertSame(array_merge([
'mode' => 'export',
'delete_logs' => 1,
'export_date_from' => '2024-01-01',
'export_date_to' => '2024-12-31',
'export_username' => 'Alice',
'export_consent_version' => 2,
- ], self::$confirm_hidden_fields);
+ ], $expected_token_fields), self::$confirm_hidden_fields);
}
- public function test_handle_logs_delete_cancel_returns_to_form_and_next_request_confirms_again()
+ public function handle_logs_delete_confirmation_data()
{
- self::$valid_form = false;
+ return [
+ 'with current csrf tokens' => [
+ [
+ 'creation_time' => 1234567890,
+ 'form_token' => 'form-token-value',
+ ],
+ [
+ 'creation_time' => 1234567890,
+ 'form_token' => 'form-token-value',
+ ],
+ ],
+ 'without current csrf tokens' => [
+ [],
+ [],
+ ],
+ ];
+ }
+
+ public function test_handle_logs_delete_cancel_returns_to_form_without_invalid_form_error()
+ {
+ self::$valid_form = true;
self::$confirm_result = false;
+ $_POST = [
+ 'cancel' => 1,
+ 'confirm_key' => 'existing-confirm-key',
+ ];
$this->acp_manager->expects(self::never())->method('delete_logs');
$this->acp_manager->expects(self::never())->method('log_admin_action');
- $this->acp_manager->expects(self::exactly(2))->method('get_user_id_by_username')->with('Alice')->willReturn(42);
- $this->acp_manager->expects(self::exactly(4))
+ $this->acp_manager->expects(self::once())->method('get_user_id_by_username')->with('Alice')->willReturn(42);
+ $this->acp_manager->expects(self::exactly(2))
->method('parse_date_filter')
- ->willReturnOnConsecutiveCalls(1704067200, 1735689599, 1704067200, 1735689599);
- $this->template->expects(self::exactly(2))
+ ->willReturnOnConsecutiveCalls(1704067200, 1735689599);
+ $this->template->expects(self::once())
->method('assign_vars')
->with([
'S_ERROR' => false,
@@ -332,33 +378,23 @@ public function test_handle_logs_delete_cancel_returns_to_form_and_next_request_
'EXPORT_USERNAME' => 'Alice',
'EXPORT_CONSENT_VER' => 2,
'U_FIND_USERNAME' => 'u_find_username',
- 'U_ACTION' => 'adm.php?i=test&mode=export',
+ 'U_ACTION' => self::EXPORT_URL,
]);
- $cancel_request = $this->create_request_mock([
+ $reopened_request = $this->create_request_mock([
'delete_logs' => 1,
'confirm_key' => 'existing-confirm-key',
'export_date_from' => '2024-01-01',
'export_date_to' => '2024-12-31',
'export_username' => 'Alice',
'export_consent_version' => 2,
+ 'creation_time' => 1234567890,
+ 'form_token' => 'form-token-value',
]);
- $this->create_controller($cancel_request, 'adm.php?i=test&mode=export')->handle_logs();
-
- self::$confirm_title = '';
- self::$confirm_hidden_fields = null;
+ $this->create_controller($reopened_request, self::EXPORT_URL)->handle_logs();
- $fresh_request = $this->create_request_mock([
- 'delete_logs' => 1,
- 'export_date_from' => '2024-01-01',
- 'export_date_to' => '2024-12-31',
- 'export_username' => 'Alice',
- 'export_consent_version' => 2,
- ]);
-
- $this->create_controller($fresh_request, 'adm.php?i=test&mode=export')->handle_logs();
-
- self::assertSame($this->language->lang('ACP_CONSENTMANAGER_DELETE_CONFIRM'), self::$confirm_title);
+ self::assertSame('', self::$confirm_title);
+ self::assertNull(self::$confirm_hidden_fields);
}
/**
@@ -382,6 +418,7 @@ public function test_handle_logs_invalid_filters_show_error($action, array $requ
->willReturnOnConsecutiveCalls(...$parse_results);
}
+ $error_substring = $this->language->lang($error_substring);
$args = [self::callback(static function ($vars) use ($error_substring) {
return $vars['S_ERROR'] === true && strpos($vars['ERROR_MSG'], $error_substring) !== false;
})];
@@ -390,7 +427,7 @@ public function test_handle_logs_invalid_filters_show_error($action, array $requ
->with(...$args);
$request_values[$action] = 1;
- $this->create_controller($this->create_request_mock($request_values), 'adm.php?i=test&mode=export')->handle_logs();
+ $this->create_controller($this->create_request_mock($request_values), self::EXPORT_URL)->handle_logs();
}
public function handle_logs_invalid_filter_data()
@@ -404,7 +441,7 @@ public function handle_logs_invalid_filter_data()
'export_consent_version' => 0,
],
[false],
- 'Date from',
+ 'ACP_CONSENTMANAGER_EXPORT_DATE_FROM',
],
'invalid date to' => [
[
@@ -414,7 +451,7 @@ public function handle_logs_invalid_filter_data()
'export_consent_version' => 0,
],
[false],
- 'Date to',
+ 'ACP_CONSENTMANAGER_EXPORT_DATE_TO',
],
'reversed date range' => [
[
@@ -424,7 +461,7 @@ public function handle_logs_invalid_filter_data()
'export_consent_version' => 0,
],
[1735603200, 1704067200],
- 'Date from',
+ 'ACP_CONSENTMANAGER_EXPORT_DATE_FROM',
],
];
@@ -467,7 +504,7 @@ public function test_handle_logs_export_success_logs_and_passes_filters_to_downl
$phpbb_root_path,
$phpEx
);
- $controller->set_page_url('adm.php?i=test&mode=export');
+ $controller->set_page_url(self::EXPORT_URL);
$controller->handle_logs();
self::assertSame([
@@ -480,7 +517,7 @@ public function test_handle_logs_export_success_logs_and_passes_filters_to_downl
public function test_handle_logs_delete_confirmed_logs_and_triggers_success_notice()
{
- self::$valid_form = false;
+ self::$valid_form = true;
self::$confirm_result = true;
$this->acp_manager->expects(self::once())->method('get_user_id_by_username')->with('Alice')->willReturn(42);
@@ -504,8 +541,10 @@ public function test_handle_logs_delete_confirmed_logs_and_triggers_success_noti
'export_date_to' => '2024-12-31',
'export_username' => 'Alice',
'export_consent_version' => 2,
+ 'creation_time' => 1234567890,
+ 'form_token' => 'form-token-value',
]);
- $this->create_controller($request, 'adm.php?i=test&mode=export')->handle_logs();
+ $this->create_controller($request, self::EXPORT_URL)->handle_logs();
}
/**
@@ -522,7 +561,7 @@ public function test_handle_logs_unknown_username_shows_error($action)
$this->acp_manager->method('parse_date_filter')
->willReturn(false);
- $args = [self::callback(function ($vars) {
+ $args = [self::callback(static function ($vars) {
return $vars['S_ERROR'] === true
&& strpos($vars['ERROR_MSG'], 'MissingUser') !== false
&& $vars['EXPORT_USERNAME'] === 'MissingUser'
@@ -535,7 +574,7 @@ public function test_handle_logs_unknown_username_shows_error($action)
$this->create_controller($this->create_request_mock([
$action => 1,
'export_username' => 'MissingUser',
- ]), 'adm.php?i=test&mode=export')->handle_logs();
+ ]), self::EXPORT_URL)->handle_logs();
}
public function handle_logs_unknown_username_data()
@@ -621,9 +660,19 @@ function confirm_box($check, $title = '', $hidden = null)
{
if ($check)
{
+ if (isset($_POST['cancel']))
+ {
+ return false;
+ }
+
return \phpbb\consentmanager\tests\controller\acp_controller_test::$confirm_result;
}
+ if (!empty($_POST['confirm_key']))
+ {
+ return false;
+ }
+
\phpbb\consentmanager\tests\controller\acp_controller_test::$confirm_title = $title;
\phpbb\consentmanager\tests\controller\acp_controller_test::$confirm_hidden_fields = $hidden;
return false;
diff --git a/tests/functional/acp_test.php b/tests/functional/acp_test.php
index 7e2694c..2194c2d 100644
--- a/tests/functional/acp_test.php
+++ b/tests/functional/acp_test.php
@@ -15,6 +15,13 @@
*/
class acp_test extends functional_base
{
+ protected function setUp(): void
+ {
+ parent::setUp();
+
+ $this->add_lang_ext('phpbb/consentmanager', 'acp_consentmanager');
+ }
+
public function test_acp_page_renders_consent_manager_settings()
{
$this->login();
@@ -22,9 +29,9 @@ public function test_acp_page_renders_consent_manager_settings()
$crawler = self::request('GET', $this->get_module_url());
- $this->assertStringContainsString('Consent categories', $crawler->filter('#main')->text());
- $this->assertStringContainsString('ACP-managed integrations', $crawler->filter('#main')->text());
- $this->assertStringContainsString('Current consent version', $crawler->filter('#main')->text());
+ $this->assertContainsLang('ACP_CONSENTMANAGER_CATEGORIES', $crawler->filter('#main')->text());
+ $this->assertContainsLang('ACP_CONSENTMANAGER_INTEGRATIONS', $crawler->filter('#main')->text());
+ $this->assertContainsLang('ACP_CONSENTMANAGER_VERSION', $crawler->filter('#main')->text());
}
public function test_acp_form_saves_settings_and_integrations()
@@ -77,10 +84,10 @@ public function test_acp_force_reprompt_increments_version()
$before = $this->get_consent_version();
$crawler = self::request('GET', $this->get_module_url());
- $form = $crawler->selectButton('Force re-prompt')->form();
+ $form = $crawler->selectButton($this->lang('ACP_CONSENTMANAGER_FORCE_REPROMPT'))->form();
$crawler = self::submit($form);
- $this->assertStringContainsString('Consent version increased. Visitors will be asked to review their settings again.', $crawler->text());
+ $this->assertContainsLang('ACP_CONSENTMANAGER_REPROMPT_SUCCESS', $crawler->text());
$this->assertSame($before + 1, $this->get_consent_version());
}
diff --git a/tests/functional/frontend_test.php b/tests/functional/frontend_test.php
index d5fced6..28e23e7 100644
--- a/tests/functional/frontend_test.php
+++ b/tests/functional/frontend_test.php
@@ -31,7 +31,7 @@ public function test_frontend_markup_is_injected_on_board_pages()
$payload = $this->extract_payload($content);
$this->assertStringContainsString('consent-manager-root', $content);
- $this->assertStringContainsString('Privacy settings', $crawler->filter('#consent-manager-link')->text());
+ $this->assertContainsLang('CONSENTMANAGER_SETTINGS_TITLE', $crawler->filter('#consent-manager-link')->text());
$this->assertSame(1, $payload['version']);
$this->assertSame('phpbb_consent_manager', $payload['storageKey']);
$this->assertSame($this->lang('CONSENTMANAGER_MEDIA_PLACEHOLDER'), $this->extract_media_placeholder_label($content));
diff --git a/tests/service/acp_manager_test.php b/tests/service/acp_manager_test.php
index a4fc58a..e3bff43 100644
--- a/tests/service/acp_manager_test.php
+++ b/tests/service/acp_manager_test.php
@@ -30,6 +30,16 @@ protected function setUp(): void
global $db, $phpbb_root_path, $phpEx;
$lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang_loader->set_extension_manager(new \phpbb_mock_extension_manager(
+ $phpbb_root_path,
+ [
+ 'phpbb/consentmanager' => [
+ 'ext_name' => 'phpbb/consentmanager',
+ 'ext_active' => '1',
+ 'ext_path' => 'ext/phpbb/consentmanager/',
+ ],
+ ]
+ ));
$this->language = new \phpbb\language\language($lang_loader);
$this->language->add_lang('common', 'phpbb/consentmanager');
$this->language->add_lang('acp_consentmanager', 'phpbb/consentmanager');
@@ -155,6 +165,7 @@ public function test_get_settings_template_data_pretty_prints_stored_integration
$template_data = $manager->get_settings_template_data();
self::assertSame($this->get_pretty_integrations_json(), $template_data['CONSENTMANAGER_INTEGRATIONS']);
+ self::assertSame($this->get_example_integrations_json(), $template_data['CONSENTMANAGER_INTEGRATIONS_EXAMPLE']);
self::assertSame(1, $template_data['CONSENTMANAGER_VERSION']);
}
@@ -164,6 +175,7 @@ public function test_get_settings_template_data_returns_empty_integrations_when_
$template_data = $manager->get_settings_template_data();
self::assertSame('', $template_data['CONSENTMANAGER_INTEGRATIONS']);
+ self::assertSame($this->get_example_integrations_json(), $template_data['CONSENTMANAGER_INTEGRATIONS_EXAMPLE']);
}
public function test_get_settings_template_data_keeps_invalid_json_verbatim()
@@ -797,6 +809,22 @@ protected function get_pretty_integrations_json()
JSON;
}
+ protected function get_example_integrations_json()
+ {
+ return <<<'JSON'
+[
+ {
+ "id": "example.analytics",
+ "category": "analytics",
+ "label": "Example Analytics",
+ "description": "Loads a simple analytics library after consent.",
+ "src": "https://cdn.example.com/analytics.js",
+ "async": true
+ }
+]
+JSON;
+ }
+
protected function get_language_messages(array $message_specs)
{
return array_map(function ($message_spec) {