Пример #1
0
 def fetch_params():
     is_draft = Parser.bool('json', 'is_draft', optional=True) or False
     if is_draft:
         REVIEW_TEXT_MIN_LENGTH = None
     entity_id = Parser.uuid('json', 'entity_id')
     entity_type = Parser.string('json',
                                 'entity_type',
                                 valid_values=ENTITY_TYPES)
     text = Parser.string('json',
                          'text',
                          min=REVIEW_TEXT_MIN_LENGTH,
                          max=REVIEW_TEXT_MAX_LENGTH,
                          optional=True)
     rating = Parser.int('json',
                         'rating',
                         min=REVIEW_RATING_MIN,
                         max=REVIEW_RATING_MAX,
                         optional=True)
     license_choice = Parser.string('json', 'license_choice')
     language = Parser.string(
         'json', 'language', min=2, max=3, optional=True) or 'en'
     if text is None and rating is None:
         raise InvalidRequest(desc='Review must have either text or rating')
     if language and language not in supported_languages:
         raise InvalidRequest(desc='Unsupported language')
     if db_review.list_reviews(user_id=user.id, entity_id=entity_id)[1]:
         raise InvalidRequest(
             desc='You have already published a review for this album')
     return entity_id, entity_type, text, rating, license_choice, language, is_draft
Пример #2
0
def review_vote_put_handler(review_id, user):
    """Set your vote for a specified review.

    **OAuth scope:** vote

    :json boolean vote: ``true`` if upvote, ``false`` if downvote

    :statuscode 200: success
    :statuscode 400: invalid request (see source)
    :statuscode 403: daily vote limit exceeded
    :statuscode 404: review not found

    :resheader Content-Type: *application/json*
    """

    def fetch_params():
        vote = Parser.bool('json', 'vote')
        return vote

    review = Review.query.get_or_404(str(review_id))
    if review.is_hidden:
        raise NotFound("Review has been hidden.")
    vote = fetch_params()
    if review.user_id == user.id:
        raise InvalidRequest(desc='You cannot rate your own review.')
    if user.is_vote_limit_exceeded is True and user.has_voted(review) is False:
        raise LimitExceeded('You have exceeded your limit of votes per day.')
    if vote is True and user.user_type not in review.review_class.upvote:
        raise InvalidRequest(desc='You are not allowed to upvote this review.')
    if vote is False and user.user_type not in review.review_class.downvote:
        raise InvalidRequest(desc='You are not allowed to downvote this review.')
    Vote.create(user, review, vote)  # overwrites an existing vote, if needed
    return jsonify(message='Request processed successfully')
Пример #3
0
def review_vote_put_handler(review_id, user):
    """Set your vote for a specified review.

    **OAuth scope:** vote

    **Request Example:**

    .. code-block:: bash

        $ curl "https://critiquebrainz.org/ws/1/review/9cb11424-d070-4ac1-8771-a8703ae5cccd/vote" \\
               -X PUT \\
               -H "Content-type: application/json" \\
               -H "Authorization: Bearer <access token>" \\
               -d '{"vote":true}'

    **Response Example:**

    .. code-block:: json

        {
          "message": "Request processed successfully"
        }

    :json boolean vote: ``true`` if upvote, ``false`` if downvote

    **NOTE:** Voting on reviews without text is not allowed.

    :statuscode 200: success
    :statuscode 400: invalid request (see source)
    :statuscode 403: daily vote limit exceeded
    :statuscode 404: review not found

    :resheader Content-Type: *application/json*
    """
    def fetch_params():
        vote = Parser.bool('json', 'vote')
        return vote

    review = get_review_or_404(review_id)
    if review["is_hidden"]:
        raise NotFound("Review has been hidden.")
    vote = fetch_params()
    if str(review["user_id"]) == user.id:
        raise InvalidRequest(desc='You cannot rate your own review.')
    if review["text"] is None:
        raise InvalidRequest(
            desc='Voting on reviews without text is not allowed.')
    if user.is_vote_limit_exceeded and not db_users.has_voted(
            user.id, review_id):
        raise LimitExceeded('You have exceeded your limit of votes per day.')

    db_vote.submit(
        user_id=user.id,
        revision_id=review["last_revision"]["id"],
        vote=vote,  # overwrites an existing vote, if needed
    )

    return jsonify(message='Request processed successfully')
Пример #4
0
 def fetch_params():
     is_draft = Parser.bool('json', 'is_draft', optional=True) or False
     if is_draft:
         REVIEW_MIN_LENGTH = None
     entity_id = Parser.uuid('json', 'entity_id')
     entity_type = Parser.string('json', 'entity_type', valid_values=ENTITY_TYPES)
     text = Parser.string('json', 'text', min=REVIEW_MIN_LENGTH, max=REVIEW_MAX_LENGTH)
     license_choice = Parser.string('json', 'license_choice')
     language = Parser.string('json', 'language', min=2, max=3, optional=True) or 'en'
     if language and language not in supported_languages:
         raise InvalidRequest(desc='Unsupported language')
     if Review.query.filter_by(user=user, entity_id=entity_id).count():
         raise InvalidRequest(desc='You have already published a review for this album')
     return entity_id, entity_type, text, license_choice, language, is_draft
Пример #5
0
def review_vote_delete_handler(review_id, user):
    """Delete your vote for a specified review.

    **OAuth scope:** vote

    **Request Example:**

    .. code-block:: bash

        $ curl "https://critiquebrainz.org/ws/1/review/9cb11424-d070-4ac1-8771-a8703ae5cccd/vote" \\
               -X DELETE \\
               -H "Authorization: Bearer <access token>"

    **Response Example:**

    .. code-block:: json

        {
          "message": "Request processed successfully"
        }

    :resheader Content-Type: *application/json*
    """
    review = get_review_or_404(review_id)
    if review["is_hidden"]:
        raise NotFound("Review has been hidden.")
    try:
        vote = db_vote.get(user_id=user.id,
                           revision_id=review["last_revision"]["id"])
    except db_exceptions.NoDataFoundException:
        raise InvalidRequest("Review is not rated yet.")
    db_vote.delete(user_id=vote["user_id"], revision_id=vote["revision_id"])
    return jsonify(message="Request processed successfully")
Пример #6
0
def review_list_handler():
    """Get list of reviews.

    :json uuid entity_id: UUID of the release group that is being reviewed
    :json string entity_type: One of the supported reviewable entities. 'release_group' or 'event' etc. **(optional)**
    :query user_id: user's UUID **(optional)**
    :query sort: ``rating`` or ``created`` **(optional)**
    :query limit: results limit, min is 0, max is 50, default is 50 **(optional)**
    :query offset: result offset, default is 0 **(optional)**
    :query language: language code (ISO 639-1) **(optional)**

    :resheader Content-Type: *application/json*
    """
    # TODO: This checking is added to keep old clients working and needs to be removed.
    release_group = Parser.uuid('uri', 'release_group', optional=True)
    if release_group:
        entity_id = release_group
        entity_type = 'release_group'
    else:        
        entity_id = Parser.uuid('uri', 'entity_id', optional=True)
        entity_type = Parser.string('uri', 'entity_type', valid_values=ENTITY_TYPES, optional=True)

    user_id = Parser.uuid('uri', 'user_id', optional=True)
    sort = Parser.string('uri', 'sort', valid_values=['rating', 'created'], optional=True)
    limit = Parser.int('uri', 'limit', min=1, max=50, optional=True) or 50
    offset = Parser.int('uri', 'offset', optional=True) or 0
    language = Parser.string('uri', 'language', min=2, max=3, optional=True)
    if language and language not in supported_languages:
        raise InvalidRequest(desc='Unsupported language')

    # TODO(roman): Ideally caching logic should live inside the model. Otherwise it
    # becomes hard to track all this stuff.
    cache_key = cache.gen_key('list', entity_id, user_id, sort, limit, offset, language)
    cached_result = cache.get(cache_key, Review.CACHE_NAMESPACE)
    if cached_result:
        reviews = cached_result['reviews']
        count = cached_result['count']

    else:
        reviews, count = Review.list(
            entity_id=entity_id,
            entity_type=entity_type,
            user_id=user_id,
            sort=sort,
            limit=limit,
            offset=offset,
            language=language,
        )
        reviews = [p.to_dict() for p in reviews]
        cache.set(cache_key, {
            'reviews': reviews,
            'count': count,
        }, namespace=Review.CACHE_NAMESPACE)

    return jsonify(limit=limit, offset=offset, count=count, reviews=reviews)
Пример #7
0
 def fetch_params(review):
     try:
         text = Parser.string('json', 'text', min=REVIEW_TEXT_MIN_LENGTH, max=REVIEW_TEXT_MAX_LENGTH)
     except MissingDataError:
         text = review['text']
     try:
         rating = Parser.int('json', 'rating', min=REVIEW_RATING_MIN, max=REVIEW_RATING_MAX)
     except MissingDataError:
         rating = review['rating']
     if text is None and rating is None:
         raise InvalidRequest(desc='Review must have either text or rating')
     return text, rating
Пример #8
0
def review_spam_report_handler(review_id, user):
    """Create spam report for a specified review.

    **OAuth scope:** vote

    :resheader Content-Type: *application/json*
    """
    review = get_review_or_404(review_id)
    if review["is_hidden"]:
        raise NotFound("Review has been hidden.")
    if review["user_id"] == user.id:
        raise InvalidRequest('own')
    db_spam_report.create(review["last_revision"]["id"], user.id, "Spam")
    return jsonify(message="Spam report created successfully")
Пример #9
0
def review_spam_report_handler(review_id, user):
    """Create spam report for a specified review.

    **OAuth scope:** vote

    :resheader Content-Type: *application/json*
    """
    review = Review.query.get_or_404(str(review_id))
    if review.is_hidden:
        raise NotFound("Review has been hidden.")
    if review.user_id == user.id:
        raise InvalidRequest('own')
    SpamReport.create(review, user)
    return jsonify(message="Spam report created successfully")
Пример #10
0
def review_vote_delete_handler(review_id, user):
    """Delete your vote for a specified review.

    **OAuth scope:** vote

    :resheader Content-Type: *application/json*
    """
    review = Review.query.get_or_404(str(review_id))
    if review.is_hidden:
        raise NotFound("Review has been hidden.")
    vote = Vote.query.filter_by(user=user, revision=review.last_revision).first()
    if not vote:
        raise InvalidRequest(desc='Review is not rated yet.')
    vote.delete()
    return jsonify(message='Request processed successfully')
Пример #11
0
def review_list_handler():
    """Get list of reviews.

    **Request Example:**

    .. code-block:: bash

        $ curl "https://critiquebrainz.org/ws/1/review/?limit=1&offset=50" \\
                -X GET

    **Response Example:**

    .. code-block:: json

        {
          "count": 9197,
          "limit": 1,
          "offset": 50,
          "reviews": [
            {
              "created": "Fri, 16 May 2008 00:00:00 GMT",
              "edits": 0,
              "entity_id": "09259937-6477-3959-8b10-af1cbaea8e6e",
              "entity_type": "release_group",
              "id": "c807d0b4-0dd0-43fe-a7c4-d29bb61f389e",
              "language": "en",
              "last_updated": "Fri, 16 May 2008 00:00:00 GMT",
              "license": {
                "full_name": "Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported",
                "id": "CC BY-NC-SA 3.0",
                "info_url": "https://creativecommons.org/licenses/by-nc-sa/3.0/"
              },
              "popularity": 0,
              "source": "BBC",
              "source_url": "http://www.bbc.co.uk/music/reviews/vh54",
              "text": "TEXT CONTENT OF REVIEW",
              "rating": 5,
              "user": {
                "created": "Wed, 07 May 2014 16:20:47 GMT",
                "display_name": "Jenny Nelson",
                "id": "3bf3fe0c-6db2-4746-bcf1-f39912113852",
                "karma": 0,
                "user_type": "Noob"
              },
              "votes": {
                "positive": 0,
                "negative": 0
              }
            }
          ]
        }

    :json uuid entity_id: UUID of the release group that is being reviewed
    :json string entity_type: One of the supported reviewable entities. 'release_group' or 'event' etc. **(optional)**
    :query user_id: user's UUID **(optional)**
    :query sort: ``popularity`` or ``published_on`` **(optional)**
    :query limit: results limit, min is 0, max is 50, default is 50 **(optional)**
    :query offset: result offset, default is 0 **(optional)**
    :query language: language code (ISO 639-1) **(optional)**

    :resheader Content-Type: *application/json*
    """
    # TODO: This checking is added to keep old clients working and needs to be removed.
    release_group = Parser.uuid('uri', 'release_group', optional=True)
    if release_group:
        entity_id = release_group
        entity_type = 'release_group'
    else:
        entity_id = Parser.uuid('uri', 'entity_id', optional=True)
        entity_type = Parser.string('uri',
                                    'entity_type',
                                    valid_values=ENTITY_TYPES,
                                    optional=True)

    user_id = Parser.uuid('uri', 'user_id', optional=True)
    sort = Parser.string(
        'uri',
        'sort',
        valid_values=['popularity', 'published_on', 'rating', 'created'],
        optional=True)

    # "rating" and "created" sort values are deprecated and but allowed here for backward compatibility
    if sort == 'created':
        sort = 'published_on'
    if sort == 'rating':
        sort = 'popularity'

    limit = Parser.int('uri', 'limit', min=1, max=50, optional=True) or 50
    offset = Parser.int('uri', 'offset', optional=True) or 0
    language = Parser.string('uri', 'language', min=2, max=3, optional=True)
    if language and language not in supported_languages:
        raise InvalidRequest(desc='Unsupported language')

    # TODO(roman): Ideally caching logic should live inside the model. Otherwise it
    # becomes hard to track all this stuff.
    cache_key = cache.gen_key('list', entity_id, user_id, sort, limit, offset,
                              language)
    cached_result = cache.get(cache_key, REVIEW_CACHE_NAMESPACE)
    if cached_result:
        reviews = cached_result['reviews']
        count = cached_result['count']

    else:
        reviews, count = db_review.list_reviews(
            entity_id=entity_id,
            entity_type=entity_type,
            user_id=user_id,
            sort=sort,
            limit=limit,
            offset=offset,
            language=language,
        )
        reviews = [db_review.to_dict(p) for p in reviews]
        cache.set(cache_key, {
            'reviews': reviews,
            'count': count,
        },
                  namespace=REVIEW_CACHE_NAMESPACE)

    return jsonify(limit=limit, offset=offset, count=count, reviews=reviews)