Source code for akvo.scripts.cordaid.post_import

# -*- coding: utf-8 -*-

# Akvo RSR is covered by the GNU Affero General Public License.
# See more details in the license.txt file located at the root folder of the Akvo RSR module.
# For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.


import django
import os
import sys

from decimal import Decimal
from lxml import etree
from os.path import join, pardir, splitext

project_root = join(os.path.dirname(os.path.realpath(__file__)), *[pardir] * 3)
sys.path.append(project_root)

os.environ['DJANGO_SETTINGS_MODULE'] = 'akvo.settings'

from django.core.files import File
from django.core.files.temp import NamedTemporaryFile

from akvo.rsr.models import Project, Partnership, Organisation, BudgetItem, BudgetItemLabel, PublishingStatus
from akvo.utils import model_and_instance_based_filename, who_am_i

from akvo.scripts.cordaid import (
    CORDAID_IATI_ACTIVITIES_XML, CORDAID_PROJECT_IMAGES_DIR, CORDAID_ORG_ID, OTHERS_ORG_ID,
    print_log, log, ACTION_FUNDING_SET, ACTION_FUNDING_FOUND, ERROR_IMAGE_UPLOAD, ACTION_SET_IMAGE,
    CORDAID_ACTIVITIES_CSV_FILE, init_log, ACTION_BUDGET_SET, outsys,
    ACTION_PUBLISHING_SET)


[docs]def import_images(image_dir, photos): outsys("\nRunning {}() ".format(who_am_i())) for image_name in os.listdir(image_dir): photo_id, ext = splitext(image_name) if ext.lower() in ['.png', '.jpg', '.jpeg', '.gif']: try: internal_id = photos.get( photo_id, {'internal_project_id': None} )['internal_project_id'] project = Project.objects.get( partnerships__internal_id=internal_id ) filename = model_and_instance_based_filename( 'Project', project.pk, 'current_image', image_name ) with open(os.path.join(image_dir, image_name), 'rb') as f: image_data = f.read() image_temp = NamedTemporaryFile(delete=True) image_temp.write(image_data) image_temp.flush() project.current_image.save(filename, File(image_temp), save=True) f.close() project.current_image_caption = photos.get( photo_id, {'image_caption': ''} )['image_caption'] project.current_image_credit = photos.get( photo_id, {'image_credit': ''} )['image_credit'] project.save() log( "Uploaded image to project {pk}", dict(internal_id=internal_id, pk=project.pk, event=ACTION_SET_IMAGE)) outsys(".") except Exception as e: log( "Upload failed. internal_id: {internal_id} Exception class: {extra}", dict(internal_id=internal_id, event=ERROR_IMAGE_UPLOAD, extra=e.__class__), ) outsys("*")
[docs]def fix_funding(budgets): """ Add Cordaid as a funding partner to all its projects and "fill the project up" """ outsys("\nRunning {}() ".format(who_am_i())) def assign_funding_partner(project, organisation, amount): funding_partnership, created = Partnership.objects.get_or_create( organisation=organisation, project=project, iati_organisation_role=Partnership.IATI_FUNDING_PARTNER, defaults={'funding_amount': amount} ) if created: log( "Added {org_name} as funding partner to project {{pk}}, funding amount: {{extra}}".format(org_name=organisation.name), dict(internal_id=internal_id, pk=project.pk, event=ACTION_FUNDING_SET, extra=amount) ) else: funding_partnership.funding_amount = amount funding_partnership.save() log( "Found {org_name} as funding partner to project {{pk}}, setting funding amount: {{extra}}".format(org_name=organisation.name), dict(internal_id=internal_id, pk=project.pk, event=ACTION_FUNDING_FOUND, extra=amount) ) cordaid = Organisation.objects.get(pk=CORDAID_ORG_ID) others = Organisation.objects.get(pk=OTHERS_ORG_ID) for budget in budgets: internal_id = budget['internal_project_id'] try: project = None project = Project.objects.get( partnerships__internal_id=internal_id, partnerships__organisation=cordaid ) project.set_reporting_org(cordaid) project.save() cordaid_funding = budget.get('cordaid_funding', 0) others_funding = budget.get('others_funding', 0) if cordaid_funding: assign_funding_partner(project, cordaid, cordaid_funding) if others_funding: assign_funding_partner(project, others, others_funding) total_budget = cordaid_funding + others_funding old_budgets = BudgetItem.objects.filter(project=project) old_budgets.delete() BudgetItem.objects.create( project=project, label=BudgetItemLabel.objects.get(pk=BudgetItemLabel.TOTAL_BUDGET_LABEL_ID), amount=total_budget ) log( "Total budget for project {pk}: {extra}", dict(internal_id=internal_id, pk=project.pk, event=ACTION_BUDGET_SET, extra=total_budget) ) outsys(".") except Exception as e: log("Error setting up funding partners for project {pk}\nException class: {extra}", dict(internal_id=internal_id, pk=getattr(project, 'pk', None), event=e.__class__, extra=str(e)), ) outsys("*") outsys('\n')
[docs]def set_publishing_status(publishing_statuses): outsys("\nRunning {}() ".format(who_am_i())) cordaid = Organisation.objects.get(pk=CORDAID_ORG_ID) for internal_id, publish in publishing_statuses.items(): try: status = PublishingStatus.objects.get( project__partnerships__internal_id=internal_id, project__partnerships__organisation=cordaid, ) status.status = PublishingStatus.STATUS_PUBLISHED if publish else PublishingStatus.STATUS_UNPUBLISHED status.save() log( "Set publishing status for project ID: {pk}: {extra}", dict(internal_id=internal_id, pk=status.project.pk, event=ACTION_PUBLISHING_SET, extra=status.status) ) outsys(".") except Exception as e: log("Error setting publishing status for project {internal_id}\nException class: {extra}", dict(internal_id=internal_id, event=e.__class__, extra=str(e)), ) outsys("*") outsys('\n')
[docs]def get_post_process_data(): """ Create a dictionary with photo IDs as keys: { <photo-id>: { 'internal_project_id': <internal_project_id>, 'image_caption': <image-caption>, 'image_credit': <image-credit>, 'cordaid_funding': <cordaid-funding>, 'others_funding': <others-funding>, } }, """ outsys("\nRunning {}() ".format(who_am_i())) with open(CORDAID_IATI_ACTIVITIES_XML, 'r') as f: root = etree.fromstring(f.read()) AKVO_NS = '{{{akvo_ns}}}'.format(akvo_ns=root.nsmap['akvo']) photos = {} budgets = [] publishing_statuses = {} for activity in root: outsys(".") photos[ activity.get(AKVO_NS + 'photo-id') ] = dict( internal_project_id=activity.get(AKVO_NS + 'internal-project-id'), image_caption=activity.get(AKVO_NS + 'image-caption', '').strip(), image_credit=activity.get(AKVO_NS + 'photo-credit', '').strip(), ) cordaid_budget = activity.findall('budget[@' + AKVO_NS + 'budget-from="Cordaid"]') others_budget = activity.findall('budget[@' + AKVO_NS + 'budget-from="Others"]') budgets.append( dict( internal_project_id=activity.get(AKVO_NS + 'internal-project-id'), cordaid_funding=Decimal(cordaid_budget[0].find('value').text if cordaid_budget else 0), others_funding=Decimal(others_budget[0].find('value').text if others_budget else 0), ) ) publishing_statuses[ activity.get(AKVO_NS + 'internal-project-id') ] = activity.get(AKVO_NS + 'publish') == 'true' return photos, budgets, publishing_statuses
if __name__ == '__main__': django.setup() photos, budgets, publishing_statuses = get_post_process_data() set_publishing_status(publishing_statuses) import_images(CORDAID_PROJECT_IMAGES_DIR, photos) fix_funding(budgets) log_file = init_log(CORDAID_ACTIVITIES_CSV_FILE) names = ('internal_id', 'pk', 'label', 'event', 'extra') print_log(log_file, names)