diff --git a/ebl/corpus/web/bootstrap.py b/ebl/corpus/web/bootstrap.py index 5c7e9c9a4..d3fbd1161 100644 --- a/ebl/corpus/web/bootstrap.py +++ b/ebl/corpus/web/bootstrap.py @@ -13,7 +13,7 @@ from ebl.corpus.web.lemmatizations import LemmatizationResource from ebl.corpus.web.lines import LinesImportResource, LinesResource, LineResource from ebl.corpus.web.manuscripts import ManuscriptsResource -from ebl.corpus.web.texts import TextResource, TextSearchResource, TextsResource +from ebl.corpus.web.texts import TextResource, TextsResource, make_text_search_resource from ebl.corpus.web.unplaced_lines import UnplacedLinesResource from ebl.transliteration.application.transliteration_query_factory import ( TransliterationQueryFactory, @@ -32,8 +32,8 @@ def create_corpus_routes(api: falcon.App, context: Context): texts = TextsResource(corpus) text = TextResource(corpus) - text_search = TextSearchResource( - corpus, TransliterationQueryFactory(context.sign_repository) + text_search = make_text_search_resource( + context.cache, corpus, TransliterationQueryFactory(context.sign_repository) ) chapters = ChaptersResource(corpus) chapters_display = ChaptersDisplayResource(corpus) diff --git a/ebl/corpus/web/texts.py b/ebl/corpus/web/texts.py index 564550b72..dda544d3e 100644 --- a/ebl/corpus/web/texts.py +++ b/ebl/corpus/web/texts.py @@ -1,5 +1,8 @@ import falcon +from falcon_caching import Cache +from falcon_caching.utils import register +from ebl.cache import DEFAULT_TIMEOUT, cache_control from ebl.corpus.application.corpus import Corpus from ebl.corpus.web.chapter_info_schema import ( ChapterInfosPaginationSchema, @@ -35,21 +38,34 @@ def on_get( resp.media = ApiTextSchema().dump(text) -class TextSearchResource: - def __init__( - self, corpus: Corpus, transliteration_query_factory: TransliterationQueryFactory - ): - self._corpus = corpus - self._transliteration_query_factory = transliteration_query_factory +def make_text_search_resource( + cache: Cache, + corpus: Corpus, + transliteration_query_factory: TransliterationQueryFactory, +): + class TextSearchResource: + def __init__( + self, + corpus: Corpus, + transliteration_query_factory: TransliterationQueryFactory, + ): + self._corpus = corpus + self._transliteration_query_factory = transliteration_query_factory - @falcon.before(require_scope, "read:texts") - def on_get(self, req: falcon.Request, resp: falcon.Response) -> None: - query = self._transliteration_query_factory.create( - req.params["transliteration"] + @register( + falcon.before(require_scope, "read:texts"), + cache_control(["private", f"max-age={DEFAULT_TIMEOUT}"]), + cache.cached(timeout=DEFAULT_TIMEOUT), ) - try: - pagination_index = int(req.params["paginationIndex"]) - except ValueError as error: - raise DataError("Pagination Index has to be a number") from error - chapters = self._corpus.search_transliteration(query, pagination_index) - resp.media = ChapterInfosPaginationSchema().dump(chapters) + def on_get(self, req: falcon.Request, resp: falcon.Response) -> None: + query = self._transliteration_query_factory.create( + req.params["transliteration"] + ) + try: + pagination_index = int(req.params["paginationIndex"]) + except ValueError as error: + raise DataError("Pagination Index has to be a number") from error + chapters = self._corpus.search_transliteration(query, pagination_index) + resp.text = ChapterInfosPaginationSchema().dumps(chapters) + + return TextSearchResource(corpus, transliteration_query_factory) diff --git a/ebl/fragmentarium/web/fragment_search.py b/ebl/fragmentarium/web/fragment_search.py index f5890375d..0b74fd2e1 100644 --- a/ebl/fragmentarium/web/fragment_search.py +++ b/ebl/fragmentarium/web/fragment_search.py @@ -20,7 +20,17 @@ ) from ebl.users.web.require_scope import require_scope -CACHED_COMMANDS = frozenset({"latest", "needsRevision"}) +CACHED_COMMANDS = frozenset( + { + "latest", + "needsRevision", + "number", + "transliteration", + "bibliographyId", + "pages", + "paginationIndex", + } +) class FragmentSearch: @@ -53,20 +63,22 @@ def find_latest(_): "paginationIndex", ] ): lambda value: self._search_fragmentarium(finder, value), - frozenset(["random"]): lambda _: self.api_fragment_info_schema.dump( + frozenset(["random"]): lambda _: self.api_fragment_info_schema.dumps( finder.find_random() ), frozenset( ["interesting"] - ): lambda _: self.api_fragment_info_schema.dump( + ): lambda _: self.api_fragment_info_schema.dumps( finder.find_interesting() ), - frozenset(["latest"]): lambda x: self.api_fragment_info_schema.dump( + frozenset(["latest"]): lambda x: self.api_fragment_info_schema.dumps( find_latest(x) ), frozenset( ["needsRevision"] - ): lambda x: self.api_fragment_info_schema.dump(find_needs_revision(x)), + ): lambda x: self.api_fragment_info_schema.dumps( + find_needs_revision(x) + ), } ) @@ -74,7 +86,9 @@ def _search_fragmentarium(self, finder: FragmentFinder, query: Dict) -> Dict: fragment_infos_pagination = finder.search_fragmentarium( self._parse_fragmentarium_search(**query) ) - return self.api_fragment_infos_pagination_schema.dump(fragment_infos_pagination) + return self.api_fragment_infos_pagination_schema.dumps( + fragment_infos_pagination + ) def _parse_fragmentarium_search( self, @@ -128,4 +142,4 @@ def _validate_pages(id: str, pages: str) -> Tuple[str, str]: when=lambda req, _: req.params.keys() <= CACHED_COMMANDS, ) def on_get(self, req: falcon.Request, resp: falcon.Response) -> None: - resp.media = self._dispatch(req.params) + resp.text = self._dispatch(req.params) diff --git a/ebl/tests/corpus/test_texts_route.py b/ebl/tests/corpus/test_texts_route.py index 883a93952..164df0eb1 100644 --- a/ebl/tests/corpus/test_texts_route.py +++ b/ebl/tests/corpus/test_texts_route.py @@ -77,3 +77,4 @@ def test_searching_texts(client, bibliography, sign_repository, signs, text_repo ], "totalCount": 1, } + assert get_result.headers["Cache-Control"] == "private, max-age=600" diff --git a/ebl/tests/fragmentarium/test_fragments_search_route.py b/ebl/tests/fragmentarium/test_fragments_search_route.py index c136902b9..de4f615df 100644 --- a/ebl/tests/fragmentarium/test_fragments_search_route.py +++ b/ebl/tests/fragmentarium/test_fragments_search_route.py @@ -58,7 +58,7 @@ def test_search_fragmentarium_number(get_number, client, fragmentarium): FragmentInfosPagination([FragmentInfo.of(fragment)], 1) ) - assert "Cache-Control" not in result.headers + assert result.headers["Cache-Control"] == "private, max-age=600" def test_search_fragmentarium_number_not_found(client): @@ -76,6 +76,7 @@ def test_search_fragmentarium_number_not_found(client): assert result.json == expected_fragment_infos_pagination_dto( FragmentInfosPagination([], 0) ) + assert result.headers["Cache-Control"] == "private, max-age=600" def test_search_fragmentarium_references(client, fragmentarium, bibliography, user): @@ -113,7 +114,7 @@ def test_search_fragmentarium_references(client, fragmentarium, bibliography, us assert result.json == expected_fragment_infos_pagination_dto( FragmentInfosPagination([FragmentInfo.of(fragment_expected)], 1) ) - assert "Cache-Control" not in result.headers + assert result.headers["Cache-Control"] == "private, max-age=600" def test_search_fragmentarium_invalid_references_query(client, fragmentarium): @@ -134,6 +135,7 @@ def test_search_fragmentarium_invalid_references_query(client, fragmentarium): }, ) assert result.status == falcon.HTTP_UNPROCESSABLE_ENTITY + assert "Cache-Control" not in result.headers def test_search_fragmentarium_transliteration( @@ -180,7 +182,7 @@ def test_search_fragmentarium_transliteration( ) ) - assert "Cache-Control" not in result.headers + assert result.headers["Cache-Control"] == "private, max-age=600" def test_search_fragmentarium_combined_query( @@ -231,7 +233,7 @@ def test_search_fragmentarium_combined_query( 1, ) ) - assert "Cache-Control" not in result.headers + assert result.headers["Cache-Control"] == "private, max-age=600" def test_search_signs_invalid(client, fragmentarium, sign_repository, signs):