Skip to content

Commit

Permalink
[SDESK-7062] Allow registering new resources for autocomplete suggest…
Browse files Browse the repository at this point in the history
…ions (#2478)

* [SDESK-7062] Allow registering new resources for autocomplete suggestions

* update behave tests

* Add `count` to response
  • Loading branch information
MarkLark86 authored Oct 15, 2023
1 parent b62b0bf commit 527ecb0
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 44 deletions.
110 changes: 69 additions & 41 deletions apps/archive/autocomplete.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import locale
from typing import List, Dict, Callable
import warnings
import superdesk

Expand All @@ -16,62 +16,89 @@
SETTING_LIMIT = "ARCHIVE_AUTOCOMPLETE_LIMIT"


AutocompleteSuggestionProvider = Callable[[str, str], Dict[str, int]]
_registered_autocomplete_resources: Dict[str, AutocompleteSuggestionProvider] = {}


def register_autocomplete_suggestion_provider(resource: str, provider: AutocompleteSuggestionProvider):
_registered_autocomplete_resources[resource] = provider


class AutocompleteResource(superdesk.Resource):
item_methods = []
resource_methods = ["GET"]
schema = {
"value": {"type": "string"},
"count": {"type": "integer"},
}


class AutocompleteService(superdesk.Service):
field_mapping = {
"slugline": "slugline.keyword",
}

def get(self, req, lookup):
field = request.args.get("field", "slugline")
language = request.args.get("language", app.config.get("DEFAULT_LANGUAGE", "en"))
resources: List[str] = (
_registered_autocomplete_resources.keys()
if not request.args.get("resources")
else request.args.get("resources").split(",")
)
field: str = request.args.get("field", "slugline")
language: str = request.args.get("language", app.config.get("DEFAULT_LANGUAGE", "en"))

if not app.config.get(SETTING_ENABLED):
raise SuperdeskApiError(_("Archive autocomplete is not enabled"), 404)
all_suggestions: Dict[str, int] = {}
for resource in resources:
get_suggestions = _registered_autocomplete_resources.get(resource)
if not get_suggestions:
raise SuperdeskApiError(
_(f"Autocomplete suggestion for resource type '{resource}' not registered"), 404
)

if field not in self.field_mapping:
raise SuperdeskApiError(_("Field %(field)s is not allowed", field=field), 400)
for key, count in get_suggestions(field, language).items():
all_suggestions.setdefault(key, 0)
all_suggestions[key] += count

versioncreated_min = (
utcnow()
- timedelta(
days=app.config[SETTING_DAYS],
hours=app.config[SETTING_HOURS],
)
).replace(
microsecond=0
) # avoid different microsecond each time so elastic has 1s to cache

query = {
"query": {
"bool": {
"filter": [
{"term": {"state": "published"}},
{"term": {"language": language}},
{"range": {"versioncreated": {"gte": versioncreated_min}}},
],
},
return ListCursor([{"value": key, "count": all_suggestions[key]} for key in sorted(all_suggestions.keys())])


def get_archive_suggestions(field: str, language: str) -> Dict[str, int]:
if not app.config.get(SETTING_ENABLED):
raise SuperdeskApiError(_("Archive autocomplete is not enabled"), 404)

field_mapping = {"slugline": "slugline.keyword"}

if field not in field_mapping:
raise SuperdeskApiError(_("Field %(field)s is not allowed", field=field), 400)

versioncreated_min = (
utcnow()
- timedelta(
days=app.config[SETTING_DAYS],
hours=app.config[SETTING_HOURS],
)
).replace(
microsecond=0
) # avoid different microsecond each time so elastic has 1s to cache

query = {
"query": {
"bool": {
"filter": [
{"term": {"state": "published"}},
{"term": {"language": language}},
{"range": {"versioncreated": {"gte": versioncreated_min}}},
],
},
"aggs": {
"values": {
"terms": {
"field": self.field_mapping[field],
"size": app.config[SETTING_LIMIT],
"order": {"_key": "asc"},
},
},
"aggs": {
"values": {
"terms": {
"field": field_mapping[field],
"size": app.config[SETTING_LIMIT],
"order": {"_key": "asc"},
},
},
}
res = app.data.elastic.search(query, "archive", params={"size": 0})
docs = [{"value": bucket["key"]} for bucket in res.hits["aggregations"]["values"]["buckets"]]
return ListCursor(docs)
},
}
res = app.data.elastic.search(query, "archive", params={"size": 0})
return {bucket["key"]: bucket["doc_count"] for bucket in res.hits["aggregations"]["values"]["buckets"]}


def init_app(_app) -> None:
Expand All @@ -87,3 +114,4 @@ def init_app(_app) -> None:
)

superdesk.register_resource("archive_autocomplete", AutocompleteResource, AutocompleteService, _app=_app)
register_autocomplete_suggestion_provider("archive", get_archive_suggestions)
18 changes: 15 additions & 3 deletions features/archive_autocomplete.feature
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Feature: Archive autocomplete
"""
[
{"slugline": "PUBLISHED-A", "state": "published", "versioncreated": "2019-01-01T00:00:00+0000"},
{"slugline": "PUBLISHED-A", "state": "published", "versioncreated": "2019-01-01T01:00:00+0000"},
{"slugline": "PUBLISHED-OLD", "state": "published", "versioncreated": "1919-01-01T00:00:00+0000"},
{"slugline": "DRAFT", "state": "draft", "versioncreated": "2019-01-01T00:00:00+0000"},
{"slugline": "CZECH", "state": "published", "versioncreated": "2019-01-01T00:00:00+0000", "language": "cs"},
Expand All @@ -29,8 +30,19 @@ Feature: Archive autocomplete
Then we get list with 3 items
"""
{"_items": [
{"value": "PUBLISHED-A"},
{"value": "PUBLISHED-B"},
{"value": "PUBLISHED-C"}
{"value": "PUBLISHED-A", "count": 2},
{"value": "PUBLISHED-B", "count": 1},
{"value": "PUBLISHED-C", "count": 1}
]}
"""
When we get "/archive_autocomplete?field=slugline&language=en&resources=archive"
Then we get list with 3 items
"""
{"_items": [
{"value": "PUBLISHED-A", "count": 2},
{"value": "PUBLISHED-B", "count": 1},
{"value": "PUBLISHED-C", "count": 1}
]}
"""
When we get "/archive_autocomplete?field=slugline&language=en&resources=no_such_resource"
Then we get error 404

0 comments on commit 527ecb0

Please sign in to comment.