def test_is_feature_flag(code, is_active, lookup, expected): """Tests if is_feature_flag returns correct state of feature flag.""" if code != '': FeatureFlagFactory(code=code, is_active=is_active) result = is_feature_flag_active(lookup) assert result is expected
def _enrich_data(self, data): """ Get the marketing consent from the consent service """ if is_feature_flag_active(GET_CONSENT_FROM_CONSENT_SERVICE): emails = [item['email'] for item in data] consent_lookups = consent.get_many(emails) for item in data: item['accepts_dit_email_marketing'] = consent_lookups.get( item['email'], False) return data
def _get_desired_stage_order(desired_stage, next_stage): if not next_stage: return desired_stage.order is_streamlined_flow_active = is_feature_flag_active( FEATURE_FLAG_STREAMLINED_FLOW) if is_streamlined_flow_active and str( desired_stage.id) == Stage.prospect.value.id: return desired_stage.order + 200.0 return desired_stage.order + 100.0
def changelist_view(self, request, extra_context=None): """ The changelist view. Overridden to add the add adviser from SSO feature flag to the template context. TODO: Remove this once the feature flag has been removed. """ combined_extra_context = { 'show_add_from_sso': is_feature_flag_active(ADMIN_ADD_ADVISER_FROM_SSO_FEATURE_FLAG), **(extra_context or {}), } return super().changelist_view(request, combined_extra_context)
def update_contact_consent(email_address, accepts_dit_email_marketing, modified_at=None): """ Archive inactive companies. """ if not is_feature_flag_active(UPDATE_CONSENT_SERVICE_FEATURE_FLAG): logger.info( f'Feature flag "{UPDATE_CONSENT_SERVICE_FEATURE_FLAG}" is not active, exiting.', ) return consent.update_consent( email_address, accepts_dit_email_marketing, modified_at=modified_at, )
def complete(self): """Complete a proposition.""" if not is_feature_flag_active(FEATURE_FLAG_PROPOSITION_DOCUMENT): # if proposition documents are not enabled, "details" field is mandatory if self.validated_data['details'] == '': raise ValidationError({ 'details': ['This field may not be blank.'], }) self.instance.complete( by=self.context['current_user'], details=self.validated_data['details'], ) return self.instance
def notify_new_dnb_investigation(company): """ Notify DNB of a new company investigation. """ if not is_feature_flag_active(NOTIFY_DNB_INVESTIGATION_FEATURE_FLAG): return investigation_context = get_dnb_investigation_context(company) recipients = settings.DNB_INVESTIGATION_NOTIFICATION_RECIPIENTS for email_address in recipients: notify_by_email( email_address, Template.request_new_business_record.value, investigation_context, notify_service_name=NotifyServiceName.dnb_investigation, )
def complete(self, by, details): """ Complete a proposition :param by: the adviser who marked the proposition as complete :param details: details of completion :raises ValidationError: when trying to complete proposition without uploaded documents :raises APIConflictException: when proposition status is not ongoing """ if is_feature_flag_active(FEATURE_FLAG_PROPOSITION_DOCUMENT): if self.documents.filter(document__status=UPLOAD_STATUSES.virus_scanned).count() == 0: raise ValidationError({ 'non_field_errors': ['Proposition has no documents uploaded.'], }) self._change_status(PropositionStatus.completed, by, details)
def automatic_company_archive(self, limit=1000, simulate=True): """ Archive inactive companies. """ if not is_feature_flag_active(AUTOMATIC_COMPANY_ARCHIVE_FEATURE_FLAG): logger.info( f'Feature flag "{AUTOMATIC_COMPANY_ARCHIVE_FEATURE_FLAG}" is not active, exiting.', ) return with advisory_lock('automatic_company_archive', wait=False) as acquired: if not acquired: logger.info('Another instance of this task is already running.') return _automatic_company_archive(limit, simulate)
def _send_email(self, **data): """Send email in a separate thread.""" # override recipient if needed if settings.OMIS_NOTIFICATION_OVERRIDE_RECIPIENT_EMAIL: data[ 'email_address'] = settings.OMIS_NOTIFICATION_OVERRIDE_RECIPIENT_EMAIL use_notification_app = is_feature_flag_active( OMIS_USE_NOTIFICATION_APP_FEATURE_FLAG_NAME) if use_notification_app: notify_by_email( data['email_address'], data['template_id'], data.get('personalisation'), NotifyServiceName.omis, ) else: submit_to_thread_pool(send_email, self.client, **data)
def process_mailbox_emails(): """ Process new emails for S3 mailboxes. """ # NOTE: This is a long-lived feature flag which allows us to quickly switch off email # ingestion in case of any problems with third party (SMTP) services or security issues if not is_feature_flag_active(MAILBOX_INGESTION_FEATURE_FLAG_NAME): logger.info( f'Feature flag "{MAILBOX_INGESTION_FEATURE_FLAG_NAME}" is not active, ' 'exiting.', ) return # Acquire a processing lock for the duration of the current DB session - # this will ensure that multiple ingestion workers do not run at the same # time and therefore prevent the chance of messages being processed more # than once with advisory_lock('process_mailbox_emails', wait=False) as acquired: if not acquired: logger.info('Emails are already being processed by another worker') return emails.process_ingestion_emails()
def automatic_company_archive(self, limit=1000, simulate=True): """ Archive inactive companies. """ if not is_feature_flag_active(AUTOMATIC_COMPANY_ARCHIVE_FEATURE_FLAG): logger.info( f'Feature flag "{AUTOMATIC_COMPANY_ARCHIVE_FEATURE_FLAG}" is not active, exiting.', ) return with advisory_lock('automatic_company_archive', wait=False) as acquired: if not acquired: logger.info('Another instance of this task is already running.') return archive_count = _automatic_company_archive(limit, simulate) realtime_message = f'{self.name} archived: {archive_count}' if simulate: realtime_message = f'[SIMULATE] {realtime_message}' send_realtime_message(realtime_message)
def get_company_updates(self, last_updated_after=None, fields_to_update=None): """ Gets the lastest updates for D&B companies from dnb-service. The `dnb-service` exposes these updates as a cursor-paginated list. This task goes through the pages and spawns tasks that update the records in Data Hub. """ # TODO: remove this feature flag after a reasonable period after going live # with unlimited company updates if not is_feature_flag_active(FEATURE_FLAG_DNB_COMPANY_UPDATES): logger.info( f'Feature flag "{FEATURE_FLAG_DNB_COMPANY_UPDATES}" is not active, exiting.', ) return with advisory_lock('get_company_updates', wait=False) as acquired: if not acquired: logger.info('Another instance of this task is already running.') return _get_company_updates(self, last_updated_after, fields_to_update)
def ingest_emails(): """ Ingest and process new emails for all mailboxes in the application - i.e. those in the MAILBOXES django setting. """ # NOTE: This is a long-lived feature flag which allows us to quickly switch off email # ingestion in case of any problems with third party (SMTP) services or security issues if not is_feature_flag_active( INTERACTION_EMAIL_INGESTION_FEATURE_FLAG_NAME): logger.info( f'Feature flag "{INTERACTION_EMAIL_INGESTION_FEATURE_FLAG_NAME}" is not active, ' 'exiting.', ) return # Acquire a processing lock for the duration of the current DB session - # this will ensure that multiple ingestion workers do not run at the same # time and therefore prevent the chance of messages being processed more # than once with advisory_lock('ingest_emails', wait=False) as acquired: if not acquired: logger.info('Emails are already being ingested by another worker') return for mailbox in mailbox_handler.get_all_mailboxes(): mailbox.process_new_mail()
def notify_meeting_ingest_success(adviser, interaction, recipients): """ Notify an adviser that a meeting ingest has succeeeded - including a link to the interaction and intended recipients. """ domain_label = get_domain_label(adviser.get_email_domain()) statsd.incr(f'celery.calendar-invite-ingest.success.{domain_label}') if not is_feature_flag_active( INTERACTION_EMAIL_NOTIFICATION_FEATURE_FLAG_NAME): logger.info( f'Feature flag "{INTERACTION_EMAIL_NOTIFICATION_FEATURE_FLAG_NAME}" is not active, ' 'exiting.', ) return flat_recipients = ', '.join(recipients) notify_adviser_by_email( adviser, Template.meeting_ingest_success.value, context={ 'interaction_url': interaction.get_absolute_url(), 'recipients': flat_recipients, 'support_team_email': settings.DATAHUB_SUPPORT_EMAIL_ADDRESS, }, )
def notify_meeting_ingest_failure(adviser, errors, recipients): """ Notify an adviser that a meeting ingest has failed - including error details and intended recipients. """ domain_label = get_domain_label(adviser.get_email_domain()) statsd.incr(f'celery.calendar-invite-ingest.failure.{domain_label}') if not is_feature_flag_active( INTERACTION_EMAIL_NOTIFICATION_FEATURE_FLAG_NAME): logger.info( f'Feature flag "{INTERACTION_EMAIL_NOTIFICATION_FEATURE_FLAG_NAME}" is not active, ' 'exiting.', ) return flat_recipients = ', '.join(recipients) notify_adviser_by_email( adviser, Template.meeting_ingest_failure.value, context={ 'errors': errors, 'recipients': flat_recipients, 'support_team_email': settings.DATAHUB_SUPPORT_EMAIL_ADDRESS, }, )
def __init__(self): """Checking feature flags that alter validation mapping.""" self.is_streamlined_flow = is_feature_flag_active( FEATURE_FLAG_STREAMLINED_FLOW)
def __call__(self, _) -> bool: """ Returns True if the feature flag is active. """ return is_feature_flag_active(self.feature_flag)