Skip to content

Commit

Permalink
Add facebook invite active flags
Browse files Browse the repository at this point in the history
  • Loading branch information
erikh360 committed Jan 17, 2024
1 parent f30b55c commit 98142ff
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 12 deletions.
1 change: 1 addition & 0 deletions vaccine/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ class TState:
errormax: int = 0
banner: bool = False
contact_fields: dict = field(default_factory=dict)
globals: dict = field(default_factory=dict)


def unused_port():
Expand Down
53 changes: 50 additions & 3 deletions yal/surveys/facebook_invite.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
from vaccine.base_application import BaseApplication
from vaccine.states import Choice, EndState, WhatsAppButtonState
from yal import config
from yal import config, rapidpro
from yal.utils import get_generic_error


class Application(BaseApplication):
START_STATE = "state_facebook_member"
START_STATE = "state_check_study_active"
NOT_INTERESTED_STATE = "state_facebook_invite_decline"

async def state_check_study_active(self):
status = await rapidpro.get_global_value("facebook_survey_status")

if status == "inactive":
return await self.go_to_state("state_facebook_study_not_active")

return await self.go_to_state("state_facebook_member")

async def state_facebook_member(self):
async def _next(choice: Choice):
if choice.value == "no":
return "state_not_a_member"
return "state_was_a_member"
return "state_check_survey_active"

return WhatsAppButtonState(
self,
Expand All @@ -28,6 +36,14 @@ async def _next(choice: Choice):
error=self._(get_generic_error()),
)

async def state_check_survey_active(self):
status = await rapidpro.get_global_value("facebook_survey_status")

if status == "study_b_only":
return await self.go_to_state("state_facebook_study_not_active")

return await self.go_to_state("state_was_a_member")

async def state_was_a_member(self):
return EndState(
self,
Expand Down Expand Up @@ -115,3 +131,34 @@ async def state_facebook_invite_decline(self):
),
next=self.START_STATE,
)

async def state_facebook_study_not_active(self):
choices = [
Choice("menu", "Go to the menu"),
Choice("aaq", "Ask a question"),
]

question = self._(
"\n".join(
[
"Eish! It looks like you just missed the cut off for our survey. "
"No worries, we get it, life happens!",
"",
"Stay tuned for more survey opportunities. We appreciate your "
"enthusiasm and hope you can catch the next one.",
"",
"Go ahead and browse the menu or ask us a question.",
]
)
)

return WhatsAppButtonState(
self,
question=question,
choices=choices,
error=self._(get_generic_error()),
next={
"menu": "state_pre_mainmenu",
"aaq": "state_aaq_start",
},
)
19 changes: 11 additions & 8 deletions yal/tests/states_dictionary.md
Original file line number Diff line number Diff line change
Expand Up @@ -832,11 +832,14 @@


## Facebook Survey Invite
| state_name | accepts_user_input | data_type | added_to_flow_results_app | description |
| ----------------------------- | ------------------ | --------- | ------------------------- | ----------------------------------------------------------------|
| state_facebook_member | TRUE | Text | TRUE | Asks user if they've been a member of the bwise facebook group. |
| state_was_a_member | FALSE | | | Shows user the relavant survey link |
| state_not_a_member | TRUE | Text | TRUE | Asks user if they've seen a bwise post in their FB feed |
| state_fb_feed_seen | FALSE | | | Shows user the relavant survey link |
| state_fb_feed_not_seen | FALSE | | | Tells user they're not eligible |
| state_facebook_invite_decline | FALSE | | | Confirmation message |
| state_name | accepts_user_input | data_type | added_to_flow_results_app | description |
| ------------------------------- | ------------------ | --------- | ------------------------- | ----------------------------------------------------------------|
| state_facebook_member | TRUE | Text | TRUE | Asks user if they've been a member of the bwise facebook group. |
| state_was_a_member | FALSE | | | Shows user the relavant survey link |
| state_not_a_member | TRUE | Text | TRUE | Asks user if they've seen a bwise post in their FB feed |
| state_fb_feed_seen | FALSE | | | Shows user the relavant survey link |
| state_fb_feed_not_seen | FALSE | | | Tells user they're not eligible |
| state_facebook_invite_decline | FALSE | | | Confirmation message |
| state_check_study_active | FALSE | | | Checks if the study is still active |
| state_facebook_study_not_active | TRUE | Text | TRUE | Tells user study is not active, give main and aaq buttons |
| state_check_survey_active | FALSE | | | Checks if the specific survey is still active |
114 changes: 113 additions & 1 deletion yal/tests/surveys/test_facebook_invite.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
from unittest import mock

import pytest
from sanic import Sanic, response
Expand Down Expand Up @@ -40,6 +41,27 @@ def get_contact(request):
status=200,
)

@app.route("/api/v2/globals.json", methods=["GET"])
def get_global_value(request):
tstate.requests.append(request)
assert request.args.get("key") == "facebook_survey_status"

return response.json(
{
"next": None,
"previous": None,
"results": [
{
"key": "Facebook Survey Status",
"name": "facebook_survey_status",
"value": tstate.globals["facebook_survey_status"],
"modified_on": "2023-05-30T07:34:06.216776Z",
}
],
},
status=200,
)

async with run_sanic(app) as server:
url = config.RAPIDPRO_URL
config.RAPIDPRO_URL = f"http://{server.host}:{server.port}"
Expand All @@ -49,11 +71,36 @@ def get_contact(request):
config.RAPIDPRO_URL = url


@pytest.fixture
async def contentrepo_api_mock():
Sanic.test_mode = True
app = Sanic("contentrepo_api_mock")
tstate = TState()

@app.route("/api/v2/pages", methods=["GET"])
def get_main_menu(request):
tstate.requests.append(request)
return response.json(
{
"count": 0,
"results": [],
}
)

async with run_sanic(app) as server:
url = config.CONTENTREPO_API_URL
config.CONTENTREPO_API_URL = f"http://{server.host}:{server.port}"
server.tstate = tstate
yield server
config.CONTENTREPO_API_URL = url


@pytest.mark.asyncio
async def test_facebook_invite_yes(tester: AppTester, rapidpro_mock):
rapidpro_mock.tstate.contact_fields["onboarding_completed"] = True
rapidpro_mock.tstate.contact_fields["terms_accepted"] = True
rapidpro_mock.tstate.contact_fields["facebook_survey_invite_status"] = "sent"
rapidpro_mock.tstate.globals["facebook_survey_status"] = "active"

await tester.user_input("Yes, take part")
tester.assert_state("state_facebook_member")
Expand All @@ -72,6 +119,39 @@ async def test_facebook_invite_yes(tester: AppTester, rapidpro_mock):
}


@pytest.mark.asyncio
async def test_facebook_invite_yes_study_inactive(tester: AppTester, rapidpro_mock):
rapidpro_mock.tstate.contact_fields["onboarding_completed"] = True
rapidpro_mock.tstate.contact_fields["terms_accepted"] = True
rapidpro_mock.tstate.contact_fields["facebook_survey_invite_status"] = "sent"
rapidpro_mock.tstate.globals["facebook_survey_status"] = "inactive"

await tester.user_input("Yes, take part")
tester.assert_state("state_facebook_study_not_active")

tester.assert_message(
"\n".join(
[
"Eish! It looks like you just missed the cut off for our survey. "
"No worries, we get it, life happens!",
"",
"Stay tuned for more survey opportunities. We appreciate your "
"enthusiasm and hope you can catch the next one.",
"",
"Go ahead and browse the menu or ask us a question.",
]
)
)

request = rapidpro_mock.tstate.requests[1]

assert json.loads(request.body.decode("utf-8")) == {
"fields": {
"facebook_survey_invite_status": "responded_yes",
}
}


@pytest.mark.asyncio
async def test_facebook_invite_no(tester: AppTester, rapidpro_mock):
rapidpro_mock.tstate.contact_fields["onboarding_completed"] = True
Expand Down Expand Up @@ -124,8 +204,9 @@ async def test_facebook_invite_not_invited(tester: AppTester, rapidpro_mock):


@pytest.mark.asyncio
async def test_state_facebook_member_yes(tester: AppTester):
async def test_state_facebook_member_yes_active(tester: AppTester, rapidpro_mock):
tester.setup_state("state_facebook_member")
rapidpro_mock.tstate.globals["facebook_survey_status"] = "active"

await tester.user_input("Yes")

Expand All @@ -145,6 +226,15 @@ async def test_state_facebook_member_yes(tester: AppTester):
)
)

@pytest.mark.asyncio
async def test_state_facebook_member_yes_survey_b_only(tester: AppTester, rapidpro_mock):
tester.setup_state("state_facebook_member")
rapidpro_mock.tstate.globals["facebook_survey_status"] = "study_b_only"

await tester.user_input("Yes")

tester.assert_state("state_facebook_study_not_active")


@pytest.mark.asyncio
async def test_state_facebook_member_no(tester: AppTester):
Expand Down Expand Up @@ -201,3 +291,25 @@ async def test_state_not_a_member_no(tester: AppTester):
]
)
)


@pytest.mark.asyncio
async def test_state_facebook_study_not_active_menu(
tester: AppTester, contentrepo_api_mock
):
tester.setup_state("state_facebook_study_not_active")

await tester.user_input("Go to the menu")

tester.assert_state("state_mainmenu")


@pytest.mark.asyncio
@mock.patch("yal.askaquestion.config")
async def test_state_facebook_study_not_active_aaq(mock_config, tester: AppTester):
mock_config.AAQ_URL = "http://aaq-test.com"
tester.setup_state("state_facebook_study_not_active")

await tester.user_input("Ask a question")

tester.assert_state("state_aaq_start")

0 comments on commit 98142ff

Please sign in to comment.