Ejemplo n.º 1
0
def get(review_id, limit=1, offset=0):
    """Get revisions on a review ordered by the timestamp

    Args:
        review_id (uuid): ID of review
        limit (int): The number of revisions to return(default=1)
        offset (int): The number of revisions to skip from top(default=0)

    Returns:
        List of dictionaries of revisions of the review
        with the following structure:
        {
            "id": (int),
            "review_id": (uuid),
            "timestamp": (datetime),
            "text": (string),
            "rating": (int),
            "votes_positive": (int),
            "votes_negative": (int),
        }
    """
    with db.engine.connect() as connection:
        result = connection.execute(
            sqlalchemy.text("""
            SELECT id,
                   review_id,
                   timestamp,
                   text,
                   rating,
                   SUM(
                       CASE WHEN vote='t' THEN 1 ELSE 0 END
                   ) AS votes_positive,
                   SUM(
                       CASE WHEN vote='f' THEN 1 ELSE 0 END
                   ) AS votes_negative
              FROM revision
         LEFT JOIN vote
                ON vote.revision_id = revision.id
             WHERE review_id = :review_id
          GROUP BY revision.id
          ORDER BY timestamp DESC
            OFFSET :offset
             LIMIT :limit
        """), {
                "review_id": review_id,
                "offset": offset,
                "limit": limit
            })

        rows = result.fetchall()
        if not rows:
            raise db_exceptions.NoDataFoundException(
                "Cannot find specified review.")
        rows = [dict(row) for row in rows]
        # Convert ratings to values on a scale 1-5
        for row in rows:
            row["rating"] = RATING_SCALE_1_5.get(row["rating"])
    return rows
Ejemplo n.º 2
0
def get(review_id, limit=1, offset=0):
    """Get revisions on a review ordered by the timestamp

    Args:
        review_id (uuid): ID of review
        limit (int): The number of revisions to return(default=1)
        offset (int): The number of revisions to skip from top(default=0)

    Returns:
        List of dictionaries of revisions of the review
        with the following structure:
        {
            "id": (int),
            "review_id": (uuid),
            "timestamp": (datetime),
            "text": (string),
            "rating": (int),
            "votes_positive": (int),
            "votes_negative": (int),
        }
    """
    with db.engine.connect() as connection:
        result = connection.execute(sqlalchemy.text("""
            SELECT id,
                   review_id,
                   timestamp,
                   text,
                   rating,
                   SUM(
                       CASE WHEN vote='t' THEN 1 ELSE 0 END
                   ) AS votes_positive,
                   SUM(
                       CASE WHEN vote='f' THEN 1 ELSE 0 END
                   ) AS votes_negative
              FROM revision
         LEFT JOIN vote
                ON vote.revision_id = revision.id
             WHERE review_id = :review_id
          GROUP BY revision.id
          ORDER BY timestamp DESC
            OFFSET :offset
             LIMIT :limit
        """), {
            "review_id": review_id,
            "offset": offset,
            "limit": limit
        })

        rows = result.fetchall()
        if not rows:
            raise db_exceptions.NoDataFoundException("Cannot find specified review.")
        rows = [dict(row) for row in rows]
        # Convert ratings to values on a scale 1-5
        for row in rows:
            row["rating"] = RATING_SCALE_1_5.get(row["rating"])
    return rows
Ejemplo n.º 3
0
def get_popular(limit=None):
    """Get a list of popular reviews.

    Popularity is determined by 'popularity' of a particular review. popularity is a
    difference between positive votes and negative. In this case only votes
    from the last month are used to calculate popularity to make results more
    varied.

    Args:
        limit (int): Maximum number of reviews to return.

    Returns:
        Randomized list of popular reviews which are converted into
        dictionaries using to_dict method.
    """
    cache_key = cache.gen_key("popular_reviews", limit)
    reviews = cache.get(cache_key, REVIEW_CACHE_NAMESPACE)
    defined_limit = 4 * limit if limit else None

    if not reviews:
        with db.engine.connect() as connection:
            results = connection.execute(
                sqlalchemy.text("""
                SELECT review.id,
                       review.entity_id,
                       review.entity_type,
                       review.user_id,
                       review.edits,
                       review.is_draft,
                       review.is_hidden,
                       review.license_id,
                       review.language,
                       review.source,
                       review.source_url,
                       SUM(
                           CASE WHEN vote = 't' THEN 1
                                WHEN vote = 'f' THEN -1
                                WHEN vote IS NULL THEN 0 END
                       ) AS popularity,
                       latest_revision.id AS latest_revision_id,
                       latest_revision.timestamp AS latest_revision_timestamp,
                       latest_revision.text AS text,
                       latest_revision.rating AS rating
                  FROM review
                  JOIN revision ON revision.review_id = review.id
             LEFT JOIN (
                        SELECT revision_id, vote
                          FROM vote
                         WHERE rated_at > :last_month
                       ) AS votes_last_month
                    ON votes_last_month.revision_id = revision.id
                  JOIN (
                        revision JOIN (
                          SELECT review.id AS review_uuid,
                                 MAX(timestamp) AS latest_timestamp
                            FROM review
                            JOIN revision ON review.id = review_id
                        GROUP BY review.id
                        ) AS latest ON latest.review_uuid = revision.review_id
                        AND latest.latest_timestamp = revision.timestamp
                       ) AS latest_revision
                    ON review.id = latest_revision.review_id
                 WHERE entity_id
                    IN (
                        SELECT DISTINCT entity_id
                          FROM (
                        SELECT entity_id
                          FROM review
                      ORDER BY RANDOM()
                      ) AS randomized_entity_ids
                    )
                   AND latest_revision.text IS NOT NULL
              GROUP BY review.id, latest_revision.id
              ORDER BY popularity
                 LIMIT :limit
            """), {
                    "limit": defined_limit,
                    "last_month": datetime.now() - timedelta(weeks=4)
                })
            reviews = results.fetchall()

        reviews = [dict(review) for review in reviews]
        if reviews:
            for review in reviews:
                review["rating"] = RATING_SCALE_1_5.get(review["rating"])
                review["last_revision"] = {
                    "id": review.pop("latest_revision_id"),
                    "timestamp": review.pop("latest_revision_timestamp"),
                    "text": review["text"],
                    "rating": review["rating"],
                    "review_id": review["id"],
                }
            reviews = [
                to_dict(review, confidential=True) for review in reviews
            ]
        cache.set(cache_key, reviews, 1 * 60 * 60,
                  REVIEW_CACHE_NAMESPACE)  # 1 hour
    shuffle(reviews)
    return reviews[:limit]
Ejemplo n.º 4
0
def get_by_id(review_id):
    """Get a review by its ID.

    Args:
        review_id (uuid): ID of the review.

    Returns:
        Dictionary with the following structure
        {
            "id": uuid,
            "entity_id": uuid,
            "entity_type": str,
            "user_id": uuid,
            "user": dict,
            "edits": int,
            "is_draft": bool,
            "is_hidden": bool,
            "language": str,
            "license_id": str,
            "source": str,
            "source_url": str,
            "last_revision: dict,
            "votes": dict,
            "popularity": int,
            "rating": int,
            "text": str,
            "created": datetime,
            "license": dict,
        }
    """
    with db.engine.connect() as connection:
        result = connection.execute(
            sqlalchemy.text("""
            SELECT review.id AS id,
                   review.entity_id,
                   review.entity_type,
                   review.user_id,
                   review.edits,
                   review.is_draft,
                   review.is_hidden,
                   review.license_id,
                   review.language,
                   review.source,
                   review.source_url,
                   revision.id AS last_revision_id,
                   revision.timestamp,
                   revision.text,
                   revision.rating,
                   "user".email,
                   "user".created as user_created,
                   "user".display_name,
                   "user".show_gravatar,
                   "user".musicbrainz_id,
                   "user".is_blocked,
                   created_time.created,
                   license.full_name,
                   license.info_url
              FROM review
              JOIN revision ON revision.review_id = review.id
              JOIN "user" ON "user".id = review.user_id
              JOIN license ON license.id = license_id
              JOIN (
                    SELECT review.id,
                           timestamp AS created
                      FROM review
                      JOIN revision ON review.id = revision.review_id
                     WHERE review.id = :review_id
                  ORDER BY revision.timestamp ASC
                     LIMIT 1
                   ) AS created_time
                ON created_time.id = review.id
          ORDER BY timestamp DESC
        """), {
                "review_id": review_id,
            })

        review = result.fetchone()
        if not review:
            raise db_exceptions.NoDataFoundException(
                "Can't find review with ID: {id}".format(id=review_id))

        review = dict(review)
        review["rating"] = RATING_SCALE_1_5.get(review["rating"])
        review["last_revision"] = {
            "id": review.pop("last_revision_id"),
            "timestamp": review.pop("timestamp"),
            "text": review.get("text"),
            "rating": review.get("rating"),
            "review_id": review.get("id"),
        }
        review["user"] = User({
            "id":
            review["user_id"],
            "display_name":
            review.pop("display_name", None),
            "is_blocked":
            review.pop("is_blocked", False),
            "show_gravatar":
            review.pop("show_gravatar", False),
            "musicbrainz_username":
            review.pop("musicbrainz_id"),
            "email":
            review.pop("email"),
            "created":
            review.pop("user_created"),
        })
        review["license"] = {
            "id": review["license_id"],
            "info_url": review["info_url"],
            "full_name": review["full_name"],
        }
        votes = db_revision.votes(review["last_revision"]["id"])
        review["votes"] = {
            "positive": votes["positive"],
            "negative": votes["negative"],
        }
        review["popularity"] = review["votes"]["positive"] - review["votes"][
            "negative"]
    return review
Ejemplo n.º 5
0
def list_reviews(*,
                 inc_drafts=False,
                 inc_hidden=False,
                 entity_id=None,
                 entity_type=None,
                 license_id=None,
                 user_id=None,
                 language=None,
                 exclude=None,
                 sort=None,
                 limit=20,
                 offset=None):
    """Get a list of reviews.

    This function provides several filters that can be used to select a subset of reviews.

    Args:
        entity_id (uuid): ID of the entity that has been reviewed.
        entity_type (str): Type of the entity that has been reviewed.
        user_id (uuid): ID of the author.
        sort (str): Order of the returned reviews. Can be either "popularity" (order by difference in +/- votes),
                    or "created" (order by creation time), or "random" (order randomly).
        limit (int): Maximum number of reviews to return.
        offset (int): Offset that can be used in conjunction with the limit.
        language (str): Language code of reviews.
        license_id (str): License ID that reviews are associated with.
        inc_drafts (bool): True if reviews marked as drafts should be included, False if not.
        inc_hidden (bool): True if reviews marked as hidden should be included, False if not.
        exclude (list): List of reviews (their IDs) to exclude from results.

    Returns:
        Tuple with two values:
        1. list of reviews as dictionaries,
        2. total number of reviews that match the specified filters.
    """
    filters = []
    filter_data = {}
    if not inc_drafts:
        filters.append("is_draft = :is_draft")
        filter_data["is_draft"] = False

    if not inc_hidden:
        filters.append("is_hidden = :is_hidden")
        filter_data["is_hidden"] = False

    # FILTERING
    if entity_id is not None:
        filters.append("entity_id = :entity_id")
        filter_data["entity_id"] = entity_id

    if entity_type is not None:
        filters.append("entity_type = :entity_type")
        filter_data["entity_type"] = entity_type

    if license_id is not None:
        filters.append("license_id = :license_id")
        filter_data["license_id"] = license_id

    if user_id is not None:
        filters.append("review.user_id = :user_id")
        filter_data["user_id"] = user_id

    if exclude is not None:
        filters.append("review.id NOT IN :exclude")
        filter_data["exclude"] = tuple(exclude)

    if language is not None:
        filters.append("language = :language")
        filter_data["language"] = language

    filterstr = " AND ".join(filters)
    if filterstr:
        filterstr = " WHERE " + filterstr

    query = sqlalchemy.text("""
        SELECT COUNT(*)
          FROM review
            {filterstr}
        """.format(filterstr=filterstr))

    with db.engine.connect() as connection:
        result = connection.execute(query, filter_data)
        count = result.fetchone()[0]
    order_by_clause = str()

    if sort == "popularity":
        order_by_clause = """
            ORDER BY popularity DESC
        """
    elif sort == "created":
        order_by_clause = """
            ORDER BY created DESC
        """
    elif sort == "random":
        order_by_clause = """
            ORDER BY RANDOM()
        """
    # Note that all revisions' votes are considered in this popularity
    query = sqlalchemy.text("""
        SELECT review.id,
               review.entity_id,
               review.entity_type,
               review.edits,
               review.is_draft,
               review.is_hidden,
               review.license_id,
               review.language,
               review.source,
               review.source_url,
               review.user_id,
               "user".display_name,
               "user".show_gravatar,
               "user".is_blocked,
               "user".email,
               "user".created as user_created,
               "user".musicbrainz_id,
               MIN(revision.timestamp) as created,
               SUM(
                   CASE WHEN vote='t' THEN 1 ELSE 0 END
               ) AS votes_positive_count,
               SUM(
                   CASE WHEN vote='f' THEN 1 ELSE 0 END
               ) AS votes_negative_count,
               SUM(
                   CASE WHEN vote = 't' THEN 1
                   WHEN vote = 'f' THEN -1 WHEN vote IS NULL THEN 0 END
               ) AS popularity,
               latest_revision.id as latest_revision_id,
               latest_revision.timestamp as latest_revision_timestamp,
               latest_revision.text as text,
               latest_revision.rating as rating,
               license.full_name,
               license.info_url
          FROM review
          JOIN revision ON review.id = revision.review_id
     LEFT JOIN vote ON vote.revision_id = revision.id
          JOIN "user" ON review.user_id = "user".id
          JOIN license ON license.id = license_id
          JOIN (
                revision
                JOIN (
                    SELECT review.id AS review_uuid,
                           MAX(timestamp) AS latest_timestamp
                      FROM review
                      JOIN revision ON review.id = review_id
                  GROUP BY review.id
                  ) AS latest
                  ON latest.review_uuid = revision.review_id
                 AND latest.latest_timestamp = revision.timestamp
               ) AS latest_revision ON review.id = latest_revision.review_id
        {where_clause}
      GROUP BY review.id, latest_revision.id, "user".id, license.id
        {order_by_clause}
         LIMIT :limit
        OFFSET :offset
        """.format(where_clause=filterstr, order_by_clause=order_by_clause))

    filter_data["limit"] = limit
    filter_data["offset"] = offset

    with db.engine.connect() as connection:
        results = connection.execute(query, filter_data)
        rows = results.fetchall()
        rows = [dict(row) for row in rows]
        # Organise last revision info in reviews
        if rows:
            for row in rows:
                row["rating"] = RATING_SCALE_1_5.get(row["rating"])
                row["last_revision"] = {
                    "id": row.pop("latest_revision_id"),
                    "timestamp": row.pop("latest_revision_timestamp"),
                    "text": row["text"],
                    "rating": row["rating"],
                    "review_id": row["id"],
                }
                row["user"] = User({
                    "id":
                    row["user_id"],
                    "display_name":
                    row.pop("display_name"),
                    "show_gravatar":
                    row.pop("show_gravatar"),
                    "is_blocked":
                    row.pop("is_blocked"),
                    "musicbrainz_username":
                    row.pop("musicbrainz_id"),
                    "email":
                    row.pop("email"),
                    "created":
                    row.pop("user_created"),
                })
    return rows, count
Ejemplo n.º 6
0
def get_reviews_list(connection,
                     *,
                     inc_drafts=False,
                     inc_hidden=False,
                     entity_id=None,
                     entity_type=None,
                     license_id=None,
                     user_id=None,
                     language=None,
                     exclude=None,
                     sort=None,
                     limit=20,
                     offset=None):
    """
        helper function for list_reviews() that extends support for execution within a transaction by directly receiving the
        connection object
    """
    filters = []
    filter_data = {}
    if not inc_drafts:
        filters.append("is_draft = :is_draft")
        filter_data["is_draft"] = False

    if not inc_hidden:
        filters.append("is_hidden = :is_hidden")
        filter_data["is_hidden"] = False

    # FILTERING
    if entity_id is not None:
        filters.append("entity_id = :entity_id")
        filter_data["entity_id"] = entity_id

    if entity_type is not None:
        filters.append("entity_type = :entity_type")
        filter_data["entity_type"] = entity_type

    if license_id is not None:
        filters.append("license_id = :license_id")
        filter_data["license_id"] = license_id

    if user_id is not None:
        filters.append("review.user_id = :user_id")
        filter_data["user_id"] = user_id

    if exclude is not None:
        filters.append("review.id NOT IN :exclude")
        filter_data["exclude"] = tuple(exclude)

    if language is not None:
        filters.append("language = :language")
        filter_data["language"] = language

    filterstr = " AND ".join(filters)
    if filterstr:
        filterstr = " WHERE " + filterstr

    query = sqlalchemy.text("""
        SELECT COUNT(*)
          FROM review
            {filterstr}
        """.format(filterstr=filterstr))

    result = connection.execute(query, filter_data)
    count = result.fetchone()[0]
    order_by_clause = str()

    if sort == "popularity":
        order_by_clause = """
            ORDER BY popularity DESC
        """
    elif sort == "published_on":
        order_by_clause = """
            ORDER BY review.published_on DESC
        """
    elif sort == "random":
        order_by_clause = """
            ORDER BY RANDOM()
        """
    # Note that all revisions' votes are considered in this popularity
    query = sqlalchemy.text("""
        SELECT review.id,
               review.entity_id,
               review.entity_type,
               review.edits,
               review.is_draft,
               review.is_hidden,
               review.license_id,
               review.language,
               review.source,
               review.source_url,
               review.user_id,
               "user".display_name,
               "user".show_gravatar,
               "user".is_blocked,
               "user".email,
               "user".created as user_created,
               "user".musicbrainz_id,
               review.published_on,
               MIN(revision.timestamp) as created,
               SUM(
                   CASE WHEN vote='t' THEN 1 ELSE 0 END
               ) AS votes_positive_count,
               SUM(
                   CASE WHEN vote='f' THEN 1 ELSE 0 END
               ) AS votes_negative_count,
               SUM(
                   CASE WHEN vote = 't' THEN 1
                   WHEN vote = 'f' THEN -1 WHEN vote IS NULL THEN 0 END
               ) AS popularity,
               latest_revision.id as latest_revision_id,
               latest_revision.timestamp as latest_revision_timestamp,
               latest_revision.text as text,
               latest_revision.rating as rating,
               license.full_name,
               license.info_url
          FROM review
          JOIN revision ON review.id = revision.review_id
     LEFT JOIN vote ON vote.revision_id = revision.id
          JOIN "user" ON review.user_id = "user".id
          JOIN license ON license.id = license_id
          JOIN (
                revision
                JOIN (
                    SELECT review.id AS review_uuid,
                           MAX(timestamp) AS latest_timestamp
                      FROM review
                      JOIN revision ON review.id = review_id
                  GROUP BY review.id
                  ) AS latest
                  ON latest.review_uuid = revision.review_id
                 AND latest.latest_timestamp = revision.timestamp
               ) AS latest_revision ON review.id = latest_revision.review_id
        {where_clause}
      GROUP BY review.id, latest_revision.id, "user".id, license.id
        {order_by_clause}
         LIMIT :limit
        OFFSET :offset
        """.format(where_clause=filterstr, order_by_clause=order_by_clause))

    filter_data["limit"] = limit
    filter_data["offset"] = offset

    results = connection.execute(query, filter_data)
    rows = results.fetchall()
    rows = [dict(row) for row in rows]

    # Organise last revision info in reviews
    if rows:
        for row in rows:
            row["rating"] = RATING_SCALE_1_5.get(row["rating"])
            row["last_revision"] = {
                "id": row.pop("latest_revision_id"),
                "timestamp": row.pop("latest_revision_timestamp"),
                "text": row["text"],
                "rating": row["rating"],
                "review_id": row["id"],
            }
            row["user"] = User({
                "id":
                row["user_id"],
                "display_name":
                row.pop("display_name"),
                "show_gravatar":
                row.pop("show_gravatar"),
                "is_blocked":
                row.pop("is_blocked"),
                "musicbrainz_username":
                row.pop("musicbrainz_id"),
                "email":
                row.pop("email"),
                "created":
                row.pop("user_created"),
            })

    return rows, count
Ejemplo n.º 7
0
def get_popular(limit=None):
    """Get a list of popular reviews.

    Popularity is determined by 'popularity' of a particular review. popularity is a
    difference between positive votes and negative. In this case only votes
    from the last month are used to calculate popularity to make results more
    varied.

    Args:
        limit (int): Maximum number of reviews to return.

    Returns:
        Randomized list of popular reviews which are converted into
        dictionaries using to_dict method.
    """
    cache_key = cache.gen_key("popular_reviews", limit)
    reviews = cache.get(cache_key, REVIEW_CACHE_NAMESPACE)
    defined_limit = 4 * limit if limit else None

    if not reviews:
        with db.engine.connect() as connection:
            results = connection.execute(sqlalchemy.text("""
                SELECT review.id,
                       review.entity_id,
                       review.entity_type,
                       review.user_id,
                       review.edits,
                       review.is_draft,
                       review.is_hidden,
                       review.license_id,
                       review.language,
                       review.source,
                       review.source_url,
                       SUM(
                           CASE WHEN vote = 't' THEN 1
                                WHEN vote = 'f' THEN -1
                                WHEN vote IS NULL THEN 0 END
                       ) AS popularity,
                       latest_revision.id AS latest_revision_id,
                       latest_revision.timestamp AS latest_revision_timestamp,
                       latest_revision.text AS text,
                       latest_revision.rating AS rating
                  FROM review
                  JOIN revision ON revision.review_id = review.id
             LEFT JOIN (
                        SELECT revision_id, vote
                          FROM vote
                         WHERE rated_at > :last_month
                       ) AS votes_last_month
                    ON votes_last_month.revision_id = revision.id
                  JOIN (
                        revision JOIN (
                          SELECT review.id AS review_uuid,
                                 MAX(timestamp) AS latest_timestamp
                            FROM review
                            JOIN revision ON review.id = review_id
                        GROUP BY review.id
                        ) AS latest ON latest.review_uuid = revision.review_id
                        AND latest.latest_timestamp = revision.timestamp
                       ) AS latest_revision
                    ON review.id = latest_revision.review_id
                 WHERE entity_id
                    IN (
                        SELECT DISTINCT entity_id
                          FROM (
                        SELECT entity_id
                          FROM review
                      ORDER BY RANDOM()
                      ) AS randomized_entity_ids
                    )
                   AND latest_revision.text IS NOT NULL
                   AND review.is_hidden = 'f'
                   AND review.is_draft = 'f'
              GROUP BY review.id, latest_revision.id
              ORDER BY popularity
                 LIMIT :limit
            """), {
                "limit": defined_limit,
                "last_month": datetime.now() - timedelta(weeks=4)
            })
            reviews = results.fetchall()

        reviews = [dict(review) for review in reviews]
        if reviews:
            for review in reviews:
                review["rating"] = RATING_SCALE_1_5.get(review["rating"])
                review["last_revision"] = {
                    "id": review.pop("latest_revision_id"),
                    "timestamp": review.pop("latest_revision_timestamp"),
                    "text": review["text"],
                    "rating": review["rating"],
                    "review_id": review["id"],
                }
            reviews = [to_dict(review, confidential=True) for review in reviews]
        cache.set(cache_key, reviews, 1 * 60 * 60, REVIEW_CACHE_NAMESPACE)  # 1 hour
    shuffle(reviews)
    return reviews[:limit]
Ejemplo n.º 8
0
def get_by_id(review_id):
    """Get a review by its ID.

    Args:
        review_id (uuid): ID of the review.

    Returns:
        Dictionary with the following structure
        {
            "id": uuid,
            "entity_id": uuid,
            "entity_type": str,
            "user_id": uuid,
            "user": dict,
            "edits": int,
            "is_draft": bool,
            "is_hidden": bool,
            "language": str,
            "license_id": str,
            "source": str,
            "source_url": str,
            "last_revision: dict,
            "votes": dict,
            "popularity": int,
            "rating": int,
            "text": str,
            "license": dict,
            "published_on": datetime,
        }
    """
    with db.engine.connect() as connection:
        result = connection.execute(sqlalchemy.text("""
            SELECT review.id AS id,
                   review.entity_id,
                   review.entity_type,
                   review.user_id,
                   review.edits,
                   review.is_draft,
                   review.is_hidden,
                   review.license_id,
                   review.language,
                   review.source,
                   review.source_url,
                   review.published_on,
                   revision.id AS last_revision_id,
                   revision.timestamp,
                   revision.text,
                   revision.rating,
                   "user".email,
                   "user".created as user_created,
                   "user".display_name,
                   "user".show_gravatar,
                   "user".musicbrainz_id,
                   "user".is_blocked,
                   license.full_name,
                   license.info_url
              FROM review
              JOIN revision ON revision.review_id = review.id
              JOIN "user" ON "user".id = review.user_id
              JOIN license ON license.id = license_id
             WHERE review.id = :review_id
          ORDER BY timestamp DESC
        """), {
            "review_id": review_id,
        })

        review = result.fetchone()
        if not review:
            raise db_exceptions.NoDataFoundException("Can't find review with ID: {id}".format(id=review_id))

        review = dict(review)
        review["rating"] = RATING_SCALE_1_5.get(review["rating"])
        review["last_revision"] = {
            "id": review.pop("last_revision_id"),
            "timestamp": review.pop("timestamp"),
            "text": review.get("text"),
            "rating": review.get("rating"),
            "review_id": review.get("id"),
        }
        review["user"] = User({
            "id": review["user_id"],
            "display_name": review.pop("display_name", None),
            "is_blocked": review.pop("is_blocked", False),
            "show_gravatar": review.pop("show_gravatar", False),
            "musicbrainz_username": review.pop("musicbrainz_id"),
            "email": review.pop("email"),
            "created": review.pop("user_created"),
        })
        review["license"] = {
            "id": review["license_id"],
            "info_url": review["info_url"],
            "full_name": review["full_name"],
        }
        votes = db_revision.votes(review["last_revision"]["id"])
        review["votes"] = {
            "positive": votes["positive"],
            "negative": votes["negative"],
        }
        review["popularity"] = review["votes"]["positive"] - review["votes"]["negative"]
    return review
Ejemplo n.º 9
0
def get_reviews_list(connection, *, inc_drafts=False, inc_hidden=False, entity_id=None,
                     entity_type=None, license_id=None, user_id=None, language=None,
                     exclude=None, sort=None, limit=20, offset=None):
    """
        helper function for list_reviews() that extends support for execution within a transaction by directly receiving the
        connection object
    """
    filters = []
    filter_data = {}
    if not inc_drafts:
        filters.append("is_draft = :is_draft")
        filter_data["is_draft"] = False

    if not inc_hidden:
        filters.append("is_hidden = :is_hidden")
        filter_data["is_hidden"] = False

    # FILTERING
    if entity_id is not None:
        filters.append("entity_id = :entity_id")
        filter_data["entity_id"] = entity_id

    if entity_type is not None:
        filters.append("entity_type = :entity_type")
        filter_data["entity_type"] = entity_type

    if license_id is not None:
        filters.append("license_id = :license_id")
        filter_data["license_id"] = license_id

    if user_id is not None:
        filters.append("review.user_id = :user_id")
        filter_data["user_id"] = user_id

    if exclude is not None:
        filters.append("review.id NOT IN :exclude")
        filter_data["exclude"] = tuple(exclude)

    if language is not None:
        filters.append("language = :language")
        filter_data["language"] = language

    filterstr = " AND ".join(filters)
    if filterstr:
        filterstr = " WHERE " + filterstr

    query = sqlalchemy.text("""
        SELECT COUNT(*)
          FROM review
            {filterstr}
        """.format(filterstr=filterstr))

    result = connection.execute(query, filter_data)
    count = result.fetchone()[0]
    order_by_clause = str()

    if sort == "popularity":
        order_by_clause = """
            ORDER BY popularity DESC
        """
    elif sort == "published_on":
        order_by_clause = """
            ORDER BY review.published_on DESC
        """
    elif sort == "random":
        order_by_clause = """
            ORDER BY RANDOM()
        """
    # Note that all revisions' votes are considered in this popularity
    query = sqlalchemy.text("""
        SELECT review.id,
               review.entity_id,
               review.entity_type,
               review.edits,
               review.is_draft,
               review.is_hidden,
               review.license_id,
               review.language,
               review.source,
               review.source_url,
               review.user_id,
               "user".display_name,
               "user".show_gravatar,
               "user".is_blocked,
               "user".email,
               "user".created as user_created,
               "user".musicbrainz_id,
               review.published_on,
               MIN(revision.timestamp) as created,
               SUM(
                   CASE WHEN vote='t' THEN 1 ELSE 0 END
               ) AS votes_positive_count,
               SUM(
                   CASE WHEN vote='f' THEN 1 ELSE 0 END
               ) AS votes_negative_count,
               SUM(
                   CASE WHEN vote = 't' THEN 1
                   WHEN vote = 'f' THEN -1 WHEN vote IS NULL THEN 0 END
               ) AS popularity,
               latest_revision.id as latest_revision_id,
               latest_revision.timestamp as latest_revision_timestamp,
               latest_revision.text as text,
               latest_revision.rating as rating,
               license.full_name,
               license.info_url
          FROM review
          JOIN revision ON review.id = revision.review_id
     LEFT JOIN vote ON vote.revision_id = revision.id
          JOIN "user" ON review.user_id = "user".id
          JOIN license ON license.id = license_id
          JOIN (
                revision
                JOIN (
                    SELECT review.id AS review_uuid,
                           MAX(timestamp) AS latest_timestamp
                      FROM review
                      JOIN revision ON review.id = review_id
                  GROUP BY review.id
                  ) AS latest
                  ON latest.review_uuid = revision.review_id
                 AND latest.latest_timestamp = revision.timestamp
               ) AS latest_revision ON review.id = latest_revision.review_id
        {where_clause}
      GROUP BY review.id, latest_revision.id, "user".id, license.id
        {order_by_clause}
         LIMIT :limit
        OFFSET :offset
        """.format(where_clause=filterstr, order_by_clause=order_by_clause))

    filter_data["limit"] = limit
    filter_data["offset"] = offset

    results = connection.execute(query, filter_data)
    rows = results.fetchall()
    rows = [dict(row) for row in rows]

    # Organise last revision info in reviews
    if rows:
        for row in rows:
            row["rating"] = RATING_SCALE_1_5.get(row["rating"])
            row["last_revision"] = {
                "id": row.pop("latest_revision_id"),
                "timestamp": row.pop("latest_revision_timestamp"),
                "text": row["text"],
                "rating": row["rating"],
                "review_id": row["id"],
            }
            row["user"] = User({
                "id": row["user_id"],
                "display_name": row.pop("display_name"),
                "show_gravatar": row.pop("show_gravatar"),
                "is_blocked": row.pop("is_blocked"),
                "musicbrainz_username": row.pop("musicbrainz_id"),
                "email": row.pop("email"),
                "created": row.pop("user_created"),
            })

    return rows, count