AssertionError: 302 != 200 : Couldn't retrieve redirection page '/api/v2/app/nextdialog': response code was 302 (expected 200)
In Django is it possible to have three views where each one redirects to the next. View 1 redirects to view 2 and view 2 redirects to view 3?
Views.py:
class ConversationLayerView(generics.GenericAPIView):
permission_classes = (permissions.IsAuthenticated,)
def post(self, request, *args, **kwargs):
body = request.data
cardType = body["cardType"]
if cardType == "CHOICE":
serializer = appChoiceTypeSerializer(body)
elif cardType == "TEXT":
serializer = appTextTypeSerializer(body)
elif cardType == "INPUT":
serializer = appInputTypeSerializer(body)
else:
serializer = StartAssessmentSerializer(body)
validated_body = serializer.validate_value(body)
url = get_endpoint(validated_body)
reverse_url = encodeurl(body, url)
return HttpResponseRedirect(reverse_url)
class NextDialog(generics.GenericAPIView):
permission_classes = (permissions.AllowAny,)
def get(self, request, *args, **kwargs):
result = request.GET
data = result.dict()
contact_uuid = data["contact_uuid"]
step = data["step"]
value = data["value"]
description = data["description"]
title = data["title"]
if data["cardType"] == "CHOICE":
optionId = int(value) - 1
else:
optionId = data["optionId"]
path = get_path(data)
assessment_id = path.split("/")[-3]
request = build_rp_request(data)
app_response = post_to_app(request, path)
if data["cardType"] != "TEXT":
if data["cardType"] == "INPUT":
optionId = None
store_url_entry = appAssessments(
contact_id=contact_uuid,
assessment_id=assessment_id,
title=title,
description=description,
step=step,
user_input=value,
optionId=optionId,
)
store_url_entry.save()
pdf = pdf_ready(app_response)
if pdf:
response = pdf_endpoint(app_response)
return HttpResponseRedirect(response)
else:
message = format_message(app_response)
return Response(message, status=status.HTTP_200_OK)
class Reports(generics.GenericAPIView):
permission_classes = (permissions.AllowAny,)
def get(self, request, *args, **kwargs):
report_id = request.GET.get("report_id")
response = get_report(report_id)
return Response(response, status=status.HTTP_200_OK)
Utils.py
def get_endpoint(payload):
value = payload["value"]
if value != "":
if value == "back":
url = reverse("app-previous-dialog")
elif value == "abort":
url = reverse("app-abort")
else:
url = reverse("app-next-dialog")
elif value == "":
url = reverse("app-start-assessment")
return url
def encodeurl(payload, url):
qs = "?" + urlencode(payload, safe="")
reverse_url = url + qs
return reverse_url
Code explanation: The app receives a json payload in the ConversationLayerView. It calls the endpoint method to know which endpoint to redirect to based on the 'value' key in the payload is set to.
The request looks something like this:
{
"contact_uuid": "67460e74-02e3-11e8-b443-00163e990bdb",
"choices": null,
"value": "Charles",
"cardType": "INPUT",
"step": null,
"optionId": null,
"path": "",
"title": "",
"description": "What's your name",
"message": ""
}
Since "value" is "Charles", the view redirects to "app-next-dialog" in the NextDialog view. In this view a POST request is done to an external application and a json response is received. If the response has a PDF key this view redirects to the third view. THis happens here:
if pdf:
response = pdf_endpoint(app_response)
return HttpResponseRedirect(response)
else:
message = format_message(app_response)
return Response(message, status=status.HTTP_200_OK)
If the key is present then redirect to "response" whose output is "/api/v2/app/reports?report_id=/reports/17340f51604cb35bd2c6b7b9b16f3aec" otherwise do not redirect but return a 200.
Error:
AssertionError: 302 != 200 : Couldn't retrieve redirection page '/api/v2/app/nextdialog': response code was 302 (expected 200)
Url.py
path(
"api/v2/app/assessments",
views.PresentationLayerView.as_view(),
name="app-assessments",
),
path("api/v2/app/nextdialog", views.NextDialog.as_view(), name="app-next-dialog"),
path("api/v2/app/reports", views.Reports.as_view(), name="app-reports"),
test_views.py:
class appAssessmentReport(APITestCase):
data = {
"contact_uuid": "67460e74-02e3-11e8-b443-00163e990bdd",
"choices": None,
"message": (
"How old are you?\n\nReply *back* to go to "
"the previous question or *abort* to "
"end the assessment"
),
"explanations": "",
"step": 39,
"value": "27",
"optionId": None,
"path": "/assessments/f9d4be32-78fa-48e0-b9a3-e12e305e73ce/dialog/next",
"cardType": "INPUT",
"title": "Patient Information",
"description": "How old are you?",
}
start_url = reverse("app-assessments")
next_dialog_url = reverse("app-next-dialog")
pdf_url = reverse("app-reports")
destination_url = (
"/api/v2/app/nextdialog?contact_uuid="
"67460e74-02e3-11e8-b443-00163e990bdd&"
"choices=None&message=How+old+are+you%3F"
"%0A%0AReply+%2Aback%2A+to+go+to+the+"
"previous+question+or+%2Aabort%2A+to+end"
"+the+assessment&explanations=&step="
"39&value=27&optionId=None&path=%2F"
"assessments%2Ff9d4be32-78fa-48e0-b9a3"
"-e12e305e73ce%2Fdialog%2Fnext&cardType"
"=INPUT&title=Patient+Information&"
"description=How+old+are+you%3F"
)
@patch("app.views.pdf_ready")
@patch("app.views.post_to_app")
def test_assessment_report(self, mock_post_to_app, mock_pdf_ready):
mock_post_to_app.return_value = {
"cardType": "CHOICE",
"step": 40,
"title": {"en-US": "YOUR REPORT"},
"description": {"en-US": ""},
"options": [
{"optionId": 0, "text": {"en-US": "Option 1"}},
{"optionId": 1, "text": {"en-US": "Option 2"}},
{"optionId": 2, "text": {"en-US": "Option 3"}},
],
"_links": {
"self": {
"method": "GET",
"href": "/assessments/898d915e-229f-48f2-9b98-cfd760ba8965",
},
"report": {
"method": "GET",
"href": "/reports/17340f51604cb35bd2c6b7b9b16f3aec",
},
},
}
mock_pdf_ready.return_value = utils.pdf_ready(mock_post_to_app.return_value)
user = get_user_model().objects.create_user("test")
self.client.force_authenticate(user)
response = self.client.post(self.start_url, self.data, format="json")
print(response)
self.assertRedirects(response, self.destination_url)
So far this isn't working. In summary I'm just trying to start in view 1, redirect to view 2 and redirect to view 3 from view 2. Is this possible in Django? Thanks.