diff --git a/discovery-provider/src/api/v1/helpers.py b/discovery-provider/src/api/v1/helpers.py index 48f6fa193db..23d5ca2ad96 100644 --- a/discovery-provider/src/api/v1/helpers.py +++ b/discovery-provider/src/api/v1/helpers.py @@ -3,8 +3,8 @@ from src.utils.config import shared_config from hashids import Hashids from flask_restx import fields, reqparse -from src.queries.search_queries import SearchKind from datetime import datetime +from .models.common import full_response logger = logging.getLogger(__name__) @@ -244,6 +244,12 @@ def make_response(name, namespace, modelType): "data": modelType, }) +def make_full_response(name, namespace, modelType): + return namespace.clone(name, full_response, { + "data": modelType + }) + + def to_dict(multi_dict): """Converts a multi dict into a dict where only list entries are not flat""" return {k: v if len(v) > 1 else v[0] for (k, v) in multi_dict.to_dict(flat=False).items()} diff --git a/discovery-provider/src/api/v1/models/common.py b/discovery-provider/src/api/v1/models/common.py index 1cb2c3d10e6..d8f9b07459d 100644 --- a/discovery-provider/src/api/v1/models/common.py +++ b/discovery-provider/src/api/v1/models/common.py @@ -26,7 +26,6 @@ "latest_indexed_block": fields.Integer(required=True), "owner_wallet": fields.Integer(required=True), "signature": fields.String(required=True), - "success": fields.Boolean(required=True), "timestamp": fields.String(required=True), "version": fields.Nested(version_metadata, required=True), }) diff --git a/discovery-provider/src/api/v1/models/search.py b/discovery-provider/src/api/v1/models/search.py index 8b7be6d3ee7..a3cd6e40f2f 100644 --- a/discovery-provider/src/api/v1/models/search.py +++ b/discovery-provider/src/api/v1/models/search.py @@ -1,5 +1,3 @@ -from flask_restx.fields import Boolean -from src.api.v1.helpers import make_response from flask_restx import fields from .common import ns from .tracks import track_full diff --git a/discovery-provider/src/api/v1/models/tracks.py b/discovery-provider/src/api/v1/models/tracks.py index f6f44d70fd4..a416fc02c0b 100644 --- a/discovery-provider/src/api/v1/models/tracks.py +++ b/discovery-provider/src/api/v1/models/tracks.py @@ -1,5 +1,3 @@ -from flask_restx.fields import Boolean, Integer -from src.api.v1.helpers import make_response from flask_restx import fields from .users import user_model, user_model_full from .common import favorite, ns, repost diff --git a/discovery-provider/src/api/v1/models/users.py b/discovery-provider/src/api/v1/models/users.py index f1bd2aa7129..2c13b6ed7a9 100644 --- a/discovery-provider/src/api/v1/models/users.py +++ b/discovery-provider/src/api/v1/models/users.py @@ -1,4 +1,3 @@ -from src.api.v1.helpers import make_response from flask_restx import fields from .common import ns @@ -32,6 +31,7 @@ user_model_full = ns.clone("user_full", user_model, { "blocknumber": fields.Integer(required=True), + "wallet": fields.String(required=True), "created_at": fields.String(required=True), "creator_node_endpoint": fields.String, "current_user_followee_follow_count": fields.Integer(required=True), diff --git a/discovery-provider/src/api/v1/playlists.py b/discovery-provider/src/api/v1/playlists.py index 9b5d2c3e267..5101ac09f12 100644 --- a/discovery-provider/src/api/v1/playlists.py +++ b/discovery-provider/src/api/v1/playlists.py @@ -5,7 +5,7 @@ from src.queries.get_playlists import get_playlists from flask_restx import Resource, Namespace, fields, reqparse from src.queries.get_playlist_tracks import get_playlist_tracks -from src.api.v1.helpers import abort_not_found, decode_with_abort, extend_playlist, extend_track,\ +from src.api.v1.helpers import abort_not_found, decode_with_abort, extend_playlist, extend_track, make_full_response,\ make_response, success_response, search_parser, abort_bad_request_param, decode_string_id, \ extend_user, get_default_max, get_current_user_id from .models.tracks import track @@ -21,7 +21,7 @@ full_ns = Namespace('playlists', description='Full playlist related operations') playlists_response = make_response("playlist_response", ns, fields.List(fields.Nested(playlist_model))) -full_playlists_response = make_response("full_playlist_response", full_ns, fields.List(fields.Nested(full_playlist_model))) +full_playlists_response = make_full_response("full_playlist_response", full_ns, fields.List(fields.Nested(full_playlist_model))) def get_playlist(playlist_id, current_user_id): """Returns a single playlist, or None""" @@ -181,7 +181,7 @@ def get(self): playlist_favorites_route_parser.add_argument('user_id', required=False) playlist_favorites_route_parser.add_argument('limit', required=False, type=int) playlist_favorites_route_parser.add_argument('offset', required=False, type=int) -playlist_favorites_response = make_response("following_response", full_ns, fields.List(fields.Nested(user_model_full))) +playlist_favorites_response = make_full_response("following_response", full_ns, fields.List(fields.Nested(user_model_full))) @full_ns.route("//favorites") class FullTrackFavorites(Resource): @full_ns.expect(playlist_favorites_route_parser) @@ -221,7 +221,7 @@ def get(self, playlist_id): playlist_reposts_route_parser.add_argument('user_id', required=False) playlist_reposts_route_parser.add_argument('limit', required=False, type=int) playlist_reposts_route_parser.add_argument('offset', required=False, type=int) -playlist_reposts_response = make_response("following_response", full_ns, fields.List(fields.Nested(user_model_full))) +playlist_reposts_response = make_full_response("following_response", full_ns, fields.List(fields.Nested(user_model_full))) @full_ns.route("//reposts") class FullPlaylistReposts(Resource): @full_ns.expect(playlist_reposts_route_parser) diff --git a/discovery-provider/src/api/v1/search.py b/discovery-provider/src/api/v1/search.py index 41d3046d269..29c42f3bdf1 100644 --- a/discovery-provider/src/api/v1/search.py +++ b/discovery-provider/src/api/v1/search.py @@ -1,6 +1,6 @@ import logging # pylint: disable=C0302 from flask_restx import Resource, Namespace, fields, reqparse -from src.api.v1.helpers import extend_track, make_response, \ +from src.api.v1.helpers import extend_track, make_full_response, \ success_response, format_offset, format_limit, decode_string_id, \ extend_user, extend_track, extend_playlist, get_current_user_id from src.queries.search_queries import SearchKind, search @@ -41,7 +41,7 @@ def extend_search(resp): search_route_parser.add_argument('query', required=True, type=str) search_route_parser.add_argument('limit', required=False, type=int) search_route_parser.add_argument('offset', required=False, type=int) -search_full_response = make_response("search_full_response", full_ns, fields.Nested(search_model)) +search_full_response = make_full_response("search_full_response", full_ns, fields.Nested(search_model)) @full_ns.route("/full") class FullSearch(Resource): @full_ns.expect(search_route_parser) @@ -83,7 +83,7 @@ def get(self): return success_response(resp) -search_autocomplete_response = make_response("search_autocomplete_response", full_ns, fields.Nested(search_model)) +search_autocomplete_response = make_full_response("search_autocomplete_response", full_ns, fields.Nested(search_model)) @full_ns.route("/autocomplete") class FullSearch(Resource): @full_ns.expect(search_route_parser) diff --git a/discovery-provider/src/api/v1/tracks.py b/discovery-provider/src/api/v1/tracks.py index ffa93a97f7d..ce4f76fb7e3 100644 --- a/discovery-provider/src/api/v1/tracks.py +++ b/discovery-provider/src/api/v1/tracks.py @@ -5,7 +5,7 @@ from src.queries.get_tracks import get_tracks from src.queries.get_track_user_creator_node import get_track_user_creator_node from src.api.v1.helpers import abort_not_found, decode_with_abort, \ - extend_track, make_response, search_parser, extend_user, get_default_max, \ + extend_track, make_full_response, make_response, search_parser, extend_user, get_default_max, \ trending_parser, full_trending_parser, success_response, abort_bad_request_param, to_dict, \ format_offset, format_limit, decode_string_id, stem_from_track, \ get_current_user_id @@ -33,12 +33,12 @@ full_ns = Namespace('tracks', description='Full track operations') track_response = make_response("track_response", ns, fields.Nested(track)) -full_track_response = make_response( +full_track_response = make_full_response( "full_track_response", full_ns, fields.Nested(track_full)) tracks_response = make_response( "tracks_response", ns, fields.List(fields.Nested(track))) -full_tracks_response = make_response( +full_tracks_response = make_full_response( "full_tracks_response", full_ns, fields.List(fields.Nested(track_full)) ) @@ -303,7 +303,7 @@ def get(self): track_favorites_route_parser.add_argument('user_id', required=False) track_favorites_route_parser.add_argument('limit', required=False, type=int) track_favorites_route_parser.add_argument('offset', required=False, type=int) -track_favorites_response = make_response( +track_favorites_response = make_full_response( "following_response", full_ns, fields.List(fields.Nested(user_model_full))) @@ -348,7 +348,7 @@ def get(self, track_id): track_reposts_route_parser.add_argument('user_id', required=False) track_reposts_route_parser.add_argument('limit', required=False, type=int) track_reposts_route_parser.add_argument('offset', required=False, type=int) -track_reposts_response = make_response( +track_reposts_response = make_full_response( "following_response", full_ns, fields.List(fields.Nested(user_model_full))) @full_ns.route("//reposts") class FullTrackReposts(Resource): @@ -385,7 +385,7 @@ def get(self, track_id): users = list(map(extend_user, users)) return success_response(users) -track_stems_response = make_response( +track_stems_response = make_full_response( "stems_response", full_ns, fields.List(fields.Nested(stem_full))) @full_ns.route("//stems") @@ -399,7 +399,7 @@ def get(self, track_id): return success_response(stems) -remixes_response = make_response( +remixes_response = make_full_response( "remixes_response", full_ns, fields.Nested(remixes_response)) remixes_parser = reqparse.RequestParser() remixes_parser.add_argument('user_id', required=False) @@ -426,7 +426,7 @@ def get(self, track_id): response["tracks"] = list(map(extend_track, response["tracks"])) return success_response(response) -remixing_response = make_response( +remixing_response = make_full_response( "remixing_response", full_ns, fields.List(fields.Nested(track_full))) remixing_parser = reqparse.RequestParser() remixing_parser.add_argument('user_id', required=False) diff --git a/discovery-provider/src/api/v1/users.py b/discovery-provider/src/api/v1/users.py index 85bba9f2aef..8145fb9d1d0 100644 --- a/discovery-provider/src/api/v1/users.py +++ b/discovery-provider/src/api/v1/users.py @@ -14,7 +14,7 @@ from src.queries.get_followers_for_user import get_followers_for_user from src.api.v1.helpers import abort_not_found, decode_with_abort, extend_activity, extend_favorite, extend_track, \ - extend_user, format_limit, format_offset, get_current_user_id, make_response, search_parser, success_response, abort_bad_request_param, \ + extend_user, format_limit, format_offset, get_current_user_id, make_full_response, make_response, search_parser, success_response, abort_bad_request_param, \ get_default_max from .models.tracks import track, track_full from .models.activities import activity_model, activity_model_full @@ -28,7 +28,7 @@ full_ns = Namespace('users', description='Full user operations') user_response = make_response("user_response", ns, fields.Nested(user_model)) -full_user_response = make_response( +full_user_response = make_full_response( "full_user_response", full_ns, fields.List(fields.Nested(user_model_full))) def get_single_user(user_id, current_user_id): @@ -150,7 +150,7 @@ def get(self, user_id): tracks = list(map(extend_track, tracks)) return success_response(tracks) -full_tracks_response = make_response("full_tracks", full_ns, fields.List(fields.Nested(track_full))) +full_tracks_response = make_full_response("full_tracks", full_ns, fields.List(fields.Nested(track_full))) @full_ns.route(USER_TRACKS_ROUTE) class FullTrackList(Resource): @record_metrics @@ -244,7 +244,7 @@ def get(self, handle): user_reposts_route_parser.add_argument('limit', required=False, type=int) user_reposts_route_parser.add_argument('offset', required=False, type=int) -reposts_response = make_response("reposts", full_ns, fields.List(fields.Nested(activity_model))) +reposts_response = make_full_response("reposts", full_ns, fields.List(fields.Nested(activity_model))) @ns.route(USER_REPOSTS_ROUTE) class RepostList(Resource): @record_metrics @@ -285,7 +285,7 @@ def get(self, user_id): return success_response(activities) -full_reposts_response = make_response("full_reposts", full_ns, fields.List(fields.Nested(activity_model_full))) +full_reposts_response = make_full_response("full_reposts", full_ns, fields.List(fields.Nested(activity_model_full))) @full_ns.route(USER_REPOSTS_ROUTE) class FullRepostList(Resource): @record_metrics @@ -397,7 +397,7 @@ def get(self, user_id): favorite_route_parser.add_argument('user_id', required=False, type=str) favorite_route_parser.add_argument('limit', required=False, type=int) favorite_route_parser.add_argument('offset', required=False, type=int) -favorites_response = make_response("favorites_response", ns, fields.List(fields.Nested(activity_model_full))) +favorites_response = make_full_response("favorites_response", full_ns, fields.List(fields.Nested(activity_model_full))) @full_ns.route("//favorites/tracks") class FavoritedTracks(Resource): @record_metrics @@ -475,7 +475,7 @@ def get(self): followers_route_parser.add_argument('limit', required=False, type=int) followers_route_parser.add_argument('offset', required=False, type=int) -followers_response = make_response("followers_response", full_ns, fields.List(fields.Nested(user_model_full))) +followers_response = make_full_response("followers_response", full_ns, fields.List(fields.Nested(user_model_full))) @full_ns.route("//followers") class FollowerUsers(Resource): @record_metrics @@ -516,7 +516,7 @@ def get(self, user_id): following_route_parser.add_argument('user_id', required=False) following_route_parser.add_argument('limit', required=False, type=int) following_route_parser.add_argument('offset', required=False, type=int) -following_response = make_response("following_response", full_ns, fields.List(fields.Nested(user_model_full))) +following_response = make_full_response("following_response", full_ns, fields.List(fields.Nested(user_model_full))) @full_ns.route("//following") class FollowingUsers(Resource): @record_metrics @@ -556,7 +556,7 @@ def get(self, user_id): top_genre_users_route_parser.add_argument('genre', required=False, action='append') top_genre_users_route_parser.add_argument('limit', required=False, type=int) top_genre_users_route_parser.add_argument('offset', required=False, type=int) -top_genre_users_response = make_response("top_genre_users_response", full_ns, fields.List(fields.Nested(user_model_full))) +top_genre_users_response = make_full_response("top_genre_users_response", full_ns, fields.List(fields.Nested(user_model_full))) @full_ns.route("/genre/top") class FullTopGenreUsers(Resource): @full_ns.expect(top_genre_users_route_parser) diff --git a/discovery-provider/src/api_helpers.py b/discovery-provider/src/api_helpers.py index f53f53e0dce..67357447575 100644 --- a/discovery-provider/src/api_helpers.py +++ b/discovery-provider/src/api_helpers.py @@ -32,21 +32,21 @@ def error_response(error, error_code=500): # Create a response dict with just data, signature, and timestamp # This response will contain a duplicate of response_entity -def success_response_backwards_compat(response_entity=None, status=200): +def success_response_backwards_compat(response_entity=None, status=200, sign_response=True): starting_response_dictionary = {'data': response_entity, **response_entity} - response_dictionary = response_dict_with_metadata(starting_response_dictionary) + response_dictionary = response_dict_with_metadata(starting_response_dictionary, sign_response) return jsonify(response_dictionary), status # Create a response dict with metadata, data, signature, and timestamp -def success_response(response_entity=None, status=200, to_json=True): +def success_response(response_entity=None, status=200, to_json=True, sign_response=True): starting_response_dictionary = {'data': response_entity} - response_dictionary = response_dict_with_metadata(starting_response_dictionary) + response_dictionary = response_dict_with_metadata(starting_response_dictionary, sign_response) response = jsonify(response_dictionary) if to_json else response_dictionary return response, status # Create a response dict with metadata fields of success, latest_indexed_block, latest_chain_block, # version, and owner_wallet -def response_dict_with_metadata(response_dictionary): +def response_dict_with_metadata(response_dictionary, sign_response): response_dictionary['success'] = True latest_indexed_block = redis.get(most_recent_indexed_block_redis_key) @@ -57,12 +57,13 @@ def response_dict_with_metadata(response_dictionary): response_dictionary['version'] = disc_prov_version response_dictionary['signer'] = shared_config['delegate']['owner_wallet'] - # generate timestamp with format HH:MM:SS.sssZ - timestamp = datetime.datetime.now().isoformat(timespec='milliseconds') + 'Z' - response_dictionary['timestamp'] = timestamp + if sign_response: + # generate timestamp with format HH:MM:SS.sssZ + timestamp = datetime.datetime.now().isoformat(timespec='milliseconds') + 'Z' + response_dictionary['timestamp'] = timestamp - signature = generate_signature(response_dictionary) - response_dictionary['signature'] = signature + signature = generate_signature(response_dictionary) + response_dictionary['signature'] = signature return response_dictionary diff --git a/discovery-provider/src/queries/health_check.py b/discovery-provider/src/queries/health_check.py index 13dba4dfc5f..01b198c6b48 100644 --- a/discovery-provider/src/queries/health_check.py +++ b/discovery-provider/src/queries/health_check.py @@ -16,7 +16,10 @@ @bp.route("/version", methods=["GET"]) def version(): - return success_response_backwards_compat(disc_prov_version) + return success_response_backwards_compat( + disc_prov_version, + sign_response=False + ) # Health check for server, db, and redis. Consumes latest block data from redis instead of chain. # Optional boolean "verbose" flag to output db connection info. @@ -34,7 +37,8 @@ def health_check(): (health_results, error) = get_health(args) return success_response_backwards_compat( health_results, - 500 if error else 200 + 500 if error else 200, + sign_response=False ) @@ -50,7 +54,8 @@ def block_check(): (health_results, error) = get_health(args, use_redis_cache=False) return success_response_backwards_compat( health_results, - 500 if error else 200 + 500 if error else 200, + sign_response=False ) # Health check for latest play stored in the db @@ -68,4 +73,8 @@ def play_check(): # Error if max drift was provided and the drift is greater than max_drift error = max_drift and drift > max_drift - return success_response(latest_play, 500 if error else 200) + return success_response( + latest_play, + 500 if error else 200, + sign_response=False + )