From 67c57f962149c93e60c5c2dcb3bce738f8576961 Mon Sep 17 00:00:00 2001 From: Serhii Buniak Date: Wed, 14 Jul 2021 13:40:22 +0300 Subject: [PATCH 1/8] Update SDK due to new changes in openapi spec --- okta/models/__init__.py | 20 +++ okta/models/user_schema.py | 16 +- okta/models/user_schema_attribute.py | 98 ++++++++++++- okta/models/user_schema_attribute_enum.py | 49 +++++++ okta/models/user_schema_attribute_items.py | 62 ++++++++ okta/models/user_schema_attribute_master.py | 26 +++- .../user_schema_attribute_master_priority.py | 49 +++++++ .../user_schema_attribute_master_type.py | 34 +++++ okta/models/user_schema_attribute_scope.py | 33 +++++ okta/models/user_schema_attribute_type.py | 36 +++++ okta/models/user_schema_attribute_union.py | 33 +++++ okta/models/user_schema_properties.py | 57 ++++++++ okta/models/user_schema_properties_profile.py | 51 +++++++ .../user_schema_properties_profile_item.py | 45 ++++++ okta/resource_clients/group_client.py | 9 +- okta/resource_clients/network_zone_client.py | 32 +++- tests/integration/test_network_zone_it.py | 5 +- tests/unit/test_user_schema.py | 137 ++++++++++++++++++ 18 files changed, 770 insertions(+), 22 deletions(-) create mode 100644 okta/models/user_schema_attribute_enum.py create mode 100644 okta/models/user_schema_attribute_items.py create mode 100644 okta/models/user_schema_attribute_master_priority.py create mode 100644 okta/models/user_schema_attribute_master_type.py create mode 100644 okta/models/user_schema_attribute_scope.py create mode 100644 okta/models/user_schema_attribute_type.py create mode 100644 okta/models/user_schema_attribute_union.py create mode 100644 okta/models/user_schema_properties.py create mode 100644 okta/models/user_schema_properties_profile.py create mode 100644 okta/models/user_schema_properties_profile_item.py create mode 100644 tests/unit/test_user_schema.py diff --git a/okta/models/__init__.py b/okta/models/__init__.py index 12bec8e5..91671288 100644 --- a/okta/models/__init__.py +++ b/okta/models/__init__.py @@ -690,16 +690,36 @@ UserSchema = user_schema.UserSchema from okta.models import user_schema_attribute as user_schema_attribute UserSchemaAttribute = user_schema_attribute.UserSchemaAttribute +from okta.models import user_schema_attribute_enum as user_schema_attribute_enum +UserSchemaAttributeEnum = user_schema_attribute_enum.UserSchemaAttributeEnum +from okta.models import user_schema_attribute_items as user_schema_attribute_items +UserSchemaAttributeItems = user_schema_attribute_items.UserSchemaAttributeItems from okta.models import user_schema_attribute_master as user_schema_attribute_master UserSchemaAttributeMaster = user_schema_attribute_master.UserSchemaAttributeMaster +from okta.models import user_schema_attribute_master_priority as user_schema_attribute_master_priority +UserSchemaAttributeMasterPriority = user_schema_attribute_master_priority.UserSchemaAttributeMasterPriority +from okta.models import user_schema_attribute_master_type as user_schema_attribute_master_type +UserSchemaAttributeMasterType = user_schema_attribute_master_type.UserSchemaAttributeMasterType from okta.models import user_schema_attribute_permission as user_schema_attribute_permission UserSchemaAttributePermission = user_schema_attribute_permission.UserSchemaAttributePermission +from okta.models import user_schema_attribute_scope as user_schema_attribute_scope +UserSchemaAttributeScope = user_schema_attribute_scope.UserSchemaAttributeScope +from okta.models import user_schema_attribute_type as user_schema_attribute_type +UserSchemaAttributeType = user_schema_attribute_type.UserSchemaAttributeType +from okta.models import user_schema_attribute_union as user_schema_attribute_union +UserSchemaAttributeUnion = user_schema_attribute_union.UserSchemaAttributeUnion from okta.models import user_schema_base as user_schema_base UserSchemaBase = user_schema_base.UserSchemaBase from okta.models import user_schema_base_properties as user_schema_base_properties UserSchemaBaseProperties = user_schema_base_properties.UserSchemaBaseProperties from okta.models import user_schema_definitions as user_schema_definitions UserSchemaDefinitions = user_schema_definitions.UserSchemaDefinitions +from okta.models import user_schema_properties as user_schema_properties +UserSchemaProperties = user_schema_properties.UserSchemaProperties +from okta.models import user_schema_properties_profile as user_schema_properties_profile +UserSchemaPropertiesProfile = user_schema_properties_profile.UserSchemaPropertiesProfile +from okta.models import user_schema_properties_profile_item as user_schema_properties_profile_item +UserSchemaPropertiesProfileItem = user_schema_properties_profile_item.UserSchemaPropertiesProfileItem from okta.models import user_schema_public as user_schema_public UserSchemaPublic = user_schema_public.UserSchemaPublic from okta.models import user_status as user_status diff --git a/okta/models/user_schema.py b/okta/models/user_schema.py index e53b92fa..ae2a1a2c 100644 --- a/okta/models/user_schema.py +++ b/okta/models/user_schema.py @@ -21,6 +21,8 @@ from okta.okta_object import OktaObject from okta.models import user_schema_definitions\ as user_schema_definitions +from okta.models import user_schema_properties\ + as user_schema_properties class UserSchema( @@ -57,8 +59,18 @@ def __init__(self, config=None): if "lastUpdated" in config else None self.name = config["name"]\ if "name" in config else None - self.properties = config["properties"]\ - if "properties" in config else None + if "properties" in config: + if isinstance(config["properties"], + user_schema_properties.UserSchemaProperties): + self.properties = config["properties"] + elif config["properties"] is not None: + self.properties = user_schema_properties.UserSchemaProperties( + config["properties"] + ) + else: + self.properties = None + else: + self.properties = None self.title = config["title"]\ if "title" in config else None self.type = config["type"]\ diff --git a/okta/models/user_schema_attribute.py b/okta/models/user_schema_attribute.py index 4497b197..21ad1122 100644 --- a/okta/models/user_schema_attribute.py +++ b/okta/models/user_schema_attribute.py @@ -20,10 +20,20 @@ from okta.okta_object import OktaObject from okta.okta_collection import OktaCollection +from okta.models import user_schema_attribute_items\ + as user_schema_attribute_items from okta.models import user_schema_attribute_master\ as user_schema_attribute_master +from okta.models import user_schema_attribute_enum\ + as user_schema_attribute_enum from okta.models import user_schema_attribute_permission\ as user_schema_attribute_permission +from okta.models import user_schema_attribute_scope\ + as user_schema_attribute_scope +from okta.models import user_schema_attribute_type\ + as user_schema_attribute_type +from okta.models import user_schema_attribute_union\ + as user_schema_attribute_union class UserSchemaAttribute( @@ -38,6 +48,27 @@ def __init__(self, config=None): if config: self.description = config["description"]\ if "description" in config else None + self.enum = OktaCollection.form_list( + config["enum"] if "enum"\ + in config else [], + str + ) + self.external_name = config["externalName"]\ + if "externalName" in config else None + self.external_namespace = config["externalNamespace"]\ + if "externalNamespace" in config else None + if "items" in config: + if isinstance(config["items"], + user_schema_attribute_items.UserSchemaAttributeItems): + self.items = config["items"] + elif config["items"] is not None: + self.items = user_schema_attribute_items.UserSchemaAttributeItems( + config["items"] + ) + else: + self.items = None + else: + self.items = None if "master" in config: if isinstance(config["master"], user_schema_attribute_master.UserSchemaAttributeMaster): @@ -56,6 +87,13 @@ def __init__(self, config=None): if "minLength" in config else None self.mutability = config["mutability"]\ if "mutability" in config else None + self.one_of = OktaCollection.form_list( + config["oneOf"] if "oneOf"\ + in config else [], + user_schema_attribute_enum.UserSchemaAttributeEnum + ) + self.pattern = config["pattern"]\ + if "pattern" in config else None self.permissions = OktaCollection.form_list( config["permissions"] if "permissions"\ in config else [], @@ -63,37 +101,87 @@ def __init__(self, config=None): ) self.required = config["required"]\ if "required" in config else None - self.scope = config["scope"]\ - if "scope" in config else None + if "scope" in config: + if isinstance(config["scope"], + user_schema_attribute_scope.UserSchemaAttributeScope): + self.scope = config["scope"] + elif config["scope"] is not None: + self.scope = user_schema_attribute_scope.UserSchemaAttributeScope( + config["scope"].upper() + ) + else: + self.scope = None + else: + self.scope = None self.title = config["title"]\ if "title" in config else None - self.type = config["type"]\ - if "type" in config else None + if "type" in config: + if isinstance(config["type"], + user_schema_attribute_type.UserSchemaAttributeType): + self.type = config["type"] + elif config["type"] is not None: + self.type = user_schema_attribute_type.UserSchemaAttributeType( + config["type"].upper() + ) + else: + self.type = None + else: + self.type = None + if "union" in config: + if isinstance(config["union"], + user_schema_attribute_union.UserSchemaAttributeUnion): + self.union = config["union"] + elif config["union"] is not None: + self.union = user_schema_attribute_union.UserSchemaAttributeUnion( + config["union"].upper() + ) + else: + self.union = None + else: + self.union = None + self.unique = config["unique"]\ + if "unique" in config else None else: self.description = None + self.enum = [] + self.external_name = None + self.external_namespace = None + self.items = None self.master = None self.max_length = None self.min_length = None self.mutability = None + self.one_of = [] + self.pattern = None self.permissions = [] self.required = None self.scope = None self.title = None self.type = None + self.union = None + self.unique = None def request_format(self): parent_req_format = super().request_format() current_obj_format = { "description": self.description, + "enum": self.enum, + "externalName": self.external_name, + "externalNamespace": self.external_namespace, + "items": self.items, "master": self.master, "maxLength": self.max_length, "minLength": self.min_length, "mutability": self.mutability, + "oneOf": self.one_of, + "pattern": self.pattern, "permissions": self.permissions, "required": self.required, "scope": self.scope, "title": self.title, - "type": self.type + "type": self.type, + "union": self.union, + "unique": self.unique } parent_req_format.update(current_obj_format) return parent_req_format diff --git a/okta/models/user_schema_attribute_enum.py b/okta/models/user_schema_attribute_enum.py new file mode 100644 index 00000000..190389f0 --- /dev/null +++ b/okta/models/user_schema_attribute_enum.py @@ -0,0 +1,49 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from okta.okta_object import OktaObject + + +class UserSchemaAttributeEnum( + OktaObject +): + """ + A class for UserSchemaAttributeEnum objects. + """ + + def __init__(self, config=None): + super().__init__(config) + if config: + self.const = config["const"]\ + if "const" in config else None + self.title = config["title"]\ + if "title" in config else None + else: + self.const = None + self.title = None + + def request_format(self): + parent_req_format = super().request_format() + current_obj_format = { + "const": self.const, + "title": self.title + } + parent_req_format.update(current_obj_format) + return parent_req_format diff --git a/okta/models/user_schema_attribute_items.py b/okta/models/user_schema_attribute_items.py new file mode 100644 index 00000000..18cee135 --- /dev/null +++ b/okta/models/user_schema_attribute_items.py @@ -0,0 +1,62 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from okta.okta_object import OktaObject +from okta.okta_collection import OktaCollection +from okta.models import user_schema_attribute_enum\ + as user_schema_attribute_enum + + +class UserSchemaAttributeItems( + OktaObject +): + """ + A class for UserSchemaAttributeItems objects. + """ + + def __init__(self, config=None): + super().__init__(config) + if config: + self.enum = OktaCollection.form_list( + config["enum"] if "enum"\ + in config else [], + str + ) + self.one_of = OktaCollection.form_list( + config["oneOf"] if "oneOf"\ + in config else [], + user_schema_attribute_enum.UserSchemaAttributeEnum + ) + self.type = config["type"]\ + if "type" in config else None + else: + self.enum = [] + self.one_of = [] + self.type = None + + def request_format(self): + parent_req_format = super().request_format() + current_obj_format = { + "enum": self.enum, + "oneOf": self.one_of, + "type": self.type + } + parent_req_format.update(current_obj_format) + return parent_req_format diff --git a/okta/models/user_schema_attribute_master.py b/okta/models/user_schema_attribute_master.py index 4ae3f4ff..d56745ce 100644 --- a/okta/models/user_schema_attribute_master.py +++ b/okta/models/user_schema_attribute_master.py @@ -19,6 +19,11 @@ # SEE CONTRIBUTOR DOCUMENTATION from okta.okta_object import OktaObject +from okta.okta_collection import OktaCollection +from okta.models import user_schema_attribute_master_priority\ + as user_schema_attribute_master_priority +from okta.models import user_schema_attribute_master_type\ + as user_schema_attribute_master_type class UserSchemaAttributeMaster( @@ -31,14 +36,31 @@ class UserSchemaAttributeMaster( def __init__(self, config=None): super().__init__(config) if config: - self.type = config["type"]\ - if "type" in config else None + self.priority = OktaCollection.form_list( + config["priority"] if "priority"\ + in config else [], + user_schema_attribute_master_priority.UserSchemaAttributeMasterPriority + ) + if "type" in config: + if isinstance(config["type"], + user_schema_attribute_master_type.UserSchemaAttributeMasterType): + self.type = config["type"] + elif config["type"] is not None: + self.type = user_schema_attribute_master_type.UserSchemaAttributeMasterType( + config["type"].upper() + ) + else: + self.type = None + else: + self.type = None else: + self.priority = [] self.type = None def request_format(self): parent_req_format = super().request_format() current_obj_format = { + "priority": self.priority, "type": self.type } parent_req_format.update(current_obj_format) diff --git a/okta/models/user_schema_attribute_master_priority.py b/okta/models/user_schema_attribute_master_priority.py new file mode 100644 index 00000000..3d0507cc --- /dev/null +++ b/okta/models/user_schema_attribute_master_priority.py @@ -0,0 +1,49 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from okta.okta_object import OktaObject + + +class UserSchemaAttributeMasterPriority( + OktaObject +): + """ + A class for UserSchemaAttributeMasterPriority objects. + """ + + def __init__(self, config=None): + super().__init__(config) + if config: + self.type = config["type"]\ + if "type" in config else None + self.valuse = config["valuse"]\ + if "valuse" in config else None + else: + self.type = None + self.valuse = None + + def request_format(self): + parent_req_format = super().request_format() + current_obj_format = { + "type": self.type, + "valuse": self.valuse + } + parent_req_format.update(current_obj_format) + return parent_req_format diff --git a/okta/models/user_schema_attribute_master_type.py b/okta/models/user_schema_attribute_master_type.py new file mode 100644 index 00000000..dbe7276c --- /dev/null +++ b/okta/models/user_schema_attribute_master_type.py @@ -0,0 +1,34 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from aenum import MultiValueEnum + + +class UserSchemaAttributeMasterType( + str, + MultiValueEnum +): + """ + An enumeration class for UserSchemaAttributeMasterType. + """ + + PROFILE_MASTER = "PROFILE_MASTER", "profile_master" + OKTA = "OKTA", "okta" + OVERRIDE = "OVERRIDE", "override" diff --git a/okta/models/user_schema_attribute_scope.py b/okta/models/user_schema_attribute_scope.py new file mode 100644 index 00000000..1b4b9118 --- /dev/null +++ b/okta/models/user_schema_attribute_scope.py @@ -0,0 +1,33 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from aenum import MultiValueEnum + + +class UserSchemaAttributeScope( + str, + MultiValueEnum +): + """ + An enumeration class for UserSchemaAttributeScope. + """ + + SELF = "SELF", "self" + NONE = "NONE", "none" diff --git a/okta/models/user_schema_attribute_type.py b/okta/models/user_schema_attribute_type.py new file mode 100644 index 00000000..1c926dab --- /dev/null +++ b/okta/models/user_schema_attribute_type.py @@ -0,0 +1,36 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from aenum import MultiValueEnum + + +class UserSchemaAttributeType( + str, + MultiValueEnum +): + """ + An enumeration class for UserSchemaAttributeType. + """ + + STRING = "string", "STRING" + BOOLEAN = "boolean", "BOOLEAN" + NUMBER = "number", "NUMBER" + INTEGER = "integer", "INTEGER" + ARRAY = "array", "ARRAY" diff --git a/okta/models/user_schema_attribute_union.py b/okta/models/user_schema_attribute_union.py new file mode 100644 index 00000000..911e7058 --- /dev/null +++ b/okta/models/user_schema_attribute_union.py @@ -0,0 +1,33 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from aenum import MultiValueEnum + + +class UserSchemaAttributeUnion( + str, + MultiValueEnum +): + """ + An enumeration class for UserSchemaAttributeUnion. + """ + + DISABLE = "DISABLE", "disable" + ENABLE = "ENABLE", "enable" diff --git a/okta/models/user_schema_properties.py b/okta/models/user_schema_properties.py new file mode 100644 index 00000000..dd62f127 --- /dev/null +++ b/okta/models/user_schema_properties.py @@ -0,0 +1,57 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from okta.okta_object import OktaObject +from okta.models import user_schema_properties_profile\ + as user_schema_properties_profile + + +class UserSchemaProperties( + OktaObject +): + """ + A class for UserSchemaProperties objects. + """ + + def __init__(self, config=None): + super().__init__(config) + if config: + if "profile" in config: + if isinstance(config["profile"], + user_schema_properties_profile.UserSchemaPropertiesProfile): + self.profile = config["profile"] + elif config["profile"] is not None: + self.profile = user_schema_properties_profile.UserSchemaPropertiesProfile( + config["profile"] + ) + else: + self.profile = None + else: + self.profile = None + else: + self.profile = None + + def request_format(self): + parent_req_format = super().request_format() + current_obj_format = { + "profile": self.profile + } + parent_req_format.update(current_obj_format) + return parent_req_format diff --git a/okta/models/user_schema_properties_profile.py b/okta/models/user_schema_properties_profile.py new file mode 100644 index 00000000..a51e35cf --- /dev/null +++ b/okta/models/user_schema_properties_profile.py @@ -0,0 +1,51 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from okta.okta_object import OktaObject +from okta.okta_collection import OktaCollection +from okta.models import user_schema_properties_profile_item\ + as user_schema_properties_profile_item + + +class UserSchemaPropertiesProfile( + OktaObject +): + """ + A class for UserSchemaPropertiesProfile objects. + """ + + def __init__(self, config=None): + super().__init__(config) + if config: + self.all_of = OktaCollection.form_list( + config["allOf"] if "allOf"\ + in config else [], + user_schema_properties_profile_item.UserSchemaPropertiesProfileItem + ) + else: + self.all_of = [] + + def request_format(self): + parent_req_format = super().request_format() + current_obj_format = { + "allOf": self.all_of + } + parent_req_format.update(current_obj_format) + return parent_req_format diff --git a/okta/models/user_schema_properties_profile_item.py b/okta/models/user_schema_properties_profile_item.py new file mode 100644 index 00000000..b60720ad --- /dev/null +++ b/okta/models/user_schema_properties_profile_item.py @@ -0,0 +1,45 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from okta.okta_object import OktaObject + + +class UserSchemaPropertiesProfileItem( + OktaObject +): + """ + A class for UserSchemaPropertiesProfileItem objects. + """ + + def __init__(self, config=None): + super().__init__(config) + if config: + self.ref = config["ref"]\ + if "ref" in config else None + else: + self.ref = None + + def request_format(self): + parent_req_format = super().request_format() + current_obj_format = { + "$ref": self.ref + } + parent_req_format.update(current_obj_format) + return parent_req_format diff --git a/okta/resource_clients/group_client.py b/okta/resource_clients/group_client.py index 1b72e2b8..3206688f 100644 --- a/okta/resource_clients/group_client.py +++ b/okta/resource_clients/group_client.py @@ -53,7 +53,7 @@ async def list_groups( Args: query_params {dict}: Map of query parameters for request [query_params.q] {str} - [query_params.filter] {str} + [query_params.search] {str} [query_params.after] {str} [query_params.limit] {str} [query_params.expand] {str} @@ -239,19 +239,24 @@ async def create_group_rule( return (result, response, None) async def delete_group_rule( - self, ruleId + self, ruleId, query_params={} ): """ Removes a specific group rule by id from your organizat ion Args: rule_id {str} + query_params {dict}: Map of query parameters for request + [query_params.removeUsers] {str} """ http_method = "delete".upper() api_url = format_url(f""" {self._base_url} /api/v1/groups/rules/{ruleId} """) + if query_params: + encoded_query_params = urlencode(query_params) + api_url += f"/?{encoded_query_params}" body = {} headers = {} diff --git a/okta/resource_clients/network_zone_client.py b/okta/resource_clients/network_zone_client.py index 1f47b403..715cc15f 100644 --- a/okta/resource_clients/network_zone_client.py +++ b/okta/resource_clients/network_zone_client.py @@ -255,6 +255,8 @@ async def activate_network_zone( Activate Network Zone Args: zone_id {str} + Returns: + NetworkZone """ http_method = "post".upper() api_url = format_url(f""" @@ -270,15 +272,21 @@ async def activate_network_zone( ) if error: - return (None, error) + return (None, None, error) response, error = await self._request_executor\ - .execute(request) + .execute(request, NetworkZone) if error: - return (response, error) + return (None, response, error) - return (response, None) + try: + result = NetworkZone( + self.form_response_body(response.get_body()) + ) + except Exception as error: + return (None, response, error) + return (result, response, None) async def deactivate_network_zone( self, zoneId @@ -287,6 +295,8 @@ async def deactivate_network_zone( Deactivates a network zone. Args: zone_id {str} + Returns: + NetworkZone """ http_method = "post".upper() api_url = format_url(f""" @@ -302,12 +312,18 @@ async def deactivate_network_zone( ) if error: - return (None, error) + return (None, None, error) response, error = await self._request_executor\ - .execute(request) + .execute(request, NetworkZone) if error: - return (response, error) + return (None, response, error) - return (response, None) + try: + result = NetworkZone( + self.form_response_body(response.get_body()) + ) + except Exception as error: + return (None, response, error) + return (result, response, None) diff --git a/tests/integration/test_network_zone_it.py b/tests/integration/test_network_zone_it.py index 06afe365..66acb0e4 100644 --- a/tests/integration/test_network_zone_it.py +++ b/tests/integration/test_network_zone_it.py @@ -61,13 +61,12 @@ async def test_create_and_delete_network_zone(self, fs): finally: errors = [] try: - _, err = await client.deactivate_network_zone(resp.id) + _, _, err = await client.deactivate_network_zone(resp.id) assert err is None except Exception as exc: errors.append(exc) try: _, err = await client.delete_network_zone(resp.id) - assert err is None except Exception as exc: errors.append(exc) assert len(errors) == 0 @@ -108,7 +107,7 @@ async def test_update_network_zone(self, fs): finally: errors = [] try: - _, err = await client.deactivate_network_zone(resp.id) + _, _, err = await client.deactivate_network_zone(resp.id) assert err is None except Exception as exc: errors.append(exc) diff --git a/tests/unit/test_user_schema.py b/tests/unit/test_user_schema.py new file mode 100644 index 00000000..a207ee7f --- /dev/null +++ b/tests/unit/test_user_schema.py @@ -0,0 +1,137 @@ +import aiohttp +import json +import pytest +from okta.client import Client as OktaClient +from okta.models import UserSchema + + +MOCK_RESPONSE = """{ + "id": "https://${yourOktaDomain}/meta/schemas/apps/0oa25gejWwdXNnFH90g4/default", + "$schema": "http://json-schema.org/draft-04/schema#", + "name": "Example App", + "title": "Example App User", + "lastUpdated": "2017-07-18T23:18:43.000Z", + "created": "2017-07-18T22:35:30.000Z", + "definitions": { + "base": { + "id": "#base", + "type": "object", + "properties": { + "login": { + "title": "Username", + "type": "string", + "required": true, + "scope": "NONE", + "minLength": 5, + "maxLength": 100 + } + }, + "required": [ + "login" + ] + }, + "custom": { + "id": "#custom", + "type": "object", + "properties": { + }, + "required": [] + } + }, + "type": "object", + "properties": { + "profile": { + "allOf": [ + { + "$ref": "#/definitions/base" + }, + { + "$ref": "#/definitions/custom" + } + ] + } + } + }""" + + +class MockHTTPRequest(): + def __call__(self, **params): + self.request_info = params + self.headers = params['headers'] + self.url = params['url'] + self.content_type = 'application/json' + self.links = '' + self.text = MockHTTPRequest.mock_response_text + self.status = 200 + return self + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + pass + + @staticmethod + async def mock_response_text(): + return MOCK_RESPONSE + + +class TestUserSchemaResource: + """ + Unit Tests for the User Schema Resource + """ + + @pytest.mark.asyncio + async def test_get_application_user_schema(self, monkeypatch): + mock_http_request = MockHTTPRequest() + monkeypatch.setattr(aiohttp, 'request', mock_http_request) + + org_url = "https://test.okta.com" + token = "TOKEN" + config = {'orgUrl': org_url, 'token': token} + client = OktaClient(config) + + resp, _, err = await client.get_application_user_schema('0oa25gejWwdXNnFH90g4') + assert err is None + assert isinstance(resp, UserSchema) + assert resp.schema == 'http://json-schema.org/draft-04/schema#' + assert resp.name == 'Example App' + assert resp.title == 'Example App User' + assert resp.type == 'object' + assert resp.definitions.base.id == '#base' + assert resp.definitions.base.type == 'object' + assert resp.definitions.base.properties.login.title == 'Username' + assert resp.definitions.base.properties.login.type == 'string' + assert resp.definitions.base.properties.login.required + assert resp.definitions.base.properties.login.scope == 'NONE' + assert resp.definitions.base.properties.login.min_length == 5 + assert resp.definitions.base.properties.login.max_length == 100 + assert 'login' in resp.definitions.base.required + + @pytest.mark.asyncio + async def test_update_application_user_profile(self, monkeypatch): + mock_http_request = MockHTTPRequest() + monkeypatch.setattr(aiohttp, 'request', mock_http_request) + + org_url = "https://test.okta.com" + token = "TOKEN" + config = {'orgUrl': org_url, 'token': token} + client = OktaClient(config) + + schema = UserSchema(json.loads(MOCK_RESPONSE)) + resp, _, err = await client.update_application_user_profile('0oa25gejWwdXNnFH90g4', schema) + assert err is None + assert isinstance(resp, UserSchema) + assert resp.schema == 'http://json-schema.org/draft-04/schema#' + assert resp.name == 'Example App' + assert resp.title == 'Example App User' + assert resp.type == 'object' + assert resp.definitions.base.id == '#base' + assert resp.definitions.base.type == 'object' + assert resp.definitions.base.properties.login.title == 'Username' + assert resp.definitions.base.properties.login.type == 'string' + assert resp.definitions.base.properties.login.required + assert resp.definitions.base.properties.login.scope == 'NONE' + assert resp.definitions.base.properties.login.min_length == 5 + assert resp.definitions.base.properties.login.max_length == 100 + assert 'login' in resp.definitions.base.required From 802d8c7f8430b538c41811046a4505190b794a11 Mon Sep 17 00:00:00 2001 From: Serhii Buniak Date: Wed, 14 Jul 2021 15:59:48 +0300 Subject: [PATCH 2/8] Update Domains resource and unittests due to changes in openapi spec. --- okta/models/dns_record.py | 4 ++ okta/models/domain_response.py | 4 ++ tests/unit/test_domains.py | 102 ++++++++++++++++++++++++++++++++- 3 files changed, 109 insertions(+), 1 deletion(-) diff --git a/okta/models/dns_record.py b/okta/models/dns_record.py index 54693e35..160c1e11 100644 --- a/okta/models/dns_record.py +++ b/okta/models/dns_record.py @@ -32,6 +32,8 @@ class DnsRecord( def __init__(self, config=None): super().__init__(config) if config: + self.expiration = config["expiration"]\ + if "expiration" in config else None self.fqdn = config["fqdn"]\ if "fqdn" in config else None self.record_type = config["recordType"]\ @@ -42,6 +44,7 @@ def __init__(self, config=None): str ) else: + self.expiration = None self.fqdn = None self.record_type = None self.values = [] @@ -49,6 +52,7 @@ def __init__(self, config=None): def request_format(self): parent_req_format = super().request_format() current_obj_format = { + "expiration": self.expiration, "fqdn": self.fqdn, "recordType": self.record_type, "values": self.values diff --git a/okta/models/domain_response.py b/okta/models/domain_response.py index 938341d2..bd96c505 100644 --- a/okta/models/domain_response.py +++ b/okta/models/domain_response.py @@ -50,6 +50,8 @@ def __init__(self, config=None): self.links = None else: self.links = None + self.certificate_sourcetype = config["certificateSourcetype"]\ + if "certificateSourcetype" in config else None self.dns_records = OktaCollection.form_list( config["dnsRecords"] if "dnsRecords"\ in config else [], @@ -75,6 +77,7 @@ def __init__(self, config=None): if "validationStatus" in config else None else: self.links = None + self.certificate_sourcetype = None self.dns_records = [] self.domain = None self.id = None @@ -85,6 +88,7 @@ def request_format(self): parent_req_format = super().request_format() current_obj_format = { "_links": self.links, + "certificateSourcetype": self.certificate_sourcetype, "dnsRecords": self.dns_records, "domain": self.domain, "id": self.id, diff --git a/tests/unit/test_domains.py b/tests/unit/test_domains.py index ac949880..47a5390c 100644 --- a/tests/unit/test_domains.py +++ b/tests/unit/test_domains.py @@ -1,7 +1,7 @@ import aiohttp import asyncio from okta.client import Client as OktaClient -from okta.models import DomainCertificate +from okta.models import DnsRecord, DomainCertificate, DomainCertificateMetadata, DomainResponse CREATE_DOMAIN_RESP = """{ @@ -45,9 +45,11 @@ } }""" + VERIFY_DOMAIN_RESP = """{ "id": "OcDz6iRyjkaCTXkdo0g3", "domain": "login.example.com", + "certificateSourceType": "MANUAL", "validationStatus": "VERIFIED", "dnsRecords": [ { @@ -66,6 +68,14 @@ } ], "_links": { + "certificate": { + "href": "https://test.okta.com/api/v1/domains/OcDz6iRyjkaCTXkdo0g3/certificate", + "hints": { + "allow": [ + "PUT" + ] + } + }, "self": { "href": "https://test.okta.com/api/v1/domains/OcDz6iRyjkaCTXkdo0g3", "hints": { @@ -74,6 +84,53 @@ "DELETE" ] } + } + } +}""" + + +GET_DOMAIN_RESP = """{ + "id": "OcDz6iRyjkaCTXkdo0g3", + "domain": "login.example.com", + "certificateSourceType": "MANUAL", + "validationStatus": "COMPLETED", + "dnsRecords": [ + { + "fqdn": "_oktaverification.login.example.com", + "values": [ + "79496f234c814638b1cc44f51a782781" + ], + "recordType": "TXT" + }, + { + "fqdn": "login.example.com", + "values": [ + "test.okta.com.customdomains.okta1.com" + ], + "recordType": "CNAME" + } + ], + "publicCertificate": { + "subject": "CN=login.example.com", + "fingerprint": "73:68:82:7B:83:2E:48:29:A5:5E:E8:40:41:80:B3:AA:03:C4:42:43:05:73:45:BC:AA:47:00:23:A3:70:E5:C4", + "expiration": "2021-05-11T05:13:05.000Z" + }, + "_links": { + "certificate": { + "href": "https://test.okta.com/api/v1/domains/OcDz6iRyjkaCTXkdo0g3/certificate", + "hints": { + "allow": [ + "PUT" + ] + } + }, + "self": { + "href": "https://test.okta.com/api/v1/domains/OcDz6iRyjkaCTXkdo0g3", + "hints": { + "allow": [ + "DELETE" + ] + } }, "verify": { "href": "https://test.okta.com/api/v1/domains/OcDz6iRyjkaCTXkdo0g3/verify", @@ -92,6 +149,49 @@ class TestDomainResource: Unit Tests for the Domain Resource """ + def test_get_domain(self, monkeypatch): + org_url = "https://test.okta.com" + token = "TOKEN" + config = {'orgUrl': org_url, 'token': token} + client = OktaClient(config) + + # mock http requests + class MockHTTPRequest(): + + _mocked_response = None + + def __call__(self, **params): + self.request_info = params + self.headers = params['headers'] + self.url = params['url'] + self.content_type = 'application/json' + self.links = '' + self.text = MockHTTPRequest.mock_response_text + self.status = 200 + return self + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + pass + + @staticmethod + async def mock_response_text(): + return GET_DOMAIN_RESP + + mock_http_request = MockHTTPRequest() + monkeypatch.setattr(aiohttp, 'request', mock_http_request) + + domain_resp, _, err = asyncio.run(client.get_domain('OcDz6iRyjkaCTXkdo0g3')) + assert err is None + assert isinstance(domain_resp, DomainResponse) + assert isinstance(domain_resp.public_certificate, DomainCertificateMetadata) + assert len(domain_resp.dns_records) > 0 + for dns_record in domain_resp.dns_records: + assert isinstance(dns_record, DnsRecord) + assert domain_resp.domain == 'login.example.com' + def test_create_certificate_and_verify_domain(self, monkeypatch): org_url = "https://test.okta.com" token = "TOKEN" From 87403874b90265e94ce21de413bf608b517a3776 Mon Sep 17 00:00:00 2001 From: Serhii Buniak Date: Wed, 14 Jul 2021 13:40:22 +0300 Subject: [PATCH 3/8] Update SDK due to new changes in openapi spec --- okta/models/__init__.py | 20 +++ okta/models/user_schema.py | 16 +- okta/models/user_schema_attribute.py | 98 ++++++++++++- okta/models/user_schema_attribute_enum.py | 49 +++++++ okta/models/user_schema_attribute_items.py | 62 ++++++++ okta/models/user_schema_attribute_master.py | 26 +++- .../user_schema_attribute_master_priority.py | 49 +++++++ .../user_schema_attribute_master_type.py | 34 +++++ okta/models/user_schema_attribute_scope.py | 33 +++++ okta/models/user_schema_attribute_type.py | 36 +++++ okta/models/user_schema_attribute_union.py | 33 +++++ okta/models/user_schema_properties.py | 57 ++++++++ okta/models/user_schema_properties_profile.py | 51 +++++++ .../user_schema_properties_profile_item.py | 45 ++++++ okta/resource_clients/group_client.py | 9 +- okta/resource_clients/network_zone_client.py | 32 +++- tests/integration/test_network_zone_it.py | 5 +- tests/unit/test_user_schema.py | 137 ++++++++++++++++++ 18 files changed, 770 insertions(+), 22 deletions(-) create mode 100644 okta/models/user_schema_attribute_enum.py create mode 100644 okta/models/user_schema_attribute_items.py create mode 100644 okta/models/user_schema_attribute_master_priority.py create mode 100644 okta/models/user_schema_attribute_master_type.py create mode 100644 okta/models/user_schema_attribute_scope.py create mode 100644 okta/models/user_schema_attribute_type.py create mode 100644 okta/models/user_schema_attribute_union.py create mode 100644 okta/models/user_schema_properties.py create mode 100644 okta/models/user_schema_properties_profile.py create mode 100644 okta/models/user_schema_properties_profile_item.py create mode 100644 tests/unit/test_user_schema.py diff --git a/okta/models/__init__.py b/okta/models/__init__.py index 12bec8e5..91671288 100644 --- a/okta/models/__init__.py +++ b/okta/models/__init__.py @@ -690,16 +690,36 @@ UserSchema = user_schema.UserSchema from okta.models import user_schema_attribute as user_schema_attribute UserSchemaAttribute = user_schema_attribute.UserSchemaAttribute +from okta.models import user_schema_attribute_enum as user_schema_attribute_enum +UserSchemaAttributeEnum = user_schema_attribute_enum.UserSchemaAttributeEnum +from okta.models import user_schema_attribute_items as user_schema_attribute_items +UserSchemaAttributeItems = user_schema_attribute_items.UserSchemaAttributeItems from okta.models import user_schema_attribute_master as user_schema_attribute_master UserSchemaAttributeMaster = user_schema_attribute_master.UserSchemaAttributeMaster +from okta.models import user_schema_attribute_master_priority as user_schema_attribute_master_priority +UserSchemaAttributeMasterPriority = user_schema_attribute_master_priority.UserSchemaAttributeMasterPriority +from okta.models import user_schema_attribute_master_type as user_schema_attribute_master_type +UserSchemaAttributeMasterType = user_schema_attribute_master_type.UserSchemaAttributeMasterType from okta.models import user_schema_attribute_permission as user_schema_attribute_permission UserSchemaAttributePermission = user_schema_attribute_permission.UserSchemaAttributePermission +from okta.models import user_schema_attribute_scope as user_schema_attribute_scope +UserSchemaAttributeScope = user_schema_attribute_scope.UserSchemaAttributeScope +from okta.models import user_schema_attribute_type as user_schema_attribute_type +UserSchemaAttributeType = user_schema_attribute_type.UserSchemaAttributeType +from okta.models import user_schema_attribute_union as user_schema_attribute_union +UserSchemaAttributeUnion = user_schema_attribute_union.UserSchemaAttributeUnion from okta.models import user_schema_base as user_schema_base UserSchemaBase = user_schema_base.UserSchemaBase from okta.models import user_schema_base_properties as user_schema_base_properties UserSchemaBaseProperties = user_schema_base_properties.UserSchemaBaseProperties from okta.models import user_schema_definitions as user_schema_definitions UserSchemaDefinitions = user_schema_definitions.UserSchemaDefinitions +from okta.models import user_schema_properties as user_schema_properties +UserSchemaProperties = user_schema_properties.UserSchemaProperties +from okta.models import user_schema_properties_profile as user_schema_properties_profile +UserSchemaPropertiesProfile = user_schema_properties_profile.UserSchemaPropertiesProfile +from okta.models import user_schema_properties_profile_item as user_schema_properties_profile_item +UserSchemaPropertiesProfileItem = user_schema_properties_profile_item.UserSchemaPropertiesProfileItem from okta.models import user_schema_public as user_schema_public UserSchemaPublic = user_schema_public.UserSchemaPublic from okta.models import user_status as user_status diff --git a/okta/models/user_schema.py b/okta/models/user_schema.py index e53b92fa..ae2a1a2c 100644 --- a/okta/models/user_schema.py +++ b/okta/models/user_schema.py @@ -21,6 +21,8 @@ from okta.okta_object import OktaObject from okta.models import user_schema_definitions\ as user_schema_definitions +from okta.models import user_schema_properties\ + as user_schema_properties class UserSchema( @@ -57,8 +59,18 @@ def __init__(self, config=None): if "lastUpdated" in config else None self.name = config["name"]\ if "name" in config else None - self.properties = config["properties"]\ - if "properties" in config else None + if "properties" in config: + if isinstance(config["properties"], + user_schema_properties.UserSchemaProperties): + self.properties = config["properties"] + elif config["properties"] is not None: + self.properties = user_schema_properties.UserSchemaProperties( + config["properties"] + ) + else: + self.properties = None + else: + self.properties = None self.title = config["title"]\ if "title" in config else None self.type = config["type"]\ diff --git a/okta/models/user_schema_attribute.py b/okta/models/user_schema_attribute.py index 4497b197..21ad1122 100644 --- a/okta/models/user_schema_attribute.py +++ b/okta/models/user_schema_attribute.py @@ -20,10 +20,20 @@ from okta.okta_object import OktaObject from okta.okta_collection import OktaCollection +from okta.models import user_schema_attribute_items\ + as user_schema_attribute_items from okta.models import user_schema_attribute_master\ as user_schema_attribute_master +from okta.models import user_schema_attribute_enum\ + as user_schema_attribute_enum from okta.models import user_schema_attribute_permission\ as user_schema_attribute_permission +from okta.models import user_schema_attribute_scope\ + as user_schema_attribute_scope +from okta.models import user_schema_attribute_type\ + as user_schema_attribute_type +from okta.models import user_schema_attribute_union\ + as user_schema_attribute_union class UserSchemaAttribute( @@ -38,6 +48,27 @@ def __init__(self, config=None): if config: self.description = config["description"]\ if "description" in config else None + self.enum = OktaCollection.form_list( + config["enum"] if "enum"\ + in config else [], + str + ) + self.external_name = config["externalName"]\ + if "externalName" in config else None + self.external_namespace = config["externalNamespace"]\ + if "externalNamespace" in config else None + if "items" in config: + if isinstance(config["items"], + user_schema_attribute_items.UserSchemaAttributeItems): + self.items = config["items"] + elif config["items"] is not None: + self.items = user_schema_attribute_items.UserSchemaAttributeItems( + config["items"] + ) + else: + self.items = None + else: + self.items = None if "master" in config: if isinstance(config["master"], user_schema_attribute_master.UserSchemaAttributeMaster): @@ -56,6 +87,13 @@ def __init__(self, config=None): if "minLength" in config else None self.mutability = config["mutability"]\ if "mutability" in config else None + self.one_of = OktaCollection.form_list( + config["oneOf"] if "oneOf"\ + in config else [], + user_schema_attribute_enum.UserSchemaAttributeEnum + ) + self.pattern = config["pattern"]\ + if "pattern" in config else None self.permissions = OktaCollection.form_list( config["permissions"] if "permissions"\ in config else [], @@ -63,37 +101,87 @@ def __init__(self, config=None): ) self.required = config["required"]\ if "required" in config else None - self.scope = config["scope"]\ - if "scope" in config else None + if "scope" in config: + if isinstance(config["scope"], + user_schema_attribute_scope.UserSchemaAttributeScope): + self.scope = config["scope"] + elif config["scope"] is not None: + self.scope = user_schema_attribute_scope.UserSchemaAttributeScope( + config["scope"].upper() + ) + else: + self.scope = None + else: + self.scope = None self.title = config["title"]\ if "title" in config else None - self.type = config["type"]\ - if "type" in config else None + if "type" in config: + if isinstance(config["type"], + user_schema_attribute_type.UserSchemaAttributeType): + self.type = config["type"] + elif config["type"] is not None: + self.type = user_schema_attribute_type.UserSchemaAttributeType( + config["type"].upper() + ) + else: + self.type = None + else: + self.type = None + if "union" in config: + if isinstance(config["union"], + user_schema_attribute_union.UserSchemaAttributeUnion): + self.union = config["union"] + elif config["union"] is not None: + self.union = user_schema_attribute_union.UserSchemaAttributeUnion( + config["union"].upper() + ) + else: + self.union = None + else: + self.union = None + self.unique = config["unique"]\ + if "unique" in config else None else: self.description = None + self.enum = [] + self.external_name = None + self.external_namespace = None + self.items = None self.master = None self.max_length = None self.min_length = None self.mutability = None + self.one_of = [] + self.pattern = None self.permissions = [] self.required = None self.scope = None self.title = None self.type = None + self.union = None + self.unique = None def request_format(self): parent_req_format = super().request_format() current_obj_format = { "description": self.description, + "enum": self.enum, + "externalName": self.external_name, + "externalNamespace": self.external_namespace, + "items": self.items, "master": self.master, "maxLength": self.max_length, "minLength": self.min_length, "mutability": self.mutability, + "oneOf": self.one_of, + "pattern": self.pattern, "permissions": self.permissions, "required": self.required, "scope": self.scope, "title": self.title, - "type": self.type + "type": self.type, + "union": self.union, + "unique": self.unique } parent_req_format.update(current_obj_format) return parent_req_format diff --git a/okta/models/user_schema_attribute_enum.py b/okta/models/user_schema_attribute_enum.py new file mode 100644 index 00000000..190389f0 --- /dev/null +++ b/okta/models/user_schema_attribute_enum.py @@ -0,0 +1,49 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from okta.okta_object import OktaObject + + +class UserSchemaAttributeEnum( + OktaObject +): + """ + A class for UserSchemaAttributeEnum objects. + """ + + def __init__(self, config=None): + super().__init__(config) + if config: + self.const = config["const"]\ + if "const" in config else None + self.title = config["title"]\ + if "title" in config else None + else: + self.const = None + self.title = None + + def request_format(self): + parent_req_format = super().request_format() + current_obj_format = { + "const": self.const, + "title": self.title + } + parent_req_format.update(current_obj_format) + return parent_req_format diff --git a/okta/models/user_schema_attribute_items.py b/okta/models/user_schema_attribute_items.py new file mode 100644 index 00000000..18cee135 --- /dev/null +++ b/okta/models/user_schema_attribute_items.py @@ -0,0 +1,62 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from okta.okta_object import OktaObject +from okta.okta_collection import OktaCollection +from okta.models import user_schema_attribute_enum\ + as user_schema_attribute_enum + + +class UserSchemaAttributeItems( + OktaObject +): + """ + A class for UserSchemaAttributeItems objects. + """ + + def __init__(self, config=None): + super().__init__(config) + if config: + self.enum = OktaCollection.form_list( + config["enum"] if "enum"\ + in config else [], + str + ) + self.one_of = OktaCollection.form_list( + config["oneOf"] if "oneOf"\ + in config else [], + user_schema_attribute_enum.UserSchemaAttributeEnum + ) + self.type = config["type"]\ + if "type" in config else None + else: + self.enum = [] + self.one_of = [] + self.type = None + + def request_format(self): + parent_req_format = super().request_format() + current_obj_format = { + "enum": self.enum, + "oneOf": self.one_of, + "type": self.type + } + parent_req_format.update(current_obj_format) + return parent_req_format diff --git a/okta/models/user_schema_attribute_master.py b/okta/models/user_schema_attribute_master.py index 4ae3f4ff..d56745ce 100644 --- a/okta/models/user_schema_attribute_master.py +++ b/okta/models/user_schema_attribute_master.py @@ -19,6 +19,11 @@ # SEE CONTRIBUTOR DOCUMENTATION from okta.okta_object import OktaObject +from okta.okta_collection import OktaCollection +from okta.models import user_schema_attribute_master_priority\ + as user_schema_attribute_master_priority +from okta.models import user_schema_attribute_master_type\ + as user_schema_attribute_master_type class UserSchemaAttributeMaster( @@ -31,14 +36,31 @@ class UserSchemaAttributeMaster( def __init__(self, config=None): super().__init__(config) if config: - self.type = config["type"]\ - if "type" in config else None + self.priority = OktaCollection.form_list( + config["priority"] if "priority"\ + in config else [], + user_schema_attribute_master_priority.UserSchemaAttributeMasterPriority + ) + if "type" in config: + if isinstance(config["type"], + user_schema_attribute_master_type.UserSchemaAttributeMasterType): + self.type = config["type"] + elif config["type"] is not None: + self.type = user_schema_attribute_master_type.UserSchemaAttributeMasterType( + config["type"].upper() + ) + else: + self.type = None + else: + self.type = None else: + self.priority = [] self.type = None def request_format(self): parent_req_format = super().request_format() current_obj_format = { + "priority": self.priority, "type": self.type } parent_req_format.update(current_obj_format) diff --git a/okta/models/user_schema_attribute_master_priority.py b/okta/models/user_schema_attribute_master_priority.py new file mode 100644 index 00000000..3d0507cc --- /dev/null +++ b/okta/models/user_schema_attribute_master_priority.py @@ -0,0 +1,49 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from okta.okta_object import OktaObject + + +class UserSchemaAttributeMasterPriority( + OktaObject +): + """ + A class for UserSchemaAttributeMasterPriority objects. + """ + + def __init__(self, config=None): + super().__init__(config) + if config: + self.type = config["type"]\ + if "type" in config else None + self.valuse = config["valuse"]\ + if "valuse" in config else None + else: + self.type = None + self.valuse = None + + def request_format(self): + parent_req_format = super().request_format() + current_obj_format = { + "type": self.type, + "valuse": self.valuse + } + parent_req_format.update(current_obj_format) + return parent_req_format diff --git a/okta/models/user_schema_attribute_master_type.py b/okta/models/user_schema_attribute_master_type.py new file mode 100644 index 00000000..dbe7276c --- /dev/null +++ b/okta/models/user_schema_attribute_master_type.py @@ -0,0 +1,34 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from aenum import MultiValueEnum + + +class UserSchemaAttributeMasterType( + str, + MultiValueEnum +): + """ + An enumeration class for UserSchemaAttributeMasterType. + """ + + PROFILE_MASTER = "PROFILE_MASTER", "profile_master" + OKTA = "OKTA", "okta" + OVERRIDE = "OVERRIDE", "override" diff --git a/okta/models/user_schema_attribute_scope.py b/okta/models/user_schema_attribute_scope.py new file mode 100644 index 00000000..1b4b9118 --- /dev/null +++ b/okta/models/user_schema_attribute_scope.py @@ -0,0 +1,33 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from aenum import MultiValueEnum + + +class UserSchemaAttributeScope( + str, + MultiValueEnum +): + """ + An enumeration class for UserSchemaAttributeScope. + """ + + SELF = "SELF", "self" + NONE = "NONE", "none" diff --git a/okta/models/user_schema_attribute_type.py b/okta/models/user_schema_attribute_type.py new file mode 100644 index 00000000..1c926dab --- /dev/null +++ b/okta/models/user_schema_attribute_type.py @@ -0,0 +1,36 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from aenum import MultiValueEnum + + +class UserSchemaAttributeType( + str, + MultiValueEnum +): + """ + An enumeration class for UserSchemaAttributeType. + """ + + STRING = "string", "STRING" + BOOLEAN = "boolean", "BOOLEAN" + NUMBER = "number", "NUMBER" + INTEGER = "integer", "INTEGER" + ARRAY = "array", "ARRAY" diff --git a/okta/models/user_schema_attribute_union.py b/okta/models/user_schema_attribute_union.py new file mode 100644 index 00000000..911e7058 --- /dev/null +++ b/okta/models/user_schema_attribute_union.py @@ -0,0 +1,33 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from aenum import MultiValueEnum + + +class UserSchemaAttributeUnion( + str, + MultiValueEnum +): + """ + An enumeration class for UserSchemaAttributeUnion. + """ + + DISABLE = "DISABLE", "disable" + ENABLE = "ENABLE", "enable" diff --git a/okta/models/user_schema_properties.py b/okta/models/user_schema_properties.py new file mode 100644 index 00000000..dd62f127 --- /dev/null +++ b/okta/models/user_schema_properties.py @@ -0,0 +1,57 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from okta.okta_object import OktaObject +from okta.models import user_schema_properties_profile\ + as user_schema_properties_profile + + +class UserSchemaProperties( + OktaObject +): + """ + A class for UserSchemaProperties objects. + """ + + def __init__(self, config=None): + super().__init__(config) + if config: + if "profile" in config: + if isinstance(config["profile"], + user_schema_properties_profile.UserSchemaPropertiesProfile): + self.profile = config["profile"] + elif config["profile"] is not None: + self.profile = user_schema_properties_profile.UserSchemaPropertiesProfile( + config["profile"] + ) + else: + self.profile = None + else: + self.profile = None + else: + self.profile = None + + def request_format(self): + parent_req_format = super().request_format() + current_obj_format = { + "profile": self.profile + } + parent_req_format.update(current_obj_format) + return parent_req_format diff --git a/okta/models/user_schema_properties_profile.py b/okta/models/user_schema_properties_profile.py new file mode 100644 index 00000000..a51e35cf --- /dev/null +++ b/okta/models/user_schema_properties_profile.py @@ -0,0 +1,51 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from okta.okta_object import OktaObject +from okta.okta_collection import OktaCollection +from okta.models import user_schema_properties_profile_item\ + as user_schema_properties_profile_item + + +class UserSchemaPropertiesProfile( + OktaObject +): + """ + A class for UserSchemaPropertiesProfile objects. + """ + + def __init__(self, config=None): + super().__init__(config) + if config: + self.all_of = OktaCollection.form_list( + config["allOf"] if "allOf"\ + in config else [], + user_schema_properties_profile_item.UserSchemaPropertiesProfileItem + ) + else: + self.all_of = [] + + def request_format(self): + parent_req_format = super().request_format() + current_obj_format = { + "allOf": self.all_of + } + parent_req_format.update(current_obj_format) + return parent_req_format diff --git a/okta/models/user_schema_properties_profile_item.py b/okta/models/user_schema_properties_profile_item.py new file mode 100644 index 00000000..b60720ad --- /dev/null +++ b/okta/models/user_schema_properties_profile_item.py @@ -0,0 +1,45 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from okta.okta_object import OktaObject + + +class UserSchemaPropertiesProfileItem( + OktaObject +): + """ + A class for UserSchemaPropertiesProfileItem objects. + """ + + def __init__(self, config=None): + super().__init__(config) + if config: + self.ref = config["ref"]\ + if "ref" in config else None + else: + self.ref = None + + def request_format(self): + parent_req_format = super().request_format() + current_obj_format = { + "$ref": self.ref + } + parent_req_format.update(current_obj_format) + return parent_req_format diff --git a/okta/resource_clients/group_client.py b/okta/resource_clients/group_client.py index 1b72e2b8..3206688f 100644 --- a/okta/resource_clients/group_client.py +++ b/okta/resource_clients/group_client.py @@ -53,7 +53,7 @@ async def list_groups( Args: query_params {dict}: Map of query parameters for request [query_params.q] {str} - [query_params.filter] {str} + [query_params.search] {str} [query_params.after] {str} [query_params.limit] {str} [query_params.expand] {str} @@ -239,19 +239,24 @@ async def create_group_rule( return (result, response, None) async def delete_group_rule( - self, ruleId + self, ruleId, query_params={} ): """ Removes a specific group rule by id from your organizat ion Args: rule_id {str} + query_params {dict}: Map of query parameters for request + [query_params.removeUsers] {str} """ http_method = "delete".upper() api_url = format_url(f""" {self._base_url} /api/v1/groups/rules/{ruleId} """) + if query_params: + encoded_query_params = urlencode(query_params) + api_url += f"/?{encoded_query_params}" body = {} headers = {} diff --git a/okta/resource_clients/network_zone_client.py b/okta/resource_clients/network_zone_client.py index 1f47b403..715cc15f 100644 --- a/okta/resource_clients/network_zone_client.py +++ b/okta/resource_clients/network_zone_client.py @@ -255,6 +255,8 @@ async def activate_network_zone( Activate Network Zone Args: zone_id {str} + Returns: + NetworkZone """ http_method = "post".upper() api_url = format_url(f""" @@ -270,15 +272,21 @@ async def activate_network_zone( ) if error: - return (None, error) + return (None, None, error) response, error = await self._request_executor\ - .execute(request) + .execute(request, NetworkZone) if error: - return (response, error) + return (None, response, error) - return (response, None) + try: + result = NetworkZone( + self.form_response_body(response.get_body()) + ) + except Exception as error: + return (None, response, error) + return (result, response, None) async def deactivate_network_zone( self, zoneId @@ -287,6 +295,8 @@ async def deactivate_network_zone( Deactivates a network zone. Args: zone_id {str} + Returns: + NetworkZone """ http_method = "post".upper() api_url = format_url(f""" @@ -302,12 +312,18 @@ async def deactivate_network_zone( ) if error: - return (None, error) + return (None, None, error) response, error = await self._request_executor\ - .execute(request) + .execute(request, NetworkZone) if error: - return (response, error) + return (None, response, error) - return (response, None) + try: + result = NetworkZone( + self.form_response_body(response.get_body()) + ) + except Exception as error: + return (None, response, error) + return (result, response, None) diff --git a/tests/integration/test_network_zone_it.py b/tests/integration/test_network_zone_it.py index 06afe365..66acb0e4 100644 --- a/tests/integration/test_network_zone_it.py +++ b/tests/integration/test_network_zone_it.py @@ -61,13 +61,12 @@ async def test_create_and_delete_network_zone(self, fs): finally: errors = [] try: - _, err = await client.deactivate_network_zone(resp.id) + _, _, err = await client.deactivate_network_zone(resp.id) assert err is None except Exception as exc: errors.append(exc) try: _, err = await client.delete_network_zone(resp.id) - assert err is None except Exception as exc: errors.append(exc) assert len(errors) == 0 @@ -108,7 +107,7 @@ async def test_update_network_zone(self, fs): finally: errors = [] try: - _, err = await client.deactivate_network_zone(resp.id) + _, _, err = await client.deactivate_network_zone(resp.id) assert err is None except Exception as exc: errors.append(exc) diff --git a/tests/unit/test_user_schema.py b/tests/unit/test_user_schema.py new file mode 100644 index 00000000..a207ee7f --- /dev/null +++ b/tests/unit/test_user_schema.py @@ -0,0 +1,137 @@ +import aiohttp +import json +import pytest +from okta.client import Client as OktaClient +from okta.models import UserSchema + + +MOCK_RESPONSE = """{ + "id": "https://${yourOktaDomain}/meta/schemas/apps/0oa25gejWwdXNnFH90g4/default", + "$schema": "http://json-schema.org/draft-04/schema#", + "name": "Example App", + "title": "Example App User", + "lastUpdated": "2017-07-18T23:18:43.000Z", + "created": "2017-07-18T22:35:30.000Z", + "definitions": { + "base": { + "id": "#base", + "type": "object", + "properties": { + "login": { + "title": "Username", + "type": "string", + "required": true, + "scope": "NONE", + "minLength": 5, + "maxLength": 100 + } + }, + "required": [ + "login" + ] + }, + "custom": { + "id": "#custom", + "type": "object", + "properties": { + }, + "required": [] + } + }, + "type": "object", + "properties": { + "profile": { + "allOf": [ + { + "$ref": "#/definitions/base" + }, + { + "$ref": "#/definitions/custom" + } + ] + } + } + }""" + + +class MockHTTPRequest(): + def __call__(self, **params): + self.request_info = params + self.headers = params['headers'] + self.url = params['url'] + self.content_type = 'application/json' + self.links = '' + self.text = MockHTTPRequest.mock_response_text + self.status = 200 + return self + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + pass + + @staticmethod + async def mock_response_text(): + return MOCK_RESPONSE + + +class TestUserSchemaResource: + """ + Unit Tests for the User Schema Resource + """ + + @pytest.mark.asyncio + async def test_get_application_user_schema(self, monkeypatch): + mock_http_request = MockHTTPRequest() + monkeypatch.setattr(aiohttp, 'request', mock_http_request) + + org_url = "https://test.okta.com" + token = "TOKEN" + config = {'orgUrl': org_url, 'token': token} + client = OktaClient(config) + + resp, _, err = await client.get_application_user_schema('0oa25gejWwdXNnFH90g4') + assert err is None + assert isinstance(resp, UserSchema) + assert resp.schema == 'http://json-schema.org/draft-04/schema#' + assert resp.name == 'Example App' + assert resp.title == 'Example App User' + assert resp.type == 'object' + assert resp.definitions.base.id == '#base' + assert resp.definitions.base.type == 'object' + assert resp.definitions.base.properties.login.title == 'Username' + assert resp.definitions.base.properties.login.type == 'string' + assert resp.definitions.base.properties.login.required + assert resp.definitions.base.properties.login.scope == 'NONE' + assert resp.definitions.base.properties.login.min_length == 5 + assert resp.definitions.base.properties.login.max_length == 100 + assert 'login' in resp.definitions.base.required + + @pytest.mark.asyncio + async def test_update_application_user_profile(self, monkeypatch): + mock_http_request = MockHTTPRequest() + monkeypatch.setattr(aiohttp, 'request', mock_http_request) + + org_url = "https://test.okta.com" + token = "TOKEN" + config = {'orgUrl': org_url, 'token': token} + client = OktaClient(config) + + schema = UserSchema(json.loads(MOCK_RESPONSE)) + resp, _, err = await client.update_application_user_profile('0oa25gejWwdXNnFH90g4', schema) + assert err is None + assert isinstance(resp, UserSchema) + assert resp.schema == 'http://json-schema.org/draft-04/schema#' + assert resp.name == 'Example App' + assert resp.title == 'Example App User' + assert resp.type == 'object' + assert resp.definitions.base.id == '#base' + assert resp.definitions.base.type == 'object' + assert resp.definitions.base.properties.login.title == 'Username' + assert resp.definitions.base.properties.login.type == 'string' + assert resp.definitions.base.properties.login.required + assert resp.definitions.base.properties.login.scope == 'NONE' + assert resp.definitions.base.properties.login.min_length == 5 + assert resp.definitions.base.properties.login.max_length == 100 + assert 'login' in resp.definitions.base.required From 21f87d49b98d1f5a6500726c15b5c22dd7c12d56 Mon Sep 17 00:00:00 2001 From: Serhii Buniak Date: Wed, 14 Jul 2021 15:59:48 +0300 Subject: [PATCH 4/8] Update Domains resource and unittests due to changes in openapi spec. --- okta/models/dns_record.py | 4 ++ okta/models/domain_response.py | 4 ++ tests/unit/test_domains.py | 102 ++++++++++++++++++++++++++++++++- 3 files changed, 109 insertions(+), 1 deletion(-) diff --git a/okta/models/dns_record.py b/okta/models/dns_record.py index 54693e35..160c1e11 100644 --- a/okta/models/dns_record.py +++ b/okta/models/dns_record.py @@ -32,6 +32,8 @@ class DnsRecord( def __init__(self, config=None): super().__init__(config) if config: + self.expiration = config["expiration"]\ + if "expiration" in config else None self.fqdn = config["fqdn"]\ if "fqdn" in config else None self.record_type = config["recordType"]\ @@ -42,6 +44,7 @@ def __init__(self, config=None): str ) else: + self.expiration = None self.fqdn = None self.record_type = None self.values = [] @@ -49,6 +52,7 @@ def __init__(self, config=None): def request_format(self): parent_req_format = super().request_format() current_obj_format = { + "expiration": self.expiration, "fqdn": self.fqdn, "recordType": self.record_type, "values": self.values diff --git a/okta/models/domain_response.py b/okta/models/domain_response.py index 938341d2..bd96c505 100644 --- a/okta/models/domain_response.py +++ b/okta/models/domain_response.py @@ -50,6 +50,8 @@ def __init__(self, config=None): self.links = None else: self.links = None + self.certificate_sourcetype = config["certificateSourcetype"]\ + if "certificateSourcetype" in config else None self.dns_records = OktaCollection.form_list( config["dnsRecords"] if "dnsRecords"\ in config else [], @@ -75,6 +77,7 @@ def __init__(self, config=None): if "validationStatus" in config else None else: self.links = None + self.certificate_sourcetype = None self.dns_records = [] self.domain = None self.id = None @@ -85,6 +88,7 @@ def request_format(self): parent_req_format = super().request_format() current_obj_format = { "_links": self.links, + "certificateSourcetype": self.certificate_sourcetype, "dnsRecords": self.dns_records, "domain": self.domain, "id": self.id, diff --git a/tests/unit/test_domains.py b/tests/unit/test_domains.py index ac949880..47a5390c 100644 --- a/tests/unit/test_domains.py +++ b/tests/unit/test_domains.py @@ -1,7 +1,7 @@ import aiohttp import asyncio from okta.client import Client as OktaClient -from okta.models import DomainCertificate +from okta.models import DnsRecord, DomainCertificate, DomainCertificateMetadata, DomainResponse CREATE_DOMAIN_RESP = """{ @@ -45,9 +45,11 @@ } }""" + VERIFY_DOMAIN_RESP = """{ "id": "OcDz6iRyjkaCTXkdo0g3", "domain": "login.example.com", + "certificateSourceType": "MANUAL", "validationStatus": "VERIFIED", "dnsRecords": [ { @@ -66,6 +68,14 @@ } ], "_links": { + "certificate": { + "href": "https://test.okta.com/api/v1/domains/OcDz6iRyjkaCTXkdo0g3/certificate", + "hints": { + "allow": [ + "PUT" + ] + } + }, "self": { "href": "https://test.okta.com/api/v1/domains/OcDz6iRyjkaCTXkdo0g3", "hints": { @@ -74,6 +84,53 @@ "DELETE" ] } + } + } +}""" + + +GET_DOMAIN_RESP = """{ + "id": "OcDz6iRyjkaCTXkdo0g3", + "domain": "login.example.com", + "certificateSourceType": "MANUAL", + "validationStatus": "COMPLETED", + "dnsRecords": [ + { + "fqdn": "_oktaverification.login.example.com", + "values": [ + "79496f234c814638b1cc44f51a782781" + ], + "recordType": "TXT" + }, + { + "fqdn": "login.example.com", + "values": [ + "test.okta.com.customdomains.okta1.com" + ], + "recordType": "CNAME" + } + ], + "publicCertificate": { + "subject": "CN=login.example.com", + "fingerprint": "73:68:82:7B:83:2E:48:29:A5:5E:E8:40:41:80:B3:AA:03:C4:42:43:05:73:45:BC:AA:47:00:23:A3:70:E5:C4", + "expiration": "2021-05-11T05:13:05.000Z" + }, + "_links": { + "certificate": { + "href": "https://test.okta.com/api/v1/domains/OcDz6iRyjkaCTXkdo0g3/certificate", + "hints": { + "allow": [ + "PUT" + ] + } + }, + "self": { + "href": "https://test.okta.com/api/v1/domains/OcDz6iRyjkaCTXkdo0g3", + "hints": { + "allow": [ + "DELETE" + ] + } }, "verify": { "href": "https://test.okta.com/api/v1/domains/OcDz6iRyjkaCTXkdo0g3/verify", @@ -92,6 +149,49 @@ class TestDomainResource: Unit Tests for the Domain Resource """ + def test_get_domain(self, monkeypatch): + org_url = "https://test.okta.com" + token = "TOKEN" + config = {'orgUrl': org_url, 'token': token} + client = OktaClient(config) + + # mock http requests + class MockHTTPRequest(): + + _mocked_response = None + + def __call__(self, **params): + self.request_info = params + self.headers = params['headers'] + self.url = params['url'] + self.content_type = 'application/json' + self.links = '' + self.text = MockHTTPRequest.mock_response_text + self.status = 200 + return self + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + pass + + @staticmethod + async def mock_response_text(): + return GET_DOMAIN_RESP + + mock_http_request = MockHTTPRequest() + monkeypatch.setattr(aiohttp, 'request', mock_http_request) + + domain_resp, _, err = asyncio.run(client.get_domain('OcDz6iRyjkaCTXkdo0g3')) + assert err is None + assert isinstance(domain_resp, DomainResponse) + assert isinstance(domain_resp.public_certificate, DomainCertificateMetadata) + assert len(domain_resp.dns_records) > 0 + for dns_record in domain_resp.dns_records: + assert isinstance(dns_record, DnsRecord) + assert domain_resp.domain == 'login.example.com' + def test_create_certificate_and_verify_domain(self, monkeypatch): org_url = "https://test.okta.com" token = "TOKEN" From 8811772d1d7e5d3944690fddbd7e88f41508e899 Mon Sep 17 00:00:00 2001 From: Serhii Buniak Date: Wed, 21 Jul 2021 15:11:19 +0300 Subject: [PATCH 5/8] Update domains api due to openapi spec. --- okta/models/__init__.py | 12 ++- okta/models/dns_record.py | 16 ++- okta/models/dns_record_type.py | 33 +++++++ okta/models/domain.py | 64 +++++++++++- okta/models/domain_certificate.py | 16 ++- okta/models/domain_certificate_source_type.py | 32 ++++++ okta/models/domain_certificate_type.py | 32 ++++++ okta/models/domain_links.py | 53 ---------- okta/models/domain_list_response.py | 6 +- okta/models/domain_response.py | 99 ------------------- okta/models/domain_validation_status.py | 35 +++++++ okta/resource_clients/domain_client.py | 22 ++--- tests/integration/test_domains_it.py | 12 +-- tests/unit/test_domains.py | 4 +- 14 files changed, 250 insertions(+), 186 deletions(-) create mode 100644 okta/models/dns_record_type.py create mode 100644 okta/models/domain_certificate_source_type.py create mode 100644 okta/models/domain_certificate_type.py delete mode 100644 okta/models/domain_links.py delete mode 100644 okta/models/domain_response.py create mode 100644 okta/models/domain_validation_status.py diff --git a/okta/models/__init__.py b/okta/models/__init__.py index 91671288..1f9d84df 100644 --- a/okta/models/__init__.py +++ b/okta/models/__init__.py @@ -150,6 +150,8 @@ CustomHotpUserFactorProfile = custom_hotp_user_factor_profile.CustomHotpUserFactorProfile from okta.models import dns_record as dns_record DnsRecord = dns_record.DnsRecord +from okta.models import dns_record_type as dns_record_type +DnsRecordType = dns_record_type.DnsRecordType from okta.models import device_policy_rule_condition as device_policy_rule_condition DevicePolicyRuleCondition = device_policy_rule_condition.DevicePolicyRuleCondition from okta.models import device_policy_rule_condition_platform as device_policy_rule_condition_platform @@ -160,12 +162,14 @@ DomainCertificate = domain_certificate.DomainCertificate from okta.models import domain_certificate_metadata as domain_certificate_metadata DomainCertificateMetadata = domain_certificate_metadata.DomainCertificateMetadata -from okta.models import domain_links as domain_links -DomainLinks = domain_links.DomainLinks +from okta.models import domain_certificate_source_type as domain_certificate_source_type +DomainCertificateSourceType = domain_certificate_source_type.DomainCertificateSourceType +from okta.models import domain_certificate_type as domain_certificate_type +DomainCertificateType = domain_certificate_type.DomainCertificateType from okta.models import domain_list_response as domain_list_response DomainListResponse = domain_list_response.DomainListResponse -from okta.models import domain_response as domain_response -DomainResponse = domain_response.DomainResponse +from okta.models import domain_validation_status as domain_validation_status +DomainValidationStatus = domain_validation_status.DomainValidationStatus from okta.models import duration as duration Duration = duration.Duration from okta.models import email_user_factor as email_user_factor diff --git a/okta/models/dns_record.py b/okta/models/dns_record.py index 160c1e11..99ef7fb4 100644 --- a/okta/models/dns_record.py +++ b/okta/models/dns_record.py @@ -20,6 +20,8 @@ from okta.okta_object import OktaObject from okta.okta_collection import OktaCollection +from okta.models import dns_record_type\ + as dns_record_type class DnsRecord( @@ -36,8 +38,18 @@ def __init__(self, config=None): if "expiration" in config else None self.fqdn = config["fqdn"]\ if "fqdn" in config else None - self.record_type = config["recordType"]\ - if "recordType" in config else None + if "recordType" in config: + if isinstance(config["recordType"], + dns_record_type.DnsRecordType): + self.record_type = config["recordType"] + elif config["recordType"] is not None: + self.record_type = dns_record_type.DnsRecordType( + config["recordType"].upper() + ) + else: + self.record_type = None + else: + self.record_type = None self.values = OktaCollection.form_list( config["values"] if "values"\ in config else [], diff --git a/okta/models/dns_record_type.py b/okta/models/dns_record_type.py new file mode 100644 index 00000000..1c5775a5 --- /dev/null +++ b/okta/models/dns_record_type.py @@ -0,0 +1,33 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from aenum import MultiValueEnum + + +class DnsRecordType( + str, + MultiValueEnum +): + """ + An enumeration class for DnsRecordType. + """ + + TXT = "TXT", "txt" + CNAME = "CNAME", "cname" diff --git a/okta/models/domain.py b/okta/models/domain.py index 61d25e1b..31c0291e 100644 --- a/okta/models/domain.py +++ b/okta/models/domain.py @@ -19,6 +19,15 @@ # SEE CONTRIBUTOR DOCUMENTATION from okta.okta_object import OktaObject +from okta.okta_collection import OktaCollection +from okta.models import domain_certificate_source_type\ + as domain_certificate_source_type +from okta.models import dns_record\ + as dns_record +from okta.models import domain_certificate_metadata\ + as domain_certificate_metadata +from okta.models import domain_validation_status\ + as domain_validation_status class Domain( @@ -31,19 +40,68 @@ class Domain( def __init__(self, config=None): super().__init__(config) if config: - self.certificate_sourcetype = config["certificateSourcetype"]\ - if "certificateSourcetype" in config else None + if "certificateSourcetype" in config: + if isinstance(config["certificateSourcetype"], + domain_certificate_source_type.DomainCertificateSourceType): + self.certificate_sourcetype = config["certificateSourcetype"] + elif config["certificateSourcetype"] is not None: + self.certificate_sourcetype = domain_certificate_source_type.DomainCertificateSourceType( + config["certificateSourcetype"].upper() + ) + else: + self.certificate_sourcetype = None + else: + self.certificate_sourcetype = None + self.dns_records = OktaCollection.form_list( + config["dnsRecords"] if "dnsRecords"\ + in config else [], + dns_record.DnsRecord + ) self.domain = config["domain"]\ if "domain" in config else None + self.id = config["id"]\ + if "id" in config else None + if "publicCertificate" in config: + if isinstance(config["publicCertificate"], + domain_certificate_metadata.DomainCertificateMetadata): + self.public_certificate = config["publicCertificate"] + elif config["publicCertificate"] is not None: + self.public_certificate = domain_certificate_metadata.DomainCertificateMetadata( + config["publicCertificate"] + ) + else: + self.public_certificate = None + else: + self.public_certificate = None + if "validationStatus" in config: + if isinstance(config["validationStatus"], + domain_validation_status.DomainValidationStatus): + self.validation_status = config["validationStatus"] + elif config["validationStatus"] is not None: + self.validation_status = domain_validation_status.DomainValidationStatus( + config["validationStatus"].upper() + ) + else: + self.validation_status = None + else: + self.validation_status = None else: self.certificate_sourcetype = None + self.dns_records = [] self.domain = None + self.id = None + self.public_certificate = None + self.validation_status = None def request_format(self): parent_req_format = super().request_format() current_obj_format = { "certificateSourcetype": self.certificate_sourcetype, - "domain": self.domain + "dnsRecords": self.dns_records, + "domain": self.domain, + "id": self.id, + "publicCertificate": self.public_certificate, + "validationStatus": self.validation_status } parent_req_format.update(current_obj_format) return parent_req_format diff --git a/okta/models/domain_certificate.py b/okta/models/domain_certificate.py index bea19422..3ab2a7e5 100644 --- a/okta/models/domain_certificate.py +++ b/okta/models/domain_certificate.py @@ -19,6 +19,8 @@ # SEE CONTRIBUTOR DOCUMENTATION from okta.okta_object import OktaObject +from okta.models import domain_certificate_type\ + as domain_certificate_type class DomainCertificate( @@ -37,8 +39,18 @@ def __init__(self, config=None): if "certificateChain" in config else None self.private_key = config["privateKey"]\ if "privateKey" in config else None - self.type = config["type"]\ - if "type" in config else None + if "type" in config: + if isinstance(config["type"], + domain_certificate_type.DomainCertificateType): + self.type = config["type"] + elif config["type"] is not None: + self.type = domain_certificate_type.DomainCertificateType( + config["type"].upper() + ) + else: + self.type = None + else: + self.type = None else: self.certificate = None self.certificate_chain = None diff --git a/okta/models/domain_certificate_source_type.py b/okta/models/domain_certificate_source_type.py new file mode 100644 index 00000000..a7c4bcbd --- /dev/null +++ b/okta/models/domain_certificate_source_type.py @@ -0,0 +1,32 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from aenum import MultiValueEnum + + +class DomainCertificateSourceType( + str, + MultiValueEnum +): + """ + An enumeration class for DomainCertificateSourceType. + """ + + MANUAL = "MANUAL", "manual" diff --git a/okta/models/domain_certificate_type.py b/okta/models/domain_certificate_type.py new file mode 100644 index 00000000..cbbf8a0a --- /dev/null +++ b/okta/models/domain_certificate_type.py @@ -0,0 +1,32 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from aenum import MultiValueEnum + + +class DomainCertificateType( + str, + MultiValueEnum +): + """ + An enumeration class for DomainCertificateType. + """ + + PEM = "PEM", "pem" diff --git a/okta/models/domain_links.py b/okta/models/domain_links.py deleted file mode 100644 index 843c49ba..00000000 --- a/okta/models/domain_links.py +++ /dev/null @@ -1,53 +0,0 @@ -# flake8: noqa -""" -Copyright 2020 - Present Okta, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -""" - -# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY -# SEE CONTRIBUTOR DOCUMENTATION - -from okta.okta_object import OktaObject - - -class DomainLinks( - OktaObject -): - """ - A class for DomainLinks objects. - """ - - def __init__(self, config=None): - super().__init__(config) - if config: - self.certificate = config["certificate"]\ - if "certificate" in config else None - self.self = config["self"]\ - if "self" in config else None - self.verify = config["verify"]\ - if "verify" in config else None - else: - self.certificate = None - self.self = None - self.verify = None - - def request_format(self): - parent_req_format = super().request_format() - current_obj_format = { - "certificate": self.certificate, - "self": self.self, - "verify": self.verify - } - parent_req_format.update(current_obj_format) - return parent_req_format diff --git a/okta/models/domain_list_response.py b/okta/models/domain_list_response.py index ae633d7d..2600584b 100644 --- a/okta/models/domain_list_response.py +++ b/okta/models/domain_list_response.py @@ -20,8 +20,8 @@ from okta.okta_object import OktaObject from okta.okta_collection import OktaCollection -from okta.models import domain_response\ - as domain_response +from okta.models import domain\ + as domain class DomainListResponse( @@ -37,7 +37,7 @@ def __init__(self, config=None): self.domains = OktaCollection.form_list( config["domains"] if "domains"\ in config else [], - domain_response.DomainResponse + domain.Domain ) else: self.domains = [] diff --git a/okta/models/domain_response.py b/okta/models/domain_response.py deleted file mode 100644 index bd96c505..00000000 --- a/okta/models/domain_response.py +++ /dev/null @@ -1,99 +0,0 @@ -# flake8: noqa -""" -Copyright 2020 - Present Okta, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -""" - -# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY -# SEE CONTRIBUTOR DOCUMENTATION - -from okta.okta_object import OktaObject -from okta.okta_collection import OktaCollection -from okta.models import domain_links\ - as domain_links -from okta.models import dns_record\ - as dns_record -from okta.models import domain_certificate_metadata\ - as domain_certificate_metadata - - -class DomainResponse( - OktaObject -): - """ - A class for DomainResponse objects. - """ - - def __init__(self, config=None): - super().__init__(config) - if config: - if "links" in config: - if isinstance(config["links"], - domain_links.DomainLinks): - self.links = config["links"] - elif config["links"] is not None: - self.links = domain_links.DomainLinks( - config["links"] - ) - else: - self.links = None - else: - self.links = None - self.certificate_sourcetype = config["certificateSourcetype"]\ - if "certificateSourcetype" in config else None - self.dns_records = OktaCollection.form_list( - config["dnsRecords"] if "dnsRecords"\ - in config else [], - dns_record.DnsRecord - ) - self.domain = config["domain"]\ - if "domain" in config else None - self.id = config["id"]\ - if "id" in config else None - if "publicCertificate" in config: - if isinstance(config["publicCertificate"], - domain_certificate_metadata.DomainCertificateMetadata): - self.public_certificate = config["publicCertificate"] - elif config["publicCertificate"] is not None: - self.public_certificate = domain_certificate_metadata.DomainCertificateMetadata( - config["publicCertificate"] - ) - else: - self.public_certificate = None - else: - self.public_certificate = None - self.validation_status = config["validationStatus"]\ - if "validationStatus" in config else None - else: - self.links = None - self.certificate_sourcetype = None - self.dns_records = [] - self.domain = None - self.id = None - self.public_certificate = None - self.validation_status = None - - def request_format(self): - parent_req_format = super().request_format() - current_obj_format = { - "_links": self.links, - "certificateSourcetype": self.certificate_sourcetype, - "dnsRecords": self.dns_records, - "domain": self.domain, - "id": self.id, - "publicCertificate": self.public_certificate, - "validationStatus": self.validation_status - } - parent_req_format.update(current_obj_format) - return parent_req_format diff --git a/okta/models/domain_validation_status.py b/okta/models/domain_validation_status.py new file mode 100644 index 00000000..262ed988 --- /dev/null +++ b/okta/models/domain_validation_status.py @@ -0,0 +1,35 @@ +# flake8: noqa +""" +Copyright 2020 - Present Okta, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +# AUTO-GENERATED! DO NOT EDIT FILE DIRECTLY +# SEE CONTRIBUTOR DOCUMENTATION + +from aenum import MultiValueEnum + + +class DomainValidationStatus( + str, + MultiValueEnum +): + """ + An enumeration class for DomainValidationStatus. + """ + + NOT_STARTED = "NOT_STARTED", "not_started" + IN_PROGRESS = "IN_PROGRESS", "in_progress" + VERIFIED = "VERIFIED", "verified" + COMPLETED = "COMPLETED", "completed" diff --git a/okta/resource_clients/domain_client.py b/okta/resource_clients/domain_client.py index 4efdb014..445acfe1 100644 --- a/okta/resource_clients/domain_client.py +++ b/okta/resource_clients/domain_client.py @@ -19,8 +19,8 @@ from okta.models.domain_list_response\ import DomainListResponse -from okta.models.domain_response\ - import DomainResponse +from okta.models.domain\ + import Domain from okta.utils import format_url from okta.api_client import APIClient @@ -80,7 +80,7 @@ async def create_domain( Args: {domain} Returns: - DomainResponse + Domain """ http_method = "post".upper() api_url = format_url(f""" @@ -105,13 +105,13 @@ async def create_domain( return (None, None, error) response, error = await self._request_executor\ - .execute(request, DomainResponse) + .execute(request, Domain) if error: return (None, response, error) try: - result = DomainResponse( + result = Domain( self.form_response_body(response.get_body()) ) except Exception as error: @@ -158,7 +158,7 @@ async def get_domain( Args: domain_id {str} Returns: - DomainResponse + Domain """ http_method = "get".upper() api_url = format_url(f""" @@ -177,13 +177,13 @@ async def get_domain( return (None, None, error) response, error = await self._request_executor\ - .execute(request, DomainResponse) + .execute(request, Domain) if error: return (None, response, error) try: - result = DomainResponse( + result = Domain( self.form_response_body(response.get_body()) ) except Exception as error: @@ -237,7 +237,7 @@ async def verify_domain( Args: domain_id {str} Returns: - DomainResponse + Domain """ http_method = "post".upper() api_url = format_url(f""" @@ -256,13 +256,13 @@ async def verify_domain( return (None, None, error) response, error = await self._request_executor\ - .execute(request, DomainResponse) + .execute(request, Domain) if error: return (None, response, error) try: - result = DomainResponse( + result = Domain( self.form_response_body(response.get_body()) ) except Exception as error: diff --git a/tests/integration/test_domains_it.py b/tests/integration/test_domains_it.py index 4094c624..d6562c23 100644 --- a/tests/integration/test_domains_it.py +++ b/tests/integration/test_domains_it.py @@ -1,6 +1,6 @@ import pytest from tests.mocks import MockOktaClient -from okta.models import DomainResponse +from okta.models import Domain, DomainListResponse class TestDomainResource: @@ -12,10 +12,8 @@ class TestDomainResource: @pytest.mark.asyncio async def test_list_domains(self, fs): client = MockOktaClient(fs) - domains_list_resp, _, err = await client.list_domains() - for domain in domains_list_resp.domains: - assert isinstance(domain, DomainResponse) - assert domain.domain + domain_list_resp, _, err = await client.list_domains() + assert isinstance(domain_list_resp, DomainListResponse) @pytest.mark.vcr() @pytest.mark.asyncio @@ -28,7 +26,7 @@ async def test_create_and_delete_domain(self, fs): domain, _, err = await client.create_domain(domain_config) assert err is None try: - assert isinstance(domain, DomainResponse) + assert isinstance(domain, Domain) assert domain.id finally: _, err = await client.delete_domain(domain.id) @@ -45,7 +43,7 @@ async def test_get_domain(self, fs): assert err is None try: get_domain, _, err = await client.get_domain(domain.id) - assert isinstance(domain, DomainResponse) + assert isinstance(domain, Domain) assert domain.id == get_domain.id assert domain.domain == get_domain.domain finally: diff --git a/tests/unit/test_domains.py b/tests/unit/test_domains.py index 47a5390c..22c441e4 100644 --- a/tests/unit/test_domains.py +++ b/tests/unit/test_domains.py @@ -1,7 +1,7 @@ import aiohttp import asyncio from okta.client import Client as OktaClient -from okta.models import DnsRecord, DomainCertificate, DomainCertificateMetadata, DomainResponse +from okta.models import DnsRecord, DomainCertificate, DomainCertificateMetadata, Domain CREATE_DOMAIN_RESP = """{ @@ -185,7 +185,7 @@ async def mock_response_text(): domain_resp, _, err = asyncio.run(client.get_domain('OcDz6iRyjkaCTXkdo0g3')) assert err is None - assert isinstance(domain_resp, DomainResponse) + assert isinstance(domain_resp, Domain) assert isinstance(domain_resp.public_certificate, DomainCertificateMetadata) assert len(domain_resp.dns_records) > 0 for dns_record in domain_resp.dns_records: From 1ebe4b39d11f122a00b4893985f8b64aee683263 Mon Sep 17 00:00:00 2001 From: Serhii Buniak <73126645+serhiibuniak-okta@users.noreply.github.com> Date: Mon, 26 Jul 2021 18:54:00 +0300 Subject: [PATCH 6/8] Update SDK, bump version to 2.0.0 (#221) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update SDK, bump version to 2.0.0 Co-authored-by: Laura Rodríguez --- CHANGELOG.md | 41 +++++++++++++++++++++++++++++++++++++++++ okta/__init__.py | 2 +- openapi/package.json | 2 +- openapi/yarn.lock | 8 ++++---- 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfdd77b9..12fe61f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,46 @@ # Okta Python SDK Changelog +## v2.0.0 +- Regenerate code using the [open API spec v2.5.0](https://github.com/okta/okta-management-openapi-spec/releases/tag/openapi-2.5.0). +- Make sign_on_mode of all apps instance of enum, issue #198 (this change might be not compatible with custom clients code, although probability is low) +- Add response headers to OktaAPIResponse object, issue #218 + +_New resources:_ +* Domain +* UserSchema + +_New models:_ +* DnsRecord +* DnsRecordType +* Domain +* DomainCertificate +* DomainCertificateMetadata +* DomainCertificateSourceType +* DomainCertificateType +* DomainListResponse +* DomainValidationStatus +* UserSchemaAttributeEnum +* UserSchemaAttributeItems +* UserSchemaAttributeMasterPriority +* UserSchemaAttributeMasterType +* UserSchemaAttributeScope +* UserSchemaAttributeType +* UserSchemaAttributeUnion +* UserSchemaProperties +* UserSchemaPropertiesProfile +* UserSchemaPropertiesProfileItem + +### Breaking changes +Previously, the type of `sign_on_mode` attribute was inconsistent among different applications. While some applications, including the generic application, defined this attribute as string, others defined it as `ApplicationSignOnMode`. + +We have now standardized the sign_on_mode attribute making its type an ApplicationSignOnMode. Thus, code like the following, which was working previously, won't provide desired result: + +```py +# if sign_on_mode is not an ApplicationSignOnMode type, then it should be string, but now all sign_on_modes are string +if not isinstance(app.sign_on_mode, ApplicationSignOnMode): + do_some_stuff() +``` + ## v1.7.0 - Regenerate code using the [open API spec v2.4.0](https://github.com/okta/okta-management-openapi-spec/releases/tag/openapi-2.4.0). - Fix case issue with user custom attributes, issue #202. diff --git a/okta/__init__.py b/okta/__init__.py index 0e1a38d3..afced147 100644 --- a/okta/__init__.py +++ b/okta/__init__.py @@ -1 +1 @@ -__version__ = '1.7.0' +__version__ = '2.0.0' diff --git a/openapi/package.json b/openapi/package.json index 339e2f85..6ab2a26d 100644 --- a/openapi/package.json +++ b/openapi/package.json @@ -1,6 +1,6 @@ { "dependencies": { - "@okta/openapi": "^2.4.0", + "@okta/openapi": "^2.5.0", "lodash": "^4.17.15" }, "scripts": { diff --git a/openapi/yarn.lock b/openapi/yarn.lock index bb8ca685..27f34425 100644 --- a/openapi/yarn.lock +++ b/openapi/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@okta/openapi@^2.4.0": - "integrity" "sha512-isPw9DuGLbLI1UndwHWeinIn0uToCiuYXhJok/h2NEuciv7dD3SBz4SwkPuyKIETJgsKdhWgo0naK5c9KH031w==" - "resolved" "https://registry.npmjs.org/@okta/openapi/-/openapi-2.4.0.tgz" - "version" "2.4.0" +"@okta/openapi@^2.5.0": + "integrity" "sha512-Hke9OXDVaq8lSJI3XepZXxoD2xysQH0KeQta6s/V2fS5aE8HB0utv8DrOaSjnXF7/bFUxteBxRIO7hllpkx1cw==" + "resolved" "https://registry.npmjs.org/@okta/openapi/-/openapi-2.5.0.tgz" + "version" "2.5.0" dependencies: "commander" "2.9.0" "fs-extra" "3.0.1" From c2e159a08360d01af272fb5b623ce34d12ac777e Mon Sep 17 00:00:00 2001 From: Serhii Buniak <73126645+serhiibuniak-okta@users.noreply.github.com> Date: Mon, 26 Jul 2021 20:20:05 +0300 Subject: [PATCH 7/8] Update CHANGELOG.md Fix typo in CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12fe61f2..63c9cafd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,7 @@ Previously, the type of `sign_on_mode` attribute was inconsistent among differen We have now standardized the sign_on_mode attribute making its type an ApplicationSignOnMode. Thus, code like the following, which was working previously, won't provide desired result: ```py -# if sign_on_mode is not an ApplicationSignOnMode type, then it should be string, but now all sign_on_modes are string +# if sign_on_mode is not an ApplicationSignOnMode type, then it should be string, but now all sign_on_modes are an ApplicationSignOnMode if not isinstance(app.sign_on_mode, ApplicationSignOnMode): do_some_stuff() ``` From 0798576bd27c8ced8ef5cbbbc7bb4c533c3dc0c5 Mon Sep 17 00:00:00 2001 From: Serhii Buniak <73126645+serhiibuniak-okta@users.noreply.github.com> Date: Tue, 27 Jul 2021 10:17:11 +0300 Subject: [PATCH 8/8] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63c9cafd..706c31ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,7 @@ Previously, the type of `sign_on_mode` attribute was inconsistent among differen We have now standardized the sign_on_mode attribute making its type an ApplicationSignOnMode. Thus, code like the following, which was working previously, won't provide desired result: ```py -# if sign_on_mode is not an ApplicationSignOnMode type, then it should be string, but now all sign_on_modes are an ApplicationSignOnMode +# if sign_on_mode is not an ApplicationSignOnMode type, then it should be string; but now all sign_on_modes are of type ApplicationSignOnMode if not isinstance(app.sign_on_mode, ApplicationSignOnMode): do_some_stuff() ```