Skip to content

Commit

Permalink
Add new poll results models
Browse files Browse the repository at this point in the history
  • Loading branch information
norkans7 committed Dec 2, 2021
1 parent c1237e9 commit 35a65b9
Show file tree
Hide file tree
Showing 6 changed files with 528 additions and 2 deletions.
4 changes: 2 additions & 2 deletions ureport/backend/tests/test_rapidpro.py
Original file line number Diff line number Diff line change
Expand Up @@ -1230,7 +1230,7 @@ def release_boundary(boundary):
]
)

with self.assertNumQueries(7):
with self.assertNumQueries(9):
boundaries_results = self.backend.pull_boundaries(self.nigeria)

self.assertEqual(
Expand Down Expand Up @@ -1276,7 +1276,7 @@ def release_boundary(boundary):
]
)

with self.assertNumQueries(13):
with self.assertNumQueries(17):
boundaries_results = self.backend.pull_boundaries(self.nigeria)

self.assertEqual(
Expand Down
61 changes: 61 additions & 0 deletions ureport/sql/stats_0028.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
-----------------------------------------------------------------------------
-- Insert missing PollContactResult's ContactEngagementActivity rows
-----------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION
ureport_insert_missing_contact_engagement_activities(_poll_contact_result stats_pollcontactresult)
RETURNS VOID AS $$
BEGIN
INSERT INTO stats_contactengagementactivity(contact, date, org_id) WITH month_days(missing_month) AS (
SELECT generate_series(date_trunc('month', _poll_contact_result.date)::timestamp,(date_trunc('month', _poll_contact_result.date)::timestamp+ interval '11 months')::date,interval '1 month')::date
), curr_activity AS (
SELECT * FROM stats_contactengagementactivity WHERE org_id = _poll_contact_result.org_id and contact = _poll_contact_result.contact
) SELECT _poll_contact_result.contact, missing_month::date, _poll_contact_result.org_id FROM month_days LEFT JOIN stats_contactengagementactivity ON stats_contactengagementactivity.date = month_days.missing_month AND stats_contactengagementactivity.contact = _poll_contact_result.contact AND org_id = _poll_contact_result.org_id
WHERE stats_contactengagementactivity.date IS NULL;
UPDATE stats_contactengagementactivity SET age_segment_id = _poll_contact_result.age_segment_id, gender_segment_id = _poll_contact_result.gender_segment_id, location_id = _poll_contact_result.location_id, scheme_segment_id = _poll_contact_result.scheme_segment_id, used = TRUE WHERE org_id = _poll_contact_result.org_id and contact = _poll_contact_result.contact and date > date_trunc('month', CURRENT_DATE) - INTERVAL '1 year';
END;
$$ LANGUAGE plpgsql;

-----------------------------------------------------------------------------
-- Generate ContactEngagementActivity rows for latest PollContactResult
-----------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION generate_contact_engagement_activities_for_latest_poll_contact_result(_poll_contact_result stats_pollcontactresult)
RETURNS VOID AS $$
BEGIN
-- Count only if we have an org and a flow and a flow_result
IF _poll_contact_result.org_id IS NOT NULL AND _poll_contact_result.flow IS NOT NULL AND _poll_contact_result.flow_result_id IS NOT NULL AND _poll_contact_result.flow_result_category_id IS NOT NULL THEN
PERFORM ureport_insert_missing_contact_engagement_activities(_poll_contact_result);
END IF;
END;
$$ LANGUAGE plpgsql;

-----------------------------------------------------------------------------
-- Updates our results counters
-----------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION ureport_update_contact_engagement_activities() RETURNS TRIGGER AS $$
BEGIN
-- PollContactResult row being created, increment counters for PollContactResult NEW
IF TG_OP = 'INSERT' THEN
PERFORM generate_contact_engagement_activities_for_latest_poll_contact_result(NEW);
ELSIF TG_OP = 'UPDATE' THEN
PERFORM generate_contact_engagement_activities_for_latest_poll_contact_result(NEW);
-- PollContactResult row is being deleted
ELSIF TG_OP = 'TRUNCATE' THEN
-- Clear all ContactEngagementActivity rows
TRUNCATE stats_contactengagementactivity;
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;


-- Install trigger for INSERT, UPDATE, AND DELETE on stats_pollcontactresult
DROP TRIGGER IF EXISTS ureport_when_poll_contact_result_contact_engagement_activities on stats_pollcontactresult;
CREATE TRIGGER ureport_when_poll_contact_result_contact_engagement_activities
AFTER INSERT OR DELETE OR UPDATE ON stats_pollcontactresult
FOR EACH ROW EXECUTE PROCEDURE ureport_update_contact_engagement_activities();

-- Install trigger for TRUNCATE on stats_pollcontactresult
DROP TRIGGER IF EXISTS ureport_when_poll_contact_results_truncate_then_update_contact_engagement_activities ON stats_pollcontactresult;
CREATE TRIGGER ureport_when_poll_contact_results_truncate_then_update_contact_engagement_activities
AFTER TRUNCATE ON stats_pollcontactresult
EXECUTE PROCEDURE ureport_update_contact_engagement_activities();
173 changes: 173 additions & 0 deletions ureport/stats/migrations/0027_auto_20211202_1422.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Generated by Django 3.2.8 on 2021-12-02 14:22

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("orgs", "0029_auto_20211025_1504"),
("flows", "0001_initial"),
("locations", "0006_boundary_backend"),
("stats", "0026_populate_flow_result_word_clouds"),
]

operations = [
migrations.CreateModel(
name="PollContactResult",
fields=[
("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("contact", models.CharField(max_length=36)),
("flow", models.CharField(max_length=36)),
("text", models.TextField(null=True)),
("date", models.DateTimeField(null=True)),
(
"age_segment",
models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to="stats.agesegment"),
),
(
"flow_result",
models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to="flows.flowresult"),
),
(
"flow_result_category",
models.ForeignKey(
null=True, on_delete=django.db.models.deletion.SET_NULL, to="flows.flowresultcategory"
),
),
(
"gender_segment",
models.ForeignKey(
null=True, on_delete=django.db.models.deletion.SET_NULL, to="stats.gendersegment"
),
),
(
"location",
models.ForeignKey(
null=True, on_delete=django.db.models.deletion.SET_NULL, to="locations.boundary"
),
),
(
"org",
models.ForeignKey(
db_index=False,
on_delete=django.db.models.deletion.PROTECT,
related_name="poll_contact_results",
to="orgs.org",
),
),
(
"scheme_segment",
models.ForeignKey(
null=True, on_delete=django.db.models.deletion.SET_NULL, to="stats.schemesegment"
),
),
],
),
migrations.CreateModel(
name="ContactEngagementActivity",
fields=[
("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("contact", models.CharField(max_length=36)),
("date", models.DateField(help_text="The starting date for for the month")),
("used", models.BooleanField(null=True)),
(
"age_segment",
models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to="stats.agesegment"),
),
(
"gender_segment",
models.ForeignKey(
null=True, on_delete=django.db.models.deletion.SET_NULL, to="stats.gendersegment"
),
),
(
"location",
models.ForeignKey(
null=True, on_delete=django.db.models.deletion.SET_NULL, to="locations.boundary"
),
),
(
"org",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="contact_engagement_activities",
to="orgs.org",
),
),
(
"scheme_segment",
models.ForeignKey(
null=True, on_delete=django.db.models.deletion.SET_NULL, to="stats.schemesegment"
),
),
],
),
migrations.AddIndex(
model_name="pollcontactresult",
index=models.Index(fields=["contact"], name="stats_pcr_contact"),
),
migrations.AddIndex(
model_name="pollcontactresult",
index=models.Index(fields=["org", "flow", "contact"], name="stats_pcr_org_flow_contact"),
),
migrations.AddIndex(
model_name="pollcontactresult",
index=models.Index(fields=["org", "flow"], name="stats_pcr_org_flow"),
),
migrations.AddIndex(
model_name="pollcontactresult",
index=models.Index(fields=["org", "flow", "flow_result", "text"], name="stats_pcr_org_flow_result_text"),
),
migrations.AddIndex(
model_name="contactengagementactivity",
index=models.Index(fields=["org", "contact"], name="stats_cea_org_contact"),
),
migrations.AddIndex(
model_name="contactengagementactivity",
index=models.Index(fields=["org", "date"], name="stats_cea_org_date"),
),
migrations.AddIndex(
model_name="contactengagementactivity",
index=models.Index(
condition=models.Q(("used", True)), fields=["org", "date", "used"], name="stats_cea_org_date_used"
),
),
migrations.AddIndex(
model_name="contactengagementactivity",
index=models.Index(
condition=models.Q(("location__isnull", False), ("used", True)),
fields=["org", "date", "location", "used"],
name="stats_cea_org_date_state_used",
),
),
migrations.AddIndex(
model_name="contactengagementactivity",
index=models.Index(
condition=models.Q(("age_segment__isnull", False), ("used", True)),
fields=["org", "date", "age_segment", "used"],
name="stats_cea_org_date_age_used",
),
),
migrations.AddIndex(
model_name="contactengagementactivity",
index=models.Index(
condition=models.Q(("scheme_segment__isnull", False), ("used", True)),
fields=["org", "date", "scheme_segment", "used"],
name="stats_cea_org_date_scheme_used",
),
),
migrations.AddIndex(
model_name="contactengagementactivity",
index=models.Index(
condition=models.Q(("gender_segment__isnull", False), ("used", True)),
fields=["org", "date", "gender_segment", "used"],
name="stats_cea_org_date_gender_used",
),
),
migrations.AlterUniqueTogether(
name="contactengagementactivity",
unique_together={("org", "contact", "date")},
),
]
14 changes: 14 additions & 0 deletions ureport/stats/migrations/0028_install_cea_triggers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Generated by Django 3.2.8 on 2021-12-02 14:23

from django.db import migrations

from ureport.sql import InstallSQL


class Migration(migrations.Migration):

dependencies = [
("stats", "0027_auto_20211202_1422"),
]

operations = [InstallSQL("stats_0028")]
80 changes: 80 additions & 0 deletions ureport/stats/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,86 @@ def calculate_average_response_rate(cls, org):
return percentage


class PollContactResult(models.Model):
org = models.ForeignKey(Org, on_delete=models.PROTECT, related_name="poll_contact_results", db_index=False)

contact = models.CharField(max_length=36)

flow = models.CharField(max_length=36)

flow_result = models.ForeignKey(FlowResult, null=True, on_delete=models.SET_NULL)

flow_result_category = models.ForeignKey(FlowResultCategory, null=True, on_delete=models.SET_NULL)

text = models.TextField(null=True)

age_segment = models.ForeignKey(AgeSegment, null=True, on_delete=models.SET_NULL)

gender_segment = models.ForeignKey(GenderSegment, null=True, on_delete=models.SET_NULL)

scheme_segment = models.ForeignKey(SchemeSegment, null=True, on_delete=models.SET_NULL)

location = models.ForeignKey(Boundary, null=True, on_delete=models.SET_NULL)

date = models.DateTimeField(null=True)

class Meta:
indexes = [
models.Index(name="%(app_label)s_pcr_contact", fields=["contact"]),
models.Index(name="%(app_label)s_pcr_org_flow_contact", fields=["org", "flow", "contact"]),
models.Index(name="%(app_label)s_pcr_org_flow", fields=["org", "flow"]),
models.Index(name="%(app_label)s_pcr_org_flow_result_text", fields=["org", "flow", "flow_result", "text"]),
]


class ContactEngagementActivity(models.Model):
org = models.ForeignKey(Org, on_delete=models.PROTECT, related_name="contact_engagement_activities")

contact = models.CharField(max_length=36)

age_segment = models.ForeignKey(AgeSegment, null=True, on_delete=models.SET_NULL)

gender_segment = models.ForeignKey(GenderSegment, null=True, on_delete=models.SET_NULL)

scheme_segment = models.ForeignKey(SchemeSegment, null=True, on_delete=models.SET_NULL)

location = models.ForeignKey(Boundary, null=True, on_delete=models.SET_NULL)

date = models.DateField(help_text="The starting date for for the month")

used = models.BooleanField(null=True)

class Meta:
indexes = [
models.Index(name="%(app_label)s_cea_org_contact", fields=["org", "contact"]),
models.Index(name="%(app_label)s_cea_org_date", fields=["org", "date"]),
models.Index(
name="%(app_label)s_cea_org_date_used", fields=["org", "date", "used"], condition=Q(used=True)
),
models.Index(
name="%(app_label)s_cea_org_date_state_used",
fields=["org", "date", "location", "used"],
condition=Q(location__isnull=False) & Q(used=True),
),
models.Index(
name="%(app_label)s_cea_org_date_age_used",
fields=["org", "date", "age_segment", "used"],
condition=Q(age_segment__isnull=False) & Q(used=True),
),
models.Index(
name="%(app_label)s_cea_org_date_scheme_used",
fields=["org", "date", "scheme_segment", "used"],
condition=Q(scheme_segment__isnull=False) & Q(used=True),
),
models.Index(
name="%(app_label)s_cea_org_date_gender_used",
fields=["org", "date", "gender_segment", "used"],
condition=Q(gender_segment__isnull=False) & Q(used=True),
),
]
unique_together = ("org", "contact", "date")


class ContactActivity(models.Model):
org = models.ForeignKey(Org, on_delete=models.PROTECT, related_name="contact_activities")

Expand Down
Loading

0 comments on commit 35a65b9

Please sign in to comment.