Exemple #1
0
    def test_list(self):
        data = CommentForm(self.unicef).generate_security_data()
        data.update({'comment': 'Foo'})
        self.url_post('unicef', reverse('comments-post-comment'), data)

        data = CommentForm(self.unicef).generate_security_data()
        data.update({'comment': 'Bar'})
        self.url_post('unicef', reverse('comments-post-comment'), data)

        response = self.url_get('unicef', reverse('msg_board.messageboardcomment_list'))

        comment1, comment2 = list(MessageBoardComment.objects.order_by('pk'))

        self.assertEqual(response.json, {'results': [
            {
                'id': comment2.pk,
                'comment': "Bar",
                'user': {'id': self.user1.pk, 'name': "Evan"},
                'submitted_on': format_iso8601(comment2.submit_date),
                'pinned_on': None
            },
            {
                'id': comment1.pk,
                'comment': "Foo",
                'user': {'id': self.user1.pk, 'name': "Evan"},
                'submitted_on': format_iso8601(comment1.submit_date),
                'pinned_on': None
            }
        ]})
Exemple #2
0
    def test_search(self):
        url = reverse('msgs.message_search')

        ann = self.create_contact(self.unicef, 'C-001', "Ann")
        bob = self.create_contact(self.unicef, 'C-002', "Bob")
        cat = self.create_contact(self.unicef, 'C-003', "Cat")
        don = self.create_contact(self.unicef, 'C-004', "Don")
        nic = self.create_contact(self.nyaruka, 'C-101', "Nic")

        # labelled but not cased
        self.create_message(self.unicef, 101, ann, "What is HIV?", [self.aids], is_handled=True)
        self.create_message(self.unicef, 102, bob, "I ♡ RapidPro", [self.pregnancy], is_handled=True)

        # labelled and flagged
        self.create_message(self.unicef, 103, bob, "HELP!", [self.pregnancy], is_handled=True, is_flagged=True)

        # labelled and cased/archived
        self.create_message(self.unicef, 104, bob, "raids", [self.aids], is_handled=True, is_archived=True)
        msg5 = self.create_message(self.unicef, 105, cat, "AIDS??", [self.aids], is_handled=True, is_archived=True)
        case = self.create_case(self.unicef, cat, self.moh, msg5)

        # unlabelled
        self.create_message(self.unicef, 106, don, "RapidCon 2016", is_handled=True)

        # different org
        self.create_message(self.nyaruka, 201, nic, "Moar codes", is_handled=True)

        # log in as a non-administrator
        self.login(self.user1)

        # request first page of inbox (i.e. labelled) messages
        t0 = now()
        response = self.url_get('unicef', url, {
            'folder': 'inbox', 'text': "", 'page': 1, 'after': "", 'before': format_iso8601(t0)
        })

        self.assertEqual(len(response.json['results']), 3)
        self.assertEqual(response.json['results'][0]['id'], 103)
        self.assertEqual(response.json['results'][1]['id'], 102)
        self.assertEqual(response.json['results'][1]['contact'], {'uuid': "C-002", 'name': "Bob"})
        self.assertEqual(response.json['results'][1]['text'], "I ♡ RapidPro")
        self.assertEqual(response.json['results'][1]['labels'], [{'id': self.pregnancy.pk, 'name': "Pregnancy"}])
        self.assertEqual(response.json['results'][2]['id'], 101)

        # request first page of archived messages
        t0 = now()
        response = self.url_get('unicef', url, {
            'folder': 'archived', 'text': "", 'page': 1, 'after': "", 'before': format_iso8601(t0)
        })

        self.assertEqual(len(response.json['results']), 2)
        self.assertEqual(response.json['results'][0]['id'], 105)
        self.assertEqual(response.json['results'][0]['contact'], {'uuid': "C-003", 'name': "Cat"})
        self.assertEqual(response.json['results'][0]['text'], "AIDS??")
        self.assertEqual(response.json['results'][0]['labels'], [{'id': self.aids.pk, 'name': "AIDS"}])
        self.assertEqual(response.json['results'][0]['case'], {'id': case.pk,
                                                               'assignee': {'id': self.moh.pk, 'name': "MOH"}})
        self.assertEqual(response.json['results'][1]['id'], 104)
Exemple #3
0
    def org_task(self, org):
        """
        Fetches new and modified flow runs for the given org and creates/updates
        poll responses.
        """
        from tracpro.orgs_ext.constants import TaskType
        from tracpro.polls.models import Poll, PollRun, Response

        client = org.get_temba_client()
        redis_connection = get_redis_connection()
        last_time_key = LAST_FETCHED_RUN_TIME_KEY % org.pk
        last_time = redis_connection.get(last_time_key)

        if last_time is not None:
            last_time = parse_iso8601(last_time)
        else:
            newest_runs = Response.objects.filter(
                pollrun__poll__org=org).order_by('-created_on')
            newest_runs = newest_runs.exclude(
                pollrun__pollrun_type=PollRun.TYPE_SPOOFED)
            newest_run = newest_runs.first()
            last_time = newest_run.created_on if newest_run else None

        until = timezone.now()

        total_runs = 0
        for poll in Poll.objects.active().by_org(org):
            poll_runs = client.get_runs(flows=[poll.flow_uuid],
                                        after=last_time,
                                        before=until)
            total_runs += len(poll_runs)

            # convert flow runs into poll responses
            for run in poll_runs:
                try:
                    Response.from_run(org, run, poll=poll)
                except ValueError as e:
                    logger.error("Unable to save run #%d due to error: %s" %
                                 (run.id, e.message))
                    continue

        logger.info("Fetched %d new and updated runs for org #%d (since=%s)" %
                    (total_runs, org.id,
                     format_iso8601(last_time) if last_time else 'Never'))

        task_result = dict(time=datetime_to_ms(timezone.now()),
                           counts=dict(fetched=total_runs))
        org.set_task_result(TaskType.fetch_runs, task_result)

        redis_connection.set(last_time_key, format_iso8601(until))
def send_registration_to_rapidpro(contact, msisdn, referral_msisdn, channel,
                                  clinic_code, timestamp):
    # Create/Update contact
    contact_data = {
        "preferred_channel": channel.lower(),
        "registered_by": referral_msisdn or msisdn,
        "facility_code": clinic_code,
        "registration_date": format_iso8601(datetime.fromtimestamp(timestamp)),
        "reg_source": "mobi-site",
    }
    contact = get_rapidpro_contact(
        msisdn)  # Refresh contact so we don't recreate it
    if contact:
        uuid = contact.get("uuid")
        contact = tembaclient.update_contact(uuid, fields=contact_data)
    else:
        urns = ["tel:%s" % msisdn]
        if channel == "WhatsApp":
            urns.append("whatsapp:%s" % msisdn.replace("+", ""))
        contact = tembaclient.create_contact(urns=urns, fields=contact_data)

    # Start the contact on the registration flow
    flow = get_rapidpro_flow_by_name("post registration")
    tembaclient.create_flow_start(flow.uuid, contacts=[contact.uuid])

    return (msisdn, contact.uuid)
Exemple #5
0
    def default(self, val):
        if isinstance(val, datetime.datetime):
            return format_iso8601(val)
        elif isinstance(val, Enum):
            return val.name

        return json.JSONEncoder.default(self, val)
Exemple #6
0
def fetch_org_runs(org_id):
    """
    Fetches new and modified flow runs for the given org and creates/updates
    poll responses.
    """
    from tracpro.orgs_ext.constants import TaskType
    from tracpro.polls.models import Poll, PollRun, Response

    org = Org.objects.get(pk=org_id)

    client = org.get_temba_client()
    redis_connection = get_redis_connection()
    last_time_key = LAST_FETCHED_RUN_TIME_KEY % org.pk
    last_time = redis_connection.get(last_time_key)

    if last_time is not None:
        last_time = parse_iso8601(last_time)
    else:
        newest_runs = Response.objects.filter(pollrun__poll__org=org).order_by("-created_on")
        newest_runs = newest_runs.exclude(pollrun__pollrun_type=PollRun.TYPE_SPOOFED)
        newest_run = newest_runs.first()
        last_time = newest_run.created_on if newest_run else None

    until = timezone.now()

    total_runs = 0
    for poll in Poll.get_all(org):
        poll_runs = client.get_runs(flows=[poll.flow_uuid], after=last_time, before=until)
        total_runs += len(poll_runs)

        # convert flow runs into poll responses
        for run in poll_runs:
            try:
                Response.from_run(org, run, poll=poll)
            except ValueError as e:
                logger.error("Unable to save run #%d due to error: %s" % (run.id, e.message))
                continue

    logger.info(
        "Fetched %d new and updated runs for org #%d (since=%s)"
        % (total_runs, org.id, format_iso8601(last_time) if last_time else "Never")
    )

    task_result = dict(time=datetime_to_ms(timezone.now()), counts=dict(fetched=total_runs))
    org.set_task_result(TaskType.fetch_runs, task_result)

    redis_connection.set(last_time_key, format_iso8601(until))
Exemple #7
0
    def default(self, val):
        if isinstance(val, datetime):
            return format_iso8601(val)
        elif isinstance(val, Enum):
            return val.name
        elif hasattr(val, "to_json") and callable(val.to_json):
            return val.to_json()

        return json.JSONEncoder.default(self, val)  # pragma: no cover
Exemple #8
0
    def default(self, val):
        if isinstance(val, datetime):
            return format_iso8601(val)
        elif isinstance(val, Enum):
            return val.name
        elif hasattr(val, 'to_json') and callable(val.to_json):
            return val.to_json()

        return json.JSONEncoder.default(self, val)  # pragma: no cover
Exemple #9
0
    def test_list(self):
        data = CommentForm(self.unicef).generate_security_data()
        data.update({"comment": "Foo"})
        self.url_post("unicef", reverse("comments-post-comment"), data)

        data = CommentForm(self.unicef).generate_security_data()
        data.update({"comment": "Bar"})
        self.url_post("unicef", reverse("comments-post-comment"), data)

        response = self.url_get("unicef",
                                reverse("msg_board.messageboardcomment_list"))

        comment1, comment2 = list(MessageBoardComment.objects.order_by("pk"))

        self.assertEqual(
            response.json,
            {
                "results": [
                    {
                        "id": comment2.pk,
                        "comment": "Bar",
                        "user": {
                            "id": self.user1.pk,
                            "name": "Evan"
                        },
                        "submitted_on": format_iso8601(comment2.submit_date),
                        "pinned_on": None,
                    },
                    {
                        "id": comment1.pk,
                        "comment": "Foo",
                        "user": {
                            "id": self.user1.pk,
                            "name": "Evan"
                        },
                        "submitted_on": format_iso8601(comment1.submit_date),
                        "pinned_on": None,
                    },
                ]
            },
        )
Exemple #10
0
    def test_list(self):
        data = CommentForm(self.unicef).generate_security_data()
        data.update({'comment': 'Foo'})
        self.url_post('unicef', reverse('comments-post-comment'), data)

        data = CommentForm(self.unicef).generate_security_data()
        data.update({'comment': 'Bar'})
        self.url_post('unicef', reverse('comments-post-comment'), data)

        response = self.url_get('unicef',
                                reverse('msg_board.messageboardcomment_list'))

        comment1, comment2 = list(MessageBoardComment.objects.order_by('pk'))

        self.assertEqual(
            response.json, {
                'results':
                [{
                    'id': comment2.pk,
                    'comment': "Bar",
                    'user': {
                        'id': self.user1.pk,
                        'name': "Evan"
                    },
                    'submitted_on': format_iso8601(comment2.submit_date),
                    'pinned_on': None
                }, {
                    'id': comment1.pk,
                    'comment': "Foo",
                    'user': {
                        'id': self.user1.pk,
                        'name': "Evan"
                    },
                    'submitted_on': format_iso8601(comment1.submit_date),
                    'pinned_on': None
                }]
            })
Exemple #11
0
    def check_rate_limit(self, org):
        """Return the next run time if this task has run too recently."""
        now = timezone.now()
        last_run_time = self.cache_get(org, LAST_RUN_TIME)
        if last_run_time is not None:
            # Calculate when the task will be eligible to run again.
            last_run_time = parse_iso8601(last_run_time) if last_run_time else None
            failure_count = self.cache_get(org, FAILURE_COUNT, default=0)
            delta = settings.ORG_TASK_TIMEOUT * 2 ** failure_count
            next_run_time = last_run_time + min(delta, MAX_TIME_BETWEEN_RUNS)
            if now < next_run_time:
                # Task has been run too recently.
                raise ValueError(
                    "Skipping task because rate limit was exceeded. "
                    "Last run time was {}. "
                    "Task has failed {} times recently. "
                    "Task won't be run again before {}.".format(
                        last_run_time, failure_count, next_run_time))

        # Set the current time as the last run time.
        self.cache_set(org, LAST_RUN_TIME, value=format_iso8601(now), timeout=RUNS_TIMEOUT)
    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())},
        )