clear-skies-cortex 2.0.1__py3-none-any.whl → 2.0.3__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clear-skies-cortex
3
- Version: 2.0.1
3
+ Version: 2.0.3
4
4
  Summary: Cortex module for Clearskies
5
5
  Project-URL: Docs, https://https://clearskies.info/modules/clear-skies-cortex
6
6
  Project-URL: Repository, https://github.com/clearskies-py/cortex
@@ -14,7 +14,7 @@ Classifier: Intended Audience :: Developers
14
14
  Classifier: License :: OSI Approved :: MIT License
15
15
  Classifier: Programming Language :: Python :: 3
16
16
  Requires-Python: <4.0,>=3.11
17
- Requires-Dist: clear-skies<3.0.0,>=2.0.0
17
+ Requires-Dist: clear-skies<3.0.0,>=2.0.37
18
18
  Requires-Dist: dacite>=1.9.2
19
19
  Provides-Extra: dev
20
20
  Requires-Dist: types-requests>=2.32.4; extra == 'dev'
@@ -1,27 +1,28 @@
1
1
  clearskies_cortex/__init__.py,sha256=SwFkNfKLJgcq2qE6YJ_78_JfeoRGojlKuR_3DymZZSQ,142
2
- clearskies_cortex/dataclasses.py,sha256=yZhRm2dnGCVGaZUEuh8n86kqqxFTuKU_jljkh0gAW-4,1432
2
+ clearskies_cortex/dataclasses.py,sha256=rmSwJkMPwyfQltHuGzRRn9OrwMXKHajkG1jA39ix9lU,1446
3
3
  clearskies_cortex/backends/__init__.py,sha256=Ek74kpJLE7ERY-6yhH2KwFO25gm3Yjz51laUApnhgnU,179
4
- clearskies_cortex/backends/cortex_backend.py,sha256=OnbrHXjojBWoOBYRjfKD26FO7XzzYsVrpWJAfQ95wn0,1650
5
- clearskies_cortex/backends/cortex_team_relationship_backend.py,sha256=IHvYzDMcmUqJHjdWzm1QtNbwWD9LbUNMRQVUC2Afx-U,7795
4
+ clearskies_cortex/backends/cortex_backend.py,sha256=kmF54P0W3eK2BpCAh4dpIBPmo6iWKU7oUYSPB-IG7IE,4149
5
+ clearskies_cortex/backends/cortex_team_relationship_backend.py,sha256=UiMZp0jcKvpx3tLbR8aMBS8-KIfECxJGiwM3fz8DmuM,7648
6
6
  clearskies_cortex/columns/__init__.py,sha256=BpoVCEVXRtKcsyRFnAYLtlwYtHBjciUbzuzaBxmfH00,87
7
7
  clearskies_cortex/columns/string_list.py,sha256=khsJS_0T4XZvTeXFpRvZsFX8iNTWbx_urCEa9Tv0Bmo,754
8
8
  clearskies_cortex/defaults/__init__.py,sha256=tulZSvFgp4YUKj_bnArIevmlpC8z_AQKO0okYs4hCDo,216
9
9
  clearskies_cortex/defaults/default_cortex_auth.py,sha256=yA5kCwGxPEdV2t-28UArkKXgI3qbxt-7P6az4cLI1Rg,508
10
10
  clearskies_cortex/defaults/default_cortex_url.py,sha256=SaR6dQW3ELtuy4Woap8ufYL_zGQ0K0XwHUv0CYi_p78,305
11
- clearskies_cortex/models/__init__.py,sha256=aJXrP5UwHCoKe833Mpg4hbTEftXSgAdRFXrUYZ0KGOA,1026
12
- clearskies_cortex/models/cortex_catalog_entity.py,sha256=-7lo67x09N-iNWRGKpdDrn1raGyhH1oL8UpscUVxb9I,1766
13
- clearskies_cortex/models/cortex_catalog_entity_domain.py,sha256=UTa2vBGt8DuTFrO_Prcckb0NXHB0YsppZv47D3NmpFs,735
11
+ clearskies_cortex/models/__init__.py,sha256=zckJ4-KOjIcmtN7h7lXOESUu3d6JBsZZJq-s2MJ0NLQ,1145
12
+ clearskies_cortex/models/cortex_catalog_entity.py,sha256=ASwCKiZ682YvsFUrkPo8J_MQYCT_39aElJGWDTDH7GQ,3060
13
+ clearskies_cortex/models/cortex_catalog_entity_domain.py,sha256=gApQwSIGO0UGxhkJo-aaDK7clCxmTQTzHcgCjdPAZEE,1386
14
14
  clearskies_cortex/models/cortex_catalog_entity_group.py,sha256=dvuwwuj8Mwm0HgqVjkz1MpUycBAl9WUrDNC0XNGeWGk,514
15
15
  clearskies_cortex/models/cortex_catalog_entity_scorecard.py,sha256=sWp_v7O9uY3VbJjdb_VWUPHgBIn-rRj6kZDHqZq4lXI,908
16
- clearskies_cortex/models/cortex_catalog_entity_service.py,sha256=4Ibodm7orM9O_HZB1BkAVgYkM2st8Cm9iBO-qdyffhM,3344
16
+ clearskies_cortex/models/cortex_catalog_entity_service.py,sha256=GeJmR9qfRjNFwxbJriJeTWMm4L4yH-z6wCXQWXAolg4,2780
17
+ clearskies_cortex/models/cortex_catalog_entity_team.py,sha256=mKVKjOMf0xOk53XJI8juPQzNSdHvmxI1bJWfQVCKEQQ,1364
17
18
  clearskies_cortex/models/cortex_catalog_entity_types.py,sha256=EJBRv0ZMHwZ6HpaXxy0A_EBGqmu9EeVAZiX4xPIljz4,568
18
19
  clearskies_cortex/models/cortex_entity_relationships.py,sha256=bB46YFK8Vc2SZsvobvFeyTfEj8YfcaXFaPnkW0o_nG4,607
19
20
  clearskies_cortex/models/cortex_model.py,sha256=QmwQ45vuK4iUKCJsOk1pwu1at8IYKg39pYO9TtlYrEA,175
20
21
  clearskies_cortex/models/cortex_scorecard.py,sha256=YlINfUGudmqQHe-0ZpD2qOzAUKWshUycwgXYEcxqsUk,663
21
- clearskies_cortex/models/cortex_team.py,sha256=wPJxkNV1qQPq4WwMhBdKBnotQAB9KbmdVpowWCmfqp0,2042
22
+ clearskies_cortex/models/cortex_team.py,sha256=LXqHx_lwBvuVMyUlj1l2Sfpngj0zTZGpVi0WrJP-o3E,2246
22
23
  clearskies_cortex/models/cortex_team_category_tree.py,sha256=PLC-9E5kuMeItow7RKFX7jKUiAfJ-7ehXIy3eeaFzr8,721
23
24
  clearskies_cortex/models/cortex_team_department.py,sha256=DL3k91462-R0VVqbUQgBfYM_TndE5MKmDPBSF448XYw,639
24
- clear_skies_cortex-2.0.1.dist-info/METADATA,sha256=LM3SjjrLaNTpz66dKoRs1p6hbOoalJpVN46uWAMg3gc,2116
25
- clear_skies_cortex-2.0.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
26
- clear_skies_cortex-2.0.1.dist-info/licenses/LICENSE,sha256=MkEX8JF8kZxdyBpTTcB0YTd-xZpWnHvbRlw-pQh8u58,1069
27
- clear_skies_cortex-2.0.1.dist-info/RECORD,,
25
+ clear_skies_cortex-2.0.3.dist-info/METADATA,sha256=aDSWFEtcMWOw5fGdQGg1B--y7ECfX89nyI1WRa-36jg,2117
26
+ clear_skies_cortex-2.0.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
27
+ clear_skies_cortex-2.0.3.dist-info/licenses/LICENSE,sha256=MkEX8JF8kZxdyBpTTcB0YTd-xZpWnHvbRlw-pQh8u58,1069
28
+ clear_skies_cortex-2.0.3.dist-info/RECORD,,
@@ -1,9 +1,13 @@
1
+ from typing import Any
2
+
1
3
  import clearskies
2
- from clearskies import configs
4
+ import requests
5
+ from clearskies import Column, configs
3
6
  from clearskies.authentication import Authentication
4
7
  from clearskies.decorators import parameters_to_properties
5
8
  from clearskies.di import inject
6
9
  from clearskies.query import Query
10
+ from clearskies.query.result import CountQueryResult
7
11
 
8
12
 
9
13
  class CortexBackend(clearskies.backends.ApiBackend):
@@ -12,10 +16,13 @@ class CortexBackend(clearskies.backends.ApiBackend):
12
16
  base_url = configs.String(default="https://api.getcortexapp.com/api/v1/")
13
17
  authentication = inject.ByName("cortex_auth") # type: ignore[assignment]
14
18
  requests = inject.Requests()
19
+ api_casing = configs.Select(["snake_case", "camelCase", "TitleCase"], default="camelCase")
20
+
15
21
  _auth_headers: dict[str, str] = {}
16
22
 
17
23
  api_to_model_map = configs.AnyDict(default={})
18
24
  pagination_parameter_name = configs.String(default="page")
25
+ limit_parameter_name = configs.String(default="pageSize")
19
26
 
20
27
  can_count = True
21
28
 
@@ -33,7 +40,7 @@ class CortexBackend(clearskies.backends.ApiBackend):
33
40
  ):
34
41
  self.finalize_and_validate_configuration()
35
42
 
36
- def count(self, query: Query) -> int:
43
+ def count(self, query: Query) -> CountQueryResult:
37
44
  """Return count of records matching query."""
38
45
  self.check_query(query)
39
46
  (url, method, body, headers) = self.build_records_request(query)
@@ -41,5 +48,54 @@ class CortexBackend(clearskies.backends.ApiBackend):
41
48
  response.raise_for_status()
42
49
  data = response.json()
43
50
  if "total" in data:
44
- return data["total"]
45
- return len(data)
51
+ return CountQueryResult(count=data["total"])
52
+ data = self.map_records_response(data, query)
53
+ return CountQueryResult(count=len(data))
54
+
55
+ def map_records_response(
56
+ self, response_data: Any, query: Query, query_data: dict[str, Any] | None = None
57
+ ) -> list[dict[str, Any]]:
58
+ """Map api response to model fields."""
59
+ if isinstance(response_data, dict):
60
+ if "page" in response_data:
61
+ del response_data["page"]
62
+ del response_data["totalPages"]
63
+ del response_data["total"]
64
+ first_item = next(iter(response_data))
65
+ if isinstance(response_data[first_item], list) and all(
66
+ isinstance(item, dict) for item in response_data[first_item]
67
+ ):
68
+ return super().map_records_response(response_data[first_item], query, query_data)
69
+ return super().map_records_response(response_data, query, query_data)
70
+
71
+ def set_next_page_data_from_response(
72
+ self,
73
+ next_page_data: dict[str, Any],
74
+ query: Query,
75
+ response: "requests.Response", # type: ignore
76
+ ) -> None:
77
+ """
78
+ Update the next_page_data dictionary with the appropriate data needed to fetch the next page of records.
79
+
80
+ This method has a very important job, which is to inform clearskies about how to make another API call to fetch the next
81
+ page of records. The way this happens is by updating the `next_page_data` dictionary in place with whatever pagination
82
+ information is necessary. Note that this relies on next_page_data being passed by reference, hence the need to update
83
+ it in place. That means that you can do this:
84
+
85
+ ```python
86
+ next_page_data["some_key"] = "some_value"
87
+ ```
88
+
89
+ but if you do this:
90
+
91
+ ```python
92
+ next_page_data = {"some_key": "some_value"}
93
+ ```
94
+
95
+ Then things simply won't work.
96
+ """
97
+ if isinstance(response.json(), dict):
98
+ page = response.json().get("page", None)
99
+ total_pages = response.json().get("totalPages", None)
100
+ if page is not None and total_pages is not None and page < total_pages:
101
+ next_page_data[self.pagination_parameter_name] = page + 1
@@ -8,7 +8,8 @@ from clearskies import Configurable, Model, configs
8
8
  from clearskies.backends.memory_backend import MemoryBackend, MemoryTable
9
9
  from clearskies.columns import String, Uuid
10
10
  from clearskies.di import inject
11
- from clearskies.query.query import Query
11
+ from clearskies.query import Condition, Query
12
+ from clearskies.query.result import RecordsQueryResult
12
13
 
13
14
  from clearskies_cortex.backends import cortex_backend as rest_backend
14
15
 
@@ -34,7 +35,7 @@ class CortexTeamRelationshipBackend(MemoryBackend, Configurable):
34
35
  # or we need to let the di system build the CortexBackend. This change does both:
35
36
  self.cortex_backend = cortex_backend
36
37
 
37
- def records(self, query: Query, next_page_data: dict[str, str | int] | None = None) -> list[dict[str, Any]]:
38
+ def records(self, query: Query) -> RecordsQueryResult:
38
39
  """Accept either a model or a model class and creates a "table" for it."""
39
40
  table_name = query.model_class.destination_name()
40
41
  if table_name not in self._tables:
@@ -45,7 +46,7 @@ class CortexTeamRelationshipBackend(MemoryBackend, Configurable):
45
46
  # we don't need since we built the data ourselves. In short, it will be a lot slower, so I cheat.
46
47
  self._tables[table_name]._rows = records # type: ignore[assignment]
47
48
  self._tables[table_name]._id_index = id_index # type: ignore[assignment]
48
- return super().records(query, next_page_data)
49
+ return super().records(query)
49
50
 
50
51
  def _fetch_and_map_relationship_data(self, table_name: str) -> tuple[list[dict[str, str | int]], dict[str, int]]:
51
52
  class RelationshipModel(Model):
@@ -61,20 +62,6 @@ class CortexTeamRelationshipBackend(MemoryBackend, Configurable):
61
62
  def destination_name(cls) -> str:
62
63
  return "teams/relationships"
63
64
 
64
- try:
65
- relationship_data = self._get_cortex_backend().records(
66
- Query(
67
- model_class=RelationshipModel,
68
- ),
69
- {},
70
- )[0]
71
-
72
- except IndexError:
73
- relationship_data = {"edges": []}
74
-
75
- # this should match up to exactly what backend.records() will return
76
- # relationship_data = example_data["edges"]
77
-
78
65
  # we need to map this to the kind of row structure expected by the category_tree column
79
66
  # (see https://github.com/clearskies-py/clearskies/blob/main/src/clearskies/columns/category_tree.py)
80
67
  # This takes slightly more time up front but makes for quick lookups in both directions (and we'll
@@ -89,9 +76,17 @@ class CortexTeamRelationshipBackend(MemoryBackend, Configurable):
89
76
  root_categories: dict[str, str] = {}
90
77
  known_children: dict[str, str] = {}
91
78
  relationships: dict[str, set[str]] = {}
92
- for relationship in relationship_data["edges"]:
93
- child_category = relationship["childTeamTag"]
94
- parent_category = relationship["parentTeamTag"]
79
+ for relationship in (
80
+ self._get_cortex_backend()
81
+ .records(
82
+ Query(
83
+ model_class=RelationshipModel,
84
+ ),
85
+ )
86
+ .records
87
+ ):
88
+ child_category = relationship["child_team_tag"]
89
+ parent_category = relationship["parent_team_tag"]
95
90
  # Skip if either parent or child is archived
96
91
  if parent_category not in relationships:
97
92
  relationships[parent_category] = set()
@@ -115,8 +110,8 @@ class CortexTeamRelationshipBackend(MemoryBackend, Configurable):
115
110
  for idx, ancestor in enumerate(ancestors):
116
111
  if (
117
112
  not self.all_teams().get(node_name)
118
- or self.all_teams().get(node_name, {}).get("isArchived")
119
- or self.all_teams().get(ancestor, {}).get("isArchived")
113
+ # or self.all_teams().get(node_name, {}).get("is_archived")
114
+ # or self.all_teams().get(ancestor, {}).get("is_archived")
120
115
  ):
121
116
  continue
122
117
  mapped.append(
@@ -162,13 +157,16 @@ class CortexTeamRelationshipBackend(MemoryBackend, Configurable):
162
157
  from clearskies_cortex.models.cortex_team import CortexTeam
163
158
 
164
159
  teams: dict[str, dict[str, Any]] = {}
165
- team_result = self._get_cortex_backend().records(
166
- Query(
167
- model_class=CortexTeam,
168
- ),
169
- {},
170
- )[0]
171
- for team in team_result["teams"]:
172
- teams[team["teamTag"]] = team
160
+ for team in (
161
+ self._get_cortex_backend()
162
+ .records(
163
+ Query(
164
+ model_class=CortexTeam,
165
+ conditions=[Condition("include_teams_without_members=true")],
166
+ ),
167
+ )
168
+ .records
169
+ ):
170
+ teams[team["team_tag"]] = team
173
171
  self._cached_teams = teams
174
172
  return teams
@@ -20,7 +20,7 @@ class ServiceEntityHierarchyParent:
20
20
  description: str | None
21
21
  definition: None | dict[str, Any]
22
22
  parents: list["ServiceEntityHierarchyParent"]
23
- groups: list[str]
23
+ groups: list[str] | None
24
24
 
25
25
 
26
26
  @dataclass
@@ -33,7 +33,7 @@ class ServiceEntityHierarchyChild:
33
33
  description: str | None
34
34
  definition: None | dict[str, Any]
35
35
  children: list["ServiceEntityHierarchyChild"]
36
- groups: list[str]
36
+ groups: list[str] | None
37
37
 
38
38
 
39
39
  @dataclass
@@ -3,6 +3,7 @@ from clearskies_cortex.models.cortex_catalog_entity_domain import CortexCatalogE
3
3
  from clearskies_cortex.models.cortex_catalog_entity_group import CortexCatalogEntityGroup
4
4
  from clearskies_cortex.models.cortex_catalog_entity_scorecard import CortexCatalogEntityScorecard
5
5
  from clearskies_cortex.models.cortex_catalog_entity_service import CortexCatalogEntityService
6
+ from clearskies_cortex.models.cortex_catalog_entity_team import CortexCatalogEntityTeam
6
7
  from clearskies_cortex.models.cortex_scorecard import CortexScorecard
7
8
  from clearskies_cortex.models.cortex_team import CortexTeam
8
9
  from clearskies_cortex.models.cortex_team_category_tree import CortexTeamCategoryTree
@@ -14,6 +15,7 @@ __all__ = [
14
15
  "CortexCatalogEntityGroup",
15
16
  "CortexCatalogEntityScorecard",
16
17
  "CortexCatalogEntityService",
18
+ "CortexCatalogEntityTeam",
17
19
  "CortexScorecard",
18
20
  "CortexTeam",
19
21
  "CortexTeamCategoryTree",
@@ -1,11 +1,19 @@
1
- from typing import Self
1
+ from collections.abc import Iterator
2
+ from typing import Any, Self
2
3
 
3
4
  from clearskies import Model
4
5
  from clearskies.columns import Boolean, Datetime, HasMany, Json, String
6
+ from clearskies.di import inject
7
+ from clearskies.query import Query
8
+ from dacite import from_dict
5
9
 
10
+ from clearskies_cortex import dataclasses
6
11
  from clearskies_cortex.backends import CortexBackend
7
12
  from clearskies_cortex.columns import StringList
8
- from clearskies_cortex.models import cortex_catalog_entity_group, cortex_catalog_entity_scorecard
13
+ from clearskies_cortex.models import (
14
+ cortex_catalog_entity_group,
15
+ cortex_catalog_entity_scorecard,
16
+ )
9
17
 
10
18
 
11
19
  class CortexCatalogEntity(Model):
@@ -25,7 +33,7 @@ class CortexCatalogEntity(Model):
25
33
  groups = StringList("groups")
26
34
  owners = Json()
27
35
  ownership = Json()
28
- ownersV2 = Json()
36
+ owners_v2 = Json()
29
37
  description = String()
30
38
  git = Json()
31
39
  hierarchy = Json()
@@ -46,6 +54,22 @@ class CortexCatalogEntity(Model):
46
54
  foreign_column_name="entity_tag",
47
55
  )
48
56
 
57
+ # search columns
58
+ hierarchy_depth = String(is_searchable=True, is_temporary=True)
59
+ git_repositories = StringList(is_searchable=True, is_temporary=True)
60
+ types = StringList(is_searchable=True, is_temporary=True)
61
+ query = String(is_searchable=True, is_temporary=True)
62
+ include_archived = Boolean(is_searchable=True, is_temporary=True)
63
+ include_metadata = Boolean(is_searchable=True, is_temporary=True)
64
+ include_links = Boolean(is_searchable=True, is_temporary=True)
65
+ include_owners = Boolean(is_searchable=True)
66
+ include_nested_fields = StringList(is_searchable=True, is_temporary=True)
67
+ include_hierarchy_fields = StringList(is_searchable=True, is_temporary=True)
68
+
69
+ def parse_hierarchy(self) -> dataclasses.ServiceEntityHierarchy:
70
+ """Parse the hierarchy column into a dictionary."""
71
+ return from_dict(dataclasses.ServiceEntityHierarchy, data=self.hierarchy)
72
+
49
73
  def parse_groups(self) -> dict[str, str]:
50
74
  """
51
75
  Parse the strings of groups.
@@ -60,3 +84,7 @@ class CortexCatalogEntity(Model):
60
84
  if len(splitted) > 1:
61
85
  parsed[splitted[0]] = splitted[1]
62
86
  return parsed
87
+
88
+ def parse_owners(self) -> dataclasses.EntityTeamOwner:
89
+ """Parse the owners column into a dictionary."""
90
+ return from_dict(dataclasses.EntityTeamOwner, data=self.owners)
@@ -1,6 +1,7 @@
1
1
  from typing import Any, Self
2
2
 
3
3
  from clearskies import Column
4
+ from clearskies.query import Condition, Query
4
5
 
5
6
  from clearskies_cortex.models import cortex_catalog_entity
6
7
 
@@ -8,18 +9,30 @@ from clearskies_cortex.models import cortex_catalog_entity
8
9
  class CortexCatalogEntityDomain(cortex_catalog_entity.CortexCatalogEntity):
9
10
  """Model for domain entities."""
10
11
 
11
- def where_for_request(
12
- self: Self,
13
- model: Self,
14
- input_output: Any,
15
- routing_data: dict[str, str],
16
- authorization_data: dict[str, Any],
17
- overrides: dict[str, Column] = {},
18
- ) -> Self:
12
+ def get_final_query(self) -> Query:
19
13
  return (
20
- model.where("types=domain")
21
- .where("include_nested_fields=team:members")
22
- .where("include_owners=true")
23
- .where("include_metadata=true")
24
- .where("include_hierarchy_fields=groups")
14
+ self.get_query()
15
+ .add_where(Condition("types=domain"))
16
+ .add_where(Condition("include_nested_fields=team:members"))
17
+ .add_where(Condition("include_owners=true"))
18
+ .add_where(Condition("include_metadata=true"))
19
+ .add_where(Condition("include_hierarchy_fields=groups"))
25
20
  )
21
+
22
+ def get_top_level_domain(self: Self) -> Self:
23
+ """Get the upper domain of this service if set."""
24
+ hierarchy = self.parse_hierarchy()
25
+ if hierarchy.parents:
26
+ parent = hierarchy.parents[0]
27
+ while parent.parents:
28
+ parent = parent.parents[0]
29
+ return self.as_query().find(f"tag={parent.tag}")
30
+ return self.empty()
31
+
32
+ def get_parent(self: Self) -> Self:
33
+ """Get the first domain of this service if set."""
34
+ hierarchy = self.parse_hierarchy()
35
+ if hierarchy.parents:
36
+ container = hierarchy.parents[0]
37
+ return self.as_query().find(f"tag={container.tag}")
38
+ return self.empty()
@@ -1,8 +1,9 @@
1
1
  import logging
2
- from typing import Any, Self, cast
2
+ from typing import Any, Iterator, Self, cast
3
3
 
4
4
  from clearskies import Column
5
5
  from clearskies.di import inject
6
+ from clearskies.query import Condition, Query
6
7
  from dacite import from_dict
7
8
 
8
9
  from clearskies_cortex import dataclasses
@@ -13,8 +14,6 @@ from clearskies_cortex.models import (
13
14
  cortex_team,
14
15
  )
15
16
 
16
- logger = logging.getLogger(__name__)
17
-
18
17
 
19
18
  class CortexCatalogEntityService(cortex_catalog_entity.CortexCatalogEntity):
20
19
  """Model for domain entities."""
@@ -24,51 +23,19 @@ class CortexCatalogEntityService(cortex_catalog_entity.CortexCatalogEntity):
24
23
  teams = inject.ByClass(cortex_team.CortexTeam)
25
24
  entity_domains = inject.ByClass(cortex_catalog_entity_domain.CortexCatalogEntityDomain)
26
25
 
27
- def where_for_request(
28
- self: Self,
29
- model: Self,
30
- input_output: Any,
31
- routing_data: dict[str, str],
32
- authorization_data: dict[str, Any],
33
- overrides: dict[str, Column] = {},
34
- ) -> Self:
35
- """Return iterable models."""
26
+ def get_final_query(self) -> Query:
36
27
  return (
37
- model.where("types=service")
38
- .where("include_nested_fields=team:members")
39
- .where("include_owners=true")
40
- .where("include_metadata=true")
41
- .where("include_hierarchy_fields=groups")
28
+ self.get_query()
29
+ .add_where(Condition("types=service"))
30
+ .add_where(Condition("include_nested_fields=team:members"))
31
+ .add_where(Condition("include_owners=true"))
32
+ .add_where(Condition("include_metadata=true"))
33
+ .add_where(Condition("include_hierarchy_fields=groups"))
42
34
  )
43
35
 
44
- def get_software_domain(self: Self) -> cortex_catalog_entity_domain.CortexCatalogEntityDomain:
45
- """Get the upper domain of this service if set."""
46
- hierarchy = from_dict(dataclasses.ServiceEntityHierarchy, data=self.hierarchy)
47
- if hierarchy.parents:
48
- parent = hierarchy.parents[0]
49
- while parent.parents:
50
- parent = parent.parents[0]
51
- return cast(
52
- cortex_catalog_entity_domain.CortexCatalogEntityDomain,
53
- self.entity_domains.find(f"tag={parent.tag}"),
54
- )
55
- return cast(cortex_catalog_entity_domain.CortexCatalogEntityDomain, self.entity_domains.empty())
56
-
57
- def get_software_container(self: Self) -> cortex_catalog_entity_domain.CortexCatalogEntityDomain:
58
- """Get the first domain of this service if set."""
59
- hierarchy = from_dict(dataclasses.ServiceEntityHierarchy, data=self.hierarchy)
60
- if hierarchy.parents:
61
- container = hierarchy.parents[0]
62
- return cast(
63
- cortex_catalog_entity_domain.CortexCatalogEntityDomain,
64
- self.entity_domains.find(f"tag={container.tag}"),
65
- )
66
- return cast(cortex_catalog_entity_domain.CortexCatalogEntityDomain, self.entity_domains.empty())
67
-
68
36
  def get_top_level_team(self: Self) -> cortex_team.CortexTeam:
69
37
  """Find the top level team based on the team ownership."""
70
38
  team = self.get_team()
71
-
72
39
  if team:
73
40
  return team.find_top_level_team()
74
41
 
@@ -76,17 +43,34 @@ class CortexCatalogEntityService(cortex_catalog_entity.CortexCatalogEntity):
76
43
 
77
44
  def get_team(self: Self) -> cortex_team.CortexTeam:
78
45
  """Find the team based on the team ownership."""
79
- team = cast(cortex_team.CortexTeam, self.teams.empty())
80
- if not self.ownersV2:
46
+ team = self.teams.empty()
47
+ self.logger.debug(f"EntityService: owners {self.owners}")
48
+ if not self.owners:
81
49
  return team
82
-
83
- logger.debug(f"EntityService: ownersV2 {self.ownersV2}")
84
- owners = from_dict(dataclasses.EntityTeamOwner, data=self.ownersV2)
85
-
50
+ owners = self.parse_owners()
51
+ self.logger.debug(f"Parsed owners: {owners}")
86
52
  if not owners.teams:
87
53
  return team
88
54
 
89
55
  entity_team = owners.teams[0]
90
- logger.debug(f"Found entity team: {entity_team}")
56
+ self.logger.debug(f"Found entity team: {entity_team}")
91
57
 
92
58
  return self.teams.find(f"team_tag={entity_team.tag}")
59
+
60
+ def get_top_level_domain(self: Self) -> cortex_catalog_entity_domain.CortexCatalogEntityDomain:
61
+ """Get the upper domain of this service if set."""
62
+ hierarchy = self.parse_hierarchy()
63
+ if hierarchy.parents:
64
+ parent = hierarchy.parents[0]
65
+ while parent.parents:
66
+ parent = parent.parents[0]
67
+ return self.entity_domains.find(f"tag={parent.tag}")
68
+ return self.entity_domains.empty()
69
+
70
+ def get_parent_domain(self: Self) -> cortex_catalog_entity_domain.CortexCatalogEntityDomain:
71
+ """Get the first domain of this service if set."""
72
+ hierarchy = self.parse_hierarchy()
73
+ if hierarchy.parents:
74
+ container = hierarchy.parents[0]
75
+ return self.entity_domains.find(f"tag={container.tag}")
76
+ return self.entity_domains.empty()
@@ -0,0 +1,38 @@
1
+ from typing import Any, Self
2
+
3
+ from clearskies import Column
4
+ from clearskies.query import Condition, Query
5
+
6
+ from clearskies_cortex.models import cortex_catalog_entity
7
+
8
+
9
+ class CortexCatalogEntityTeam(cortex_catalog_entity.CortexCatalogEntity):
10
+ """Model for team entities."""
11
+
12
+ def get_final_query(self) -> Query:
13
+ return (
14
+ self.get_query()
15
+ .add_where(Condition("types=team"))
16
+ .add_where(Condition("include_nested_fields=team:members"))
17
+ .add_where(Condition("include_owners=true"))
18
+ .add_where(Condition("include_metadata=true"))
19
+ .add_where(Condition("include_hierarchy_fields=groups"))
20
+ )
21
+
22
+ def get_top_level_team(self: Self) -> Self:
23
+ """Get the upper team of this service if set."""
24
+ hierarchy = self.parse_hierarchy()
25
+ if hierarchy.parents:
26
+ parent = hierarchy.parents[0]
27
+ while parent.parents:
28
+ parent = parent.parents[0]
29
+ return self.as_query().find(f"tag={parent.tag}")
30
+ return self.empty()
31
+
32
+ def get_parent(self: Self) -> Self:
33
+ """Get the first team of this service if set."""
34
+ hierarchy = self.parse_hierarchy()
35
+ if hierarchy.parents:
36
+ team = hierarchy.parents[0]
37
+ return self.as_query().find(f"tag={team.tag}")
38
+ return self.empty()
@@ -1,4 +1,4 @@
1
- from typing import Self, cast
1
+ from typing import Self
2
2
 
3
3
  from clearskies import Model
4
4
  from clearskies.columns import (
@@ -8,6 +8,7 @@ from clearskies.columns import (
8
8
  CategoryTreeAncestors,
9
9
  CategoryTreeChildren,
10
10
  CategoryTreeDescendants,
11
+ Datetime,
11
12
  Json,
12
13
  String,
13
14
  )
@@ -21,7 +22,11 @@ class CortexTeam(Model):
21
22
 
22
23
  id_column_name: str = "team_tag"
23
24
 
24
- backend = CortexBackend()
25
+ backend = CortexBackend(
26
+ api_to_model_map={
27
+ "cortexTeam.members": "members",
28
+ }
29
+ )
25
30
 
26
31
  @classmethod
27
32
  def destination_name(cls: type[Self]) -> str:
@@ -45,8 +50,10 @@ class CortexTeam(Model):
45
50
  metadata = Json()
46
51
  slack_channels = Json()
47
52
  type = String()
48
- cortex_team = Json()
53
+ members = Json()
49
54
  id = String()
55
+ last_updated = Datetime()
56
+ include_teams_without_members = Boolean(is_searchable=True, is_temporary=True)
50
57
 
51
58
  def get_name(self) -> str:
52
59
  """Retrieve name from metadata."""