Exemple #1
0
def test_zoom_api_request_missing_creds():
    common.APIGEE_KEY = None

    # (ZOOM_API_KEY, ZOOM_API_SECRET)
    cases = [(None, None), ("key", None), (None, "secret")]

    for key, secret in cases:
        common.ZOOM_API_KEY = key
        common.ZOOM_API_SECRET = secret
        with pytest.raises(Exception) as exc_info:
            common.zoom_api_request("meetings")
        assert exc_info.match("Missing api credentials.")
Exemple #2
0
def test_apigee_key(caplog):
    common.APIGEE_KEY = "apigee_key"
    common.ZOOM_API_KEY = None
    common.ZOOM_API_SECRET = None
    caplog.set_level(logging.INFO)
    common.zoom_api_request("meetings")
    assert "apigee request" in caplog.text.lower()

    # Should still use apigee key even if zoom api key/secret defined
    common.ZOOM_API_KEY = "key"
    common.ZOOM_API_SECRET = "secret"
    common.zoom_api_request("meetings")
    assert "apigee request" in caplog.text.lower()
Exemple #3
0
def test_zoom_api_key(caplog):
    common.APIGEE_KEY = None
    common.ZOOM_API_KEY = "key"
    common.ZOOM_API_SECRET = "secret"
    caplog.set_level(logging.INFO)
    common.zoom_api_request("meetings")
    assert "zoom api request" in caplog.text.lower()

    common.APIGEE_KEY = ""
    common.ZOOM_API_KEY = "key"
    common.ZOOM_API_SECRET = "secret"
    caplog.set_level(logging.INFO)
    common.zoom_api_request("meetings")
    assert "zoom api request" in caplog.text.lower()
def test_zoom_api_request_success():
    # test successful call
    with requests_mock.mock() as req_mock:
        req_mock.get(requests_mock.ANY,
                     status_code=200,
                     json={"mock_payload": 123})
        r = zoom_api_request("meetings")
        assert "mock_payload" in r.json()
 def host_name(self):
     if not hasattr(self, "_host_name"):
         resp = zoom_api_request("users/{}".format(
             self.data["host_id"])).json()
         logger.info({"Host details": resp})
         self._host_name = "{} {}".format(resp["first_name"],
                                          resp["last_name"])
     return self._host_name
def test_zoom_api_request_failures():

    # test failed call that returns
    with requests_mock.mock() as req_mock:
        req_mock.get(requests_mock.ANY,
                     status_code=400,
                     json={"mock_payload": 123})
        r = zoom_api_request("meetings", ignore_failure=True)
        assert r.status_code == 400

    # test failed call that raises
    with requests_mock.mock() as req_mock:
        req_mock.get(requests_mock.ANY,
                     status_code=400,
                     json={"mock_payload": 123})
        error_msg = "400 Client Error"
        with pytest.raises(requests.exceptions.HTTPError, match=error_msg):
            zoom_api_request("meetings", ignore_failure=False, retries=0)

    # test ConnectionError handling
    with requests_mock.mock() as req_mock:
        req_mock.get(requests_mock.ANY,
                     exc=requests.exceptions.ConnectionError)
        error_msg = "Error requesting https://api.zoom.us/v2/meetings"
        with pytest.raises(ZoomApiRequestError, match=error_msg):
            zoom_api_request("meetings")

    # test ConnectTimeout handling
    with requests_mock.mock() as req_mock:
        req_mock.get(requests_mock.ANY, exc=requests.exceptions.ConnectTimeout)
        error_msg = "Error requesting https://api.zoom.us/v2/meetings"
        with pytest.raises(ZoomApiRequestError, match=error_msg):
            zoom_api_request("meetings")
Exemple #7
0
def test_url_construction(caplog):
    common.APIGEE_KEY = None
    common.ZOOM_API_KEY = "key"
    common.ZOOM_API_SECRET = "secret"
    caplog.set_level(logging.INFO)

    cases = [
        ("https://www.foo.com", "meetings", "https://www.foo.com/meetings"),
        ("https://www.foo.com/", "meetings", "https://www.foo.com/meetings"),
        ("https://www.foo.com/", "/meetings", "https://www.foo.com/meetings")
    ]
    with requests_mock.mock() as req_mock:
        req_mock.get(requests_mock.ANY,
                     status_code=200,
                     json={"mock_payload": 123})
        for url, endpoint, expected in cases:
            common.ZOOM_API_BASE_URL = url
            common.zoom_api_request(endpoint)
            assert f"zoom api request to https://www.foo.com/meetings" in caplog.text.lower(
            )
Exemple #8
0
def test_zoom_api_request_success():
    # test successful call
    cases = [(None, "zoom_key", "zoom_secret"),
             ("", "zoom_key", "zoom_secret")]
    for apigee_key, zoom_key, zoom_secret in cases:
        common.APIGEE_KEY = apigee_key
        common.ZOOM_API_KEY = zoom_key
        common.ZOOM_API_SECRET = zoom_secret

        with requests_mock.mock() as req_mock:
            req_mock.get(requests_mock.ANY,
                         status_code=200,
                         json={"mock_payload": 123})
            r = common.zoom_api_request("meetings")
            assert "mock_payload" in r.json()
Exemple #9
0
def test_zoom_api_request_failures():
    common.APIGEE_KEY = None
    common.ZOOM_API_KEY = "zoom_key"
    common.ZOOM_API_SECRET = "zoom_secret"
    common.ZOOM_API_BASE_URL = "https://api.zoom.us/v2/"
    # test failed call that returns
    with requests_mock.mock() as req_mock:
        req_mock.get(requests_mock.ANY,
                     status_code=400,
                     json={"mock_payload": 123})
        r = common.zoom_api_request("meetings", ignore_failure=True)
        assert r.status_code == 400

    # test failed call that raises
    with requests_mock.mock() as req_mock:
        req_mock.get(requests_mock.ANY,
                     status_code=400,
                     json={"mock_payload": 123})
        error_msg = "400 Client Error"
        with pytest.raises(requests.exceptions.HTTPError, match=error_msg):
            common.zoom_api_request("meetings",
                                    ignore_failure=False,
                                    retries=0)

    # test ConnectionError handling
    with requests_mock.mock() as req_mock:
        req_mock.get(requests_mock.ANY,
                     exc=requests.exceptions.ConnectionError)
        error_msg = "Error requesting https://api.zoom.us/v2/meetings"
        with pytest.raises(common.ZoomApiRequestError, match=error_msg):
            common.zoom_api_request("meetings")

    # test ConnectTimeout handling
    with requests_mock.mock() as req_mock:
        req_mock.get(requests_mock.ANY, exc=requests.exceptions.ConnectTimeout)
        error_msg = "Error requesting https://api.zoom.us/v2/meetings"
        with pytest.raises(common.ZoomApiRequestError, match=error_msg):
            common.zoom_api_request("meetings")
def test_zoom_api_request_missing_endpoint():
    with pytest.raises(Exception) as exc_info:
        zoom_api_request(endpoint=None)
    assert exc_info.match("missing required param 'endpoint'")
def get_admin_token():
    # get admin level zak token from admin id
    r = zoom_api_request("users/{}/token?type=zak".format(ZOOM_ADMIN_ID))
    return r.json()["token"]
Exemple #12
0
def handler(event, context):
    """
    This function acts as a relay to the traditional zoom webhook. The webhook
    function is called by Zoom on a "recording.completed" event, along with data
    about the recordings. Here we fetch the recording data from the zoom API.
    The response to that API call is (mostly) identical to the payload zoom
    sends to the webhook, so we can simply pass it along in our own webhook
    request, using a "on.demand.ingest" event type and including the series id
    as "on_demand_series_id".
    """

    logger.info(event)

    if "body" not in event or event["body"] is None:
        return resp(400, "Bad data. No body found in event.")

    try:
        body = json.loads(event["body"])
        logger.info({"on-demand request": body})
    except json.JSONDecodeError:
        return resp(400, "Webhook notification body is not valid json.")

    if "uuid" not in body:
        return resp(
            400, "Missing recording uuid field in webhook notification "
            "body.")

    uuid = body["uuid"]
    if uuid.startswith("https"):
        # it's a link; parse the uuid from the query string
        parsed_url = urlparse(uuid)
        query_params = parse_qs(parsed_url.query)
        if "meeting_id" not in query_params:
            return resp(
                404, "Zoom URL is malformed or missing 'meeting_id' "
                "param.")
        uuid = query_params["meeting_id"][0]

    logger.info("Got recording uuid: '{}'".format(uuid))

    try:
        try:
            # zoom api can break if uuid is not double urlencoded
            double_urlencoded_uuid = quote(quote(uuid, safe=""), safe="")
            zoom_endpoint = (
                "meetings/{}/recordings".format(double_urlencoded_uuid))
            r = zoom_api_request(zoom_endpoint)
            recording_data = r.json()
        except requests.HTTPError as e:
            # return a 404 if there's no such meeting
            if e.response.status_code == 404:
                return resp(404, "No zoom recording with id '{}'".format(uuid))
            else:
                raise
    # otherwise return a 500 on any other errors (bad json, bad request, etc)
    except Exception as e:
        return resp(
            500,
            "Something went wrong querying the zoom api: {}".format(str(e)))

    if "recording_files" not in recording_data \
            or not len(recording_data["recording_files"]):
        return resp(
            503,
            "Zoom api response contained no recording files for {}".format(
                uuid))

    # verify that all the recording files are actually "completed"
    not_completed = sum(1 for x in recording_data["recording_files"]
                        if x.get("status") and x.get("status") != "completed")

    if not_completed > 0:
        return resp(503, "Not all recorded files have status 'completed'")

    webhook_data = {
        "event": "on.demand.ingest",
        "payload": {
            "object": recording_data
        }
    }

    # series id is an optional param. if not present the download function will
    # attempt to determine the series id by matching the recording times against
    # it's known schedule as usual.
    if "oc_series_id" in body and body["oc_series_id"]:
        webhook_data["payload"]["on_demand_series_id"] = body["oc_series_id"]

    if "allow_multiple_ingests" in body:
        webhook_data["payload"]["allow_multiple_ingests"] = body[
            "allow_multiple_ingests"]

    logger.info({"webhook_data": webhook_data})
    try:
        r = requests.post(WEBHOOK_ENDPOINT_URL,
                          data=json.dumps(webhook_data),
                          headers={"Content-type": "application/json"})
        r.raise_for_status()
        if r.status_code == 204:
            raise Exception("Webhook returned 204: ingest not accepted")
    except Exception as e:
        err_msg = str(e)
        logger.exception(
            "Something went wrong calling the webhook: {}".format(err_msg))
        return resp(500, err_msg)

    return resp(200, "Ingest accepted")
Exemple #13
0
def test_zoom_api_request_missing_endpoint():
    with pytest.raises(Exception) as exc_info:
        common.zoom_api_request(endpoint=None)
    assert exc_info.match("Call to zoom_api_request missing endpoint")