Exemple #1
0
    def read_event_schema(self, filepath):
        logger.info("Reading %s" % filepath)

        with open(filepath, "r", encoding="utf-8") as f:
            json_schema = yaml.load(f, OrderedLoader)

        schema = {
            # one of "Message Event" or "State Event"
            "typeof": "",
            "typeof_info": "",

            # event type, eg "m.room.member". Note *not* the type of the
            # event object (which should always be 'object').
            "type": None,
            "title": None,
            "desc": None,
            "msgtype": None,
            "content_fields": [
                # <TypeTable>
            ]
        }

        # before we resolve the references, see if the first reference is to
        # the message event or state event schemas, and add typeof info if so.
        base_defs = {
            ROOM_EVENT: "Message Event",
            STATE_EVENT: "State Event"
        }
        if type(json_schema.get("allOf")) == list:
            firstRef = json_schema["allOf"][0]["$ref"]
            if firstRef in base_defs:
                schema["typeof"] = base_defs[firstRef]

        json_schema = resolve_references(filepath, json_schema)

        # add type
        schema["type"] = Units.prop(
            json_schema, "properties/type/enum"
        )[0]

        # add summary and desc
        schema["title"] = json_schema.get("title")
        schema["desc"] = json_schema.get("description", "")

        # walk the object for field info
        schema["content_fields"] = get_tables_for_schema(
            Units.prop(json_schema, "properties/content")
        )

        # grab msgtype if it is the right kind of event
        msgtype = Units.prop(
            json_schema, "properties/content/properties/msgtype/enum"
        )
        if msgtype:
            schema["msgtype"] = msgtype[0]  # enum prop

        # link to msgtypes for m.room.message
        if schema["type"] == "m.room.message" and not msgtype:
            schema["desc"] += (
                " For more information on ``msgtypes``, see "+
                "`m.room.message msgtypes`_."
            )

        # Assign state key info if it has some
        if schema["typeof"] == "State Event":
            skey_desc = Units.prop(
                json_schema, "properties/state_key/description"
            )
            if not skey_desc:
                raise Exception("Missing description for state_key")
            schema["typeof_info"] = "``state_key``: %s" % skey_desc

        return schema
Exemple #2
0
    def read_event_schema(self, filepath):
        logger.info("Reading %s" % filepath)

        with open(filepath, "r") as f:
            json_schema = yaml.load(f, OrderedLoader)

        schema = {
            "typeof": "",
            "typeof_info": "",
            "type": None,
            "title": None,
            "desc": None,
            "msgtype": None,
            "content_fields": [
                # {
                #   title: "<title> key"
                #   rows: [
                #       { key: <key_name>, type: <string>,
                #         desc: <desc>, required: <bool> }
                #   ]
                # }
            ]
        }

        # add typeof
        base_defs = {
            ROOM_EVENT: "Message Event",
            STATE_EVENT: "State Event"
        }
        if type(json_schema.get("allOf")) == list:
            firstRef = json_schema["allOf"][0]["$ref"]
            if firstRef in base_defs:
                schema["typeof"] = base_defs[firstRef]

        json_schema = resolve_references(filepath, json_schema)

        # add type
        schema["type"] = Units.prop(
            json_schema, "properties/type/enum"
        )[0]

        # add summary and desc
        schema["title"] = json_schema.get("title")
        schema["desc"] = json_schema.get("description", "")

        # walk the object for field info
        schema["content_fields"] = get_tables_for_schema(
            Units.prop(json_schema, "properties/content")
        )

        # This is horrible because we're special casing a key on m.room.member.
        # We need to do this because we want to document a non-content object.
        if schema["type"] == "m.room.member":
            invite_room_state = get_tables_for_schema(
                json_schema["properties"]["invite_room_state"]["items"],
            )
            schema["content_fields"].extend(invite_room_state)


        # grab msgtype if it is the right kind of event
        msgtype = Units.prop(
            json_schema, "properties/content/properties/msgtype/enum"
        )
        if msgtype:
            schema["msgtype"] = msgtype[0]  # enum prop

        # link to msgtypes for m.room.message
        if schema["type"] == "m.room.message" and not msgtype:
            schema["desc"] += (
                " For more information on ``msgtypes``, see "+
                "`m.room.message msgtypes`_."
            )

        # Assign state key info if it has some
        if schema["typeof"] == "State Event":
            skey_desc = Units.prop(
                json_schema, "properties/state_key/description"
            )
            if not skey_desc:
                raise Exception("Missing description for state_key")
            schema["typeof_info"] = "``state_key``: %s" % skey_desc

        return schema
Exemple #3
0
    def load_event_schemas(self):
        path = EVENT_SCHEMA
        schemata = {}

        for filename in os.listdir(path):
            if not filename.startswith("m."):
                continue
            filepath = os.path.join(path, filename)
            self.log("Reading %s" % filepath)
            with open(filepath, "r") as f:
                json_schema = yaml.load(f)
                schema = {
                    "typeof":
                    None,
                    "typeof_info":
                    "",
                    "type":
                    None,
                    "title":
                    None,
                    "desc":
                    None,
                    "msgtype":
                    None,
                    "content_fields": [
                        # {
                        #   title: "<title> key"
                        #   rows: [
                        #       { key: <key_name>, type: <string>,
                        #         desc: <desc>, required: <bool> }
                        #   ]
                        # }
                    ]
                }

                # add typeof
                base_defs = {
                    ROOM_EVENT: "Message Event",
                    STATE_EVENT: "State Event"
                }
                if type(json_schema.get("allOf")) == list:
                    schema["typeof"] = base_defs.get(
                        json_schema["allOf"][0].get("$ref"))
                elif json_schema.get("title"):
                    schema["typeof"] = json_schema["title"]

                json_schema = resolve_references(filepath, json_schema)

                # add type
                schema["type"] = Units.prop(json_schema,
                                            "properties/type/enum")[0]

                # add summary and desc
                schema["title"] = json_schema.get("title")
                schema["desc"] = json_schema.get("description", "")

                # walk the object for field info
                schema["content_fields"] = get_tables_for_schema(
                    Units.prop(json_schema, "properties/content"))

                # This is horrible because we're special casing a key on m.room.member.
                # We need to do this because we want to document a non-content object.
                if schema["type"] == "m.room.member":
                    invite_room_state = get_tables_for_schema(
                        json_schema["properties"]["invite_room_state"]
                        ["items"], )
                    schema["content_fields"].extend(invite_room_state)

                # grab msgtype if it is the right kind of event
                msgtype = Units.prop(
                    json_schema, "properties/content/properties/msgtype/enum")
                if msgtype:
                    schema["msgtype"] = msgtype[0]  # enum prop

                # link to msgtypes for m.room.message
                if schema["type"] == "m.room.message" and not msgtype:
                    schema["desc"] += (
                        " For more information on ``msgtypes``, see " +
                        "`m.room.message msgtypes`_.")

                # Assign state key info if it has some
                if schema["typeof"] == "State Event":
                    skey_desc = Units.prop(json_schema,
                                           "properties/state_key/description")
                    if not skey_desc:
                        raise Exception("Missing description for state_key")
                    schema["typeof_info"] = "``state_key``: %s" % skey_desc

                schemata[filename] = schema
        return schemata
Exemple #4
0
    def _load_swagger_meta(self, api, group_name):
        endpoints = []
        for path in api["paths"]:
            for method in api["paths"][path]:
                single_api = api["paths"][path][method]
                full_path = api.get("basePath", "").rstrip("/") + path
                endpoint = {
                    "title":
                    single_api.get("summary", ""),
                    "deprecated":
                    single_api.get("deprecated", False),
                    "desc":
                    single_api.get("description",
                                   single_api.get("summary", "")),
                    "method":
                    method.upper(),
                    "path":
                    full_path.strip(),
                    "requires_auth":
                    "security" in single_api,
                    "rate_limited":
                    429 in single_api.get("responses", {}),
                    "req_param_by_loc": {},
                    "req_body_tables": [],
                    "res_tables": [],
                    "example": {
                        "req": "",
                        "responses": [],
                        "good_response": ""
                    }
                }
                self.log(" ------- Endpoint: %s %s ------- " % (method, path))
                for param in single_api.get("parameters", []):
                    param_loc = param["in"]
                    if param_loc == "body":
                        self._handle_body_param(param, endpoint)
                        continue

                    param_name = param["name"]

                    # description
                    desc = param.get("description", "")
                    if param.get("required"):
                        desc = "**Required.** " + desc

                    # assign value expected for this param
                    val_type = param.get("type")  # integer/string

                    if param.get("enum"):
                        val_type = "enum"
                        desc += (" One of: %s" % json.dumps(param.get("enum")))

                    endpoint["req_param_by_loc"].setdefault(param_loc,
                                                            []).append({
                                                                "key":
                                                                param_name,
                                                                "type":
                                                                val_type,
                                                                "desc":
                                                                desc
                                                            })
                # endfor[param]

                good_response = None
                for code, res in single_api.get("responses", {}).items():
                    if not good_response and code == 200:
                        good_response = res
                    description = res.get("description", "")
                    example = res.get("examples",
                                      {}).get("application/json", "")
                    if description and example:
                        endpoint["example"]["responses"].append({
                            "code":
                            code,
                            "description":
                            description,
                            "example":
                            example,
                        })

                # form example request if it has one. It "has one" if all params
                # have either "x-example" or a "schema" with an "example".
                params_missing_examples = [
                    p for p in single_api.get("parameters", [])
                    if ("x-example" not in p
                        and not Units.prop(p, "schema/example"))
                ]
                if len(params_missing_examples) == 0:
                    path_template = api.get("basePath", "").rstrip("/") + path
                    qps = []
                    body = ""
                    for param in single_api.get("parameters", []):
                        if param["in"] == "path":
                            path_template = path_template.replace(
                                "{%s}" % param["name"],
                                urllib.quote(param["x-example"]))
                        elif param["in"] == "body":
                            body = param["schema"]["example"]
                        elif param["in"] == "query":
                            example = param["x-example"]
                            if type(example) == list:
                                for value in example:
                                    qps.append((param["name"], value))
                            else:
                                qps.append((param["name"], example))
                    query_string = "" if len(
                        qps) == 0 else "?" + urllib.urlencode(qps)
                    if body:
                        endpoint["example"][
                            "req"] = "%s %s%s HTTP/1.1\nContent-Type: application/json\n\n%s" % (
                                method.upper(), path_template, query_string,
                                body)
                    else:
                        endpoint["example"]["req"] = "%s %s%s HTTP/1.1\n\n" % (
                            method.upper(), path_template, query_string)

                else:
                    self.log(
                        "The following parameters are missing examples :( \n %s"
                        % [p["name"] for p in params_missing_examples])

                # add response params if this API has any.
                if good_response:
                    self.log("Found a 200 response for this API")
                    res_type = Units.prop(good_response, "schema/type")
                    res_name = Units.prop(good_response, "schema/name")
                    if res_type and res_type not in ["object", "array"]:
                        # response is a raw string or something like that
                        good_table = {
                            "title":
                            None,
                            "rows": [{
                                "key":
                                "<" + res_type +
                                ">" if not res_name else res_name,
                                "type":
                                res_type,
                                "desc":
                                res.get("description", ""),
                                "req_str":
                                ""
                            }]
                        }
                        if good_response.get("headers"):
                            for (header_name, header
                                 ) in good_response.get("headers").iteritems():
                                good_table["rows"].append({
                                    "key":
                                    header_name,
                                    "type":
                                    "Header<" + header["type"] + ">",
                                    "desc":
                                    header["description"],
                                    "req_str":
                                    ""
                                })
                        endpoint["res_tables"].append(good_table)
                    elif res_type and Units.prop(good_response,
                                                 "schema/properties"):
                        # response is an object:
                        schema = good_response["schema"]
                        res_tables = get_tables_for_schema(
                            schema,
                            mark_required=False,
                        )
                        endpoint["res_tables"].extend(res_tables)
                    elif res_type and Units.prop(good_response,
                                                 "schema/items"):
                        # response is an array:
                        # FIXME: Doesn't recurse at all.
                        schema = good_response["schema"]
                        array_type = Units.prop(schema, "items/type")
                        if Units.prop(schema, "items/allOf"):
                            array_type = (Units.prop(schema, "items/title"))
                        endpoint["res_tables"].append({
                            "title":
                            schema.get("title", ""),
                            "rows": [{
                                "key": "N/A",
                                "type": ("[%s]" % array_type),
                                "desc": schema.get("description", ""),
                                "req_str": ""
                            }]
                        })

                for response_table in endpoint["res_tables"]:
                    self.log("Response: %s" % response_table["title"])
                    for r in response_table["rows"]:
                        self.log("Row: %s" % r)
                if len(endpoint["res_tables"]) == 0:
                    self.log(
                        "This API appears to have no response table. Are you "
                        + "sure this API returns no parameters?")

                endpoints.append(endpoint)

        return {
            "base": api.get("basePath").rstrip("/"),
            "group": group_name,
            "endpoints": endpoints,
        }
Exemple #5
0
    def _load_swagger_meta(self, api, group_name):
        endpoints = []
        for path in api["paths"]:
            for method in api["paths"][path]:
                single_api = api["paths"][path][method]
                full_path = api.get("basePath", "").rstrip("/") + path
                endpoint = {
                    "title": single_api.get("summary", ""),
                    "deprecated": single_api.get("deprecated", False),
                    "desc": single_api.get("description", single_api.get("summary", "")),
                    "method": method.upper(),
                    "path": full_path.strip(),
                    "requires_auth": "security" in single_api,
                    "rate_limited": 429 in single_api.get("responses", {}),
                    "req_param_by_loc": {},
                    "req_body_tables": [],
                    "res_tables": [],
                    "responses": [],
                    "example": {
                        "req": "",
                    }
                }
                self.log(" ------- Endpoint: %s %s ------- " % (method, path))
                for param in single_api.get("parameters", []):
                    param_loc = param["in"]
                    if param_loc == "body":
                        self._handle_body_param(param, endpoint)
                        continue

                    param_name = param["name"]

                    # description
                    desc = param.get("description", "")
                    if param.get("required"):
                        desc = "**Required.** " + desc

                    # assign value expected for this param
                    val_type = param.get("type") # integer/string

                    if param.get("enum"):
                        val_type = "enum"
                        desc += (
                            " One of: %s" % json.dumps(param.get("enum"))
                        )

                    endpoint["req_param_by_loc"].setdefault(param_loc, []).append({
                        "key": param_name,
                        "type": val_type,
                        "desc": desc
                    })
                # endfor[param]

                good_response = None
                for code in sorted(single_api.get("responses", {}).keys()):
                    res = single_api["responses"][code]
                    if not good_response and code == 200:
                        good_response = res
                    description = res.get("description", "")
                    example = res.get("examples", {}).get("application/json", "")
                    endpoint["responses"].append({
                        "code": code,
                        "description": description,
                        "example": example,
                    })

                path_template = api.get("basePath", "").rstrip("/") + path
                qps = []
                body = ""
                for param in single_api.get("parameters", []):
                    try:
                        example = get_example_for_param(param)

                        if not example:
                            self.log(
                                "The parameter %s is missing an example." %
                                param["name"])
                            continue

                        if param["in"] == "path":
                            path_template = path_template.replace(
                                "{%s}" % param["name"], urllib.quote(example)
                            )
                        elif param["in"] == "body":
                            body = example
                        elif param["in"] == "query":
                            if type(example) == list:
                                for value in example:
                                    qps.append((param["name"], value))
                                else:
                                    qps.append((param["name"], example))
                    except Exception, e:
                        raise Exception("Error handling parameter %s" % param["name"],
                                        e)

                query_string = "" if len(qps) == 0 else "?"+urllib.urlencode(qps)
                if body:
                    endpoint["example"]["req"] = "%s %s%s HTTP/1.1\nContent-Type: application/json\n\n%s" % (
                        method.upper(), path_template, query_string, body
                    )
                else:
                    endpoint["example"]["req"] = "%s %s%s HTTP/1.1\n\n" % (
                        method.upper(), path_template, query_string
                    )

                # add response params if this API has any.
                if good_response:
                    self.log("Found a 200 response for this API")
                    res_type = Units.prop(good_response, "schema/type")
                    res_name = Units.prop(good_response, "schema/name")
                    if res_type and res_type not in ["object", "array"]:
                        # response is a raw string or something like that
                        good_table = {
                            "title": None,
                            "rows": [{
                                "key": "<" + res_type + ">" if not res_name else res_name,
                                "type": res_type,
                                "desc": res.get("description", ""),
                                "req_str": ""
                            }]
                        }
                        if good_response.get("headers"):
                            for (header_name, header) in good_response.get("headers").iteritems():
                                good_table["rows"].append({
                                    "key": header_name,
                                    "type": "Header<" + header["type"] + ">",
                                    "desc": header["description"],
                                    "req_str": ""
                                })
                        endpoint["res_tables"].append(good_table)
                    elif res_type and Units.prop(good_response, "schema/properties"):
                        # response is an object:
                        schema = good_response["schema"]
                        res_tables = get_tables_for_schema(schema,
                            mark_required=False,
                        )
                        endpoint["res_tables"].extend(res_tables)
                    elif res_type and Units.prop(good_response, "schema/items"):
                        # response is an array:
                        # FIXME: Doesn't recurse at all.
                        schema = good_response["schema"]
                        array_type = Units.prop(schema, "items/type")
                        if Units.prop(schema, "items/allOf"):
                            array_type = (
                                Units.prop(schema, "items/title")
                            )
                        endpoint["res_tables"].append({
                            "title": schema.get("title", ""),
                            "rows": [{
                                "key": "N/A",
                                "type": ("[%s]" % array_type),
                                "desc": schema.get("description", ""),
                                "req_str": ""
                            }]
                        })

                for response_table in endpoint["res_tables"]:
                    self.log("Response: %s" % response_table["title"])
                    for r in response_table["rows"]:
                        self.log("Row: %s" % r)
                if len(endpoint["res_tables"]) == 0:
                    self.log(
                        "This API appears to have no response table. Are you " +
                        "sure this API returns no parameters?"
                    )

                endpoints.append(endpoint)
Exemple #6
0
    def read_event_schema(self, filepath):
        logger.info("Reading %s" % filepath)

        with open(filepath, "r", encoding="utf-8") as f:
            json_schema = yaml.load(f, OrderedLoader)

        schema = {
            # one of "Message Event" or "State Event"
            "typeof": "",
            "typeof_info": "",

            # event type, eg "m.room.member". Note *not* the type of the
            # event object (which should always be 'object').
            "type": None,
            "title": None,
            "desc": None,
            "msgtype": None,
            "content_fields": [
                # <TypeTable>
            ]
        }

        # before we resolve the references, see if the first reference is to
        # the message event or state event schemas, and add typeof info if so.
        base_defs = {
            ROOM_EVENT: "Message Event",
            STATE_EVENT: "State Event"
        }
        if type(json_schema.get("allOf")) == list:
            firstRef = json_schema["allOf"][0]["$ref"]
            if firstRef in base_defs:
                schema["typeof"] = base_defs[firstRef]

        json_schema = resolve_references(filepath, json_schema)

        # add type
        schema["type"] = Units.prop(
            json_schema, "properties/type/enum"
        )[0]

        # add summary and desc
        schema["title"] = json_schema.get("title")
        schema["desc"] = json_schema.get("description", "")

        # walk the object for field info
        schema["content_fields"] = get_tables_for_schema(
            Units.prop(json_schema, "properties/content")
        )

        # grab msgtype if it is the right kind of event
        msgtype = Units.prop(
            json_schema, "properties/content/properties/msgtype/enum"
        )
        if msgtype:
            schema["msgtype"] = msgtype[0]  # enum prop

        # link to msgtypes for m.room.message
        if schema["type"] == "m.room.message" and not msgtype:
            schema["desc"] += (
                " For more information on ``msgtypes``, see "+
                "`m.room.message msgtypes`_."
            )

        # Assign state key info if it has some
        if schema["typeof"] == "State Event":
            skey_desc = Units.prop(
                json_schema, "properties/state_key/description"
            )
            if not skey_desc:
                raise Exception("Missing description for state_key")
            schema["typeof_info"] = "``state_key``: %s" % skey_desc

        return schema