Commit | Line | Data |
---|---|---|
57c6473a JW |
1 | # GNU MediaGoblin -- federated, autonomous media hosting |
2 | # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. | |
3 | # | |
4 | # This program is free software: you can redistribute it and/or modify | |
5 | # it under the terms of the GNU Affero General Public License as published by | |
6 | # the Free Software Foundation, either version 3 of the License, or | |
7 | # (at your option) any later version. | |
8 | # | |
9 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU Affero General Public License for more details. | |
13 | # | |
14 | # You should have received a copy of the GNU Affero General Public License | |
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
ee9956c3 | 16 | import json |
57c6473a | 17 | |
3a02813c CAW |
18 | try: |
19 | import mock | |
20 | except ImportError: | |
21 | import unittest.mock as mock | |
5c2ece74 CAW |
22 | import pytest |
23 | ||
967df5ef JT |
24 | from webtest import AppError |
25 | ||
247a3b78 | 26 | from .resources import GOOD_JPG |
57c6473a | 27 | from mediagoblin import mg_globals |
8d75091d | 28 | from mediagoblin.db.models import User, MediaEntry, MediaComment |
9c602458 | 29 | from mediagoblin.tools.routing import extract_url_arguments |
5c2ece74 | 30 | from mediagoblin.tests.tools import fixture_add_user |
ee9956c3 | 31 | from mediagoblin.moderation.tools import take_away_privileges |
57c6473a | 32 | |
57c6473a | 33 | class TestAPI(object): |
a14d90c2 | 34 | """ Test mediagoblin's pump.io complient APIs """ |
57c6473a | 35 | |
ee9956c3 JT |
36 | @pytest.fixture(autouse=True) |
37 | def setup(self, test_app): | |
38 | self.test_app = test_app | |
57c6473a | 39 | self.db = mg_globals.database |
57c6473a | 40 | |
5e5d4458 | 41 | self.user = fixture_add_user(privileges=[u'active', u'uploader', u'commenter']) |
8917ffb1 JT |
42 | self.other_user = fixture_add_user( |
43 | username="otheruser", | |
44 | privileges=[u'active', u'uploader', u'commenter'] | |
45 | ) | |
9246a6ba | 46 | self.active_user = self.user |
57c6473a | 47 | |
51ab5192 JT |
48 | def _activity_to_feed(self, test_app, activity, headers=None): |
49 | """ Posts an activity to the user's feed """ | |
50 | if headers: | |
51 | headers.setdefault("Content-Type", "application/json") | |
52 | else: | |
53 | headers = {"Content-Type": "application/json"} | |
54 | ||
9246a6ba | 55 | with self.mock_oauth(): |
51ab5192 | 56 | response = test_app.post( |
9246a6ba | 57 | "/api/user/{0}/feed".format(self.active_user.username), |
51ab5192 JT |
58 | json.dumps(activity), |
59 | headers=headers | |
60 | ) | |
61 | ||
21cbf829 | 62 | return response, json.loads(response.body.decode()) |
51ab5192 JT |
63 | |
64 | def _upload_image(self, test_app, image): | |
65 | """ Uploads and image to MediaGoblin via pump.io API """ | |
66 | data = open(image, "rb").read() | |
67 | headers = { | |
68 | "Content-Type": "image/jpeg", | |
69 | "Content-Length": str(len(data)) | |
70 | } | |
71 | ||
72 | ||
9246a6ba | 73 | with self.mock_oauth(): |
51ab5192 | 74 | response = test_app.post( |
9246a6ba | 75 | "/api/user/{0}/uploads".format(self.active_user.username), |
51ab5192 JT |
76 | data, |
77 | headers=headers | |
78 | ) | |
21cbf829 | 79 | image = json.loads(response.body.decode()) |
51ab5192 JT |
80 | |
81 | return response, image | |
82 | ||
83 | def _post_image_to_feed(self, test_app, image): | |
84 | """ Posts an already uploaded image to feed """ | |
85 | activity = { | |
86 | "verb": "post", | |
87 | "object": image, | |
88 | } | |
89 | ||
90 | return self._activity_to_feed(test_app, activity) | |
91 | ||
967df5ef JT |
92 | def mocked_oauth_required(self, *args, **kwargs): |
93 | """ Mocks mediagoblin.decorator.oauth_required to always validate """ | |
94 | ||
95 | def fake_controller(controller, request, *args, **kwargs): | |
9246a6ba | 96 | request.user = User.query.filter_by(id=self.active_user.id).first() |
967df5ef JT |
97 | return controller(request, *args, **kwargs) |
98 | ||
99 | def oauth_required(c): | |
100 | return lambda *args, **kwargs: fake_controller(c, *args, **kwargs) | |
101 | ||
102 | return oauth_required | |
103 | ||
9246a6ba JT |
104 | def mock_oauth(self): |
105 | """ Returns a mock.patch for the oauth_required decorator """ | |
106 | return mock.patch( | |
107 | target="mediagoblin.decorators.oauth_required", | |
108 | new_callable=self.mocked_oauth_required | |
109 | ) | |
110 | ||
ee9956c3 JT |
111 | def test_can_post_image(self, test_app): |
112 | """ Tests that an image can be posted to the API """ | |
113 | # First request we need to do is to upload the image | |
51ab5192 | 114 | response, image = self._upload_image(test_app, GOOD_JPG) |
ee9956c3 | 115 | |
51ab5192 JT |
116 | # I should have got certain things back |
117 | assert response.status_code == 200 | |
ee9956c3 | 118 | |
51ab5192 JT |
119 | assert "id" in image |
120 | assert "fullImage" in image | |
121 | assert "url" in image["fullImage"] | |
122 | assert "url" in image | |
123 | assert "author" in image | |
124 | assert "published" in image | |
125 | assert "updated" in image | |
126 | assert image["objectType"] == "image" | |
247a3b78 | 127 | |
51ab5192 JT |
128 | # Check that we got the response we're expecting |
129 | response, _ = self._post_image_to_feed(test_app, image) | |
130 | assert response.status_code == 200 | |
8d75091d | 131 | |
8917ffb1 JT |
132 | def test_unable_to_upload_as_someone_else(self, test_app): |
133 | """ Test that can't upload as someoen else """ | |
134 | data = open(GOOD_JPG, "rb").read() | |
135 | headers = { | |
136 | "Content-Type": "image/jpeg", | |
137 | "Content-Length": str(len(data)) | |
138 | } | |
8d75091d | 139 | |
9246a6ba | 140 | with self.mock_oauth(): |
8917ffb1 JT |
141 | # Will be self.user trying to upload as self.other_user |
142 | with pytest.raises(AppError) as excinfo: | |
143 | test_app.post( | |
144 | "/api/user/{0}/uploads".format(self.other_user.username), | |
145 | data, | |
146 | headers=headers | |
147 | ) | |
8d75091d | 148 | |
6430ae97 | 149 | assert "403 FORBIDDEN" in excinfo.value.args[0] |
8d75091d | 150 | |
8917ffb1 JT |
151 | def test_unable_to_post_feed_as_someone_else(self, test_app): |
152 | """ Tests that can't post an image to someone else's feed """ | |
153 | response, data = self._upload_image(test_app, GOOD_JPG) | |
8d75091d | 154 | |
8917ffb1 JT |
155 | activity = { |
156 | "verb": "post", | |
157 | "object": data | |
158 | } | |
8d75091d | 159 | |
8917ffb1 JT |
160 | headers = { |
161 | "Content-Type": "application/json", | |
162 | } | |
8d75091d | 163 | |
9246a6ba | 164 | with self.mock_oauth(): |
8917ffb1 JT |
165 | with pytest.raises(AppError) as excinfo: |
166 | test_app.post( | |
167 | "/api/user/{0}/feed".format(self.other_user.username), | |
168 | json.dumps(activity), | |
169 | headers=headers | |
170 | ) | |
8d75091d | 171 | |
6430ae97 | 172 | assert "403 FORBIDDEN" in excinfo.value.args[0] |
8d75091d JT |
173 | |
174 | def test_only_able_to_update_own_image(self, test_app): | |
175 | """ Test's that the uploader is the only person who can update an image """ | |
176 | response, data = self._upload_image(test_app, GOOD_JPG) | |
177 | response, data = self._post_image_to_feed(test_app, data) | |
178 | ||
179 | activity = { | |
180 | "verb": "update", | |
181 | "object": data["object"], | |
182 | } | |
183 | ||
184 | headers = { | |
185 | "Content-Type": "application/json", | |
186 | } | |
187 | ||
188 | # Lets change the image uploader to be self.other_user, this is easier | |
189 | # than uploading the image as someone else as the way self.mocked_oauth_required | |
190 | # and self._upload_image. | |
c7c26b17 | 191 | id = int(data["object"]["id"].split("/")[-2]) |
9c602458 | 192 | media = MediaEntry.query.filter_by(id=id).first() |
8d75091d JT |
193 | media.uploader = self.other_user.id |
194 | media.save() | |
195 | ||
196 | # Now lets try and edit the image as self.user, this should produce a 403 error. | |
9246a6ba | 197 | with self.mock_oauth(): |
8d75091d JT |
198 | with pytest.raises(AppError) as excinfo: |
199 | test_app.post( | |
200 | "/api/user/{0}/feed".format(self.user.username), | |
201 | json.dumps(activity), | |
202 | headers=headers | |
203 | ) | |
204 | ||
6430ae97 | 205 | assert "403 FORBIDDEN" in excinfo.value.args[0] |
57c6473a | 206 | |
51ab5192 JT |
207 | def test_upload_image_with_filename(self, test_app): |
208 | """ Tests that you can upload an image with filename and description """ | |
209 | response, data = self._upload_image(test_app, GOOD_JPG) | |
210 | response, data = self._post_image_to_feed(test_app, data) | |
ee9956c3 | 211 | |
51ab5192 JT |
212 | image = data["object"] |
213 | ||
214 | # Now we need to add a title and description | |
215 | title = "My image ^_^" | |
216 | description = "This is my super awesome image :D" | |
217 | license = "CC-BY-SA" | |
218 | ||
219 | image["displayName"] = title | |
220 | image["content"] = description | |
221 | image["license"] = license | |
222 | ||
223 | activity = {"verb": "update", "object": image} | |
224 | ||
9246a6ba | 225 | with self.mock_oauth(): |
ee9956c3 JT |
226 | response = test_app.post( |
227 | "/api/user/{0}/feed".format(self.user.username), | |
51ab5192 JT |
228 | json.dumps(activity), |
229 | headers={"Content-Type": "application/json"} | |
ee9956c3 JT |
230 | ) |
231 | ||
21cbf829 | 232 | image = json.loads(response.body.decode())["object"] |
51ab5192 JT |
233 | |
234 | # Check everything has been set on the media correctly | |
c7c26b17 | 235 | id = int(image["id"].split("/")[-2]) |
9c602458 | 236 | media = MediaEntry.query.filter_by(id=id).first() |
51ab5192 JT |
237 | assert media.title == title |
238 | assert media.description == description | |
239 | assert media.license == license | |
240 | ||
241 | # Check we're being given back everything we should on an update | |
c7c26b17 | 242 | assert int(image["id"].split("/")[-2]) == media.id |
51ab5192 JT |
243 | assert image["displayName"] == title |
244 | assert image["content"] == description | |
245 | assert image["license"] == license | |
246 | ||
ee9956c3 JT |
247 | |
248 | def test_only_uploaders_post_image(self, test_app): | |
249 | """ Test that only uploaders can upload images """ | |
250 | # Remove uploader permissions from user | |
251 | take_away_privileges(self.user.username, u"uploader") | |
252 | ||
253 | # Now try and upload a image | |
254 | data = open(GOOD_JPG, "rb").read() | |
255 | headers = { | |
256 | "Content-Type": "image/jpeg", | |
257 | "Content-Length": str(len(data)), | |
258 | } | |
259 | ||
9246a6ba | 260 | with self.mock_oauth(): |
967df5ef | 261 | with pytest.raises(AppError) as excinfo: |
a14d90c2 | 262 | test_app.post( |
967df5ef JT |
263 | "/api/user/{0}/uploads".format(self.user.username), |
264 | data, | |
265 | headers=headers | |
266 | ) | |
57c6473a | 267 | |
ee9956c3 | 268 | # Assert that we've got a 403 |
6430ae97 | 269 | assert "403 FORBIDDEN" in excinfo.value.args[0] |
51ab5192 | 270 | |
3c8bd177 JT |
271 | def test_object_endpoint(self, test_app): |
272 | """ Tests that object can be looked up at endpoint """ | |
273 | # Post an image | |
274 | response, data = self._upload_image(test_app, GOOD_JPG) | |
275 | response, data = self._post_image_to_feed(test_app, data) | |
276 | ||
277 | # Now lookup image to check that endpoint works. | |
278 | image = data["object"] | |
279 | ||
280 | assert "links" in image | |
281 | assert "self" in image["links"] | |
282 | ||
283 | # Get URI and strip testing host off | |
284 | object_uri = image["links"]["self"]["href"] | |
285 | object_uri = object_uri.replace("http://localhost:80", "") | |
286 | ||
9246a6ba | 287 | with self.mock_oauth(): |
3c8bd177 JT |
288 | request = test_app.get(object_uri) |
289 | ||
1db2bd3f | 290 | image = json.loads(request.body.decode()) |
c7c26b17 | 291 | entry_id = int(image["id"].split("/")[-2]) |
9c602458 | 292 | entry = MediaEntry.query.filter_by(id=entry_id).first() |
3c8bd177 JT |
293 | |
294 | assert request.status_code == 200 | |
3c8bd177 JT |
295 | |
296 | assert "image" in image | |
297 | assert "fullImage" in image | |
298 | assert "pump_io" in image | |
299 | assert "links" in image | |
51ab5192 JT |
300 | |
301 | def test_post_comment(self, test_app): | |
302 | """ Tests that I can post an comment media """ | |
303 | # Upload some media to comment on | |
304 | response, data = self._upload_image(test_app, GOOD_JPG) | |
305 | response, data = self._post_image_to_feed(test_app, data) | |
306 | ||
307 | content = "Hai this is a comment on this lovely picture ^_^" | |
308 | ||
309 | activity = { | |
310 | "verb": "post", | |
311 | "object": { | |
312 | "objectType": "comment", | |
313 | "content": content, | |
314 | "inReplyTo": data["object"], | |
315 | } | |
316 | } | |
317 | ||
318 | response, comment_data = self._activity_to_feed(test_app, activity) | |
319 | assert response.status_code == 200 | |
320 | ||
321 | # Find the objects in the database | |
c7c26b17 | 322 | media_id = int(data["object"]["id"].split("/")[-2]) |
9c602458 | 323 | media = MediaEntry.query.filter_by(id=media_id).first() |
51ab5192 JT |
324 | comment = media.get_comments()[0] |
325 | ||
326 | # Tests that it matches in the database | |
327 | assert comment.author == self.user.id | |
328 | assert comment.content == content | |
329 | ||
330 | # Test that the response is what we should be given | |
51ab5192 | 331 | assert comment.content == comment_data["object"]["content"] |
8d75091d | 332 | |
8917ffb1 JT |
333 | def test_unable_to_post_comment_as_someone_else(self, test_app): |
334 | """ Tests that you're unable to post a comment as someone else. """ | |
335 | # Upload some media to comment on | |
336 | response, data = self._upload_image(test_app, GOOD_JPG) | |
337 | response, data = self._post_image_to_feed(test_app, data) | |
8d75091d | 338 | |
8917ffb1 JT |
339 | activity = { |
340 | "verb": "post", | |
341 | "object": { | |
342 | "objectType": "comment", | |
343 | "content": "comment commenty comment ^_^", | |
344 | "inReplyTo": data["object"], | |
345 | } | |
346 | } | |
8d75091d | 347 | |
8917ffb1 JT |
348 | headers = { |
349 | "Content-Type": "application/json", | |
350 | } | |
8d75091d | 351 | |
9246a6ba | 352 | with self.mock_oauth(): |
8917ffb1 JT |
353 | with pytest.raises(AppError) as excinfo: |
354 | test_app.post( | |
355 | "/api/user/{0}/feed".format(self.other_user.username), | |
356 | json.dumps(activity), | |
357 | headers=headers | |
358 | ) | |
8d75091d | 359 | |
6430ae97 | 360 | assert "403 FORBIDDEN" in excinfo.value.args[0] |
8917ffb1 | 361 | |
8d75091d JT |
362 | def test_unable_to_update_someone_elses_comment(self, test_app): |
363 | """ Test that you're able to update someoen elses comment. """ | |
364 | # Upload some media to comment on | |
365 | response, data = self._upload_image(test_app, GOOD_JPG) | |
366 | response, data = self._post_image_to_feed(test_app, data) | |
367 | ||
368 | activity = { | |
369 | "verb": "post", | |
370 | "object": { | |
371 | "objectType": "comment", | |
372 | "content": "comment commenty comment ^_^", | |
373 | "inReplyTo": data["object"], | |
374 | } | |
375 | } | |
376 | ||
377 | headers = { | |
378 | "Content-Type": "application/json", | |
379 | } | |
380 | ||
381 | # Post the comment. | |
382 | response, comment_data = self._activity_to_feed(test_app, activity) | |
383 | ||
384 | # change who uploaded the comment as it's easier than changing | |
c7c26b17 | 385 | comment_id = int(comment_data["object"]["id"].split("/")[-2]) |
8d75091d JT |
386 | comment = MediaComment.query.filter_by(id=comment_id).first() |
387 | comment.author = self.other_user.id | |
9246a6ba | 388 | comment.save() |
8d75091d JT |
389 | |
390 | # Update the comment as someone else. | |
391 | comment_data["object"]["content"] = "Yep" | |
392 | activity = { | |
393 | "verb": "update", | |
394 | "object": comment_data["object"] | |
395 | } | |
396 | ||
9246a6ba | 397 | with self.mock_oauth(): |
8d75091d JT |
398 | with pytest.raises(AppError) as excinfo: |
399 | test_app.post( | |
400 | "/api/user/{0}/feed".format(self.user.username), | |
401 | json.dumps(activity), | |
402 | headers=headers | |
403 | ) | |
404 | ||
6430ae97 | 405 | assert "403 FORBIDDEN" in excinfo.value.args[0] |
51ab5192 JT |
406 | |
407 | def test_profile(self, test_app): | |
408 | """ Tests profile endpoint """ | |
409 | uri = "/api/user/{0}/profile".format(self.user.username) | |
9246a6ba | 410 | with self.mock_oauth(): |
51ab5192 | 411 | response = test_app.get(uri) |
21cbf829 | 412 | profile = json.loads(response.body.decode()) |
51ab5192 JT |
413 | |
414 | assert response.status_code == 200 | |
415 | ||
416 | assert profile["preferredUsername"] == self.user.username | |
417 | assert profile["objectType"] == "person" | |
418 | ||
419 | assert "links" in profile | |
8ac7a653 | 420 | |
9246a6ba JT |
421 | def test_user(self, test_app): |
422 | """ Test the user endpoint """ | |
423 | uri = "/api/user/{0}/".format(self.user.username) | |
424 | with self.mock_oauth(): | |
425 | response = test_app.get(uri) | |
21cbf829 | 426 | user = json.loads(response.body.decode()) |
57c6473a | 427 | |
9246a6ba | 428 | assert response.status_code == 200 |
57c6473a | 429 | |
9246a6ba JT |
430 | assert user["nickname"] == self.user.username |
431 | assert user["updated"] == self.user.created.isoformat() | |
432 | assert user["published"] == self.user.created.isoformat() | |
57c6473a | 433 | |
9246a6ba JT |
434 | # Test profile exists but self.test_profile will test the value |
435 | assert "profile" in response | |
57c6473a | 436 | |
5e5d4458 JT |
437 | def test_whoami_without_login(self, test_app): |
438 | """ Test that whoami endpoint returns error when not logged in """ | |
439 | with pytest.raises(AppError) as excinfo: | |
440 | response = test_app.get("/api/whoami") | |
57c6473a | 441 | |
6430ae97 | 442 | assert "401 UNAUTHORIZED" in excinfo.value.args[0] |
57c6473a | 443 | |
9246a6ba JT |
444 | def test_read_feed(self, test_app): |
445 | """ Test able to read objects from the feed """ | |
446 | response, data = self._upload_image(test_app, GOOD_JPG) | |
447 | response, data = self._post_image_to_feed(test_app, data) | |
57c6473a | 448 | |
9246a6ba JT |
449 | uri = "/api/user/{0}/feed".format(self.active_user.username) |
450 | with self.mock_oauth(): | |
451 | response = test_app.get(uri) | |
21cbf829 | 452 | feed = json.loads(response.body.decode()) |
57c6473a | 453 | |
9246a6ba | 454 | assert response.status_code == 200 |
57c6473a | 455 | |
9246a6ba JT |
456 | # Check it has the attributes it should |
457 | assert "displayName" in feed | |
458 | assert "objectTypes" in feed | |
459 | assert "url" in feed | |
460 | assert "links" in feed | |
461 | assert "author" in feed | |
462 | assert "items" in feed | |
57c6473a | 463 | |
9246a6ba JT |
464 | # Check that image i uploaded is there |
465 | assert feed["items"][0]["verb"] == "post" | |
466 | assert feed["items"][0]["actor"] | |
57c6473a | 467 | |
9246a6ba JT |
468 | def test_cant_post_to_someone_elses_feed(self, test_app): |
469 | """ Test that can't post to someone elses feed """ | |
470 | response, data = self._upload_image(test_app, GOOD_JPG) | |
471 | self.active_user = self.other_user | |
57c6473a | 472 | |
9246a6ba JT |
473 | with self.mock_oauth(): |
474 | with pytest.raises(AppError) as excinfo: | |
475 | self._post_image_to_feed(test_app, data) | |
57c6473a | 476 | |
6430ae97 | 477 | assert "403 FORBIDDEN" in excinfo.value.args[0] |
57c6473a | 478 | |
f6bad0eb | 479 | def test_object_endpoint_requestable(self, test_app): |
9246a6ba JT |
480 | """ Test that object endpoint can be requested """ |
481 | response, data = self._upload_image(test_app, GOOD_JPG) | |
482 | response, data = self._post_image_to_feed(test_app, data) | |
483 | object_id = data["object"]["id"] | |
57c6473a | 484 | |
9246a6ba JT |
485 | with self.mock_oauth(): |
486 | response = test_app.get(data["object"]["links"]["self"]["href"]) | |
21cbf829 | 487 | data = json.loads(response.body.decode()) |
57c6473a | 488 | |
9246a6ba | 489 | assert response.status_code == 200 |
57c6473a | 490 | |
9246a6ba JT |
491 | assert object_id == data["id"] |
492 | assert "url" in data | |
493 | assert "links" in data | |
494 | assert data["objectType"] == "image" | |
4dec1cd6 JT |
495 | |
496 | def test_delete_media_by_activity(self, test_app): | |
497 | """ Test that an image can be deleted by a delete activity to feed """ | |
498 | response, data = self._upload_image(test_app, GOOD_JPG) | |
499 | response, data = self._post_image_to_feed(test_app, data) | |
500 | object_id = data["object"]["id"] | |
501 | ||
502 | activity = { | |
503 | "verb": "delete", | |
504 | "object": { | |
505 | "id": object_id, | |
506 | "objectType": "image", | |
507 | } | |
508 | } | |
509 | ||
510 | response = self._activity_to_feed(test_app, activity)[1] | |
511 | ||
512 | # Check the media is no longer in the database | |
513 | media_id = int(object_id.split("/")[-2]) | |
514 | media = MediaEntry.query.filter_by(id=media_id).first() | |
515 | ||
516 | assert media is None | |
517 | ||
518 | # Check we've been given the full delete activity back | |
519 | assert "id" in response | |
520 | assert response["verb"] == "delete" | |
521 | assert "object" in response | |
522 | assert response["object"]["id"] == object_id | |
523 | assert response["object"]["objectType"] == "image" | |
524 | ||
525 | def test_delete_comment_by_activity(self, test_app): | |
526 | """ Test that a comment is deleted by a delete activity to feed """ | |
527 | # First upload an image to comment against | |
528 | response, data = self._upload_image(test_app, GOOD_JPG) | |
529 | response, data = self._post_image_to_feed(test_app, data) | |
530 | ||
531 | # Post a comment to delete | |
532 | activity = { | |
533 | "verb": "post", | |
534 | "object": { | |
535 | "objectType": "comment", | |
536 | "content": "This is a comment.", | |
537 | "inReplyTo": data["object"], | |
538 | } | |
539 | } | |
540 | ||
541 | comment = self._activity_to_feed(test_app, activity)[1] | |
542 | ||
543 | # Now delete the image | |
544 | activity = { | |
545 | "verb": "delete", | |
546 | "object": { | |
547 | "id": comment["object"]["id"], | |
548 | "objectType": "comment", | |
549 | } | |
550 | } | |
551 | ||
552 | delete = self._activity_to_feed(test_app, activity)[1] | |
553 | ||
554 | # Verify the comment no longer exists | |
555 | comment_id = int(comment["object"]["id"].split("/")[-2]) | |
556 | assert MediaComment.query.filter_by(id=comment_id).first() is None | |
557 | ||
558 | # Check we've got a delete activity back | |
559 | assert "id" in delete | |
560 | assert delete["verb"] == "delete" | |
561 | assert "object" in delete | |
562 | assert delete["object"]["id"] == comment["object"]["id"] | |
563 | assert delete["object"]["objectType"] == "comment" | |
9e715bb0 JT |
564 | |
565 | def test_edit_comment(self, test_app): | |
566 | """ Test that someone can update their own comment """ | |
567 | # First upload an image to comment against | |
568 | response, data = self._upload_image(test_app, GOOD_JPG) | |
569 | response, data = self._post_image_to_feed(test_app, data) | |
570 | ||
571 | # Post a comment to edit | |
572 | activity = { | |
573 | "verb": "post", | |
574 | "object": { | |
575 | "objectType": "comment", | |
576 | "content": "This is a comment", | |
577 | "inReplyTo": data["object"], | |
578 | } | |
579 | } | |
580 | ||
581 | comment = self._activity_to_feed(test_app, activity)[1] | |
582 | ||
583 | # Now create an update activity to change the content | |
584 | activity = { | |
585 | "verb": "update", | |
586 | "object": { | |
587 | "id": comment["object"]["id"], | |
588 | "content": "This is my fancy new content string!", | |
589 | "objectType": "comment", | |
590 | }, | |
591 | } | |
592 | ||
593 | comment = self._activity_to_feed(test_app, activity)[1] | |
594 | ||
595 | # Verify the comment reflects the changes | |
596 | comment_id = int(comment["object"]["id"].split("/")[-2]) | |
597 | model = MediaComment.query.filter_by(id=comment_id).first() | |
598 | ||
599 | assert model.content == activity["object"]["content"] | |
600 |