stoobly-agent 0.33.7__py3-none-any.whl → 0.34.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- stoobly_agent/__init__.py +1 -1
- stoobly_agent/app/cli/dev_tools_cli.py +1 -0
- stoobly_agent/app/cli/endpoint_cli.py +25 -2
- stoobly_agent/app/cli/helpers/endpoint_facade.py +22 -1
- stoobly_agent/app/cli/helpers/endpoints_import_context.py +57 -0
- stoobly_agent/app/cli/helpers/endpoints_import_service.py +152 -0
- stoobly_agent/app/cli/helpers/openapi_endpoint_adapter.py +111 -6
- stoobly_agent/app/cli/helpers/replay_facade.py +4 -0
- stoobly_agent/app/cli/request_cli.py +2 -0
- stoobly_agent/app/cli/scenario_cli.py +2 -0
- stoobly_agent/app/cli/types/test.py +2 -0
- stoobly_agent/app/models/factories/resource/local_db/helpers/request_builder.py +1 -1
- stoobly_agent/app/models/types/endpoint.py +28 -2
- stoobly_agent/app/proxy/handle_mock_service.py +15 -3
- stoobly_agent/app/proxy/intercept_settings.py +39 -0
- stoobly_agent/app/proxy/mock/eval_fixtures_service.py +61 -0
- stoobly_agent/app/proxy/mock/types/__init__.py +10 -0
- stoobly_agent/app/proxy/replay/replay_request_service.py +11 -3
- stoobly_agent/app/proxy/run.py +6 -0
- stoobly_agent/app/proxy/test/context.py +12 -0
- stoobly_agent/app/proxy/test/context_abc.py +15 -0
- stoobly_agent/app/settings/intercept_settings.py +1 -1
- stoobly_agent/cli.py +13 -2
- stoobly_agent/config/constants/custom_headers.py +2 -0
- stoobly_agent/config/constants/env_vars.py +2 -0
- stoobly_agent/lib/api/api.py +4 -0
- stoobly_agent/lib/api/body_param_names_resource.py +36 -0
- stoobly_agent/lib/api/endpoints_resource.py +9 -2
- stoobly_agent/lib/api/header_names_resource.py +36 -0
- stoobly_agent/lib/api/interfaces/endpoints.py +2 -0
- stoobly_agent/lib/api/query_param_names_resource.py +36 -0
- stoobly_agent/lib/api/response_header_names_resource.py +36 -0
- stoobly_agent/lib/api/response_param_names_resource.py +36 -0
- stoobly_agent/public/0-es2015.a7e60cafc0868f87a771.js +1 -0
- stoobly_agent/public/0-es5.a7e60cafc0868f87a771.js +1 -0
- stoobly_agent/public/1-es2015.cb071776436f10954db5.js +1 -0
- stoobly_agent/public/1-es5.cb071776436f10954db5.js +1 -0
- stoobly_agent/public/10-es2015.bb1702aaf3968a2cb521.js +1 -0
- stoobly_agent/public/10-es5.bb1702aaf3968a2cb521.js +1 -0
- stoobly_agent/public/12-es2015.591ec692afb8f8d13842.js +1 -0
- stoobly_agent/public/12-es5.591ec692afb8f8d13842.js +1 -0
- stoobly_agent/public/13-es2015.f381e7d6ff361b669e12.js +1 -0
- stoobly_agent/public/13-es5.f381e7d6ff361b669e12.js +1 -0
- stoobly_agent/public/14-es2015.1ffb225a16d6292dbddd.js +1 -0
- stoobly_agent/public/14-es5.1ffb225a16d6292dbddd.js +1 -0
- stoobly_agent/public/15-es2015.2cf39bcaeb0ea2c52297.js +1 -0
- stoobly_agent/public/15-es5.2cf39bcaeb0ea2c52297.js +1 -0
- stoobly_agent/public/16-es2015.0e9422b274e642f95e41.js +1 -0
- stoobly_agent/public/16-es5.0e9422b274e642f95e41.js +1 -0
- stoobly_agent/public/17-es2015.7fb08367a22d1e34aed7.js +1 -0
- stoobly_agent/public/17-es5.7fb08367a22d1e34aed7.js +1 -0
- stoobly_agent/public/18-es2015.5caa4789d1c335e628f2.js +1 -0
- stoobly_agent/public/18-es5.5caa4789d1c335e628f2.js +1 -0
- stoobly_agent/public/19-es2015.8049aef58c329c500f9b.js +1 -0
- stoobly_agent/public/19-es5.8049aef58c329c500f9b.js +1 -0
- stoobly_agent/public/2-es2015.8f184ac63348ba447b1f.js +1 -0
- stoobly_agent/public/2-es5.8f184ac63348ba447b1f.js +1 -0
- stoobly_agent/public/20-es2015.473486aabfa4d4a6431b.js +1 -0
- stoobly_agent/public/20-es5.473486aabfa4d4a6431b.js +1 -0
- stoobly_agent/public/21-es2015.63ed4e6b242fbc047bd6.js +1 -0
- stoobly_agent/public/21-es5.63ed4e6b242fbc047bd6.js +1 -0
- stoobly_agent/public/22-es2015.df183804415330639987.js +1 -0
- stoobly_agent/public/22-es5.df183804415330639987.js +1 -0
- stoobly_agent/public/23-es2015.0da63b056fabde91bb0b.js +1 -0
- stoobly_agent/public/23-es5.0da63b056fabde91bb0b.js +1 -0
- stoobly_agent/public/28-es2015.9fe030e9d3b0e52239aa.js +1 -0
- stoobly_agent/public/28-es5.9fe030e9d3b0e52239aa.js +1 -0
- stoobly_agent/public/29-es2015.9b440f22de725732e5ab.js +1 -0
- stoobly_agent/public/29-es5.9b440f22de725732e5ab.js +1 -0
- stoobly_agent/public/30-es2015.6ad2a5126b0a27c1e7c6.js +1 -0
- stoobly_agent/public/30-es5.6ad2a5126b0a27c1e7c6.js +1 -0
- stoobly_agent/public/31-es2015.f4291150f35d54ff19ca.js +1 -0
- stoobly_agent/public/31-es5.f4291150f35d54ff19ca.js +1 -0
- stoobly_agent/public/32-es2015.c8f6ccb43bdba0adf199.js +1 -0
- stoobly_agent/public/32-es5.c8f6ccb43bdba0adf199.js +1 -0
- stoobly_agent/public/33-es2015.f985e93402ebf86322ef.js +1 -0
- stoobly_agent/public/33-es5.f985e93402ebf86322ef.js +1 -0
- stoobly_agent/public/34-es2015.0e1961fb3cf649a52d49.js +1 -0
- stoobly_agent/public/34-es5.0e1961fb3cf649a52d49.js +1 -0
- stoobly_agent/public/35-es2015.a4ae56a89c0324397624.js +1 -0
- stoobly_agent/public/35-es5.a4ae56a89c0324397624.js +1 -0
- stoobly_agent/public/36-es2015.b8fdd25590a79c820119.js +1 -0
- stoobly_agent/public/36-es5.b8fdd25590a79c820119.js +1 -0
- stoobly_agent/public/37-es2015.6567a0ce4cf87ad7287b.js +1 -0
- stoobly_agent/public/37-es5.6567a0ce4cf87ad7287b.js +1 -0
- stoobly_agent/public/38-es2015.6f6d751bff41d84d727a.js +1 -0
- stoobly_agent/public/38-es5.6f6d751bff41d84d727a.js +1 -0
- stoobly_agent/public/39-es2015.47f63177e7d4509a22fa.js +1 -0
- stoobly_agent/public/39-es5.47f63177e7d4509a22fa.js +1 -0
- stoobly_agent/public/3rdpartylicenses.txt +2418 -0
- stoobly_agent/public/4-es2015.182e1ce1811ef67571fb.js +1 -0
- stoobly_agent/public/4-es5.182e1ce1811ef67571fb.js +1 -0
- stoobly_agent/public/40-es2015.5333067cdc4077c7495a.js +1 -0
- stoobly_agent/public/40-es5.5333067cdc4077c7495a.js +1 -0
- stoobly_agent/public/41-es2015.7a2434380c81c11ff2c5.js +1 -0
- stoobly_agent/public/41-es5.7a2434380c81c11ff2c5.js +1 -0
- stoobly_agent/public/42-es2015.5dde662fe1e3b4e4bdd1.js +1 -0
- stoobly_agent/public/42-es5.5dde662fe1e3b4e4bdd1.js +1 -0
- stoobly_agent/public/43-es2015.608e917d689b9bb762cb.js +1 -0
- stoobly_agent/public/43-es5.608e917d689b9bb762cb.js +1 -0
- stoobly_agent/public/44-es2015.2ae5fea15b5e8c2681d3.js +1 -0
- stoobly_agent/public/44-es5.2ae5fea15b5e8c2681d3.js +1 -0
- stoobly_agent/public/45-es2015.e46f228c795174428515.js +1 -0
- stoobly_agent/public/45-es5.e46f228c795174428515.js +1 -0
- stoobly_agent/public/46-es2015.22a0d8e0b4bbfb513741.js +1 -0
- stoobly_agent/public/46-es5.22a0d8e0b4bbfb513741.js +1 -0
- stoobly_agent/public/47-es2015.3878e5d1d692107748f3.js +1 -0
- stoobly_agent/public/47-es5.3878e5d1d692107748f3.js +1 -0
- stoobly_agent/public/5-es2015.aba7173be56fc19b4b6f.js +1 -0
- stoobly_agent/public/5-es5.aba7173be56fc19b4b6f.js +1 -0
- stoobly_agent/public/6-es2015.5fb726c0555664300974.js +1 -0
- stoobly_agent/public/6-es5.5fb726c0555664300974.js +1 -0
- stoobly_agent/public/7-es2015.9b9ab4adf24d13bdc2f8.js +1 -0
- stoobly_agent/public/7-es5.9b9ab4adf24d13bdc2f8.js +1 -0
- stoobly_agent/public/8-es2015.cdd7dce2a24aaf9d974f.js +1 -0
- stoobly_agent/public/8-es5.cdd7dce2a24aaf9d974f.js +1 -0
- stoobly_agent/public/9-es2015.cdde98f2537997afbf0f.js +1 -0
- stoobly_agent/public/9-es5.cdde98f2537997afbf0f.js +1 -0
- stoobly_agent/public/CHANGELOG.md +58 -0
- stoobly_agent/public/README.md +264 -0
- stoobly_agent/public/_redirects +1 -0
- stoobly_agent/public/assets/img/demo/1.jpg +0 -0
- stoobly_agent/public/assets/img/demo/2.jpg +0 -0
- stoobly_agent/public/assets/img/demo/3.jpg +0 -0
- stoobly_agent/public/assets/img/demo/4.jpg +0 -0
- stoobly_agent/public/assets/img/demo/5.jpg +0 -0
- stoobly_agent/public/assets/img/demo/6.jpg +0 -0
- stoobly_agent/public/assets/img/demo/7.jpg +0 -0
- stoobly_agent/public/assets/img/demo/8.jpg +0 -0
- stoobly_agent/public/assets/img/demo/landscape.jpg +0 -0
- stoobly_agent/public/assets/img/demo/mountain-cinematic.jpg +0 -0
- stoobly_agent/public/assets/img/illustrations/checklist.svg +164 -0
- stoobly_agent/public/assets/img/illustrations/data_center.svg +150 -0
- stoobly_agent/public/assets/img/illustrations/idea.svg +213 -0
- stoobly_agent/public/assets/img/illustrations/it_support.svg +168 -0
- stoobly_agent/public/assets/img/illustrations/peak_mountain_3.svg +262 -0
- stoobly_agent/public/assets/img/illustrations/under_constructions_1.svg +282 -0
- stoobly_agent/public/assets/img/logo/colored.png +0 -0
- stoobly_agent/public/assets/img/logo/colored.svg +9 -0
- stoobly_agent/public/assets/img/logo/white.png +0 -0
- stoobly_agent/public/assets/img/logo/white.svg +8 -0
- stoobly_agent/public/common-es2015.6f230354b12587f9be81.js +1 -0
- stoobly_agent/public/common-es5.6f230354b12587f9be81.js +1 -0
- stoobly_agent/public/favicon.ico +0 -0
- stoobly_agent/public/index.html +118 -0
- stoobly_agent/public/main-es2015.081bbd2709f22e95933e.js +1 -0
- stoobly_agent/public/main-es5.081bbd2709f22e95933e.js +1 -0
- stoobly_agent/public/polyfills-es2015.8ce2adc69f283f6c4c5e.js +1 -0
- stoobly_agent/public/polyfills-es5.7530172ddcec11a10eb3.js +1 -0
- stoobly_agent/public/runtime-es2015.362e49d383fb724f5414.js +1 -0
- stoobly_agent/public/runtime-es5.362e49d383fb724f5414.js +1 -0
- stoobly_agent/public/styles.ca104d947fbb2eebbeca.css +6 -0
- stoobly_agent/test/app/cli/helpers/openapi_endpoint_adapter_additional_props_test.py +34 -0
- stoobly_agent/test/app/cli/helpers/openapi_endpoint_adapter_missing_info_test.py +80 -3
- stoobly_agent/test/app/cli/helpers/openapi_endpoint_adapter_missing_oauth2_scopes_test.py +82 -1
- stoobly_agent/test/app/cli/helpers/openapi_endpoint_adapter_missing_servers_test.py +80 -3
- stoobly_agent/test/app/cli/helpers/openapi_endpoint_adapter_test.py +617 -4
- stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION +1 -1
- stoobly_agent/test/app/proxy/mock/eval_fixtures_service_test.py +95 -0
- {stoobly_agent-0.33.7.dist-info → stoobly_agent-0.34.1.dist-info}/METADATA +1 -1
- {stoobly_agent-0.33.7.dist-info → stoobly_agent-0.34.1.dist-info}/RECORD +164 -35
- {stoobly_agent-0.33.7.dist-info → stoobly_agent-0.34.1.dist-info}/LICENSE +0 -0
- {stoobly_agent-0.33.7.dist-info → stoobly_agent-0.34.1.dist-info}/WHEEL +0 -0
- {stoobly_agent-0.33.7.dist-info → stoobly_agent-0.34.1.dist-info}/entry_points.txt +0 -0
@@ -1,5 +1,6 @@
|
|
1
1
|
import os
|
2
2
|
import pdb
|
3
|
+
import yaml
|
3
4
|
|
4
5
|
from runpy import run_path
|
5
6
|
from typing import List, Union
|
@@ -37,6 +38,9 @@ class InterceptSettings:
|
|
37
38
|
self.__lifecycle_hooks = None
|
38
39
|
self.__initialize_lifecycle_hooks()
|
39
40
|
|
41
|
+
self.__response_fixtures = None
|
42
|
+
self.__initialize_response_fixtures()
|
43
|
+
|
40
44
|
@property
|
41
45
|
def settings(self):
|
42
46
|
return self.__settings
|
@@ -102,6 +106,14 @@ class InterceptSettings:
|
|
102
106
|
except InvalidProjectKey:
|
103
107
|
pass
|
104
108
|
|
109
|
+
@property
|
110
|
+
def public_directory_path(self):
|
111
|
+
if self.__headers and custom_headers.PUBLIC_DIRECTORY_PATH in self.__headers:
|
112
|
+
return self.__headers[custom_headers.PUBLIC_DIRECTORY_PATH]
|
113
|
+
|
114
|
+
if os.environ.get(env_vars.AGENT_PUBLIC_DIRECTORY_PATH):
|
115
|
+
return os.environ[env_vars.AGENT_PUBLIC_DIRECTORY_PATH]
|
116
|
+
|
105
117
|
@property
|
106
118
|
def remote_project_key(self):
|
107
119
|
# When not local project, don't return set remote project_key
|
@@ -114,6 +126,18 @@ class InterceptSettings:
|
|
114
126
|
|
115
127
|
return self.__settings.remote.project_key
|
116
128
|
|
129
|
+
@property
|
130
|
+
def response_fixtures_path(self):
|
131
|
+
if self.__headers and custom_headers.RESPONSE_FIXTURES_PATH in self.__headers:
|
132
|
+
return self.__headers[custom_headers.RESPONSE_FIXTURES_PATH]
|
133
|
+
|
134
|
+
if os.environ.get(env_vars.AGENT_RESPONSE_FIXTURES_PATH):
|
135
|
+
return os.environ[env_vars.AGENT_RESPONSE_FIXTURES_PATH]
|
136
|
+
|
137
|
+
@property
|
138
|
+
def response_fixtures(self):
|
139
|
+
return self.__response_fixtures or {}
|
140
|
+
|
117
141
|
@property
|
118
142
|
def parsed_remote_project_key(self):
|
119
143
|
try:
|
@@ -288,6 +312,21 @@ class InterceptSettings:
|
|
288
312
|
except Exception as e:
|
289
313
|
return Logger.instance().error(e)
|
290
314
|
|
315
|
+
def __initialize_response_fixtures(self):
|
316
|
+
fixtures_path = self.response_fixtures_path
|
317
|
+
|
318
|
+
if not fixtures_path:
|
319
|
+
return
|
320
|
+
|
321
|
+
if not os.path.exists(fixtures_path):
|
322
|
+
return Logger.instance().error(f"Response fixtures {fixtures_path} does not exist")
|
323
|
+
|
324
|
+
with open(fixtures_path, 'r') as stream:
|
325
|
+
try:
|
326
|
+
self.__response_fixtures = yaml.safe_load(stream)
|
327
|
+
except yaml.YAMLError as exc:
|
328
|
+
Logger.instance().error(exc)
|
329
|
+
|
291
330
|
def __policy(self, mode):
|
292
331
|
if mode == intercept_mode.MOCK:
|
293
332
|
if self.__headers and custom_headers.MOCK_POLICY in self.__headers:
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import os
|
2
|
+
import pdb
|
3
|
+
import re
|
4
|
+
|
5
|
+
from io import BytesIO
|
6
|
+
from mitmproxy.http import Request as MitmproxyRequest
|
7
|
+
from requests import Response
|
8
|
+
from typing import Union
|
9
|
+
|
10
|
+
from stoobly_agent.lib.logger import bcolors, Logger
|
11
|
+
|
12
|
+
from .types import Fixtures
|
13
|
+
|
14
|
+
class Options():
|
15
|
+
public_directory_path: str
|
16
|
+
response_fixtures: Fixtures
|
17
|
+
|
18
|
+
def eval_fixtures(request: MitmproxyRequest, **options: Options) -> Union[Response, None]:
|
19
|
+
response_fixtures = options.get('response_fixtures')
|
20
|
+
|
21
|
+
fixture_path = __eval_response_fixtures(request, response_fixtures)
|
22
|
+
if not fixture_path:
|
23
|
+
public_directory_path = options.get('public_directory_path')
|
24
|
+
|
25
|
+
if public_directory_path and os.path.exists(public_directory_path):
|
26
|
+
static_file_path = os.path.join(public_directory_path, request.path.lstrip('/'))
|
27
|
+
|
28
|
+
if os.path.exists(static_file_path):
|
29
|
+
fixture_path = static_file_path
|
30
|
+
|
31
|
+
if not fixture_path:
|
32
|
+
return
|
33
|
+
|
34
|
+
with open(fixture_path, 'rb') as fp:
|
35
|
+
response = Response()
|
36
|
+
|
37
|
+
response.status_code = 200
|
38
|
+
response.raw = BytesIO(fp.read())
|
39
|
+
|
40
|
+
Logger.instance().debug(f"{bcolors.OKBLUE}Resolved fixture {fixture_path}{bcolors.ENDC}")
|
41
|
+
|
42
|
+
return response
|
43
|
+
|
44
|
+
def __eval_response_fixtures(request: MitmproxyRequest, response_fixtures: Fixtures):
|
45
|
+
if not response_fixtures:
|
46
|
+
return
|
47
|
+
|
48
|
+
method = request.method
|
49
|
+
routes = response_fixtures.get(method)
|
50
|
+
|
51
|
+
if not routes:
|
52
|
+
return
|
53
|
+
|
54
|
+
for path_pattern in routes:
|
55
|
+
if not re.match(path_pattern, request.path):
|
56
|
+
continue
|
57
|
+
|
58
|
+
path = routes[path_pattern].get('path')
|
59
|
+
|
60
|
+
if path and os.path.exists(path):
|
61
|
+
return path
|
@@ -27,9 +27,11 @@ class ReplayRequestOptions(TypedDict):
|
|
27
27
|
after_replay: Union[Callable[[ReplayContext], Union[requests.Response, None]], None]
|
28
28
|
project_key: Union[str, None]
|
29
29
|
proxies: dict
|
30
|
+
public_directory_path: str
|
30
31
|
remote_project_key: str
|
31
32
|
report_key: Union[str, None]
|
32
33
|
request_origin: Union[request_origin.CLI, None]
|
34
|
+
response_fixtures_path: str
|
33
35
|
scenario_key: Union[str, None]
|
34
36
|
scheme: str
|
35
37
|
test_filter: test_filter.TestFilter
|
@@ -58,7 +60,7 @@ def replay(context: ReplayContext, options: ReplayRequestOptions) -> requests.Re
|
|
58
60
|
headers[custom_headers.ALIAS_RESOLVE_STRATEGY] = options['alias_resolve_strategy']
|
59
61
|
|
60
62
|
if options.get('lifecycle_hooks_path'):
|
61
|
-
|
63
|
+
__handle_path_header(custom_headers.LIFECYCLE_HOOKS_PATH, options['lifecycle_hooks_path'], headers)
|
62
64
|
|
63
65
|
if options.get('mode'):
|
64
66
|
__handle_mode_option(options['mode'], request, headers)
|
@@ -66,6 +68,9 @@ def replay(context: ReplayContext, options: ReplayRequestOptions) -> requests.Re
|
|
66
68
|
if options.get('project_key'):
|
67
69
|
headers[custom_headers.PROJECT_KEY] = options['project_key']
|
68
70
|
|
71
|
+
if options.get('public_directory_path'):
|
72
|
+
__handle_path_header(custom_headers.PUBLIC_DIRECTORY_PATH, options['public_directory_path'], headers)
|
73
|
+
|
69
74
|
if options.get('report_key'):
|
70
75
|
headers[custom_headers.REPORT_KEY] = options['report_key']
|
71
76
|
|
@@ -75,6 +80,9 @@ def replay(context: ReplayContext, options: ReplayRequestOptions) -> requests.Re
|
|
75
80
|
if custom_headers.REQUEST_ORIGIN not in headers:
|
76
81
|
headers[custom_headers.REQUEST_ORIGIN] = request_origin.CLI
|
77
82
|
|
83
|
+
if options.get('response_fixtures_path'):
|
84
|
+
__handle_path_header(custom_headers.RESPONSE_FIXTURES_PATH, options['response_fixtures_path'], headers)
|
85
|
+
|
78
86
|
if options.get('scenario_key'):
|
79
87
|
headers[custom_headers.SCENARIO_KEY] = options['scenario_key']
|
80
88
|
|
@@ -146,14 +154,14 @@ def replay(context: ReplayContext, options: ReplayRequestOptions) -> requests.Re
|
|
146
154
|
|
147
155
|
return res
|
148
156
|
|
149
|
-
def
|
157
|
+
def __handle_path_header(header_name: str, script_path: str, headers):
|
150
158
|
if not script_path:
|
151
159
|
return
|
152
160
|
|
153
161
|
if not os.path.isabs(script_path):
|
154
162
|
script_path = os.path.join(os.path.abspath('.'), script_path)
|
155
163
|
|
156
|
-
headers[
|
164
|
+
headers[header_name] = script_path
|
157
165
|
|
158
166
|
def __handle_mode_option(_mode, request: Request, headers):
|
159
167
|
headers[custom_headers.PROXY_MODE] = _mode
|
stoobly_agent/app/proxy/run.py
CHANGED
@@ -124,6 +124,12 @@ def __filter_options(options):
|
|
124
124
|
if 'lifecycle_hooks_path' in options:
|
125
125
|
del options['lifecycle_hooks_path']
|
126
126
|
|
127
|
+
if 'public_directory_path' in options:
|
128
|
+
del options['public_directory_path']
|
129
|
+
|
130
|
+
if 'response_fixtures_path' in options:
|
131
|
+
del options['response_fixtures_path']
|
132
|
+
|
127
133
|
if 'ui_host' in options:
|
128
134
|
del options['ui_host']
|
129
135
|
|
@@ -142,6 +142,10 @@ class TestContext(TestContextABC):
|
|
142
142
|
def passed(self, v):
|
143
143
|
self.__passed = v
|
144
144
|
|
145
|
+
@property
|
146
|
+
def public_directory_path(self):
|
147
|
+
return self.__intercept_settings.public_directory_path
|
148
|
+
|
145
149
|
@property
|
146
150
|
def replay_context(self) -> ReplayContext:
|
147
151
|
return self.__replay_context
|
@@ -162,6 +166,14 @@ class TestContext(TestContextABC):
|
|
162
166
|
def response(self) -> TestContextResponse:
|
163
167
|
return self.__response
|
164
168
|
|
169
|
+
@property
|
170
|
+
def response_fixtures(self):
|
171
|
+
return self.__intercept_settings.response_fixtures
|
172
|
+
|
173
|
+
@property
|
174
|
+
def response_fixtures_path(self):
|
175
|
+
return self.__intercept_settings.response_fixtures_path
|
176
|
+
|
165
177
|
@property
|
166
178
|
def response_param_names(self) -> RequestComponentNamesFacade:
|
167
179
|
if self.__cached_response_param_names:
|
@@ -119,6 +119,11 @@ class TestContextABC(abc.ABC):
|
|
119
119
|
def passed(self, v):
|
120
120
|
pass
|
121
121
|
|
122
|
+
@property
|
123
|
+
@abc.abstractmethod
|
124
|
+
def public_directory_path(self):
|
125
|
+
pass
|
126
|
+
|
122
127
|
@property
|
123
128
|
@abc.abstractmethod
|
124
129
|
def replay_context(self):
|
@@ -144,6 +149,16 @@ class TestContextABC(abc.ABC):
|
|
144
149
|
def response(self) -> TestContextResponse:
|
145
150
|
pass
|
146
151
|
|
152
|
+
@property
|
153
|
+
@abc.abstractmethod
|
154
|
+
def response_fixtures(self):
|
155
|
+
pass
|
156
|
+
|
157
|
+
@property
|
158
|
+
@abc.abstractmethod
|
159
|
+
def response_fixtures_path(self):
|
160
|
+
pass
|
161
|
+
|
147
162
|
@property
|
148
163
|
@abc.abstractmethod
|
149
164
|
def response_param_names(self) -> RequestComponentNamesFacade:
|
stoobly_agent/cli.py
CHANGED
@@ -105,6 +105,8 @@ def init(**kwargs):
|
|
105
105
|
the form of "http[s]://host[:port]".
|
106
106
|
''')
|
107
107
|
@click.option('--proxy-port', default=8080, help='Proxy service port.')
|
108
|
+
@click.option('--public-directory-path', help='Path to public files. Used for mocking requests.')
|
109
|
+
@click.option('--response-fixtures-path', help='Path to response fixtures yaml. Used for mocking requests.')
|
108
110
|
@click.option('--ssl-insecure', is_flag=True, default=False, help='Do not verify upstream server SSL/TLS certificates.')
|
109
111
|
@click.option('--ui-host', default='0.0.0.0', help='Address to bind UI to.')
|
110
112
|
@click.option('--ui-port', default=4200, help='UI service port.')
|
@@ -116,6 +118,12 @@ def run(**kwargs):
|
|
116
118
|
if kwargs.get('lifecycle_hooks_path'):
|
117
119
|
os.environ[env_vars.AGENT_LIFECYCLE_HOOKS_PATH] = kwargs['lifecycle_hooks_path']
|
118
120
|
|
121
|
+
if kwargs.get('public_directory_path'):
|
122
|
+
os.environ[env_vars.AGENT_PUBLIC_DIRECOTRY_PATH] = kwargs['public_directory_path']
|
123
|
+
|
124
|
+
if kwargs.get('response_fixtures_path'):
|
125
|
+
os.environ[env_vars.AGENT_RESPONSE_FIXTURES_PATH] = kwargs['response_fixtures_path']
|
126
|
+
|
119
127
|
# Observe config for changes
|
120
128
|
Settings.instance().watch()
|
121
129
|
|
@@ -137,7 +145,10 @@ def run(**kwargs):
|
|
137
145
|
@ConditionalDecorator(lambda f: click.option('--remote-project-key', help='Use remote project for endpoint definitions.')(f), is_remote and is_local)
|
138
146
|
@click.option('--format', type=click.Choice([RAW_FORMAT]), help='Format response')
|
139
147
|
@click.option('-H', '--header', multiple=True, help='Pass custom header(s) to server')
|
148
|
+
@click.option('--lifecycle-hooks-path', help='Path to lifecycle hooks script.')
|
140
149
|
@ConditionalDecorator(lambda f: click.option('--project-key')(f), is_remote)
|
150
|
+
@click.option('--public-directory-path', help='Path to public files. Used for mocking requests.')
|
151
|
+
@click.option('--response-fixtures-path', help='Path to response fixtures yaml. Used for mocking requests.')
|
141
152
|
@click.option('-X', '--request', default='GET', help='Specify request command to use')
|
142
153
|
@click.option('--scenario-key')
|
143
154
|
@click.argument('url')
|
@@ -165,7 +176,7 @@ def mock(**kwargs):
|
|
165
176
|
print_raw_response(response)
|
166
177
|
else:
|
167
178
|
content = response.content
|
168
|
-
print(decode(content))
|
179
|
+
print(decode(content), end='')
|
169
180
|
|
170
181
|
@main.command(
|
171
182
|
help="Record request"
|
@@ -194,7 +205,7 @@ def record(**kwargs):
|
|
194
205
|
else:
|
195
206
|
try:
|
196
207
|
content = response.raw.data
|
197
|
-
print(content.decode(json.detect_encoding(content)))
|
208
|
+
print(content.decode(json.detect_encoding(content)), end='')
|
198
209
|
except UnicodeDecodeError:
|
199
210
|
print('Warning: Binary output can mess up your terminal.')
|
200
211
|
|
@@ -9,9 +9,11 @@ DO_PROXY = 'X-Do-Proxy'
|
|
9
9
|
LIFECYCLE_HOOKS_PATH = 'X-Stoobly-Lifecycle-Hooks-Path'
|
10
10
|
PROJECT_KEY = 'X-Project-Key'
|
11
11
|
PROXY_MODE = 'X-Proxy-Mode'
|
12
|
+
PUBLIC_DIRECTORY_PATH = 'X-Stoobly-Public-Directory-Path'
|
12
13
|
RECORD_POLICY = 'X-Record-Policy'
|
13
14
|
REPORT_KEY = 'X-Report-Key'
|
14
15
|
REQUEST_ORIGIN = 'X-Proxy-Request-Origin'
|
16
|
+
RESPONSE_FIXTURES_PATH = 'X-Stoobly-Response-Fixtures-Path'
|
15
17
|
RESPONSE_ID = 'X-Response-Id'
|
16
18
|
RESPONSE_LATENCY = 'X-Stoobly-Request-Response-Latency'
|
17
19
|
RESPONSE_PROXY_MODE = 'X-Response-Proxy-Mode'
|
@@ -9,10 +9,12 @@ AGENT_LIFECYCLE_HOOKS_PATH = 'STOOBLY_AGENT_LIFECYCLE_HOOKS_PATH'
|
|
9
9
|
AGENT_POLICY = 'STOOBLY_AGENT_POLICY'
|
10
10
|
AGENT_PROJECT_KEY = 'STOOBLY_AGENT_PROJECT_KEY'
|
11
11
|
AGENT_PROXY_URL = 'STOOBLY_AGENT_PROXY_URL'
|
12
|
+
AGENT_PUBLIC_DIRECTORY_PATH = 'STOOBLY_AGENT_PUBLIC_DIRECTORY_PATH'
|
12
13
|
AGENT_REMOTE_ENABLED = 'STOOBLY_AGENT_REMOTE_ENABLED'
|
13
14
|
AGENT_REMOTE_PROJECT_KEY = 'STOOBLY_AGENT_REMOTE_PROJECT_KEY'
|
14
15
|
AGENT_REPLAY_HOST = 'STOOBLY_AGENT_REPLAY_HOST'
|
15
16
|
AGENT_REPLAY_SCHEME = 'STOOBLY_AGENT_REPLAY_SCHEME'
|
17
|
+
AGENT_RESPONSE_FIXTURES_PATH = 'STOOBLY_AGENT_RESPONSE_FIXTURES_PATH'
|
16
18
|
AGENT_SERVICE_URL = 'STOOBLY_AGENT_SERVICE_URL'
|
17
19
|
AGENT_SCENARIO_KEY = 'STOOBLY_AGENT_SCENARIO_KEY'
|
18
20
|
AGENT_SIMULATE_LATENCY = 'STOOBLY_AGENT_SIMULATE_LATENCY'
|
stoobly_agent/lib/api/api.py
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
import requests
|
2
|
+
import urllib
|
3
|
+
import pdb
|
4
|
+
|
5
|
+
from stoobly_agent.app.models.types import ParamNameCreateParams
|
6
|
+
|
7
|
+
from ..logger import Logger
|
8
|
+
from .endpoints_resource import EndpointsResource
|
9
|
+
|
10
|
+
class BodyParamNamesResource(EndpointsResource):
|
11
|
+
BODY_PARAM_NAMES_ENDPOINT = 'body_param_names'
|
12
|
+
|
13
|
+
def create(self, endpoint_id: int, params: ParamNameCreateParams = {}):
|
14
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.BODY_PARAM_NAMES_ENDPOINT}"
|
15
|
+
return self.post(url, headers=self.default_headers, json=params)
|
16
|
+
|
17
|
+
def index(self, endpoint_id: int, query_params = {}) -> requests.Response:
|
18
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.BODY_PARAM_NAMES_ENDPOINT}"
|
19
|
+
|
20
|
+
Logger.instance().debug(f"{self.LOG_ID}.request_response:{url}?{urllib.parse.urlencode(query_params)}")
|
21
|
+
|
22
|
+
return self.get(url, headers=self.default_headers, params=query_params)
|
23
|
+
|
24
|
+
def show(self, endpoint_id: int, body_param_name_id: int, query_params = {}) -> requests.Response:
|
25
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.BODY_PARAM_NAMES_ENDPOINT}/{body_param_name_id}"
|
26
|
+
|
27
|
+
Logger.instance().debug(f"{self.LOG_ID}.request_response:{url}?{urllib.parse.urlencode(query_params)}")
|
28
|
+
|
29
|
+
return self.get(url, headers=self.default_headers, params=query_params)
|
30
|
+
|
31
|
+
def destroy(self, endpoint_id, body_param_name_id: int, query_params = {}) -> requests.Response:
|
32
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.BODY_PARAM_NAMES_ENDPOINT}/{body_param_name_id}"
|
33
|
+
|
34
|
+
Logger.instance().debug(f"{self.LOG_ID}.request_response:{url}?{urllib.parse.urlencode(query_params)}")
|
35
|
+
|
36
|
+
return self.delete(url, headers=self.default_headers, params=query_params)
|
@@ -11,7 +11,7 @@ class EndpointsResource(StooblyApi):
|
|
11
11
|
|
12
12
|
def create(self, **params):
|
13
13
|
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}"
|
14
|
-
return self.post(url, headers=self.default_headers,
|
14
|
+
return self.post(url, headers=self.default_headers, json=params)
|
15
15
|
|
16
16
|
def index(self, **query_params: EndpointsIndexQueryParams) -> requests.Response:
|
17
17
|
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}"
|
@@ -25,4 +25,11 @@ class EndpointsResource(StooblyApi):
|
|
25
25
|
|
26
26
|
Logger.instance().debug(f"{self.LOG_ID}.request_response:{url}?{urllib.parse.urlencode(query_params)}")
|
27
27
|
|
28
|
-
return self.get(url, headers=self.default_headers, params=query_params)
|
28
|
+
return self.get(url, headers=self.default_headers, params=query_params)
|
29
|
+
|
30
|
+
def destroy(self, endpoint_id: int, **query_params) -> requests.Response:
|
31
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}"
|
32
|
+
|
33
|
+
Logger.instance().debug(f"{self.LOG_ID}.request_response:{url}?{urllib.parse.urlencode(query_params)}")
|
34
|
+
|
35
|
+
return self.delete(url, headers=self.default_headers, params=query_params)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import requests
|
2
|
+
import urllib
|
3
|
+
import pdb
|
4
|
+
|
5
|
+
from stoobly_agent.app.models.types import HeaderNameCreateParams
|
6
|
+
|
7
|
+
from ..logger import Logger
|
8
|
+
from .endpoints_resource import EndpointsResource
|
9
|
+
|
10
|
+
class HeaderNamesResource(EndpointsResource):
|
11
|
+
HEADER_NAMES_ENDPOINT = 'header_names'
|
12
|
+
|
13
|
+
def create(self, endpoint_id: int, params: HeaderNameCreateParams = {}):
|
14
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.HEADER_NAMES_ENDPOINT}"
|
15
|
+
return self.post(url, headers=self.default_headers, json=params)
|
16
|
+
|
17
|
+
def index(self, endpoint_id: int, query_params = {}) -> requests.Response:
|
18
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.HEADER_NAMES_ENDPOINT}"
|
19
|
+
|
20
|
+
Logger.instance().debug(f"{self.LOG_ID}.request_response:{url}?{urllib.parse.urlencode(query_params)}")
|
21
|
+
|
22
|
+
return self.get(url, headers=self.default_headers, params=query_params)
|
23
|
+
|
24
|
+
def show(self, endpoint_id: int, header_name_id: int, query_params = {}) -> requests.Response:
|
25
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.HEADER_NAMES_ENDPOINT}/{header_name_id}"
|
26
|
+
|
27
|
+
Logger.instance().debug(f"{self.LOG_ID}.request_response:{url}?{urllib.parse.urlencode(query_params)}")
|
28
|
+
|
29
|
+
return self.get(url, headers=self.default_headers, params=query_params)
|
30
|
+
|
31
|
+
def destroy(self, endpoint_id: int, header_name_id: int, query_params = {}) -> requests.Response:
|
32
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.HEADER_NAMES_ENDPOINT}/{header_name_id}"
|
33
|
+
|
34
|
+
Logger.instance().debug(f"{self.LOG_ID}.request_response:{url}?{urllib.parse.urlencode(query_params)}")
|
35
|
+
|
36
|
+
return self.delete(url, headers=self.default_headers, params=query_params)
|
@@ -43,8 +43,10 @@ class EndpointShowResponse(TypedDict):
|
|
43
43
|
path_segment_names: List[RequestComponentName]
|
44
44
|
query_param_names: List[RequestComponentName]
|
45
45
|
response_param_names: List[ResponseParamName]
|
46
|
+
response_header_names: List[RequestComponentName]
|
46
47
|
literal_query_params: Optional[dict]
|
47
48
|
literal_body_params: Optional[dict]
|
49
|
+
literal_response_params: Optional[dict]
|
48
50
|
|
49
51
|
ARRAY_TYPE = 'Array'
|
50
52
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import requests
|
2
|
+
import urllib
|
3
|
+
import pdb
|
4
|
+
|
5
|
+
from stoobly_agent.app.models.types import ParamNameCreateParams
|
6
|
+
|
7
|
+
from ..logger import Logger
|
8
|
+
from .endpoints_resource import EndpointsResource
|
9
|
+
|
10
|
+
class QueryParamNamesResource(EndpointsResource):
|
11
|
+
QUERY_PARAM_NAMES_ENDPOINT = 'query_param_names'
|
12
|
+
|
13
|
+
def create(self, endpoint_id: int, params: ParamNameCreateParams = {}):
|
14
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.QUERY_PARAM_NAMES_ENDPOINT}"
|
15
|
+
return self.post(url, headers=self.default_headers, json=params)
|
16
|
+
|
17
|
+
def index(self, endpoint_id: int, query_params = {}) -> requests.Response:
|
18
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.QUERY_PARAM_NAMES_ENDPOINT}"
|
19
|
+
|
20
|
+
Logger.instance().debug(f"{self.LOG_ID}.request_response:{url}?{urllib.parse.urlencode(query_params)}")
|
21
|
+
|
22
|
+
return self.get(url, headers=self.default_headers, params=query_params)
|
23
|
+
|
24
|
+
def show(self, endpoint_id: int, query_param_name_id: int, query_params = {}) -> requests.Response:
|
25
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.QUERY_PARAM_NAMES_ENDPOINT}/{query_param_name_id}"
|
26
|
+
|
27
|
+
Logger.instance().debug(f"{self.LOG_ID}.request_response:{url}?{urllib.parse.urlencode(query_params)}")
|
28
|
+
|
29
|
+
return self.get(url, headers=self.default_headers, params=query_params)
|
30
|
+
|
31
|
+
def destroy(self, endpoint_id: int, query_param_name_id: int, query_params = {}) -> requests.Response:
|
32
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.QUERY_PARAM_NAMES_ENDPOINT}/{query_param_name_id}"
|
33
|
+
|
34
|
+
Logger.instance().debug(f"{self.LOG_ID}.request_response:{url}?{urllib.parse.urlencode(query_params)}")
|
35
|
+
|
36
|
+
return self.delete(url, headers=self.default_headers, params=query_params)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import requests
|
2
|
+
import urllib
|
3
|
+
import pdb
|
4
|
+
|
5
|
+
from stoobly_agent.app.models.types import HeaderNameCreateParams
|
6
|
+
|
7
|
+
from ..logger import Logger
|
8
|
+
from .endpoints_resource import EndpointsResource
|
9
|
+
|
10
|
+
class ResponseHeaderNamesResource(EndpointsResource):
|
11
|
+
RESPONSE_HEADER_NAME_ENDPOINT = 'response_header_names'
|
12
|
+
|
13
|
+
def create(self, endpoint_id: int, params: HeaderNameCreateParams = {}):
|
14
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.RESPONSE_HEADER_NAME_ENDPOINT}"
|
15
|
+
return self.post(url, headers=self.default_headers, json=params)
|
16
|
+
|
17
|
+
def index(self, endpoint_id: int, query_params = {}) -> requests.Response:
|
18
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.RESPONSE_HEADER_NAME_ENDPOINT}"
|
19
|
+
|
20
|
+
Logger.instance().debug(f"{self.LOG_ID}.request_response:{url}?{urllib.parse.urlencode(query_params)}")
|
21
|
+
|
22
|
+
return self.get(url, headers=self.default_headers, params=query_params)
|
23
|
+
|
24
|
+
def show(self, endpoint_id: int, response_header_name_id: int, query_params = {}) -> requests.Response:
|
25
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.RESPONSE_HEADER_NAME_ENDPOINT}/{response_header_name_id}"
|
26
|
+
|
27
|
+
Logger.instance().debug(f"{self.LOG_ID}.request_response:{url}?{urllib.parse.urlencode(query_params)}")
|
28
|
+
|
29
|
+
return self.get(url, headers=self.default_headers, params=query_params)
|
30
|
+
|
31
|
+
def destroy(self, endpoint_id: int, response_header_name_id: int, query_params = {}) -> requests.Response:
|
32
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.RESPONSE_HEADER_NAME_ENDPOINT}/{response_header_name_id}"
|
33
|
+
|
34
|
+
Logger.instance().debug(f"{self.LOG_ID}.request_response:{url}?{urllib.parse.urlencode(query_params)}")
|
35
|
+
|
36
|
+
return self.delete(url, headers=self.default_headers, params=query_params)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import requests
|
2
|
+
import urllib
|
3
|
+
import pdb
|
4
|
+
|
5
|
+
from stoobly_agent.app.models.types import ParamNameCreateParams
|
6
|
+
|
7
|
+
from ..logger import Logger
|
8
|
+
from .endpoints_resource import EndpointsResource
|
9
|
+
|
10
|
+
class ResponseParamNamesResource(EndpointsResource):
|
11
|
+
RESPONSE_PARAM_NAMES_ENDPOINT = 'response_param_names'
|
12
|
+
|
13
|
+
def create(self, endpoint_id: int, params: ParamNameCreateParams = {}):
|
14
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.RESPONSE_PARAM_NAMES_ENDPOINT}"
|
15
|
+
return self.post(url, headers=self.default_headers, json=params)
|
16
|
+
|
17
|
+
def index(self, endpoint_id: int, query_params = {}) -> requests.Response:
|
18
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.RESPONSE_PARAM_NAMES_ENDPOINT}"
|
19
|
+
|
20
|
+
Logger.instance().debug(f"{self.LOG_ID}.request_response:{url}?{urllib.parse.urlencode(query_params)}")
|
21
|
+
|
22
|
+
return self.get(url, headers=self.default_headers, params=query_params)
|
23
|
+
|
24
|
+
def show(self, endpoint_id: int, response_param_name_id: int, query_params = {}) -> requests.Response:
|
25
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.RESPONSE_PARAM_NAMES_ENDPOINT}/{response_param_name_id}"
|
26
|
+
|
27
|
+
Logger.instance().debug(f"{self.LOG_ID}.request_response:{url}?{urllib.parse.urlencode(query_params)}")
|
28
|
+
|
29
|
+
return self.get(url, headers=self.default_headers, params=query_params)
|
30
|
+
|
31
|
+
def destroy(self, endpoint_id: int, response_param_name_id: int, query_params = {}) -> requests.Response:
|
32
|
+
url = f"{self.service_url}/{self.ENDPOINTS_ENDPOINT}/{endpoint_id}/{self.RESPONSE_PARAM_NAMES_ENDPOINT}/{response_param_name_id}"
|
33
|
+
|
34
|
+
Logger.instance().debug(f"{self.LOG_ID}.request_response:{url}?{urllib.parse.urlencode(query_params)}")
|
35
|
+
|
36
|
+
return self.delete(url, headers=self.default_headers, params=query_params)
|
@@ -0,0 +1 @@
|
|
1
|
+
(window.webpackJsonp=window.webpackJsonp||[]).push([[0],{pMoy:function(e,t,n){"use strict";n.d(t,"a",function(){return o}),n.d(t,"b",function(){return k}),n.d(t,"c",function(){return b}),n.d(t,"d",function(){return u});var c=n("8LU1"),i=n("8Y7J"),a=(n("s7LF"),n("UhP/"));const o=new i.s("mat-checkbox-default-options",{providedIn:"root",factory:r});function r(){return{color:"accent",clickAction:"check-indeterminate"}}let s=0;const h=r();class m{}class l{constructor(e){this._elementRef=e}}const d=Object(a.H)(Object(a.C)(Object(a.D)(Object(a.E)(l))));class k extends d{constructor(e,t,n,c,a,o,r){super(e),this._changeDetectorRef=t,this._focusMonitor=n,this._ngZone=c,this._animationMode=o,this._options=r,this.ariaLabel="",this.ariaLabelledby=null,this._uniqueId="mat-checkbox-"+ ++s,this.id=this._uniqueId,this.labelPosition="after",this.name=null,this.change=new i.o,this.indeterminateChange=new i.o,this._onTouched=()=>{},this._currentAnimationClass="",this._currentCheckState=0,this._controlValueAccessorChangeFn=()=>{},this._checked=!1,this._disabled=!1,this._indeterminate=!1,this._options=this._options||h,this.color=this.defaultColor=this._options.color||h.color,this.tabIndex=parseInt(a)||0}get inputId(){return(this.id||this._uniqueId)+"-input"}get required(){return this._required}set required(e){this._required=Object(c.c)(e)}ngAfterViewInit(){this._focusMonitor.monitor(this._elementRef,!0).subscribe(e=>{e||Promise.resolve().then(()=>{this._onTouched(),this._changeDetectorRef.markForCheck()})}),this._syncIndeterminate(this._indeterminate)}ngAfterViewChecked(){}ngOnDestroy(){this._focusMonitor.stopMonitoring(this._elementRef)}get checked(){return this._checked}set checked(e){e!=this.checked&&(this._checked=e,this._changeDetectorRef.markForCheck())}get disabled(){return this._disabled}set disabled(e){const t=Object(c.c)(e);t!==this.disabled&&(this._disabled=t,this._changeDetectorRef.markForCheck())}get indeterminate(){return this._indeterminate}set indeterminate(e){const t=e!=this._indeterminate;this._indeterminate=Object(c.c)(e),t&&(this._transitionCheckState(this._indeterminate?3:this.checked?1:2),this.indeterminateChange.emit(this._indeterminate)),this._syncIndeterminate(this._indeterminate)}_isRippleDisabled(){return this.disableRipple||this.disabled}_onLabelTextChange(){this._changeDetectorRef.detectChanges()}writeValue(e){this.checked=!!e}registerOnChange(e){this._controlValueAccessorChangeFn=e}registerOnTouched(e){this._onTouched=e}setDisabledState(e){this.disabled=e}_getAriaChecked(){return this.checked?"true":this.indeterminate?"mixed":"false"}_transitionCheckState(e){let t=this._currentCheckState,n=this._elementRef.nativeElement;if(t!==e&&(this._currentAnimationClass.length>0&&n.classList.remove(this._currentAnimationClass),this._currentAnimationClass=this._getAnimationClassForCheckStateTransition(t,e),this._currentCheckState=e,this._currentAnimationClass.length>0)){n.classList.add(this._currentAnimationClass);const e=this._currentAnimationClass;this._ngZone.runOutsideAngular(()=>{setTimeout(()=>{n.classList.remove(e)},1e3)})}}_emitChangeEvent(){const e=new m;e.source=this,e.checked=this.checked,this._controlValueAccessorChangeFn(this.checked),this.change.emit(e)}toggle(){this.checked=!this.checked}_onInputClick(e){var t;const n=null===(t=this._options)||void 0===t?void 0:t.clickAction;e.stopPropagation(),this.disabled||"noop"===n?this.disabled||"noop"!==n||(this._inputElement.nativeElement.checked=this.checked,this._inputElement.nativeElement.indeterminate=this.indeterminate):(this.indeterminate&&"check"!==n&&Promise.resolve().then(()=>{this._indeterminate=!1,this.indeterminateChange.emit(this._indeterminate)}),this.toggle(),this._transitionCheckState(this._checked?1:2),this._emitChangeEvent())}focus(e="keyboard",t){this._focusMonitor.focusVia(this._inputElement,e,t)}_onInteractionEvent(e){e.stopPropagation()}_getAnimationClassForCheckStateTransition(e,t){if("NoopAnimations"===this._animationMode)return"";let n="";switch(e){case 0:if(1===t)n="unchecked-checked";else{if(3!=t)return"";n="unchecked-indeterminate"}break;case 2:n=1===t?"unchecked-checked":"unchecked-indeterminate";break;case 1:n=2===t?"checked-unchecked":"checked-indeterminate";break;case 3:n=1===t?"indeterminate-checked":"indeterminate-unchecked"}return"mat-checkbox-anim-"+n}_syncIndeterminate(e){const t=this._inputElement;t&&(t.nativeElement.indeterminate=e)}}class u{}class b{}},"y3B+":function(e,t,n){"use strict";n.d(t,"a",function(){return s}),n.d(t,"b",function(){return h});var c=n("8Y7J"),i=(n("pMoy"),n("9b/N")),a=(n("9gLZ"),n("UhP/")),o=(n("YEUz"),n("SVse"),n("SCoL")),r=n("omvX"),s=(n("s7LF"),c.yb({encapsulation:2,styles:["@keyframes mat-checkbox-fade-in-background{0%{opacity:0}50%{opacity:1}}@keyframes mat-checkbox-fade-out-background{0%,50%{opacity:1}100%{opacity:0}}@keyframes mat-checkbox-unchecked-checked-checkmark-path{0%,50%{stroke-dashoffset:22.910259}50%{animation-timing-function:cubic-bezier(0, 0, 0.2, 0.1)}100%{stroke-dashoffset:0}}@keyframes mat-checkbox-unchecked-indeterminate-mixedmark{0%,68.2%{transform:scaleX(0)}68.2%{animation-timing-function:cubic-bezier(0, 0, 0, 1)}100%{transform:scaleX(1)}}@keyframes mat-checkbox-checked-unchecked-checkmark-path{from{animation-timing-function:cubic-bezier(0.4, 0, 1, 1);stroke-dashoffset:0}to{stroke-dashoffset:-22.910259}}@keyframes mat-checkbox-checked-indeterminate-checkmark{from{animation-timing-function:cubic-bezier(0, 0, 0.2, 0.1);opacity:1;transform:rotate(0deg)}to{opacity:0;transform:rotate(45deg)}}@keyframes mat-checkbox-indeterminate-checked-checkmark{from{animation-timing-function:cubic-bezier(0.14, 0, 0, 1);opacity:0;transform:rotate(45deg)}to{opacity:1;transform:rotate(360deg)}}@keyframes mat-checkbox-checked-indeterminate-mixedmark{from{animation-timing-function:cubic-bezier(0, 0, 0.2, 0.1);opacity:0;transform:rotate(-45deg)}to{opacity:1;transform:rotate(0deg)}}@keyframes mat-checkbox-indeterminate-checked-mixedmark{from{animation-timing-function:cubic-bezier(0.14, 0, 0, 1);opacity:1;transform:rotate(0deg)}to{opacity:0;transform:rotate(315deg)}}@keyframes mat-checkbox-indeterminate-unchecked-mixedmark{0%{animation-timing-function:linear;opacity:1;transform:scaleX(1)}32.8%,100%{opacity:0;transform:scaleX(0)}}.mat-checkbox-background,.mat-checkbox-frame{top:0;left:0;right:0;bottom:0;position:absolute;border-radius:2px;box-sizing:border-box;pointer-events:none}.mat-checkbox{display:inline-block;transition:background 400ms cubic-bezier(0.25, 0.8, 0.25, 1),box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);cursor:pointer;-webkit-tap-highlight-color:transparent}._mat-animation-noopable.mat-checkbox{transition:none;animation:none}.mat-checkbox .mat-ripple-element:not(.mat-checkbox-persistent-ripple){opacity:.16}.mat-checkbox-layout{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:inherit;align-items:baseline;vertical-align:middle;display:inline-flex;white-space:nowrap}.mat-checkbox-label{-webkit-user-select:auto;-moz-user-select:auto;-ms-user-select:auto;user-select:auto}.mat-checkbox-inner-container{display:inline-block;height:16px;line-height:0;margin:auto;margin-right:8px;order:0;position:relative;vertical-align:middle;white-space:nowrap;width:16px;flex-shrink:0}[dir=rtl] .mat-checkbox-inner-container{margin-left:8px;margin-right:auto}.mat-checkbox-inner-container-no-side-margin{margin-left:0;margin-right:0}.mat-checkbox-frame{background-color:transparent;transition:border-color 90ms cubic-bezier(0, 0, 0.2, 0.1);border-width:2px;border-style:solid}._mat-animation-noopable .mat-checkbox-frame{transition:none}.cdk-high-contrast-active .mat-checkbox.cdk-keyboard-focused .mat-checkbox-frame{border-style:dotted}.mat-checkbox-background{align-items:center;display:inline-flex;justify-content:center;transition:background-color 90ms cubic-bezier(0, 0, 0.2, 0.1),opacity 90ms cubic-bezier(0, 0, 0.2, 0.1)}._mat-animation-noopable .mat-checkbox-background{transition:none}.cdk-high-contrast-active .mat-checkbox .mat-checkbox-background{background:none}.mat-checkbox-persistent-ripple{display:block;width:100%;height:100%;transform:none}.mat-checkbox-inner-container:hover .mat-checkbox-persistent-ripple{opacity:.04}.mat-checkbox.cdk-keyboard-focused .mat-checkbox-persistent-ripple{opacity:.12}.mat-checkbox-persistent-ripple,.mat-checkbox.mat-checkbox-disabled .mat-checkbox-inner-container:hover .mat-checkbox-persistent-ripple{opacity:0}@media(hover: none){.mat-checkbox-inner-container:hover .mat-checkbox-persistent-ripple{display:none}}.mat-checkbox-checkmark{top:0;left:0;right:0;bottom:0;position:absolute;width:100%}.mat-checkbox-checkmark-path{stroke-dashoffset:22.910259;stroke-dasharray:22.910259;stroke-width:2.1333333333px}.cdk-high-contrast-black-on-white .mat-checkbox-checkmark-path{stroke:#000 !important}.mat-checkbox-mixedmark{width:calc(100% - 6px);height:2px;opacity:0;transform:scaleX(0) rotate(0deg);border-radius:2px}.cdk-high-contrast-active .mat-checkbox-mixedmark{height:0;border-top:solid 2px;margin-top:2px}.mat-checkbox-label-before .mat-checkbox-inner-container{order:1;margin-left:8px;margin-right:auto}[dir=rtl] .mat-checkbox-label-before .mat-checkbox-inner-container{margin-left:auto;margin-right:8px}.mat-checkbox-checked .mat-checkbox-checkmark{opacity:1}.mat-checkbox-checked .mat-checkbox-checkmark-path{stroke-dashoffset:0}.mat-checkbox-checked .mat-checkbox-mixedmark{transform:scaleX(1) rotate(-45deg)}.mat-checkbox-indeterminate .mat-checkbox-checkmark{opacity:0;transform:rotate(45deg)}.mat-checkbox-indeterminate .mat-checkbox-checkmark-path{stroke-dashoffset:0}.mat-checkbox-indeterminate .mat-checkbox-mixedmark{opacity:1;transform:scaleX(1) rotate(0deg)}.mat-checkbox-unchecked .mat-checkbox-background{background-color:transparent}.mat-checkbox-disabled{cursor:default}.cdk-high-contrast-active .mat-checkbox-disabled{opacity:.5}.mat-checkbox-anim-unchecked-checked .mat-checkbox-background{animation:180ms linear 0ms mat-checkbox-fade-in-background}.mat-checkbox-anim-unchecked-checked .mat-checkbox-checkmark-path{animation:180ms linear 0ms mat-checkbox-unchecked-checked-checkmark-path}.mat-checkbox-anim-unchecked-indeterminate .mat-checkbox-background{animation:180ms linear 0ms mat-checkbox-fade-in-background}.mat-checkbox-anim-unchecked-indeterminate .mat-checkbox-mixedmark{animation:90ms linear 0ms mat-checkbox-unchecked-indeterminate-mixedmark}.mat-checkbox-anim-checked-unchecked .mat-checkbox-background{animation:180ms linear 0ms mat-checkbox-fade-out-background}.mat-checkbox-anim-checked-unchecked .mat-checkbox-checkmark-path{animation:90ms linear 0ms mat-checkbox-checked-unchecked-checkmark-path}.mat-checkbox-anim-checked-indeterminate .mat-checkbox-checkmark{animation:90ms linear 0ms mat-checkbox-checked-indeterminate-checkmark}.mat-checkbox-anim-checked-indeterminate .mat-checkbox-mixedmark{animation:90ms linear 0ms mat-checkbox-checked-indeterminate-mixedmark}.mat-checkbox-anim-indeterminate-checked .mat-checkbox-checkmark{animation:500ms linear 0ms mat-checkbox-indeterminate-checked-checkmark}.mat-checkbox-anim-indeterminate-checked .mat-checkbox-mixedmark{animation:500ms linear 0ms mat-checkbox-indeterminate-checked-mixedmark}.mat-checkbox-anim-indeterminate-unchecked .mat-checkbox-background{animation:180ms linear 0ms mat-checkbox-fade-out-background}.mat-checkbox-anim-indeterminate-unchecked .mat-checkbox-mixedmark{animation:300ms linear 0ms mat-checkbox-indeterminate-unchecked-mixedmark}.mat-checkbox-input{bottom:0;left:50%}.mat-checkbox .mat-checkbox-ripple{position:absolute;left:calc(50% - 20px);top:calc(50% - 20px);height:40px;width:40px;z-index:1;pointer-events:none}\n"],data:{}}));function h(e){return c.bc(2,[c.Ub(671088640,1,{_inputElement:0}),c.Ub(671088640,2,{ripple:0}),(e()(),c.Ab(2,0,[["label",1]],null,16,"label",[["class","mat-checkbox-layout"]],[[1,"for",0]],null,null,null,null)),(e()(),c.Ab(3,0,null,null,10,"span",[["class","mat-checkbox-inner-container"]],[[2,"mat-checkbox-inner-container-no-side-margin",null]],null,null,null,null)),(e()(),c.Ab(4,0,[[1,0],["input",1]],null,0,"input",[["class","mat-checkbox-input cdk-visually-hidden"],["type","checkbox"]],[[8,"id",0],[8,"required",0],[8,"checked",0],[1,"value",0],[8,"disabled",0],[1,"name",0],[8,"tabIndex",0],[1,"aria-label",0],[1,"aria-labelledby",0],[1,"aria-checked",0],[1,"aria-describedby",0]],[[null,"change"],[null,"click"]],function(e,t,n){var c=!0,i=e.component;return"change"===t&&(c=!1!==i._onInteractionEvent(n)&&c),"click"===t&&(c=!1!==i._onInputClick(n)&&c),c},null,null)),(e()(),c.Ab(5,0,null,null,3,"span",[["class","mat-checkbox-ripple mat-focus-indicator mat-ripple"],["matRipple",""]],[[2,"mat-ripple-unbounded",null]],null,null,null,null)),c.zb(6,212992,[[2,4]],0,a.v,[c.l,c.B,o.a,[2,a.k],[2,r.a]],{centered:[0,"centered"],radius:[1,"radius"],animation:[2,"animation"],disabled:[3,"disabled"],trigger:[4,"trigger"]},null),c.Rb(7,{enterDuration:0}),(e()(),c.Ab(8,0,null,null,0,"span",[["class","mat-ripple-element mat-checkbox-persistent-ripple"]],null,null,null,null,null)),(e()(),c.Ab(9,0,null,null,0,"span",[["class","mat-checkbox-frame"]],null,null,null,null,null)),(e()(),c.Ab(10,0,null,null,3,"span",[["class","mat-checkbox-background"]],null,null,null,null,null)),(e()(),c.Ab(11,0,null,null,1,":svg:svg",[[":xml:space","preserve"],["class","mat-checkbox-checkmark"],["focusable","false"],["version","1.1"],["viewBox","0 0 24 24"]],null,null,null,null,null)),(e()(),c.Ab(12,0,null,null,0,":svg:path",[["class","mat-checkbox-checkmark-path"],["d","M4.1,12.7 9,17.6 20.3,6.3"],["fill","none"],["stroke","white"]],null,null,null,null,null)),(e()(),c.Ab(13,0,null,null,0,"span",[["class","mat-checkbox-mixedmark"]],null,null,null,null,null)),(e()(),c.Ab(14,0,[["checkboxLabel",1]],null,4,"span",[["class","mat-checkbox-label"]],null,[[null,"cdkObserveContent"]],function(e,t,n){var c=!0;return"cdkObserveContent"===t&&(c=!1!==e.component._onLabelTextChange()&&c),c},null,null)),c.zb(15,1196032,null,0,i.a,[i.b,c.l,c.B],null,{event:"cdkObserveContent"}),(e()(),c.Ab(16,0,null,null,1,"span",[["style","display:none"]],null,null,null,null,null)),(e()(),c.Yb(-1,null,["\xa0"])),c.Nb(null,0)],function(e,t){var n=t.component,i=e(t,7,0,150);e(t,6,0,!0,20,i,n._isRippleDisabled(),c.Ob(t,2))},function(e,t){var n=t.component;e(t,2,0,n.inputId),e(t,3,0,!c.Ob(t,14).textContent||!c.Ob(t,14).textContent.trim()),e(t,4,1,[n.inputId,n.required,n.checked,n.value,n.disabled,n.name,n.tabIndex,n.ariaLabel||null,n.ariaLabelledby,n._getAriaChecked(),n.ariaDescribedby]),e(t,5,0,c.Ob(t,6).unbounded)})}}}]);
|