def migrate_project_settings(apps, schema_editor): ProjectPlatformSettings = apps.get_model('projects', 'ProjectPlatformSettings') ProjectSearchFilter = apps.get_model('projects', 'ProjectSearchFilter') Client = apps.get_model('clients', 'Client') project_settings, _ = ProjectPlatformSettings.objects.get_or_create() tenant = Client.objects.get(schema_name=connection.tenant.schema_name) properties.set_tenant(tenant) project_settings.create_types = properties.PROJECT_CREATE_TYPES project_settings.create_flow = properties.PROJECT_CREATE_FLOW project_settings.contact_method = properties.PROJECT_CONTACT_METHOD project_settings.contact_types = properties.PROJECT_CONTACT_TYPES # Remove all filters ProjectSearchFilter.objects.all().delete() for filt in properties.SEARCH_OPTIONS['filters']['projects']: project_filter = ProjectSearchFilter.objects.create( project_settings=project_settings, name=filt['name']) for k, v in filt.items(): if filt['name'] == 'type' and k == 'values': v = ",".join(v) setattr(project_filter, k, v) project_filter.save() project_settings.save()
def reset_password(self, obj): reset_mail_url = reverse('admin:auth_user_password_reset_mail', kwargs={'pk': obj.id}) properties.set_tenant(connection.tenant) return format_html("<a href='{}'>{}</a>", reset_mail_url, _("Send reset password mail"))
def construct_from_header(): """ construct a from header based on what's in 'properties'. Return None if no sender data (address) is available, which shoud result in the system default being used. """ # The tenant properties will not be set if the call to this method # does not come via a django request => we need to setup the tenant # properties first. # properties.tenant_properties will be an empty dict if the tenant # properties has not be initialised yet. if not properties.tenant_properties and connection.tenant: properties.set_tenant(connection.tenant) mail_address = properties.TENANT_MAIL_PROPERTIES.get('address') mail_name = properties.TENANT_MAIL_PROPERTIES.get('sender') if not mail_name: mail_name = properties.TENANT_MAIL_PROPERTIES.get('name') if not mail_name: mail_name = mail_address if not mail_address: return None return "{0} <{1}>".format(mail_name, mail_address)
def set_tenant(self, tenant, *args, **kwargs): """ Main API method to current database schema, but it does not actually modify the db connection. """ super(DatabaseWrapper, self).set_tenant(tenant, *args, **kwargs) properties.set_tenant(tenant)
def __exit__(self, type, value, traceback): if self.clear_tenant: try: del properties.tenant del properties.tenant_properties except AttributeError: logger.info("Attempted to clear missing tenant properties.") elif self.previous_tenant: properties.set_tenant(self.previous_tenant)
def __exit__(self, type, value, traceback): if self.clear_tenant: try: del properties.tenant del properties.tenant_properties except AttributeError: logger.info("Attempted to clear missing tenant properties.") elif self.previous_tenant: connection.set_tenant(self.previous_tenant) properties.set_tenant(self.previous_tenant) ContentType.objects.clear_cache()
def migrate_activity_types(apps, schema_editor): InitiativePlatformSettings = apps.get_model('initiatives', 'InitiativePlatformSettings') Client = apps.get_model('clients', 'Client') initiative_settings, _ = InitiativePlatformSettings.objects.get_or_create() tenant = Client.objects.get(schema_name=connection.tenant.schema_name) properties.set_tenant(tenant) initiative_settings.activity_types = [u'event', u'assignment'] if 'funding' in properties.PROJECT_CREATE_TYPES: initiative_settings.activity_types += [u'funding'] initiative_settings.save()
def migrate_share_options(apps, schema_editor): ProjectPlatformSettings = apps.get_model('projects', 'ProjectPlatformSettings') Client = apps.get_model('clients', 'Client') project_settings, _ = ProjectPlatformSettings.objects.get_or_create() tenant = Client.objects.get(schema_name=connection.tenant.schema_name) properties.set_tenant(tenant) project_settings.share_options = [ key for key, value in list(properties.SHARE_OPTIONS.items()) if value ] if 'facebookAtWork' in project_settings.share_options: project_settings.facebook_at_work_url = 'https://booking.facebook.com' project_settings.save()
def migrate_settings(apps, schema_editor): Client = apps.get_model('clients', 'Client') MemberPlatformSettings = apps.get_model('members', 'MemberPlatformSettings') tenant = Client.objects.get(schema_name=connection.tenant.schema_name) properties.set_tenant(tenant) (settings, _) = MemberPlatformSettings.objects.get_or_create() try: settings.closed = properties.CLOSED_SITE except AttributeError: pass try: if properties.TOKEN_AUTH: settings.login_methods = ['SSO'] except AttributeError: pass settings.save()
def mail_pledge_platform_admin(donation): # Only process "one-off" type donations if donation.order.order_type != "one-off": return project_url = '/projects/{0}'.format(donation.project.slug) # Setup tenant properties for accessing tenant admin email if not properties.tenant_properties and connection.tenant: properties.set_tenant(connection.tenant) try: admin_email = properties.TENANT_MAIL_PROPERTIES.get('address') except AttributeError: logger.critical('No mail properties found for {0}'.format(connection.tenant.client_name)) if admin_email: # Use the platform default language with TenantLanguage(properties.LANGUAGE_CODE): subject = _('A new pledge donation has been received') payment_method = get_payment_method(donation) # Create fake user object for mail receiver = bunchify({'email': admin_email}) # Send email to the project owner. send_mail( template_name='payments_pledge/mails/pledge_details.mail', subject=subject, to=receiver, link=project_url, donation=donation, pledged=True, payment_method=payment_method )
def __enter__(self): if self.tenant: properties.set_tenant(self.tenant)
def migrate_projects(apps, schema_editor): migrate_payment_providers(apps) Project = apps.get_model('projects', 'Project') Initiative = apps.get_model('initiatives', 'Initiative') Funding = apps.get_model('funding', 'Funding') Geolocation = apps.get_model('geo', 'Geolocation') Country = apps.get_model('geo', 'Country') Image = apps.get_model('files', 'Image') Client = apps.get_model('clients', 'Client') OrganizationContact = apps.get_model('organizations', 'OrganizationContact') StripePayoutAccount = apps.get_model('funding_stripe', 'StripePayoutAccount') ExternalAccount = apps.get_model('funding_stripe', 'ExternalAccount') PlainPayoutAccount = apps.get_model('funding', 'PlainPayoutAccount') PayoutAccount = apps.get_model('funding', 'PayoutAccount') BudgetLine = apps.get_model('funding', 'BudgetLine') Reward = apps.get_model('funding', 'Reward') Fundraiser = apps.get_model('funding', 'Fundraiser') OldPayoutAccount = apps.get_model('payouts', 'PayoutAccount') FlutterwaveBankAccount = apps.get_model('funding_flutterwave', 'FlutterwaveBankAccount') VitepayBankAccount = apps.get_model('funding_vitepay', 'VitepayBankAccount') LipishaBankAccount = apps.get_model('funding_lipisha', 'LipishaBankAccount') PledgeBankAccount = apps.get_model('funding_pledge', 'PledgeBankAccount') Wallpost = apps.get_model('wallposts', 'Wallpost') ContentType = apps.get_model('contenttypes', 'ContentType') # Clean-up previous migrations of projects to initiatives Initiative.objects.all().delete() tenant = Client.objects.get(schema_name=connection.tenant.schema_name) properties.set_tenant(tenant) stripe_bank_ct = ContentType.objects.get_for_model(ExternalAccount) stripe_account_ct = ContentType.objects.get_for_model(StripePayoutAccount) plain_account_ct = ContentType.objects.get_for_model(PlainPayoutAccount) flutterwave_ct = ContentType.objects.get_for_model(FlutterwaveBankAccount) lipisha_ct = ContentType.objects.get_for_model(LipishaBankAccount) vitepay_ct = ContentType.objects.get_for_model(VitepayBankAccount) pledge_ct = ContentType.objects.get_for_model(PledgeBankAccount) funding_ct = ContentType.objects.get_for_model(Funding) project_ct = ContentType.objects.get_for_model(Project) initiative_ct = ContentType.objects.get_for_model(Initiative) for project in Project.objects.select_related( 'payout_account', 'projectlocation').iterator(): if hasattr(project, 'projectlocation') and project.projectlocation.country: if project.projectlocation.latitude and project.projectlocation.longitude: point = Point(float(project.projectlocation.longitude), float(project.projectlocation.latitude)) else: point = Point(0, 0) country = project.country if not country and project.projectlocation.country and Country.objects.filter( translations__name=project.projectlocation.country).count( ): country = Country.objects.filter( translations__name__contains=project.projectlocation. country).first() if not country: country = Country.objects.filter( alpha2_code=properties.DEFAULT_COUNTRY_CODE).first() if country: place = Geolocation.objects.create( street=project.projectlocation.street, postal_code=project.projectlocation.postal_code, country=country, locality=project.projectlocation.city, position=point) else: place = None else: if project.country: place = Geolocation.objects.create(country=project.country, position=Point(0, 0)) else: place = None initiative = Initiative.objects.create( title=project.title, slug=project.slug, pitch=project.pitch or '', story=project.story or '', theme_id=project.theme_id, video_url=project.video_url, place=place, location_id=project.location_id, owner_id=project.owner_id, reviewer_id=project.reviewer_id, activity_manager_id=project.task_manager_id, promoter_id=project.promoter_id, status=map_status(project.status)) if project.image: try: image = Image.objects.create(owner=project.owner) image.file.save(project.image.name, project.image.file, save=True) initiative.image = image except IOError: pass if project.organization: initiative.organization = project.organization contact = OrganizationContact.objects.filter( organization=project.organization).first() if contact: initiative.organization_contact = contact initiative.created = project.created initiative.categories = project.categories.all() initiative.save() # Create Funding event if there are donations if project.project_type in ['both', 'funding'] \ or project.donation_set.count() \ or project.amount_asked.amount: account = None if project.payout_account: try: stripe_account = project.payout_account.stripepayoutaccount if stripe_account.account_id: payout_account = StripePayoutAccount.objects.create( polymorphic_ctype=stripe_account_ct, account_id=stripe_account.account_id, owner=stripe_account.user, # country=stripe_account.country.alpha2_code ) account = ExternalAccount.objects.create( polymorphic_ctype=stripe_bank_ct, connect_account=payout_account, # account_id=stripe_account.bank_details.account ) except OldPayoutAccount.DoesNotExist: plain_account = project.payout_account.plainpayoutaccount payout_account = PlainPayoutAccount.objects.create( polymorphic_ctype=plain_account_ct, owner=plain_account.user, reviewed=plain_account.reviewed) if str(project.amount_asked.currency) == 'NGN': country = None if plain_account.account_bank_country: country = plain_account.account_bank_country.alpha2_code account = FlutterwaveBankAccount.objects.create( polymorphic_ctype=flutterwave_ct, connect_account=payout_account, account_holder_name=plain_account. account_holder_name, bank_country_code=country, account_number=plain_account.account_number) elif str(project.amount_asked.currency) == 'KES': account = LipishaBankAccount.objects.create( polymorphic_ctype=lipisha_ct, connect_account=payout_account, account_number=plain_account.account_number, account_name=plain_account.account_holder_name, address=plain_account.account_holder_address) elif str(project.amount_asked.currency) == 'XOF': account = VitepayBankAccount.objects.create( polymorphic_ctype=vitepay_ct, connect_account=payout_account, account_name=plain_account.account_holder_name, ) else: account = PledgeBankAccount.objects.create( polymorphic_ctype=pledge_ct, connect_account=payout_account, account_holder_name=plain_account. account_holder_name, account_holder_address=plain_account. account_holder_address, account_holder_postal_code=plain_account. account_holder_postal_code, account_holder_city=plain_account. account_holder_city, account_holder_country_id=plain_account. account_holder_country_id, account_number=plain_account.account_number, account_details=plain_account.account_details, account_bank_country_id=plain_account. account_bank_country_id, ) funding = Funding.objects.create( # Common activity fields polymorphic_ctype= funding_ct, # This does not get set automatically in migrations initiative=initiative, owner_id=project.owner_id, highlight=project.is_campaign, created=project.created, updated=project.updated, status=map_funding_status(project.status), review_status=map_funding_review_status(project.status), title=project.title, slug=project.slug, description=project.pitch or '', transition_date=project.campaign_ended, # Funding specific fields deadline=project.deadline, target=project.amount_asked, amount_matching=project.amount_extra, country=project.country, bank_account=account) project.funding_id = funding.id project.save() Wallpost.objects.filter(content_type=project_ct, object_id=project.id).\ update(content_type=funding_ct, object_id=funding.id) for budget_line in project.projectbudgetline_set.all(): new_budget_line = BudgetLine.objects.create( activity=funding, amount=budget_line.amount, description=budget_line.description, created=budget_line.created, updated=budget_line.updated) fundraiser_ct = ContentType.objects.get_for_model(Initiative) old_fundraiser_ct = ContentType.objects.get_for_model(Project) for fundraiser in project.fundraiser_set.all(): new_fundraiser = Fundraiser.objects.create( owner_id=fundraiser.owner_id, activity=funding, title=fundraiser.title, description=fundraiser.description, amount=fundraiser.amount, deadline=fundraiser.deadline, created=fundraiser.created, updated=fundraiser.updated) new_fundraiser.save() if fundraiser.image: try: image = Image.objects.create(owner=fundraiser.owner) image.file.save(fundraiser.image.name, fundraiser.image.file, save=True) initiative.image = image except IOError: pass Wallpost.objects.filter(content_type=old_fundraiser_ct, object_id=fundraiser.id). \ update(content_type=fundraiser_ct, object_id=new_fundraiser.id) for reward in project.reward_set.all(): new_reward = Reward.objects.create( activity=funding, amount=reward.amount, description=reward.description, title=reward.title, limit=reward.limit, created=reward.created, updated=reward.updated) reward.new_reward_id = new_reward.id reward.save() else: Wallpost.objects.filter(content_type=project_ct, object_id=project.id).\ update(content_type=initiative_ct, object_id=initiative.id)
def __enter__(self): if self.tenant: connection.set_tenant(self.tenant) properties.set_tenant(self.tenant) ContentType.objects.clear_cache()
def test_verify_settings(self): with mock.patch("bluebottle.clients.settings", MULTI_TENANT_DIR='/tmp/') as settings, \ mock.patch("__builtin__.execfile") as execfile: properties.set_tenant(Mock(client_name='testtenant')) self.assertEquals(execfile.call_args[0][1]['settings'], settings)
def migrate_payment_providers(apps): PledgePaymentProvider = apps.get_model('funding_pledge', 'PledgePaymentProvider') StripePaymentProvider = apps.get_model('funding_stripe', 'StripePaymentProvider') FlutterwavePaymentProvider = apps.get_model('funding_flutterwave', 'FlutterwavePaymentProvider') VitepayPaymentProvider = apps.get_model('funding_vitepay', 'VitepayPaymentProvider') LipishaPaymentProvider = apps.get_model('funding_lipisha', 'LipishaPaymentProvider') Client = apps.get_model('clients', 'Client') ContentType = apps.get_model('contenttypes', 'ContentType') tenant = Client.objects.get(schema_name=connection.tenant.schema_name) properties.set_tenant(tenant) for provider in properties.MERCHANT_ACCOUNTS: pp = None if provider['merchant'] == 'stripe': content_type = ContentType.objects.get_for_model( StripePaymentProvider) pp = StripePaymentProvider.objects.create( polymorphic_ctype=content_type, ) for payment_methods in properties.PAYMENT_METHODS: if payment_methods['id'] == 'stripe-creditcard': pp.credit_card = True elif payment_methods['id'] == 'stripe-ideal': pp.ideal = True elif payment_methods['id'] == 'stripe-directdebit': pp.direct_debit = True elif payment_methods['id'] == 'stripe-bancontact': pp.bancontact = True pp.save() set_currencies(apps, pp, 'stripe') elif provider['merchant'] == 'vitepay': content_type = ContentType.objects.get_for_model( VitepayPaymentProvider) pp = VitepayPaymentProvider.objects.create( polymorphic_ctype=content_type, api_secret=provider['api_secret'], api_key=provider['api_key'], api_url=provider['api_url'], prefix='new') set_currencies(apps, pp, 'vitepay') elif provider['merchant'] == 'lipisha': content_type = ContentType.objects.get_for_model( LipishaPaymentProvider) pp = LipishaPaymentProvider.objects.create( polymorphic_ctype=content_type, api_key=provider['api_key'], api_signature=provider['api_signature'], paybill=provider['business_number'], prefix='new') set_currencies(apps, pp, 'lipisha') elif provider['merchant'] == 'flutterwave': content_type = ContentType.objects.get_for_model( FlutterwavePaymentProvider) pp = FlutterwavePaymentProvider.objects.create( polymorphic_ctype=content_type, pub_key=provider['pub_key'], sec_key=provider['sec_key'], prefix='new') set_currencies(apps, pp, 'flutterwave') elif provider['merchant'] == 'pledge': content_type = ContentType.objects.get_for_model( PledgePaymentProvider) pp = PledgePaymentProvider.objects.create( polymorphic_ctype=content_type, ) set_currencies(apps, pp, 'pledge')
def new_oneoff_donation(instance): """ Send project owner a mail if a new "one off" donation is done. We consider a donation done if the status is pending. """ donation = instance # Only process "one-off" type donations if donation.order.order_type != "one-off": return project_url = "/projects/{0}".format(donation.project.slug) pledged = donation.order.status == StatusDefinition.PLEDGED # Setup tenant properties for accessing tenant admin email if not properties.tenant_properties and connection.tenant: properties.set_tenant(connection.tenant) try: admin_email = properties.TENANT_MAIL_PROPERTIES.get("address") except AttributeError: logger.critical("No mail properties found for {0}".format(connection.tenant.client_name)) if donation.project.owner.email: receiver = donation.project.owner with TenantLanguage(receiver.primary_language): subject = _("You received a new donation") if donation.anonymous: donor_name = _("an anonymous person") elif donation.order.user: donor_name = donation.order.user.first_name else: donor_name = _("a guest") payment_method = get_payment_method(donation) # Send email to the project owner. send_mail( template_name="bb_donations/mails/new_oneoff_donation.mail", subject=subject, to=receiver, link=project_url, donor_name=donor_name, donation=donation, pledged=pledged, admin_email=admin_email, payment_method=payment_method, ) if donation.order.user and donation.order.user.email: # Send email to the project supporter donor = donation.order.user with TenantLanguage(donor.primary_language): subject = _("Thanks for your donation") payment_method = get_payment_method(donation) send_mail( template_name="bb_donations/mails/confirmation.mail", subject=subject, to=donor, link=project_url, donation=donation, pledged=pledged, payment_method=payment_method, )
def test_verify_settings(self): tenant_dir = os.path.join(os.path.dirname(__file__), 'files/') with mock.patch("bluebottle.clients.settings", MULTI_TENANT_DIR=tenant_dir): properties.set_tenant(Mock(client_name='testtenant')) self.assertEqual(properties.set_by_test, True)
def migrate_tasks(apps, schema_editor): Client = apps.get_model('clients', 'Client') tenant = Client.objects.get(schema_name=connection.tenant.schema_name) properties.set_tenant(tenant) Task = apps.get_model('tasks', 'Task') Activity = apps.get_model('activities', 'Activity') Event = apps.get_model('events', 'Event') Assignment = apps.get_model('assignments', 'Assignment') Contribution = apps.get_model('activities', 'Contribution') Participant = apps.get_model('events', 'Participant') Applicant = apps.get_model('assignments', 'Applicant') Initiative = apps.get_model('initiatives', 'Initiative') ContentType = apps.get_model('contenttypes', 'ContentType') Wallpost = apps.get_model('wallposts', 'Wallpost') Place = apps.get_model('geo', 'Place') Geolocation = apps.get_model('geo', 'Geolocation') # Clean-up previous migrations of projects to initiatives Event.objects.all().delete() Assignment.objects.all().delete() event_ctype = ContentType.objects.get_for_model(Event) participant_ctype = ContentType.objects.get_for_model(Participant) assignment_ctype = ContentType.objects.get_for_model(Assignment) applicant_ctype = ContentType.objects.get_for_model(Applicant) task_ctype = ContentType.objects.get_for_model(Task) def get_location(task): place = Place.objects.filter(content_type=task_ctype, object_id=task.pk).first() if place: return Geolocation.objects.create( street_number=place.street_number, street=place.street, postal_code=place.postal_code, locality=place.locality, province=place.province, position=Point(float(place.position.longitude), float(place.position.latitude)), country_id=place.country_id) else: return None for task in Task.objects.select_related('project').prefetch_related( 'members').iterator(): if task.type == 'event' and (not task.skill_id or not task.skill.expertise): initiative = Initiative.objects.get(slug=task.project.slug) geolocation = get_location(task) status = map_event_status(task) event = Event.objects.create( # activity fields polymorphic_ctype=event_ctype, initiative=initiative, title=task.title, slug=slugify(task.title), description=task.description, review_status=initiative.status, status=status, owner_id=task.author_id, # event fields capacity=task.people_needed, automatically_accept=bool(task.accepting == 'automatic'), is_online=bool(not task.location), location=geolocation, location_hint=task.location, start_date=task.deadline.date(), start_time=task.deadline.time(), duration=task.time_needed, transition_date=task.deadline) task.activity_id = event.pk task.save() event.created = task.created event.updated = task.updated event.polymorphic_ctype = event_ctype event.save() for task_member in task.members.all(): status = map_participant_status(task_member) participant = Participant.objects.create( activity=event, user=task_member.member, status=status, time_spent=task_member.time_spent, transition_date=task.updated) participant.created = task.created participant.updated = task.updated participant.polymorphic_ctype = participant_ctype participant.save() old_ct = ContentType.objects.get_for_model(Task) Wallpost.objects.filter(content_type=old_ct, object_id=task.id).\ update(content_type=event_ctype, object_id=event.id) else: initiative = Initiative.objects.get(slug=task.project.slug) geolocation = get_location(task) status = map_event_status(task) end_date_type = 'deadline' if task.type == 'event': end_date_type = 'on_date' assignment = Assignment.objects.create( # activity fields polymorphic_ctype=assignment_ctype, initiative=initiative, title=task.title, slug=slugify(task.title), description=task.description, status=status, review_status=initiative.status, owner=task.author, # assignment fields end_date_type=end_date_type, registration_deadline=task.deadline_to_apply.date(), end_date=task.deadline.date(), capacity=task.people_needed, is_online=bool(not task.location), location=geolocation, duration=task.time_needed, expertise=task.skill, transition_date=task.deadline) task.activity_id = assignment.pk task.save() assignment.created = task.created assignment.updated = task.updated assignment.polymorphic_ctype = assignment_ctype assignment.save() for task_member in task.members.all(): status = map_applicant_status(task_member) applicant = Applicant.objects.create( activity=assignment, user=task_member.member, status=status, time_spent=task_member.time_spent, motivation=task_member.motivation, transition_date=task.updated) applicant.created = task.created applicant.updated = task.updated applicant.polymorphic_ctype = applicant_ctype applicant.save() old_ct = ContentType.objects.get_for_model(Task) Wallpost.objects.filter(content_type=old_ct, object_id=task.id). \ update(content_type=assignment_ctype, object_id=assignment.id)