def test_no_duplicate_versions(self):
        self.person.record_version(get_change_metadata(None, "First update"))
        self.assertEqual(len(json.loads(self.person.versions)), 1)

        self.person.record_version(get_change_metadata(None, "Nothing changed"))
        self.assertEqual(len(json.loads(self.person.versions)), 1)

        self.person.name = "New Name"
        self.person.record_version(get_change_metadata(None, "Nothing changed"))
        self.assertEqual(len(json.loads(self.person.versions)), 2)
    def update_popit_person(self, popit_person_id, ppc_data, image_filename):
        from candidates.models import PopItPerson
        from ..images import image_uploaded_already

        # Get the existing data first:
        person_data, _ = self.get_person(popit_person_id)
        previous_versions = person_data.pop("versions")
        new_person_data = self.get_person_data_from_ppc(ppc_data)
        # Remove any empty keys, we don't want to overwrite exiting
        # data with nothing:
        keys = new_person_data.keys()
        warnings = []
        for key in keys:
            if not new_person_data[key]:
                del new_person_data[key]
            # Also make sure that we don't overwrite any existing
            # fields that are filled in with different values:
            if key not in ("standing_in", "party_memberships"):
                new_person_data_value = new_person_data.get(key)
                person_data_value = person_data.get(key)
                if (person_data_value and new_person_data_value
                        and new_person_data_value != person_data_value):
                    if key_value_appeared_in_previous_version(
                            key, new_person_data_value, previous_versions):
                        warning_message = "[{0}] it looks as if a previous "
                        warning_message += "version had {1}, so not "
                        warning_message += "overwriting the current value {2}"
                        warnings.append(
                            warning_message.format(key, new_person_data_value,
                                                   person_data_value))
                        del new_person_data[key]
                    else:
                        warnings.append("[{}] replacing      {}".format(
                            key, person_data_value))
                        warnings.append("[{}] with new value {}".format(
                            key, new_person_data_value))
        if warnings:
            print("Warnings for person/{} {}".format(
                popit_person_id, person_data["name"]).encode("utf-8"))
            for warning in warnings:
                print("  ...", warning.encode("utf-8"))
        merged_person_data = merge_person_data(person_data, new_person_data)
        change_metadata = get_change_metadata(
            None,
            "Updated candidate from official PPC data ({})".format(
                ppc_data["party_slug"]),
        )
        person = PopItPerson.create_from_reduced_json(merged_person_data)
        person.record_version(change_metadata)
        person_id = person.save_to_popit(self.api)
        if image_filename:
            if image_uploaded_already(self.api.persons, person_id,
                                      image_filename):
                print("That image has already been uploaded!")
            else:
                print("Uploading image...")
                self.upload_person_image(person_id, image_filename,
                                         ppc_data["image_url"])
        person.invalidate_cache_entries()
        return person_id
Beispiel #3
0
 def get_change_metadata_for_bot(self, source):
     """
     Wraps get_change_metadata without requiring a request object
     """
     metadata = get_change_metadata(None, source)
     metadata["username"] = self.user.username
     return metadata
    def add_person(self, person_data):
        # TODO Move this out of the view layer
        person = Person.objects.create(name=person_data['name'])
        person_extra = PersonExtra.objects.create(base=person)
        check_creation_allowed(
            self.request.user, person_extra.current_candidacies
        )

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

        person_extra.record_version(change_metadata)
        person_extra.save()

        LoggedAction.objects.create(
            user=self.request.user,
            person=person,
            action_type='person-create',
            ip_address=get_client_ip(self.request),
            popit_person_new_version=change_metadata['version_id'],
            source=change_metadata['information_source'],
        )

        # Add a message to be displayed after redirect:
        messages.add_message(
            self.request,
            messages.SUCCESS,
            get_call_to_action_flash_message(person, new_person=True),
            extra_tags='safe do-something-else'
        )
        return person_extra
Beispiel #5
0
    def add_person(self, person_data):
        # TODO Move this out of the view layer
        person = Person.objects.create(name=person_data['name'])
        person_extra = PersonExtra.objects.create(base=person)
        check_creation_allowed(self.request.user,
                               person_extra.current_candidacies)

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

        person_extra.record_version(change_metadata)
        person_extra.save()

        LoggedAction.objects.create(
            user=self.request.user,
            person=person,
            action_type='person-create',
            ip_address=get_client_ip(self.request),
            popit_person_new_version=change_metadata['version_id'],
            source=change_metadata['information_source'],
        )

        # Add a message to be displayed after redirect:
        messages.add_message(self.request,
                             messages.SUCCESS,
                             get_call_to_action_flash_message(person,
                                                              new_person=True),
                             extra_tags='safe do-something-else')
        return person_extra
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"],
    )
 def update_popit_person(self, popit_person_id, ppc_data, image_filename):
     from candidates.models import PopItPerson
     from ..images import image_uploaded_already
     # Get the existing data first:
     person_data, _ = self.get_person(popit_person_id)
     previous_versions = person_data.pop('versions')
     new_person_data = self.get_person_data_from_ppc(ppc_data)
     # Remove any empty keys, we don't want to overwrite exiting
     # data with nothing:
     keys = new_person_data.keys()
     warnings = []
     for key in keys:
         if not new_person_data[key]:
             del new_person_data[key]
         # Also make sure that we don't overwrite any existing
         # fields that are filled in with different values:
         if key not in ('standing_in', 'party_memberships'):
             new_person_data_value = new_person_data.get(key)
             person_data_value = person_data.get(key)
             if person_data_value and new_person_data_value and new_person_data_value != person_data_value:
                 if key_value_appeared_in_previous_version(
                     key,
                     new_person_data_value,
                     previous_versions
                 ):
                     warning_message = "[{0}] it looks as if a previous "
                     warning_message += "version had {1}, so not "
                     warning_message += "overwriting the current value {2}"
                     warnings.append(warning_message.format(
                         key,
                         new_person_data_value,
                         person_data_value
                     ))
                     del new_person_data[key]
                 else:
                     warnings.append("[{0}] replacing      {1}".format(key, person_data_value))
                     warnings.append("[{0}] with new value {1}".format(key, new_person_data_value))
     if warnings:
         print("Warnings for person/{0} {1}".format(
             popit_person_id, person_data['name']
         ).encode('utf-8'))
         for warning in warnings:
             print("  ...", warning.encode('utf-8'))
     merged_person_data = merge_person_data(person_data, new_person_data)
     change_metadata = get_change_metadata(
         None,
         'Updated candidate from official PPC data ({0})'.format(ppc_data['party_slug']),
     )
     person = PopItPerson.create_from_reduced_json(merged_person_data)
     person.record_version(change_metadata)
     person_id = person.save_to_popit(self.api)
     if image_filename:
         if image_uploaded_already(self.api.persons, person_id, image_filename):
             print("That image has already been uploaded!")
         else:
             print("Uploading image...")
             self.upload_person_image(person_id, image_filename, ppc_data['image_url'])
     person.invalidate_cache_entries()
     return person_id
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'],
    )
    def handle(self, **options):

        for person_popit_data in popit_unwrap_pagination(
                self.api.persons,
                per_page=100
        ):
            # Exclude anyone who doesn't have a parlparse ID; this is
            # more or less the incumbents (by-elections causing the
            # "more or less" bit.)
            if not get_parlparse_id(person_popit_data):
                continue

            if '2015' in person_popit_data['standing_in']:
                print "We already have 2015 information for", person_popit_data['name']
                continue

            person = PopItPerson.create_from_dict(person_popit_data)

            print "Considering person:", person.name

            cons_id = person.standing_in['2010']['post_id']
            party_id = person.party_memberships['2010']['id']
            party_name = person.party_memberships['2010']['name']
            cons_url = 'https://yournextmp.com/constituency/{0}'.format(cons_id)

            # We're now considering marking the candidate as standing
            # again in the same consituency as in 2010. Check that
            # there's not another candidate from their party already
            # marked as standing in that consituency.

            if self.existing_candidate_same_party(cons_id, party_id):
                msg = u"There was already a candidate for {0} in {1} - skipping"
                print msg.format(party_name, cons_url).format('utf-8')
                continue

            # Now it should be safe to update the candidate and set
            # them as standing in 2015.

            person.standing_in['2015'] = person.standing_in['2010']
            person.party_memberships['2015'] = person.party_memberships['2010']

            person.record_version(
                get_change_metadata(
                    None,
                    "Assuming that incumbents we don't have definite information on yet are standing again",
                )
            )
            person.save_to_popit(self.api)
            person.invalidate_cache_entries()

            message = u"Marked an incumbent ({name} - {party}) as standing again in {cons_url}"
            print message.format(
                name=person.name,
                party=party_name,
                cons_url=cons_url,
            ).encode('utf-8')
    def handle(self, **options):

        for person_popit_data in popit_unwrap_pagination(self.api.persons,
                                                         per_page=100):
            # Exclude anyone who doesn't have a parlparse ID; this is
            # more or less the incumbents (by-elections causing the
            # "more or less" bit.)
            if not get_parlparse_id(person_popit_data):
                continue

            if '2015' in person_popit_data['standing_in']:
                print "We already have 2015 information for", person_popit_data[
                    'name']
                continue

            person = PopItPerson.create_from_dict(person_popit_data)

            print "Considering person:", person.name

            cons_id = person.standing_in['2010']['post_id']
            party_id = person.party_memberships['2010']['id']
            party_name = person.party_memberships['2010']['name']
            cons_url = 'https://yournextmp.com/constituency/{0}'.format(
                cons_id)

            # We're now considering marking the candidate as standing
            # again in the same consituency as in 2010. Check that
            # there's not another candidate from their party already
            # marked as standing in that consituency.

            if self.existing_candidate_same_party(cons_id, party_id):
                msg = u"There was already a candidate for {0} in {1} - skipping"
                print msg.format(party_name, cons_url).format('utf-8')
                continue

            # Now it should be safe to update the candidate and set
            # them as standing in 2015.

            person.standing_in['2015'] = person.standing_in['2010']
            person.party_memberships['2015'] = person.party_memberships['2010']

            person.record_version(
                get_change_metadata(
                    None,
                    "Assuming that incumbents we don't have definite information on yet are standing again",
                ))
            person.save_to_popit(self.api)
            person.invalidate_cache_entries()

            message = u"Marked an incumbent ({name} - {party}) as standing again in {cons_url}"
            print message.format(
                name=person.name,
                party=party_name,
                cons_url=cons_url,
            ).encode('utf-8')
 def add_popit_person(self, ppc_data, image_filename):
     change_metadata = get_change_metadata(
         None,
         'Created new candidate from official PPC data ({0})'.format(ppc_data['party_slug']),
     )
     person_data = self.get_person_data_from_ppc(ppc_data)
     person = PopItPerson.create_from_reduced_json(person_data)
     person.record_version(change_metadata)
     person_id = person.save_to_popit(self.api)
     if image_filename:
         self.upload_person_image(person_id, image_filename, ppc_data['image_url'])
     person.invalidate_cache_entries()
     return person_id
Beispiel #12
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'],
        )
Beispiel #13
0
    def handle(self, *args, **options):
        person = Person.objects.get(pk=options["PERSON-ID"])
        person.identifiers.create(scheme=options["SCHEME"],
                                  identifier=options["IDENTIFIER"])

        if options["source"]:
            source = options["source"]
        else:
            source = "Added from the command-line with no source supplied"

        change_metadata = get_change_metadata(None, source)
        person.record_version(change_metadata)
        person.save()

        print("Successfully updated {}".format(person.name))
Beispiel #14
0
    def update_person(self, context, data, person_extra):
        party = Organization.objects.get(pk=data['party'])
        post = context['post_extra'].base
        election = Election.objects.get(slug=context['election'])

        previous_memberships_in_this_election = Membership.objects.filter(
            person=person_extra.base,
            extra__election=election,
            role=election.candidate_membership_role,
        )

        previous_memberships_in_this_election.delete()
        person_extra.not_standing.remove(election)

        membership, _ = Membership.objects.get_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': False,
            }
        )

        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'],
        )
Beispiel #15
0
 def add_parlparse_id_to_member(self, member):
     # Try and find the corresponding person in the popit instance
     name = u'{} {}'.format(member['firstname'], member['lastname'])
     query = u'"{}"'.format(name)
     result = self.popit.api.search.persons.get(q=query)['result']
     # Have we not got any results?
     if len(result) == 0:
         if self.verbosity > 0:
             msg = u'No results for {}, skipping'
             self.stderr.write(msg.format(name))
         return
     # Find the person with a matching constituency
     person = self.person_match(member=member, people=result)
     if not person:
         if self.verbosity > 0:
             msg = u'{} result but no matches found for {}'
             self.stderr.write(msg.format(len(result), name))
         return
     parlparse_id = self.id_mapping[name]
     person_data, _ = self.get_person(person['id'])
     previous_versions = person_data.pop('versions')
     identifiers = person_data.get('identifiers', [])
     existing_identifiers = [i['identifier'] for i in identifiers]
     # Does that person already have this identifier?
     if parlparse_id in existing_identifiers:
         if self.verbosity > 1:
             msg = u'Found existing identifier for {} ({}), skipping'
             self.stderr.write(msg.format(name, parlparse_id))
         return
     identifier = {
         'identifier': parlparse_id,
         'scheme': 'uk.org.publicwhip'
     }
     identifiers.append(identifier)
     person_data['identifiers'] = identifiers
     change_metadata = get_change_metadata(
         None,
         'Updated candidate with parlparse person id',
     )
     self.update_person(
         person_data,
         change_metadata,
         previous_versions,
     )
     if self.verbosity > 0:
         msg = u"Successfully updated {} with {}"
         self.stdout.write(msg.format(name, parlparse_id))
    def mark_candidates_as_winner(self, request, instance):
        for candidate_result in instance.candidate_results.all():
            membership = candidate_result.membership
            post = instance.post_result.post
            election = membership.extra.election

            source = instance.review_source
            if not source:
                source = instance.source

            change_metadata = get_change_metadata(
                request, source
            )


            if candidate_result.is_winner:
                membership.extra.elected = True
                membership.extra.save()


                ResultEvent.objects.create(
                    election=election,
                    winner=membership.person,
                    winner_person_name=membership.person.name,
                    post_id=post.extra.slug,
                    post_name=post.label,
                    winner_party_id=membership.on_behalf_of.extra.slug,
                    source=source,
                    user=instance.reviewed_by,
                )

                membership.person.extra.record_version(change_metadata)
                membership.person.save()

                LoggedAction.objects.create(
                    user=instance.reviewed_by,
                    action_type='set-candidate-elected',
                    popit_person_new_version=change_metadata['version_id'],
                    person=membership.person,
                    source=source,
                )
            else:
                change_metadata['information_source'] = \
                    'Setting as "not elected" by implication'
                membership.person.extra.record_version(change_metadata)
                membership.extra.elected = False
                membership.extra.save()
    def handle(self, *args, **options):
        from candidates.models import PopItPerson
        from candidates.popit import create_popit_api_object

        self.verbosity = int(options.get('verbosity', 1))
        api = create_popit_api_object()
        if len(args) != 1:
            raise CommandError("You must provide a person.js URL")
        person_js_url = args[0]
        people_data = requests.get(person_js_url).json()
        for person_data in people_data['persons']:
            twfy_person = PopItPerson.create_from_dict(person_data)
            ynmp_id = twfy_person.get_identifier('yournextmp')
            if not ynmp_id:
                continue
            parlparse_id = twfy_person.id
            ynmp_person = PopItPerson.create_from_popit(api, ynmp_id)
            existing_parlparse_id = ynmp_person.get_identifier('uk.org.publicwhip')
            if existing_parlparse_id:
                if existing_parlparse_id == parlparse_id:
                    # That's fine, there's already the right parlparse ID
                    pass
                else:
                    # Otherwise there's a mismatch, which needs investigation
                    msg = "Warning: parlparse ID mismatch between YNMP {0} "
                    msg += "and TWFY {1} for YNMP person {2}\n"
                    self.stderr.write(
                        msg.format(
                            existing_parlparse_id,
                            parlparse_id,
                            ynmp_id,
                        )
                    )
                continue
            msg = "Updating the YourNextMP person {0} with parlparse_id {1}\n"
            self.stdout.write(msg.format(ynmp_id, parlparse_id))
            ynmp_person.set_identifier(
                'uk.org.publicwhip',
                parlparse_id,
            )
            change_metadata = get_change_metadata(
                None, "Fetched a new parlparse ID"
            )
            ynmp_person.record_version(change_metadata)
            ynmp_person.save_to_popit(api)
            ynmp_person.invalidate_cache_entries()
    def merge(self, delete=True):
        """
        Do everything we need in order to merge two people.

        At the end of this, `self.source_person` should have no related objects
        left, and is deleted safely using `self.safe_delete`
        """
        with transaction.atomic():
            # Merge all the things
            self.merge_person_attrs()
            self.merge_versions_json()
            self.merge_person_identifiers()
            self.merge_images()
            self.merge_logged_actions()
            self.merge_memberships()
            self.merge_queued_images()
            self.merge_not_standing()
            self.merge_result_events()

            # Post merging tasks
            # Save the dest person (don't assume the methods above do this)
            change_metadata = get_change_metadata(
                self.request,
                "After merging person {}".format(self.source_person.pk),
            )

            # Log that the merge has taken place, and will be shown in
            # the recent changes, leaderboards, etc.
            if self.request:
                LoggedAction.objects.create(
                    user=self.request.user,
                    action_type="person-merge",
                    ip_address=get_client_ip(self.request),
                    popit_person_new_version=change_metadata["version_id"],
                    person=self.dest_person,
                    source=change_metadata["information_source"],
                )

            self.dest_person.record_version(change_metadata)
            self.dest_person.save()

            self.setup_redirect()

            if delete:
                # Delete the old person
                self.safe_delete(self.source_person)
    def handle(self, *args, **options):
        person = Person.objects.get(pk=options['PERSON-ID'])
        person.identifiers.create(
            scheme=options['SCHEME'],
            identifier=options['IDENTIFIER'],
        )

        if options['source']:
            source = options['source']
        else:
            source = "Added from the command-line with no source supplied"

        change_metadata = get_change_metadata(None, source)
        person.extra.record_version(change_metadata)
        person.extra.save()

        print "Successfully updated {0}".format(person.name)
def add_person(request, person_data):
    person = Person.objects.create(name=person_data["name"])

    change_metadata = get_change_metadata(request, person_data["source"])

    person.record_version(change_metadata, new_person=True)
    person.save()

    LoggedAction.objects.create(
        user=request.user,
        person=person,
        action_type="person-create",
        ip_address=get_client_ip(request),
        popit_person_new_version=change_metadata["version_id"],
        source=change_metadata["information_source"],
    )
    return person
    def handle(self, *args, **options):
        from candidates.models import PopItPerson
        from candidates.popit import create_popit_api_object

        self.verbosity = int(options.get('verbosity', 1))
        api = create_popit_api_object()
        if len(args) != 1:
            raise CommandError("You must provide a person.js URL")
        person_js_url = args[0]
        people_data = requests.get(person_js_url).json()
        for person_data in people_data['persons']:
            twfy_person = PopItPerson.create_from_dict(person_data)
            ynmp_id = twfy_person.get_identifier('yournextmp')
            if not ynmp_id:
                continue
            parlparse_id = twfy_person.id
            ynmp_person = PopItPerson.create_from_popit(api, ynmp_id)
            existing_parlparse_id = ynmp_person.get_identifier(
                'uk.org.publicwhip')
            if existing_parlparse_id:
                if existing_parlparse_id == parlparse_id:
                    # That's fine, there's already the right parlparse ID
                    pass
                else:
                    # Otherwise there's a mismatch, which needs investigation
                    msg = "Warning: parlparse ID mismatch between YNMP {0} "
                    msg += "and TWFY {1} for YNMP person {2}\n"
                    self.stderr.write(
                        msg.format(
                            existing_parlparse_id,
                            parlparse_id,
                            ynmp_id,
                        ))
                continue
            msg = "Updating the YourNextMP person {0} with parlparse_id {1}\n"
            self.stdout.write(msg.format(ynmp_id, parlparse_id))
            ynmp_person.set_identifier(
                'uk.org.publicwhip',
                parlparse_id,
            )
            change_metadata = get_change_metadata(
                None, "Fetched a new parlparse ID")
            ynmp_person.record_version(change_metadata)
            ynmp_person.save_to_popit(api)
            ynmp_person.invalidate_cache_entries()
def add_person(request, person_data):
    person = Person.objects.create(name=person_data['name'])
    person_extra = PersonExtra.objects.create(base=person)

    change_metadata = get_change_metadata(request, person_data['source'])

    person_extra.record_version(change_metadata, new_person=True)
    person_extra.save()

    LoggedAction.objects.create(
        user=request.user,
        person=person,
        action_type='person-create',
        ip_address=get_client_ip(request),
        popit_person_new_version=change_metadata['version_id'],
        source=change_metadata['information_source'],
    )
    return person_extra
    def handle(self, *args, **options):
        person = Person.objects.get(pk=options["PERSON-ID"])
        kwargs = {"name": options["OTHER-NAME"]}
        for k in ("note", "start_date", "end_date"):
            if options[k]:
                kwargs[k] = options[k]
        person.other_names.create(**kwargs)

        if options["source"]:
            source = options["source"]
        else:
            source = "Added from the command-line with no source supplied"

        change_metadata = get_change_metadata(None, source)
        person.extra.record_version(change_metadata)
        person.extra.save()

        print "Successfully updated {0}".format(person.name)
    def handle(self, *args, **options):
        person = Person.objects.get(pk=options["PERSON-ID"])
        kwargs = {"name": options["OTHER-NAME"]}
        for k in ("note", "start_date", "end_date"):
            if options[k]:
                kwargs[k] = options[k]
        person.other_names.create(**kwargs)

        if options["source"]:
            source = options["source"]
        else:
            source = "Added from the command-line with no source supplied"

        change_metadata = get_change_metadata(None, source)
        person.record_version(change_metadata)
        person.save()

        print("Successfully updated {}".format(person.name))
Beispiel #25
0
    def mark_candidates_as_winner(self, request, instance):
        for candidate_result in instance.candidate_results.all():
            membership = candidate_result.membership
            post = instance.post_result.post
            election = membership.extra.election

            source = instance.review_source
            if not source:
                source = instance.source

            change_metadata = get_change_metadata(request, source)

            if candidate_result.is_winner:
                membership.extra.elected = True
                membership.extra.save()

                ResultEvent.objects.create(
                    election=election,
                    winner=membership.person,
                    winner_person_name=membership.person.name,
                    post_id=post.extra.slug,
                    post_name=post.label,
                    winner_party_id=membership.on_behalf_of.extra.slug,
                    source=source,
                    user=instance.reviewed_by,
                )

                membership.person.extra.record_version(change_metadata)
                membership.person.save()

                LoggedAction.objects.create(
                    user=instance.reviewed_by,
                    action_type='set-candidate-elected',
                    popit_person_new_version=change_metadata['version_id'],
                    person=membership.person,
                    source=source,
                )
            else:
                change_metadata['information_source'] = \
                    'Setting as "not elected" by implication'
                membership.person.extra.record_version(change_metadata)
                membership.extra.elected = False
                membership.extra.save()
Beispiel #26
0
    def merge(self, delete=True):
        """
        Do everything we need in order to merge two people.

        At the end of this, `self.source_person` should have no related objects
        left, and is deleted safely using `self.safe_delete`
        """
        with transaction.atomic():
            # Merge all the things
            for method_name in set(self.SUPPORTED_FIELDS.values()):
                method = getattr(self, method_name)
                method()

            # Post merging tasks
            # Save the dest person (don't assume the methods above do this)
            change_metadata = get_change_metadata(
                self.request,
                "After merging person {}".format(self.source_person.pk),
            )
            # Save the dest person before creating a LoggedAction
            # See https://github.com/DemocracyClub/yournextrepresentative/issues/1037
            # for more
            self.dest_person.record_version(change_metadata)
            self.dest_person.save()

            # Log that the merge has taken place, and will be shown in
            # the recent changes, leaderboards, etc.
            if self.request:
                LoggedAction.objects.create(
                    user=self.request.user,
                    action_type="person-merge",
                    ip_address=get_client_ip(self.request),
                    popit_person_new_version=change_metadata["version_id"],
                    person=self.dest_person,
                    source=change_metadata["information_source"],
                )

            self.setup_redirect()

            if delete:
                # Delete the old person
                self.safe_delete(self.source_person)
        return self.dest_person
    def handle(self, *args, **options):
        person = Person.objects.get(pk=options['PERSON-ID'])
        kwargs = {
            'name': options['OTHER-NAME'],
        }
        for k in ('note', 'start_date', 'end_date'):
            if options[k]:
                kwargs[k] = options[k]
        person.other_names.create(**kwargs)

        if options['source']:
            source = options['source']
        else:
            source = "Added from the command-line with no source supplied"

        change_metadata = get_change_metadata(None, source)
        person.extra.record_version(change_metadata)
        person.extra.save()

        print("Successfully updated {0}".format(person.name))
Beispiel #28
0
def mark_candidates_as_winner(request, instance):
    for candidate_result in instance.candidate_results.all():
        membership = candidate_result.membership
        post_election = instance.post_election
        election = post_election.election

        source = instance.source

        change_metadata = get_change_metadata(request, source)

        if candidate_result.is_winner:
            membership.elected = True
            membership.save()

            ResultEvent.objects.create(
                election=election,
                winner=membership.person,
                post=post_election.post,
                old_post_id=post_election.post.slug,
                old_post_name=post_election.post.label,
                winner_party=membership.party,
                source=source,
                user=request.user,
            )

            membership.person.record_version(change_metadata)
            membership.person.save()

            LoggedAction.objects.create(
                user=instance.user,
                action_type="set-candidate-elected",
                popit_person_new_version=change_metadata["version_id"],
                person=membership.person,
                source=source,
            )
        else:
            change_metadata[
                "information_source"] = 'Setting as "not elected" by implication'
            membership.person.record_version(change_metadata)
            membership.elected = False
            membership.save()
Beispiel #29
0
    def add_person(self, person_data):
        # TODO Move this out of the view layer
        person = Person.objects.create(name=person_data['name'])
        person_extra = PersonExtra.objects.create(base=person)
        check_creation_allowed(self.request.user,
                               person_extra.current_candidacies)

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

        person_extra.record_version(change_metadata)
        person_extra.save()

        LoggedAction.objects.create(
            user=self.request.user,
            person=person,
            action_type='person-create',
            ip_address=get_client_ip(self.request),
            popit_person_new_version=change_metadata['version_id'],
            source=change_metadata['information_source'],
        )

        return person_extra
Beispiel #30
0
    def form_valid(self, form):
        decision = form.cleaned_data['decision']
        person = Person.objects.get(
            id=self.queued_image.person.id
        )
        person_extra = person.extra
        candidate_path = person_extra.get_absolute_url()
        candidate_name = person.name
        candidate_link = '<a href="{url}">{name}</a>'.format(
            url=candidate_path,
            name=candidate_name,
        )
        photo_review_url = self.request.build_absolute_uri(
            self.queued_image.get_absolute_url()
        )
        site_name = Site.objects.get_current().name
        def flash(level, message):
            messages.add_message(
                self.request,
                level,
                message,
                extra_tags='safe photo-review'
            )
        if self.queued_image.user:
            uploaded_by = self.queued_image.user.username
        else:
            uploaded_by = _("a script")

        if decision == 'approved':
            # Crop the image...
            crop_fields = ('x_min', 'y_min', 'x_max', 'y_max')
            self.crop_and_upload_image_to_popit(
                self.queued_image.image.path,
                [form.cleaned_data[e] for e in crop_fields],
                form.cleaned_data['moderator_why_allowed'],
                form.cleaned_data['make_primary'],
            )
            self.queued_image.decision = 'approved'
            for i, field in enumerate(crop_fields):
                setattr(
                    self.queued_image,
                    'crop_' + field,
                    form.cleaned_data[field]
                )
            self.queued_image.save()

            update_message = _('Approved a photo upload from '
                '{uploading_user} who provided the message: '
                '"{message}"').format(
                uploading_user=uploaded_by,
                message=self.queued_image.justification_for_use,
            )
            change_metadata = get_change_metadata(
                self.request,
                update_message
            )
            person_extra.record_version(change_metadata)
            person_extra.save()
            person.save()
            LoggedAction.objects.create(
                user=self.request.user,
                action_type='photo-approve',
                ip_address=get_client_ip(self.request),
                popit_person_new_version=change_metadata['version_id'],
                person=person,
                source=update_message,
            )
            candidate_full_url = person_extra.get_absolute_url(self.request)
            self.send_mail(
                _('{site_name} image upload approved').format(
                    site_name=site_name
                ),
                render_to_string(
                    'moderation_queue/photo_approved_email.txt',
                    {
                        'site_name': site_name,
                        'candidate_page_url': candidate_full_url,
                        'intro': _(
                            "Thank-you for submitting a photo to "
                            "{site_name}; that's been uploaded now for "
                            "the candidate page here:"
                        ).format(site_name=site_name),
                        'signoff': _(
                            "Many thanks from the {site_name} volunteers"
                        ).format(site_name=site_name),
                    }
                ),
            )
            flash(
                messages.SUCCESS,
                _('You approved a photo upload for %s') % candidate_link
            )
        elif decision == 'rejected':
            self.queued_image.decision = 'rejected'
            self.queued_image.save()
            update_message = _('Rejected a photo upload from '
                '{uploading_user}').format(
                uploading_user=uploaded_by,
            )
            LoggedAction.objects.create(
                user=self.request.user,
                action_type='photo-reject',
                ip_address=get_client_ip(self.request),
                popit_person_new_version='',
                person=person,
                source=update_message,
            )
            retry_upload_link = self.request.build_absolute_uri(
                reverse(
                    'photo-upload',
                    kwargs={'person_id': self.queued_image.person.id}
                )
            )
            self.send_mail(
                _('{site_name} image moderation results').format(
                    site_name=Site.objects.get_current().name
                ),
                render_to_string(
                    'moderation_queue/photo_rejected_email.txt',
                    {
                        'reason': form.cleaned_data['rejection_reason'],
                        'retry_upload_link': retry_upload_link,
                        'photo_review_url': photo_review_url,
                        'intro': _(
                            "Thank-you for uploading a photo of "
                            "{candidate_name} to {site_name}, but "
                            "unfortunately we can't use that image because:"
                        ).format(
                            candidate_name=candidate_name,
                            site_name=site_name
                        ),
                        'possible_actions': _(
                            'You can just reply to this email if you want to '
                            'discuss that further, or you can try uploading a '
                            'photo with a different reason or justification '
                            'for its use using this link:'
                        ),
                        'signoff': _(
                            "Many thanks from the {site_name} volunteers"
                        ).format(site_name=site_name),
                    },
                ),
                email_support_too=True,
            )
            flash(
                messages.INFO,
                _('You rejected a photo upload for %s') % candidate_link
            )
        elif decision == 'undecided':
            # If it's left as undecided, just redirect back to the
            # photo review queue...
            flash(
                messages.INFO,
                _('You left a photo upload for {0} in the queue').format(
                    candidate_link
                )
            )
        elif decision == 'ignore':
            self.queued_image.decision = 'ignore'
            self.queued_image.save()
            update_message = _('Ignored a photo upload from '
                '{uploading_user} (This usually means it was a duplicate)').format(
                uploading_user=uploaded_by)
            LoggedAction.objects.create(
                user=self.request.user,
                action_type='photo-ignore',
                ip_address=get_client_ip(self.request),
                popit_person_new_version='',
                person=person,
                source=update_message,
            )
            flash(
                messages.INFO,
                _('You indicated a photo upload for {0} should be ignored').format(
                    candidate_link
                )
            )
        else:
            raise Exception("BUG: unexpected decision {0}".format(decision))
        return HttpResponseRedirect(reverse('photo-review-list'))
Beispiel #31
0
 def form_valid(self, form):
     decision = form.cleaned_data['decision']
     if decision == 'approved':
         # Crop the image...
         self.crop_and_upload_image_to_popit(
             self.queued_image.image.path,
             [form.cleaned_data[e] for e in
              ('x_min', 'y_min', 'x_max', 'y_max')],
             form.cleaned_data['moderator_why_allowed']
         )
         self.queued_image.decision = 'approved'
         self.queued_image.save()
         # Now create a new version in PopIt:
         person_data, _ = self.get_person(
             self.queued_image.popit_person_id
         )
         previous_versions = person_data.pop('versions')
         update_message = (u'Approved a photo upload from ' +
             u'{uploading_user} who provided the message: ' +
             u'"{message}"').format(
             uploading_user=self.queued_image.user.username,
             message=self.queued_image.justification_for_use,
         )
         change_metadata = get_change_metadata(
             self.request,
             update_message
         )
         self.update_person(
             person_data,
             change_metadata,
             previous_versions,
         )
         LoggedAction.objects.create(
             user=self.request.user,
             action_type='photo-approve',
             ip_address=get_client_ip(self.request),
             popit_person_new_version=change_metadata['version_id'],
             popit_person_id=self.queued_image.popit_person_id,
             source=update_message,
         )
         candidate_path = reverse(
             'person-view',
             kwargs={'person_id': self.queued_image.popit_person_id}
         )
         self.send_mail(
             'YourNextMP image upload approved',
             render_to_string(
                 'moderation_queue/photo_approved_email.txt',
                 {'candidate_page_url':
                  self.request.build_absolute_uri(candidate_path)}
             ),
         )
     elif decision == 'rejected':
         self.queued_image.decision = 'rejected'
         self.queued_image.save()
         update_message = u'Rejected a photo upload from ' + \
             u'{uploading_user}'.format(
             uploading_user=self.queued_image.user.username,
         )
         LoggedAction.objects.create(
             user=self.request.user,
             action_type='photo-reject',
             ip_address=get_client_ip(self.request),
             popit_person_new_version='',
             popit_person_id=self.queued_image.popit_person_id,
             source=update_message,
         )
         self.send_mail(
             'YourNextMP image moderation results',
             render_to_string(
                 'moderation_queue/photo_rejected_email.txt',
                 {'reason': form.cleaned_data['rejection_reason']}
             ),
         )
     elif decision == 'undecided':
         # If it's left as undecided, just redirect back to the
         # photo review queue...
         pass
     else:
         raise Exception("BUG: unexpected decision {0}".format(decision))
     return HttpResponseRedirect(reverse('photo-review-list'))
    def handle(self, username=None, **options):
        from slumber.exceptions import HttpClientError
        from candidates.popit import create_popit_api_object
        from candidates.election_specific import PARTY_DATA, shorten_post_label
        from candidates.models import PopItPerson

        if username is None:
            message = "You must supply the name of a user to be associated with the image uploads."
            raise CommandError(message)
        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            message = "No user with the username '{0}' could be found"
            raise CommandError(message.format(username))

        api = create_popit_api_object()

        json_filename = join(
            dirname(__file__), '..', '..','data', 'candidates.json'
        )
        with open(json_filename) as f:
            all_data = json.load(f)

        # This map is needed to get getting YNR election data from
        # the election ID used in the JSON file.
        json_election_id_to_name = {
            e['pk']: e['fields']['name']
            for e in all_data if e['model'] == 'elections.election'
        }

        person_dict = {
            e['pk']: e['fields']
            for e in all_data if e['model'] == 'popolo.person'
        }

        candidate_list = [
            dict(person_id=e['pk'], election_id=e['fields']['election'])
            for e in all_data if e['model'] == 'elections.candidate'
        ]

        for candidate in candidate_list:
            vi_person_id = candidate['person_id']
            person_data = person_dict[vi_person_id]
            election_data, post_data = get_post_data(
                api, candidate['election_id'], json_election_id_to_name
            )
            birth_date = None
            if person_data['birth_date']:
                birth_date = str(dateutil.parser.parse(
                    person_data['birth_date'], dayfirst=True
                ).date())
            name = person_data['name']
            gender = person_data['gender']
            image_url = person_data['image']

            person = get_existing_popit_person(vi_person_id)
            if person:
                print("Found an existing person:", person.get_absolute_url())
            else:
                print("No existing person, creating a new one:", name)
                person = PopItPerson()

            # Now update fields from the imported data:
            person.name = name
            person.gender = gender
            if birth_date:
                person.birth_date = str(birth_date)
            else:
                person.birth_date = None
            standing_in_election = {
                'post_id': post_data['id'],
                'name': shorten_post_label(post_data['label']),
            }
            if 'area' in post_data:
                standing_in_election['mapit_url'] = post_data['area']['identifier']
            person.standing_in = {
                election_data.slug: standing_in_election
            }
            person.party_memberships = {
                election_data.slug: {
                    'id': UNKNOWN_PARTY_ID,
                    'name': PARTY_DATA.party_id_to_name[UNKNOWN_PARTY_ID],
                }
            }
            person.set_identifier('import-id', vi_person_id)
            change_metadata = get_change_metadata(
                None,
                'Imported candidate from JSON',
            )

            person.record_version(change_metadata)
            try:
                person.save_to_popit(api)
                if image_url:
                    enqueue_image(person, user, image_url)
            except HttpClientError as hce:
                print("Got an HttpClientError:", hce.content)
                raise
Beispiel #33
0
 def form_valid(self, form):
     decision = form.cleaned_data['decision']
     if decision == 'approved':
         # Crop the image...
         self.crop_and_upload_image_to_popit(
             self.queued_image.image.path, [
                 form.cleaned_data[e]
                 for e in ('x_min', 'y_min', 'x_max', 'y_max')
             ], form.cleaned_data['moderator_why_allowed'])
         self.queued_image.decision = 'approved'
         self.queued_image.save()
         # Now create a new version in PopIt:
         person_data, _ = self.get_person(self.queued_image.popit_person_id)
         previous_versions = person_data.pop('versions')
         update_message = (
             u'Approved a photo upload from ' +
             u'{uploading_user} who provided the message: ' +
             u'"{message}"').format(
                 uploading_user=self.queued_image.user.username,
                 message=self.queued_image.justification_for_use,
             )
         change_metadata = get_change_metadata(self.request, update_message)
         self.update_person(
             person_data,
             change_metadata,
             previous_versions,
         )
         LoggedAction.objects.create(
             user=self.request.user,
             action_type='photo-approve',
             ip_address=get_client_ip(self.request),
             popit_person_new_version=change_metadata['version_id'],
             popit_person_id=self.queued_image.popit_person_id,
             source=update_message,
         )
         candidate_path = reverse(
             'person-view',
             kwargs={'person_id': self.queued_image.popit_person_id})
         self.send_mail(
             'YourNextMP image upload approved',
             render_to_string(
                 'moderation_queue/photo_approved_email.txt', {
                     'candidate_page_url':
                     self.request.build_absolute_uri(candidate_path)
                 }),
         )
     elif decision == 'rejected':
         self.queued_image.decision = 'rejected'
         self.queued_image.save()
         update_message = u'Rejected a photo upload from ' + \
             u'{uploading_user}'.format(
             uploading_user=self.queued_image.user.username,
         )
         LoggedAction.objects.create(
             user=self.request.user,
             action_type='photo-reject',
             ip_address=get_client_ip(self.request),
             popit_person_new_version='',
             popit_person_id=self.queued_image.popit_person_id,
             source=update_message,
         )
         self.send_mail(
             'YourNextMP image moderation results',
             render_to_string(
                 'moderation_queue/photo_rejected_email.txt',
                 {'reason': form.cleaned_data['rejection_reason']}),
         )
     elif decision == 'undecided':
         # If it's left as undecided, just redirect back to the
         # photo review queue...
         pass
     elif decision == 'ignore':
         self.queued_image.decision = 'ignore'
         self.queued_image.save()
     else:
         raise Exception("BUG: unexpected decision {0}".format(decision))
     return HttpResponseRedirect(reverse('photo-review-list'))
    def handle(self, **options):
        from slumber.exceptions import HttpClientError
        from candidates.cache import get_post_cached, UnknownPostException
        from candidates.election_specific import PARTY_DATA, shorten_post_label
        from candidates.models import PopItPerson
        from candidates.popit import create_popit_api_object

        spreadsheet_url = 'https://docs.google.com/spreadsheets/d/{0}/pub?output=csv'\
                              .format(GOOGLE_DOC_ID)

        candidate_list = requests.get(spreadsheet_url)

        content = StringIO(unicode(candidate_list.content))
        reader = csv.DictReader(content)

        api = create_popit_api_object()

        for row in reader:

            try:
                election_data = Election.objects.get_by_slug('council-member-2015')
                ocd_division = election_data.post_id_format.format(area_id=row['Ward'])
                post_data = get_post_cached(api, ocd_division)['result']
            except (UnknownPostException, memcache.Client.MemcachedKeyCharacterError):
                election_data = Election.objects.get_by_slug('school-board-2015')
                post_data = get_post_cached(api, election_data.post_id_format)['result']

            person_id = slugify(row['Name'])

            person = get_existing_popit_person(person_id)

            if person:
                print("Found an existing person:", row['Name'])
            else:
                print("No existing person, creating a new one:", row['Name'])
                person = PopItPerson()

            person.name = row['Name']

            # TODO: Get these attributes in the spreadsheet
            # person.gender = gender
            # if birth_date:
            #     person.birth_date = str(birth_date)
            # else:
            #     person.birth_date = None

            person.email = row['Campaign Email']
            person.facebook_personal_url = row["Candidate's Personal Facebook Profile"]
            person.facebook_page_url = row['Campaign Facebook Page']


            person.twitter_username = row['Campaign Twitter']\
                                          .replace('N', '')\
                                          .replace('N/A', '')\
                                          .replace('http://twitter.com/', '')\
                                          .replace('https://twitter.com/', '')

            person.linkedin_url = row['LinkedIn']
            person.homepage_url = row['Campaign Website\n']

            standing_in_election = {
                'post_id': post_data['id'],
                'name': shorten_post_label(post_data['label']),
            }
            if 'area' in post_data:
                standing_in_election['mapit_url'] = post_data['area']['identifier']
            person.standing_in = {
                election_data.slug: standing_in_election
            }

            if 'dfl' in row['Party'].lower():
                party_id = 'party:101'
            elif 'green' in row['Party'].lower():
                party_id = 'party:201'
            elif 'independence' in row['Party'].lower():
                party_id = 'party:301'
            else:
                party_id = 'party:401'


            party_name = PARTY_DATA.party_id_to_name[party_id]

            person.party_memberships = {
                election_data.slug: {
                    'id': party_id,
                    'name': party_name,
                }
            }

            person.set_identifier('import-id', person_id)
            change_metadata = get_change_metadata(
                None,
                'Imported candidate from Google Spreadsheet',
            )

            person.record_version(change_metadata)
            try:
                person.save_to_popit(api)

                # TODO: Get candidate Images
                # if image_url:
                #     enqueue_image(person, user, image_url)
            except HttpClientError as hce:
                print "Got an HttpClientError:", hce.content
                raise
    def form_valid(self, form):
        decision = form.cleaned_data["decision"]
        person = Person.objects.get(id=self.queued_image.person.id)

        candidate_path = person.get_absolute_url()
        candidate_name = person.name
        candidate_link = '<a href="{url}">{name}</a>'.format(
            url=candidate_path, name=candidate_name)
        photo_review_url = self.request.build_absolute_uri(
            self.queued_image.get_absolute_url())
        site_name = Site.objects.get_current().name

        def flash(level, message):
            messages.add_message(self.request,
                                 level,
                                 message,
                                 extra_tags="safe photo-review")

        if self.queued_image.user:
            uploaded_by = self.queued_image.user.username
        else:
            uploaded_by = _("a script")

        if decision == "approved":
            # Crop the image...
            crop_fields = ("x_min", "y_min", "x_max", "y_max")
            self.crop_and_upload_image_to_popit(
                self.queued_image.image.file,
                [form.cleaned_data[e] for e in crop_fields],
                form.cleaned_data["moderator_why_allowed"],
                form.cleaned_data["make_primary"],
            )
            self.queued_image.decision = "approved"
            for i, field in enumerate(crop_fields):
                setattr(self.queued_image, "crop_" + field,
                        form.cleaned_data[field])
            self.queued_image.save()

            sentence = "Approved a photo upload from {uploading_user}"
            ' who provided the message: "{message}"'

            update_message = _(sentence).format(
                uploading_user=uploaded_by,
                message=self.queued_image.justification_for_use,
            )
            change_metadata = get_change_metadata(self.request, update_message)
            person.record_version(change_metadata)
            person.save()
            person.save()
            LoggedAction.objects.create(
                user=self.request.user,
                action_type="photo-approve",
                ip_address=get_client_ip(self.request),
                popit_person_new_version=change_metadata["version_id"],
                person=person,
                source=update_message,
            )
            candidate_full_url = self.request.build_absolute_uri(
                person.get_absolute_url(self.request))

            self.send_mail(
                _("{site_name} image upload approved").format(
                    site_name=site_name),
                render_to_string(
                    "moderation_queue/photo_approved_email.txt",
                    {
                        "site_name":
                        site_name,
                        "candidate_page_url":
                        candidate_full_url,
                        "intro":
                        _("Thank you for submitting a photo to "
                          "{site_name}. It has been uploaded to "
                          "the candidate page here:").format(
                              site_name=site_name),
                        "signoff":
                        _("Many thanks from the {site_name} volunteers").
                        format(site_name=site_name),
                    },
                ),
            )
            flash(
                messages.SUCCESS,
                _("You approved a photo upload for %s") % candidate_link,
            )
        elif decision == "rejected":
            self.queued_image.decision = "rejected"
            self.queued_image.save()

            sentence = "Rejected a photo upload from {uploading_user}"

            update_message = _(sentence).format(uploading_user=uploaded_by)
            LoggedAction.objects.create(
                user=self.request.user,
                action_type="photo-reject",
                ip_address=get_client_ip(self.request),
                popit_person_new_version="",
                person=person,
                source=update_message,
            )
            retry_upload_link = self.request.build_absolute_uri(
                reverse(
                    "photo-upload",
                    kwargs={"person_id": self.queued_image.person.id},
                ))
            self.send_mail(
                _("{site_name} image moderation results").format(
                    site_name=Site.objects.get_current().name),
                render_to_string(
                    "moderation_queue/photo_rejected_email.txt",
                    {
                        "reason":
                        form.cleaned_data["rejection_reason"],
                        "retry_upload_link":
                        retry_upload_link,
                        "photo_review_url":
                        photo_review_url,
                        "intro":
                        _("Thank-you for uploading a photo of "
                          "{candidate_name} to {site_name}, "
                          "but unfortunately we can't use that image because:"
                          ).format(candidate_name=candidate_name,
                                   site_name=site_name),
                        "possible_actions":
                        _("You can just reply to this email if you want to "
                          "discuss that further, or you can try uploading a "
                          "photo with a different reason or justification "
                          "for its use using this link:"),
                        "signoff":
                        _("Many thanks from the {site_name} volunteers").
                        format(site_name=site_name),
                    },
                ),
                email_support_too=True,
            )
            flash(
                messages.INFO,
                _("You rejected a photo upload for %s") % candidate_link,
            )
        elif decision == "undecided":
            # If it's left as undecided, just redirect back to the
            # photo review queue...
            flash(
                messages.INFO,
                _("You left a photo upload for {0} in the queue").format(
                    candidate_link),
            )
        elif decision == "ignore":
            self.queued_image.decision = "ignore"
            self.queued_image.save()

            sentence = "Ignored a photo upload from {uploading_user}"
            " (This usually means it was a duplicate)"

            update_message = _(sentence).format(uploading_user=uploaded_by)
            LoggedAction.objects.create(
                user=self.request.user,
                action_type="photo-ignore",
                ip_address=get_client_ip(self.request),
                popit_person_new_version="",
                person=person,
                source=update_message,
            )
            flash(
                messages.INFO,
                _("You indicated a photo upload for {0} should be ignored").
                format(candidate_link),
            )
        else:
            raise Exception("BUG: unexpected decision {}".format(decision))
        return HttpResponseRedirect(reverse("photo-review-list"))
Beispiel #36
0
    def handle(self, **options):
        from slumber.exceptions import HttpClientError, HttpServerError
        from candidates.election_specific import PARTY_DATA, shorten_post_label
        from candidates.models import PopItPerson
        from candidates.popit import create_popit_api_object

        api = create_popit_api_object()

        csv_filename = join(dirname(__file__), '..', '..', 'data',
                            'candidates.csv')
        with open(csv_filename) as f:
            all_data = csv.DictReader(f)

            for candidate in all_data:
                vi_person_id = candidate['Distrito'] + candidate[
                    'Numero Lista'] + candidate['Posicion'] + candidate[
                        'Cargo'] + candidate['Nombre Lista']

                election_data, post_data = get_post_data(
                    api, candidate['Cargo'], candidate['Distrito'])
                if (election_data == False):
                    print("Skipping: " + candidate['Cargo'] + ", " +
                          candidate['Distrito'] + ", " + candidate['Nombre'])
                    continue

                name = candidate['Nombre']
                birth_date = None
                gender = None
                image_url = None

                person = get_existing_popit_person(vi_person_id)
                if person:
                    print("Found an existing person:",
                          person.get_absolute_url())
                else:
                    print("No existing person, creating a new one:", name)
                    person = PopItPerson()

                # Now update fields from the imported data:
                person.name = name.split(",")[1] + " " + name.split(",")[0]
                person.gender = gender
                if birth_date:
                    person.birth_date = str(birth_date)
                else:
                    person.birth_date = None
                standing_in_election = {
                    'post_id': post_data['id'],
                    'name': shorten_post_label(post_data['label']),
                    'party_list_position': candidate['Posicion'],
                }
                if 'area' in post_data:
                    standing_in_election['mapit_url'] = post_data['area'][
                        'identifier']

                person.standing_in = {election_data.slug: standing_in_election}

                party_id = get_party_id(candidate["Partido"])

                person.party_memberships = {
                    election_data.slug: {
                        'id': party_id,
                        'name': PARTY_DATA.party_id_to_name[party_id],
                    }
                }
                person.set_identifier('import-id', vi_person_id)
                change_metadata = get_change_metadata(
                    None,
                    'Imported candidate from CSV',
                )

                person.record_version(change_metadata)
                try:
                    person.save_to_popit(api)
                except HttpClientError as hce:
                    print("Got an HttpClientError:", hce.content)
                    raise
                except HttpServerError as hse:
                    print("The server error content was:", hse.content)
                    raise
Beispiel #37
0
    def form_valid(self, form):
        decision = form.cleaned_data['decision']
        person = PopItPerson.create_from_popit(
            self.api, self.queued_image.popit_person_id)
        candidate_path = person.get_absolute_url()
        candidate_name = person.name
        candidate_link = u'<a href="{url}">{name}</a>'.format(
            url=candidate_path,
            name=candidate_name,
        )
        photo_review_url = self.request.build_absolute_uri(
            self.queued_image.get_absolute_url())

        def flash(level, message):
            messages.add_message(self.request,
                                 level,
                                 message,
                                 extra_tags='safe photo-review')

        if decision == 'approved':
            # Crop the image...
            crop_fields = ('x_min', 'y_min', 'x_max', 'y_max')
            self.crop_and_upload_image_to_popit(
                self.queued_image.image.path,
                [form.cleaned_data[e] for e in crop_fields],
                form.cleaned_data['moderator_why_allowed'],
                form.cleaned_data['make_primary'],
            )
            self.queued_image.decision = 'approved'
            for i, field in enumerate(crop_fields):
                setattr(self.queued_image, 'crop_' + field,
                        form.cleaned_data[field])
            self.queued_image.save()
            update_message = _(
                u'Approved a photo upload from '
                u'{uploading_user} who provided the message: '
                u'"{message}"').format(
                    uploading_user=self.queued_image.user.username,
                    message=self.queued_image.justification_for_use,
                )
            change_metadata = get_change_metadata(self.request, update_message)
            # We have to refetch the person from PopIt, otherwise
            # saving the new version will write back the images array
            # from before we uploaded the image:
            person = PopItPerson.create_from_popit(self.api, person.id)
            person.record_version(change_metadata)
            person.save_to_popit(self.api, self.request.user)
            LoggedAction.objects.create(
                user=self.request.user,
                action_type='photo-approve',
                ip_address=get_client_ip(self.request),
                popit_person_new_version=change_metadata['version_id'],
                popit_person_id=self.queued_image.popit_person_id,
                source=update_message,
            )
            self.send_mail(
                _('YourNextMP image upload approved'),
                render_to_string('moderation_queue/photo_approved_email.txt', {
                    'candidate_page_url':
                    person.get_absolute_url(self.request)
                }),
            )
            flash(messages.SUCCESS,
                  _(u'You approved a photo upload for %s') % candidate_link)
        elif decision == 'rejected':
            self.queued_image.decision = 'rejected'
            self.queued_image.save()
            update_message = _(
                u'Rejected a photo upload from '
                u'{uploading_user}').format(
                    uploading_user=self.queued_image.user.username, )
            LoggedAction.objects.create(
                user=self.request.user,
                action_type='photo-reject',
                ip_address=get_client_ip(self.request),
                popit_person_new_version='',
                popit_person_id=self.queued_image.popit_person_id,
                source=update_message,
            )
            retry_upload_link = self.request.build_absolute_uri(
                reverse('photo-upload',
                        kwargs={
                            'popit_person_id':
                            self.queued_image.popit_person_id
                        }))
            self.send_mail(
                _('YourNextMP image moderation results'),
                render_to_string(
                    'moderation_queue/photo_rejected_email.txt',
                    {
                        'reason': form.cleaned_data['rejection_reason'],
                        'candidate_name': candidate_name,
                        'retry_upload_link': retry_upload_link,
                        'photo_review_url': photo_review_url
                    },
                ),
                email_support_too=True,
            )
            flash(messages.INFO,
                  _(u'You rejected a photo upload for %s') % candidate_link)
        elif decision == 'undecided':
            # If it's left as undecided, just redirect back to the
            # photo review queue...
            flash(
                messages.INFO,
                _(u'You left a photo upload for {0} in the queue').format(
                    candidate_link))
        elif decision == 'ignore':
            self.queued_image.decision = 'ignore'
            self.queued_image.save()
            update_message = _(
                u'Ignored a photo upload from '
                u'{uploading_user} (This usually means it was a duplicate)'
            ).format(uploading_user=self.queued_image.user.username)
            LoggedAction.objects.create(
                user=self.request.user,
                action_type='photo-ignore',
                ip_address=get_client_ip(self.request),
                popit_person_new_version='',
                popit_person_id=self.queued_image.popit_person_id,
                source=update_message,
            )
            flash(
                messages.INFO,
                _(u'You indicated a photo upload for {0} should be ignored').
                format(candidate_link))
        else:
            raise Exception("BUG: unexpected decision {0}".format(decision))
        return HttpResponseRedirect(reverse('photo-review-list'))
 def form_valid(self, form):
     decision = form.cleaned_data['decision']
     person = PopItPerson.create_from_popit(
         self.api,
         self.queued_image.popit_person_id
     )
     candidate_path = person.get_absolute_url()
     candidate_name = person.name
     candidate_link = u'<a href="{url}">{name}</a>'.format(
         url=candidate_path,
         name=candidate_name,
     )
     photo_review_url = self.request.build_absolute_uri(
         self.queued_image.get_absolute_url()
     )
     def flash(level, message):
         messages.add_message(
             self.request,
             level,
             message,
             extra_tags='safe photo-review'
         )
     if decision == 'approved':
         # Crop the image...
         crop_fields = ('x_min', 'y_min', 'x_max', 'y_max')
         self.crop_and_upload_image_to_popit(
             self.queued_image.image.path,
             [form.cleaned_data[e] for e in crop_fields],
             form.cleaned_data['moderator_why_allowed'],
             form.cleaned_data['make_primary'],
         )
         self.queued_image.decision = 'approved'
         for i, field in enumerate(crop_fields):
             setattr(
                 self.queued_image,
                 'crop_' + field,
                 form.cleaned_data[field]
             )
         self.queued_image.save()
         update_message = _(u'Approved a photo upload from '
             u'{uploading_user} who provided the message: '
             u'"{message}"').format(
             uploading_user=self.queued_image.user.username,
             message=self.queued_image.justification_for_use,
         )
         change_metadata = get_change_metadata(
             self.request,
             update_message
         )
         # We have to refetch the person from PopIt, otherwise
         # saving the new version will write back the images array
         # from before we uploaded the image:
         person = PopItPerson.create_from_popit(self.api, person.id)
         person.record_version(change_metadata)
         person.save_to_popit(self.api, self.request.user)
         LoggedAction.objects.create(
             user=self.request.user,
             action_type='photo-approve',
             ip_address=get_client_ip(self.request),
             popit_person_new_version=change_metadata['version_id'],
             popit_person_id=self.queued_image.popit_person_id,
             source=update_message,
         )
         self.send_mail(
             _('YourNextMP image upload approved'),
             render_to_string(
                 'moderation_queue/photo_approved_email.txt',
                 {'candidate_page_url':
                  person.get_absolute_url(self.request)}
             ),
         )
         flash(
             messages.SUCCESS,
             _(u'You approved a photo upload for %s') % candidate_link
         )
     elif decision == 'rejected':
         self.queued_image.decision = 'rejected'
         self.queued_image.save()
         update_message = _(u'Rejected a photo upload from '
             u'{uploading_user}').format(
             uploading_user=self.queued_image.user.username,
         )
         LoggedAction.objects.create(
             user=self.request.user,
             action_type='photo-reject',
             ip_address=get_client_ip(self.request),
             popit_person_new_version='',
             popit_person_id=self.queued_image.popit_person_id,
             source=update_message,
         )
         retry_upload_link = self.request.build_absolute_uri(
             reverse(
                 'photo-upload',
                 kwargs={'popit_person_id': self.queued_image.popit_person_id}
             )
         )
         self.send_mail(
             _('YourNextMP image moderation results'),
             render_to_string(
                 'moderation_queue/photo_rejected_email.txt',
                 {'reason': form.cleaned_data['rejection_reason'],
                  'candidate_name': candidate_name,
                  'retry_upload_link': retry_upload_link,
                  'photo_review_url': photo_review_url},
             ),
             email_support_too=True,
         )
         flash(
             messages.INFO,
             _(u'You rejected a photo upload for %s') % candidate_link
         )
     elif decision == 'undecided':
         # If it's left as undecided, just redirect back to the
         # photo review queue...
         flash(
             messages.INFO,
             _(u'You left a photo upload for {0} in the queue').format(
                 candidate_link
             )
         )
     elif decision == 'ignore':
         self.queued_image.decision = 'ignore'
         self.queued_image.save()
         update_message = _(u'Ignored a photo upload from '
             u'{uploading_user} (This usually means it was a duplicate)').format(
             uploading_user=self.queued_image.user.username)
         LoggedAction.objects.create(
             user=self.request.user,
             action_type='photo-ignore',
             ip_address=get_client_ip(self.request),
             popit_person_new_version='',
             popit_person_id=self.queued_image.popit_person_id,
             source=update_message,
         )
         flash(
             messages.INFO,
             _(u'You indicated a photo upload for {0} should be ignored').format(
                 candidate_link
             )
         )
     else:
         raise Exception("BUG: unexpected decision {0}".format(decision))
     return HttpResponseRedirect(reverse('photo-review-list'))
Beispiel #39
0
    def handle(self, username=None, **options):
        from slumber.exceptions import HttpClientError
        from candidates.popit import create_popit_api_object
        from candidates.election_specific import PARTY_DATA, shorten_post_label
        from candidates.models import PopItPerson

        if username is None:
            message = "You must supply the name of a user to be associated with the image uploads."
            raise CommandError(message)
        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            message = "No user with the username '{0}' could be found"
            raise CommandError(message.format(username))

        api = create_popit_api_object()

        json_filename = join(dirname(__file__), '..', '..', 'data',
                             'candidates.json')
        with open(json_filename) as f:
            all_data = json.load(f)

        # This map is needed to get getting YNR election data from
        # the election ID used in the JSON file.
        json_election_id_to_name = {
            e['pk']: e['fields']['name']
            for e in all_data if e['model'] == 'elections.election'
        }

        person_dict = {
            e['pk']: e['fields']
            for e in all_data if e['model'] == 'popolo.person'
        }

        candidate_list = [
            dict(person_id=e['pk'], election_id=e['fields']['election'])
            for e in all_data if e['model'] == 'elections.candidate'
        ]

        for candidate in candidate_list:
            vi_person_id = candidate['person_id']
            person_data = person_dict[vi_person_id]
            election_data, post_data = get_post_data(api,
                                                     candidate['election_id'],
                                                     json_election_id_to_name)
            birth_date = None
            if person_data['birth_date']:
                birth_date = str(
                    dateutil.parser.parse(person_data['birth_date'],
                                          dayfirst=True).date())
            name = person_data['name']
            gender = person_data['gender']
            image_url = person_data['image']

            person = get_existing_popit_person(vi_person_id)
            if person:
                print("Found an existing person:", person.get_absolute_url())
            else:
                print("No existing person, creating a new one:", name)
                person = PopItPerson()

            # Now update fields from the imported data:
            person.name = name
            person.gender = gender
            if birth_date:
                person.birth_date = str(birth_date)
            else:
                person.birth_date = None
            standing_in_election = {
                'post_id': post_data['id'],
                'name': shorten_post_label(post_data['label']),
            }
            if 'area' in post_data:
                standing_in_election['mapit_url'] = post_data['area'][
                    'identifier']
            person.standing_in = {election_data.slug: standing_in_election}
            person.party_memberships = {
                election_data.slug: {
                    'id': UNKNOWN_PARTY_ID,
                    'name': PARTY_DATA.party_id_to_name[UNKNOWN_PARTY_ID],
                }
            }
            person.set_identifier('import-id', vi_person_id)
            change_metadata = get_change_metadata(
                None,
                'Imported candidate from JSON',
            )

            person.record_version(change_metadata)
            try:
                person.save_to_popit(api)
                if image_url:
                    enqueue_image(person, user, image_url)
            except HttpClientError as hce:
                print("Got an HttpClientError:", hce.content)
                raise
Beispiel #40
0
    def handle(self, username=None, **options):
        from slumber.exceptions import HttpClientError
        from candidates.election_specific import PARTY_DATA, shorten_post_label
        from candidates.models import PopItPerson
        from candidates.popit import create_popit_api_object

        election_data = {
            'prv-2015':
            'listedescandidatsauxelectionslegislativeslisteprovincialeanptic.csv',
            'nat-2015': 'listedescandidatsauxelectionslegislativesanptic.csv'
        }

        field_map = {
            'prv-2015': {
                'region': 1,
                'party': 4,
                'list_order': 5,
                'first_name': 7,
                'last_name': 6,
                'gender': 8,
                'birth_date': 9,
                'party_short': 3
            },
            'nat-2015': {
                'region': 0,
                'party': 2,
                'list_order': 3,
                'first_name': 5,
                'last_name': 4,
                'gender': 6,
                'birth_date': 7,
                'party_short': 2
            }
        }

        api = create_popit_api_object()

        party_id_missing = {}
        party_name_to_id = {}
        for party_id, party_name in PARTY_DATA.party_id_to_name.items():
            party_name_to_id[party_name] = party_id

        for election_id, filename in election_data.items():
            csv_filename = join(dirname(__file__), '..', '..', 'data',
                                filename)

            fields = field_map[election_id]

            with codecs.open(csv_filename, 'r', encoding='windows-1252') as f:

                initial = True
                for candidate in unicode_csv_reader(f):
                    # skip header line
                    if initial:
                        initial = False
                        continue

                    region = candidate[fields['region']]
                    party = candidate[fields['party']]
                    party_list_order = candidate[fields['list_order']]
                    first_name = string.capwords(
                        candidate[fields['first_name']])
                    last_name = string.capwords(candidate[fields['last_name']])
                    gender = candidate[fields['gender']]
                    birth_date = None

                    if candidate[fields['birth_date']] is not None:
                        birth_date = str(
                            dateutil.parser.parse(
                                candidate[fields['birth_date']],
                                dayfirst=True).date())

                    name = first_name + ' ' + last_name

                    id = '-'.join([
                        re.sub('[^\w]*', '',
                               re.sub(r' ', '-', strip_accents(name.lower()))),
                        re.sub('[^\w]*', '',
                               candidate[fields['party_short']].lower()),
                        birth_date
                    ])

                    # national candidate
                    if region == 'PAYS':
                        region = 'Burkina Faso'
                    election_data, post_data = get_post_data(
                        api, election_id, region)

                    # debug
                    # tmp = '%s %s %s (%s) - %s (%s)' % ( id, first_name, last_name, party, region, post_data['label'] )
                    # print(tmp)

                    person = get_existing_popit_person(id)
                    if person:
                        # print("Found an existing person:", person.get_absolute_url())
                        pass
                    else:
                        print("No existing person, creating a new one:", name)
                        person = PopItPerson()

                    person.set_identifier('import-id', id)
                    person.family_name = last_name
                    person.given_name = first_name
                    person.name = name
                    person.gender = gender
                    if birth_date:
                        person.birth_date = str(birth_date)
                    else:
                        person.birth_date = None

                    standing_in_election = {
                        'post_id': post_data['id'],
                        'name': shorten_post_label(post_data['label']),
                        'party_list_position': party_list_order,
                    }

                    if 'area' in post_data:
                        standing_in_election['mapit_url'] = post_data['area'][
                            'identifier']

                    person.standing_in = {
                        election_data.slug: standing_in_election
                    }

                    change_metadata = get_change_metadata(
                        None,
                        'Imported candidate from CSV',
                    )

                    party_comp = re.sub(' +', ' ', party)
                    party_id = UNKNOWN_PARTY_ID
                    if party_comp in party_name_to_id.keys():
                        party_id = party_name_to_id[party_comp]
                        party = party_comp
                    else:
                        party_id = party_name_to_id['Unknown Party']
                        party = 'Unknown Party'

                    if party_id == UNKNOWN_PARTY_ID and party_comp not in party_id_missing.keys(
                    ):
                        party_id_missing[party_comp] = 1

                    person.party_memberships = {
                        election_data.slug: {
                            'id': party_id,
                            'name': party,
                            'imported_name': party_comp
                        }
                    }

                    person.record_version(change_metadata)
                    try:
                        person.save_to_popit(api)
                    except HttpClientError as hce:
                        print("Got an HttpClientError:", hce.content)
                        raise

        if len(party_id_missing) > 0:
            print("Unmatched party names:")
            for name in party_id_missing.keys():
                print(name)
    def handle(self, **options):
        from slumber.exceptions import HttpClientError, HttpServerError
        from candidates.election_specific import PARTY_DATA, shorten_post_label
        from candidates.models import PopItPerson
        from candidates.popit import create_popit_api_object

        api = create_popit_api_object()

        csv_filename = join(
            dirname(__file__), '..', '..','data', 'candidates.csv'
        )
        with open(csv_filename) as f:
            all_data = csv.DictReader(f)

            for candidate in all_data:
                vi_person_id = candidate['Distrito']+candidate['Numero Lista']+candidate['Posicion']+candidate['Cargo']+candidate['Nombre Lista']

                election_data, post_data = get_post_data(
                    api, candidate['Cargo'], candidate['Distrito']
                )
                if (election_data == False):
                    print("Skipping: "+ candidate['Cargo'] +", " + candidate['Distrito']+", " + candidate['Nombre'])
                    continue;

                name = candidate['Nombre']
                birth_date = None
                gender = None
                image_url = None

                person = get_existing_popit_person(vi_person_id)
                if person:
                    print("Found an existing person:", person.get_absolute_url())
                else:
                    print("No existing person, creating a new one:", name)
                    person = PopItPerson()

                # Now update fields from the imported data:
                person.name = name.split(",")[1] + " "  + name.split(",")[0]
                person.gender = gender
                if birth_date:
                    person.birth_date = str(birth_date)
                else:
                    person.birth_date = None
                standing_in_election = {
                    'post_id': post_data['id'],
                    'name': shorten_post_label(post_data['label']),
                    'party_list_position': candidate['Posicion'],
                }
                if 'area' in post_data:
                    standing_in_election['mapit_url'] = post_data['area']['identifier']

                person.standing_in = {
                    election_data.slug: standing_in_election
                }

                party_id = get_party_id(candidate["Partido"]);

                person.party_memberships = {
                    election_data.slug: {
                        'id': party_id,
                        'name': PARTY_DATA.party_id_to_name[party_id],
                    }
                }
                person.set_identifier('import-id', vi_person_id)
                change_metadata = get_change_metadata(
                    None,
                    'Imported candidate from CSV',
                )

                person.record_version(change_metadata)
                try:
                    person.save_to_popit(api)
                except HttpClientError as hce:
                    print("Got an HttpClientError:", hce.content)
                    raise
                except HttpServerError as hse:
                    print("The server error content was:", hse.content)
                    raise
Beispiel #42
0
 def form_valid(self, form):
     decision = form.cleaned_data['decision']
     person = Person.objects.get(
         id=self.queued_image.person.id
     )
     person_extra = person.extra
     candidate_path = person_extra.get_absolute_url()
     candidate_name = person.name
     candidate_link = '<a href="{url}">{name}</a>'.format(
         url=candidate_path,
         name=candidate_name,
     )
     photo_review_url = self.request.build_absolute_uri(
         self.queued_image.get_absolute_url()
     )
     site_name = Site.objects.get_current().name
     def flash(level, message):
         messages.add_message(
             self.request,
             level,
             message,
             extra_tags='safe photo-review'
         )
     if decision == 'approved':
         # Crop the image...
         crop_fields = ('x_min', 'y_min', 'x_max', 'y_max')
         self.crop_and_upload_image_to_popit(
             self.queued_image.image.path,
             [form.cleaned_data[e] for e in crop_fields],
             form.cleaned_data['moderator_why_allowed'],
             form.cleaned_data['make_primary'],
         )
         self.queued_image.decision = 'approved'
         for i, field in enumerate(crop_fields):
             setattr(
                 self.queued_image,
                 'crop_' + field,
                 form.cleaned_data[field]
             )
         self.queued_image.save()
         update_message = _('Approved a photo upload from '
             '{uploading_user} who provided the message: '
             '"{message}"').format(
             uploading_user=self.queued_image.user.username,
             message=self.queued_image.justification_for_use,
         )
         change_metadata = get_change_metadata(
             self.request,
             update_message
         )
         person_extra.record_version(change_metadata)
         person_extra.save()
         person.save()
         LoggedAction.objects.create(
             user=self.request.user,
             action_type='photo-approve',
             ip_address=get_client_ip(self.request),
             popit_person_new_version=change_metadata['version_id'],
             person=person,
             source=update_message,
         )
         candidate_full_url = person_extra.get_absolute_url(self.request)
         self.send_mail(
             _('{site_name} image upload approved').format(
                 site_name=site_name
             ),
             render_to_string(
                 'moderation_queue/photo_approved_email.txt',
                 {
                     'site_name': site_name,
                     'candidate_page_url': candidate_full_url,
                     'intro': _(
                         "Thank-you for submitting a photo to "
                         "{site_name}; that's been uploaded now for "
                         "the candidate page here:"
                     ).format(site_name=site_name),
                     'signoff': _(
                         "Many thanks from the {site_name} volunteers"
                     ).format(site_name=site_name),
                 }
             ),
         )
         flash(
             messages.SUCCESS,
             _('You approved a photo upload for %s') % candidate_link
         )
     elif decision == 'rejected':
         self.queued_image.decision = 'rejected'
         self.queued_image.save()
         update_message = _('Rejected a photo upload from '
             '{uploading_user}').format(
             uploading_user=self.queued_image.user.username,
         )
         LoggedAction.objects.create(
             user=self.request.user,
             action_type='photo-reject',
             ip_address=get_client_ip(self.request),
             popit_person_new_version='',
             person=person,
             source=update_message,
         )
         retry_upload_link = self.request.build_absolute_uri(
             reverse(
                 'photo-upload',
                 kwargs={'person_id': self.queued_image.person.id}
             )
         )
         self.send_mail(
             _('{site_name} image moderation results').format(
                 site_name=Site.objects.get_current().name
             ),
             render_to_string(
                 'moderation_queue/photo_rejected_email.txt',
                 {
                     'reason': form.cleaned_data['rejection_reason'],
                     'retry_upload_link': retry_upload_link,
                     'photo_review_url': photo_review_url,
                     'intro': _(
                         "Thank-you for uploading a photo of "
                         "{candidate_name} to {site_name}, but "
                         "unfortunately we can't use that image because:"
                     ).format(
                         candidate_name=candidate_name,
                         site_name=site_name
                     ),
                     'possible_actions': _(
                         'You can just reply to this email if you want to '
                         'discuss that further, or you can try uploading a '
                         'photo with a different reason or justification '
                         'for its use using this link:'
                     ),
                     'signoff': _(
                         "Many thanks from the {site_name} volunteers"
                     ).format(site_name=site_name),
                 },
             ),
             email_support_too=True,
         )
         flash(
             messages.INFO,
             _('You rejected a photo upload for %s') % candidate_link
         )
     elif decision == 'undecided':
         # If it's left as undecided, just redirect back to the
         # photo review queue...
         flash(
             messages.INFO,
             _('You left a photo upload for {0} in the queue').format(
                 candidate_link
             )
         )
     elif decision == 'ignore':
         self.queued_image.decision = 'ignore'
         self.queued_image.save()
         update_message = _('Ignored a photo upload from '
             '{uploading_user} (This usually means it was a duplicate)').format(
             uploading_user=self.queued_image.user.username)
         LoggedAction.objects.create(
             user=self.request.user,
             action_type='photo-ignore',
             ip_address=get_client_ip(self.request),
             popit_person_new_version='',
             person=person,
             source=update_message,
         )
         flash(
             messages.INFO,
             _('You indicated a photo upload for {0} should be ignored').format(
                 candidate_link
             )
         )
     else:
         raise Exception("BUG: unexpected decision {0}".format(decision))
     return HttpResponseRedirect(reverse('photo-review-list'))
    def handle(self, username=None, **options):

        election_data = {
            'prv-2015': 'listedescandidatsauxelectionslegislativeslisteprovincialeanptic.csv',
            'nat-2015': 'listedescandidatsauxelectionslegislativesanptic.csv'
            }

        field_map = {
            'prv-2015': {
                'region': 1,
                'party': 4,
                'list_order': 5,
                'first_name': 7,
                'last_name': 6,
                'gender': 8,
                'birth_date': 9,
                'party_short': 3
            },
            'nat-2015': {
                'region': 0,
                'party': 2,
                'list_order': 3,
                'first_name': 5,
                'last_name': 4,
                'gender': 6,
                'birth_date': 7,
                'party_short': 2
            }
        }

        api = create_popit_api_object()

        party_id_missing = {}
        party_name_to_id = {}
        for party_id, party_name in PARTY_DATA.party_id_to_name.items():
            party_name_to_id[party_name] = party_id

        for election_id, filename in election_data.items():
            csv_filename = join(
                dirname(__file__), '..', '..', 'data', filename
            )

            fields = field_map[election_id]

            with codecs.open(csv_filename, 'r', encoding='windows-1252') as f:

                initial = True
                for candidate in unicode_csv_reader(f):
                    # skip header line
                    if initial:
                        initial = False
                        continue

                    region = candidate[fields['region']]
                    party = candidate[fields['party']]
                    party_list_order = candidate[fields['list_order']]
                    first_name = string.capwords(candidate[fields['first_name']])
                    last_name = string.capwords(candidate[fields['last_name']])
                    gender = candidate[fields['gender']]
                    birth_date = None

                    if candidate[fields['birth_date']] is not None:
                        birth_date = str(dateutil.parser.parse(
                            candidate[fields['birth_date']], dayfirst=True
                        ).date())

                    name = first_name + ' ' + last_name

                    id = '-'.join([
                        re.sub('[^\w]*', '', re.sub(r' ', '-', strip_accents(name.lower()))),
                        re.sub('[^\w]*', '', candidate[fields['party_short']].lower()),
                        birth_date
                    ])

                    # national candidate
                    if region == 'PAYS':
                        region = 'Burkina Faso'
                    election_data, post_data = get_post_data(
                        api, election_id, region
                    )

                    # debug
                    # tmp = '%s %s %s (%s) - %s (%s)' % ( id, first_name, last_name, party, region, post_data['label'] )
                    # print tmp

                    person = get_existing_popit_person(id)
                    if person:
                        # print "Found an existing person:", person.get_absolute_url()
                        pass
                    else:
                        print "No existing person, creating a new one:", name
                        person = PopItPerson()

                    person.set_identifier('import-id', id)
                    person.family_name = last_name
                    person.given_name = first_name
                    person.name = name
                    person.gender = gender
                    if birth_date:
                        person.birth_date = str(birth_date)
                    else:
                        person.birth_date = None

                    standing_in_election = {
                        'post_id': post_data['id'],
                        'name': AREA_POST_DATA.shorten_post_label(
                            election_data.slug,
                            post_data['label'],
                        ),
                        'party_list_position': party_list_order,
                    }

                    if 'area' in post_data:
                        standing_in_election['mapit_url'] = post_data['area']['identifier']

                    person.standing_in = {
                        election_data.slug: standing_in_election
                    }

                    change_metadata = get_change_metadata(
                        None,
                        'Imported candidate from CSV',
                    )

                    party_comp = re.sub(' +', ' ', party)
                    party_id = UNKNOWN_PARTY_ID
                    if party_comp in party_name_to_id.keys():
                        party_id = party_name_to_id[party_comp]
                        party = party_comp
                    else:
                        party_id = party_name_to_id['Unknown Party']
                        party = 'Unknown Party'

                    if party_id == UNKNOWN_PARTY_ID and party_comp not in party_id_missing.keys():
                        party_id_missing[party_comp] = 1

                    person.party_memberships = {
                        election_data.slug: {
                            'id': party_id,
                            'name': party,
                            'imported_name': party_comp
                        }
                    }

                    person.record_version(change_metadata)
                    try:
                        person.save_to_popit(api)
                    except HttpClientError as hce:
                        print "Got an HttpClientError:", hce.content
                        raise

        if len(party_id_missing) > 0:
            print "Unmatched party names:"
            for name in party_id_missing.keys():
                print name