def handle(self, *args, **options):
        hub_url = options['hub_url']
        hub_token = options['hub_token']
        id_url = options['identity_url']
        id_token = options['identity_token']
        hub_id_field = options['hub_identity_field']

        if not hub_url or not hub_token:
            self.warning("hub-url and hub-token is required.")
            return

        hubApi = HubApiClient(hub_token, hub_url)
        idApi = IdentityStoreApiClient(id_token, id_url)

        subscriptions = Subscription.objects.filter(process_status=5)

        reg_count = 0
        id_count = 0
        for subscription in subscriptions.iterator():
            identity = subscription.identity

            # find and update linked registrations
            registrations = hubApi.get_registrations({hub_id_field: identity})

            for registration in registrations['results']:

                if not registration['data'].get('exclude_report', False):
                    registration['data']['exclude_report'] = True

                    try:
                        hubApi.update_registration(
                            registration['id'], {'data': registration['data']})
                        reg_count += 1
                    except exceptions.ConnectionError as exc:
                        self.warning(
                            'Connection error to Hub API: {}'.format(exc))
                    except HTTPServiceError as exc:
                        self.warning('Invalid Hub API response({}): {}'.format(
                            exc.response.status_code, exc.response.url))

            # find and update linked identities
            identity = idApi.get_identity(identity)

            if not identity['details'].get('exclude_report', False):
                identity['details']['exclude_report'] = True

                try:
                    idApi.update_identity(identity['id'],
                                          {'details': identity['details']})
                    id_count += 1
                except exceptions.ConnectionError as exc:
                    self.warning(
                        'Connection error to Identity API: {}'.format(exc))
                except HTTPServiceError as exc:
                    self.warning(
                        'Invalid Identity Store API response({}): {}'.format(
                            exc.response.status_code, exc.response.url))

        self.success('Updated %s identities and %s registrations.' %
                     (id_count, reg_count))
コード例 #2
0
def identities(request):
    context = {}
    idApi = IdentityStoreApiClient(
        api_url=request.session["user_tokens"]["SEED_IDENTITY_SERVICE"]
        ["url"],  # noqa
        auth_token=request.session["user_tokens"]["SEED_IDENTITY_SERVICE"][
            "token"]  # noqa
    )
    if 'address_value' in request.GET:
        form = IdentitySearchForm(request.GET)
        if form.is_valid():
            results = idApi.get_identity_by_address(
                address_type=form.cleaned_data['address_type'],
                address_value=form.cleaned_data['address_value'])['results']
        else:
            results = []
    else:
        form = IdentitySearchForm()
        results = idApi.get_identities()['results']

    identities = utils.get_page_of_iterator(results,
                                            settings.IDENTITY_LIST_PAGE_SIZE,
                                            request.GET.get('page'))

    context['identities'] = identities
    context['form'] = form
    return render(request, 'ci/identities.html', context)
コード例 #3
0
def identity(request, identity):
    idApi = IdentityStoreApiClient(
        api_url=request.session["user_tokens"]["SEED_IDENTITY_SERVICE"]
        ["url"],  # noqa
        auth_token=request.session["user_tokens"]["SEED_IDENTITY_SERVICE"][
            "token"]  # noqa
    )
    hubApi = HubApiClient(
        api_url=request.session["user_tokens"]["HUB"]["url"],  # noqa
        auth_token=request.session["user_tokens"]["HUB"]["token"]  # noqa
    )
    sbmApi = StageBasedMessagingApiClient(
        api_url=request.session["user_tokens"]["SEED_STAGE_BASED_MESSAGING"]
        ["url"],  # noqa
        auth_token=request.session["user_tokens"]["SEED_STAGE_BASED_MESSAGING"]
        ["token"]  # noqa
    )
    msApi = MessageSenderApiClient(
        api_url=request.session["user_tokens"]["SEED_MESSAGE_SENDER"]
        ["url"],  # noqa
        auth_token=request.session["user_tokens"]["SEED_MESSAGE_SENDER"][
            "token"]  # noqa
    )
    messagesets_results = sbmApi.get_messagesets()
    messagesets = {}
    schedules = {}
    choices = []
    for messageset in messagesets_results["results"]:
        messagesets[messageset["id"]] = messageset["short_name"]
        schedules[messageset["id"]] = messageset["default_schedule"]
        choices.append((messageset["id"], messageset["short_name"]))

    results = idApi.get_identity(identity)
    sbm_filter = {"identity": identity}
    subscriptions = sbmApi.get_subscriptions(params=sbm_filter)

    if request.method == "POST":
        if 'add_subscription' in request.POST:
            form = AddSubscriptionForm(request.POST)
            language = results['details'].get(settings.LANGUAGE_FIELD)

            if language:

                if form.is_valid():
                    subscription = {
                        "active": True,
                        "identity": identity,
                        "completed": False,
                        "lang": language,
                        "messageset": form.cleaned_data['messageset'],
                        "next_sequence_number": 1,
                        "schedule": schedules[form.cleaned_data['messageset']],
                        "process_status": 0,
                    }
                    sbmApi.create_subscription(subscription)

                    messages.add_message(
                        request,
                        messages.INFO,
                        'Successfully created a subscription.',
                        extra_tags='success')
            else:
                messages.add_message(
                    request,
                    messages.ERROR,
                    'No language value in {} on the identity.'.format(
                        settings.LANGUAGE_FIELD),
                    extra_tags='danger')

        elif 'deactivate_subscription' in request.POST:
            form = DeactivateSubscriptionForm(request.POST)

            if form.is_valid():
                data = {"active": False}
                sbmApi.update_subscription(
                    form.cleaned_data['subscription_id'], data)

                messages.add_message(
                    request,
                    messages.INFO,
                    'Successfully deactivated the subscription.',
                    extra_tags='success')

        elif 'optout_identity' in request.POST:
            try:
                details = results.get('details', {})
                addresses = details.get('addresses', {})

                for address_type, addresses in addresses.items():
                    for address, info in addresses.items():
                        idApi.create_optout({
                            "identity": identity,
                            "optout_type": "stop",
                            "address_type": address_type,
                            "address": address,
                            "request_source": "ci"
                        })

                hubApi.create_optout_admin({settings.IDENTITY_FIELD: identity})

                messages.add_message(request,
                                     messages.INFO,
                                     'Successfully opted out.',
                                     extra_tags='success')
            except:
                messages.add_message(request,
                                     messages.ERROR,
                                     'Optout failed.',
                                     extra_tags='danger')

    hub_filter = {settings.IDENTITY_FIELD: identity}
    registrations = hubApi.get_registrations(params=hub_filter)
    changes = hubApi.get_changes(params=hub_filter)
    if results is None:
        return redirect('not_found')

    outbound_message_params = {
        'to_identity': identity,
        'ordering': '-created_at',
    }
    outbound_messages = msApi.get_outbounds(params=outbound_message_params)
    outbound_page = request.GET.get('outbound_page')
    outbound_paginator = Paginator(list(outbound_messages['results']),
                                   settings.IDENTITY_MESSAGES_PAGE_SIZE)

    try:
        outbound_messages = outbound_paginator.page(outbound_page)
    except PageNotAnInteger:
        outbound_messages = outbound_paginator.page(1)
    except EmptyPage:
        outbound_messages = outbound_paginator.page(
            outbound_paginator.num_pages)

    inbound_message_params = {
        'from_identity': identity,
        'ordering': '-created_at',
    }
    inbound_messages = msApi.get_inbounds(inbound_message_params)
    inbound_page = request.GET.get('inbound_page')
    inbound_paginator = Paginator(list(inbound_messages['results']),
                                  settings.IDENTITY_MESSAGES_PAGE_SIZE)

    try:
        inbound_messages = inbound_paginator.page(inbound_page)
    except PageNotAnInteger:
        inbound_messages = inbound_paginator.page(1)
    except EmptyPage:
        inbound_messages = inbound_paginator.page(inbound_paginator.num_pages)

    deactivate_subscription_form = DeactivateSubscriptionForm()
    add_subscription_form = AddSubscriptionForm()
    add_subscription_form.fields['messageset'] = forms.ChoiceField(
        choices=choices)

    optout_visible = False
    details = results.get('details', {})
    addresses = details.get('addresses', {})
    msisdns = addresses.get('msisdn', {})
    optout_visible = any((not d.get('optedout') for _, d in msisdns.items()))

    context = {
        "identity": results,
        "registrations": registrations,
        "changes": changes,
        "messagesets": messagesets,
        "subscriptions": subscriptions,
        "outbound_messages": outbound_messages,
        "add_subscription_form": add_subscription_form,
        "deactivate_subscription_form": deactivate_subscription_form,
        "inbound_messages": inbound_messages,
        "optout_visible": optout_visible
    }
    context.update(csrf(request))
    return render(request, 'ci/identities_detail.html', context)
コード例 #4
0
    def handle(self, *args, **options):
        identity_store_token = options['identity_store_token']
        identity_store_url = options['identity_store_url']
        hub_token = options['hub_token']
        hub_url = options['hub_url']
        file_name = options['csv']
        start = options['start']
        end = options['end']
        no_is = options['no_is_lookup']
        log = get_logger()

        if not file_name:
            raise CommandError('--csv is a required parameter')

        if not os.path.isfile(file_name):
            raise CommandError('--csv must be a valid path to a file')

        if not hub_url:
            raise CommandError('--hub-url is a required parameter')

        if not hub_token:
            raise CommandError('--hub-token is a required parameter')

        if not no_is:
            if not identity_store_url:
                raise CommandError('--identity-store-url is a required '
                                   'parameter')

            if not identity_store_token:
                raise CommandError('--identity-store-token is a required '
                                   'parameter')

            ids_client = IdentityStoreApiClient(identity_store_token,
                                                identity_store_url)

        hub_client = HubApiClient(hub_token, hub_url)

        with open(file_name) as csv_file:
            csv_reader = csv.reader(csv_file, delimiter=';')

            if start and end:
                rows = itertools.islice(csv_reader, start, end)
                row_count = start
            elif start and not end:
                rows = itertools.islice(csv_reader, start)
                row_count = start
            elif end and not start:
                raise CommandError('--start is a required parameter when '
                                   'specifying --end')
            else:
                rows = csv_reader
                row_count = 1
                # skip the header row
                next(csv_reader)

            for idx, row in enumerate(rows, start=row_count):
                loop_log = log.bind(row=idx)
                msisdn = '+{0}'.format(row[1])
                loop_log = loop_log.bind(msisdn=msisdn)
                if no_is:
                    identity = row[3]
                    if not identity:
                        loop_log.error('Could not load identity for msisdn.')
                        continue

                else:
                    result = list(ids_client.get_identity_by_address(
                        'msisdn', msisdn)['result'])
                    if len(result) < 1:
                        loop_log.error('Could not load identity for msisdn.')
                        continue

                    if len(result) > 1:
                        msg = 'Warning: Found {0} identities'
                        msg = msg.format(len(result))
                        loop_log.warn(msg)
                    identity = result[0]['id']

                # Use this logger only for this iteration of the loop
                id_log = loop_log.bind(identity=identity)
                change = {
                    'registrant_id': identity,
                    'action': 'momconnect_nonloss_optout',
                    'data': {
                        'reason': 'sms_failure'
                    }
                }
                try:
                    result = hub_client.create_change(change)
                except exceptions.ConnectionError as exc:
                    id_log.error('Connection error to Hub API: {}'
                                 .format(exc.message))
                    break
                except HTTPServiceError as exc:
                    id_log.error('Invalid Hub API response',
                                 url=exc.response.url,
                                 status_code=exc.response.status_code)
                    break

                if result:
                    id_log.info('Successfully submitted changed.')
                else:
                    id_log.error('Change failed', response=result)
コード例 #5
0
    def handle(self, *options, **kwargs):
        self.identity_cache = {}

        hub_token = kwargs['hub_token']
        hub_url = kwargs['hub_url']
        id_store_token = kwargs['identity_store_token']
        id_store_url = kwargs['identity_store_url']
        group = kwargs['group']

        headers = ['risk', 'count']
        if group == 'msisdn':
            if not id_store_token or not id_store_url:
                raise CommandError(
                    'Please make sure the --identity-store-url and '
                    '--identity-store-token is set.')

            ids_client = IdentityStoreApiClient(id_store_token, id_store_url)
            headers = ['msisdn', 'risk']

        output = self.stdout
        if kwargs['output']:
            output = open(kwargs['output'], 'w')

        results = defaultdict(int)

        def add_to_result(risk, reg):
            if group == "msisdn":
                identity = self.get_identity(ids_client, reg)

                if identity:
                    details = identity.get('details', {})
                    default_addr_type = details.get('default_addr_type')
                    if default_addr_type:
                        addresses = details.get('addresses', {})
                        msisdns = addresses.get(default_addr_type, {}).keys()
                    else:
                        msisdns = []

                    results[', '.join(msisdns)] = 1 if risk == "high" else 0
            else:
                results[risk] += 1

        if hub_token and hub_url:
            hub_client = HubApiClient(hub_token, hub_url)

            for source in (1, 3):
                registrations = hub_client.get_registrations({
                    "source": source,
                    "validated": True
                })['results']

                for registration in registrations:
                    mom_dob = registration["data"].get("mom_dob")
                    if not mom_dob:
                        identity = self.get_identity(
                            ids_client, registration["registrant_id"])
                        if not identity:
                            continue
                        mom_dob = identity["details"].get("mom_dob")

                    risk = get_risk_status(registration["reg_type"], mom_dob,
                                           registration["data"].get("edd"))

                    add_to_result(risk, registration['registrant_id'])

        else:
            registrations = Registration.objects.filter(
                Q(reg_type='pmtct_postbirth') | Q(reg_type='pmtct_prebirth')
                | Q(reg_type='whatsapp_pmtct_postbirth')
                | Q(reg_type='whatsapp_pmtct_prebirth'),
                validated=True)

            for registration in registrations.iterator():
                add_personally_identifiable_fields(registration)
                risk = get_risk_status(registration.reg_type,
                                       registration.data["mom_dob"],
                                       registration.data.get("edd"))

                add_to_result(risk, registration.registrant_id)

        writer = csv.DictWriter(output, headers)
        writer.writeheader()
        for risk, count in results.items():
            writer.writerow({headers[0]: risk, headers[1]: count})
コード例 #6
0
    def handle(self, *args, **kwargs):
        self.identity_cache = {}
        self.messageset_cache = {}
        hub_token = kwargs['hub_token']
        hub_url = kwargs['hub_url']
        id_store_token = kwargs['identity_store_token']
        id_store_url = kwargs['identity_store_url']
        sbm_token = kwargs['sbm_token']
        sbm_url = kwargs['sbm_url']
        ms_token = kwargs['ms_token']
        ms_url = kwargs['ms_url']
        start_date = kwargs['start']
        end_date = kwargs['end']
        output_file = kwargs['output_file']

        email_recipients = kwargs['email_to']
        email_sender = kwargs['email_from']
        email_subject = kwargs['email_subject']

        if not sbm_url:
            raise CommandError('Please make sure the --sbm-url is set.')

        if not sbm_token:
            raise CommandError('Please make sure the --sbm-token is set.')

        if not ms_url:
            raise CommandError('Please make sure the --ms-url is set.')

        if not ms_token:
            raise CommandError('Please make sure the --ms-token is set.')

        if not output_file:
            raise CommandError('Please specify --output-file.')

        if end_date is None:
            end_date = one_month_after(start_date)

        hub_client = HubApiClient(hub_token, hub_url)
        ids_client = IdentityStoreApiClient(id_store_token, id_store_url)
        sbm_client = StageBasedMessagingApiClient(sbm_token, sbm_url)
        ms_client = MessageSenderApiClient(ms_token, ms_url)

        workbook = self.workbook_class()
        sheet = workbook.add_sheet('Registrations by date', 0)
        self.handle_registrations(sheet, hub_client, ids_client, start_date,
                                  end_date)

        sheet = workbook.add_sheet('Health worker registrations', 1)
        self.handle_health_worker_registrations(sheet, hub_client, ids_client,
                                                start_date, end_date)

        sheet = workbook.add_sheet('Enrollments', 2)
        self.handle_enrollments(sheet, sbm_client, ids_client, start_date,
                                end_date)

        sheet = workbook.add_sheet('SMS delivery per MSISDN', 3)
        self.handle_sms_delivery_msisdn(sheet, ms_client, start_date, end_date)

        sheet = workbook.add_sheet('OBD Delivery Failure', 4)
        self.handle_obd_delivery_failure(sheet, ms_client, start_date,
                                         end_date)

        sheet = workbook.add_sheet('Opt Outs by Subscription', 5)
        self.handle_optouts_by_subscription(sheet, sbm_client, ids_client,
                                            start_date, end_date)

        sheet = workbook.add_sheet('Opt Outs by Date', 6)
        self.handle_optouts_by_date(sheet, hub_client, sbm_client, ids_client,
                                    start_date, end_date)

        workbook.save(output_file)

        if email_recipients:
            file_name = 'report-%s-to-%s.xlsx' % (
                start_date.strftime('%Y-%m-%d'), end_date.strftime('%Y-%m-%d'))
            self.send_email(email_subject, file_name, output_file,
                            email_sender, email_recipients)
コード例 #7
0
    def handle(self, *args, **options):
        schedules = options['schedule']
        default_addr_type = options['default_addr_type']
        identity_store_token = options['identity_store_token']
        identity_store_url = options['identity_store_url']
        message_sender_token = options['message_sender_token']
        message_sender_url = options['message_sender_url']
        since = options['since']
        until = options['until']
        dry_run = options['dry_run']

        if not since:
            raise CommandError('--since is a required parameter')

        if not until:
            raise CommandError('--until is a required parameter')

        from seed_services_client import (StageBasedMessagingApiClient,
                                          IdentityStoreApiClient,
                                          MessageSenderApiClient)

        id_store_client = IdentityStoreApiClient(identity_store_token,
                                                 identity_store_url)

        message_sender_client = MessageSenderApiClient(message_sender_token,
                                                       message_sender_url)

        def confirm(prompt):
            if options['confirm']:
                return True
            try:
                return input("%s [y/n] > " % (prompt, )).lower() == "y"
            except KeyboardInterrupt:
                raise CommandError("Please confirm the question.")

        msg = ("You are about to trigger a stage based messaging send for %s "
               "subscriptions. Are you sure you want to be doing this?" %
               (self.style.NOTICE(str(schedules.count()))))

        if not confirm(msg):
            raise CommandError(
                'Please confirm as you need to know what you are doing.')

        for schedule in schedules.iterator():
            sbm_api_url, subscription_uuid = self.parse_sbm_api_url(
                schedule.endpoint)
            sbm_client = StageBasedMessagingApiClient(schedule.auth_token,
                                                      sbm_api_url)
            subscription = sbm_client.get_subscription(subscription_uuid)
            identity = id_store_client.get_identity(subscription['identity'])
            addresses = self.get_addresses(identity, default_addr_type)
            any_outbounds = []
            for address in addresses:
                outbounds = message_sender_client.get_outbounds(
                    params={
                        'to_addr': address,
                        'before': until.isoformat(),
                        'after': since.isoformat(),
                    })
                any_outbounds.extend(outbounds['results'])

            if any_outbounds:
                continue

            if dry_run:
                self.stdout.write('Dry run for %s' % (schedule, ))
            else:
                self.stdout.write('%s' % (schedule, ))
                DeliverTask.apply_async(
                    kwargs={"schedule_id": str(schedule.id)})
コード例 #8
0
import random
import re
from django.conf import settings
from contentstore.models import MessageSet
from subscriptions.models import Subscription
from seed_services_client import IdentityStoreApiClient

NORMALISE_METRIC_RE = re.compile(r'\W+')

identity_store_client = IdentityStoreApiClient(
    settings.IDENTITY_STORE_TOKEN,
    settings.IDENTITY_STORE_URL,
    retries=5,
    timeout=settings.DEFAULT_REQUEST_TIMEOUT,
)


def get_identity(identity_uuid):
    return identity_store_client.get_identity(identity_uuid)


def normalise_metric_name(name):
    """
    Replaces all non-alphanumeric characters with underscores.
    """
    return NORMALISE_METRIC_RE.sub('_', name).rstrip('_').lstrip('_')


def get_identity_address(identity_uuid, use_communicate_through=False):
    params = {"default": True}
    if use_communicate_through: