Example #1
0
def send_url(request):
    try:
        if "CONTENT_TYPE" in request.META:
            content_type = "CONTENT_TYPE"
        else:
            content_type = "HTTP_CONTENT_TYPE"
        if request.META[content_type] == RP_RESPONSE_CONTENT_TYPES[
                "URL_ENCODED"]:
            data = request.data
            content = data.dict()
        else:
            content = request.data
        # decrement key1
        to = content['to_no_plus']
        key1 = f"MO_MT_KEY_{to}"
        key2 = f"MSG_KEY_{to}"
        key1_val = int(r.decr(key1))
        if key1_val >= 0:
            r.lpush(key2, str(content))
        else:
            action = "end"
            # code here is currently temporary
            if content["session_status"] == RP_RESPONSE_STATUSES["waiting"]:
                action = "request"
            msg_extras = dict(msg_type="Outgoing",
                              status="Received",
                              action=action)
            content.update(msg_extras)
            push = push_ussd(content, request)
            # reset key to 1
            r.set(key1, 0, ex=10)
        return Response({"message": "success"}, status=200)
    except Exception as err:
        error_logger.exception(err)
 def post(self, request, *args, **kwargs):
     access_logger.info(request)
     try:
         if "channel_id" in kwargs:
             channel_id = kwargs['channel_id']
             channel = USSDChannel.objects.get(pk=channel_id)
             form = ChannelConfForm(request.POST, instance=channel)
         else:
             form = ChannelConfForm(request.POST)
         if form.is_valid():
             form.save()
             self.msg = 'Channel configurations  successfully saved.'
             self.success = True
             return redirect(reverse("channel_list"))
         else:
             self.msg = 'Form is not valid'
         return render(
             request, self.template_name, {
                 "form": form,
                 "msg": self.msg,
                 "success": self.success,
                 "hostname": self.hostname
             })
     except Exception as err:
         error_logger.exception(err)
    def post(self, request, handler_id=None):
        access_logger.info(request)
        try:
            if handler_id:
                handler = Handler.objects.get(pk=handler_id)
                self.auth_scheme = handler.auth_scheme
                self.aggregator = handler.aggregator
                self.get_auth_token()
                self.isNewHandler = False
                form = HandlerForm(request.POST, instance=handler)
            else:
                form = HandlerForm(request.POST)
            if form.is_valid():
                form.save()
                # create new non-staff user and assign them an auth token
                if self.isNewHandler:
                    aggregator = form.cleaned_data["aggregator"]
                    self.create_auth_user(aggregator)

                self.msg = 'Saved'
                self.success = True
            else:
                self.msg = 'Form is invalid'
                self.success = False
            return render(request, self.template_name,
                          {"form": form, "msg": self.msg, "token": self.token, "success": self.success,
                           "auth_scheme": self.auth_scheme})

        except Exception as err:
            self.success = False
            error_logger.exception(err)
            self.msg = str(err)
            return render(request, self.template_name,
                          {"form": form, "msg": self.msg, "token": self.token, "success": self.success,
                           "auth_scheme": self.auth_scheme})
Example #4
0
def push_ussd(payload, request):
    try:
        host = request.get_host()
        ws = create_connection(f"ws://{host}/ws/demo")
        ws.send(json.dumps(payload))
        ws.close()
        return True
    except Exception as err:
        error_logger.exception(err)
        return False
Example #5
0
def clear_sessions(request):
    try:
        # delete all sessions
        USSDSession.objects.all().delete()
        response = dict(status="success")
        return Response(response, status=200)
    except Exception as error:
        error_logger.exception(error)
        response = dict(status="error", message=f"{str(error)}")
        return Response(response, status=500)
Example #6
0
 def process_handler(self):
     try:
         # determine service_code
         self.determine_service_code()
         self.handler = Handler.objects.get(short_code=self.service_code)
         request_format = self.handler.request_format
         # use defined template
         self.rapidpro_keys, self.handler_keys = separate_keys(
             request_format)
         # generate standard request_string to send to rapidPro
         self.generate_standard_request()
         # save contact if it doesn't exist
         self.store_contact()
         return self.standard_request
     except Exception as err:
         error_logger.exception(err)
Example #7
0
 def post(self, request):
     access_logger.info(request.META)
     try:
         channels = USSDChannel.objects.all()
         if len(channels) > 0:
             channel = channels[0]
             form = ChannelConfForm(request.POST, instance=channel)
         else:
             form = ChannelConfForm(request.POST)
         if form.is_valid():
             form.save()
             self.msg = 'Channel configurations  successfully saved.'
             self.success = True
             return redirect("/")
         else:
             self.msg = 'Form is not valid'
         return render(request, self.template_name,
                       {"form": form, "msg": self.msg, "success": self.success, "hostname": self.hostname})
     except Exception as err:
         error_logger.exception(err)
Example #8
0
 def get(self, request, handler_id=None):
     access_logger.info(str(request))
     try:
         if handler_id:
             if Handler.objects.filter(id=handler_id).exists():
                 handler = Handler.objects.get(pk=handler_id)
                 self.aggregator = handler.aggregator
                 form = HandlerForm(instance=handler)
                 self.get_auth_token()
             else:
                 form = HandlerForm()
                 redirect('add_handler', permanent=True)
         else:
             form = HandlerForm()
         return render(request, self.template_name, {
             "form": form,
             "token": self.token
         })
     except Exception as err:
         error_logger.exception(err)
    def get(self, request, handler_id=None):
        access_logger.info(str(request))
        try:
            if handler_id:
                if Handler.objects.filter(id=handler_id).exists():
                    handler = Handler.objects.get(pk=handler_id)
                    self.callback_url = f"{handler.channel.send_url}/adaptor/call-back"
                    self.auth_scheme = handler.auth_scheme
                    self.aggregator = handler.aggregator
                    form = HandlerForm(instance=handler)
                    self.get_auth_token()
                else:
                    form = HandlerForm()
                    redirect('add_handler', permanent=True)
            else:
                form = HandlerForm()
            return render(request, self.template_name,
                          {"form": form, "token": self.token, "auth_scheme": self.auth_scheme,
                           "callback_url": self.callback_url})

        except Exception as err:
            error_logger.exception(err)
Example #10
0
 def process_handler(self):
     try:
         '''
         Lets first run the clear_timedout_sessions(), to create a task that deletes timed-out sessions
         '''
         if PeriodicTask.objects.filter(
                 name="Clear_Timedout_sessions").exists():
             pass
         else:
             # only if the task and its scheduler have not been create yet
             clear_timedout_sessions()
         # determine service_code
         self.determine_service_code()
         request_format = self.handler.request_format
         # use defined template
         self.rapidpro_keys, self.handler_keys = separate_keys(
             request_format)
         # generate standard request_string to send to rapidPro
         self.generate_standard_request()
         # save contact if it doesn't exist
         self.store_contact()
         return self.standard_request
     except Exception as err:
         error_logger.exception(err)
Example #11
0
def call_back(request):
    # CHECK METHOD USED
    if request.META["REQUEST_METHOD"] == "GET":
        data = request.GET
        request_data = data.dict()
    else:
        request_data = request.data
    try:
        sr = ProcessAggregatorRequest(request_data)
        standard_request_string = sr.process_handler()
        current_session = sr.log_session()
        is_new_session = sr.is_new_session
        still_in_flow = sr.is_in_flow
        handler = sr.get_handler
        end_action = handler.signal_end_string
        reply_action = handler.signal_reply_string
        urn = standard_request_string['from']
        channel = get_channel()
        if channel is None:
            raise Exception(
                "Could not continue without a channel, configure one first and try again"
            )

        if is_new_session:
            text = " " if still_in_flow else channel.trigger_word
        else:
            text = standard_request_string["text"]
        allowed_urn = standard_urn(urn)

        rapid_pro_request = {"from": allowed_urn, "text": text}
        # create redis keys
        key1 = f"MO_MT_KEY_{allowed_urn}"
        r.set(key1, 1)  # proven necessary or else
        key2 = f"MSG_KEY_{allowed_urn}"
        """""Channel details """ ""

        # receive_url is used to send msgs to rapidPro
        receive_url = channel.rapidpro_receive_url
        # req = requests.post(receive_url, json.dumps(rapid_pro_request), headers=HEADERS)
        req = requests.post(receive_url, rapid_pro_request, headers=HEADERS)
        if req.status_code == 200:
            # increment key1
            r.incr(key1)
            r.expire(key1, 30)  # expire key1 after 30s
            data = r.blpop(key2, channel.timeout_after
                           )  # wait for configured time for rapidPro instance
            if data:
                feedback = literal_eval(
                    data[1].decode("utf-8"))  # from RapidPro
                text = feedback[RP_RESPONSE_FORMAT['text']]
                status = feedback[RP_RESPONSE_FORMAT['session_status']]
                if status == RP_RESPONSE_STATUSES['waiting']:
                    action = reply_action
                else:
                    # mark session complete and give it a green badge
                    changeSessionStatus(current_session,
                                        SESSION_STATUSES['COMPLETED'],
                                        'success')
                    action = end_action
                new_format = dict(text=text, action=action)
                response = sr.get_expected_response(new_format)
            else:
                # mark session timed out and give it a red badge
                changeSessionStatus(current_session,
                                    SESSION_STATUSES['TIMED_OUT'], 'danger')
                error_logger.debug(f"Response timed out for redis key {key2}")
                res_format = dict(text="Response timed out", action=end_action)
                response = sr.get_expected_response(res_format)
        else:
            changeSessionStatus(current_session, SESSION_STATUSES['TIMED_OUT'],
                                'danger')
            res_format = dict(text="External Application unreachable",
                              action=end_action)
            error_logger.exception(req.content)
            response = sr.get_expected_response(res_format)
        return Response(response, status=200)
    except Exception as err:
        error_logger.exception(err)
        response = {
            "responseString": "External Application unreachable",
            "action": "end"
        }
        return Response(response, status=500)
    def process_request(self):
        try:
            current_session = self.request_factory.log_session()
            is_new_session = self.request_factory.is_new_session
            still_in_flow = self.request_factory.is_in_flow
            handler = self.request_factory.get_handler
            end_action = handler.signal_end_string
            reply_action = handler.signal_reply_string
            urn = self.standard_request_string['from']
            channel = handler.channel

            if is_new_session:
                text = handler.repeat_trigger if still_in_flow else handler.trigger_word
            else:
                text = self.standard_request_string["text"].strip()
            allowed_urn = standard_urn(urn, handler)

            rapid_pro_request = {"from": allowed_urn, "text": text}
            access_logger.info(
                f"Is new session: {is_new_session}, Still in flow: {still_in_flow}"
            )
            access_logger.info(rapid_pro_request)
            # create redis keys
            key1 = f"MO_MT_KEY_{allowed_urn}"
            r.set(key1, 1)  # proven necessary or else
            key2 = f"MSG_KEY_{allowed_urn}"
            """""Channel details """ ""

            # receive_url is used to send msgs to rapidPro
            receive_url = channel.rapidpro_receive_url
            req = requests.post(receive_url,
                                rapid_pro_request,
                                headers=HEADERS)
            if req.status_code == 200:
                # increment key1
                r.incr(key1)
                r.expire(key1, 30)  # expire key1 after 30s
                data = r.blpop(
                    key2, channel.timeout_after
                )  # wait for configured time for rapidPro instance
                if data:
                    feedback = literal_eval(
                        data[1].decode("utf-8"))  # from RapidPro
                    text = feedback[RP_RESPONSE_FORMAT['text']]
                    status = feedback[RP_RESPONSE_FORMAT['session_status']]
                    access_logger.info(f"From redis key:  {data}")
                    if status == RP_RESPONSE_STATUSES['waiting']:
                        action = reply_action
                    else:
                        # mark session complete and give it a green badge
                        changeSessionStatus(current_session,
                                            SESSION_STATUSES['COMPLETED'],
                                            'success')
                        action = end_action
                    new_format = dict(text=text, action=action)
                    response = self.request_factory.get_expected_response(
                        new_format)
                else:
                    # mark session timed out and give it a red badge
                    changeSessionStatus(current_session,
                                        SESSION_STATUSES['TIMED_OUT'],
                                        'danger')
                    error_logger.debug(
                        f"Response timed out for redis key {key2}")
                    res_format = dict(text="Response timed out",
                                      action=end_action)
                    '''
                    We need to delete this contact as it will delete-cascade(which ever way they say it) sessions attached to it.
                    Next time user comes back, they will submit a trigger word
                    '''
                    contact = Contact.objects.get(urn=urn)
                    contact.delete()
                    response = self.request_factory.get_expected_response(
                        res_format)
                r.delete(key2)  # lets delete the key
            else:
                changeSessionStatus(current_session,
                                    SESSION_STATUSES['TIMED_OUT'], 'danger')
                res_format = dict(text="External Application error",
                                  action=end_action)
                contact = Contact.objects.get(urn=urn)
                contact.delete()
                error_logger.exception(req.content)
                response = self.request_factory.get_expected_response(
                    res_format)
            return Response(response, status=200)
        except Exception as err:
            error_logger.exception(err)
            response = {
                "responseString": "External Application error",
                "action": "end"
            }
            return Response(response, status=500)