def setUp(self):
        super(CFRecommendationsViewsTestCase, self).setUp()

        self.user = db_user.get_or_create(1, 'vansika_1')
        self.user2 = db_user.get_or_create(2, 'vansika_2')
        self.user3 = db_user.get_or_create(3, 'vansika_3')

        # generate test data
        data = {"recording_mbid": []}

        for score in range(1500, 0, -1):
            data["recording_mbid"].append({
                "recording_mbid": str(uuid.uuid4()),
                "score": score
            })

        db_recommendations_cf_recording.insert_user_recommendation(
            1,
            UserRecommendationsJson(**{
                'top_artist': data['recording_mbid'],
                'similar_artist': []
            }))

        db_recommendations_cf_recording.insert_user_recommendation(
            2,
            UserRecommendationsJson(**{
                'top_artist': [],
                'similar_artist': data['recording_mbid']
            }))

        # get recommendations
        self.user_recommendations = db_recommendations_cf_recording.get_user_recommendation(
            1)
        self.user2_recommendations = db_recommendations_cf_recording.get_user_recommendation(
            2)
    def setUp(self):
        super(CFRecommendationsViewsTestCase, self).setUp()

        self.user = db_user.get_or_create(1, 'vansika_1')
        self.user2 = db_user.get_or_create(2, 'vansika_2')
        self.user3 = db_user.get_or_create(3, 'vansika_3')
        # insert recommendations
        with open(self.path_to_data_file('cf_recommendations_db_data_for_api_test_recording.json'), 'r') as f:
            self.payload = json.load(f)

        db_recommendations_cf_recording.insert_user_recommendation(
            1,
            UserRecommendationsJson(**{
                'top_artist': self.payload['recording_mbid'],
                'similar_artist': []
            })
        )

        db_recommendations_cf_recording.insert_user_recommendation(
            2,
            UserRecommendationsJson(**{
                'top_artist': [],
                'similar_artist': self.payload['recording_mbid']
            })
        )

        # get recommendations
        self.user_recommendations = db_recommendations_cf_recording.get_user_recommendation(1)
        self.user2_recommendations = db_recommendations_cf_recording.get_user_recommendation(2)
    def test_insert_user_recommendation(self):
        top_artist_recording_mbids = [{
            'recording_mbid': 'a36d6fc9-49d0-4789-a7dd-a2b72369ca45',
            'score': 2.3
        }, {
            'recording_mbid': 'b36d6fc9-49d0-4789-a7dd-a2b72369ca45',
            'score': 3.0
        }]

        similar_artist_recording_mbids = [{
            'recording_mbid': 'c36d6fc9-49d0-4789-a7dd-a2b72369ca45',
            'score': 1.9
        }, {
            'recording_mbid': 'd36d6fc9-49d0-4789-a7dd-a2b72369ca45',
            'score': 7.6
        }]

        db_recommendations_cf_recording.insert_user_recommendation(
            self.user['id'],
            UserRecommendationsJson(
                **{
                    'top_artist': top_artist_recording_mbids,
                    'similar_artist': similar_artist_recording_mbids
                }))

        result = db_recommendations_cf_recording.get_user_recommendation(
            self.user['id'])
        self.assertEqual(
            getattr(result, 'recording_mbid').dict()['top_artist'],
            top_artist_recording_mbids)
        self.assertEqual(
            getattr(result, 'recording_mbid').dict()['similar_artist'],
            similar_artist_recording_mbids)
        self.assertGreater(int(getattr(result, 'created').strftime('%s')), 0)
    def test_get_user_recommendation(self):
        data_inserted = self.insert_test_data()

        data_received = db_recommendations_cf_recording.get_user_recommendation(
            self.user['id'])
        self.assertEqual(
            getattr(data_received, 'recording_mbid').dict()['top_artist'],
            data_inserted['top_artist_recording_mbids'])
        self.assertEqual(
            getattr(data_received, 'recording_mbid').dict()['similar_artist'],
            data_inserted['similar_artist_recording_mbids'])
def _get_template(active_section, user):
    """ Get template to render based on active section.

        Args:
            active_section (str): Type of recommendation playlist to render i.e top_artist, similar_artist
            user: Database user object.

        Returns:
            Template to render.
    """

    data = db_recommendations_cf_recording.get_user_recommendation(user.id)

    if data is None:
        current_app.logger.error('Inactive user: "******"'.format(user.musicbrainz_id))
        return render_template(
            "recommendations_cf_recording/{}.html".format(active_section),
            active_section=active_section,
            user=user,
            error_msg="Looks like the user wasn't active in the last week. Submit your listens and check back after a week!"
        )

    result = getattr(data, 'recording_mbid').dict()[active_section]

    if not result:
        current_app.logger.error('Top/Similar artists not found in Mapping/artist relation for "{}"'.format(user.musicbrainz_id))
        return render_template(
            "recommendations_cf_recording/{}.html".format(active_section),
            active_section=active_section,
            user=user,
            error_msg="Looks like the recommendations weren't generated because of anomalies in our data." \
                      "We are working on it. Check back later."
        )

    listens = _get_listens_from_recording_mbid(result)
    if not listens:
        current_app.logger.error('The API returned an empty response for {} recommendations.\nData: {}'
                                 .format(active_section, result))
        return render_template(
            "recommendations_cf_recording/{}.html".format(active_section),
            active_section=active_section,
            user=user,
            error_msg="An error occurred while processing your request. Check back later!"
        )

    spotify_data = {}
    current_user_data = {}

    if current_user.is_authenticated:
        spotify_data = spotify.get_user_dict(current_user.id)

        current_user_data = {
                "id": current_user.id,
                "name": current_user.musicbrainz_id,
                "auth_token": current_user.auth_token,
        }

    props = {
        "user": {
            "id": user.id,
            "name": user.musicbrainz_id,
        },
        "current_user": current_user_data,
        "spotify": spotify_data,
        "api_url": current_app.config["API_URL"],
        "web_sockets_server_url": current_app.config['WEBSOCKETS_SERVER_URL'],
        "listens": listens,
        "mode": "cf_recs"
    }

    return render_template(
        "recommendations_cf_recording/{}.html".format(active_section),
        active_section=active_section,
        props=ujson.dumps(props),
        user=user,
        last_updated=getattr(data, 'created').strftime('%d %b %Y')
    )
def get_recommendations(user_name):
    """ Get recommendations sorted on rating and ratings for user ``user_name``.

        A sample response from the endpoint may look like:

        .. code-block:: json

            {
                "payload": {
                    "last_updated": 1588494361,
                    "type": "<artist_type>",
                    "entity": "recording",
                    "mbids": [
                        {
                            "recording_mbid": "526bd613-fddd-4bd6-9137-ab709ac74cab",
                            "score": 9.345
                        },
                        {
                            "recording_mbid": "a6081bc1-2a76-4984-b21f-38bc3dcca3a5",
                            "score": 6.998
                        }
                    ],
                    "user_name": "unclejohn69",
                    "count": 10,
                    "total_mbid_count": 30,
                    "offset": 10
                }
            }


        .. note::
            - This endpoint is experimental and probably will change in the future.
            - <artist_type>: 'top' or 'similar'

        :param artist_type: Mandatory, artist type in ['top', 'similar']

            Ex. artist_type = top will fetch recommended recording mbids that belong to top artists listened to by the user.

            artist_type = similar will fetch recommended recording mbids that belong to artists similar to top artists listened to by the user.
        :type artist_type: ``str``

        :param count: Optional, number of recording mbids to return, Default: :data:`~webserver.views.api.DEFAULT_ITEMS_PER_GET`
            Max: :data:`~webserver.views.api.MAX_ITEMS_PER_GET`
        :type count: ``int``

        :param offset: Optional, number of mbids to skip from the beginning, for pagination.
            Ex. An offset of 5 means the 5 mbids will be skipped, defaults to 0
        :type offset: ``int``

        :statuscode 200: Successful query, you have data!
        :statuscode 400: Bad request, check ``response['error']`` for more details
        :statuscode 404: User not found.
        :statuscode 204: Recommendations for the user haven't been generated, empty response will be returned
    """
    user = db_user.get_by_mb_id(user_name)
    if user is None:
        raise APINotFound("Cannot find user: {}".format(user_name))

    artist_type = request.args.get('artist_type')
    if not _is_valid_artist_type(artist_type):
        raise APIBadRequest("Invalid artist type: {}".format(artist_type))

    offset = get_non_negative_param('offset', default=0)
    count = get_non_negative_param('count', default=DEFAULT_ITEMS_PER_GET)

    recommendations = db_recommendations_cf_recording.get_user_recommendation(user['id'])

    if recommendations is None:
        err_msg = 'No recommendations due to absence of recent listening history for user {}'.format(user_name)
        raise APINoContent(err_msg)

    mbid_list, total_mbid_count = _process_recommendations(recommendations, count, artist_type, user_name, offset)

    payload = {
        'payload': {
            'mbids': mbid_list,
            'entity': "recording",
            'type': artist_type,
            'user_name': user_name,
            'last_updated': int(getattr(recommendations, 'created').timestamp()),
            'count': len(mbid_list),
            'total_mbid_count': total_mbid_count,
            'offset': offset
        }
    }

    return jsonify(payload)