From b24ea87662fc9fc3f55c7ff090bd16afad353350 Mon Sep 17 00:00:00 2001 From: Matt Gros <3311227+mpge@users.noreply.github.com> Date: Wed, 8 Apr 2026 09:02:17 -0400 Subject: [PATCH] feat: add knowledge base toggle settings Add KnowledgeBaseService with three toggle settings: knowledge_base_enabled, knowledge_base_public, and knowledge_base_feedback_enabled. Provides guard methods (can_access, permission_check) for protecting KB routes/endpoints based on settings. Includes comprehensive PHPUnit tests covering defaults, toggles, access guards, and permission callbacks for enabled/disabled/public/private combinations. --- includes/Services/KnowledgeBaseService.php | 118 +++++++++++ tests/Test_Knowledge_Base_Settings.php | 216 +++++++++++++++++++++ 2 files changed, 334 insertions(+) create mode 100644 includes/Services/KnowledgeBaseService.php create mode 100644 tests/Test_Knowledge_Base_Settings.php diff --git a/includes/Services/KnowledgeBaseService.php b/includes/Services/KnowledgeBaseService.php new file mode 100644 index 0000000..4895d32 --- /dev/null +++ b/includes/Services/KnowledgeBaseService.php @@ -0,0 +1,118 @@ + + */ + public static function get_settings(): array + { + return [ + 'knowledge_base_enabled' => self::is_enabled(), + 'knowledge_base_public' => self::is_public(), + 'knowledge_base_feedback_enabled' => self::is_feedback_enabled(), + ]; + } + + /** + * Update KB settings. + * + * @param array $settings Settings to update. + */ + public static function update_settings(array $settings): void + { + $allowed = [ + 'knowledge_base_enabled', + 'knowledge_base_public', + 'knowledge_base_feedback_enabled', + ]; + + foreach ($allowed as $key) { + if (isset($settings[$key])) { + Setting::set($key, $settings[$key] ? '1' : '0'); + } + } + } + + /** + * Guard check: should KB routes be accessible? + * + * Returns true if the KB is enabled. For public access, also checks + * knowledge_base_public or if user is authenticated. + * + * @param bool $require_auth Whether authentication is required. + */ + public static function can_access(bool $require_auth = false): bool + { + if (! self::is_enabled()) { + return false; + } + + if ($require_auth) { + return is_user_logged_in(); + } + + // If KB is not public, require authentication. + if (! self::is_public()) { + return is_user_logged_in(); + } + + return true; + } + + /** + * Permission callback for KB REST API routes. + * + * @return bool|\WP_Error + */ + public static function permission_check() + { + if (! self::is_enabled()) { + return new \WP_Error( + 'escalated_kb_disabled', + __('Knowledge base is disabled.', 'escalated'), + ['status' => 403] + ); + } + + if (! self::is_public() && ! is_user_logged_in()) { + return new \WP_Error( + 'escalated_kb_private', + __('Knowledge base requires authentication.', 'escalated'), + ['status' => 401] + ); + } + + return true; + } +} diff --git a/tests/Test_Knowledge_Base_Settings.php b/tests/Test_Knowledge_Base_Settings.php new file mode 100644 index 0000000..56a1ca8 --- /dev/null +++ b/tests/Test_Knowledge_Base_Settings.php @@ -0,0 +1,216 @@ +assertTrue(KnowledgeBaseService::is_enabled()); + } + + public function test_kb_public_by_default(): void + { + $this->assertTrue(KnowledgeBaseService::is_public()); + } + + public function test_kb_feedback_enabled_by_default(): void + { + $this->assertTrue(KnowledgeBaseService::is_feedback_enabled()); + } + + // ========================================================================= + // Toggle Tests + // ========================================================================= + + public function test_disable_knowledge_base(): void + { + Setting::set('knowledge_base_enabled', '0'); + + $this->assertFalse(KnowledgeBaseService::is_enabled()); + } + + public function test_enable_knowledge_base(): void + { + Setting::set('knowledge_base_enabled', '0'); + Setting::set('knowledge_base_enabled', '1'); + + $this->assertTrue(KnowledgeBaseService::is_enabled()); + } + + public function test_make_kb_private(): void + { + Setting::set('knowledge_base_public', '0'); + + $this->assertFalse(KnowledgeBaseService::is_public()); + } + + public function test_disable_feedback(): void + { + Setting::set('knowledge_base_feedback_enabled', '0'); + + $this->assertFalse(KnowledgeBaseService::is_feedback_enabled()); + } + + // ========================================================================= + // Get Settings Tests + // ========================================================================= + + public function test_get_settings_returns_all_keys(): void + { + $settings = KnowledgeBaseService::get_settings(); + + $this->assertArrayHasKey('knowledge_base_enabled', $settings); + $this->assertArrayHasKey('knowledge_base_public', $settings); + $this->assertArrayHasKey('knowledge_base_feedback_enabled', $settings); + } + + public function test_get_settings_reflects_changes(): void + { + Setting::set('knowledge_base_enabled', '0'); + Setting::set('knowledge_base_public', '0'); + Setting::set('knowledge_base_feedback_enabled', '0'); + + $settings = KnowledgeBaseService::get_settings(); + + $this->assertFalse($settings['knowledge_base_enabled']); + $this->assertFalse($settings['knowledge_base_public']); + $this->assertFalse($settings['knowledge_base_feedback_enabled']); + } + + // ========================================================================= + // Update Settings Tests + // ========================================================================= + + public function test_update_settings(): void + { + KnowledgeBaseService::update_settings([ + 'knowledge_base_enabled' => false, + 'knowledge_base_public' => false, + 'knowledge_base_feedback_enabled' => false, + ]); + + $this->assertFalse(KnowledgeBaseService::is_enabled()); + $this->assertFalse(KnowledgeBaseService::is_public()); + $this->assertFalse(KnowledgeBaseService::is_feedback_enabled()); + } + + public function test_update_settings_ignores_unknown_keys(): void + { + KnowledgeBaseService::update_settings([ + 'unknown_setting' => 'value', + ]); + + // Should not throw or affect anything. + $this->assertTrue(KnowledgeBaseService::is_enabled()); + } + + // ========================================================================= + // Access Guard Tests + // ========================================================================= + + public function test_can_access_when_enabled_and_public(): void + { + Setting::set('knowledge_base_enabled', '1'); + Setting::set('knowledge_base_public', '1'); + + $this->assertTrue(KnowledgeBaseService::can_access()); + } + + public function test_cannot_access_when_disabled(): void + { + Setting::set('knowledge_base_enabled', '0'); + + $this->assertFalse(KnowledgeBaseService::can_access()); + } + + public function test_cannot_access_private_kb_without_auth(): void + { + Setting::set('knowledge_base_enabled', '1'); + Setting::set('knowledge_base_public', '0'); + + // Not logged in. + wp_set_current_user(0); + + $this->assertFalse(KnowledgeBaseService::can_access()); + } + + public function test_can_access_private_kb_with_auth(): void + { + Setting::set('knowledge_base_enabled', '1'); + Setting::set('knowledge_base_public', '0'); + + $user_id = $this->factory->user->create(['role' => 'subscriber']); + wp_set_current_user($user_id); + + $this->assertTrue(KnowledgeBaseService::can_access()); + } + + // ========================================================================= + // Permission Callback Tests + // ========================================================================= + + public function test_permission_check_returns_error_when_disabled(): void + { + Setting::set('knowledge_base_enabled', '0'); + + $result = KnowledgeBaseService::permission_check(); + + $this->assertInstanceOf(\WP_Error::class, $result); + $this->assertEquals('escalated_kb_disabled', $result->get_error_code()); + } + + public function test_permission_check_returns_error_when_private_and_not_logged_in(): void + { + Setting::set('knowledge_base_enabled', '1'); + Setting::set('knowledge_base_public', '0'); + wp_set_current_user(0); + + $result = KnowledgeBaseService::permission_check(); + + $this->assertInstanceOf(\WP_Error::class, $result); + $this->assertEquals('escalated_kb_private', $result->get_error_code()); + } + + public function test_permission_check_returns_true_when_enabled_and_public(): void + { + Setting::set('knowledge_base_enabled', '1'); + Setting::set('knowledge_base_public', '1'); + + $result = KnowledgeBaseService::permission_check(); + + $this->assertTrue($result); + } + + public function test_permission_check_returns_true_when_private_and_logged_in(): void + { + Setting::set('knowledge_base_enabled', '1'); + Setting::set('knowledge_base_public', '0'); + + $user_id = $this->factory->user->create(['role' => 'subscriber']); + wp_set_current_user($user_id); + + $result = KnowledgeBaseService::permission_check(); + + $this->assertTrue($result); + } +}