def test_assignment_reminder_task_on_date(self): user = BlueBottleUserFactory.create(first_name='Nono') end = now() + timedelta(days=4) assignment = AssignmentFactory.create( owner=user, status='open', end_date_type='on_date', initiative=self.initiative, date=end ) ApplicantFactory.create_batch(2, activity=assignment, status='new') ApplicantFactory.create(activity=assignment, status='accepted') withdrawn = ApplicantFactory.create(activity=assignment, status='new') withdrawn.states.withdraw(save=True) mail.outbox = [] tenant = connection.tenant assignment_tasks() with LocalTenant(tenant, clear_tenant=True): assignment.refresh_from_db() recipients = [message.to[0] for message in mail.outbox] for applicant in assignment.contributions.instance_of(Applicant).all(): if applicant.status in ['new', 'accepted']: self.assertTrue(applicant.user.email in recipients) else: self.assertFalse(applicant.user.email in recipients) self.assertEqual( mail.outbox[0].subject, '"{}" will take place in 5 days!'.format(assignment.title) )
def test_assignment_check_end_date_future(self): user = BlueBottleUserFactory.create(first_name='Nono') deadline = now() - timedelta(days=4) date = now() + timedelta(days=2) assignment = AssignmentFactory.create( owner=user, status='open', capacity=3, registration_deadline=deadline.date(), initiative=self.initiative, date=date, ) applicants = ApplicantFactory.create_batch(3, activity=assignment) for applicant in applicants: applicant.states.accept(save=True) ApplicantFactory.create_batch(3, activity=assignment) tenant = connection.tenant future = timezone.now() + timedelta(days=3) with mock.patch.object(timezone, 'now', return_value=future): assignment_tasks() with LocalTenant(tenant, clear_tenant=True): assignment.refresh_from_db() self.assertEqual(assignment.status, 'succeeded') for applicant in assignment.applicants: self.assertEqual(applicant.status, 'succeeded')
def test_event_end_task(self): user = BlueBottleUserFactory.create(first_name='Nono') start = timezone.now() + timedelta(hours=5) event = EventFactory.create( owner=user, initiative=self.initiative, title='Finish them translations, Rolfertjan!', start=start, duration=1 ) event.states.submit(save=True) ParticipantFactory.create_batch(3, activity=event) tenant = connection.tenant mail.outbox = [] future = timezone.now() + timedelta(hours=6) with mock.patch.object(timezone, 'now', return_value=future): event_tasks() with LocalTenant(tenant, clear_tenant=True): event = Event.objects.get(pk=event.pk) self.assertEqual(event.status, EventStateMachine.succeeded.value) self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].subject, u'Your event "{}" took place! \U0001f389'.format(event.title)) self.assertTrue("Hi Nono,", mail.outbox[0].body)
def test_assignment_check_registration_deadline(self): user = BlueBottleUserFactory.create(first_name='Nono') deadline = now() - timedelta(days=1) end = now() + timedelta(days=4) assignment = AssignmentFactory.create( owner=user, status='open', capacity=3, end_date_type='on_date', registration_deadline=deadline.date(), initiative=self.initiative, duration=4, date=end, ) applicants = ApplicantFactory.create_batch(3, activity=assignment, status='new') for applicant in applicants: applicant.states.accept(save=True) tenant = connection.tenant assignment_tasks() with LocalTenant(tenant, clear_tenant=True): assignment.refresh_from_db() self.assertEqual(assignment.status, 'full')
def update_time_spent(apps, schema_editor): TaskMember = apps.get_model('tasks', "TaskMember") with LocalTenant(connection.tenant): for tm in TaskMember.objects.filter(status='realized'): if tm.task and tm.task.time_needed: tm.time_spent = tm.task.time_needed tm.save()
def generate_participation_xls(self): file_name = self.get_file_name() self.file_path = self.get_xls_file_name(file_name) client = Client.objects.get(client_name=self.tenant) with xlsxwriter.Workbook(self.file_path, { 'default_date_format': 'dd/mm/yy', 'remove_timezone': True }) as workbook: with LocalTenant(client, clear_tenant=True): logger.info( 'export participation metrics - tenant:{} start_date:{} end_date:{}' .format(self.tenant, self.start_date.to_iso8601_string(), self.end_date.to_iso8601_string())) logger.info('file path: {}'.format(self.file_path)) self.generate_participants_worksheet(workbook) self.generate_worksheet(workbook, 'aggregated') self.generate_worksheet(workbook, 'location_segmentation') self.generate_worksheet(workbook, 'theme_segmentation') if self.to_email: with open(self.file_path, 'r') as f: User = namedtuple('User', 'email') user = User(email=self.to_email) send_mail(template_name='participation_metrics_email', subject='Participation Metrics', to=user, attachments=[(file_name, f.read())], connection=connection)
def create_refunded_phase(apps, schema_editor): ProjectPhase = apps.get_model('bb_projects', 'ProjectPhase') try: ProjectPhase.objects.get_or_create( id=13, slug='refunded', viewable=True, editable=False, sequence=11, description='The project was refunded') except FieldError: # If project phases are already translated then translate description object, created = ProjectPhase.objects.get_or_create(id=13, slug='refunded', viewable=True, editable=False, sequence=11) Client = apps.get_model('clients', 'Client') PhaseTranslation = apps.get_model('bb_projects', 'ProjectPhaseTranslation') tenant = Client.objects.get(schema_name=connection.tenant.schema_name) with LocalTenant(tenant): languages = get_languages() for (language, _long_language) in languages: activate(language) _trans._active.value = tenant_translation( language, tenant.client_name) PhaseTranslation.objects.create( master_id=object.pk, language_code=language, name=_('Refunded'), description=_('The project was refunded'), )
def handle(self, *args, **options): if options['all']: tenants = Client.objects.all() if options['tenant']: tenants = [Client.objects.get(schema_name=options['tenant'])] for client in tenants: print "\n\nCreating homepage for {}".format(client.name) with LocalTenant(client, clear_tenant=True): ContentType.objects.clear_cache() (page, _created) = HomePage.objects.get_or_create(pk=1) languages = [lang[0] for lang in properties.LANGUAGES] for language_code in languages: page.translations.get_or_create( language_code=language_code, ) page_type = ContentType.objects.get_for_model(page) (placeholder, _created) = Placeholder.objects.get_or_create( parent_id=page.pk, parent_type_id=page_type.pk, slot='content', role='m') for item in ContentItem.objects.filter(parent_id=page.pk, parent_type=page_type): item.delete() for lang, blocks in properties.HOMEPAGE.items(): for (block_type, block) in blocks: self.create_block(block_type, block, placeholder, lang)
def _merge_attrs(data, attrs): try: items = attrs.iteritems() except AttributeError: logger.exception('analytics_merge_attrs') return for label, attr in items: options = {} # If a dict is passed then the key is the dotted # property string and the value is options. try: new_attr = attr.keys()[0] options = attr[new_attr] attr = new_attr except AttributeError: # TODO: Logging pass value = _multi_getattr(instance, attr, default='') if options.get('translate', False): with LocalTenant(): # Translate using the default tenant language with TenantLanguage( getattr(properties, 'LANGUAGE_CODE', 'en')): # If attr is a string then try to translate # Note: tag values should always be strings. value = _(value) data[label] = value
def handle(self, *args, **options): if options['all'] and options['tenant']: raise CommandError('--all and --tenant cannot be used together') if options['all']: tenants = Client.objects.all() else: tenants = Client.objects.filter(client_name=options['tenant']) tokens = [] for tenant in tenants: with LocalTenant(tenant): tokens += [{ 'api_key': token.key, 'name': tenant.client_name, 'domain': 'https://{}'.format(tenant.domain_url), 'fees': { 'under_target': properties.PROJECT_PAYOUT_FEES.get( 'not_fully_funded', 0), 'over_target': properties.PROJECT_PAYOUT_FEES.get('fully_funded', 0) } } for token in Token.objects.filter( user__email=options['email'])] self.stdout.write(json.dumps(tokens, indent=4))
def add_group_permissions(apps, schema_editor): tenant = Client.objects.get(schema_name=connection.tenant.schema_name) with LocalTenant(tenant): group_perms = { 'Staff': { 'perms': ( 'add_participant', 'change_participant', 'delete_participant', ) }, 'Anonymous': { 'perms': ('api_read_event', ) if not properties.CLOSED_SITE else () }, 'Authenticated': { 'perms': ( 'api_read_participant', 'api_add_participant', 'api_change_own_participant', ) } } update_group_permissions('events', group_perms, apps)
def _post_to_facebook(instance, tenant=None): """ Post a Wallpost to users Facebook page using Celery """ logger.info("FB post for:") logger.info("{0} with id {1} and tenant {2}".format(instance.__class__, instance.id, tenant.client_name)) if not tenant: return with LocalTenant(tenant, clear_tenant=True): social = instance.author.social_auth.get(provider='facebook') authorization_header = 'Bearer {token}'.format( token=social.extra_data['access_token'] ) graph_url = 'https://graph.facebook.com/v2.4/me/feed' base_url = 'https://{domain}'.format( domain=tenant.domain_url) link = instance.content_object.get_absolute_url() image = None # This code is executed via Celery, we assume the MediaWallpostPhoto # is saved and available on the instance. If the user uploaded # photos with the MediaWallpost we take the first one and include it # in the Facebook post. Otherwise we fallback to the project image. if isinstance(instance, MediaWallpost) and instance.photos.count() > 0: image = urljoin(base_url, get_thumbnail(instance.photos.all()[0].photo, "600x400").url ) else: if hasattr(instance.content_object, 'image') and instance.content_object.image: image = urljoin( base_url, get_thumbnail(instance.content_object.image, "600x400").url ) description = getattr( instance.content_object, 'pitch', instance.content_object.description ) data = { 'link': link, 'name': instance.content_object.title, 'description': description, 'message': instance.text, 'picture': image, 'caption': tenant_url() } # TODO: log failed requests requests.post( graph_url, data=json.dumps(data), headers={ 'Authorization': authorization_header, 'Content-Type': 'application/json'} )
def handle(self, *args, **options): results = [] for client in Client.objects.all(): connection.set_tenant(client) with LocalTenant(client, clear_tenant=True): ContentType.objects.clear_cache() projects = Project.objects.filter(amount_donated__gt=0) if options['start']: projects = projects.filter(created__gte=options['start']) if options['end']: projects = projects.filter(deadline__lte=options['end']) for project in projects: started = project.campaign_started if project.campaign_started else project.created ended = project.campaign_ended if project.campaign_ended else project.deadline results.append({ 'tenant': client.client_name, 'id': project.id, 'title': project.title, 'slug': project.slug, 'started': started.strftime('%Y-%m-%d'), 'ended': ended.strftime('%Y-%m-%d') }) if options['file']: text_file = open(options['file'], "w") text_file.write(json.dumps(results)) text_file.close() else: print json.dumps(results)
def test_enough_donations(self): donation = DonationFactory.create(activity=self.funding, amount=Money(300, 'EUR')) PledgePaymentFactory.create(donation=donation) donation = DonationFactory.create(activity=self.funding, amount=Money(450, 'EUR')) PledgePaymentFactory.create(donation=donation) self.assertEqual(len(mail.outbox), 4) self.assertEqual(donation.status, 'succeeded') self.funding.deadline = now() - timedelta(days=1) self.funding.save() # Run scheduled task tenant = connection.tenant funding_tasks() with LocalTenant(tenant, clear_tenant=True): self.funding.refresh_from_db() self.assertEqual(len(mail.outbox), 5) self.assertEqual( mail.outbox[4].subject, u'Your campaign "{}" has been successfully completed! \U0001f389'. format(self.funding.title)) self.assertTrue('Hi Jean Baptiste,' in mail.outbox[4].body) self.assertTrue(self.funding.title in mail.outbox[4].body) url = 'http://testserver/en/initiatives/activities/details/funding/{}/{}'.format( self.funding.id, self.funding.slug) self.assertTrue(url in mail.outbox[4].body) organizer = self.funding.contributions.instance_of(Organizer).get() self.assertEqual(organizer.status, organizer.states.succeeded.value)
def test_assignment_check_start_date(self): user = BlueBottleUserFactory.create(first_name='Nono') registration_deadline = now() - timedelta(days=1) date = now() + timedelta(hours=6) assignment = AssignmentFactory.create( owner=user, status='open', capacity=3, registration_deadline=registration_deadline.date(), initiative=self.initiative, end_date_type='on_date', duration=10, date=date ) applicants = ApplicantFactory.create_batch(3, activity=assignment, status='new') for applicant in applicants: applicant.states.accept(save=True) tenant = connection.tenant with mock.patch.object(timezone, 'now', return_value=(timezone.now() + timedelta(hours=7))): assignment_tasks() with LocalTenant(tenant, clear_tenant=True): assignment.refresh_from_db() self.assertEqual(assignment.status, 'running')
def handle(self, **options): logger = logging.getLogger('console') send_email = not options['no_email'] try: client = Client.objects.get(client_name=options['tenant']) except Client.DoesNotExist: logger.error( "You must specify a valid tenant with -t or --tenant.") tenants = Client.objects.all().values_list('client_name', flat=True) logger.info("Valid tenants are: {0}".format(", ".join(tenants))) sys.exit(1) with LocalTenant(client, clear_tenant=True): if options['prepare']: prepare_monthly_batch() if options['process']: process_monthly_batch(tenant=client, monthly_batch=None, send_email=send_email) if options['process_single']: process_single_monthly_order(options['process_single'], None, send_email)
def handle(self, *args, **options): client = Client.objects.get(client_name=options['tenant']) self.upload = options['upload'] with LocalTenant(client, clear_tenant=True): with open(options['file']) as json_file: data = json.load(json_file) if options['models']: self.models = options['models'] counter = Counter() for key in self.models: if key in data: logger.info("Importing {}".format(key)) counter.reset(total=len(data[key])) for value in data[key]: counter.inc() method_to_call = getattr(self, '_handle_{}'.format(key)) method_to_call(value) logger.info(" Done!\n") if 'orders' in self.models: for project in Project.objects.exclude( status__slug='plan-new').all(): if project.deadline < now(): project.status = ProjectPhase.objects.get( slug='campaign') project.campaign_ended = None project.save()
def handle(self, *args, **options): results = [] for client in Client.objects.all(): with LocalTenant(client, clear_tenant=True): payouts = ProjectPayout.objects.filter(amount_payable__gt=0, status='settled') if options['start']: payouts = payouts.filter(created__gte=options['start']) if options['end']: payouts = payouts.filter(created__lte=options['end']) for payout in payouts: result = { 'id': payout.id, 'tenant': client.client_name, 'status': payout.status, 'created': payout.created.strftime('%Y-%m-%d'), 'invoice_reference': payout.invoice_reference, 'amount_raised': { 'amount': float(payout.amount_raised.amount), 'currency': str(payout.amount_raised.currency) }, 'amount_payable': { 'amount': float(payout.amount_payable.amount), 'currency': str(payout.amount_payable.currency) }, 'organization_fee': { 'amount': float(payout.organization_fee.amount), 'currency': str(payout.organization_fee.currency) }, 'donations': [ serialize_donation(donation) for donation in payout.project.donations ] } if payout.amount_raised != payout.project.amount_donated: result['donations'] += [ serialize_donation(donation) for donation in Donation.objects.filter( project=payout.project, order__order_payments__status='charged_back', order__updated__gt=payout.created) ] results.append(result) if options['file']: text_file = open(options['file'], "w") text_file.write(json.dumps(results)) text_file.close() else: print json.dumps(results)
def test_validators_different_tenant(self): with override_properties( AUTH_PASSWORD_VALIDATORS=self.password_validators): validators = get_default_password_validators() self.assertEqual(validators[0].min_length, 10) with LocalTenant(Client.objects.get(client_name='test2')): validators = get_default_password_validators() self.assertEqual(validators[0].min_length, 8)
def refund_project(tenant, project): with LocalTenant(tenant, clear_tenant=True): for donation in project.donations: service = PaymentService(donation.order.order_payment) try: service.refund_payment() except Exception: # Don't trip if one refund throws an error pass
def add_group_permissions(apps, schema_editor): tenant = Client.objects.get(schema_name=connection.tenant.schema_name) with LocalTenant(tenant): group_perms = { 'Anonymous': { 'perms': ('api_read_category', ) if not properties.CLOSED_SITE else () } } update_group_permissions('categories', group_perms, apps)
def check_payment_statuses(order_payments, tenant): connection.set_tenant(tenant) with LocalTenant(tenant, clear_tenant=True): for order_payment in order_payments: service = PaymentService(order_payment) try: service.check_payment_status() except (PaymentException, TypeError): pass
def test_event_scheduled_task_expire(self): tenant = connection.tenant with mock.patch.object(timezone, 'now', return_value=(timezone.now() + timedelta(days=10, hours=12))): event_tasks() with LocalTenant(tenant, clear_tenant=True): self.event.refresh_from_db() event = Event.objects.get(pk=self.event.pk) self.assertEqual(event.status, 'cancelled')
def handle(self, *args, **options): results = [] for client in Client.objects.all(): connection.set_tenant(client) with LocalTenant(client, clear_tenant=True): ContentType.objects.clear_cache() orders = Order.objects.filter( status__in=('pending', 'success')).exclude( order_payments__payment_method='') if options['start']: orders = orders.filter(created__gte=options['start']) if options['end']: orders = orders.filter(created__lte=options['end']) for order in orders: try: transaction_reference = order.order_payment.payment.transaction_reference except Exception: transaction_reference = '' results.append({ 'id': order.id, 'transaction_reference': transaction_reference, 'tenant': client.client_name, 'status': order.status, 'created': order.created.strftime('%Y-%m-%d'), 'amount': { 'amount': float(order.total.amount), 'currency': str(order.total.currency) }, 'donations': [{ 'id': donation.id, 'amount': { 'amount': float(donation.amount.amount), 'currency': str(donation.amount.currency) }, 'donation_id': donation.pk, 'project_id': donation.project.pk } for donation in order.donations.all()] }) if options['file']: text_file = open(options['file'], "w") text_file.write(json.dumps(results)) text_file.close() else: print json.dumps(results)
def timeout_locked_order(order, tenant): """ Timeout locked orders. If the order's status is still LOCKED, assume the the order will never be payed. """ logger.info("Timeing out order {}".format(order)) with LocalTenant(tenant, clear_tenant=True): order = Order.objects.get(pk=order.pk) if order.status == StatusDefinition.LOCKED: order.transition_to(StatusDefinition.FAILED)
def generate_engagement_xls(self): file_name = self.get_xls_file_name(self.start_date, self.end_date) with xlsxwriter.Workbook(file_name) as workbook: for client in Client.objects.all(): if self.tenants is None or client.client_name in self.tenants: with LocalTenant(client, clear_tenant=True): logger.info('export tenant:{}'.format(client.client_name)) raw_data = self.generate_raw_data() aggregated_data = self.generate_aggregated_data(raw_data) self.generate_raw_data_worksheet(workbook, client.client_name, raw_data) self.generate_aggregated_data_worksheet(workbook, client.client_name, aggregated_data)
def add_group_permissions(apps, schema_editor): tenant = Client.objects.get(schema_name=connection.tenant.schema_name) with LocalTenant(tenant): group_perms = { 'Staff': { 'perms': ( 'add_homepagestatisticscontent', 'change_homepagestatisticscontent', 'delete_homepagestatisticscontent', ) }, } update_group_permissions('cms', group_perms, apps)
def update_popularity(): """ Update the popularity score of all the projects Simply loops over all the tenants, and updates the scores """ logger.info("Updating projects popularity using Celery") for tenant in Client.objects.all(): with LocalTenant(tenant, clear_tenant=True): Project.update_popularity() logger.info("Finished updating projects popularity using Celery")
def timeout_new_order(order, tenant): """ Timeout new orders. If the order's status is still CREATED, assume that the order will never be finished. """ logger.info("Timeing out order {}".format(order)) with LocalTenant(tenant, clear_tenant=True): order = Order.objects.get(pk=order.pk) if order.status == StatusDefinition.CREATED: order.transition_to(StatusDefinition.FAILED)
def update_exchange_rates(): """ Update the popularity score of all the projects Simply loops over all the tenants, and updates the scores """ logger.info("Retrieving up to date exchange rates") # call_command('update_rates') logger.info("Updating amounts of all running projects") for tenant in Client.objects.all(): with LocalTenant(tenant, clear_tenant=True): for project in Project.objects.filter(status__slug='campaign'): project.update_amounts()