diff options
-rw-r--r-- | python/fatcat_web/routes.py | 8 | ||||
-rw-r--r-- | python/fatcat_web/search.py | 64 | ||||
-rw-r--r-- | python/fatcat_web/templates/container_view_browse.html | 37 |
3 files changed, 79 insertions, 30 deletions
diff --git a/python/fatcat_web/routes.py b/python/fatcat_web/routes.py index f8182679..0f847cca 100644 --- a/python/fatcat_web/routes.py +++ b/python/fatcat_web/routes.py @@ -393,10 +393,10 @@ def container_view_browse(ident: str) -> AnyResponse: query_string = f"year:{year}" query_sort = ["release_date"] else: - entity._browse_volume_year = get_elastic_container_browse_year_volume_issue( + entity._browse_year_volume_issue = get_elastic_container_browse_year_volume_issue( entity.ident ) - print(entity._browse_volume_year) + # print(entity._browse_year_volume_issue) return render_template( "container_view_browse.html", entity_type="container", @@ -404,7 +404,7 @@ def container_view_browse(ident: str) -> AnyResponse: editgroup_id=None, ) - print(query_string) + # print(query_string) query = ReleaseQuery( q=query_string, limit=200, @@ -1093,7 +1093,7 @@ def release_search() -> AnyResponse: container_found = None filter_only_query = True for p in request.args.get("q", "").split(): - if not ":" in p: + if ":" not in p: filter_only_query = False break if request.args.get("generic") and not filter_only_query: diff --git a/python/fatcat_web/search.py b/python/fatcat_web/search.py index e79fcd8d..7528c3d4 100644 --- a/python/fatcat_web/search.py +++ b/python/fatcat_web/search.py @@ -247,9 +247,39 @@ def get_elastic_container_random_releases(ident: str, limit: int = 5) -> List[Di return results -def get_elastic_container_browse_year_volume_issue(ident: str) -> Dict[int, Dict[str, Any]]: +def _sort_vol_key(val: Optional[str]) -> Tuple[bool, bool, int, str]: """ - Returns a set of histogram buckets, by year (int), volume (str), issue (str) + Helper for sorting volume and issue strings. Defined order is: + + - None values first + - any non-integers next, in non-integer order + - any integers next, in integer sorted order (ascending) + + Note that the actual sort used/displayed is reversed + """ + if val is None: + return (False, False, 0, "") + if val.isdigit(): + return (True, True, int(val), "") + else: + return (True, False, 0, val) + + +def get_elastic_container_browse_year_volume_issue(ident: str) -> List[Dict[str, Any]]: + """ + Returns a set of histogram buckets, as nested dicts/lists: + + [ + { year: int, + volumes: [ + { volume: str|None + issues: [ + { issue: str|None + count: int + } + ] } + ] } + ] """ search = Search(using=app.es_client, index=app.config["ELASTICSEARCH_RELEASE_INDEX"]) @@ -269,9 +299,6 @@ def get_elastic_container_browse_year_volume_issue(ident: str) -> Dict[int, Dict "field": "release_year", "interval": 1, "missing_bucket": True, - # TODO: es-public-proxy support? - # "order": "asc", - # "missing_order": "last", }, } }, @@ -306,12 +333,31 @@ def get_elastic_container_browse_year_volume_issue(ident: str) -> Dict[int, Dict year_dicts[year] = {} for row in buckets: year = int(row["key"]["year"]) - volume = row["key"]["volume"] or "000_unknown" - issue = row["key"]["issue"] or "000_unknown" - if not volume in year_dicts[year]: + volume = row["key"]["volume"] or "" + issue = row["key"]["issue"] or "" + if volume not in year_dicts[year]: year_dicts[year][volume] = {} year_dicts[year][volume][issue] = int(row["doc_count"]) - return year_dicts + + # transform to lists-of-dicts + year_list = [] + for year in year_dicts.keys(): + volume_list = [] + for volume in year_dicts[year].keys(): + issue_list = [] + for issue in year_dicts[year][volume].keys(): + issue_list.append( + dict(issue=issue or None, count=year_dicts[year][volume][issue]) + ) + issue_list = sorted( + issue_list, key=lambda x: _sort_vol_key(x["issue"]), reverse=True + ) + volume_list.append(dict(volume=volume or None, issues=issue_list)) + volume_list = sorted( + volume_list, key=lambda x: _sort_vol_key(x["volume"]), reverse=True + ) + year_list.append(dict(year=year, volumes=volume_list)) + return sorted(year_list, key=lambda x: x["year"], reverse=True) def get_elastic_entity_stats() -> dict: diff --git a/python/fatcat_web/templates/container_view_browse.html b/python/fatcat_web/templates/container_view_browse.html index a2ad251b..6ea06df8 100644 --- a/python/fatcat_web/templates/container_view_browse.html +++ b/python/fatcat_web/templates/container_view_browse.html @@ -17,36 +17,36 @@ <tbody> {# NOTE: this section is pretty nested, with complex behavior; it could be hard to edit and understand #} {# TODO: these "sorts" are lexical, not numeric, which causes problems #} - {% for year in data.keys()|sort|reverse %} + {% for year in data %} {% set year_loop = loop %} - {% for volume in data[year].keys()|sort|reverse %} + {% for volume in year.volumes %} {% set volume_loop = loop %} - {% for issue in data[year][volume].keys()|sort|reverse %} + {% for issue in volume.issues %} {% set issue_loop = loop %} <tr> {% if volume_loop.first and issue_loop.first %} - {% set year_rowspan = data[year].values()|map('length')|sum %} + {% set year_rowspan = year.volumes|map(attribute='issues')|map('length')|sum %} <td rowspan="{{ year_rowspan }}" class="top aligned"> - <a href="/container/{{ entity.ident }}/browse?year={{ year }}">{{ year }}</a> + <a href="/container/{{ entity.ident }}/browse?year={{ year.year }}">{{ year.year }}</a> </td> {% endif %} {% if issue_loop.first %} - <td rowspan="{{ data[year][volume]|length }}" class="top aligned"> - {% if volume != '000_unknown' %} - <a href="/container/{{ entity.ident }}/browse?volume={{ volume }}">Vol. {{ volume }}</a> + <td rowspan="{{ volume.issues|length }}" class="top aligned"> + {% if volume.volume %} + <a href="/container/{{ entity.ident }}/browse?volume={{ volume.volume }}">Vol. {{ volume.volume }}</a> {% endif %} </td> {% endif %} <td> - {% if issue != '000_unknown' %} - <a href="/container/{{ entity.ident }}/browse?year={{ year }}{% if volume != '000_unknown' %}&volume={{ volume }}{% endif %}&issue={{ issue }}">Issue {{ issue }}</a> + {% if issue.issue %} + <a href="/container/{{ entity.ident }}/browse?year={{ year.year }}{% if volume.volume %}&volume={{ volume.volume }}{% endif %}&issue={{ issue.issue }}">Issue {{ issue.issue }}</a> {% endif %} </td> <td class="right aligned"> - <a href="/container/{{ entity.ident }}/browse?year={{ year }}{% if volume != '000_unknown' %}&volume={{ volume }}{% endif %}{% if issue != '000_unknown' %}&issue={{ issue }}{% endif %}">{{ "{:,}".format(data[year][volume][issue]) }} releases</a> + <a href="/container/{{ entity.ident }}/browse?year={{ year.year }}{% if volume.volume %}&volume={{ volume.volume }}{% endif %}{% if issue.issue %}&issue={{ issue.issue }}{% endif %}">{{ "{:,}".format(issue.count) }} releases</a> </td> </tr> {% endfor %} @@ -58,10 +58,13 @@ {% macro browse_releases(found) %} <h2> - Browsing: - {% if request.args.volume %}Volume {{ request.args.volume }} {% endif %} - {% if request.args.issue %}Issue {{ request.args.issue }} {% endif %} - {% if request.args.year %}Year {{ request.args.year }} {% endif %} + {% if request.args.volume %} + Volume {{ request.args.volume }} + {%- if request.args.issue %}, Issue {{ request.args.issue }}{% endif -%} + {%- if request.args.year %} ({{ request.args.year }}){% endif %} + {% else %} + Year {{ request.args.year }} + {% endif %} </h2> <br> {% for release_doc in found.results %} @@ -88,13 +91,13 @@ {% if releases_found %} {{ browse_releases(releases_found) }} -{% elif entity._browse_volume_year %} +{% elif entity._browse_year_volume_issue %} <div class="ui container text"> <h3>Publications by Year, Volume, and Issue</h3> <p>This table includes content which does not have article-level metadata about volume or issue, but at least the year of publication must be known. "Stub" releases (eg, spam or duplicate DOIs) are not listed. - {{ browse_year_volume_issue_table(entity, entity._browse_volume_year) }} + {{ browse_year_volume_issue_table(entity, entity._browse_year_volume_issue) }} </div> {% endif %} |