<> = 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 [[https://launchpad.net/rnr-server|lp:rnr-server]] project (to ensure it’s always compatible).