RatingsAndReviews

Ratings & reviews

Contact: Michael Nelson (noodles), Fabián Ezequiel Gallina (fgallina)

The click review API can be tested at http://reviews.staging.ubuntu.com/click/api/1.0/reviews/ as shown below.

Other functionality that we'll want to add when needed (just moving across with small updates from existing non-click review functionality):

  1. Update the query for reviews so it can filter by version and arch as well (ie. so client can show top reviews by default, but allow UI to filter by the version that the user is looking at if needed).
  2. Add a +1 to a review (mark it as useful).
  3. Add the export api handler (like the non-click version) so that search.apps.ubuntu.com can import rating stats.

Client Setup

Python setup

For the following examples, make sure you've got a python environment with requests installed, eg:

$ virtualenv testauth
$ . testauth/bin/activate
$ pip install requests requests_oauthlib
$ python

Credentials Setup

First, create a new test account on https://login.staging.ubuntu.com.

Once it's done, you can setup a client for authenticated calls with the following snippet:

import json

import requests
import requests_oauthlib


# Create u1 creds using the new account:
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
account_details = {"email": "your+email@example.com", "password": "yourpassword", "token_name": "testreviews"}
result = requests.post("https://login.staging.ubuntu.com/api/v2/tokens/oauth", headers=headers, data=json.dumps(account_details))
u1_creds = result.json()

oauth1_session_plaintext = requests_oauthlib.OAuth1Session(u1_creds['consumer_key'], client_secret=u1_creds['consumer_secret'], resource_owner_key=u1_creds['token_key'], resource_owner_secret=u1_creds['token_secret'], signature_method='PLAINTEXT')

In the following API usage examples oauth1_session_plaintext will be used for authenticated calls to endpoints, while requests will be used for public access.

API

Reading reviews for a given package

>>> response = requests.get("http://reviews.staging.ubuntu.com/click/api/1.0/reviews/?package_name=com.ubuntu.developer.matiasb-testing.hello")

>>> len(response.json())
1
>>> response.json()
[{u'date_created': u'2014-01-28T09:09:47.218Z',
  u'date_deleted': None,
  u'hide': False,
  u'id': 1,
  u'language': u'en',
  u'package_name': u'com.ubuntu.developer.matiasb-testing.hello',
  u'rating': 4,
  u'review_text': u'top stuff',
  u'reviewer_displayname': u'Michael',
  u'reviewer_username': u'8tNPhpD',
  u'summary': u'install it',
  u'usefulness_favorable': 0,
  u'usefulness_total': 0,
  u'version': u'0.2'}]

Submitting a review

eg_data = {
    'arch_tag': 'i386',
    'language': 'en',
    'package_name': 'com.ubuntu.developer.matiasb-testing.hello',
    'rating': '4',
    'review_text': 'top stuff',
    'summary': 'install it',
    'version': '0.2'
}

response = oauth1_session_plaintext.post(
    "https://reviews.staging.ubuntu.com/click/api/1.0/reviews/", 
    data=json.dumps(eg_data),
    headers={'Content-Type': 'application/json'})                                  

# >>> response.reason
# 'OK'
# >>> response.content
# '{\n    "rating": 4, \n    "hide": false, \n    ...

# Creating a second review for the same package does not work

response = oauth1_session_plaintext.post(
    "https://reviews.staging.ubuntu.com/click/api/1.0/reviews/",
    data=json.dumps(eg_data),
    headers={'Content-Type': 'application/json'})

# >>> response.reason
# 'BAD REQUEST'
# >>> response.text
# u'{"errors": {"__all__": ["A user cannot create multiple reviews for an app."]}}'

# The filter of all reviews for the package now includes our review:

response = requests.get(
    "http://reviews.staging.ubuntu.com/click/api/1.0/reviews/?package_name=com.ubuntu.developer.matiasb-testing.hello")

# >>> response.json()
# [list of reviews for that app.]

Editing a review

Reviews are allowed to be edited at any time while they have no flags.

review_id = 19
url = 'https://reviews.staging.ubuntu.com/click/api/1.0/reviews/%s/' % review_id

# 'summary', 'review_text' and 'rating' are mandatory.
response = oauth1_session_plaintext.put(
    url, data=json.dumps({'review_text': 'review_text', 'rating': 5}),
    headers={'Content-Type': 'application/json'})

# >>> response.content
# '{"errors": {"summary": ["This field is required."]}}'

response = oauth1_session_plaintext.put(
    url, data=json.dumps({'summary': 'summary', 'review_text': 'review_text', 'rating': 5}),
    headers={'Content-Type': 'application/json'})

# >>> response.reason
# 'OK'

Deleting a review

review_id = 19
url = 'https://reviews.staging.ubuntu.com/click/api/1.0/reviews/%s/' % review_id

response = oauth1_session_plaintext.delete(url)

# >>> response.reason
# 'OK'

# >>> response.content
# '{\n    "rating": 5, \n    "hide": true, \n    ...

response = oauth1_session_plaintext.delete(url)

# >>> response.reason
# 'NOT FOUND'

Flagging a click package

response = oauth1_session_plaintext.post(
    "https://reviews.staging.ubuntu.com/click/api/1.0/packages/com.ubuntu.developer.matiasb-testing.hello/flags/",
    data='summary=sum&description=desc', headers={'Accept': 'application/json'})

# >>> response.status_code
# 200
# >>> response.json()
# {"id": 12, "date_created": "2014-08-21 16:28:49", "description": "desc", "summary": "sum"}

response = oauth1_session_plaintext.post(
    "https://reviews.staging.ubuntu.com/click/api/1.0/packages/com.ubuntu.developer.matiasb-testing.hello/flags/",
    data='summary=sum&description=desc', headers={'Accept': 'application/json'})

# >>> response.status_code
# 400
# >>> response.json()
# {"errors": {"package_name": ["User cannot flag same package twice."]}}

Flagging a click package review

# data could also be JSON encoded.
response = oauth1_session_plaintext.post(
    "https://reviews.staging.ubuntu.com/click/api/1.0/reviews/1/flags/",
    data='summary=sum&description=desc', headers={'Accept': 'application/json'})

# >>> response.status_code
# 200
# >>> response.json()
# {"id": 12, "date_created": "2014-08-21 16:28:49", "description": "desc", "summary": "sum"}

response = oauth1_session_plaintext.post(
    "https://reviews.staging.ubuntu.com/click/api/1.0/reviews/1/flags/",
    data='summary=sum&description=desc', headers={'Accept': 'application/json'})

# >>> response.status_code
# 400
# >>> response.json()
# {"errors": {"review": ["User cannot flag same review twice."]}}

[1] We may need to update the bulk delivery of stats so that the click package index can consume click-packages only. [2] The tests in the rnrclient module look unmaintained (2 failures), but the rnrclient is tested by the lp:rnr-server project (to ensure it’s always compatible).

AppStore/Interfaces/RatingsAndReviews (last edited 2015-04-22 20:40:02 by fgallina)