Beispiel #1
0
    def save_contacts(cls, group):
        client = TembaClient(settings.HOST, settings.KEY)
        added = 0
        folders = [
            'inbox', 'sent', 'flows', 'archived', 'outbox', 'incoming',
            'failed', 'calls'
        ]

        for contact_batch in client.get_contacts().iterfetches(
                retry_on_rate_exceed=True):
            for contact in contact_batch:
                if not cls.contact_exists(contact):
                    cls.objects.create(uuid=contact.uuid,
                                       name=contact.name,
                                       language=contact.language,
                                       urns=contact.urns,
                                       groups=group,
                                       fields=contact.fields,
                                       blocked=contact.blocked,
                                       stopped=contact.stopped,
                                       created_on=contact.created_on,
                                       modified_on=contact.modified_on)
                    c = Contact.objects.get(uuid=contact.uuid)

                    for folder in folders:
                        Message.save_messages(contact=c, msg_folder=folder)
                    added += 1
        return added
Beispiel #2
0
    def save_messages(cls, contact, msg_folder='sent'):
        client = TembaClient(settings.HOST, settings.KEY)
        added = 0

        for message_batch in client.get_messages(
                folder=msg_folder).iterfetches(retry_on_rate_exceed=True):
            for message in message_batch:
                if not cls.message_exists(message):
                    cls.objects.create(id=message.id,
                                       folder=msg_folder,
                                       broadcast=message.broadcast,
                                       contact=contact,
                                       urn=message.urn,
                                       channel=message.channel,
                                       direction=message.direction,
                                       type=message.type,
                                       status=message.status,
                                       visibility=message.visibility,
                                       text=message.text,
                                       labels=message.labels,
                                       created_on=message.created_on,
                                       sent_on=message.sent_on,
                                       modified_on=message.modified_on)
                    added += 1
        return added
Beispiel #3
0
 def get_contact(cls):
     client = TembaClient(settings.HOST, settings.KEY)
     contacts = client.get_contacts().all()
     for contact in contacts:
         cls.objects.create(uuid=contact.uuid,
                            name=contact.name,
                            urn=contact.urn)
    def populate_poll_poll_date(apps, schema_editor):
        Poll = apps.get_model("polls", "Poll")
        Org = apps.get_model("orgs", "Org")

        agent = getattr(settings, "SITE_API_USER_AGENT", None)
        host = settings.SITE_API_HOST

        for org in Org.objects.all():
            temba_client = TembaClient(host, org.api_token, user_agent=agent)
            api_flows = temba_client.get_flows()
            flows_date = dict()
            for flow in api_flows:
                flows_date[flow.uuid] = datetime_to_json_date(flow.created_on)

            for poll in Poll.objects.filter(org=org):
                json_date = flows_date.get(poll.flow_uuid, None)
                if json_date:
                    date = json_date_to_datetime(json_date)
                else:
                    logger.info(
                        "using created_on for flow_date on poll with id %s" %
                        poll.pk)
                    date = poll.created_on

                poll.poll_date = date
                poll.save()
 def read_rapidpro_credentials_file(self, credential_file):
     with open(credential_file, encoding='utf-8') as data_file:
         data = json.loads(data_file.read())
     self.rapidpro_apikey = data['rapidpro_apikey']
     self.rapidpro_url = data['rapidpro_url']
     self.rapidpro_message_sending_flow = data['rapidpro_message_send_flow']
     self.client = TembaClient(self.rapidpro_url, self.rapidpro_apikey)
Beispiel #6
0
    def fetch(cls, domain_name, token_id):
        client = TembaClient(domain_name, token_id)
        for page_data in client.get_groups().iterfetches(
                retry_on_rate_exceed=True):
            for group1 in page_data:
                cls.objects.create(name=group1.name, count=group1.count)

        return True
Beispiel #7
0
 def __init__(self, server, token):
     """
     :param server: Server hostname, e.g. 'rapidpro.io'
     :type server: str
     :param token: Organization API token
     :type token: str
     """
     self.rapid_pro = TembaClient(server, token)
Beispiel #8
0
 def get_flow(cls):
     client = TembaClient(settings.HOST, settings.KEY)
     flows = client.get_flows().all()
     for flow in flows:
         cls.objects.create(uuid=flow.uuid,
                            name=flow.name,
                            created_on=flow.created_on,
                            complete_runs=flow.runs.completed,
                            interrupted_runs=flow.runs.interrupted,
                            expired_runs=flow.runs.expired)
Beispiel #9
0
def get_or_create_contact(client: TembaClient, name: str,
                          phone_number: str) -> Contact:
    '''
    Retrieve the contact with the given phone number, creating them (and providing the
    given name) if they don't already exist.
    '''

    urn = f'tel:+1{phone_number}'
    contact = client.get_contacts(urn=urn).first(retry_on_rate_exceed=True)
    if contact is None:
        contact = client.create_contact(name=name, urns=[urn])
    return contact
Beispiel #10
0
    def add_groups(cls):
        client = TembaClient(settings.HOST, settings.KEY)
        groups = client.get_groups().all()
        added = 0
        for group in groups:
            if not cls.group_exists(group):
                cls.objects.create(uuid=group.uuid,
                                   name=group.name,
                                   query=group.query,
                                   count=group.count)
                added += 1

        return added
Beispiel #11
0
 def add_groups(cls):
     client = TembaClient(settings.HOST, settings.KEY)
     added = 0
     for group_batch in client.get_groups().iterfetches(
             retry_on_rate_exceed=True):
         for group in group_batch:
             if not cls.group_exists(group):
                 g = cls.objects.create(uuid=group.uuid,
                                        name=group.name,
                                        query=group.query,
                                        count=group.count)
                 Contact.save_contacts(group=g)
                 added += 1
     return added
Beispiel #12
0
 def test_add_flows(self):
     client = TembaClient('hiwa.tmcg.co.ug',
                          'f7f5d2ae2e5d37e9e879cc7f8375d1b980b6f3e8 ')
     flow = Flow.objects.first()
     flow_count = Flow.objects.count()
     added_flow = Flow.add_flows(client)
     self.assertEquals(Flow.objects.count(), flow_count + added_flow)
Beispiel #13
0
 def test_add_flows(self):
     client = TembaClient('hiwa.tmcg.co.ug',
                          '1da6d399139139812e2f949a64ce80264184996f')
     flow = Flow.objects.first()
     flow_count = Flow.objects.count()
     added_flow = Flow.add_flows(client)
     self.assertEquals(Flow.objects.count(), flow_count + added_flow)
Beispiel #14
0
 def test_save_contacts(self):
     client = TembaClient('hiwa.tmcg.co.ug',
                          '1da6d399139139812e2f949a64ce80264184996f')
     contact_count = Contact.objects.count()
     added_contacts = Contact.save_contacts(client=client)
     self.assertEquals(Contact.objects.count(),
                       contact_count + added_contacts)
Beispiel #15
0
def get_or_create_contact(client: TembaClient, name: str, phone_number: str,
                          locale: str) -> Contact:
    """
    Retrieve the contact with the given phone number, creating them (and providing the
    given name and locale) if they don't already exist.

    Locale should be an ISO 639-1 code, e.g. "en".
    """

    urn = f"tel:+1{phone_number}"
    contact = client.get_contacts(urn=urn).first(retry_on_rate_exceed=True)
    if contact is None:
        contact = client.create_contact(name=name,
                                        urns=[urn],
                                        language=iso639one2two(locale))
    return contact
Beispiel #16
0
 def test_save_messages(self):
     client = TembaClient('hiwa.tmcg.co.ug',
                          '1da6d399139139812e2f949a64ce80264184996f')
     message_count = Message.objects.count()
     added_messages = Message.save_messages(client=client)
     self.assertEquals(Message.objects.count(),
                       message_count + added_messages)
Beispiel #17
0
    def save_consent(self):
        # call RapidPro instance and save consent for uuid
        client = TembaClient(settings.RAPIDPRO_URL, settings.RAPIDPRO_TOKEN)
        contact = client.get_contacts(uuid=self.cleaned_data["uuid"]).first()
        if not contact:
            return

        client.update_contact(
            contact=self.cleaned_data["uuid"],
            fields={
                "consent_date": "{}T00:00:00.000000+02:00".format(
                    date.today().isoformat()
                ),
                "consent": "true",
            },
        )
Beispiel #18
0
    def get_run(cls):
        client = TembaClient(settings.HOST, settings.KEY)
        runs = client.get_runs().all()
        initial_runs = 0
        for run in runs:
            if not cls.run_exists(run):
                cls.objects.create(id=run.id,
                                   responded=run.responded,
                                   created_on=run.created_on,
                                   modified_on=run.modified_on)

                k = Run.objects.get(run_id=run.run_id)
                Value.get_values(values=run.values, run_id=k)
                Step.get_steps(path=run.path, run_id=k)
                initial_runs += 1

        return initial_runs
Beispiel #19
0
 def iter_exited_runs(self, client: TembaClient) -> Iterator[Run]:
     print(f"Processing exited runs of flow '{self.name}'.")
     run_batches = client.get_runs(flow=self.uuid).iterfetches(
         retry_on_rate_exceed=True)
     for run_batch in run_batches:
         for run in run_batch:
             if run.exit_type:
                 yield run
Beispiel #20
0
 def test_save_contacts(self):
     client = TembaClient('hiwa.tmcg.co.ug',
                          'f7f5d2ae2e5d37e9e879cc7f8375d1b980b6f3e8')
     contact_count = Contact.objects.count()
     workspace = Workspace.objects.first()
     added_contacts = Contact.save_contacts(client=client,
                                            workspace=workspace)
     self.assertEquals(Contact.objects.count(),
                       contact_count + added_contacts)
Beispiel #21
0
def get_client_from_settings() -> Optional[TembaClient]:
    """
    Retrieve a RapidPro client based on Django settings, or None if
    RapidPro isn't configured.
    """

    if not settings.RAPIDPRO_API_TOKEN:
        return None
    return TembaClient(settings.RAPIDPRO_HOSTNAME, settings.RAPIDPRO_API_TOKEN)
Beispiel #22
0
def get_field(client: TembaClient, key: str) -> Field:
    """
    Return the RapidPro field with the given key, raising an exception
    if it doesn't exist.
    """

    field = client.get_fields(key=key).first(retry_on_rate_exceed=True)
    if field is None:
        raise ValueError(f"Unable to find RapidPro field with key '{key}'")
    return field
 def add_fields_to_contact(self, contact_urn, field_dict):
     client = TembaClient(self.rapidpro_url, self.rapidpro_apikey)
     #get the groups we need to add them too
     field_names = list(field_dict.keys())
     for field in field_names:
         check_field = self.client.get_fields(field.replace('-',
                                                            '_')).first()
         if check_field is None:
             self.client.create_field(field.replace('_', '-'), "text")
     add_fields = self.client.update_contact(contact_urn, fields=field_dict)
Beispiel #24
0
def get_group(client: TembaClient, name: str) -> Group:
    """
    Return the RapidPro group with the given name, raising an exception
    if it doesn't exist.
    """

    group = client.get_groups(name=name).first(retry_on_rate_exceed=True)
    if group is None:
        raise ValueError(f"Unable to find RapidPro group '{name}'")
    return group
Beispiel #25
0
    def POST(self):
        params = web.input()
        web.header("Content-Type", "application/json; charset=utf-8")
        username, password = get_basic_auth_credentials()
        r = auth_user(db, username, password)
        if not r[0]:
            web.header('WWW-Authenticate', 'Basic realm="Auth API"')
            web.ctx.status = '401 Unauthorized'
            return json.dumps({'detail': 'Authentication failed!'})

        client = TembaClient(
            config.get('familyconnect_uri', 'http://localhost:8000/'),
            config['api_token'])

        secreceivers = get_webhook_msg_old(params, 'secreceivers')
        pprint.pprint(secreceivers)
        payload = json.loads(secreceivers)

        optout_option = get_webhook_msg_old(params, 'OptOutOption')
        print("OptOutOption => ", optout_option)
        try:
            contact_details = payload['%s' % int(float(optout_option))]
        except:
            contact_details = None
        if not contact_details:
            return json.dumps({'success': 'False'})

        contact_id = contact_details['contact_id']
        contact_uuid = contact_details['uuid']
        print("contact_id=>", contact_id, " uuid => ", contact_uuid)

        date_of_birth = get_webhook_msg_old(params, 'child_dob')

        try:
            client.create_flow_start(config['babytrigger_flow_uuid'],
                                     contacts=[contact_uuid],
                                     extra={'child_dob': date_of_birth})
        except:
            pass

        return json.dumps({'success': 'True'})
Beispiel #26
0
    def get_rapidpro_workspaces(cls):
        workspaces = cls.objects.all()
        for workspace in workspaces:
            client = TembaClient(workspace.host, workspace.key)
            Group.add_groups(client=client)
            Contact.save_contacts(client=client, workspace=workspace)
            Flow.add_flows(client=client)
            Run.add_runs(client=client)
            Campaign.add_campaigns(client=client)
            CampaignEvent.add_campaign_events(client=client)

        return cls.objects.count()
Beispiel #27
0
    def test_save_messages(self):
        client = TembaClient('hiwa.tmcg.co.ug',
                             'f7f5d2ae2e5d37e9e879cc7f8375d1b980b6f3e8 ')
        message_count = Message.objects.count()
        contacts = Contact.objects.all()
        added_messages = 0
        for contact in contacts:
            added_messages = +Message.save_messages(client=client,
                                                    contact=contact)

        self.assertEquals(Message.objects.count(),
                          message_count + added_messages)
def index():
    form = PhoneEmailSignUpForm(request.form)
    if request.method == "POST":
        if form.validate():
            app.logger.debug("Form Validated")
            name = request.form["name"]
            phone_number = request.form["phone"]

            # TODO: include this in validation of phone number as well
            processed_phone_number = process_number(phone_number)
            formatted_rapidpro_number = "tel:{}".format(processed_phone_number)

            registration_pin = math.floor(random.uniform(10000, 99999))
            fields = {}
            fields[RAPIDPRO_FIELD] = registration_pin
            try:
                app.logger.debug("Creating Client")
                client = TembaClient(RAPIDPRO_URL, RAPIDPRO_TOKEN)
                app.logger.debug("Creating Contact")
                client.create_contact(
                    name=name,
                    urns=[formatted_rapidpro_number],
                    groups=[RAPIDPRO_GROUP],
                    fields=fields,
                )
                try:
                    app.logger.debug("Starting Flow")
                    client.create_flow_start(
                        RAPIDPRO_FLOW_UUID,
                        urns=[formatted_rapidpro_number],
                        restart_participants=True,
                        extra=None,
                    )
                    return redirect(
                        url_for("success", registration_pin=registration_pin, name=name)
                    )

                except Exception as e_1:
                    # try and delete the number so that they can start again if they want to
                    try:
                        app.logger.error("Flow Start Failed\n{}".format(e_1))
                        client.delete_contact(formatted_rapidpro_number)
                    except Exception as e_2:
                        app.logger.error("Unable to delete contact\n{}".format(e_2))
                    flash("Apologies, something went wrong, please try again.")

            except TembaBadRequestError:
                flash("That number has already been submitted")

    return render_template("index.html", form=form)
    def add_to_group_and_update_date_field(self, client: TembaClient, contact: Contact):
        """
        Add the given contact to the follow-up campaign's group, setting the campaign's
        field key to the current date and time.
        """
        blocked_or_stopped = (
            "blocked" if contact.blocked else "stopped texts from" if contact.stopped else None
        )
        if blocked_or_stopped:
            logger.info(
                "Contact has %s Justfix, so not adding them to group %s",
                self.group_name,
                blocked_or_stopped,
                exc_info=True,
            )
            return

        client.update_contact(
            contact,
            groups=[*contact.groups, get_group(client, self.group_name)],
            fields={**contact.fields, self.field_key: format_iso8601(datetime.datetime.now())},
        )
Beispiel #30
0
    def process(self, after, before):
        client = TembaClient('rapidpro.io', RAPIDPRO_API_KEY)
        engine = sqla.create_engine(SQLALCHEMY_DATABASE_URI, encoding='utf8')

        if self.table is None:
            raise ValueError('Improperly configured. '
                             'A table needs to be provided')

        if not engine.dialect.has_table(engine, self.table.name):
            self.table.create(engine)

        conn = engine.connect()

        latest = self.latest(conn)

        extras = {}
        if after:
            extras['after'] = parser.parse(after)
        elif latest:
            extras['after'] = latest[self.order_field]

        if before:
            extras['before'] = parser.parse(before)

        print(
            f"Fetching objects between {extras.get('after')} and {extras.get('before')}"
        )

        batches = self.api_call(client, extras)\
            .iterfetches(retry_on_rate_exceed=True)

        cols = [i.key for i in self.table.columns]

        for batch in batches:
            print(f'Importing a batch of runs ({len(batch)})...')
            for elem in batch:
                if (latest and getattr(elem, self.id_field) == getattr(
                        latest, self.id_field)):
                    print(
                        f'Skipping already imported object {getattr(elem,self.id_field)}.'
                    )
                    continue
                data = elem.serialize()
                print(f'Importing object {data[self.id_field]}')
                insert = self.table.insert().values(
                    **{c: process_column(self.table, data, c)
                       for c in cols})
                try:
                    conn.execute(insert)
                except Exception as e:
                    print(f'Error during: {e.orig}')