diff --git a/readthedocs/api/v3/mixins.py b/readthedocs/api/v3/mixins.py index 02be261b1e9..9db1091600a 100644 --- a/readthedocs/api/v3/mixins.py +++ b/readthedocs/api/v3/mixins.py @@ -94,8 +94,9 @@ def _get_parent_project(self): return get_object_or_404(Project, slug=slug) def _get_parent_build(self): - pk = self._get_parent_object_lookup(self.BUILD_LOOKUP_NAMES) - return get_object_or_404(Build, pk=pk) + project_slug = self._get_parent_object_lookup(self.PROJECT_LOOKUP_NAMES) + build_pk = self._get_parent_object_lookup(self.BUILD_LOOKUP_NAMES) + return get_object_or_404(Build, pk=build_pk, project__slug=project_slug) def _get_parent_version(self): project_slug = self._get_parent_object_lookup(self.PROJECT_LOOKUP_NAMES) diff --git a/readthedocs/api/v3/tests/mixins.py b/readthedocs/api/v3/tests/mixins.py index c1fb1de7dff..739008bcd2f 100644 --- a/readthedocs/api/v3/tests/mixins.py +++ b/readthedocs/api/v3/tests/mixins.py @@ -12,7 +12,7 @@ from rest_framework.authtoken.models import Token from rest_framework.test import APIClient -from readthedocs.builds.constants import TAG +from readthedocs.builds.constants import LATEST, TAG from readthedocs.builds.models import Build, Version from readthedocs.core.notifications import MESSAGE_EMAIL_VALIDATION_PENDING from readthedocs.doc_builder.exceptions import BuildCancelled @@ -98,6 +98,7 @@ def setUp(self): self.build = fixture.get( Build, + id=1, date=self.created, type="html", state="finished", @@ -125,6 +126,21 @@ def setUp(self): external_builds_privacy_level=PUBLIC, privacy_level=PUBLIC, ) + self.others_version = self.others_project.versions.get(slug=LATEST) + self.others_build = fixture.get( + Build, + date=self.created, + type="html", + state="finished", + error="", + success=True, + _config={"property": "test value"}, + version=self.others_version, + project=self.others_project, + builder="builder01", + commit="a1b2c3", + length=60, + ) # Make all non-html true so responses are complete self.project.versions.update( @@ -171,6 +187,13 @@ def setUp(self): message_id=MESSAGE_EMAIL_VALIDATION_PENDING, ) + self.notification_others_build = fixture.get( + Notification, + attached_to_content_type=ContentType.objects.get_for_model(Build), + attached_to_id=self.others_build.pk, + message_id=BuildCancelled.CANCELLED_BY_USER, + ) + self.client = APIClient() def tearDown(self): diff --git a/readthedocs/api/v3/tests/responses/projects-versions-builds-list_POST.json b/readthedocs/api/v3/tests/responses/projects-versions-builds-list_POST.json index e1d05ba0a9a..d434936ee6c 100644 --- a/readthedocs/api/v3/tests/responses/projects-versions-builds-list_POST.json +++ b/readthedocs/api/v3/tests/responses/projects-versions-builds-list_POST.json @@ -5,15 +5,15 @@ "duration": null, "error": "", "finished": null, - "id": 2, + "id": 3, "_links": { - "_self": "https://readthedocs.org/api/v3/projects/project/builds/2/", - "notifications": "https://readthedocs.org/api/v3/projects/project/builds/2/notifications/", + "_self": "https://readthedocs.org/api/v3/projects/project/builds/3/", + "notifications": "https://readthedocs.org/api/v3/projects/project/builds/3/notifications/", "project": "https://readthedocs.org/api/v3/projects/project/", "version": "https://readthedocs.org/api/v3/projects/project/versions/v1.0/" }, "urls": { - "build": "https://readthedocs.org/projects/project/builds/2/", + "build": "https://readthedocs.org/projects/project/builds/3/", "project": "https://readthedocs.org/projects/project/", "version": "https://readthedocs.org/dashboard/project/version/v1.0/edit/" }, diff --git a/readthedocs/api/v3/tests/test_builds.py b/readthedocs/api/v3/tests/test_builds.py index 2410d0c845e..abd1b89349d 100644 --- a/readthedocs/api/v3/tests/test_builds.py +++ b/readthedocs/api/v3/tests/test_builds.py @@ -149,6 +149,28 @@ def test_projects_builds_notifications_list_other_user(self): response = self.client.get(url) self.assertEqual(response.status_code, 403) + # User can see their own notifications. + url = reverse( + "projects-builds-notifications-list", + kwargs={ + "parent_lookup_project__slug": self.others_project.slug, + "parent_lookup_build__id": self.others_build.pk, + }, + ) + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + + # User can't see notifications from other users through his project. + url = reverse( + "projects-builds-notifications-list", + kwargs={ + "parent_lookup_project__slug": self.others_project.slug, + "parent_lookup_build__id": self.build.pk, + }, + ) + response = self.client.get(url) + self.assertEqual(response.status_code, 404) + def test_projects_builds_notifications_list_post(self): url = reverse( "projects-builds-notifications-list",