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 } ]})
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)
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)
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)
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))
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
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
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, }, ] }, )
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 }] })
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())}, )