Example #1
0
 def get_other_participant(cls, virtual_tn, sender):
     """
     Returns the 2nd particpant and session when given the virtual TN
     and the first participant
     """
     session = None
     try:
         session = ProxySession.query.filter_by(virtual_TN=virtual_tn).one()
     except NoResultFound:
             msg = ("A session with virtual TN '{}'"
                    " could not be found").format(virtual_tn)
             log.info({"message": msg})
             return None, None
     if session:
         participant_a = session.participant_a
         participant_b = session.participant_b
         if participant_a == sender:
             return participant_b, session.id
         elif participant_b == sender:
             return participant_a, session.id
         else:
             msg = ("{} is not a participant of session {}").format(
                 sender,
                 session.id)
             log.info({"message": msg})
             return None, None
Example #2
0
def send_message(recipients, virtual_tn, msg, session_id, is_system_msg=False):
    """
    For each recipient, passes a Message to Flowroute's messaging controller.
    The message will be sent from the 'virtual_tn' number. If this is a system
    message, the message body will be prefixed with the org name for context.
    If an exception is raised by the controller, an error is logged, and an
    internal error is raised with the exception content.
    """
    if is_system_msg:
        msg = "[{}]: {}".format(ORG_NAME.upper(), msg)
    for recipient in recipients:
        message = Message(to=recipient, from_=virtual_tn, content=msg)
        try:
            app.sms_controller.create_message(message)
        except Exception as e:
            strerr = vars(e).get("response_body", None)
            log.critical(
                {
                    "message": "Raised an exception sending SMS",
                    "status": "failed",
                    "exc": e,
                    "strerr": vars(e).get("response_body", None),
                }
            )
            raise InternalSMSDispatcherError(
                "An error occured when requesting against Flowroute's API.",
                payload={"strerr": strerr, "reason": "InternalSMSDispatcherError"},
            )
        else:
            log.info(
                {"message": "Message sent to {} for session {}".format(recipient, session_id), "status": "succeeded"}
            )
Example #3
0
def add_virtual_tn():
    """
    The VirtualTN resource endpoint for adding VirtualTN's from the pool.
    """
    body = request.json
    try:
        value = str(body['value'])
        assert len(value) <= 18
    except (AssertionError, KeyError):
        raise InvalidAPIUsage("Required argument: 'value' (str, length <= 18)",
                              payload={'reason': 'invalidAPIUsage'})
    virtual_tn = VirtualTN(value)
    try:
        db_session.add(virtual_tn)
        db_session.commit()
    except IntegrityError:
        db_session.rollback()
        msg = ("Did not add virtual TN {} to the pool "
               "-- already exists").format(value)
        log.info({"message": msg})
        raise InvalidAPIUsage("Virtual TN already exists",
                              payload={'reason': 'duplicate virtual TN'})
    return Response(json.dumps({
        "message": "Successfully added TN to pool",
        "value": value
    }),
                    content_type="application/json")
Example #4
0
def inbound_handler():
    """
    The inbound request handler for consuming HTTP wrapped SMS content from
    Flowroute's messaging service.
    """
    # We'll take this time to clear out any expired sessions and release
    # TNs back to the pool if possible
    ProxySession.clean_expired()
    body = request.json
    try:
        virtual_tn = body['to']
        assert len(virtual_tn) <= 18
        tx_participant = body['from']
        assert len(tx_participant) <= 18
        message = body['body']
    except (TypeError, KeyError, AssertionError) as e:
        msg = ("Malformed inbound message: {}".format(body))
        log.error({"message": msg, "status": "failed", "exc": str(e)})
        return Response('There was an issue parsing your request.', status=400)
    rcv_participant, session_id = ProxySession.get_other_participant(
        virtual_tn, tx_participant)
    if rcv_participant is not None:
        recipients = [rcv_participant]
        send_message(recipients, virtual_tn, message, session_id)
    else:
        recipients = [tx_participant]
        send_message(recipients,
                     virtual_tn,
                     NO_SESSION_MSG,
                     None,
                     is_system_msg=True)
        msg = ("ProxySession not found, or {} is not authorized "
               "to participate".format(tx_participant))
        log.info({"message": msg, "status": "succeeded"})
    return Response(status=200)
Example #5
0
 def get_other_participant(cls, virtual_tn, sender):
     """
     Returns the 2nd particpant and session when given the virtual TN
     and the first participant
     """
     session = None
     try:
         session = ProxySession.query.filter_by(virtual_TN=virtual_tn).one()
     except NoResultFound:
         msg = ("A session with virtual TN '{}'"
                " could not be found").format(virtual_tn)
         log.info({"message": msg})
         return None, None
     if session:
         participant_a = session.participant_a
         participant_b = session.participant_b
         if participant_a == sender:
             return participant_b, session.id
         elif participant_b == sender:
             return participant_a, session.id
         else:
             msg = ("{} is not a participant of session {}").format(
                 sender, session.id)
             log.info({"message": msg})
             return None, None
Example #6
0
def inbound_handler():
    """
    The inbound request handler for consuming HTTP wrapped SMS content from
    Flowroute's messaging service.
    """
    # We'll take this time to clear out any expired sessions and release
    # TNs back to the pool if possible
    ProxySession.clean_expired()
    body = request.json
    try:
        virtual_tn = body["to"]
        assert len(virtual_tn) <= 18
        tx_participant = body["from"]
        assert len(tx_participant) <= 18
        message = body["body"]
    except (TypeError, KeyError, AssertionError) as e:
        msg = "Malformed inbound message: {}".format(body)
        log.error({"message": msg, "status": "failed", "exc": str(e)})
        return Response("There was an issue parsing your request.", status=400)
    rcv_participant, session_id = ProxySession.get_other_participant(virtual_tn, tx_participant)
    if rcv_participant is not None:
        recipients = [rcv_participant]
        send_message(recipients, virtual_tn, message, session_id)
    else:
        recipients = [tx_participant]
        send_message(recipients, virtual_tn, NO_SESSION_MSG, None, is_system_msg=True)
        msg = "ProxySession not found, or {} is not authorized " "to participate".format(tx_participant)
        log.info({"message": msg, "status": "succeeded"})
    return Response(status=200)
Example #7
0
def delete_session():
    """
    The ProxySession resource endpoint for removing a ProxySession
    to the pool.
    """
    body = request.json
    try:
        session_id = str(body["session_id"])
    except (KeyError):
        raise InvalidAPIUsage("Required argument: 'session_id' (str)", payload={"reason": "invalidAPIUsage"})
    try:
        session = ProxySession.query.filter_by(id=session_id).one()
    except NoResultFound:
        msg = "ProxySession {} could not be deleted because" " it does not exist".format(session_id)
        log.info({"message": msg, "status": "failed"})
        raise InvalidAPIUsage(msg, status_code=404, payload={"reason": "ProxySession not found"})
    participant_a, participant_b, virtual_tn = ProxySession.terminate(session_id)
    recipients = [participant_a, participant_b]
    send_message(recipients, virtual_tn.value, SESSION_END_MSG, session_id, is_system_msg=True)
    msg = "Ended session {} and released {} back to pool".format(session_id, virtual_tn.value)
    log.info({"message": msg, "status": "succeeded"})
    return Response(
        json.dumps({"message": "Successfully ended the session.", "status": "succeeded", "session_id": session_id}),
        content_type="application/json",
    )
Example #8
0
def remove_virtual_tn():
    """
    The VirtualTN resource endpoint for removing VirtualTN's from the pool.
    """
    body = request.json
    try:
        value = str(body['value'])
    except (AssertionError, KeyError):
        raise InvalidAPIUsage("Required argument: 'value' (str, length <= 18)",
                              payload={'reason': 'invalidAPIUsage'})
    try:
        virtualTN = VirtualTN.query.filter_by(value=value).one()
    except NoResultFound:
        msg = ("Could not delete virtual TN ({})"
               " because it does not exist").format(value)
        log.info({"message": msg, "status": "failed"})
        raise InvalidAPIUsage(
            "Virtual TN could not be deleted because it does not exist",
            status_code=404,
            payload={'reason': 'virtual TN not found'})
    else:
        # Release any VirtualTNs from expired ProxySessions
        ProxySession.clean_expired()
        try:
            active_session = ProxySession.query.filter_by(
                virtual_TN=virtualTN.value).one()
        except NoResultFound:
            db_session.delete(virtualTN)
            db_session.commit()
        else:
            msg = ("Cannot delete the number. There is an active "
                   "ProxySession {} using that VirtualTN.".format(
                       active_session.id))
            return Response(json.dumps({
                "message": msg,
                "status": "failed",
            }),
                            content_type="application/json",
                            status=400)
    return Response(json.dumps({
        "message": "Successfully removed TN from pool",
        "value": value,
        "status": "succeeded"
    }),
                    content_type="application/json")
Example #9
0
def add_virtual_tn():
    """
    The VirtualTN resource endpoint for adding VirtualTN's from the pool.
    """
    body = request.json
    try:
        value = str(body["value"])
        assert len(value) <= 18
    except (AssertionError, KeyError):
        raise InvalidAPIUsage("Required argument: 'value' (str, length <= 18)", payload={"reason": "invalidAPIUsage"})
    virtual_tn = VirtualTN(value)
    try:
        db_session.add(virtual_tn)
        db_session.commit()
    except IntegrityError:
        db_session.rollback()
        msg = ("Did not add virtual TN {} to the pool " "-- already exists").format(value)
        log.info({"message": msg})
        raise InvalidAPIUsage("Virtual TN already exists", payload={"reason": "duplicate virtual TN"})
    return Response(
        json.dumps({"message": "Successfully added TN to pool", "value": value}), content_type="application/json"
    )
Example #10
0
def remove_virtual_tn():
    """
    The VirtualTN resource endpoint for removing VirtualTN's from the pool.
    """
    body = request.json
    try:
        value = str(body["value"])
    except (AssertionError, KeyError):
        raise InvalidAPIUsage("Required argument: 'value' (str, length <= 18)", payload={"reason": "invalidAPIUsage"})
    try:
        virtualTN = VirtualTN.query.filter_by(value=value).one()
    except NoResultFound:
        msg = ("Could not delete virtual TN ({})" " because it does not exist").format(value)
        log.info({"message": msg, "status": "failed"})
        raise InvalidAPIUsage(
            "Virtual TN could not be deleted because it does not exist",
            status_code=404,
            payload={"reason": "virtual TN not found"},
        )
    else:
        # Release any VirtualTNs from expired ProxySessions
        ProxySession.clean_expired()
        try:
            active_session = ProxySession.query.filter_by(virtual_TN=virtualTN.value).one()
        except NoResultFound:
            db_session.delete(virtualTN)
            db_session.commit()
        else:
            msg = "Cannot delete the number. There is an active " "ProxySession {} using that VirtualTN.".format(
                active_session.id
            )
            return Response(
                json.dumps({"message": msg, "status": "failed"}), content_type="application/json", status=400
            )
    return Response(
        json.dumps({"message": "Successfully removed TN from pool", "value": value, "status": "succeeded"}),
        content_type="application/json",
    )
Example #11
0
def delete_session():
    """
    The ProxySession resource endpoint for removing a ProxySession
    to the pool.
    """
    body = request.json
    try:
        session_id = str(body['session_id'])
    except (KeyError):
        raise InvalidAPIUsage("Required argument: 'session_id' (str)",
                              payload={'reason': 'invalidAPIUsage'})
    try:
        session = ProxySession.query.filter_by(id=session_id).one()
    except NoResultFound:
        msg = ("ProxySession {} could not be deleted because"
               " it does not exist".format(session_id))
        log.info({"message": msg, "status": "failed"})
        raise InvalidAPIUsage(msg,
                              status_code=404,
                              payload={'reason': 'ProxySession not found'})
    participant_a, participant_b, virtual_tn = ProxySession.terminate(
        session_id)
    recipients = [participant_a, participant_b]
    send_message(recipients,
                 virtual_tn.value,
                 SESSION_END_MSG,
                 session_id,
                 is_system_msg=True)
    msg = "Ended session {} and released {} back to pool".format(
        session_id, virtual_tn.value)
    log.info({"message": msg, "status": "succeeded"})
    return Response(json.dumps({
        "message": "Successfully ended the session.",
        "status": "succeeded",
        "session_id": session_id
    }),
                    content_type="application/json")
Example #12
0
def send_message(recipients, virtual_tn, msg, session_id, is_system_msg=False):
    """
    For each recipient, passes a Message to Flowroute's messaging controller.
    The message will be sent from the 'virtual_tn' number. If this is a system
    message, the message body will be prefixed with the org name for context.
    If an exception is raised by the controller, an error is logged, and an
    internal error is raised with the exception content.
    """
    if is_system_msg:
        msg = "[{}]: {}".format(ORG_NAME.upper(), msg)
    for recipient in recipients:
        message = Message(to=recipient, from_=virtual_tn, content=msg)
        try:
            app.sms_controller.create_message(message)
        except Exception as e:
            strerr = vars(e).get('response_body', None)
            log.critical({
                "message": "Raised an exception sending SMS",
                "status": "failed",
                "exc": e,
                "strerr": vars(e).get('response_body', None)
            })
            raise InternalSMSDispatcherError(
                "An error occured when requesting against Flowroute's API.",
                payload={
                    "strerr": strerr,
                    "reason": "InternalSMSDispatcherError"
                })
        else:
            log.info({
                "message":
                "Message sent to {} for session {}".format(
                    recipient, session_id),
                "status":
                "succeeded"
            })
Example #13
0
def add_proxy_session():
    """
    The ProxySession resource endpoint for adding a new ProxySession
    to the pool.
    """
    body = request.json
    try:
        participant_a = body['participant_a']
        participant_b = body['participant_b']
        assert len(participant_a) <= 18
        assert len(participant_b) <= 18
    except (AssertionError, KeyError):
        raise InvalidAPIUsage(
            ("Required argument: 'participant_a' (str, length <= 18)"
             ", 'participant_b' (str, length <= 18)"),
            payload={'reason': 'invalidAPIUsage'})
    if 'expiry_window' in body:
        expiry_window = body['expiry_window']
    else:
        expiry_window = None
    # Release any VirtualTNs from expired ProxySessions back to the pool
    ProxySession.clean_expired()
    virtual_tn = VirtualTN.get_next_available()
    if virtual_tn is None:
        msg = "Could not create a new session -- No virtual TNs available."
        log.critical({"message": msg, "status": "failed"})
        return Response(json.dumps({
            "message": msg,
            "status": "failed"
        }),
                        content_type="application/json",
                        status=400)
    else:
        session = ProxySession(virtual_tn.value, participant_a, participant_b,
                               expiry_window)
        try:
            virtual_tn.session_id = session.id
            db_session.add(session)
            db_session.add(virtual_tn)
            db_session.commit()
        except IntegrityError:
            db_session.rollback()
            msg = "There were two sessions attempting to reserve the same virtual tn. Please retry."
            log.error({"message": msg, "status": "failed"})
            return Response(json.dumps({
                "message": msg,
                "status": "failed"
            }),
                            content_type="application/json",
                            status=500)
        expiry_date = session.expiry_date.strftime(
            '%Y-%m-%d %H:%M:%S') if session.expiry_date else None
        recipients = [participant_a, participant_b]
        try:
            send_message(recipients,
                         virtual_tn.value,
                         SESSION_START_MSG,
                         session.id,
                         is_system_msg=True)
        except InternalSMSDispatcherError as e:
            db_session.delete(session)
            virtual_tn.session_id = None
            db_session.add(virtual_tn)
            db_session.commit()
            raise e
        msg = "ProxySession {} started with participants {} and {}".format(
            session.id, participant_a, participant_b)
        log.info({"message": msg, "status": "succeeded"})
        return Response(json.dumps({
            "message": "Created new session",
            "status": "succeeded",
            "session_id": session.id,
            "expiry_date": expiry_date,
            "virtual_tn": virtual_tn.value,
            "participant_a": participant_a,
            "participant_b": participant_b
        }),
                        content_type="application/json")
Example #14
0
def add_proxy_session():
    """
    The ProxySession resource endpoint for adding a new ProxySession
    to the pool.
    """
    body = request.json
    try:
        participant_a = body["participant_a"]
        participant_b = body["participant_b"]
        assert len(participant_a) <= 18
        assert len(participant_b) <= 18
    except (AssertionError, KeyError):
        raise InvalidAPIUsage(
            ("Required argument: 'participant_a' (str, length <= 18)" ", 'participant_b' (str, length <= 18)"),
            payload={"reason": "invalidAPIUsage"},
        )
    if "expiry_window" in body:
        expiry_window = body["expiry_window"]
    else:
        expiry_window = None
    # Release any VirtualTNs from expired ProxySessions back to the pool
    ProxySession.clean_expired()
    virtual_tn = VirtualTN.get_next_available()
    if virtual_tn is None:
        msg = "Could not create a new session -- No virtual TNs available."
        log.critical({"message": msg, "status": "failed"})
        return Response(json.dumps({"message": msg, "status": "failed"}), content_type="application/json", status=400)
    else:
        session = ProxySession(virtual_tn.value, participant_a, participant_b, expiry_window)
        try:
            virtual_tn.session_id = session.id
            db_session.add(session)
            db_session.add(virtual_tn)
            db_session.commit()
        except IntegrityError:
            db_session.rollback()
            msg = "There were two sessions attempting to reserve the same virtual tn. Please retry."
            log.error({"message": msg, "status": "failed"})
            return Response(
                json.dumps({"message": msg, "status": "failed"}), content_type="application/json", status=500
            )
        expiry_date = session.expiry_date.strftime("%Y-%m-%d %H:%M:%S") if session.expiry_date else None
        recipients = [participant_a, participant_b]
        try:
            send_message(recipients, virtual_tn.value, SESSION_START_MSG, session.id, is_system_msg=True)
        except InternalSMSDispatcherError as e:
            db_session.delete(session)
            virtual_tn.session_id = None
            db_session.add(virtual_tn)
            db_session.commit()
            raise e
        msg = "ProxySession {} started with participants {} and {}".format(session.id, participant_a, participant_b)
        log.info({"message": msg, "status": "succeeded"})
        return Response(
            json.dumps(
                {
                    "message": "Created new session",
                    "status": "succeeded",
                    "session_id": session.id,
                    "expiry_date": expiry_date,
                    "virtual_tn": virtual_tn.value,
                    "participant_a": participant_a,
                    "participant_b": participant_b,
                }
            ),
            content_type="application/json",
        )