stoobly-agent 0.26.11__py3-none-any.whl → 0.27.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.
Files changed (34) hide show
  1. stoobly_agent/__init__.py +1 -1
  2. stoobly_agent/app/api/configs_controller.py +17 -12
  3. stoobly_agent/app/cli/helpers/print_service.py +4 -2
  4. stoobly_agent/app/models/factories/resource/local_db/helpers/create_request_columns_service.py +1 -1
  5. stoobly_agent/app/models/factories/resource/local_db/request_adapter.py +29 -11
  6. stoobly_agent/app/proxy/record/overwrite_scenario_service.py +1 -1
  7. stoobly_agent/lib/api/keys/request_key.py +14 -5
  8. stoobly_agent/lib/api/keys/scenario_key.py +14 -5
  9. stoobly_agent/lib/api/keys/uuid_key.py +24 -0
  10. stoobly_agent/lib/orm/request.py +11 -1
  11. stoobly_agent/lib/orm/scenario.py +1 -1
  12. stoobly_agent/public/11-es2015.0d86b95c0db1e55945f4.js +1 -0
  13. stoobly_agent/public/11-es5.0d86b95c0db1e55945f4.js +1 -0
  14. stoobly_agent/public/18-es2015.750ef954bde422debcb6.js +1 -0
  15. stoobly_agent/public/18-es5.750ef954bde422debcb6.js +1 -0
  16. stoobly_agent/public/dashboard.agent-alpha-0.27.0.tar.gz +0 -0
  17. stoobly_agent/public/index.html +1 -1
  18. stoobly_agent/public/{main-es2015.ece107681f10e74540af.js → main-es2015.9aaecf72f47ebb58efdb.js} +1 -1
  19. stoobly_agent/public/{main-es5.ece107681f10e74540af.js → main-es5.9aaecf72f47ebb58efdb.js} +1 -1
  20. stoobly_agent/public/runtime-es2015.6d14514e90ffbe7aa697.js +1 -0
  21. stoobly_agent/public/runtime-es5.6d14514e90ffbe7aa697.js +1 -0
  22. {stoobly_agent-0.26.11.dist-info → stoobly_agent-0.27.1.dist-info}/METADATA +1 -1
  23. {stoobly_agent-0.26.11.dist-info → stoobly_agent-0.27.1.dist-info}/RECORD +27 -26
  24. stoobly_agent/public/11-es2015.8feb8504fdd3e6813e67.js +0 -1
  25. stoobly_agent/public/11-es5.8feb8504fdd3e6813e67.js +0 -1
  26. stoobly_agent/public/18-es2015.4b1aafce0739bb8141fd.js +0 -1
  27. stoobly_agent/public/18-es5.4b1aafce0739bb8141fd.js +0 -1
  28. stoobly_agent/public/dashboard.agent-alpha-0.26.10.tar.gz +0 -0
  29. stoobly_agent/public/runtime-es2015.da33ff934331415e9631.js +0 -1
  30. stoobly_agent/public/runtime-es5.da33ff934331415e9631.js +0 -1
  31. {stoobly_agent-0.26.11.dist-info → stoobly_agent-0.27.1.dist-info}/LICENSE +0 -0
  32. {stoobly_agent-0.26.11.dist-info → stoobly_agent-0.27.1.dist-info}/WHEEL +0 -0
  33. {stoobly_agent-0.26.11.dist-info → stoobly_agent-0.27.1.dist-info}/entry_points.txt +0 -0
  34. {stoobly_agent-0.26.11.dist-info → stoobly_agent-0.27.1.dist-info}/top_level.txt +0 -0
stoobly_agent/__init__.py CHANGED
@@ -1,2 +1,2 @@
1
1
  COMMAND = 'stoobly-agent'
2
- VERSION = '0.26.11'
2
+ VERSION = '0.27.1'
@@ -2,14 +2,14 @@ import pdb
2
2
 
3
3
  from mergedeep import merge
4
4
 
5
+ from stoobly_agent.app.api.simple_http_request_handler import SimpleHTTPRequestHandler
5
6
  from stoobly_agent.app.cli.helpers.handle_config_update_service import context as handle_context, handle_project_update, handle_policy_update, handle_scenario_update
6
- from stoobly_agent.app.settings import Settings
7
+ from stoobly_agent.app.models.scenario_model import ScenarioModel
7
8
  from stoobly_agent.app.proxy.intercept_settings import InterceptSettings
8
- from stoobly_agent.config.constants import mode, replay_policy
9
- from stoobly_agent.config.constants import mock_policy, record_policy
9
+ from stoobly_agent.app.settings import Settings
10
+ from stoobly_agent.config.constants import mock_policy, mode, record_policy, replay_policy
10
11
  from stoobly_agent.lib.api.keys.project_key import ProjectKey
11
12
  from stoobly_agent.lib.api.keys.scenario_key import ScenarioKey
12
- from stoobly_agent.lib.api.scenarios_resource import ScenariosResource
13
13
 
14
14
  class ConfigsController:
15
15
  _instance = None
@@ -67,17 +67,20 @@ class ConfigsController:
67
67
  project_id = ProjectKey(project_key).id if project_key else None
68
68
 
69
69
  scenario_key = intercept_settings.scenario_key
70
- scenario_id = ScenarioKey(scenario_key).id if scenario_key else None
70
+ scenario_id = None
71
71
 
72
72
  # Check to make sure the scenario still exists
73
- if self.is_remote_enabled(context) and scenario_id:
74
- resource = ScenariosResource(settings.remote.api_url, settings.remote.api_key)
75
- res = resource.show(scenario_id)
73
+ scenario_uuid = ScenarioKey(scenario_key).id if scenario_key else None
74
+
75
+ if scenario_uuid:
76
+ model = self.__scenario_model(context, settings)
77
+ scenario, status = model.show(scenario_uuid)
76
78
 
77
- if not res.ok and res.status_code == 404:
78
- scenario_id = None
79
+ if status == 404:
79
80
  intercept_settings.scenario_key = None
80
81
  settings.commit()
82
+ elif status == 200:
83
+ scenario_id = scenario['id']
81
84
 
82
85
  modes = [mode.RECORD, mode.MOCK, mode.TEST, mode.REPLAY] if not context.params.get('agent') else [mode.RECORD, mode.MOCK, mode.REPLAY]
83
86
 
@@ -114,5 +117,7 @@ class ConfigsController:
114
117
  status = 200
115
118
  )
116
119
 
117
- def is_remote_enabled(self, context):
118
- return context.headers.get('access-token')
120
+ def __scenario_model(self, context: SimpleHTTPRequestHandler, settings: Settings = None):
121
+ scenario_model = ScenarioModel(settings or Settings.instance())
122
+ scenario_model.as_remote() if context.headers.get('access-token') else scenario_model.as_local()
123
+ return scenario_model
@@ -24,7 +24,9 @@ def print_projects(projects, **kwargs):
24
24
  def print_requests(requests, **kwargs):
25
25
  tabulate_print(
26
26
  requests,
27
- filter=['components' , 'created_at', 'endpoint', 'endpoint_id', 'id', 'position', 'project_id', 'scenario_id', 'scheme', 'starred', 'updated_at', 'url'],
27
+ filter=[
28
+ 'body_params_hash', 'body_text_hash', 'components' , 'created_at', 'endpoint', 'endpoint_id', 'http_version', 'is_deleted', 'position', 'project_id', 'pushed_at', 'query_params_hash', 'scenario_id', 'scheme', 'starred', 'uuid', 'updated_at', 'url'
29
+ ],
28
30
  headers=not kwargs.get('without_headers'),
29
31
  select=kwargs.get('select') or []
30
32
  )
@@ -32,7 +34,7 @@ def print_requests(requests, **kwargs):
32
34
  def print_scenarios(scenarios, **kwargs):
33
35
  tabulate_print(
34
36
  scenarios,
35
- filter=['created_at', 'priority', 'project_id', 'starred', 'updated_at'],
37
+ filter=['created_at', 'is_deleted', 'priority', 'project_id', 'starred', 'uuid', 'updated_at'],
36
38
  headers=not kwargs.get('without_headers'),
37
39
  select=kwargs.get('select') or []
38
40
  )
@@ -20,7 +20,7 @@ def build_request_columns(flow: MitmproxyHTTPFlow, joined_request: JoinedRequest
20
20
  'is_deleted': params.get('is_deleted') or False,
21
21
  'latency': joined_request.response_string.latency,
22
22
  'raw': joined_request.request_string.get(),
23
- 'scenario_id': int(params['scenario_id']) if params.get('scenario_id') else None,
23
+ 'scenario_id': params['scenario_id'] if params.get('scenario_id') else None,
24
24
  'status': flow.response.status_code,
25
25
  'uuid': joined_request.request_string.request_id,
26
26
  }
@@ -13,6 +13,7 @@ from stoobly_agent.app.proxy.record.joined_request import JoinedRequest
13
13
  from stoobly_agent.lib.orm import ORM
14
14
  from stoobly_agent.lib.orm.request import Request
15
15
  from stoobly_agent.lib.orm.response import Response
16
+ from stoobly_agent.lib.orm.scenario import Scenario
16
17
  from stoobly_agent.lib.orm.transformers.orm_to_stoobly_request_transformer import ORMToStooblyRequestTransformer
17
18
  from stoobly_agent.lib.orm.types.request_columns import RequestColumns
18
19
  from stoobly_agent.lib.orm.transformers import ORMToRequestTransformer, ORMToRequestsResponseTransformer
@@ -28,16 +29,20 @@ class LocalDBRequestAdapter(LocalDBAdapter):
28
29
  __request_orm = None
29
30
  __response_orm = None
30
31
 
31
- def __init__(self, request_orm: Request.__class__ = Request, response_orm: Response.__class__ = Response):
32
+ def __init__(self, request_orm: Request.__class__ = Request, response_orm: Response.__class__ = Response, scenario_orm = Scenario.__class__):
32
33
  self.__request_orm: Request = request_orm
33
34
  self.__response_orm: Response = response_orm
35
+ self.__scenario_orm: Scenario = scenario_orm
34
36
 
35
37
  def create(self, **params: RequestCreateParams) -> Tuple[RequestShowResponse, int]:
38
+ self.__adapt_scenario_id(params)
39
+
36
40
  flow: MitmproxyHTTPFlow = params['flow']
37
41
  joined_request: JoinedRequest = params['joined_request']
42
+ scenario_id = params.get('scenario_id')
38
43
 
39
44
  with ORM.instance().db.transaction():
40
- request_columns = build_request_columns(flow, joined_request, scenario_id=params.get('scenario_id'))
45
+ request_columns = build_request_columns(flow, joined_request, scenario_id=scenario_id)
41
46
  request_record = self.__request_orm.create(**request_columns)
42
47
 
43
48
  response_columns = {
@@ -89,6 +94,8 @@ class LocalDBRequestAdapter(LocalDBAdapter):
89
94
  return ORMToRequestsResponseTransformer(response_record).transform()
90
95
 
91
96
  def index(self, **query_params: RequestsIndexQueryParams) -> Tuple[RequestsIndexResponse, int]:
97
+ self.__adapt_scenario_id(query_params)
98
+
92
99
  scenario_id = query_params.get('scenario_id')
93
100
  page = int(query_params.get('page') or 0)
94
101
  query = query_params.get('q')
@@ -105,7 +112,7 @@ class LocalDBRequestAdapter(LocalDBAdapter):
105
112
  if unassigned:
106
113
  requests = requests.where('scenario_id', None)
107
114
  elif scenario_id:
108
- requests = requests.where('scenario_id', int(scenario_id))
115
+ requests = requests.where('scenario_id', scenario_id)
109
116
  sort_order = query_params.get('sort_order') or 'asc'
110
117
 
111
118
  if starred:
@@ -258,15 +265,30 @@ class LocalDBRequestAdapter(LocalDBAdapter):
258
265
 
259
266
  return candidates.get()
260
267
 
268
+ def __filter_request_response_columns(self, request_columns: RequestCreateParams):
269
+ if request_columns.get('project_id'):
270
+ del request_columns['project_id']
271
+
261
272
  def __request(self, request_id: str):
262
273
  if self.validate_uuid(request_id):
263
274
  return self.__request_orm.find_by(uuid=request_id)
264
275
  else:
265
276
  return self.__request_orm.find(request_id)
266
277
 
267
- def __filter_request_response_columns(self, request_columns: RequestCreateParams):
268
- if request_columns.get('project_id'):
269
- del request_columns['project_id']
278
+ def __request_not_found(self):
279
+ return self.not_found('Request not found')
280
+
281
+ def __adapt_scenario_id(self, params: dict):
282
+ if not params.get('scenario_id'):
283
+ return
284
+
285
+ scenario_id = params['scenario_id']
286
+ if not self.validate_uuid(scenario_id):
287
+ return
288
+
289
+ scenario = self.__scenario_orm.find_by(uuid=scenario_id)
290
+ if scenario:
291
+ params['scenario_id'] = scenario.id
270
292
 
271
293
  def __search(self, base_model: Request, query: str) -> Request:
272
294
  uri = urlparse(query)
@@ -275,8 +297,4 @@ class LocalDBRequestAdapter(LocalDBAdapter):
275
297
  return base_model.where('host', uri.hostname).where('path', uri.path)
276
298
  else:
277
299
  pattern = f"%{query}%"
278
- return base_model.where('path', 'like', pattern).or_where('host', 'like', pattern)
279
-
280
- def __request_not_found(self):
281
- return self.not_found('Request not found')
282
-
300
+ return base_model.where('path', 'like', pattern).or_where('host', 'like', pattern)
@@ -31,7 +31,7 @@ def overwrite_scenario(scenario_key: str):
31
31
  return
32
32
 
33
33
  requests_model = RequestModel(settings)
34
- res, status = requests_model.destroy_all(scenario_id=scenario_key.id)
34
+ res, status = requests_model.destroy_all(scenario_id=scenario['id'])
35
35
 
36
36
  if status != 200:
37
37
  return
@@ -1,14 +1,18 @@
1
- from .resource_key import ResourceKey
1
+ import uuid
2
+
3
+ from .uuid_key import UuidKey
2
4
 
3
5
  from stoobly_agent.app.settings import Settings
4
6
 
5
7
  class InvalidRequestKey(Exception):
6
8
  pass
7
9
 
8
- class RequestKey(ResourceKey):
10
+ class RequestKey(UuidKey):
9
11
  def __init__(self, key: str):
10
12
  super().__init__(key)
11
13
 
14
+ self.__raw = key
15
+
12
16
  if not self.id:
13
17
  raise InvalidRequestKey('Missing id')
14
18
 
@@ -19,15 +23,20 @@ class RequestKey(ResourceKey):
19
23
 
20
24
  @property
21
25
  def id(self) -> str:
22
- return self.get('i')
26
+ u = uuid.UUID(self.get('i'))
27
+ return str(u)
23
28
 
24
29
  @property
25
30
  def project_id(self) -> str:
26
31
  return self.get('p')
27
32
 
33
+ @property
34
+ def raw(self):
35
+ return self.__raw
36
+
28
37
  @staticmethod
29
38
  def encode(project_id: str, request_id: str):
30
- return ResourceKey.encode({
39
+ return UuidKey.encode({
31
40
  'p': project_id,
32
- 'i': request_id,
41
+ 'i': request_id.replace('-', ''),
33
42
  })
@@ -1,13 +1,17 @@
1
- from .resource_key import ResourceKey
1
+ import uuid
2
+
3
+ from .uuid_key import UuidKey
2
4
 
3
5
  class InvalidScenarioKey(Exception):
4
6
  pass
5
7
 
6
- class ScenarioKey(ResourceKey):
8
+ class ScenarioKey(UuidKey):
7
9
 
8
10
  def __init__(self, key: str):
9
11
  super().__init__(key)
10
12
 
13
+ self.__raw = key
14
+
11
15
  if not self.id:
12
16
  raise InvalidScenarioKey('Missing id')
13
17
 
@@ -20,11 +24,16 @@ class ScenarioKey(ResourceKey):
20
24
 
21
25
  @property
22
26
  def id(self) -> str:
23
- return self.get('i')
27
+ u = uuid.UUID(self.get('i'))
28
+ return str(u)
29
+
30
+ @property
31
+ def raw(self):
32
+ return self.__raw
24
33
 
25
34
  @staticmethod
26
35
  def encode(project_id: str, request_id: str):
27
- return ResourceKey.encode({
36
+ return UuidKey.encode({
28
37
  'p': project_id,
29
- 'i': request_id,
38
+ 'i': request_id.replace('-', ''),
30
39
  })
@@ -0,0 +1,24 @@
1
+ from .resource_key import ResourceKey
2
+
3
+ DELIMITTER = '.'
4
+
5
+ class UuidKey(ResourceKey):
6
+ def __init__(self, key: str):
7
+ super().__init__(super().encode(self.__decode(key)))
8
+
9
+ @staticmethod
10
+ def encode(d: dict):
11
+ toks = []
12
+ for key in d:
13
+ toks.append(f"{key}{d[key]}")
14
+
15
+ return DELIMITTER.join(toks)
16
+
17
+ def __decode(self, key: str):
18
+ toks = key.split(DELIMITTER)
19
+
20
+ d = {}
21
+ for tok in toks:
22
+ d[tok[0]] = tok[1:]
23
+
24
+ return d
@@ -52,7 +52,7 @@ class Request(Base):
52
52
  return Scenario
53
53
 
54
54
  def key(self):
55
- return decode(RequestKey.encode(LOCAL_PROJECT_ID, self.id))
55
+ return decode(RequestKey.encode(LOCAL_PROJECT_ID, self.uuid))
56
56
 
57
57
  # Override
58
58
  def to_dict(self):
@@ -96,6 +96,16 @@ def handle_saving(request):
96
96
  if hasattr(request, 'is_deleted') and request.is_deleted:
97
97
  request.scenario_id = None
98
98
 
99
+ if hasattr(request, 'scenario_id') and request.scenario_id:
100
+ try:
101
+ # If set as uuid, convert to id
102
+ uuid.UUID(request.scenario_id)
103
+
104
+ scenario = Scenario.find_by(uuid=request.scenario_id)
105
+ request.scenario_id = scenario.id
106
+ except Exception:
107
+ pass
108
+
99
109
  def handle_saved(request):
100
110
  request_before = request.get_original()
101
111
 
@@ -17,7 +17,7 @@ class Scenario(Base):
17
17
  return Request
18
18
 
19
19
  def key(self):
20
- return ScenarioKey.encode(LOCAL_PROJECT_ID, self.id).decode()
20
+ return ScenarioKey.encode(LOCAL_PROJECT_ID, self.uuid)
21
21
 
22
22
  # Override
23
23
  def to_dict(self):