Example #1
0
class EnvironmentsListPresenter:
    def __init__(self, parent_view=None):
        self.parent_view = parent_view
        self.app_state_interactor = AppStateInteractor()
        app_settings.app_data_writer.signals.environment_added.connect(
            self.refresh)
        app_settings.app_data_writer.signals.environment_removed.connect(
            self.refresh)
        app_settings.app_data_writer.signals.environment_renamed.connect(
            self.refresh)

    def __get_combox_box(self):
        toolbar_actions = self.parent_view.tool_bar.actions()
        tags_list_action = next(act for act in toolbar_actions
                                if act.text() == "Environmnents")
        return tags_list_action.defaultWidget()

    def on_env_changed(self, new_env):
        if not new_env:
            return

        self.app_state_interactor.update_selected_environment(new_env)

    def refresh(self):
        all_envs = app_settings.app_data_cache.get_environments()
        envs_list_field = self.__get_combox_box()
        selected_env = app_settings.app_data_cache.get_appstate_environment()
        envs_list_field.clear()
        for env in all_envs:
            envs_list_field.addItem(env.name)

        envs_list_field.setCurrentText(selected_env)
Example #2
0
 def __init__(self, parent_view=None):
     self.parent_view = parent_view
     self.app_state_interactor = AppStateInteractor()
     app_settings.app_data_writer.signals.environment_added.connect(
         self.refresh)
     app_settings.app_data_writer.signals.environment_removed.connect(
         self.refresh)
     app_settings.app_data_writer.signals.environment_renamed.connect(
         self.refresh)
Example #3
0
class TagsListPresenter:
    def __init__(self, parent_view=None):
        self.parent_view = parent_view
        self.app_state_interactor = AppStateInteractor()
        app_settings.app_data_writer.signals.project_info_updated.connect(self.refresh)

    def __get_combox_box(self):
        toolbar_actions = self.parent_view.tool_bar.actions()
        tags_list_action = next(act for act in toolbar_actions if act.text() == 'Tags')
        return tags_list_action.defaultWidget()

    def on_tag_changed(self, tag_name):
        self.app_state_interactor.update_selected_tag(tag_name)

    def refresh(self):
        project_info = app_settings.app_data_reader.get_or_create_project_info()
        tags_list_field = self.__get_combox_box()
        selected_tag = tags_list_field.currentText()
        tags_list_field.clear()
        tags_list_field.addItem(DEFAULT_TAG)
        for tag in project_info.tags:
            tags_list_field.addItem(tag.name)

        tags_list_field.setCurrentText(selected_tag)
Example #4
0
class CurlImporter:
    name: str = "Curl"
    input_type: str = "text"
    app_state_interactor = AppStateInteractor()

    def import_data(self, curl_command):
        try:
            ctx: ParsedContext = uncurl.parse_context(curl_command)
            api_call = self.__extract_api_call(ctx)
            return None, [api_call]
        except BaseException:
            raise SyntaxError("Unable to parse curl command")

    def __extract_api_call(self, ctx):
        url, qs = split_url_qs(ctx.url.strip())
        return ApiCall(
            title="Curl command",
            description=f"Imported from {url}",
            http_url=url,
            http_method=ctx.method,
            http_request_body=self.__extract_request_body(ctx),
            form_params=self.__extract_form_data(ctx),
            http_params=qs,
            http_headers=self.__extract_header_data(ctx.headers),
            sequence_number=self.app_state_interactor.update_sequence_number(),
        )

    def __extract_header_data(self, headers):
        return {hk: DynamicStringData(value=hv) for hk, hv in headers.items()}

    def __extract_form_data(self, ctx: ParsedContext):
        form_content_type = (ctx.headers.get(
            "Content-Type", None) == "application/x-www-form-urlencoded")
        if form_content_type:
            return {
                fk: DynamicStringData(value=",".join(fv))
                for fk, fv in parse.parse_qs(ctx.data).items()
            }
        else:
            return {}

    def __extract_request_body(self, ctx: ParsedContext):
        form_content_type = (ctx.headers.get(
            "Content-Type", None) == "application/x-www-form-urlencoded")
        if not form_content_type:
            return ctx.data or ""
        else:
            return ""
class PostmanCollectionImporter:
    name: str = "Postman Collections v2"
    input_type: str = "file"
    var_selector = r"({{(\w+)}})+"
    app_state_interactor = AppStateInteractor()

    def import_data(self, file_path):
        self.__validate_file(file_path)
        json_data = json.loads(Path(file_path).read_text())
        postman_data: PostmanDataModel = cattr.structure(
            json_data, PostmanDataModel)
        return None, [
            self.__extract_api_call(item, sub_item)
            for item in postman_data.item for sub_item in item.item
        ]

    def __extract_api_call(self, item: PostmanItem, sub_item: PostmanSubItem):
        api_call = ApiCall(
            tags=[item.name],
            title=sub_item.name,
            description=sub_item.name,
            http_url=self.__internal_variables(
                sub_item.request.url.get('raw')),
            http_method=sub_item.request.method,
            http_request_body=self.__internal_variables(
                sub_item.request.body.get('raw')),
            http_headers={
                k: DynamicStringData(display_text=self.__internal_variables(v))
                for k, v in kv_list_to_dict(sub_item.request.header).items()
            },
            sequence_number=self.app_state_interactor.update_sequence_number())
        return api_call

    def __internal_variables(self, input_str):
        return re.sub(self.var_selector, r"${\2}", input_str, count=0)

    def __validate_file(self, file_path):
        if not (Path(file_path).exists() and Path(file_path).is_file()):
            raise FileNotFoundError(
                f"Path {file_path} should be a valid file path")
class OpenApiV3Importer:
    name: str = "OpenApi(v3)"
    input_type: str = "file"
    app_state_interactor = AppStateInteractor()

    def import_data(self, file_path):
        openapi_spec: ResolvingParser = self.__load_swagger_spec(file_path)
        project_info = self.__extract_project_info(openapi_spec)
        base_path = project_info.servers[0] if project_info.servers else ""
        api_calls = self.__extract_api_calls(base_path, openapi_spec)
        return project_info, api_calls

    def __load_swagger_spec(self, file_path):
        return ResolvingParser(url=file_path)

    def __extract_project_info(self, openapi_spec):
        openapi_info = openapi_spec.specification["info"]
        openapi_tags = openapi_spec.specification["tags"]
        openapi_servers = openapi_spec.specification["servers"]
        info = ProjectInfo(
            info=openapi_info["description"].strip(),
            title=openapi_info["title"].strip(),
            version=openapi_info["version"].strip(),
            contact_email=openapi_info.get("contact", {}).get("email",
                                                              "").strip(),
            contact_name=openapi_info.get("contact", {}).get("name",
                                                             "").strip(),
            tags=[
                TagInfo(t["name"].strip(), t["description"].strip())
                for t in openapi_tags
            ],
            servers=[server.get("url", "") for server in openapi_servers])
        return info

    def __extract_api_calls(self, base_path, openapi_spec):
        openapi_paths = openapi_spec.specification["paths"]
        return [
            self.__convert_to_api_call(base_path, path, path_spec, api_method,
                                       api_method_spec, content_type, schema)
            for path, path_spec in openapi_paths.items()
            for api_method, api_method_spec in path_spec.items()
            for content_type, schema in self.__request_content_types(
                api_method_spec).items()
            if api_method.strip().lower() in VALID_METHODS_OPENAPI_V3
        ]

    def __request_content_types(self, api_method_spec):
        has_request_body = type(api_method_spec) is dict \
                           and api_method_spec.get("requestBody", False) \
                           and api_method_spec.get("requestBody").get("content", False)

        if not has_request_body:
            return {None: None}
        else:
            return api_method_spec["requestBody"]["content"]

    def __process_parameters(self, path_spec, api_method_spec):
        path_params = path_spec.get("parameters", [])
        method_params = api_method_spec.get("parameters", [])
        all_params = path_params + method_params
        data = sorted(all_params, key=itemgetter("in"))
        grouped_data = groupby(data, key=itemgetter("in"))

        def params(pv):
            return {p["name"]: DynamicStringData(display_text="") for p in pv}

        gp = {k: params(data) for k, data in grouped_data}

        return gp.get("header", {}), gp.get("query", {}), gp.get("form", {})

    def __convert_to_api_call(self, base_path, path, path_spec, api_method,
                              api_method_spec, content_type, schema):
        logging.info(f"Converting {api_method} - {content_type} - {path}")
        headers_params, query_params, form_params = self.__process_parameters(
            path_spec, api_method_spec)

        if content_type:
            headers_params["Content-Type"] = DynamicStringData(
                display_text=content_type)

        return ApiCall(
            tags=[t for t in api_method_spec.get("tags", [])],
            http_url=f"{base_path}{path}",
            http_method=api_method.upper(),
            title=api_method_spec.get("summary", ""),
            http_request_body=self.__extract_request_body(
                content_type, schema),
            description=api_method_spec.get("description", ""),
            http_headers=headers_params,
            http_params=query_params,
            form_params=form_params,
            sequence_number=self.app_state_interactor.update_sequence_number())

    def __extract_request_body(self, content_type, schema):
        if schema:
            return json.dumps(json_from_schema(schema.get("schema")))

        return ""
Example #7
0
 def __init__(self, parent_view=None):
     self.parent_view = parent_view
     self.app_state_interactor = AppStateInteractor()
     app_settings.app_data_writer.signals.project_info_updated.connect(self.refresh)
Example #8
0
 def __init__(self, parent_view):
     self.view = parent_view
     self.app_state_interactor = AppStateInteractor()
     self.view.btn_add_request.pressed.connect(self.on_btn_add_request)
Example #9
0
class EmptyFramePresenter:
    def __init__(self, parent_view):
        self.view = parent_view
        self.app_state_interactor = AppStateInteractor()
        self.view.btn_add_request.pressed.connect(self.on_btn_add_request)

    def on_btn_add_request(self):
        api_call = ApiCall()
        api_call.http_url = "http://127.0.0.1:8000/get"
        api_call.http_method = "GET"
        api_call.title = "Get httpbin"
        api_call.description = "Httpbin call to get request data"
        api_call.sequence_number = self.app_state_interactor.update_sequence_number(
        )

        api_call_interactor.add_api_call(api_call)

        self.focus_http_url()

    def on_btn_add_separator(self):
        api_call = ApiCall()
        api_call.title = "Separator"
        api_call.is_separator = True
        api_call.sequence_number = self.app_state_interactor.update_sequence_number(
        )
        api_call_interactor.add_api_call(api_call)

    def focus_http_url(self):
        self.__select_text(self.view.txt_http_url)

    def focus_headers(self):
        self.view.tabWidget.setCurrentIndex(1)

    def focus_query_params(self):
        self.view.tabWidget.setCurrentIndex(2)

    def focus_form_params(self):
        self.view.tabWidget.setCurrentIndex(3)

    def focus_request_body(self):
        self.view.tabWidget.setCurrentIndex(4)

    def focus_mocked_response(self):
        self.view.tabWidget.setCurrentIndex(5)

    def focus_http_method(self):
        self.view.cmb_http_method.setFocus(True)
        self.view.cmb_http_method.showPopup()

    def focus_description(self):
        self.view.tabWidget.setCurrentIndex(0)
        self.__select_text(self.view.txt_api_title)

    def __select_text(self, txt_field):
        txt_field.setFocus(True)
        txt_field_value = txt_field.text()
        txt_field.setSelection(0, len(txt_field_value))

    def display(self):
        """Called when all API calls are removed from list"""
        self.view.empty_frame.show()