From 236a862a651846040df897e285baaba4e3cd95f9 Mon Sep 17 00:00:00 2001 From: Ansh Goyal Date: Fri, 2 Sep 2022 10:04:00 +0000 Subject: [PATCH] feat: Add endpoints for BB entities --- critiquebrainz/ws/__init__.py | 8 + critiquebrainz/ws/bb_author/__init__.py | 0 critiquebrainz/ws/bb_author/views.py | 213 ++++++++++++++++++ .../ws/bb_edition_group/__init__.py | 0 critiquebrainz/ws/bb_edition_group/views.py | 191 ++++++++++++++++ .../ws/bb_literary_work/__init__.py | 0 critiquebrainz/ws/bb_literary_work/views.py | 211 +++++++++++++++++ critiquebrainz/ws/bb_series/__init__.py | 0 critiquebrainz/ws/bb_series/views.py | 183 +++++++++++++++ 9 files changed, 806 insertions(+) create mode 100644 critiquebrainz/ws/bb_author/__init__.py create mode 100644 critiquebrainz/ws/bb_author/views.py create mode 100644 critiquebrainz/ws/bb_edition_group/__init__.py create mode 100644 critiquebrainz/ws/bb_edition_group/views.py create mode 100644 critiquebrainz/ws/bb_literary_work/__init__.py create mode 100644 critiquebrainz/ws/bb_literary_work/views.py create mode 100644 critiquebrainz/ws/bb_series/__init__.py create mode 100644 critiquebrainz/ws/bb_series/views.py diff --git a/critiquebrainz/ws/__init__.py b/critiquebrainz/ws/__init__.py index 3eab53294..1bc0afc49 100644 --- a/critiquebrainz/ws/__init__.py +++ b/critiquebrainz/ws/__init__.py @@ -116,6 +116,10 @@ def _register_blueprints(app): from critiquebrainz.ws.recording.views import recording_bp from critiquebrainz.ws.release_group.views import release_group_bp from critiquebrainz.ws.work.views import work_bp + from critiquebrainz.ws.bb_author.views import author_bp + from critiquebrainz.ws.bb_edition_group.views import edition_group_bp + from critiquebrainz.ws.bb_literary_work.views import literary_work_bp + from critiquebrainz.ws.bb_series.views import series_bp app.register_blueprint(oauth_bp, url_prefix="/oauth") app.register_blueprint(review_bp, url_prefix="/review") app.register_blueprint(user_bp, url_prefix="/user") @@ -127,4 +131,8 @@ def _register_blueprints(app): app.register_blueprint(recording_bp, url_prefix="/recording") app.register_blueprint(release_group_bp, url_prefix="/release-group") app.register_blueprint(work_bp, url_prefix="/work") + app.register_blueprint(author_bp, url_prefix="/author") + app.register_blueprint(edition_group_bp, url_prefix="/edition-group") + app.register_blueprint(literary_work_bp, url_prefix="/literary-work") + app.register_blueprint(series_bp, url_prefix="/series") diff --git a/critiquebrainz/ws/bb_author/__init__.py b/critiquebrainz/ws/bb_author/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/critiquebrainz/ws/bb_author/views.py b/critiquebrainz/ws/bb_author/views.py new file mode 100644 index 000000000..1a9554a7b --- /dev/null +++ b/critiquebrainz/ws/bb_author/views.py @@ -0,0 +1,213 @@ +from flask import Blueprint, jsonify +import critiquebrainz.db.review as db_review +import critiquebrainz.db.rating_stats as db_rating_stats +from critiquebrainz.frontend.external.bookbrainz_db import author as db_author +from critiquebrainz.decorators import crossdomain +from critiquebrainz.ws.exceptions import NotFound +from critiquebrainz.ws.parser import Parser +from critiquebrainz.ws import REVIEWS_LIMIT + +author_bp = Blueprint('ws_author', __name__) + + +@author_bp.route('/', methods=['GET', 'OPTIONS']) +@crossdomain(headers="Authorization, Content-Type") +def author_entity_handler(author_bbid): + """Get list of reviews. + + **Request Example:** + + .. code-block:: bash + + $ curl "https://critiquebrainz.org/ws/1/author/e5c4e68b-bfce-4c77-9ca2-0f0a2d4d09f0" \\ + -X GET + + **Response Example:** + + .. code-block:: json + + { + "author": { + "area_id": null, + "area_info": [], + "author_type": "Person", + "bbid": "e5c4e68b-bfce-4c77-9ca2-0f0a2d4d09f0", + "begin_area_id": 221, + "begin_day": 31, + "begin_month": 7, + "begin_year": 1965, + "disambiguation": null, + "end_area_id": null, + "end_day": null, + "end_month": null, + "end_year": null, + "ended": false, + "gender": "Female", + "identifier_set_id": 7401, + "identifiers": [ + { + "icon": "wikidata-16.png", + "name": "Wikidata ID", + "url": "https://www.wikidata.org/wiki/Q34660", + "value": "Q34660" + }, + { + "icon": "viaf-16.png", + "name": "VIAF", + "url": "https://viaf.org/viaf/116796842", + "value": "116796842" + }, + { + "icon": "wikidata-16.png", + "name": "Wikidata ID", + "url": "https://www.wikidata.org/wiki/Q1190608", + "value": "Q1190608" + } + ], + "name": "J. K. Rowling", + "relationship_set_id": 151715, + "sort_name": "Rowling, J. K." + }, + "average_rating": 5.0, + "latest_reviews": [ + { + "created": "Tue, 16 Aug 2022 11:25:44 GMT", + "edits": 0, + "entity_id": "e5c4e68b-bfce-4c77-9ca2-0f0a2d4d09f0", + "entity_type": "bb_author", + "full_name": "Creative Commons Attribution-ShareAlike 3.0 Unported", + "id": "326e702a-020f-40e7-b369-9142a7af4315", + "info_url": "https://creativecommons.org/licenses/by-sa/3.0/", + "is_draft": false, + "is_hidden": false, + "language": "en", + "last_revision": { + "id": 11785, + "rating": 5, + "review_id": "326e702a-020f-40e7-b369-9142a7af4315", + "text": null, + "timestamp": "Fri, 02 Sep 2022 09:54:13 GMT" + }, + "last_updated": "Fri, 02 Sep 2022 09:54:13 GMT", + "license_id": "CC BY-SA 3.0", + "popularity": 0, + "published_on": "Tue, 16 Aug 2022 11:25:44 GMT", + "rating": 5, + "source": null, + "source_url": null, + "text": null, + "user": { + "created": "Tue, 18 Jan 2022 09:53:49 GMT", + "display_name": "Ansh Goyal", + "id": "11a1160e-d607-4882-8a82-e2e800f664fe", + "karma": 0, + "user_type": "Noob" + }, + "votes_negative_count": 0, + "votes_positive_count": 0 + } + ], + "ratings_stats": { + "1": 0, + "2": 0, + "3": 0, + "4": 0, + "5": 1 + }, + "reviews_count": 1, + "top_reviews": [ + { + "created": "Tue, 16 Aug 2022 11:25:44 GMT", + "edits": 0, + "entity_id": "e5c4e68b-bfce-4c77-9ca2-0f0a2d4d09f0", + "entity_type": "bb_author", + "full_name": "Creative Commons Attribution-ShareAlike 3.0 Unported", + "id": "326e702a-020f-40e7-b369-9142a7af4315", + "info_url": "https://creativecommons.org/licenses/by-sa/3.0/", + "is_draft": false, + "is_hidden": false, + "language": "en", + "last_revision": { + "id": 11785, + "rating": 5, + "review_id": "326e702a-020f-40e7-b369-9142a7af4315", + "text": null, + "timestamp": "Fri, 02 Sep 2022 09:54:13 GMT" + }, + "last_updated": "Fri, 02 Sep 2022 09:54:13 GMT", + "license_id": "CC BY-SA 3.0", + "popularity": 0, + "published_on": "Tue, 16 Aug 2022 11:25:44 GMT", + "rating": 5, + "source": null, + "source_url": null, + "text": null, + "user": { + "created": "Tue, 18 Jan 2022 09:53:49 GMT", + "display_name": "Ansh Goyal", + "id": "11a1160e-d607-4882-8a82-e2e800f664fe", + "karma": 0, + "user_type": "Noob" + }, + "votes_negative_count": 0, + "votes_positive_count": 0 + } + ] + } + + :statuscode 200: no error + :statuscode 404: author not found + + :resheader Content-Type: *application/json* + """ + + author = db_author.get_author_by_bbid(str(author_bbid)) + + if not author: + raise NotFound("Can't find an author with ID: {author_bbid}".format(author_bbid=author_bbid)) + + user_id = Parser.uuid('uri', 'user_id', optional=True) + if user_id: + user_review, _ = db_review.list_reviews( + entity_id=author['bbid'], + entity_type='bb_author', + user_id=user_id + ) + if user_review: + user_review = db_review.to_dict(user_review[0]) + else: + user_review = None + + ratings_stats, average_rating = db_rating_stats.get_stats(author_bbid, "bb_author") + + top_reviews, reviews_count = db_review.list_reviews( + entity_id=author['bbid'], + entity_type='bb_author', + sort='popularity', + limit=REVIEWS_LIMIT, + offset=0, + ) + + latest_reviews, reviews_count = db_review.list_reviews( + entity_id=author['bbid'], + entity_type='bb_author', + sort='published_on', + limit=REVIEWS_LIMIT, + offset=0, + ) + + top_reviews = [db_review.to_dict(review) for review in top_reviews] + latest_reviews = [db_review.to_dict(review) for review in latest_reviews] + + result = { + "author": author, + "average_rating": average_rating, + "ratings_stats": ratings_stats, + "reviews_count": reviews_count, + "top_reviews": top_reviews, + "latest_reviews": latest_reviews + } + if user_id: + result['user_review'] = user_review + + return jsonify(**result) diff --git a/critiquebrainz/ws/bb_edition_group/__init__.py b/critiquebrainz/ws/bb_edition_group/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/critiquebrainz/ws/bb_edition_group/views.py b/critiquebrainz/ws/bb_edition_group/views.py new file mode 100644 index 000000000..54edee1d9 --- /dev/null +++ b/critiquebrainz/ws/bb_edition_group/views.py @@ -0,0 +1,191 @@ +from flask import Blueprint, jsonify +import critiquebrainz.db.review as db_review +import critiquebrainz.db.rating_stats as db_rating_stats +from critiquebrainz.frontend.external.bookbrainz_db import edition_group as db_edition_group +from critiquebrainz.decorators import crossdomain +from critiquebrainz.ws.exceptions import NotFound +from critiquebrainz.ws.parser import Parser +from critiquebrainz.ws import REVIEWS_LIMIT + +edition_group_bp = Blueprint('ws_edition_group', __name__) + + +@edition_group_bp.route('/', methods=['GET', 'OPTIONS']) +@crossdomain(headers="Authorization, Content-Type") +def edition_group_entity_handler(edition_group_bbid): + """Get list of reviews. + + **Request Example:** + + .. code-block:: bash + + $ curl "https://critiquebrainz.org/ws/1/edition-group/b2a5f76e-91c6-46bb-a618-3ee5ebc6dd6c" \\ + -X GET + + **Response Example:** + + .. code-block:: json + + { + "average_rating": 5.0, + "edition_group": { + "author_credits": [], + "bbid": "b2a5f76e-91c6-46bb-a618-3ee5ebc6dd6c", + "disambiguation": null, + "edition_group_type": "Book", + "identifier_set_id": 1272, + "identifiers": [ + { + "icon": "wikidata-16.png", + "name": "Wikidata ID", + "url": "https://www.wikidata.org/wiki/Q47209", + "value": "Q47209" + } + ], + "name": "Harry Potter and the Chamber of Secrets", + "relationship_set_id": null, + "rels": null, + "sort_name": "Chamber of Secrets, Harry Potter and the" + }, + "latest_reviews": [ + { + "created": "Thu, 28 Jul 2022 07:03:41 GMT", + "edits": 0, + "entity_id": "b2a5f76e-91c6-46bb-a618-3ee5ebc6dd6c", + "entity_type": "bb_edition_group", + "full_name": "Creative Commons Attribution-ShareAlike 3.0 Unported", + "id": "84b01e18-50ac-484e-9e48-41d05250db76", + "info_url": "https://creativecommons.org/licenses/by-sa/3.0/", + "is_draft": false, + "is_hidden": false, + "language": "en", + "last_revision": { + "id": 11786, + "rating": 5, + "review_id": "84b01e18-50ac-484e-9e48-41d05250db76", + "text": null, + "timestamp": "Fri, 02 Sep 2022 09:58:44 GMT" + }, + "last_updated": "Fri, 02 Sep 2022 09:58:44 GMT", + "license_id": "CC BY-SA 3.0", + "popularity": 0, + "published_on": "Thu, 28 Jul 2022 07:03:41 GMT", + "rating": 5, + "source": null, + "source_url": null, + "text": null, + "user": { + "created": "Tue, 18 Jan 2022 09:53:49 GMT", + "display_name": "Ansh Goyal", + "id": "11a1160e-d607-4882-8a82-e2e800f664fe", + "karma": 0, + "user_type": "Noob" + }, + "votes_negative_count": 0, + "votes_positive_count": 0 + } + ], + "ratings_stats": { + "1": 0, + "2": 0, + "3": 0, + "4": 0, + "5": 1 + }, + "reviews_count": 1, + "top_reviews": [ + { + "created": "Thu, 28 Jul 2022 07:03:41 GMT", + "edits": 0, + "entity_id": "b2a5f76e-91c6-46bb-a618-3ee5ebc6dd6c", + "entity_type": "bb_edition_group", + "full_name": "Creative Commons Attribution-ShareAlike 3.0 Unported", + "id": "84b01e18-50ac-484e-9e48-41d05250db76", + "info_url": "https://creativecommons.org/licenses/by-sa/3.0/", + "is_draft": false, + "is_hidden": false, + "language": "en", + "last_revision": { + "id": 11786, + "rating": 5, + "review_id": "84b01e18-50ac-484e-9e48-41d05250db76", + "text": null, + "timestamp": "Fri, 02 Sep 2022 09:58:44 GMT" + }, + "last_updated": "Fri, 02 Sep 2022 09:58:44 GMT", + "license_id": "CC BY-SA 3.0", + "popularity": 0, + "published_on": "Thu, 28 Jul 2022 07:03:41 GMT", + "rating": 5, + "source": null, + "source_url": null, + "text": null, + "user": { + "created": "Tue, 18 Jan 2022 09:53:49 GMT", + "display_name": "Ansh Goyal", + "id": "11a1160e-d607-4882-8a82-e2e800f664fe", + "karma": 0, + "user_type": "Noob" + }, + "votes_negative_count": 0, + "votes_positive_count": 0 + } + ] + } + + :statuscode 200: no error + :statuscode 404: edition group not found + + :resheader Content-Type: *application/json* + """ + + edition_group = db_edition_group.get_edition_group_by_bbid(str(edition_group_bbid)) + + if not edition_group: + raise NotFound("Can't find an edition_group with ID: {edition_group_bbid}".format(edition_group_bbid=edition_group_bbid)) + + user_id = Parser.uuid('uri', 'user_id', optional=True) + if user_id: + user_review, _ = db_review.list_reviews( + entity_id=edition_group['bbid'], + entity_type='bb_edition_group', + user_id=user_id + ) + if user_review: + user_review = db_review.to_dict(user_review[0]) + else: + user_review = None + + ratings_stats, average_rating = db_rating_stats.get_stats(edition_group_bbid, "bb_edition_group") + + top_reviews, reviews_count = db_review.list_reviews( + entity_id=edition_group['bbid'], + entity_type='bb_edition_group', + sort='popularity', + limit=REVIEWS_LIMIT, + offset=0, + ) + + latest_reviews, reviews_count = db_review.list_reviews( + entity_id=edition_group['bbid'], + entity_type='bb_edition_group', + sort='published_on', + limit=REVIEWS_LIMIT, + offset=0, + ) + + top_reviews = [db_review.to_dict(review) for review in top_reviews] + latest_reviews = [db_review.to_dict(review) for review in latest_reviews] + + result = { + "edition_group": edition_group, + "average_rating": average_rating, + "ratings_stats": ratings_stats, + "reviews_count": reviews_count, + "top_reviews": top_reviews, + "latest_reviews": latest_reviews + } + if user_id: + result['user_review'] = user_review + + return jsonify(**result) diff --git a/critiquebrainz/ws/bb_literary_work/__init__.py b/critiquebrainz/ws/bb_literary_work/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/critiquebrainz/ws/bb_literary_work/views.py b/critiquebrainz/ws/bb_literary_work/views.py new file mode 100644 index 000000000..1c1d006d3 --- /dev/null +++ b/critiquebrainz/ws/bb_literary_work/views.py @@ -0,0 +1,211 @@ +from flask import Blueprint, jsonify +import critiquebrainz.db.review as db_review +import critiquebrainz.db.rating_stats as db_rating_stats +from critiquebrainz.frontend.external.bookbrainz_db import literary_work as db_literary_work +from critiquebrainz.decorators import crossdomain +from critiquebrainz.ws.exceptions import NotFound +from critiquebrainz.ws.parser import Parser +from critiquebrainz.ws import REVIEWS_LIMIT + +literary_work_bp = Blueprint('ws_literary_work', __name__) + + +@literary_work_bp.route('/', methods=['GET', 'OPTIONS']) +@crossdomain(headers="Authorization, Content-Type") +def literary_work_entity_handler(literary_work_bbid): + """Get list of reviews. + + **Request Example:** + + .. code-block:: bash + + $ curl "https://critiquebrainz.org/ws/1/literary-work/b2d19b45-117d-437d-b55b-7fff01e29603" \\ + -X GET + + **Response Example:** + + .. code-block:: json + + { + "average_rating": 5.0, + "latest_reviews": [ + { + "created": "Thu, 18 Aug 2022 09:21:37 GMT", + "edits": 0, + "entity_id": "b2d19b45-117d-437d-b55b-7fff01e29603", + "entity_type": "bb_literary_work", + "full_name": "Creative Commons Attribution-ShareAlike 3.0 Unported", + "id": "178b5ef1-ec96-40b8-a08c-b11b01550efd", + "info_url": "https://creativecommons.org/licenses/by-sa/3.0/", + "is_draft": false, + "is_hidden": false, + "language": "en", + "last_revision": { + "id": 11775, + "rating": 5, + "review_id": "178b5ef1-ec96-40b8-a08c-b11b01550efd", + "text": null, + "timestamp": "Thu, 18 Aug 2022 09:21:37 GMT" + }, + "last_updated": "Thu, 18 Aug 2022 09:21:37 GMT", + "license_id": "CC BY-SA 3.0", + "popularity": 0, + "published_on": "Thu, 18 Aug 2022 09:21:37 GMT", + "rating": 5, + "source": null, + "source_url": null, + "text": null, + "user": { + "created": "Tue, 18 Jan 2022 09:53:49 GMT", + "display_name": "Ansh Goyal", + "id": "11a1160e-d607-4882-8a82-e2e800f664fe", + "karma": 0, + "user_type": "Noob" + }, + "votes_negative_count": 0, + "votes_positive_count": 0 + } + ], + "literary_work": { + "bbid": "b2d19b45-117d-437d-b55b-7fff01e29603", + "disambiguation": null, + "identifier_set_id": 2831, + "identifiers": [ + { + "icon": "wikidata-16.png", + "name": "Wikidata ID", + "url": "https://www.wikidata.org/wiki/Q47209", + "value": "Q47209" + }, + { + "icon": "viaf-16.png", + "name": "VIAF", + "url": "https://viaf.org/viaf/190455963", + "value": "190455963" + }, + { + "icon": null, + "name": "OpenLibrary Work ID", + "url": "https://openlibrary.org/works/OL16313124W", + "value": "OL16313124W" + }, + { + "icon": null, + "name": "OpenLibrary Work ID", + "url": "https://openlibrary.org/works/OL16313123W", + "value": "OL16313123W" + } + ], + "languages": [ + "English" + ], + "name": "Harry Potter and the Chamber of Secrets", + "relationship_set_id": 136021, + "rels": null, + "sort_name": "Chamber of Secrets, Harry Potter and the", + "work_type": "Novel" + }, + "ratings_stats": { + "1": 0, + "2": 0, + "3": 0, + "4": 0, + "5": 1 + }, + "reviews_count": 1, + "top_reviews": [ + { + "created": "Thu, 18 Aug 2022 09:21:37 GMT", + "edits": 0, + "entity_id": "b2d19b45-117d-437d-b55b-7fff01e29603", + "entity_type": "bb_literary_work", + "full_name": "Creative Commons Attribution-ShareAlike 3.0 Unported", + "id": "178b5ef1-ec96-40b8-a08c-b11b01550efd", + "info_url": "https://creativecommons.org/licenses/by-sa/3.0/", + "is_draft": false, + "is_hidden": false, + "language": "en", + "last_revision": { + "id": 11775, + "rating": 5, + "review_id": "178b5ef1-ec96-40b8-a08c-b11b01550efd", + "text": null, + "timestamp": "Thu, 18 Aug 2022 09:21:37 GMT" + }, + "last_updated": "Thu, 18 Aug 2022 09:21:37 GMT", + "license_id": "CC BY-SA 3.0", + "popularity": 0, + "published_on": "Thu, 18 Aug 2022 09:21:37 GMT", + "rating": 5, + "source": null, + "source_url": null, + "text": null, + "user": { + "created": "Tue, 18 Jan 2022 09:53:49 GMT", + "display_name": "Ansh Goyal", + "id": "11a1160e-d607-4882-8a82-e2e800f664fe", + "karma": 0, + "user_type": "Noob" + }, + "votes_negative_count": 0, + "votes_positive_count": 0 + } + ] + } + + :statuscode 200: no error + :statuscode 404: literary work not found + + :resheader Content-Type: *application/json* + """ + + literary_work = db_literary_work.get_literary_work_by_bbid(str(literary_work_bbid)) + + if not literary_work: + raise NotFound("Can't find a literary_work with ID: {literary_work_bbid}".format(literary_work_bbid=literary_work_bbid)) + + user_id = Parser.uuid('uri', 'user_id', optional=True) + if user_id: + user_review, _ = db_review.list_reviews( + entity_id=literary_work['bbid'], + entity_type='bb_literary_work', + user_id=user_id + ) + if user_review: + user_review = db_review.to_dict(user_review[0]) + else: + user_review = None + + ratings_stats, average_rating = db_rating_stats.get_stats(literary_work_bbid, "bb_literary_work") + + top_reviews, reviews_count = db_review.list_reviews( + entity_id=literary_work['bbid'], + entity_type='bb_literary_work', + sort='popularity', + limit=REVIEWS_LIMIT, + offset=0, + ) + + latest_reviews, reviews_count = db_review.list_reviews( + entity_id=literary_work['bbid'], + entity_type='bb_literary_work', + sort='published_on', + limit=REVIEWS_LIMIT, + offset=0, + ) + + top_reviews = [db_review.to_dict(review) for review in top_reviews] + latest_reviews = [db_review.to_dict(review) for review in latest_reviews] + + result = { + "literary_work": literary_work, + "average_rating": average_rating, + "ratings_stats": ratings_stats, + "reviews_count": reviews_count, + "top_reviews": top_reviews, + "latest_reviews": latest_reviews + } + if user_id: + result['user_review'] = user_review + + return jsonify(**result) diff --git a/critiquebrainz/ws/bb_series/__init__.py b/critiquebrainz/ws/bb_series/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/critiquebrainz/ws/bb_series/views.py b/critiquebrainz/ws/bb_series/views.py new file mode 100644 index 000000000..da24edea9 --- /dev/null +++ b/critiquebrainz/ws/bb_series/views.py @@ -0,0 +1,183 @@ +from flask import Blueprint, jsonify +import critiquebrainz.db.review as db_review +import critiquebrainz.db.rating_stats as db_rating_stats +from critiquebrainz.frontend.external.bookbrainz_db import series as db_series +from critiquebrainz.decorators import crossdomain +from critiquebrainz.ws.exceptions import NotFound +from critiquebrainz.ws.parser import Parser +from critiquebrainz.ws import REVIEWS_LIMIT + +series_bp = Blueprint('ws_series', __name__) + + +@series_bp.route('/', methods=['GET', 'OPTIONS']) +@crossdomain(headers="Authorization, Content-Type") +def series_entity_handler(series_bbid): + """Get list of reviews. + + **Request Example:** + + .. code-block:: bash + + $ curl "https://critiquebrainz.org/ws/1/series/e6f48cbd-26de-4c2e-a24a-29892f9eb3be" \\ + -X GET + + **Response Example:** + + .. code-block:: json + + { + "average_rating": 4.0, + "latest_reviews": [ + { + "created": "Tue, 16 Aug 2022 11:26:58 GMT", + "edits": 0, + "entity_id": "e6f48cbd-26de-4c2e-a24a-29892f9eb3be", + "entity_type": "bb_series", + "full_name": "Creative Commons Attribution-ShareAlike 3.0 Unported", + "id": "998512d8-0d6b-4c76-bfb7-0ec666e3fa0a", + "info_url": "https://creativecommons.org/licenses/by-sa/3.0/", + "is_draft": false, + "is_hidden": false, + "language": "en", + "last_revision": { + "id": 11773, + "rating": 4, + "review_id": "998512d8-0d6b-4c76-bfb7-0ec666e3fa0a", + "text": null, + "timestamp": "Tue, 16 Aug 2022 11:26:58 GMT" + }, + "last_updated": "Tue, 16 Aug 2022 11:26:58 GMT", + "license_id": "CC BY-SA 3.0", + "popularity": 0, + "published_on": "Tue, 16 Aug 2022 11:26:58 GMT", + "rating": 4, + "source": null, + "source_url": null, + "text": null, + "user": { + "created": "Tue, 18 Jan 2022 09:53:49 GMT", + "display_name": "Ansh Goyal", + "id": "11a1160e-d607-4882-8a82-e2e800f664fe", + "karma": 0, + "user_type": "Noob" + }, + "votes_negative_count": 0, + "votes_positive_count": 0 + } + ], + "ratings_stats": { + "1": 0, + "2": 0, + "3": 0, + "4": 1, + "5": 0 + }, + "reviews_count": 1, + "series": { + "bbid": "e6f48cbd-26de-4c2e-a24a-29892f9eb3be", + "disambiguation": "English", + "identifier_set_id": null, + "identifiers": null, + "name": "Harry Potter", + "relationship_set_id": 151767, + "series_ordering_type": "Automatic", + "series_type": "Work", + "sort_name": "Harry Potter" + }, + "top_reviews": [ + { + "created": "Tue, 16 Aug 2022 11:26:58 GMT", + "edits": 0, + "entity_id": "e6f48cbd-26de-4c2e-a24a-29892f9eb3be", + "entity_type": "bb_series", + "full_name": "Creative Commons Attribution-ShareAlike 3.0 Unported", + "id": "998512d8-0d6b-4c76-bfb7-0ec666e3fa0a", + "info_url": "https://creativecommons.org/licenses/by-sa/3.0/", + "is_draft": false, + "is_hidden": false, + "language": "en", + "last_revision": { + "id": 11773, + "rating": 4, + "review_id": "998512d8-0d6b-4c76-bfb7-0ec666e3fa0a", + "text": null, + "timestamp": "Tue, 16 Aug 2022 11:26:58 GMT" + }, + "last_updated": "Tue, 16 Aug 2022 11:26:58 GMT", + "license_id": "CC BY-SA 3.0", + "popularity": 0, + "published_on": "Tue, 16 Aug 2022 11:26:58 GMT", + "rating": 4, + "source": null, + "source_url": null, + "text": null, + "user": { + "created": "Tue, 18 Jan 2022 09:53:49 GMT", + "display_name": "Ansh Goyal", + "id": "11a1160e-d607-4882-8a82-e2e800f664fe", + "karma": 0, + "user_type": "Noob" + }, + "votes_negative_count": 0, + "votes_positive_count": 0 + } + ] + } + + :statuscode 200: no error + :statuscode 404: series not found + + :resheader Content-Type: *application/json* + """ + + series = db_series.get_series_by_bbid(str(series_bbid)) + + if not series: + raise NotFound("Can't find a series with ID: {series_bbid}".format(series_bbid=series_bbid)) + + user_id = Parser.uuid('uri', 'user_id', optional=True) + if user_id: + user_review, _ = db_review.list_reviews( + entity_id=series['bbid'], + entity_type='bb_series', + user_id=user_id + ) + if user_review: + user_review = db_review.to_dict(user_review[0]) + else: + user_review = None + + ratings_stats, average_rating = db_rating_stats.get_stats(series_bbid, "bb_series") + + top_reviews, reviews_count = db_review.list_reviews( + entity_id=series['bbid'], + entity_type='bb_series', + sort='popularity', + limit=REVIEWS_LIMIT, + offset=0, + ) + + latest_reviews, reviews_count = db_review.list_reviews( + entity_id=series['bbid'], + entity_type='bb_series', + sort='published_on', + limit=REVIEWS_LIMIT, + offset=0, + ) + + top_reviews = [db_review.to_dict(review) for review in top_reviews] + latest_reviews = [db_review.to_dict(review) for review in latest_reviews] + + result = { + "series": series, + "average_rating": average_rating, + "ratings_stats": ratings_stats, + "reviews_count": reviews_count, + "top_reviews": top_reviews, + "latest_reviews": latest_reviews + } + if user_id: + result['user_review'] = user_review + + return jsonify(**result)