Ejemplo n.º 1
0
    def form_valid(self, form):
        post_id = form.cleaned_data["post_id"]
        with transaction.atomic():
            post = get_object_or_404(Post, slug=post_id)
            raise_if_locked(self.request, post, self.election_data)
            change_metadata = get_change_metadata(self.request,
                                                  form.cleaned_data["source"])
            person = get_object_or_404(Person,
                                       id=form.cleaned_data["person_id"])
            LoggedAction.objects.create(
                user=self.request.user,
                action_type="candidacy-delete",
                ip_address=get_client_ip(self.request),
                popit_person_new_version=change_metadata["version_id"],
                person=person,
                source=change_metadata["information_source"],
            )

            memberships_to_delete = person.memberships.filter(
                post=post,
                role=self.election_data.candidate_membership_role,
                post_election__election=self.election_data,
            )
            for m in memberships_to_delete:
                raise_if_unsafe_to_delete(m)
                m.delete()

            check_no_candidancy_for_election(person, self.election_data)
            person.not_standing.add(self.election_data)

            person.record_version(change_metadata)
            person.save()
        if self.request.is_ajax():
            return JsonResponse({"success": True})
        return get_redirect_to_post(self.election, post)
Ejemplo n.º 2
0
def update_person(
    request=None, person=None, party=None, post_election=None, source=None
):
    election = post_election.election

    person.not_standing.remove(election)

    check_creation_allowed(request.user, person.current_candidacies)

    membership, _ = Membership.objects.update_or_create(
        post=post_election.post,
        person=person,
        post_election=post_election,
        defaults={
            "party": party,
            "party_list_position": None,
            "elected": None,
            "role": election.candidate_membership_role,
        },
    )

    # Now remove other memberships in this election for that
    # person, although we raise an exception if there is any
    # object that has a
    # ForeignKey to the membership, since that would result in
    # losing data.
    old_memberships = (
        Membership.objects.exclude(pk=membership.pk)
        .exclude(post_election__candidates_locked=True)
        .filter(person=person, post_election__election=post_election.election)
    )
    for old_membership in old_memberships:
        raise_if_unsafe_to_delete(old_membership)
        old_membership.delete()

    memberships_for_election = Membership.objects.filter(
        person=person, post_election__election=post_election.election
    )

    if (
        not memberships_for_election.exists()
        or memberships_for_election.count() > 1
    ):
        raise ValueError(
            "Attempt to create invalid memberships for {}".format(person)
        )

    change_metadata = get_change_metadata(request, source)

    person.record_version(change_metadata)
    person.save()

    LoggedAction.objects.create(
        user=request.user,
        person=person,
        action_type="person-update",
        ip_address=get_client_ip(request),
        popit_person_new_version=change_metadata["version_id"],
        source=change_metadata["information_source"],
    )
Ejemplo n.º 3
0
    def clean(self):
        if "extra_election_id" in self.data:
            # We're adding a new election
            election = Election.objects.get(
                slug=self.data["extra_election_id"])

            # Add this new election to elections_with_fields
            if election not in self.elections_with_fields:
                self.elections_with_fields.append(election)

            # Then re-create the form with the new election in
            self.add_elections_fields(self.elections_with_fields)

            # Now we need to re-clean the data, with the new election in it
            self._clean_fields()

        for field in self.changed_data:
            if field.startswith("constituency_"):
                # We're changing a constituency, so we need to make sure
                # that's allowed
                if self.initial.get(field):
                    membership = self.initial["person"].memberships.get(
                        ballot__post__slug=self.initial[field],
                        ballot__election__slug=field.replace(
                            "constituency_", ""),
                    )
                    try:
                        raise_if_unsafe_to_delete(membership)
                    except UnsafeToDelete as e:
                        self.add_error(field, e)

        cleaned_data = super().clean()
        return self.check_party_and_constituency_are_selected(cleaned_data)
Ejemplo n.º 4
0
def mark_as_unsure_if_standing(person, election_data, post):
    # Remove any existing candidacy:
    for membership in Membership.objects.filter(ballot__election=election_data,
                                                person=person):
        raise_if_unsafe_to_delete(membership)
        membership.delete()
    # Now remove any entry that indicates that they're standing in
    # this election:
    person.not_standing.remove(election_data)
def update_person(request=None,
                  person_extra=None,
                  party=None,
                  post_election=None,
                  source=None):
    election = post_election.election

    person_extra.not_standing.remove(election)

    check_creation_allowed(request.user, person_extra.current_candidacies)

    membership, _ = Membership.objects.update_or_create(
        post=post_election.postextra.base,
        person=person_extra.base,
        extra__election=election,
        role=election.candidate_membership_role,
        defaults={
            'on_behalf_of': party,
        })

    MembershipExtra.objects.get_or_create(base=membership,
                                          defaults={
                                              'party_list_position': None,
                                              'election': election,
                                              'elected': None,
                                              'post_election': post_election,
                                          })

    # Now remove other memberships in this election for that
    # person, although we raise an exception if there is any
    # object (other than its MembershipExtra) that has a
    # ForeignKey to the membership, since that would result in
    # losing data.
    old_memberships = Membership.objects \
        .exclude(pk=membership.pk) \
        .filter(
            person=person_extra.base,
            extra__election=election,
            role=election.candidate_membership_role,
        )
    for old_membership in old_memberships:
        raise_if_unsafe_to_delete(old_membership)
        old_membership.delete()

    change_metadata = get_change_metadata(request, source)

    person_extra.record_version(change_metadata)
    person_extra.save()

    LoggedAction.objects.create(
        user=request.user,
        person=person_extra.base,
        action_type='person-update',
        ip_address=get_client_ip(request),
        popit_person_new_version=change_metadata['version_id'],
        source=change_metadata['information_source'],
    )
Ejemplo n.º 6
0
    def update_person(self, context, data, person_extra):
        party = Organization.objects.get(pk=data['party'].split('__')[0])
        post = context['post_extra'].base
        election = Election.objects.get(slug=context['election'])

        person_extra.not_standing.remove(election)

        membership, _ = Membership.objects.update_or_create(
            post=post,
            person=person_extra.base,
            extra__election=election,
            role=election.candidate_membership_role,
            defaults={
                'on_behalf_of': party,
            })

        MembershipExtra.objects.get_or_create(base=membership,
                                              defaults={
                                                  'party_list_position': None,
                                                  'election': election,
                                                  'elected': None,
                                              })

        # Now remove other memberships in this election for that
        # person, although we raise an exception if there is any
        # object (other than its MembershipExtra) that has a
        # ForeignKey to the membership, since that would result in
        # losing data.
        for old_membership in Membership.objects \
            .exclude(pk=membership.pk) \
            .filter(
                person=person_extra.base,
                extra__election=election,
                role=election.candidate_membership_role,
            ):
            raise_if_unsafe_to_delete(old_membership)
            old_membership.delete()

        change_metadata = get_change_metadata(self.request, data['source'])

        person_extra.record_version(change_metadata)
        person_extra.save()

        LoggedAction.objects.create(
            user=self.request.user,
            person=person_extra.base,
            action_type='person-update',
            ip_address=get_client_ip(self.request),
            popit_person_new_version=change_metadata['version_id'],
            source=change_metadata['information_source'],
        )
Ejemplo n.º 7
0
def mark_as_not_standing(person, election_data, post):
    # Remove any existing candidacy:
    for membership in Membership.objects.filter(
            ballot__election=election_data,
            person=person,
            # n.b. we are planning to make "not standing" post
            # specific in the future, in which case we would also want
            # this line:
            # post__slug=post_slug,
    ):
        raise_if_unsafe_to_delete(membership)
        membership.delete()
    from candidates.models.constraints import check_no_candidancy_for_election

    check_no_candidancy_for_election(person, election_data)
    person.not_standing.add(election_data)
Ejemplo n.º 8
0
def mark_as_standing(person, election_data, post, party, party_list_position):
    # First, if the person is marked as "not standing" in that
    # election, remove that record:
    person.not_standing.remove(election_data)
    membership_ids_to_remove = set()
    membership = None
    # This person might already be marked as standing for this
    # post. In that case, we need to make sure we preserve that
    # existing membership, since there may be metadata attached to it
    # (such as the extra.elected property or CandidateResult records)
    # which would be lost if we deleted and recreated the membership.
    # Go through the person's existing candidacies for this election:
    for existing_membership in Membership.objects.filter(
        post_election__election=election_data,
        role=election_data.candidate_membership_role,
        person=person,
    ):
        if existing_membership.post == post:
            membership = existing_membership
        else:
            membership_ids_to_remove.add(existing_membership.id)
    # If there was no existing membership, we need to create one:
    if not membership:
        membership = Membership.objects.create(
            post=post,
            person=person,
            role=election_data.candidate_membership_role,
            post_election=election_data.postextraelection_set.get(post=post),
        )
    # Update the party list position in case it's changed:
    membership.party_list_position = party_list_position
    membership.save()
    # Update the party, in case it's changed:
    membership.party = party
    membership.save()
    # Now remove any memberships that shouldn't now be there:
    for membership_to_remove in Membership.objects.filter(
        pk__in=membership_ids_to_remove
    ):
        raise_if_unsafe_to_delete(membership_to_remove)
        membership_to_remove.delete()
Ejemplo n.º 9
0
def revert_person_from_version_data(person,
                                    person_extra,
                                    version_data,
                                    part_of_merge=False):

    from popolo.models import Membership, Organization, Post
    from candidates.models import raise_if_unsafe_to_delete

    from elections.models import Election

    for field in settings.SIMPLE_POPOLO_FIELDS:
        new_value = version_data.get(field.name)
        if new_value:
            setattr(person, field.name, new_value)
        else:
            setattr(person, field.name, '')

    # Remove any old values in complex fields:
    for field in ComplexPopoloField.objects.all():
        related_manager = getattr(person, field.popolo_array)
        type_kwargs = {field.info_type_key: field.info_type}
        related_manager.filter(**type_kwargs).delete()

    # Then recreate any that should be there:
    for field in ComplexPopoloField.objects.all():
        new_value = version_data.get(field.name, '')
        if new_value:
            person_extra.update_complex_field(field, version_data[field.name])

    # Remove any extra field data and create them from the JSON:
    person.extra_field_values.all().delete()
    extra_fields_from_version = version_data.get('extra_fields', {})
    for extra_field in ExtraField.objects.all():
        value = extra_fields_from_version.get(extra_field.key)
        if value is not None:
            person.extra_field_values.create(
                field=extra_field,
                value=value,
            )

    # Other fields to preserve:
    person.image = version_data.get('image')

    # Remove all other names, and recreate:
    person.other_names.all().delete()
    for on in version_data.get('other_names', []):
        person.other_names.create(
            name=on['name'],
            note=on.get('note', ''),
            start_date=on.get('start_date'),
            end_date=on.get('end_date'),
        )

    # Remove all identifiers, and recreate:
    person.identifiers.all().delete()
    for i in version_data.get('identifiers', []):
        person.identifiers.create(
            scheme=i['scheme'],
            identifier=i['identifier'],
        )

    # Remove all candidacies, and recreate:
    for membership in Membership.objects.filter(
            person=person_extra.base,
            role=F('post_election__election__candidate_membership_role')):
        # At the moment the merge code has its own way of preserving
        # the uk_results CandidateResult data (see
        # additional_merge_actions), so they will be
        # recreated. (FIXME: omitting this check when merging does
        # mean that we're not checking for other models in the future
        # that may have a foreign key to Membership when doing
        # merges.)
        if not part_of_merge:
            raise_if_unsafe_to_delete(membership)
        membership.delete()
    # Also remove the indications of elections that this person is
    # known not to be standing in:
    person_extra.not_standing.clear()
    for election_slug, standing_in in version_data['standing_in'].items():
        election = Election.objects.get(slug=election_slug)
        # If the value for that election slug is None, then that means
        # the person is known not to be standing:
        if standing_in is None:
            person_extra.not_standing.add(election)
        else:
            # Get the corresponding party membership data:
            party = Organization.objects.get(
                extra__slug=version_data['party_memberships'][election_slug]
                ['id'])
            post = Post.objects.get(extra__slug=standing_in['post_id'])
            Membership.objects.create(
                on_behalf_of=party,
                person=person,
                post=post,
                role=election.candidate_membership_role,
                elected=standing_in.get('elected'),
                party_list_position=standing_in.get('party_list_position'),
                post_election=election.postextraelection_set.get(
                    postextra=post.extra))

    person.save()
    person_extra.save()
    try:
        update_twitter_user_id(person)
    except TwitterAPITokenMissing:
        pass
Ejemplo n.º 10
0
def revert_person_from_version_data(person, version_data):

    from popolo.models import Membership
    from candidates.models import raise_if_unsafe_to_delete

    from elections.models import Election

    for field in settings.SIMPLE_POPOLO_FIELDS:
        new_value = version_data.get(field.name)
        if new_value:
            setattr(person, field.name, new_value)
        else:
            setattr(person, field.name, "")

    person.favourite_biscuit = version_data.get("extra_fields",
                                                {}).get("favourite_biscuits")

    # Remove old PersonIdentifier objects
    from people.models import PersonIdentifier

    PersonIdentifier.objects.filter(
        person=person).editable_value_types().delete()

    # Add PersonIdentifier objects we want back again
    # TODO: https://github.com/DemocracyClub/yournextrepresentative/issues/697
    for field in PersonIdentifierFields:
        new_value = version_data.get(field.name, "")
        if new_value:
            PersonIdentifier.objects.update_or_create(person=person,
                                                      value=new_value,
                                                      value_type=field.name)

    # Remove all other names, and recreate:
    person.other_names.all().delete()
    for on in version_data.get("other_names", []):
        person.other_names.create(
            name=on["name"],
            note=on.get("note", ""),
            start_date=on.get("start_date"),
            end_date=on.get("end_date"),
        )

    # Remove all candidacies, and recreate:
    qs = (Membership.objects.filter(person=person).filter(result=None).filter(
        ballot__candidates_locked=False))
    for membership in qs:
        raise_if_unsafe_to_delete(membership)
        membership.delete()
    # Also remove the indications of elections that this person is
    # known not to be standing in:
    person.not_standing.clear()
    for ballot_paper_id, candidacy in version_data["candidacies"].items():
        ballot = Ballot.objects.get(ballot_paper_id=ballot_paper_id)
        # Get the corresponding party membership data:
        party = Party.objects.get(ec_id=candidacy["party"])
        Membership.objects.update_or_create(
            person=person,
            ballot=ballot,
            defaults={
                "party": party,
                "post": ballot.post,  # TODO: Remove this
                "elected": candidacy.get("elected"),
                "party_list_position": candidacy.get("party_list_position"),
            },
        )
    for election_slug in version_data.get("not_standing", []):
        election = Election.objects.get(slug=election_slug)
        person.not_standing.add(election)

    person.save()
Ejemplo n.º 11
0
def revert_person_from_version_data(person, version_data):

    from popolo.models import Membership, Organization, Post
    from candidates.models import raise_if_unsafe_to_delete

    from elections.models import Election

    for field in settings.SIMPLE_POPOLO_FIELDS:
        new_value = version_data.get(field.name)
        if new_value:
            setattr(person, field.name, new_value)
        else:
            setattr(person, field.name, "")

    # Remove old PersonIdentifier objects
    from people.models import PersonIdentifier

    PersonIdentifier.objects.filter(
        person=person).editable_value_types().delete()

    # Add PersonIdentifier objects we want back again
    # TODO: https://github.com/DemocracyClub/yournextrepresentative/issues/697
    for field in PersonIdentifierFields:
        new_value = version_data.get(field.name, "")
        if new_value:
            PersonIdentifier.objects.update_or_create(person=person,
                                                      value=new_value,
                                                      value_type=field.name)

    # Remove all other names, and recreate:
    person.other_names.all().delete()
    for on in version_data.get("other_names", []):
        person.other_names.create(
            name=on["name"],
            note=on.get("note", ""),
            start_date=on.get("start_date"),
            end_date=on.get("end_date"),
        )

    # Remove all candidacies, and recreate:
    for membership in Membership.objects.filter(person=person):
        raise_if_unsafe_to_delete(membership)
        membership.delete()
    # Also remove the indications of elections that this person is
    # known not to be standing in:
    person.not_standing.clear()
    for election_slug, standing_in in version_data["standing_in"].items():
        election = Election.objects.get(slug=election_slug)
        # If the value for that election slug is None, then that means
        # the person is known not to be standing:
        if standing_in is None:
            person.not_standing.add(election)
        else:
            # Get the corresponding party membership data:
            party = Party.objects.get(
                legacy_slug=version_data["party_memberships"][election_slug]
                ["id"])
            post = Post.objects.get(slug=standing_in["post_id"])
            Membership.objects.create(
                party=party,
                person=person,
                post=post,
                role=election.candidate_membership_role,
                elected=standing_in.get("elected"),
                party_list_position=standing_in.get("party_list_position"),
                post_election=election.postextraelection_set.get(post=post),
            )

    person.save()