diff --git a/doc/configuration.rst b/doc/configuration.rst index 6b6ec837..bdd89f40 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -1345,6 +1345,32 @@ Advanced publishing configuration - |confluence_publish_postfix|_ - |confluence_publish_prefix|_ +.. confval:: confluence_page_search_mode + + .. versionadded:: 2.6 + + .. note:: + + This option is only supported using the ``v1`` + :ref:`editor `. + + Configures the mode which pages will be fetched from Confluence. For + Confluence Data Center instances, there may be performance issues when + attempting to query ``content/`` API (CONFSERVER-57639_). Select environments + may opt to disable this endpoint in attempt to avoid performance issues, + which in turn prevents this extension from fetching page content. To + support these environments, users can configure this extension to use an + alternative mode for fetching page content. + + .. code-block:: python + + confluence_page_search_mode = 'search' + + Supported modes are as follows: + + - ``content`` `(default)`: Pages will fetched using the ``content/`` API. + - ``search``: Pages will fetched using the ``content/search/`` API. + .. confval:: confluence_parent_override_transform .. versionadded:: 2.2 @@ -2167,6 +2193,7 @@ Deprecated options .. references ------------------------------------------------------------------ .. _API tokens: https://confluence.atlassian.com/cloud/api-tokens-938839638.html +.. _CONFSERVER-57639: https://jira.atlassian.com/browse/CONFSERVER-57639 .. _Confluence editor: https://support.atlassian.com/confluence-cloud/docs/confluence-cloud-editor-roadmap/ .. _Confluence-supported syntax highlight languages: https://confluence.atlassian.com/confcloud/code-block-macro-724765175.html .. _Key of the space: https://support.atlassian.com/confluence-cloud/docs/choose-a-space-key/ diff --git a/sphinxcontrib/confluencebuilder/__init__.py b/sphinxcontrib/confluencebuilder/__init__.py index c044658b..88b90e8d 100644 --- a/sphinxcontrib/confluencebuilder/__init__.py +++ b/sphinxcontrib/confluencebuilder/__init__.py @@ -175,6 +175,8 @@ def setup(app): cm.add_conf_bool('confluence_disable_ssl_validation') # Ignore adding a titlefix on the index document. cm.add_conf_bool('confluence_ignore_titlefix_on_index', 'confluence') + # The mode to search for page contents. + cm.add_conf('confluence_page_search_mode') # Translation to override parent page identifier to publish to. cm.add_conf('confluence_parent_override_transform') # Proxy server needed to communicate with Confluence server. diff --git a/sphinxcontrib/confluencebuilder/config/checks.py b/sphinxcontrib/confluencebuilder/config/checks.py index eed2fc2a..aa5a3a68 100644 --- a/sphinxcontrib/confluencebuilder/config/checks.py +++ b/sphinxcontrib/confluencebuilder/config/checks.py @@ -17,6 +17,7 @@ from sphinxcontrib.confluencebuilder.config.exceptions import ConfluenceLatexMacroInvalidConfigError from sphinxcontrib.confluencebuilder.config.exceptions import ConfluenceLatexMacroMissingKeysConfigError from sphinxcontrib.confluencebuilder.config.exceptions import ConfluencePageGenerationNoticeConfigError +from sphinxcontrib.confluencebuilder.config.exceptions import ConfluencePageSearchModeConfigError from sphinxcontrib.confluencebuilder.config.exceptions import ConfluenceParentPageConfigError from sphinxcontrib.confluencebuilder.config.exceptions import ConfluencePermitRawHtmlConfigError from sphinxcontrib.confluencebuilder.config.exceptions import ConfluencePrevNextButtonsLocationConfigError @@ -407,6 +408,18 @@ def validate_configuration(builder): # ################################################################## + # confluence_page_search_mode + try: + validator.conf('confluence_page_search_mode').matching( + 'default', + 'content', + 'search', + ) + except ConfluenceConfigError as ex: + raise ConfluencePageSearchModeConfigError(ex) from ex + + # ################################################################## + # confluence_root_homepage validator.conf('confluence_root_homepage') \ .bool() diff --git a/sphinxcontrib/confluencebuilder/config/exceptions.py b/sphinxcontrib/confluencebuilder/config/exceptions.py index 50be10b6..6aa3f8fd 100644 --- a/sphinxcontrib/confluencebuilder/config/exceptions.py +++ b/sphinxcontrib/confluencebuilder/config/exceptions.py @@ -166,6 +166,17 @@ def __init__(self): ''') +class ConfluencePageSearchModeConfigError(ConfluenceConfigError): + def __init__(self, msg): + super().__init__(f'''\ +{msg} + +The option 'confluence_page_search_mode' has been provided to override the +default method for querying page content. Accepted values include 'default', +'content' and 'search'. +''') + + class ConfluenceParentPageConfigError(ConfluenceConfigError): def __init__(self): super().__init__('''\ diff --git a/sphinxcontrib/confluencebuilder/publisher.py b/sphinxcontrib/confluencebuilder/publisher.py index 160a130f..1a0635e7 100644 --- a/sphinxcontrib/confluencebuilder/publisher.py +++ b/sphinxcontrib/confluencebuilder/publisher.py @@ -549,6 +549,18 @@ def get_page(self, page_name, expand='version', status='current'): 'status': status, 'title': page_name, }) + elif self.config.confluence_page_search_mode == 'search': + rsp = self.rest.get(f'{self.APIV1}content/search', { + 'cql': 'space="' + self.space_key + + '" and type=page and title="' + page_name + '"', + "cqlcontext": json.dumps({ + 'contentStatuses': [ + status, + ], + }), + 'expand': expand, + 'limit': 1, + }) else: rsp = self.rest.get(f'{self.APIV1}content', { 'type': 'page', diff --git a/tests/unit-tests/test_config_checks.py b/tests/unit-tests/test_config_checks.py index 2c9dcd43..685e726f 100644 --- a/tests/unit-tests/test_config_checks.py +++ b/tests/unit-tests/test_config_checks.py @@ -653,6 +653,23 @@ def test_config_check_parent_page_id_check(self): with self.assertRaises(ConfluenceConfigError): self._try_config() + def test_config_check_page_search_mode(self): + self.config['confluence_page_search_mode'] = '' + self._try_config() + + self.config['confluence_page_search_mode'] = 'default' + self._try_config() + + self.config['confluence_page_search_mode'] = 'content' + self._try_config() + + self.config['confluence_page_search_mode'] = 'search' + self._try_config() + + self.config['confluence_page_search_mode'] = 'invalid' + with self.assertRaises(ConfluenceConfigError): + self._try_config() + def test_config_check_permit_raw_html(self): self.config['confluence_permit_raw_html'] = True self._try_config()