Merge lp:~aaronp/rnr-server/modify-only into lp:rnr-server

Proposed by Aaron Peachey
Status: Superseded
Proposed branch: lp:~aaronp/rnr-server/modify-only
Merge into: lp:rnr-server
Diff against target: 411 lines (+199/-15)
9 files modified
django_project/config_dev/config/main.cfg (+1/-0)
django_project/config_dev/schema.py (+1/-0)
src/reviewsapp/api/handlers.py (+32/-7)
src/reviewsapp/api/urls.py (+9/-1)
src/reviewsapp/forms.py (+16/-1)
src/reviewsapp/models/reviews.py (+8/-0)
src/reviewsapp/tests/test_handlers.py (+83/-1)
src/reviewsapp/tests/test_models.py (+10/-0)
src/reviewsapp/tests/test_rnrclient.py (+39/-5)
To merge this branch: bzr merge lp:~aaronp/rnr-server/modify-only
Reviewer Review Type Date Requested Status
Aaron Peachey (community) Needs Resubmitting
Ratings and Reviews Developers Pending
Review via email: mp+62115@code.launchpad.net

This proposal has been superseded by a proposal from 2011-05-28.

Description of the change

adds functionality for user to modify their existing review within 120 minutes (config option) of submission.

Diff of associated rnrclient changes:

=== modified file 'rnrclient.py'
--- rnrclient.py 2011-05-06 06:35:36 +0000
+++ rnrclient.py 2011-05-24 12:07:16 +0000
@@ -174,3 +174,14 @@
         """Delete a review"""
         return self._post('/reviews/delete/%s/' % review_id, data={},
             scheme=AUTHENTICATED_API_SCHEME)
+
+ @validate('review_id', int)
+ @validate('rating', int)
+ @validate_pattern('summary', r'[^\n]+')
+ @validate_pattern('review_text', r'[^\n]+')
+ @returns_json
+ def modify_review(self, review_id, rating, summary, review_text):
+ """Modify an existing review"""
+ data = {'rating':rating, 'summary':summary, 'review_text':review_text}
+ return self._put('/reviews/modify/%s/' % review_id, data=data,
+ scheme=AUTHENTICATED_API_SCHEME)

To post a comment you must log in.
Revision history for this message
Michael Nelson (michael.nelson) wrote :
Download full text (9.8 KiB)

Excellent work Aaron - as far as I can see, you've tested everything very well. I've only got a few small simplifications, formatting points or wording suggestions below. See what you think.

> === modified file 'src/reviewsapp/api/handlers.py'
> --- src/reviewsapp/api/handlers.py 2011-05-05 14:32:04 +0000
> +++ src/reviewsapp/api/handlers.py 2011-05-24 12:31:07 +0000
> @@ -239,6 +240,32 @@
>
> return review
>
> +class ModifyReviewHandler(BaseHandler):
> + allowed_methods = ('PUT',)
> +
> + def update(self, request, review_id):
> + """Uses PUT verb to modify an existing review"""
> + review = get_object_or_404(Review, id=review_id, reviewer=request.user)
> +
> + # check review modify window has not closed before allowing update
> + time_diff = datetime.utcnow() - review.date_created
> + time_limit = timedelta(minutes=settings.MODIFY_WINDOW_MINUTES)
> + if time_diff > time_limit:
> + return HttpResponseForbidden("Time to modify review has expired")

Hrm - I wonder if we can get a balance of simple language with the actual reason
in parenthesis? Maybe:

"This review can not be edited (edit window expired)."

> + elif review.is_awaiting_moderation():
> + return HttpResponseForbidden("Can't modify review with pending moderation")

"This review can not be edited (pending moderation)."

> + else:
> + form = ReviewEditForm(request.POST, instance=review)
> + if not form.is_valid():
> + errors = dict((key, [unicode(v) for v in values])
> + for (key, values) in form.errors.items())
> + response = simplejson.dumps({'errors': errors})
> + return HttpResponseBadRequest(response)

I noticed that we're already doing this for the SubmitReviewHandler - it'd be
nice to DRY it up. Feel free to leave it, but if you're keen, we could add an
'errors_json' to our forms. We'd only need to define it once if we use a mixin
like:

class JSONErrorMixin(object):
    def errors_json():
        ...

and then the forms that use this would simply do:

class ReviewEditForm(forms.ModelForm, JSONErrorMixin):
    ...

Then the above handler could be simplified to:

if not form.is_valid():
    return HttpResponse(form.errors_json())

Again, feel free to leave this - and tackle it only if it interests you.

> === modified file 'src/reviewsapp/models/reviews.py'
> --- src/reviewsapp/models/reviews.py 2011-05-06 01:17:56 +0000
> +++ src/reviewsapp/models/reviews.py 2011-05-24 12:31:07 +0000
> @@ -342,6 +342,15 @@
> def reviewer_displayname(self):
> return self.reviewer.get_full_name()
>
> + def is_awaiting_moderation(self):
> + """Return true if the review has any pending moderations"""
> + moderations = ReviewModeration.objects.filter(
> + review=self,
> + status=ReviewModeration.PENDING_STATUS).count()

Just a simplification, you should be able to do:
           moderations = self.reviewmoderation_set.filter(status=...).count()

> + if moderations == 0:
> + return False
> + return True
> +
> def delete(self):
> """...

lp:~aaronp/rnr-server/modify-only updated
188. By Aaron Peachey

* changes as per merge proposal feedback
* add JSONErrorMixin class to centralise returning
     of error json to multiple handlers that use it

Revision history for this message
Aaron Peachey (aaronp) wrote :

Thanks Michael. All changes made as per feedback.

review: Needs Resubmitting
lp:~aaronp/rnr-server/modify-only updated
189. By Aaron Peachey

update rnrclient test to cater for change to
rnrclient to return ReviewDetails insteadof json

Revision history for this message
Aaron Peachey (aaronp) wrote :

New commit (r189) with slight change to test case for rnrclient because I realised when testing my changes in the client that we should return a ReviewDetails object instead of json, for consistency.
Therefore, diff for the rnrclient branch is now:

=== modified file 'rnrclient.py'
--- rnrclient.py 2011-05-06 06:35:36 +0000
+++ rnrclient.py 2011-05-28 12:06:31 +0000
@@ -174,3 +174,14 @@
         """Delete a review"""
         return self._post('/reviews/delete/%s/' % review_id, data={},
             scheme=AUTHENTICATED_API_SCHEME)
+
+ @validate('review_id', int)
+ @validate('rating', int)
+ @validate_pattern('summary', r'[^\n]+')
+ @validate_pattern('review_text', r'[^\n]+')
+ @returns(ReviewDetails)
+ def modify_review(self, review_id, rating, summary, review_text):
+ """Modify an existing review"""
+ data = {'rating':rating, 'summary':summary, 'review_text':review_text}
+ return self._put('/reviews/modify/%s/' % review_id, data=data,
+ scheme=AUTHENTICATED_API_SCHEME)

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'django_project/config_dev/config/main.cfg'
--- django_project/config_dev/config/main.cfg 2011-04-21 14:55:23 +0000
+++ django_project/config_dev/config/main.cfg 2011-05-28 12:13:24 +0000
@@ -100,6 +100,7 @@
100token_cache_expiry_hours = 4100token_cache_expiry_hours = 4
101reviewsapp_media_root = src/reviewsapp/media101reviewsapp_media_root = src/reviewsapp/media
102enable_artificial_oops = False102enable_artificial_oops = False
103modify_window_minutes = 120
103104
104[sso_api]105[sso_api]
105sso_api_service_root = https://login.staging.ubuntu.com/api/1.0106sso_api_service_root = https://login.staging.ubuntu.com/api/1.0
106107
=== modified file 'django_project/config_dev/schema.py'
--- django_project/config_dev/schema.py 2011-04-20 16:47:48 +0000
+++ django_project/config_dev/schema.py 2011-05-28 12:13:24 +0000
@@ -57,6 +57,7 @@
57 rnr.force_https_in_environment = BoolConfigOption()57 rnr.force_https_in_environment = BoolConfigOption()
58 rnr.allow_multiple_reviews_for_testing = BoolConfigOption(default=False)58 rnr.allow_multiple_reviews_for_testing = BoolConfigOption(default=False)
59 rnr.enable_artificial_oops = BoolConfigOption()59 rnr.enable_artificial_oops = BoolConfigOption()
60 rnr.modify_window_minutes = IntConfigOption()
6061
61 # Launchpad62 # Launchpad
62 launchpad = ConfigSection()63 launchpad = ConfigSection()
6364
=== modified file 'src/reviewsapp/api/handlers.py'
--- src/reviewsapp/api/handlers.py 2011-05-05 14:32:04 +0000
+++ src/reviewsapp/api/handlers.py 2011-05-28 12:13:24 +0000
@@ -26,6 +26,7 @@
26 'ServerStatusHandler',26 'ServerStatusHandler',
27 'ShowReviewsHandler',27 'ShowReviewsHandler',
28 'SubmitReviewHandler',28 'SubmitReviewHandler',
29 'ModifyReviewHandler',
29 'ShowUsefulnessHandler',30 'ShowUsefulnessHandler',
30 'DeleteReviewHandler',31 'DeleteReviewHandler',
31]32]
@@ -44,7 +45,7 @@
44from django.utils import simplejson45from django.utils import simplejson
45from piston.handler import BaseHandler46from piston.handler import BaseHandler
4647
47from reviewsapp.forms import ReviewForm48from reviewsapp.forms import ReviewForm, ReviewEditForm
48from reviewsapp.models import (49from reviewsapp.models import (
49 Repository,50 Repository,
50 Review,51 Review,
@@ -219,11 +220,7 @@
219 review = Review(reviewer=request.user)220 review = Review(reviewer=request.user)
220 form = ReviewForm(request.data, instance=review)221 form = ReviewForm(request.data, instance=review)
221 if not form.is_valid():222 if not form.is_valid():
222 errors = dict((key, [unicode(v) for v in values])223 return HttpResponseBadRequest(form.errors_json())
223 for (key, values) in form.errors.items())
224 response = simplejson.dumps({'errors': errors})
225 return HttpResponseBadRequest(response)
226
227 review = form.save()224 review = form.save()
228225
229 # Automatically flag when appropriate.226 # Automatically flag when appropriate.
@@ -239,11 +236,39 @@
239236
240 return review237 return review
241238
239class ModifyReviewHandler(BaseHandler):
240 allowed_methods = ('PUT',)
241
242 def update(self, request, review_id):
243 """Uses PUT verb to modify an existing review"""
244 review = get_object_or_404(Review, id=review_id, reviewer=request.user)
245
246
247 # check review modify window has not closed before allowing update
248 time_diff = datetime.utcnow() - review.date_created
249 time_limit = timedelta(minutes=settings.MODIFY_WINDOW_MINUTES)
250 if time_diff > time_limit:
251 return HttpResponseForbidden(
252 "This review cannot be edited (edit window expired).")
253 elif review.is_awaiting_moderation():
254 return HttpResponseForbidden(
255 "This review cannot be edited (pending moderation).")
256 else:
257 form = ReviewEditForm(request.POST, instance=review)
258 if not form.is_valid():
259 return HttpResponseBadRequest(form.errors_json())
260 else:
261 review = form.save()
262 review.softwareitem_in_repository.update_stats()
263 return review
264
265
242class DeleteReviewHandler(BaseHandler):266class DeleteReviewHandler(BaseHandler):
243 allowed_methods = ('POST',)267 allowed_methods = ('POST',)
244 268
245 def create(self, request, review_id):269 def create(self, request, review_id):
246 review = get_object_or_404(Review, id=review_id, reviewer=request.user, date_deleted=None)270 review = get_object_or_404(Review, id=review_id, reviewer=request.user,
271 date_deleted=None)
247 return review.delete()272 return review.delete()
248273
249class FlagReviewHandler(BaseHandler):274class FlagReviewHandler(BaseHandler):
250275
=== modified file 'src/reviewsapp/api/urls.py'
--- src/reviewsapp/api/urls.py 2011-05-05 12:35:58 +0000
+++ src/reviewsapp/api/urls.py 2011-05-28 12:13:24 +0000
@@ -31,7 +31,8 @@
31 SubmitUsefulnessHandler,31 SubmitUsefulnessHandler,
32 RetrieveReviewHandler,32 RetrieveReviewHandler,
33 ShowUsefulnessHandler,33 ShowUsefulnessHandler,
34 DeleteReviewHandler34 DeleteReviewHandler,
35 ModifyReviewHandler,
35)36)
36from reviewsapp.auth import SSOOAuthAuthentication37from reviewsapp.auth import SSOOAuthAuthentication
37from reviewsapp.api.decorators import dont_vary38from reviewsapp.api.decorators import dont_vary
@@ -69,6 +70,8 @@
69# The following POST handlers have POST data and will not be cached.70# The following POST handlers have POST data and will not be cached.
70submit_review_resource = Resource(handler=SubmitReviewHandler,71submit_review_resource = Resource(handler=SubmitReviewHandler,
71 authentication=auth)72 authentication=auth)
73modify_review_resource = Resource(handler=ModifyReviewHandler,
74 authentication=auth)
72flag_review_resource = Resource(handler=FlagReviewHandler,75flag_review_resource = Resource(handler=FlagReviewHandler,
73 authentication=auth)76 authentication=auth)
74submit_usefulness_resource = Resource(handler=SubmitUsefulnessHandler,77submit_usefulness_resource = Resource(handler=SubmitUsefulnessHandler,
@@ -133,6 +136,11 @@
133 # submits a new review for a given pkg/app136 # submits a new review for a given pkg/app
134 # POST /1.0/reviews/137 # POST /1.0/reviews/
135 url(r'^1.0/reviews/$', submit_review_resource, name='rnr-api-reviews'),138 url(r'^1.0/reviews/$', submit_review_resource, name='rnr-api-reviews'),
139
140 # modifies an existing review
141 # PUT /1.0/reviews/modify/100
142 url(r'^1.0/reviews/modify/(?P<review_id>\d+)/$',
143 modify_review_resource, name='rnr-api-modify-review'),
136144
137 # flag inappropriate reviews145 # flag inappropriate reviews
138 # POST /1.0/reviews/1/+report-review/146 # POST /1.0/reviews/1/+report-review/
139147
=== modified file 'src/reviewsapp/forms.py'
--- src/reviewsapp/forms.py 2011-05-05 12:35:58 +0000
+++ src/reviewsapp/forms.py 2011-05-28 12:13:24 +0000
@@ -24,6 +24,7 @@
24__all__ = [24__all__ = [
25 'ReviewModerationFilterForm',25 'ReviewModerationFilterForm',
26 'ReviewModerationModerateForm',26 'ReviewModerationModerateForm',
27 'ReviewEditForm',
27 'ReviewForm',28 'ReviewForm',
28 ]29 ]
2930
@@ -31,6 +32,7 @@
31from django.conf import settings32from django.conf import settings
32from django.db.models import Count33from django.db.models import Count
33from django.utils.translation import ugettext_lazy as _34from django.utils.translation import ugettext_lazy as _
35from django.utils import simplejson
3436
35from reviewsapp.models import (37from reviewsapp.models import (
36 Architecture,38 Architecture,
@@ -43,6 +45,13 @@
43from reviewsapp.widgets import MultipleSubmitButton45from reviewsapp.widgets import MultipleSubmitButton
4446
4547
48class JSONErrorMixin(object):
49 def errors_json(self):
50 errs = dict((key, [unicode(v) for v in values])
51 for (key, values) in self.errors.items())
52 return simplejson.dumps({'errors': errs})
53
54
46class ReviewModerationModerateForm(forms.Form):55class ReviewModerationModerateForm(forms.Form):
47 """A simple form that can display itself."""56 """A simple form that can display itself."""
48 moderation_text = forms.CharField(required=False)57 moderation_text = forms.CharField(required=False)
@@ -53,7 +62,13 @@
53 coerce=int)62 coerce=int)
5463
5564
56class ReviewForm(forms.ModelForm):65class ReviewEditForm(forms.ModelForm, JSONErrorMixin):
66 class Meta:
67 model = Review
68 fields = ('summary', 'review_text', 'rating')
69
70
71class ReviewForm(forms.ModelForm, JSONErrorMixin):
5772
58 # The following extra fields are used to calculate their model73 # The following extra fields are used to calculate their model
59 # equivalents.74 # equivalents.
6075
=== modified file 'src/reviewsapp/models/reviews.py'
--- src/reviewsapp/models/reviews.py 2011-05-06 01:17:56 +0000
+++ src/reviewsapp/models/reviews.py 2011-05-28 12:13:24 +0000
@@ -342,6 +342,14 @@
342 def reviewer_displayname(self):342 def reviewer_displayname(self):
343 return self.reviewer.get_full_name()343 return self.reviewer.get_full_name()
344 344
345 def is_awaiting_moderation(self):
346 """Return true if the review has any pending moderations"""
347 moderations = self.reviewmoderation_set.filter(
348 status=ReviewModeration.PENDING_STATUS).count()
349 if moderations == 0:
350 return False
351 return True
352
345 def delete(self):353 def delete(self):
346 """Delete a review submitted by the user"""354 """Delete a review submitted by the user"""
347 self.hide = True355 self.hide = True
348356
=== modified file 'src/reviewsapp/tests/test_handlers.py'
--- src/reviewsapp/tests/test_handlers.py 2011-05-06 01:17:56 +0000
+++ src/reviewsapp/tests/test_handlers.py 2011-05-28 12:13:24 +0000
@@ -26,6 +26,7 @@
26 'ServerStatusHandlerTestCase',26 'ServerStatusHandlerTestCase',
27 'ShowReviewsHandlerTestCase',27 'ShowReviewsHandlerTestCase',
28 'SubmitReviewHandlerTestCase',28 'SubmitReviewHandlerTestCase',
29 'ModifyReviewHandlerTestCase',
29 'UsefulnessHandlerTestCase',30 'UsefulnessHandlerTestCase',
30 'ShowUsefulnessHandlerTestCase',31 'ShowUsefulnessHandlerTestCase',
31 'DeleteReviewHandlerTestCase',32 'DeleteReviewHandlerTestCase',
@@ -53,7 +54,8 @@
53 ShowReviewsHandler,54 ShowReviewsHandler,
54 SubmitUsefulnessHandler,55 SubmitUsefulnessHandler,
55 ShowUsefulnessHandler,56 ShowUsefulnessHandler,
56 DeleteReviewHandler57 DeleteReviewHandler,
58 ModifyReviewHandler,
57)59)
58from reviewsapp.models import (60from reviewsapp.models import (
59 Repository,61 Repository,
@@ -840,6 +842,86 @@
840 self.assertEqual(httplib.OK, first.status_code)842 self.assertEqual(httplib.OK, first.status_code)
841 self.assertEqual(httplib.OK, second.status_code)843 self.assertEqual(httplib.OK, second.status_code)
842844
845class ModifyReviewHandlerTestCase(TestCaseWithFactory):
846
847 post_data = {'rating':4, 'summary':'summary','review_text':'text'}
848 bad_post_data = {'summary':'summary','review_text':'text'}
849 oversize_post_data = {'rating': 4,'summary':'a'*82,'review_text':'text'}
850
851 def _modify_review_id(self, review_id, post_data, user=None):
852 if user is None:
853 user = self.factory.makeUser()
854 request = Mock()
855 request.POST = post_data
856 request.user = user
857 handler = ModifyReviewHandler()
858 return handler.update(request, review_id)
859
860 def test_modify_review(self):
861 review = self.factory.makeReview()
862 response = self._modify_review_id(review.id, self.post_data,
863 review.reviewer)
864 review_reloaded = Review.objects.get(id=review.id)
865 self.assertEqual(review.id, response.id)
866 self.assertEqual(self.post_data['rating'], response.rating)
867 self.assertEqual(self.post_data['summary'], response.summary)
868 self.assertEqual(self.post_data['review_text'], response.review_text)
869
870 def test_non_existent_review(self):
871 review = self.factory.makeReview()
872 self.assertRaises(Http404, self._modify_review_id, review.id+1,
873 self.post_data, review.reviewer)
874
875 def test_wrong_user(self):
876 review = self.factory.makeReview()
877 wrong_user = self.factory.makeUser(username='modifier')
878 self.assertRaises(Http404, self._modify_review_id, review.id,
879 self.post_data, wrong_user)
880
881 def test_invalid_data_modify_fails(self):
882 review = self.factory.makeReview()
883 #missing parameter
884 response = self._modify_review_id(review.id, self.bad_post_data, review.reviewer)
885 self.assertEqual(httplib.BAD_REQUEST, response.status_code)
886 #overlength field
887 response = self._modify_review_id(review.id, self.oversize_post_data,
888 review.reviewer)
889 self.assertEqual(httplib.BAD_REQUEST, response.status_code)
890
891 def test_review_awaiting_moderation_fails(self):
892 review_moderation = self.factory.makeReviewModeration()
893 review = review_moderation.review
894 response = self._modify_review_id(review.id, self.post_data,
895 review.reviewer)
896 self.assertEqual(httplib.FORBIDDEN, response.status_code)
897
898 def test_modify_time_limits(self):
899 old_time = datetime.utcnow() - timedelta(settings.MODIFY_WINDOW_MINUTES + 60)
900 review = self.factory.makeReview(date_created=old_time)
901 response = self._modify_review_id(review.id, self.post_data,
902 review.reviewer)
903 self.assertEqual(httplib.FORBIDDEN, response.status_code)
904
905 def test_stats_update_on_modify(self):
906 software_item = self.factory.makeSoftwareItem(package_name='compiz-core',
907 ratings_total=0,
908 ratings_average=0)
909 review = self.factory.makeReview(software_item=software_item, rating=2)
910 review2 = self.factory.makeReview(software_item=software_item, rating=4)
911 software_item = SoftwareItem.objects.get(id=software_item.id)
912
913 # 2 reviews with ratings of 2 + 4 = 6 (average of 3)
914 self.assertEqual(2, software_item.ratings_total)
915 self.assertEqual(3, software_item.ratings_average)
916
917 self._modify_review_id(review.id, self.post_data, review.reviewer)
918 software_item = SoftwareItem.objects.get(id=software_item.id)
919
920 # 2 reviews with ratings of 4 + 4 = 8 (average of 4)
921 self.assertEqual(2, software_item.ratings_total)
922 self.assertEqual(4, software_item.ratings_average)
923
924
843class DeleteReviewHandlerTestCase(TestCaseWithFactory):925class DeleteReviewHandlerTestCase(TestCaseWithFactory):
844 def _delete_review_id(self, review_id, user=None):926 def _delete_review_id(self, review_id, user=None):
845 if user is None:927 if user is None:
846928
=== modified file 'src/reviewsapp/tests/test_models.py'
--- src/reviewsapp/tests/test_models.py 2011-03-17 14:29:54 +0000
+++ src/reviewsapp/tests/test_models.py 2011-05-28 12:13:24 +0000
@@ -106,6 +106,16 @@
106 self.assertEqual(106 self.assertEqual(
107 u'lang: en, rating: 4, summary: \ufffdA summary\n'107 u'lang: en, rating: 4, summary: \ufffdA summary\n'
108 u'\ufffdA review', unicode(review))108 u'\ufffdA review', unicode(review))
109
110 def test_pending_moderation(self):
111 review = self.factory.makeReview()
112 result = review.is_awaiting_moderation()
113 self.assertEqual(False, result)
114
115 review_moderation = self.factory.makeReviewModeration()
116 review = review_moderation.review
117 result = review.is_awaiting_moderation()
118 self.assertEqual(True, result)
109119
110120
111class ReviewFlagTestCase(TestCaseWithFactory):121class ReviewFlagTestCase(TestCaseWithFactory):
112122
=== modified file 'src/reviewsapp/tests/test_rnrclient.py'
--- src/reviewsapp/tests/test_rnrclient.py 2011-05-05 14:32:04 +0000
+++ src/reviewsapp/tests/test_rnrclient.py 2011-05-28 12:13:24 +0000
@@ -29,6 +29,7 @@
29 'RnRReviewStatsTestCase',29 'RnRReviewStatsTestCase',
30 'RnRServerStatusTestCase',30 'RnRServerStatusTestCase',
31 'RnRSubmitReviewTestCase',31 'RnRSubmitReviewTestCase',
32 'RnRModifyReviewTestCase',
32 'RnRDeleteReviewTestCase',33 'RnRDeleteReviewTestCase',
33 'UsefulnessAPITestCase',34 'UsefulnessAPITestCase',
34 ]35 ]
@@ -248,30 +249,63 @@
248 invalidate_paginated_reviews_for(review)249 invalidate_paginated_reviews_for(review)
249250
250class RnRDeleteReviewTestCase(RnRTxBaseTestCase):251class RnRDeleteReviewTestCase(RnRTxBaseTestCase):
251 252
252 def test_delete_review(self):253 def test_delete_review(self):
253 user = self.factory.makeUser()254 user = self.factory.makeUser()
254 review = self.factory.makeReview(reviewer=user)255 review = self.factory.makeReview(reviewer=user)
255 token, consumer = self.factory.makeOAuthTokenAndConsumer(user=user)256 token, consumer = self.factory.makeOAuthTokenAndConsumer(user=user)
256 257
257 auth = OAuthAuthorizer(token.token, token.token_secret, consumer.key,258 auth = OAuthAuthorizer(token.token, token.token_secret, consumer.key,
258 consumer.secret) 259 consumer.secret)
259260
260 lp_verify_packagename_method = (261 lp_verify_packagename_method = (
261 'reviewsapp.utilities.WebServices.'262 'reviewsapp.utilities.WebServices.'
262 'lp_verify_packagename_in_repository')263 'lp_verify_packagename_in_repository')
263 264
264 mock_verify_package = Mock()265 mock_verify_package = Mock()
265 mock_verify_package.return_value = True266 mock_verify_package.return_value = True
266267
267 api = RatingsAndReviewsAPI(auth=auth)268 api = RatingsAndReviewsAPI(auth=auth)
268 269
269 with patch(lp_verify_packagename_method, mock_verify_package):270 with patch(lp_verify_packagename_method, mock_verify_package):
270 response = api.delete_review(review_id=review.id)271 response = api.delete_review(review_id=review.id)
271272
272 self.assertEqual(review.id, response['id'])273 self.assertEqual(review.id, response['id'])
273 self.assertNotEqual(None, response['date_deleted'])274 self.assertNotEqual(None, response['date_deleted'])
274275
276class RnRModifyReviewTestCase(RnRTxBaseTestCase):
277 def test_modify_review(self):
278 user = self.factory.makeUser()
279 review = self.factory.makeReview(reviewer=user)
280 token, consumer = self.factory.makeOAuthTokenAndConsumer(user=user)
281
282 auth = OAuthAuthorizer(token.token, token.token_secret, consumer.key,
283 consumer.secret)
284
285 lp_verify_packagename_method = (
286 'reviewsapp.utilities.WebServices.'
287 'lp_verify_packagename_in_repository')
288
289 mock_verify_package = Mock()
290 mock_verify_package.return_value = True
291
292 api = RatingsAndReviewsAPI(auth=auth)
293
294 rating = 4
295 summary = 'summary'
296 review_text = 'review text'
297
298 with patch(lp_verify_packagename_method, mock_verify_package):
299 response = api.modify_review(review_id=review.id,
300 rating=rating,
301 summary=summary,
302 review_text=review_text)
303
304 self.assertEqual(review.id, response.id)
305 self.assertEqual(rating, response.rating)
306 self.assertEqual(summary, response.summary)
307 self.assertEqual(review_text, response.review_text)
308
275309
276class RnRSubmitReviewTestCase(RnRTxBaseTestCase):310class RnRSubmitReviewTestCase(RnRTxBaseTestCase):
277311

Subscribers

People subscribed via source and target branches