From 4e1582d5a7702d77fed643d2f21e85f6e712b5ee Mon Sep 17 00:00:00 2001 From: Erik Harding Date: Mon, 6 May 2024 16:01:00 +0200 Subject: [PATCH] Add all yal things --- config/settings/base.py | 1 + config/urls.py | 1 + rp_yal/__init__.py | 0 rp_yal/apps.py | 6 + rp_yal/serializers.py | 5 + rp_yal/tests/__init__.py | 0 rp_yal/tests/test_utils.py | 430 ++++++++++++++++++ rp_yal/tests/test_views.py | 54 +++ rp_yal/urls.py | 11 + rp_yal/utils.py | 187 ++++++++ rp_yal/views.py | 38 ++ ...organization_contentrepo_token_and_more.py | 23 + sidekick/models.py | 2 + sidekick/tests/utils.py | 2 + 14 files changed, 760 insertions(+) create mode 100644 rp_yal/__init__.py create mode 100644 rp_yal/apps.py create mode 100644 rp_yal/serializers.py create mode 100644 rp_yal/tests/__init__.py create mode 100644 rp_yal/tests/test_utils.py create mode 100644 rp_yal/tests/test_views.py create mode 100644 rp_yal/urls.py create mode 100644 rp_yal/utils.py create mode 100644 rp_yal/views.py create mode 100644 sidekick/migrations/0014_organization_contentrepo_token_and_more.py diff --git a/config/settings/base.py b/config/settings/base.py index 01c4628..c81eff7 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -45,6 +45,7 @@ "rp_transferto", "rp_recruit", "rp_interceptors", + "rp_yal", "randomisation", ] diff --git a/config/urls.py b/config/urls.py index 7a2125d..81dac58 100644 --- a/config/urls.py +++ b/config/urls.py @@ -9,4 +9,5 @@ path("interceptor/", include("rp_interceptors.urls")), path("dtone/", include("rp_dtone.urls")), path("randomisation/", include("randomisation.urls")), + path("yal/", include("rp_yal.urls"), name="rp_yal"), ] diff --git a/rp_yal/__init__.py b/rp_yal/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rp_yal/apps.py b/rp_yal/apps.py new file mode 100644 index 0000000..9a7eacd --- /dev/null +++ b/rp_yal/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class RpYalConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "rp_yal" diff --git a/rp_yal/serializers.py b/rp_yal/serializers.py new file mode 100644 index 0000000..c018616 --- /dev/null +++ b/rp_yal/serializers.py @@ -0,0 +1,5 @@ +from rest_framework import serializers + + +class GetOrderedContentSetSerializer(serializers.Serializer): + fields = serializers.DictField() diff --git a/rp_yal/tests/__init__.py b/rp_yal/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rp_yal/tests/test_utils.py b/rp_yal/tests/test_utils.py new file mode 100644 index 0000000..62469ba --- /dev/null +++ b/rp_yal/tests/test_utils.py @@ -0,0 +1,430 @@ +from unittest.mock import patch + +import responses +from django.test import TestCase +from freezegun import freeze_time + +from rp_yal import utils +from sidekick.tests.utils import create_org + +TEST_CONTENT_SETS = [ + { + "id": 1, + "name": "Connectedness Mandatory Female relationship", + "field_count": 2, + "gender": "female", + "relationship": "in_a_relationship", + }, + { + "id": 2, + "name": "Connectedness Mandatory relationship", + "field_count": 1, + "relationship": "in_a_relationship", + }, + { + "id": 3, + "name": "Connectedness Mandatory ", + "field_count": 0, + }, +] + + +class TestGetOrderedContentSet(TestCase): + def setUp(self): + self.org = create_org() + + @freeze_time("2024-05-05 01:30:00") + @patch("rp_yal.utils.search_ordered_content_sets") + def test_get_ordered_content_set_weekend(self, mock_search_ocs): + """ + On the weekend it shouldn't attempt anything + """ + contentset_id = utils.get_ordered_content_set(self.org, {}) + + self.assertIsNone(contentset_id) + mock_search_ocs.assert_not_called() + + @freeze_time("2024-05-06 01:30:00") + @patch("rp_yal.utils.search_ordered_content_sets") + @patch("rp_yal.utils.get_first_matching_content_set") + def test_get_ordered_content_set_monday(self, mock_first_mcs, mock_search_ocs): + """ + On a Monday if a contact has no fields set the it will search for low lit sets + and return the first one that matches profile. + """ + mock_search_ocs.return_value = TEST_CONTENT_SETS + mock_first_mcs.return_value = 1 + + fields = { + "gender": "male", + "relationship_status": "yes", + } + contentset_id = utils.get_ordered_content_set(self.org, fields) + + self.assertEqual(contentset_id, 1) + mock_search_ocs.assert_called_with(self.org, "low lit") + mock_first_mcs.assert_called_with(TEST_CONTENT_SETS, fields) + + @freeze_time("2024-05-06 01:30:00") + @patch("rp_yal.utils.search_ordered_content_sets") + @patch("rp_yal.utils.get_first_matching_content_set") + @patch("rp_yal.utils.get_content_search_term") + def test_get_ordered_content_set_monday_ed_completed( + self, mock_get_search_term, mock_first_mcs, mock_search_ocs + ): + """ + On a Monday, if a contact has finished the education content, it will search + for the depression content set and return the first one that matches profile + """ + mock_search_ocs.return_value = TEST_CONTENT_SETS + mock_first_mcs.return_value = 1 + mock_get_search_term.return_value = "depression" + + fields = { + "gender": "male", + "relationship_status": "yes", + "educational_content_completed": "true", + } + contentset_id = utils.get_ordered_content_set(self.org, fields) + + self.assertEqual(contentset_id, 1) + mock_search_ocs.assert_called_with(self.org, "depression") + mock_first_mcs.assert_called_with(TEST_CONTENT_SETS, fields) + mock_get_search_term.assert_called_with(fields) + + @freeze_time("2024-05-06 01:30:00") + @patch("rp_yal.utils.search_ordered_content_sets") + @patch("rp_yal.utils.get_first_matching_content_set") + @patch("rp_yal.utils.get_content_search_term") + def test_get_ordered_content_set_monday_sex_lit_low( + self, mock_get_search_term, mock_first_mcs, mock_search_ocs + ): + """ + On a Monday, if the contact finished education content and sexual health + literacy is low, it will search for fun content sets and return the first one + that matches the profile + """ + mock_search_ocs.return_value = TEST_CONTENT_SETS + mock_first_mcs.return_value = 1 + + fields = { + "gender": "male", + "relationship_status": "yes", + "educational_content_completed": "true", + "sexual_health_lit_risk": "low", + } + contentset_id = utils.get_ordered_content_set(self.org, fields) + + self.assertEqual(contentset_id, 1) + mock_search_ocs.assert_called_with(self.org, "fun") + mock_first_mcs.assert_called_with(TEST_CONTENT_SETS, fields) + mock_get_search_term.assert_not_called() + + @freeze_time("2024-05-06 01:30:00") + @patch("rp_yal.utils.search_ordered_content_sets") + @patch("rp_yal.utils.get_first_matching_content_set") + @patch("rp_yal.utils.get_content_search_term") + def test_get_ordered_content_set_monday_sex_lit_low_fun_completed( + self, mock_get_search_term, mock_first_mcs, mock_search_ocs + ): + """ + On a Monday, if the contact finished education content and sexual health + literacy is low and fun content is completed, it will search for depression + content sets and return the first one that matches the profile + """ + mock_search_ocs.return_value = TEST_CONTENT_SETS + mock_first_mcs.return_value = 1 + mock_get_search_term.return_value = "depression" + + fields = { + "gender": "male", + "relationship_status": "yes", + "educational_content_completed": "true", + "sexual_health_lit_risk": "low", + "fun_content_completed": "true", + } + contentset_id = utils.get_ordered_content_set(self.org, fields) + + self.assertEqual(contentset_id, 1) + mock_search_ocs.assert_called_with(self.org, "depression") + mock_first_mcs.assert_called_with(TEST_CONTENT_SETS, fields) + mock_get_search_term.assert_called_with(fields) + + @freeze_time("2024-05-07 01:30:00") + @patch("rp_yal.utils.search_ordered_content_sets") + @patch("rp_yal.utils.get_first_matching_content_set") + def test_get_ordered_content_set_tuesday(self, mock_first_mcs, mock_search_ocs): + """ + On a tuesday to friday if a contact with no other fields set and hasn't + completed the push message intro set, it will return the high risk intro + """ + mock_search_ocs.return_value = TEST_CONTENT_SETS + mock_first_mcs.return_value = 1 + + fields = { + "gender": "male", + "relationship_status": "yes", + } + contentset_id = utils.get_ordered_content_set(self.org, fields) + + self.assertEqual(contentset_id, 1) + mock_search_ocs.assert_called_with(self.org, "intro high-risk") + mock_first_mcs.assert_called_with(TEST_CONTENT_SETS, fields) + + @freeze_time("2024-05-07 01:30:00") + @patch("rp_yal.utils.search_ordered_content_sets") + @patch("rp_yal.utils.get_first_matching_content_set") + def test_get_ordered_content_set_tuesday_low_risk( + self, mock_first_mcs, mock_search_ocs + ): + """ + On a tuesday to friday if a contact depression_and_anxiety_risk is low and + hasn't completed the push message intro set, it will return the low risk intro + """ + mock_search_ocs.return_value = TEST_CONTENT_SETS + mock_first_mcs.return_value = 1 + + fields = { + "gender": "male", + "relationship_status": "yes", + "depression_and_anxiety_risk": "low_risk", + } + contentset_id = utils.get_ordered_content_set(self.org, fields) + + self.assertEqual(contentset_id, 1) + mock_search_ocs.assert_called_with(self.org, "intro low-risk") + mock_first_mcs.assert_called_with(TEST_CONTENT_SETS, fields) + + @freeze_time("2024-05-07 01:30:00") + @patch("rp_yal.utils.search_ordered_content_sets") + @patch("rp_yal.utils.get_first_matching_content_set") + @patch("rp_yal.utils.get_content_search_term") + def test_get_ordered_content_set_tuesday_intro_completed( + self, mock_get_search_term, mock_first_mcs, mock_search_ocs + ): + """ + On a tuesday to friday if a contact has completed the push messages intro, it + will search for depression content sets and return the first one that matches + the profile + """ + mock_search_ocs.return_value = TEST_CONTENT_SETS + mock_first_mcs.return_value = 1 + mock_get_search_term.return_value = "depression" + + fields = { + "gender": "male", + "relationship_status": "yes", + "push_message_intro_completed": "true", + } + contentset_id = utils.get_ordered_content_set(self.org, fields) + + self.assertEqual(contentset_id, 1) + mock_search_ocs.assert_called_with(self.org, "depression") + mock_first_mcs.assert_called_with(TEST_CONTENT_SETS, fields) + + +class GetRelationshipStatusTestCase(TestCase): + def test_get_relationship_status_empty(self): + status = utils.get_relationship_status("") + self.assertEqual(status, "single") + + def test_get_relationship_status_relationship(self): + status = utils.get_relationship_status("relationship") + self.assertEqual(status, "in_a_relationship") + + def test_get_relationship_status_yes(self): + status = utils.get_relationship_status("yes") + self.assertEqual(status, "in_a_relationship") + + def test_get_relationship_status_single(self): + status = utils.get_relationship_status("single") + self.assertEqual(status, "single") + + def test_get_relationship_status_no(self): + status = utils.get_relationship_status("no") + self.assertEqual(status, "single") + + def test_get_relationship_status_complicated(self): + status = utils.get_relationship_status("complicated") + self.assertEqual(status, "single") + + +class GetGenderTestCase(TestCase): + def test_get_gender_empty(self): + status = utils.get_gender("") + self.assertEqual(status, "empty") + + def test_get_gender(self): + status = utils.get_gender("Non_Binary") + self.assertEqual(status, "non-binary") + + +class GetContentSearchTerm(TestCase): + def test_get_content_search_term_low_risk(self): + """ + If the depression and anxiety risk is low then return first item in list with + mandatory + """ + fields = {"depression_and_anxiety_risk": "low_risk"} + search_term = utils.get_content_search_term(fields) + self.assertEqual(search_term, "depression mandatory") + + def test_get_content_search_term_high_risk(self): + """ + If the depression and anxiety risk is high then return first item in list with + high-risk + """ + fields = {"depression_and_anxiety_risk": "high_risk"} + search_term = utils.get_content_search_term(fields) + self.assertEqual(search_term, "depression high-risk") + + def test_get_content_search_term_high_risk_depression_completed(self): + """ + If depression content is complete return the next one in the high risk flow, + connectedness + """ + fields = { + "depression_and_anxiety_risk": "high_risk", + "depression_content_complete": "true", + } + search_term = utils.get_content_search_term(fields) + self.assertEqual(search_term, "connectedness high-risk") + + def test_get_content_search_term_high_risk_half_completed(self): + """ + Loop through flow until we find one that isn't completed + """ + fields = { + "depression_and_anxiety_risk": "high_risk", + "depression_content_complete": "true", + "connectedness_content_complete": "true", + } + search_term = utils.get_content_search_term(fields) + self.assertEqual(search_term, "body image high-risk") + + def test_get_content_search_term_high_risk_all_completed(self): + """ + If all contentsets are completed return empty string + """ + fields = { + "depression_and_anxiety_risk": "high_risk", + "depression_content_complete": "true", + "connectedness_content_complete": "true", + "body_image_content_complete": "true", + "selfperceived_healthcare_complete": "true", + "gender_attitude_content_complete": "true", + } + search_term = utils.get_content_search_term(fields) + self.assertEqual(search_term, "") + + def test_get_content_search_term_high_risk_with_last_topic(self): + """ + If last topic is set we start looping from there + """ + fields = {"last_topic_sent": "connectedness"} + search_term = utils.get_content_search_term(fields) + self.assertEqual(search_term, "body image high-risk") + + +class SearchOrderedContentSetsTestcase(TestCase): + def setUp(self): + self.org = create_org() + + @responses.activate + def test_search_ordered_content_sets(self): + responses.add( + method=responses.GET, + url="http://contentrepo/api/v2/orderedcontent/", + json={ + "count": 2, + "next": True, + "previous": None, + "results": [ + { + "id": 154, + "name": "Connectedness Mandatory Female Single", + "profile_fields": [ + {"profile_field": "gender", "value": "female"}, + {"profile_field": "relationship", "value": "single"}, + ], + }, + { + "id": 159, + "name": "Connectedness Mandatory Male Single", + "profile_fields": [ + {"profile_field": "gender", "value": "male"}, + {"profile_field": "relationship", "value": "single"}, + ], + }, + ], + }, + status=200, + match=[ + responses.matchers.query_param_matcher( + {"search": "Connectedness Mandatory"} + ) + ], + ) + + responses.add( + method=responses.GET, + url="http://contentrepo/api/v2/orderedcontent/", + json={ + "count": 2, + "next": None, + "previous": None, + "results": [ + { + "id": 164, + "name": "Connectedness Mandatory Female Single", + "profile_fields": [ + {"profile_field": "gender", "value": "female"}, + {"profile_field": "relationship", "value": "single"}, + ], + }, + { + "id": 169, + "name": "Connectedness Mandatory Male Single", + "profile_fields": [ + {"profile_field": "gender", "value": "male"}, + {"profile_field": "relationship", "value": "single"}, + ], + }, + ], + }, + status=200, + match=[ + responses.matchers.query_param_matcher( + {"search": "Connectedness Mandatory", "page": 2} + ) + ], + ) + + contentsets = utils.search_ordered_content_sets( + self.org, "Connectedness Mandatory" + ) + + self.assertEqual(len(contentsets), 4) + self.assertEqual(contentsets[0]["field_count"], 2) + self.assertEqual(contentsets[0]["gender"], "female") + self.assertEqual(contentsets[0]["relationship"], "single") + + +class GetFirstMatchingContentSet(TestCase): + def test_get_first_matching_content_set_two_matches(self): + fields = {"gender": "female", "relationship_status": "relationship"} + contentset_id = utils.get_first_matching_content_set(TEST_CONTENT_SETS, fields) + + self.assertEqual(contentset_id, 1) + + def test_get_first_matching_content_set_one_match(self): + fields = {"relationship_status": "relationship"} + contentset_id = utils.get_first_matching_content_set(TEST_CONTENT_SETS, fields) + + self.assertEqual(contentset_id, 2) + + def test_get_first_matching_content_set_no_matches(self): + fields = {"relationship_status": "single"} + contentset_id = utils.get_first_matching_content_set(TEST_CONTENT_SETS, fields) + + self.assertEqual(contentset_id, 3) diff --git a/rp_yal/tests/test_views.py b/rp_yal/tests/test_views.py new file mode 100644 index 0000000..358ede5 --- /dev/null +++ b/rp_yal/tests/test_views.py @@ -0,0 +1,54 @@ +from unittest.mock import patch + +from django.contrib.auth.models import User +from django.urls import reverse +from rest_framework import status +from rest_framework.authtoken.models import Token +from rest_framework.test import APIClient, APITestCase + +from sidekick.tests.utils import create_org + + +class TestYalViews(APITestCase): + def setUp(self): + self.api_client = APIClient() + + self.user = User.objects.create_user( + "username", "testuser@example.com", "password" + ) + token = Token.objects.get(user=self.user) + self.token = token.key + + self.api_client.credentials(HTTP_AUTHORIZATION="Token " + self.token) + + self.org = create_org() + self.org.users.add(self.user) + + def test_get_ordered_contentset_validation(self): + response = self.api_client.post( + reverse( + "get_ordered_contentset", + kwargs={"org_id": self.org.id}, + ) + ) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.json(), {"fields": ["This field is required."]}) + + @patch("rp_yal.views.get_ordered_content_set") + def test_get_ordered_contentset(self, mock_get_ocs): + mock_get_ocs.return_value = 111 + + response = self.api_client.post( + reverse( + "get_ordered_contentset", + kwargs={"org_id": self.org.id}, + ), + data={"fields": {"last_topic_sent": "Connectedness"}}, + format="json", + ) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.json(), {"ordered_set_id": 111}) + + mock_get_ocs.assert_called_with(self.org, {"last_topic_sent": "Connectedness"}) diff --git a/rp_yal/urls.py b/rp_yal/urls.py new file mode 100644 index 0000000..0889aa7 --- /dev/null +++ b/rp_yal/urls.py @@ -0,0 +1,11 @@ +from django.urls import path + +from . import views + +urlpatterns = [ + path( + "/get_ordered_contentset/", + views.GetOrderedContentSet.as_view(), + name="get_ordered_contentset", + ), +] diff --git a/rp_yal/utils.py b/rp_yal/utils.py new file mode 100644 index 0000000..663d19f --- /dev/null +++ b/rp_yal/utils.py @@ -0,0 +1,187 @@ +from datetime import datetime +from urllib.parse import urljoin + +import requests + + +def get_ordered_content_set(org, fields): + search_term = None + + weekday = datetime.today().weekday() + + if weekday == 0: + # Monday + if "low" in fields.get("sexual_health_lit_risk", "").lower(): + if fields.get("fun_content_completed", "").lower() == "true": + search_term = get_content_search_term(fields) + else: + search_term = "fun" + else: + if fields.get("educational_content_completed", "").lower() == "true": + search_term = get_content_search_term(fields) + else: + search_term = "low lit" + elif weekday <= 4: + # Tuesday to Friday + if fields.get("push_message_intro_completed", "").lower() == "true": + search_term = get_content_search_term(fields) + else: + if fields.get("depression_and_anxiety_risk", "").lower() == "low_risk": + search_term = "intro low-risk" + else: + search_term = "intro high-risk" + + if search_term: + contentsets = search_ordered_content_sets(org, search_term) + return get_first_matching_content_set(contentsets, fields) + + return None + + +def get_relationship_status(rp_rel_status): + if rp_rel_status and rp_rel_status.lower() in ("relationship", "yes"): + return "in_a_relationship" + + return "single" + + +def get_gender(rp_gender): + if not rp_gender: + return "empty" + + return rp_gender.replace("_", "-").lower() + + +def get_content_search_term(fields): + last_topic_sent = fields.get("last_topic_sent", "").lower() + + if fields.get("depression_and_anxiety_risk", "").lower() == "low_risk": + flow = { + "depression": { + "complete": "depression_content_complete", + "next": "gender attitudes", + "risk": "depression_and_anxiety_risk", + }, + "gender attitudes": { + "complete": "gender_attitude_content_complete", + "next": "self perceived healthcare", + "risk": "gender_attitude_risk", + }, + "self perceived healthcare": { + "complete": "selfperceived_healthcare_complete", + "next": "body image", + "risk": "selfperceived_healthcare_risk", + }, + "body image": { + "complete": "body_image_content_complete", + "next": "connectedness", + "risk": "body_image_risk", + }, + "connectedness": { + "complete": "connectedness_content_complete", + "next": "", + "risk": "connectedness_risk", + }, + } + else: + flow = { + "depression": { + "complete": "depression_content_complete", + "next": "connectedness", + "risk": "depression_and_anxiety_risk", + }, + "connectedness": { + "complete": "connectedness_content_complete", + "next": "body image", + "risk": "connectedness_risk", + }, + "body image": { + "complete": "body_image_content_complete", + "next": "self perceived healthcare", + "risk": "body_image_risk", + }, + "self perceived healthcare": { + "complete": "selfperceived_healthcare_complete", + "next": "gender attitudes", + "risk": "selfperceived_healthcare_risk", + }, + "gender attitudes": { + "complete": "gender_attitude_content_complete", + "next": "", + "risk": "gender_attitude_risk", + }, + } + + def get_next_topic_and_risk(last): + if not last: + next = "depression" + else: + next = flow[last]["next"] + + if not next: + return "" + + if fields.get(flow[next]["complete"], "").lower() == "true": + return get_next_topic_and_risk(next) + else: + risk_label = "high-risk" + if "low" in fields.get(flow[next]["risk"], "").lower(): + risk_label = "mandatory" + return f"{next} {risk_label}" + + return get_next_topic_and_risk(last_topic_sent) + + +def search_ordered_content_sets(org, search_term): + page = 1 + next = True + + headers = { + "Content-Type": "application/json", + "Authorization": "Token {}".format(org.contentrepo_token), + } + params = {"search": search_term} + + contentsets = [] + while next: + if page > 1: + params["page"] = page + + response = requests.get( + urljoin(org.contentrepo_url, "api/v2/orderedcontent/"), + headers=headers, + params=params, + ) + response.raise_for_status() + + response_data = response.json() + + for contentset in response_data["results"]: + contentset["field_count"] = len(contentset["profile_fields"]) + for field in contentset["profile_fields"]: + contentset[field["profile_field"]] = field["value"] + contentsets.append(contentset) + + next = response_data["next"] + page += 1 + + return contentsets + + +def get_first_matching_content_set(contentsets, fields): + relationship_status = get_relationship_status(fields.get("relationship_status", "")) + gender = get_gender(fields.get("gender", "")) + + for contentset in sorted(contentsets, key=lambda d: d["field_count"], reverse=True): + if contentset["field_count"] == 2: + if ( + contentset["gender"] == gender + and contentset["relationship"] == relationship_status + ): + return contentset["id"] + if contentset["field_count"] == 1: + + if contentset["relationship"] == relationship_status: + return contentset["id"] + if contentset["field_count"] == 0: + return contentset["id"] diff --git a/rp_yal/views.py b/rp_yal/views.py new file mode 100644 index 0000000..25e864a --- /dev/null +++ b/rp_yal/views.py @@ -0,0 +1,38 @@ +from django.http import JsonResponse +from rest_framework import status +from rest_framework.views import APIView + +from sidekick.models import Organization + +from .serializers import GetOrderedContentSetSerializer +from .utils import get_ordered_content_set + + +class GetOrderedContentSet(APIView): + + def post(self, request, org_id): + serializer = GetOrderedContentSetSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + + try: + org = Organization.objects.get(id=org_id) + except Organization.DoesNotExist: + return JsonResponse( + {"error": "Organization not found"}, status=status.HTTP_400_BAD_REQUEST + ) + + if not org.users.filter(id=request.user.id).exists(): + return JsonResponse( + data={ + "error": "Authenticated user does not belong to specified Organization" + }, + status=status.HTTP_401_UNAUTHORIZED, + ) + + ordered_set_id = get_ordered_content_set( + org, serializer.validated_data["fields"] + ) + + return JsonResponse( + {"ordered_set_id": ordered_set_id}, status=status.HTTP_200_OK + ) diff --git a/sidekick/migrations/0014_organization_contentrepo_token_and_more.py b/sidekick/migrations/0014_organization_contentrepo_token_and_more.py new file mode 100644 index 0000000..a73c2e0 --- /dev/null +++ b/sidekick/migrations/0014_organization_contentrepo_token_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.11 on 2024-05-06 11:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("sidekick", "0013_groupmonitor"), + ] + + operations = [ + migrations.AddField( + model_name="organization", + name="contentrepo_token", + field=models.CharField(max_length=200, null=True), + ), + migrations.AddField( + model_name="organization", + name="contentrepo_url", + field=models.URLField(null=True), + ), + ] diff --git a/sidekick/models.py b/sidekick/models.py index 4fc51eb..085c2e9 100644 --- a/sidekick/models.py +++ b/sidekick/models.py @@ -22,6 +22,8 @@ class Organization(models.Model): engage_token = models.CharField(max_length=1000, null=True) point_of_contact = models.EmailField(null=True) filter_rapidpro_fields = models.CharField(max_length=4000, null=True, blank=True) + contentrepo_url = models.URLField(max_length=200, null=True) + contentrepo_token = models.CharField(max_length=200, null=True) def __str__(self): return self.name diff --git a/sidekick/tests/utils.py b/sidekick/tests/utils.py index b9f6439..950d615 100644 --- a/sidekick/tests/utils.py +++ b/sidekick/tests/utils.py @@ -8,6 +8,8 @@ def create_org(**kwargs): "token": "REPLACEME", "engage_url": "http://whatsapp/", "engage_token": "test-token", + "contentrepo_url": "http://contentrepo", + "contentrepo_token": "test-token", } data.update(kwargs) return Organization.objects.create(**data)