Exemplo n.º 1
0
    def test_management_command_sets_needs_review_flag(self, fake_get):
        fake_get.return_value.status_code = 200
        fake_get.return_value.json.return_value = {
            "memberships": [{
                "id": "uk.parliament.data/Member/374/GovernmentPost/56",
                "source": "datadotparl/governmentpost",
                "role": "Deputy Prime Minister and First Secretary of State",
                "person_id": "uk.org.publicwhip/person/10488",
                "organization_id": "house-of-commons",
                "start_date": "2001-06-08",
                "end_date": "9999-12-30",
            }]
        }
        person = PersonFactory(id=999)

        person.tmp_person_identifiers.create(
            internal_identifier="uk.org.publicwhip/person/10488",
            value_type="theyworkforyou",
        )
        person.save()

        cmd = call_command(
            "moderation_queue_set_ministers_liable_to_vandalism")
        person.refresh_from_db()
        self.assertEqual(person.edit_limitations,
                         EditLimitationStatuses.NEEDS_REVIEW.name)
Exemplo n.º 2
0
class PersonViewTests(TestCase):
    def setUp(self):
        self.party = PartyFactory()
        self.person = PersonFactory()
        self.person_url = self.person.get_absolute_url()

    def test_current_person_view(self):
        self.personpost = PersonPostFactory(person=self.person,
                                            election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, "people/person_detail.html")
        self.assertNotContains(response,
                               '<meta name="robots" content="noindex">')

    def test_not_current_person_view(self):
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response,
                                "people/not_current_person_detail.html")
        self.assertContains(response,
                            f"{ self.person.name} stood for election")
        self.assertNotContains(response, f"{ self.person.name} Online")
        self.assertContains(response, '<meta name="robots" content="noindex">')

    def test_not_current_person_with_twfy_id(self):
        self.person.twfy_id = 10999
        self.person.save()
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, "people/person_detail.html")
        self.assertNotContains(response,
                               '<meta name="robots" content="noindex">')
        self.assertContains(response, "Record in office")
        self.assertContains(response, "TheyWorkForYou")

    def test_correct_elections_listed(self):
        response = self.client.get(self.person_url, follow=True)

        election_name = "FooBar Election 2017"

        self.assertNotContains(response, election_name)
        election = ElectionFactory(
            name=election_name,
            current=True,
            election_date="2040-01-01",
            slug="local.foobar.2040-01-01",
        )
        post = PostFactory()
        pe = PostElectionFactory(
            election=election,
            post=post,
            ballot_paper_id="local.foo.bar.2040-01-01",
        )
        PersonPostFactory(
            post_election=pe,
            election=election,
            person=self.person,
            party=self.party,
        )

        response = self.client.get(self.person_url, follow=True)
        self.assertContains(response, election_name)
        self.assertContains(response, "is a")

    def test_election_in_past_listed(self):
        response = self.client.get(self.person_url, follow=True)

        election_name = "FooBar Election 2017"

        self.assertNotContains(response, election_name)
        election = ElectionFactory(
            name=election_name,
            current=False,
            election_date="2017-01-01",
            slug="local.foobar.2017-01-01",
        )
        post = PostFactory()
        pe = PostElectionFactory(
            election=election,
            post=post,
            ballot_paper_id="local.foo.bar.2017-01-01",
        )
        PersonPostFactory(
            post_election=pe,
            election=election,
            person=self.person,
            party=self.party,
        )

        response = self.client.get(self.person_url, follow=True)
        self.assertContains(response, election_name)
        self.assertContains(response, "was a")

    def test_multiple_candidacies_intro(self):
        election_one = ElectionFactory()
        election_two = ElectionFactoryLazySlug()
        party = PartyFactory(party_name="Liberal Democrat", party_id="foo")
        PersonPostFactory(person=self.person,
                          election=election_one,
                          party=party)
        PersonPostFactory(person=self.person,
                          election=election_two,
                          party=party)
        response = self.client.get(self.person_url, follow=True)
        self.assertContains(
            response,
            "is a Liberal Democrat candidate in the following elections:",
        )

    def test_multiple_independent_candidacies_intro(self):
        election_one = ElectionFactory()
        election_two = ElectionFactoryLazySlug()
        party = PartyFactory(party_name="Independent", party_id="ynmp-party:2")
        PersonPostFactory(person=self.person,
                          election=election_one,
                          party=party)
        PersonPostFactory(person=self.person,
                          election=election_two,
                          party=party)
        response = self.client.get(self.person_url, follow=True)
        self.assertContains(
            response,
            "is an Independent candidate in the following elections:")

    def test_one_candidacy_intro(self):
        election = ElectionFactory()
        party = PartyFactory(party_name="Conservative and Unionist Party",
                             party_id="ConUnion")
        person_post = PersonPostFactory(person=self.person,
                                        election=election,
                                        party=party)
        response = self.client.get(self.person_url, follow=True)
        self.assertContains(
            response,
            f"{self.person.name} is a {party.party_name} candidate in {person_post.post.label} in the {election.name}.",
        )

    def test_no_previous_elections(self):
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertNotContains(response, "Previous Elections")

    def test_previous_elections(self):
        past_election = ElectionFactoryLazySlug(election_date="2019-05-02",
                                                current=False)
        party = PartyFactory(party_name="Liberal Democrat", party_id="foo")
        PersonPostFactory(
            person=self.person,
            post_election__election=past_election,
            election=past_election,
            party=party,
            votes_cast=1000,
        )
        response = self.client.get(self.person_url, follow=True)
        self.assertContains(response, "Previous Elections")

    def test_no_statement_to_voters(self):
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertNotContains(response, "Statement to voters")

    def test_statement_to_voters(self):
        self.person.statement_to_voters = "I believe in equal rights."
        self.person.save()
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertContains(response, "Statement to voters")

    def test_no_TWFY(self):
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertNotContains(response, "Record in office")

    def test_TWFY(self):
        self.person.twfy_id = 123
        self.person.save()
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertContains(response, "Record in office")

    def test_no_wikipedia(self):
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertNotContains(response, "Wikipedia")

    def test_wikipedia(self):
        self.person.wikipedia_bio = "yo"
        self.person.wikipedia_url = "https//www.wikipedia.com/yo"
        self.person.save()
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertContains(response, "Wikipedia")

    def test_no_facebook(self):
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertNotContains(response, "username")

    def test_facebook(self):
        self.person.facebook_personal_url = "https//www.facebook.com/yo"
        self.person.facebook_page_url = "https//www.facebook.com/yo"
        self.person.save()
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertContains(response, "yo")

    def test_no_linkedin(self):
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertNotContains(response, "LinkedIn")

    def test_linkedin(self):
        self.person.linkedin_url = "https://www.linkedin.com/yo"
        self.person.save()
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertContains(response, "LinkedIn")

    def test_instagram(self):
        self.person.instagram_url = "https://www.instagram.com/yo"
        self.person.save()
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertContains(response, "Instagram")

    def test_no_instagram(self):
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertNotContains(response, "Instagram")

    def test_party_page(self):
        self.person.party_ppc_page_url = "https://www.voteforme.com/bob"
        self.person.save()
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertContains(response,
                            "The party's candidate page for this person")

    def test_no_party_page(self):
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertNotContains(response,
                               "The party's candidate page for this person")

    def test_no_youtube(self):
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertNotContains(response, "YouTube")

    def test_youtube(self):
        self.person.youtube_profile = "Mary123"
        self.person.save()
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertContains(response, "YouTube")

    def test_email(self):
        self.person.email = "*****@*****.**"
        self.person.save()
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertContains(response, "Email")

    def test_no_email(self):
        PersonPostFactory(person=self.person, election=ElectionFactory())
        response = self.client.get(self.person_url, follow=True)
        self.assertEqual(response.template_name, ["people/person_detail.html"])
        self.assertNotContains(response, "Email")

    def test_local_party_for_local_election(self):
        party = PartyFactory(party_name="Labour Party", party_id="party:53")
        local_party = LocalPartyFactory(name="Derbyshire Labour",
                                        is_local=True,
                                        parent=party)
        PersonPostFactory(
            person=self.person,
            election=ElectionFactory(),
            party=party,
        )
        response = self.client.get(self.person_url, follow=True)
        expected = f"{self.person.name}'s local party is {local_party.label}."
        self.assertContains(response, expected)

    def test_local_party_for_non_local_election(self):
        party = PartyFactory(party_name="Labour Party", party_id="party:53")
        local_party = LocalPartyFactory(name="Welsh Labour | Llafur Cymru",
                                        is_local=False,
                                        parent=party)
        PersonPostFactory(
            person=self.person,
            election=ElectionFactory(),
            party=party,
        )
        response = self.client.get(self.person_url, follow=True)
        expected = f"{self.person.name} is a {local_party.label} candidate."
        self.assertContains(response, expected)
Exemplo n.º 3
0
class TestMerging(TestUserMixin, UK2015ExamplesMixin, WebTest):
    def setUp(self):
        self.dest_person = PersonFactory(pk=1)
        self.source_person = PersonFactory(pk=2)

    def test_person_merging(self):
        """
        A small interface / smoke test for the PersonMerger class.

        Swap source and dest in the args to ensure dest is always kept
        """

        LoggedAction.objects.create(person=self.source_person, user=self.user)
        LoggedAction.objects.create(person=self.dest_person, user=self.user)

        self.assertEqual(Person.objects.count(), 2)
        self.assertEqual(LoggedAction.objects.count(), 2)

        merger = PersonMerger(self.source_person, self.dest_person)
        merger.merge()

        self.assertEqual(Person.objects.count(), 1)
        self.assertEqual(Person.objects.get().pk, self.dest_person.pk)
        self.assertEqual(LoggedAction.objects.count(), 2)

    def test_invalid_merge(self):
        other_local_post = PostFactory.create(
            elections=(self.local_election,),
            slug="DIW:E05005005",
            label="Shepway North Ward",
            party_set=self.gb_parties,
            organization=self.local_council,
        )

        self.dest_person.memberships.create(post_election=self.local_pee)
        self.source_person.memberships.create(
            post_election=other_local_post.postextraelection_set.get()
        )

        self.assertEqual(Person.objects.count(), 2)
        merger = PersonMerger(self.dest_person, self.source_person)
        with self.assertRaises(InvalidMergeError):
            merger.merge()
        # Make sure we still have two people
        self.assertEqual(Person.objects.count(), 2)

    def test_cant_delete_with_related_objects(self):
        """
        It's impossible to test that a model we know about isn't merged, as
        if we knew about a model that wasn't merged we would add a case for it
        in the merging code. However, we can test that `safe_delete` doesn't
        delete objects with related models.
        """
        self.dest_person.memberships.create(post_election=self.local_pee)
        merger = PersonMerger(self.dest_person, self.source_person)
        with self.assertRaises(UnsafeToDelete):
            merger.safe_delete(self.dest_person)
        self.assertEqual(Person.objects.count(), 2)

    def test_merge_with_results(self):
        self.source_person.memberships.create(post_election=self.local_pee)
        self.dest_person.memberships.create(post_election=self.local_pee)

        result_set = ResultSet.objects.create(
            post_election=self.local_pee,
            num_turnout_reported=10000,
            num_spoilt_ballots=30,
            user=self.user,
            ip_address="127.0.0.1",
            source="Example ResultSet for testing",
        )

        CandidateResult.objects.create(
            result_set=result_set,
            membership=self.source_person.memberships.get(),
            num_ballots=3,
            is_winner=True,
        )

        merger = PersonMerger(self.dest_person, self.source_person)
        merger.merge()

        self.assertEqual(
            self.dest_person.memberships.get().result.num_ballots, 3
        )

    def test_merge_with_results_on_both_memberships(self):
        self.source_person.memberships.create(post_election=self.local_pee)
        self.dest_person.memberships.create(post_election=self.local_pee)

        result_set = ResultSet.objects.create(
            post_election=self.local_pee,
            num_turnout_reported=10000,
            num_spoilt_ballots=30,
            user=self.user,
            ip_address="127.0.0.1",
            source="Example ResultSet for testing",
        )

        CandidateResult.objects.create(
            result_set=result_set,
            membership=self.source_person.memberships.get(),
            num_ballots=3,
            is_winner=True,
        )
        CandidateResult.objects.create(
            result_set=result_set,
            membership=self.dest_person.memberships.get(),
            num_ballots=3,
            is_winner=True,
        )

        merger = PersonMerger(self.dest_person, self.source_person)
        with self.assertRaises(InvalidMergeError) as e:
            merger.merge()

        self.assertEqual(
            e.exception.args[0], "Trying to merge two Memberships with results"
        )

        self.assertEqual(
            self.dest_person.memberships.get().result.num_ballots, 3
        )

    def test_other_names_created(self):
        self.source_person.name = "Ema Nymnot"
        self.source_person.save()

        self.dest_person.name = "Not My Name"
        self.dest_person.save()
        self.assertEqual(self.dest_person.other_names.count(), 0)

        merger = PersonMerger(self.dest_person, self.source_person)
        merger.merge()
        self.assertEqual(self.dest_person.other_names.count(), 1)
        self.assertEqual(
            self.dest_person.other_names.first().name, "Ema Nymnot"
        )

    def test_other_names_not_duplicated(self):
        self.source_person.name = "Ema Nymnot"
        self.source_person.save()
        self.source_person.other_names.create(name="nom de plume")

        self.dest_person.name = "Not My Name"
        self.dest_person.other_names.create(name="nom de plume")
        self.dest_person.save()
        self.assertEqual(self.dest_person.other_names.count(), 1)

        merger = PersonMerger(self.dest_person, self.source_person)
        merger.merge()
        self.assertEqual(self.dest_person.other_names.count(), 2)
        self.assertListEqual(
            list(
                self.dest_person.other_names.order_by("name").values_list(
                    "name", flat=True
                )
            ),
            ["Ema Nymnot", "nom de plume"],
        )

    def test_recorded_merge_data(self):
        merger = PersonMerger(self.dest_person, self.source_person)
        merger.merge()
        expected_versions = [
            {
                "information_source": "After merging person 2",
                "version_id": "40e8cf2c0c6e9260",
                "timestamp": "2019-01-28T16:08:53.112792",
                "data": {
                    "id": "1",
                    "email": "",
                    "facebook_page_url": "",
                    "facebook_personal_url": "",
                    "homepage_url": "",
                    "linkedin_url": "",
                    "party_ppc_page_url": "",
                    "twitter_username": "",
                    "wikipedia_url": "",
                    "wikidata_id": "",
                    "honorific_prefix": "",
                    "name": "",
                    "honorific_suffix": "",
                    "gender": "",
                    "birth_date": "",
                    "death_date": "",
                    "biography": "",
                    "other_names": [],
                    "extra_fields": {"favourite_biscuits": ""},
                    "standing_in": {},
                    "party_memberships": {},
                },
            }
        ]
        actual = json.loads(self.dest_person.versions)
        self.assertEqual(
            actual[0]["information_source"],
            expected_versions[0]["information_source"],
        )
        self.assertEqual(actual[0]["data"], expected_versions[0]["data"])
        self.assertEqual(len(actual), len(expected_versions))

    def test_dest_person_gets_source_properties(self):
        self.dest_person.birth_date = "1956-01-02"
        self.source_person.birth_date = "1945-01-04"

        merger = PersonMerger(self.dest_person, self.source_person)
        merger.merge()
        self.assertEqual(self.dest_person.birth_date, "1945-01-04")

    def test_dest_person_gets_empty_values_from_source(self):
        self.dest_person.birth_date = None
        self.source_person.birth_date = "1945-01-04"

        merger = PersonMerger(self.dest_person, self.source_person)
        merger.merge()
        self.assertEqual(self.dest_person.birth_date, "1945-01-04")

    def test_merge_maintain_primary_image(self):
        PersonImage.objects.update_or_create_from_file(
            EXAMPLE_IMAGE_FILENAME,
            "images/image1.jpg",
            self.dest_person,
            defaults={
                "md5sum": "md5sum",
                "copyright": "example-license",
                "uploading_user": self.user,
                "user_notes": "Here's an image...",
                "is_primary": True,
                "source": "Found on the candidate's Flickr feed",
            },
        )

        PersonImage.objects.update_or_create_from_file(
            EXAMPLE_IMAGE_FILENAME,
            "images/image2.jpg",
            self.source_person,
            defaults={
                "md5sum": "md5sum",
                "copyright": "example-license",
                "uploading_user": self.user,
                "user_notes": "Here's an image...",
                "is_primary": True,
                "source": "Found on the candidate's Flickr feed",
            },
        )

        self.assertEqual(self.dest_person.images.count(), 1)
        merger = PersonMerger(self.dest_person, self.source_person)
        merger.merge()
        self.assertEqual(self.dest_person.images.count(), 2)
        self.assertEqual(
            self.dest_person.images.filter(is_primary=True).count(), 1
        )

        self.assertTrue(
            self.dest_person.images.get(is_primary=True).image.url.startswith(
                "/media/images/images/image2"
            )
        )

    def test_merge_gets_primary_image(self):
        PersonImage.objects.update_or_create_from_file(
            EXAMPLE_IMAGE_FILENAME,
            "images/image1.jpg",
            self.dest_person,
            defaults={
                "md5sum": "md5sum",
                "copyright": "example-license",
                "uploading_user": self.user,
                "user_notes": "Here's an image...",
                "is_primary": False,
                "source": "Found on the candidate's Flickr feed",
            },
        )

        PersonImage.objects.update_or_create_from_file(
            EXAMPLE_IMAGE_FILENAME,
            "images/image2.jpg",
            self.source_person,
            defaults={
                "md5sum": "md5sum",
                "copyright": "example-license",
                "uploading_user": self.user,
                "user_notes": "Here's an image...",
                "is_primary": True,
                "source": "Found on the candidate's Flickr feed",
            },
        )

        self.assertEqual(self.dest_person.images.count(), 1)
        merger = PersonMerger(self.dest_person, self.source_person)
        merger.merge()
        self.assertEqual(self.dest_person.images.count(), 2)
        self.assertEqual(
            self.dest_person.images.filter(is_primary=True).count(), 1
        )

        self.assertTrue(
            self.dest_person.images.get(is_primary=True).image.url.startswith(
                "/media/images/images/image2"
            )
        )

    def test_person_identifier_after_merge(self):
        self.source_person.tmp_person_identifiers.create(
            value_type="email", value="*****@*****.**"
        )

        self.assertEqual(self.dest_person.get_email, None)
        self.assertEqual(self.source_person.get_email, "*****@*****.**")
        merger = PersonMerger(self.dest_person, self.source_person)
        merger.merge()
        self.assertEqual(self.dest_person.get_email, "*****@*****.**")

    def test_person_identifier_keep_dest_id(self):
        self.dest_person.tmp_person_identifiers.create(
            value_type="email", value="*****@*****.**"
        )
        self.source_person.tmp_person_identifiers.create(
            value_type="email", value="*****@*****.**"
        )

        self.assertEqual(self.dest_person.get_email, "*****@*****.**")
        self.assertEqual(self.source_person.get_email, "*****@*****.**")
        merger = PersonMerger(self.dest_person, self.source_person)
        merger.merge()
        self.assertEqual(self.dest_person.get_email, "*****@*****.**")

    def test_merge_queued_images(self):
        self.source_person.queuedimage_set.create()
        self.assertEqual(self.dest_person.queuedimage_set.count(), 0)
        merger = PersonMerger(self.source_person, self.dest_person)
        merger.merge()
        self.assertEqual(self.dest_person.queuedimage_set.count(), 1)

    def test_merge_not_standing(self):
        self.source_person.not_standing.add(self.election)
        self.assertEqual(self.dest_person.not_standing.count(), 0)
        merger = PersonMerger(self.source_person, self.dest_person)
        merger.merge()
        self.assertEqual(self.dest_person.not_standing.count(), 1)

    def test_duplicate_latest_versions_regression(self):
        """
        If there are identical latest versions from the old and new person
        then a "duplicate" version is created, with a "after merging" commit
        message.

        Normally this would get de-duplicated to save filling up the versions
        data, but in the case of a merge we *always* want to keep the merge
        commit, so we can show a proper log message.

        This is a regression test to catch that case.

        https://github.com/DemocracyClub/yournextrepresentative/issues/860

        """

        person_1 = PersonFactory(
            pk=50536,
            versions=json.dumps(
                [
                    {
                        "data": {
                            "birth_date": "",
                            "extra_fields": {"favourite_biscuits": ""},
                            "other_names": [],
                            "facebook_page_url": "",
                            "email": "",
                            "linkedin_url": "",
                            "party_ppc_page_url": "https://www.wirralconservatives.com/helencameron",
                            "death_date": "",
                            "honorific_suffix": "",
                            "honorific_prefix": "",
                            "name": "Helen Cameron",
                            "twitter_username": "",
                            "id": "50537",
                            "biography": "",
                            "wikipedia_url": "",
                            "standing_in": {
                                "local.wirral.2019-05-02": {
                                    "name": "Clatterbridge",
                                    "post_id": "MTW:E05000958",
                                }
                            },
                            "homepage_url": "",
                            "party_memberships": {
                                "local.wirral.2019-05-02": {
                                    "name": "Conservative and Unionist Party",
                                    "id": "party:52",
                                }
                            },
                            "facebook_personal_url": "",
                            "gender": "female",
                        },
                        "information_source": "https://www.wirralconservatives.com/helencameron",
                        "timestamp": "2019-03-28T14:37:30.958127",
                        "version_id": "0036d8081d566648",
                        "username": "******",
                    }
                ]
            ),
        )
        person_2 = PersonFactory(
            pk=50537,
            versions=json.dumps(
                [
                    {
                        "data": {
                            "birth_date": "",
                            "extra_fields": {"favourite_biscuits": ""},
                            "other_names": [],
                            "facebook_page_url": "",
                            "email": "",
                            "linkedin_url": "",
                            "party_ppc_page_url": "https://www.wirralconservatives.com/helencameron",
                            "death_date": "",
                            "honorific_suffix": "",
                            "honorific_prefix": "",
                            "name": "Helen Cameron",
                            "twitter_username": "",
                            "id": "50536",
                            "biography": "",
                            "wikipedia_url": "",
                            "standing_in": {
                                "local.wirral.2019-05-02": {
                                    "name": "Clatterbridge",
                                    "post_id": "MTW:E05000958",
                                }
                            },
                            "homepage_url": "",
                            "party_memberships": {
                                "local.wirral.2019-05-02": {
                                    "name": "Conservative and Unionist Party",
                                    "id": "party:52",
                                }
                            },
                            "facebook_personal_url": "",
                            "gender": "female",
                        },
                        "information_source": "https://www.wirralconservatives.com/helencameron",
                        "timestamp": "2019-03-28T14:37:30.958127",
                        "version_id": "0036d8081d566648",
                        "username": "******",
                    }
                ]
            ),
        )

        merger = PersonMerger(person_1, person_2)
        merger.merge()
        person_1.refresh_from_db()
        # This would raise if the bug existed
        self.assertIsNotNone(person_1.version_diffs)

    def test_conflicting_standing_in_values_regression(self):
        """
        https://github.com/DemocracyClub/yournextrepresentative/issues/811

        This was both a bug and a problem with the strategy of merging.

        The bug was that is was possible to have party info against an election
        in the not-standing list.

        The problem was when merging two people with a not standing value and a
        membership in the same election, we would keep both objects, leaving
        the database in an inconsistent state.

        The merging logic was changed to keep the membership and discard the
        not-standing status.

        This test checks for a regression of both cases.

        """
        self.local_election.election_date = date.today() + timedelta(days=1)
        self.local_election.save()

        other_local_post = PostFactory.create(
            elections=(self.local_election,),
            slug="LBW:E05000601",
            label="Hoe Street",
            party_set=self.gb_parties,
            organization=self.local_council,
        )
        ballot = other_local_post.postextraelection_set.get()

        # Create person 1
        response = self.app.get(ballot.get_absolute_url(), user=self.user)
        form = response.forms["new-candidate-form"]
        form["name"] = "Imaginary Candidate"
        form[
            "party_GB_{}".format(self.local_election.slug)
        ] = self.green_party.ec_id
        form[
            "constituency_{}".format(self.local_election.slug)
        ] = ballot.post.slug
        form["standing_{}".format(self.local_election.slug)] = "standing"
        form[
            "source"
        ] = "Testing adding a new candidate to a locked constituency"
        response = form.submit()
        person_1 = response.context["object"]

        # Create person 2
        response = self.app.get(ballot.get_absolute_url(), user=self.user)
        form = response.forms["new-candidate-form"]
        form["name"] = "Imaginary Candidate"
        form[
            "party_GB_{}".format(self.local_election.slug)
        ] = self.green_party.ec_id
        form[
            "constituency_{}".format(self.local_election.slug)
        ] = ballot.post.slug
        form["standing_{}".format(self.local_election.slug)] = "standing"
        form[
            "source"
        ] = "Testing adding a new candidate to a locked constituency"
        response = form.submit()
        person_2 = response.context["object"]

        # Remove the membership for person 2
        response = self.app.get(
            "/person/{}/update".format(person_2.pk), user=self.user
        )
        form = response.forms["person-details"]
        form["standing_{}".format(self.local_election.slug)].force_value(
            "not-standing"
        )
        form["source"] = "Mumsnet"
        form.submit()

        # Merge the two people. What do we expect?
        # We have a standing in and a not-standing record for the same election
        # so we decide to remove the not-standing and keep the membership
        merger = PersonMerger(person_1, person_2)
        merger.merge()
        person_1.refresh_from_db()
        version_data = json.loads(person_1.versions)[0]["data"]
        self.assertEqual(
            version_data["standing_in"],
            {
                "local.maidstone.2016-05-05": {
                    "name": "Hoe Street",
                    "post_id": "LBW:E05000601",
                }
            },
        )
        self.assertEqual(
            version_data["party_memberships"],
            {
                "local.maidstone.2016-05-05": {
                    "id": "party:63",
                    "name": "Green Party",
                }
            },
        )