diff --git a/core/tests/test_views.py b/core/tests/test_views.py index 6b66678c..3815f2af 100644 --- a/core/tests/test_views.py +++ b/core/tests/test_views.py @@ -398,9 +398,7 @@ def test_static_content_blocks_direct_doc_paths(request_factory): @pytest.mark.django_db -@override_settings( - CACHES=TEST_CACHES, -) +@override_settings(CACHES=TEST_CACHES) def test_static_content_allows_non_direct_doc_paths(request_factory): """Test that non-direct doc paths are allowed and processed normally.""" diff --git a/env.template b/env.template index c2c0dbc6..1340d656 100644 --- a/env.template +++ b/env.template @@ -33,7 +33,7 @@ PROD_MEDIA_CONTENT_REGION=$STATIC_CONTENT_REGION PROD_MEDIA_CONTENT_AWS_S3_ENDPOINT_URL=$STATIC_CONTENT_AWS_S3_ENDPOINT_URL # Mailman database settings -HYPERKITTY_DATABASE_NAME="hyperkitty_db" +HYPERKITTY_DATABASE_NAME="lists_production_web" DATABASE_URL="postgresql://postgres@db:5432/postgres" DATABASE_TYPE="postgres" DATABASE_CLASS="mailman.database.postgresql.PostgreSQLDatabase" diff --git a/libraries/models.py b/libraries/models.py index 9c6a6884..b88f27d2 100644 --- a/libraries/models.py +++ b/libraries/models.py @@ -34,6 +34,10 @@ from .utils import ( ) +class PathType(models.TextChoices): + LIB_IN_PATH = "LIP" + + class Category(models.Model): """ Library categories such as: diff --git a/libraries/path_matcher/__init__.py b/libraries/path_matcher/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/libraries/path_matcher/base_path_matcher.py b/libraries/path_matcher/base_path_matcher.py new file mode 100644 index 00000000..e520d91f --- /dev/null +++ b/libraries/path_matcher/base_path_matcher.py @@ -0,0 +1,115 @@ +import os.path +import re +from abc import ABCMeta, abstractmethod +from core.constants import BOOST_VERSION_REGEX +from core.models import RenderedContent +from libraries.models import PathType, LibraryVersion +from versions.models import Version +import structlog + +logger = structlog.get_logger(__name__) + + +class BasePathMatcher(metaclass=ABCMeta): + @property + @abstractmethod + def path_type(self) -> PathType: + raise NotImplementedError + + @property + @abstractmethod + def determination_re(self): + raise NotImplementedError + + def __init__(self, latest_library: LibraryVersion): + breakpoint() + self.latest_library_version = latest_library + self.next: BasePathMatcher | None = None + + def set_next(self, next_matcher: "BasePathMatcher"): + self.next = next_matcher + + # @abstractmethod + # def determine_match(self, path: str) -> bool: + # """ + # This method matches the path and handles or passes off to next if not a handler + # """ + # raise NotImplementedError + + @abstractmethod + def generate_latest_s3_path( + self, path: str, library_name: str, content_path: str + ) -> str: + """ + Generates a string to match the s3/cache_key path + returns something similar to: + static_content_1_84_0/libs/algorithm/doc/html/index.html + static_content_1_84_0/doc/html/accumulators.html + + + """ + # static_content_subst_re = re.compile( + # rf"static_content_\2/libs/\g/\g" + # ) + raise NotImplementedError + + def determine_match(self, path: str) -> PathType | None: + if (details := self.get_group_items(path)) is not None: + if self.confirm_path_exists(path, *details): + return self.path_type + if self.next: + self.next.determine_match(path) + else: + raise ValueError(f"No redirect path match for {path=}") + + def get_group_items(self, path: str) -> tuple[str, str] | None: + """ + returns tuple (library_name, content_path) + """ + if src_match := self.determination_re.match(path): + group_values = src_match.groupdict() + library_name = group_values.get("library_name") + content_path = group_values.get("content_path") + # todo: do we need this all check? do we sometimes get a match where these + # aren't set + if all([library_name, content_path]): + return library_name, content_path + return None + + def confirm_path_exists( + self, path: str, library_name: str, content_path: str + ) -> bool: + s3_path = self.generate_latest_s3_path(path, library_name, content_path) + if self.confirm_db_path_exists(s3_path) or self.confirm_s3_path_exists(s3_path): + return True + return False + + def confirm_s3_path_exists(self, path: str) -> bool: + logger.debug(f"{path=}") + return False + + def confirm_db_path_exists(self, path: str) -> bool: + logger.debug(f"{path=}") + if is_path := RenderedContent.objects.filter(cache_key=path).exists(): + logger.debug(f"{is_path=}") + return True + return True + + +class LibsPathMatcher(BasePathMatcher): + determination_re = re.compile( + rf"{BOOST_VERSION_REGEX}/libs/(?P[\w]+)/(?P\S+)" + ) + path_type = PathType.LIB_IN_PATH + + def generate_latest_s3_path(self, path, library_name: str, content_path: str): + latest_str = self.latest_library_version.version.stripped_boost_url_slug + return os.path.sep.join( + [f"static_content_{latest_str}", "libs", library_name, content_path] + ) + + +if __name__ == "__main__": + test_path = "1_84_0/libs/algorithm/doc/html/index.html" + matcher = LibsPathMatcher(Version.objects.most_recent()) + matcher.determine_match(test_path) diff --git a/libraries/tests/path_matcher/__init__.py b/libraries/tests/path_matcher/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/libraries/tests/path_matcher/test_matchers.py b/libraries/tests/path_matcher/test_matchers.py new file mode 100644 index 00000000..0d4de5fb --- /dev/null +++ b/libraries/tests/path_matcher/test_matchers.py @@ -0,0 +1,15 @@ +from libraries.path_matcher.base_path_matcher import LibsPathMatcher + + +def test_library_in_path_matcher(library_version): + import os + import django + + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings") + django.setup() + + test_path = "1_84_0/libs/algorithm/doc/html/index.html" + matcher = LibsPathMatcher(library_version) + type = matcher.determine_match(test_path) + + print(f"{type}")