def test_viewpoint_search_city(self): list_url = reverse("terra_opp:viewpoint-list") city = CityFactory(label="Rouperou-le-coquet") city2 = CityFactory(label="New york") city3 = CityFactory(label="Los angeles") ViewpointFactory( label="Viewpoint for search", pictures__state="accepted", city=city, active=True, ) ViewpointFactory( label="Not found", pictures__state="accepted", city=city2, active=True, ) ViewpointFactory( label="Not found also", pictures__state="accepted", city=city3, active=True, ) self.assertEqual(self.client.get(list_url).json()["count"], 4) data = self.client.get(list_url, {"city_id": city.id}).json() self.assertEqual(data.get("count"), 1) data = self.client.get(list_url, {"city": "Rouperou-le-coquet"}).json() self.assertEqual(data.get("count"), 1)
def test_viewpoint_search_themes(self): list_url = reverse("terra_opp:viewpoint-list") theme_foo = ThemeFactory(label="foo") theme_bar = ThemeFactory(label="bar") theme_baz = ThemeFactory(label="baz") theme_not = ThemeFactory(label="not") vp = ViewpointFactory( label="Viewpoint for search", pictures__state="accepted", properties={ "voie": "coin d'en bas de la rue du bout", "site": "Carrière des petits violoncelles", }, active=True, ) vp.themes.add(theme_foo, theme_bar, theme_baz) self.assertEqual(self.client.get(list_url).json()["count"], 2) data = self.client.get(list_url, {"themes_id": [theme_foo.id]}).json() self.assertEqual(data.get("count"), 1) data = self.client.get(list_url, {"themes": ["foo"]}).json() self.assertEqual(data.get("count"), 1) data = self.client.get( list_url, {"themes_id": [theme_bar.id, theme_foo.id]} ).json() self.assertEqual(data.get("count"), 1) data = self.client.get( list_url, {"themes_id": [theme_bar.id, theme_not.id]} ).json() self.assertEqual(data.get("count"), 0)
def test_anonymous_options_request_returns_correct_search_filters(self): city1 = CityFactory(label="Montcuq") city2 = CityFactory(label="Rouperou-le-coquet") theme1 = ThemeFactory(label="Bar") theme2 = ThemeFactory(label="foo") ViewpointFactory( city=city1, themes=[theme1, theme2], ) ViewpointFactory( city=city2, themes=[theme1], ) data = self.client.get(reverse("terra_opp:viewpoint-filters")).json() self.assertEqual(data.get("cities"), ["Montcuq", "Rouperou-le-coquet"]) self.assertEqual(data.get("themes"), ["Bar", "foo"])
def setUpTestData(cls): cls.feature = FeatureFactory() cls.user = TerraUserFactory() # Create viewpoint with draft picture attached to it cls.viewpoint = ViewpointFactory(label="Basic viewpoint") # Create viewpoint with accepted picture attached to it cls.viewpoint_with_accepted_picture = ViewpointFactory( label="Viewpoint with accepted picture", pictures__state="accepted", properties={"test_update": "ko"}, active=True, ) # Create viewpoints with no picture attached to it cls.viewpoint_without_picture = ViewpointFactory( label="Viewpoint without picture", pictures=None, properties={"test_update": "ko"}, )
def test_post_campaign(self): data = { "label": "My campaign", "start_date": "2021-01-25", "assignee": self.photograph.pk, "viewpoints": [ViewpointFactory().pk, ViewpointFactory().pk], } self.as_photograph() response = self.client.post(reverse("terra_opp:campaign-list"), data) self.assertEqual(status.HTTP_403_FORBIDDEN, response.status_code) self.as_admin() response = self.client.post(reverse("terra_opp:campaign-list"), data) self.assertEqual(status.HTTP_201_CREATED, response.status_code)
def test_only_active_viewpoint_retrieve(self): active_viewpoint = ViewpointFactory( label="Active viewpoint", active=True, pictures__state="accepted", ) inactive_viewpoint = ViewpointFactory( label="Unactive viewpoint", active=False, pictures__state="accepted", ) response = self.client.get(reverse("terra_opp:viewpoint-active")) self.assertEqual(status.HTTP_200_OK, response.status_code) active_viewpoint_count = ( Viewpoint.objects.with_accepted_pictures().filter(active=True).count() ) data = response.json() self.assertEqual(active_viewpoint_count, data["count"]) self.assertNotIn(inactive_viewpoint.id, [d["id"] for d in data["results"]]) self.assertIn(active_viewpoint.id, [d["id"] for d in data["results"]])
def test_viewpoint_search_json(self): list_url = reverse("terra_opp:viewpoint-list") ViewpointFactory( label="Viewpoint for search", pictures__state="accepted", properties={ "voie": "coin d'en bas de la rue du bout", "site": "Carrière des petits violoncelles", }, active=True, ) self.assertEqual(self.client.get(list_url).json()["count"], 2) data = self.client.get(list_url, {"properties__voie": "rue"}).json() self.assertEqual(data.get("count"), 1) data = self.client.get(list_url, {"properties__site": "carrière"}).json() self.assertEqual(data.get("count"), 1)
def test_search_campaign(self): viewpoint = ViewpointFactory(pictures__state="accepted") campaign = CampaignFactory(assignee=self.photograph) campaign.viewpoints.set([viewpoint]) CampaignFactory(assignee=self.photograph, state="started") CampaignFactory(assignee=self.photograph, state="closed") picture = PictureFactory(state="draft", viewpoint=viewpoint, campaign=campaign) list_url = resolve_url("terra_opp:campaign-list") self.as_admin() response = self.client.get(list_url, {"state": "draft"}) self.assertEqual(1, response.data.get("count")) response = self.client.get(list_url, {"state": "started"}) self.assertEqual(1, response.data.get("count")) response = self.client.get(list_url, {"state": "closed"}) self.assertEqual(1, response.data.get("count")) response = self.client.get(list_url, {"state": "foo"}) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) response = self.client.get(list_url, {"pictures__state": "draft"}) self.assertEqual(1, response.data.get("count")) response = self.client.get(list_url, {"pictures__state": "accepted"}) self.assertEqual(0, response.data.get("count")) picture.state = "accepted" picture.save() response = self.client.get(list_url, {"pictures__state": "draft"}) self.assertEqual(0, response.data.get("count")) response = self.client.get(list_url, {"pictures__state": "accepted"}) self.assertEqual(1, response.data.get("count")) response = self.client.get(list_url, {"pictures__state": "foo"}) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def test_auto_close(self): viewpoint = ViewpointFactory(pictures__state="accepted") viewpoint2 = ViewpointFactory(pictures__state="accepted") campaign = CampaignFactory(assignee=self.photograph, state="started") campaign.viewpoints.set([viewpoint, viewpoint2]) campaign_url = resolve_url("terra_opp:campaign-detail", pk=campaign.pk) data = { "viewpoint": viewpoint.pk, "date": timezone.datetime(2020, 8, 19, tzinfo=timezone.utc), "file": self._gen_file(), "state": "draft", } # Stats without any photo self.as_admin() response = self.client.get(campaign_url) def stats(response): return response.json().get("statistics") # Add draft photo self.as_photograph() response = self.client.post( reverse("terra_opp:picture-list"), data, format="multipart", ) data["viewpoint"] = viewpoint2.pk data["file"] = self._gen_file() response = self.client.post( reverse("terra_opp:picture-list"), data, format="multipart", ) self.as_admin() latest_picture = viewpoint.pictures.latest() latest_picture2 = viewpoint2.pictures.latest() response = self.client.patch( reverse( "terra_opp:picture-detail", args=[latest_picture.pk], ), {"state": "accepted"}, ) # Should still be started response = self.client.get(campaign_url) self.assertEqual( response.json()["state"], "started", ) response = self.client.patch( reverse( "terra_opp:picture-detail", args=[latest_picture2.pk], ), {"state": "accepted"}, ) # Should be closed after last accepted picture response = self.client.get(campaign_url) self.assertEqual( response.json()["state"], "closed", )
def test_list_campaign(self): viewpoint = ViewpointFactory() viewpoint2 = ViewpointFactory() campaign = CampaignFactory(assignee=self.photograph, state="started") campaign.viewpoints.set([viewpoint, viewpoint2]) campaign_other = CampaignFactory( state="started") # campaign for other photograph campaign_same_not_started = CampaignFactory( state="draft", assignee=self.photograph ) # campaign for same photograph but not started list_url = reverse("terra_opp:campaign-list") campaign_url = resolve_url("terra_opp:campaign-detail", pk=campaign.pk) campaign_other_url = resolve_url("terra_opp:campaign-detail", pk=campaign_other.pk) campaign_not_started_url = resolve_url("terra_opp:campaign-detail", pk=campaign_same_not_started.pk) # First we try as anonymous self.assertIn( self.client.get(list_url).status_code, [status.HTTP_401_UNAUTHORIZED, status.HTTP_403_FORBIDDEN], ) self.assertIn( self.client.get(campaign_url).status_code, [status.HTTP_401_UNAUTHORIZED, status.HTTP_403_FORBIDDEN], ) self.assertIn( self.client.get(campaign_other_url).status_code, [status.HTTP_401_UNAUTHORIZED, status.HTTP_403_FORBIDDEN], ) # Then we try with can_add_pictures permission self.as_photograph() response = self.client.get(list_url) self.assertEqual(status.HTTP_200_OK, response.status_code) # Only one should be visible self.assertEqual(1, response.data.get("count")) response = self.client.get(campaign_url) self.assertEqual(status.HTTP_200_OK, response.status_code) # Others campaigns should be forbidden self.assertEqual(status.HTTP_403_FORBIDDEN, self.client.get(campaign_other_url).status_code) # Not started campaigns should forbidden self.assertEqual( status.HTTP_403_FORBIDDEN, self.client.get(campaign_not_started_url).status_code, ) # Then as admin self.as_admin() response = self.client.get(list_url) self.assertEqual(status.HTTP_200_OK, response.status_code) self.assertEqual(response.data.get("count"), 3) campaign_response = self.client.get(campaign_url) self.assertEqual(status.HTTP_200_OK, campaign_response.status_code) self.assertNumQueries(3, lambda: self.client.get(campaign_url)) self.assertEqual(status.HTTP_200_OK, self.client.get(campaign_other_url).status_code) self.assertEqual(status.HTTP_200_OK, self.client.get(campaign_not_started_url).status_code)
def test_statistics(self): viewpoint = ViewpointFactory(pictures__state="accepted") viewpoint2 = ViewpointFactory(pictures__state="accepted") viewpoint3 = ViewpointFactory(pictures__state="accepted") viewpoint4 = ViewpointFactory(pictures__state="accepted") campaign = CampaignFactory(assignee=self.photograph, state="started") campaign.viewpoints.set( [viewpoint, viewpoint2, viewpoint3, viewpoint4]) campaign_url = resolve_url("terra_opp:campaign-detail", pk=campaign.pk) data = { "viewpoint": viewpoint.pk, "date": timezone.datetime(2020, 8, 19, tzinfo=timezone.utc), "file": self._gen_file(), "state": "draft", } # Stats without any photo self.as_admin() response = self.client.get(campaign_url) def stats(response): return response.json().get("statistics") self.assertEqual( stats(response), { "total": 4, "missing": 4, "submited": 0, "accepted": 0 }, ) # Add draft photo self.as_photograph() response = self.client.post( reverse("terra_opp:picture-list"), data, format="multipart", ) # Draft photo are considered as missing... self.as_admin() response = self.client.get(campaign_url) self.assertEqual( stats(response), { "total": 4, "missing": 4, "submited": 0, "accepted": 0 }, ) # ...But are listed self.assertEqual( response.json()["pictures"], [{ "viewpoint": 14, "date": "2020-08-19T00:00:00Z", "id": 22, "state": "draft", }], ) # Submit photo self.as_photograph() latest_picture = viewpoint.pictures.latest() response = self.client.patch( reverse( "terra_opp:picture-detail", args=[latest_picture.pk], ), {"state": "submited"}, ) # Should have 1 submited self.as_admin() response = self.client.get(campaign_url) self.assertEqual( stats(response), { "total": 4, "missing": 3, "submited": 1, "accepted": 0 }, ) # Submit another photo self.as_photograph() data["viewpoint"] = viewpoint2.pk data["file"] = self._gen_file() data["state"] = "submited" response = self.client.post( reverse("terra_opp:picture-list"), data, format="multipart", ) # Should have 2 submited self.as_admin() response = self.client.get(campaign_url) self.assertEqual( stats(response), { "total": 4, "missing": 2, "submited": 2, "accepted": 0 }, ) response = self.client.patch( reverse( "terra_opp:picture-detail", args=[latest_picture.pk], ), {"state": "accepted"}, ) # One shoud be accepted response = self.client.get(campaign_url) self.assertEqual( stats(response), { "total": 4, "missing": 2, "submited": 1, "accepted": 1 }, ) self.assertEqual( response.json()["pictures"], [ { "viewpoint": 15, "date": "2020-08-19T00:00:00Z", "id": 23, "state": "submited", }, { "viewpoint": 14, "date": "2020-08-19T00:00:00Z", "id": 22, "state": "accepted", }, ], ) # Perf check 3 queries even if 2 images and 4 viewpoints # One for campaign, one for viewpoints, one for pictures self.assertNumQueries(3, lambda: self.client.get(campaign_url)) latest_picture2 = viewpoint2.pictures.latest() response = self.client.patch( reverse( "terra_opp:picture-detail", args=[latest_picture2.pk], ), {"state": "refused"}, ) # Refused are considered as missing response = self.client.get(campaign_url) self.assertEqual( stats(response), { "total": 4, "missing": 3, "submited": 0, "accepted": 1 }, )
def test_workflow(self): viewpoint = ViewpointFactory() viewpoint2 = ViewpointFactory() campaign1 = CampaignFactory(assignee=self.photograph, state="started") campaign1.viewpoints.set([viewpoint, viewpoint2]) data = { "viewpoint": viewpoint.pk, "date": timezone.datetime(2020, 8, 19, tzinfo=timezone.utc), "file": self._gen_file(), "state": "draft", } # Photograph post draft photo self.as_photograph() self.client.post( reverse("terra_opp:picture-list"), data, format="multipart", ) latest_picture = viewpoint.pictures.latest() # Then submit the photo self.client.patch( reverse( "terra_opp:picture-detail", args=[latest_picture.pk], ), {"state": "submited"}, ) # Admin refuse the photo self.as_admin() self.client.patch( reverse( "terra_opp:picture-detail", args=[latest_picture.pk], ), {"state": "refused"}, ) # Photograph update the photo self.as_photograph() self.client.patch( reverse( "terra_opp:picture-detail", args=[latest_picture.pk], ), { "state": "submited", "file": self._gen_file() }, format="multipart", ) # Admin accept the photo self.as_admin() self.client.patch( reverse( "terra_opp:picture-detail", args=[latest_picture.pk], ), {"state": "accepted"}, ) latest_picture.refresh_from_db() self.assertEqual(latest_picture.state, "accepted")
def test_add_picture(self): viewpoint = ViewpointFactory() viewpoint2 = ViewpointFactory() viewpoint3 = ViewpointFactory() viewpoint4 = ViewpointFactory() viewpoint5 = ViewpointFactory() viewpoint6 = ViewpointFactory() campaign1 = CampaignFactory(assignee=self.photograph, state="started") campaign1.viewpoints.set([viewpoint, viewpoint2]) initial_picture_count1 = viewpoint.pictures.count() campaign2 = CampaignFactory(assignee=self.photograph, state="draft") campaign2.viewpoints.set([viewpoint3, viewpoint4]) campaign3 = CampaignFactory(state="started") campaign3.viewpoints.set([viewpoint5, viewpoint6]) data = { "viewpoint": viewpoint.pk, "date": timezone.datetime(2020, 8, 19, tzinfo=timezone.utc), "file": self._gen_file(), "state": "draft", } self.as_photograph() # Nominal cases should works response = self.client.post( reverse("terra_opp:picture-list"), data, format="multipart", ) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(viewpoint.pictures.count(), initial_picture_count1 + 1) self.assertEqual( viewpoint.pictures.latest().date, timezone.datetime(2020, 8, 19, tzinfo=timezone.utc), ) self.assertEqual( viewpoint.pictures.latest().state, "draft", ) # Should not allow to create second photo data["file"] = self._gen_file() response = self.client.post( reverse("terra_opp:picture-list"), data, format="multipart", ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) # Should update picture but ignore accepted state response = self.client.patch( reverse( "terra_opp:picture-detail", args=[viewpoint.pictures.latest().pk], ), {"state": "accepted"}, format="multipart", ) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data.get("state"), "draft") # Should update previous picture and change state response = self.client.patch( reverse( "terra_opp:picture-detail", args=[viewpoint.pictures.latest().pk], ), {"state": "submited"}, format="multipart", ) self.assertEqual(response.status_code, status.HTTP_200_OK) # Should not allow modification on submitted picture response = self.client.patch( reverse( "terra_opp:picture-detail", args=[viewpoint.pictures.latest().pk], ), {"state": "accepted"}, format="multipart", ) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) # Post to draft campaign data["viewpoint"] = viewpoint3.pk data["file"] = self._gen_file() response = self.client.post( reverse("terra_opp:picture-list"), data, format="multipart", ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) # Post to started campaign for another assignee data["viewpoint"] = viewpoint5.pk data["file"] = self._gen_file() response = self.client.post( reverse("terra_opp:picture-list"), data, format="multipart", ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) # Post to started campaign but with bad viewpoint data["viewpoint"] = viewpoint5.pk data["file"] = self._gen_file() data["campaign"] = campaign1.pk response = self.client.post( reverse("terra_opp:picture-list"), data, format="multipart", ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) # Post to started campaign bad picture state data["viewpoint"] = viewpoint5.pk data["file"] = self._gen_file() data["campaign"] = campaign1.pk response = self.client.post( reverse("terra_opp:picture-list"), data, format="multipart", ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def setUpTestData(cls): # Create viewpoint with draft picture attached to it cls.viewpoint = ViewpointFactory(label="Basic viewpoint")