Beispiel #1
0
def search(isAutocomplete):
    searchStr = request.args.get("query", type=str)
    if not searchStr:
        return api_helpers.error_response("Invalid value for parameter 'query'")
    searchStr = searchStr.replace('&', 'and')  # when creating query table, we substitute this too

    kind = request.args.get("kind", type=str, default="all")
    if kind not in SearchKind.__members__:
        return api_helpers.error_response(
            "Invalid value for parameter 'kind' must be in %s" % [k.name for k in SearchKind]
        )
    searchKind = SearchKind[kind]

    (limit, offset) = get_pagination_vars()

    results = {}
    if searchStr:
        db = get_db_read_replica()
        with db.scoped_session() as session:
            # Set similarity threshold to be used by % operator in queries.
            session.execute(sqlalchemy.text(f"select set_limit({minSearchSimilarity});"))

            if (searchKind in [SearchKind.all, SearchKind.tracks]):
                results['tracks'] = track_search_query(session, searchStr, limit, offset, False, isAutocomplete)
                results['saved_tracks'] = track_search_query(session, searchStr, limit, offset, True, isAutocomplete)
            if (searchKind in [SearchKind.all, SearchKind.users]):
                results['users'] = user_search_query(session, searchStr, limit, offset, False, isAutocomplete)
                results['followed_users'] = user_search_query(session, searchStr, limit, offset, True, isAutocomplete)
            if (searchKind in [SearchKind.all, SearchKind.playlists]):
                results['playlists'] = playlist_search_query(
                    session,
                    searchStr,
                    limit,
                    offset,
                    False,
                    False,
                    isAutocomplete
                )
                results['saved_playlists'] = playlist_search_query(
                    session,
                    searchStr,
                    limit,
                    offset,
                    False,
                    True,
                    isAutocomplete
                )
            if (searchKind in [SearchKind.all, SearchKind.albums]):
                results['albums'] = playlist_search_query(session, searchStr, limit, offset, True, False, isAutocomplete)
                results['saved_albums'] = playlist_search_query(
                    session,
                    searchStr,
                    limit,
                    offset,
                    True,
                    True,
                    isAutocomplete
                )

    return api_helpers.success_response(results)
Beispiel #2
0
def milestones_followers():
    db = get_db_read_replica()
    if "user_id" not in request.args:
        return api_helpers.error_response({'msg': 'Please provider user ids'},
                                          500)

    try:
        user_id_str_list = request.args.getlist("user_id")
        user_ids = []
        user_ids = [int(y) for y in user_id_str_list]
    except ValueError as e:
        logger.error("Invalid value found in user id list", esc_info=True)
        return api_helpers.error_response({'msg': e}, 500)

    with db.scoped_session() as session:
        follower_counts = (session.query(
            Follow.followee_user_id,
            func.count(Follow.followee_user_id)).filter(
                Follow.is_current == True, Follow.is_delete == False,
                Follow.followee_user_id.in_(user_ids)).group_by(
                    Follow.followee_user_id).all())
        follower_count_dict = \
            {user_id: follower_count for (
                user_id, follower_count) in follower_counts}

    return api_helpers.success_response(follower_count_dict)
Beispiel #3
0
def user_signals():
    handle = request.args.get("handle")
    if not handle:
        return error_response("Please pass in a handle")
    try:
        response = get_user_signals(handle)
        return success_response(response)
    except Exception as e:
        return error_response(f"Request failed: {e}")
Beispiel #4
0
def validate_search_args(args):
    searchStr = args.get("query")
    if not searchStr:
        return api_helpers.error_response(
            "Invalid value for parameter 'query'", 400)

    kind = args.get("kind", "all")
    if kind not in SearchKind.__members__:
        return api_helpers.error_response(
            "Invalid value for parameter 'kind' must be in %s" %
            [k.name for k in SearchKind], 400)
    return None
Beispiel #5
0
def get_playlist_repost_intersection_users(repost_playlist_id,
                                           follower_user_id):
    users = []
    db = get_db()
    with db.scoped_session() as session:
        # ensure playlist_id exists
        playlist_entry = session.query(Playlist).filter(
            Playlist.playlist_id == repost_playlist_id,
            Playlist.is_current == True).first()
        if playlist_entry is None:
            return api_helpers.error_response(
                'Resource not found for provided playlist id', 404)

        query = (session.query(User).filter(
            User.is_current == True, User.is_ready == True,
            User.user_id.in_(
                session.query(Repost.user_id).filter(
                    Repost.repost_item_id == repost_playlist_id,
                    Repost.repost_type != RepostType.track,
                    Repost.is_current == True,
                    Repost.is_delete == False).intersect(
                        session.query(Follow.followee_user_id).filter(
                            Follow.follower_user_id == follower_user_id,
                            Follow.is_current == True,
                            Follow.is_delete == False)))))
        users = paginate_query(query).all()
        users = helpers.query_result_to_list(users)

    return api_helpers.success_response(users)
def get_top_followee_windowed_route(type, window):
    """
        Gets a windowed (over a certain timerange) view into the "top" of a certain type
        amongst followees. Requires an account.
        This endpoint is useful in generating views like:
            - New releases

        Args:
            type: (string) The `type` (same as repost/save type) to query from. Currently only
                track is supported.
            window: (string) The window from now() to look back over. Supports all standard
                SqlAlchemy interval notation (week, month, year, etc.).
            limit?: (number) default=25, max=100
    """
    args = to_dict(request.args)
    if 'limit' in request.args:
        args['limit'] = min(request.args.get('limit', type=int), 100)
    else:
        args['limit'] = 25
    if "with_users" in request.args:
        args["with_users"] = parse_bool_param(request.args.get("with_users"))

    try:
        tracks = get_top_followee_windowed(type, window, args)
        return api_helpers.success_response(tracks)
    except exceptions.ArgumentError as e:
        return api_helpers.error_response(str(e), 400)
def get_saves_route(save_type):
    try:
        user_id = get_current_user_id()
        save_results = get_saves(save_type, user_id)
        return api_helpers.success_response(save_results)
    except exceptions.ArgumentError as e:
        return api_helpers.error_response(str(e), 400)
Beispiel #8
0
def get_top_followee_saves_route(type):
    """
    Gets a global view into the most saved of `type` amongst followees. Requires an account.
    This endpoint is useful in generating views like:
        - Most favorited

    Args:
        type: (string) The `type` (same as repost/save type) to query from. Currently only
            track is supported.
        limit?: (number) default=25, max=100
    """
    args = to_dict(request.args)
    if "limit" in request.args:
        args["limit"] = min(request.args.get("limit", type=int), 100)
    else:
        args["limit"] = 25
    if "with_users" in request.args:
        args["with_users"] = parse_bool_param(request.args.get("with_users"))
    user_id = get_current_user_id()
    args["user_id"] = user_id
    try:
        tracks = get_top_followee_saves(type, args)
        return api_helpers.success_response(tracks)
    except exceptions.ArgumentError as e:
        return api_helpers.error_response(str(e), 400)
def get_top_playlists_route(type):
    """
    An endpoint to retrieve the "top" of a certain demographic of playlists or albums.
    This endpoint is useful in generating views like:
        - Top playlists
        - Top Albums
        - Top playlists of a certain mood
        - Top playlists of a certain mood from people you follow

    Args:
        type: (string) The `type` (same as repost/save type) to query from.
        limit?: (number) default=16, max=100
        mood?: (string) default=None
        filter?: (string) Optional filter to include (supports 'followees') default=None
    """
    args = to_dict(request.args)
    if 'limit' in request.args:
        args['limit'] = min(request.args.get('limit', type=int), 100)
    else:
        args['limit'] = 16

    if 'mood' in request.args:
        args['mood'] = request.args.get('mood')
    else:
        args['mood'] = None
    if "with_users" in request.args:
        args["with_users"] = parse_bool_param(request.args.get("with_users"))
    try:
        playlists = get_top_playlists(type, args)
        return api_helpers.success_response(playlists)
    except exceptions.ArgumentError as e:
        return api_helpers.error_response(str(e), 400)
Beispiel #10
0
def get_track_listen_milestone_data():
    try:
        # Assign value only if not None or empty string
        data = get_track_listen_milestones(100)
        return api_helpers.success_response(data)
    except exceptions.ArgumentError as e:
        return api_helpers.error_response(str(e), 400)
def get_playlist_repost_intersection_users_route(repost_playlist_id, follower_user_id):
    try:
        users = get_playlist_repost_intersection_users(
            repost_playlist_id, follower_user_id)
        return api_helpers.success_response(users)
    except exceptions.NotFoundError as e:
        return api_helpers.error_response(str(e), 404)
Beispiel #12
0
def get_ursm_content_nodes():
    try:
        # Assign value only if not None or empty string
        owner_wallet = request.args.get("owner_wallet") or None
        cnodes = get_ursm_cnodes(owner_wallet)
        return api_helpers.success_response(cnodes)
    except exceptions.ArgumentError as e:
        return api_helpers.error_response(str(e), 400)
Beispiel #13
0
def get_sol_play_tx():
    try:
        # Assign value only if not None or empty string
        tx_sig = request.args.get("tx_sig") or None
        sig = get_sol_play(tx_sig)
        return api_helpers.success_response(sig)
    except exceptions.ArgumentError as e:
        return api_helpers.error_response(str(e), 400)
def get_creator_node_users():
    try:
        if "creator_node_endpoint" not in request.args:
            raise exceptions.ArgumentError("Missing creator_node_endpoint")
        cnode_url = request.args.get("creator_node_endpoint")
        users = get_users_cnode(cnode_url)
        return api_helpers.success_response(users)
    except exceptions.ArgumentError as e:
        return api_helpers.error_response(str(e), 400)
Beispiel #15
0
def get_remixes_of_route(track_id):
    args = to_dict(request.args)
    if "with_users" in request.args:
        args["with_users"] = parse_bool_param(request.args.get("with_users"))
    try:
        remixes = get_remixes_of(track_id, args)
        return api_helpers.success_response(remixes)
    except exceptions.ArgumentError as e:
        return api_helpers.error_response(str(e), 400)
def check_transaction_status():
    """
    Returns whether a transaction 'PASSED' | 'FAILED' | 'NOT_FOUND'
    based on all 3 query params 'blocknumber', 'blockhash', and 'transactionhash'
    """
    blocknumber = request.args.get("blocknumber", type=int)
    blockhash = request.args.get("blockhash")
    transactionhash = request.args.get("transactionhash")
    if blocknumber is None or blockhash is None or transactionhash is None:
        return error_response(
            "Please pass in required query parameters 'blocknumber', 'blockhash', and 'transactionhash'",
            400,
        )
    try:
        transaction_status = get_transaction_status(
            blocknumber, blockhash, transactionhash
        )
    except Exception as e:
        return error_response(e)
    return success_response(transaction_status)
Beispiel #17
0
def get_user_history_route(user_id):
    try:
        (limit, offset) = get_pagination_vars()
        args = {
            "user_id": user_id,
            "limit": limit,
            "offset": offset,
        }
        user_history = get_user_history(args)
        return api_helpers.success_response(user_history)
    except exceptions.ArgumentError as e:
        return api_helpers.error_response(str(e), 400)
Beispiel #18
0
def milestones_followers():
    db = get_db_read_replica()
    if "user_id" not in request.args:
        return api_helpers.error_response({"msg": "Please provider user ids"}, 500)

    try:
        user_id_str_list = request.args.getlist("user_id")
        user_ids = []
        user_ids = [int(y) for y in user_id_str_list]
    except ValueError as e:
        logger.error("Invalid value found in user id list", esc_info=True)
        return api_helpers.error_response({"msg": e}, 500)

    with db.scoped_session() as session:
        follower_counts = (
            session.query(AggregateUser.user_id, AggregateUser.follower_count)
            .filter(AggregateUser.user_id.in_(user_ids))
            .all()
        )
        follower_count_dict = dict(follower_counts)

    return api_helpers.success_response(follower_count_dict)
def block_confirmation():
    blockhash = request.args.get("blockhash")
    blocknumber = request.args.get("blocknumber", type=int)
    response = {"block_found": False, "block_passed": False}
    bad_request = True
    if blockhash is not None and blocknumber is not None:
        bad_request = False
        logger.info(f"block_confirmation | ARGS: {blockhash, blocknumber}")
        try:
            response = get_block_confirmation(blockhash, blocknumber)
        except Exception as e:
            return error_response(e)
    return success_response(response, 400 if bad_request else 200)
def get_savers_for_playlist_route(save_playlist_id):
    try:
        current_user_id = get_current_user_id(required=False)
        (limit, offset) = get_pagination_vars()
        args = {
            'save_playlist_id': save_playlist_id,
            'current_user_id': current_user_id,
            'limit': limit,
            'offset': offset
        }
        user_results = get_savers_for_playlist(args)
        return api_helpers.success_response(user_results)
    except exceptions.NotFoundError as e:
        return api_helpers.error_response(str(e), 404)
Beispiel #21
0
def get_savers_for_track_route(save_track_id):
    try:
        current_user_id = get_current_user_id(required=False)
        (limit, offset) = get_pagination_vars()
        args = {
            "save_track_id": save_track_id,
            "current_user_id": current_user_id,
            "limit": limit,
            "offset": offset,
        }
        user_results = get_savers_for_track(args)
        return api_helpers.success_response(user_results)
    except exceptions.NotFoundError as e:
        return api_helpers.error_response(str(e), 404)
def get_remixes_of_route(track_id):
    args = to_dict(request.args)
    args["track_id"] = track_id
    args["current_user_id"] = get_current_user_id(required=False)
    limit, offset = get_pagination_vars()
    args["limit"] = limit
    args["offset"] = offset
    if "with_users" in request.args:
        args["with_users"] = parse_bool_param(request.args.get("with_users"))
    try:
        remixes = get_remixes_of(args)
        return api_helpers.success_response(remixes)
    except exceptions.ArgumentError as e:
        return api_helpers.error_response(str(e), 400)
Beispiel #23
0
 def get(self, app_name):
     """Get the app name metrics"""
     args = metrics_app_name_parser.parse_args()
     if args.get('limit') is None:
         args['limit'] = 48
     else:
         args['limit'] = min(args.get('limit'), 48)
     try:
         args['start_time'] = datetime.utcfromtimestamp(args['start_time'])
     except:
         return api_helpers.error_response(
             'Poorly formated start_time parameter', 400)
     app_name_metrics = get_app_name_metrics(app_name, args)
     response = success_response(app_name_metrics)
     return response
Beispiel #24
0
def get_reposters_for_track(repost_track_id):
    user_results = []
    db = get_db()
    with db.scoped_session() as session:
        # ensure track_id exists
        track_entry = session.query(Track).filter(
            Track.track_id == repost_track_id,
            Track.is_current == True
        ).first()
        if track_entry is None:
            return api_helpers.error_response('Resource not found for provided track id', 404)

        follower_count_subquery = (
            session.query(
                Follow.followee_user_id,
                func.count(Follow.followee_user_id).label(response_name_constants.follower_count)
            )
            .filter(
                Follow.is_current == True,
                Follow.is_delete == False
            )
            .group_by(Follow.followee_user_id)
            .order_by(response_name_constants.follower_count + " desc")
        )
        follower_count_subquery = paginate_query(follower_count_subquery).subquery()

        query = (
            session.query(User, follower_count_subquery.c.follower_count)
            .join(Repost, User.user_id == Repost.user_id)
            .outerjoin(follower_count_subquery, follower_count_subquery.c.followee_user_id == User.user_id)
            .filter(
                User.is_current == True,
                User.is_ready == True,
                Repost.repost_item_id == repost_track_id,
                Repost.repost_type == RepostType.track,
                Repost.is_current == True,
                Repost.is_delete == False
            )
        )
        user_results = query.all()

        if user_results:
            users, follower_counts = zip(*user_results)
            user_results = helpers.query_result_to_list(users)
            for i, user in enumerate(user_results):
                user[response_name_constants.follower_count] = follower_counts[i] or 0

    return api_helpers.success_response(user_results)
def search_tags():
    search_str = request.args.get("query", type=str)
    current_user_id = get_current_user_id(required=False)
    if not search_str:
        raise exceptions.ArgumentError("Invalid value for parameter 'query'")

    user_tag_count = request.args.get("user_tag_count", type=str)
    if not user_tag_count:
        user_tag_count = "2"

    kind = request.args.get("kind", type=str, default="all")
    validSearchKinds = [SearchKind.all, SearchKind.tracks, SearchKind.users]
    try:
        searchKind = SearchKind[kind]
        if searchKind not in validSearchKinds:
            raise Exception
    except Exception:
        return api_helpers.error_response(
            "Invalid value for parameter 'kind' must be in %s" %
            [k.name for k in validSearchKinds], 400)

    results = {}

    (limit, offset) = get_pagination_vars()
    like_tags_str = str.format('%{}%', search_str)
    db = get_db_read_replica()
    with db.scoped_session() as session:
        if (searchKind in [SearchKind.all, SearchKind.tracks]):
            track_res = sqlalchemy.text(f"""
                select distinct(track_id)
                from
                (
                    select
                        strip(to_tsvector(tracks.tags)) as tagstrip,
                        track_id
                    from
                        tracks
                    where
                        (tags like :like_tags_query)
                        and (is_current is true)
                        and (is_delete is false)
                        and (is_unlisted is false)
                        and (stem_of is NULL)
                    order by
                        updated_at desc
                ) as t
                    where
                    tagstrip @@ to_tsquery(:query);
                """)
            track_ids = session.execute(track_res, {
                "query": search_str,
                "like_tags_query": like_tags_str
            }).fetchall()

            # track_ids is list of tuples - simplify to 1-D list
            track_ids = [i[0] for i in track_ids]

            tracks = (session.query(Track).filter(
                Track.is_current == True,
                Track.is_delete == False,
                Track.is_unlisted == False,
                Track.stem_of == None,
                Track.track_id.in_(track_ids),
            ).all())

            tracks = helpers.query_result_to_list(tracks)
            track_play_counts = get_track_play_counts(track_ids)

            tracks = populate_track_metadata(session, track_ids, tracks,
                                             current_user_id)

            for track in tracks:
                track_id = track["track_id"]
                track[response_name_constants.
                      play_count] = track_play_counts.get(track_id, 0)

            play_count_sorted_tracks = \
                sorted(
                    tracks, key=lambda i: i[response_name_constants.play_count], reverse=True)

            # Add pagination parameters to track and user results
            play_count_sorted_tracks = \
                play_count_sorted_tracks[slice(offset, offset + limit, 1)]

            results['tracks'] = play_count_sorted_tracks

        if (searchKind in [SearchKind.all, SearchKind.users]):
            user_res = sqlalchemy.text(f"""
                select * from
                (
                    select
                        count(track_id),
                        owner_id
                    from
                    (
                        select
                            strip(to_tsvector(tracks.tags)) as tagstrip,
                            track_id,
                            owner_id
                        from
                            tracks
                        where
                            (tags like :like_tags_query)
                            and (is_current is true)
                            and (is_unlisted is false)
                            and (stem_of is NULL)
                        order by
                            updated_at desc
                    ) as t
                    where
                            tagstrip @@ to_tsquery(:query)
                    group by
                            owner_id
                    order by
                            count desc
                ) as usr
                where
                    usr.count >= :user_tag_count;
                """)
            user_ids = session.execute(
                user_res, {
                    "query": search_str,
                    "like_tags_query": like_tags_str,
                    "user_tag_count": user_tag_count
                }).fetchall()

            # user_ids is list of tuples - simplify to 1-D list
            user_ids = [i[1] for i in user_ids]

            users = (session.query(User).filter(
                User.is_current == True, User.user_id.in_(user_ids)).all())
            users = helpers.query_result_to_list(users)

            users = populate_user_metadata(session, user_ids, users,
                                           current_user_id)

            followee_sorted_users = \
                sorted(
                    users, key=lambda i: i[response_name_constants.follower_count], reverse=True)

            followee_sorted_users = \
                followee_sorted_users[slice(offset, offset + limit, 1)]

            results['users'] = followee_sorted_users

    # Add personalized results for a given user
    if current_user_id:
        if (searchKind in [SearchKind.all, SearchKind.tracks]):
            # Query saved tracks for the current user that contain this tag
            saves_query = (session.query(Save.save_item_id).filter(
                Save.is_current == True, Save.is_delete == False,
                Save.save_type == SaveType.track,
                Save.user_id == current_user_id,
                Save.save_item_id.in_(track_ids)).all())
            saved_track_ids = [i[0] for i in saves_query]
            saved_tracks = (session.query(Track).filter(
                Track.is_current == True,
                Track.is_delete == False,
                Track.is_unlisted == False,
                Track.stem_of == None,
                Track.track_id.in_(saved_track_ids),
            ).all())
            saved_tracks = helpers.query_result_to_list(saved_tracks)
            for saved_track in saved_tracks:
                saved_track_id = saved_track["track_id"]
                saved_track[response_name_constants.play_count] = \
                    track_play_counts.get(saved_track_id, 0)
            saved_tracks = \
                populate_track_metadata(
                    session, saved_track_ids, saved_tracks, current_user_id)

            # Sort and paginate
            play_count_sorted_saved_tracks = \
                sorted(
                    saved_tracks, key=lambda i: i[response_name_constants.play_count], reverse=True)

            play_count_sorted_saved_tracks = \
                play_count_sorted_saved_tracks[slice(
                    offset, offset + limit, 1)]

            results['saved_tracks'] = play_count_sorted_saved_tracks

        if (searchKind in [SearchKind.all, SearchKind.users]):
            # Query followed users that have referenced this tag
            followed_user_query = (session.query(
                Follow.followee_user_id).filter(
                    Follow.is_current == True, Follow.is_delete == False,
                    Follow.follower_user_id == current_user_id,
                    Follow.followee_user_id.in_(user_ids)).all())
            followed_user_ids = [i[0] for i in followed_user_query]
            followed_users = (session.query(User).filter(
                User.is_current == True,
                User.user_id.in_(followed_user_ids)).all())
            followed_users = helpers.query_result_to_list(followed_users)
            followed_users = \
                populate_user_metadata(
                    session,
                    followed_user_ids,
                    followed_users,
                    current_user_id
                )

            followed_users_followee_sorted = \
                sorted(
                    followed_users,
                    key=lambda i: i[response_name_constants.follower_count],
                    reverse=True)

            followed_users_followee_sorted = \
                followed_users_followee_sorted[slice(
                    offset, offset + limit, 1)]

            results['followed_users'] = followed_users_followee_sorted

    return api_helpers.success_response(results)
def get_previously_private_playlists_route():
    try:
        playlists = get_previously_private_playlists(to_dict(request.args))
        return api_helpers.success_response(playlists)
    except exceptions.ArgumentError as e:
        return api_helpers.error_response(str(e), 400)
def get_previously_unlisted_tracks_route():
    try:
        tracks = get_previously_unlisted_tracks(to_dict(request.args))
        return api_helpers.success_response(tracks)
    except exceptions.ArgumentError as e:
        return api_helpers.error_response(str(e), 400)
Beispiel #28
0
 def handle_404(_error):  # pylint: disable=W0612
     return api_helpers.error_response(["Route does not exist"], 404)
def get_users_account_route():
    try:
        user = get_users_account(to_dict(request.args))
        return api_helpers.success_response(user)
    except exceptions.ArgumentError as e:
        return api_helpers.error_response(str(e), 400)
def get_max_id_route(type):
    try:
        latest = get_max_id(type)
        return api_helpers.success_response(latest)
    except exceptions.ArgumentError as e:
        return api_helpers.error_response(str(e), 400)