diff --git a/.gitignore b/.gitignore index c03bdb4..671d63a 100644 --- a/.gitignore +++ b/.gitignore @@ -129,4 +129,7 @@ dmypy.json .pyre/ .idea -.pytest_cache \ No newline at end of file +.pytest_cache + +# Vscode +.vscode \ No newline at end of file diff --git a/src/casdoor/application.py b/src/casdoor/application.py index ea1960f..bfb5cfd 100644 --- a/src/casdoor/application.py +++ b/src/casdoor/application.py @@ -143,7 +143,7 @@ def get_applications(self) -> List[Application]: r = requests.get(url, params) response = r.json() if response["status"] != "ok": - raise ValueError(response.msg) + raise ValueError(response["msg"]) res = [] for element in response["data"]: @@ -166,7 +166,7 @@ def get_application(self, application_id: str) -> Application: r = requests.get(url, params) response = r.json() if response["status"] != "ok": - raise ValueError(response.msg) + raise ValueError(response["msg"]) return Application.from_dict(response["data"]) def modify_application(self, method: str, application: Application) -> str: @@ -182,7 +182,7 @@ def modify_application(self, method: str, application: Application) -> str: r = requests.post(url, params=params, data=application_info) response = r.json() if response["status"] != "ok": - raise ValueError(response.msg) + raise ValueError(response["msg"]) return str(response["data"]) def add_application(self, application: Application) -> str: diff --git a/src/casdoor/group.py b/src/casdoor/group.py index 8db51ae..0d5b425 100644 --- a/src/casdoor/group.py +++ b/src/casdoor/group.py @@ -38,6 +38,25 @@ def __init__(self): self.children = [Group] self.isEnabled = False + @classmethod + def new(cls, owner, name, created_time, display_name): + self = cls() + self.owner = owner + self.name = name + self.createdTime = created_time + self.displayName = display_name + return self + + @classmethod + def from_dict(cls, data: dict): + if not data: + return None + group = cls() + for key, value in data.items(): + if hasattr(group, key): + setattr(group, key, value) + return group + def __str__(self): return str(self.__dict__) @@ -59,8 +78,15 @@ def get_groups(self) -> List[Dict]: "clientSecret": self.client_secret, } r = requests.get(url, params) - groups = r.json() - return groups + response = r.json() + if response["status"] != "ok": + raise ValueError(response["msg"]) + + res = [] + for element in response["data"]: + res.append(Group.from_dict(element)) + + return res def get_group(self, group_id: str) -> Dict: """ @@ -76,22 +102,30 @@ def get_group(self, group_id: str) -> Dict: "clientSecret": self.client_secret, } r = requests.get(url, params) - group = r.json() - return group + response = r.json() + if response["status"] != "ok": + raise ValueError(response["msg"]) + return Group.from_dict(response["data"]) def modify_group(self, method: str, group: Group) -> Dict: url = self.endpoint + f"/api/{method}" - if group.owner == "": - group.owner = self.org_name + # if group.owner == "": + # group.owner = self.org_name + group.owner = self.org_name params = { "id": f"{group.owner}/{group.name}", "clientId": self.client_id, "clientSecret": self.client_secret, } - group_info = json.dumps(group.to_dict()) + + # group_info = json.dumps(group.to_dict()) + group_info = json.dumps(group.to_dict(), default=self.custom_encoder) r = requests.post(url, params=params, data=group_info) response = r.json() - return response + if response["status"] != "ok": + raise ValueError(response["msg"]) + + return str(response["data"]) def add_group(self, group: Group) -> Dict: response = self.modify_group("add-group", group) @@ -104,3 +138,7 @@ def update_group(self, group: Group) -> Dict: def delete_group(self, group: Group) -> Dict: response = self.modify_group("delete-group", group) return response + + def custom_encoder(self, o): + if isinstance(o, (Group, User)): + return o.__dict__ diff --git a/src/casdoor/organization.py b/src/casdoor/organization.py index 53214d7..dd034ca 100644 --- a/src/casdoor/organization.py +++ b/src/casdoor/organization.py @@ -75,13 +75,58 @@ def __init__(self): self.defaultApplication = "" self.tags = [""] self.languages = [""] - self.themeData = ThemeData + # self.themeData = ThemeData self.masterPassword = "" self.initScore = 0 self.enableSoftDeletion = False self.isProfilePublic = False - self.mfaItems = [MfaItem] - self.accountItems = [AccountItem] + # self.mfaItems = [MfaItem] + # self.accountItems = [AccountItem] + + @classmethod + def new( + cls, + owner, + name, + created_time, + display_name, + website_url, + password_type, + password_options, + country_codes, + tags, + languages, + init_score, + enable_soft_deletion, + is_profile_public, + ): + self = cls() + self.owner = owner + self.name = name + self.createdTime = created_time + self.displayName = display_name + self.websiteUrl = website_url + self.passwordType = password_type + self.passwordOptions = password_options + self.countryCodes = country_codes + self.tags = tags + self.languages = languages + self.initScore = init_score + self.enableSoftDeletion = enable_soft_deletion + self.isProfilePublic = is_profile_public + + return self + + @classmethod + def from_dict(cls, data: dict): + if data is None: + return None + + org = cls() + for key, value in data.items(): + if hasattr(org, key): + setattr(org, key, value) + return org def __str__(self): return str(self.__dict__) @@ -104,8 +149,14 @@ def get_organizations(self) -> List[Dict]: "clientSecret": self.client_secret, } r = requests.get(url, params) - organizations = r.json() - return organizations + response = r.json() + if response["status"] != "ok": + raise ValueError(response.msg) + + res = [] + for element in response["data"]: + res.append(Organization.from_dict(element)) + return res def get_organization(self, organization_id: str) -> Dict: """ @@ -121,13 +172,16 @@ def get_organization(self, organization_id: str) -> Dict: "clientSecret": self.client_secret, } r = requests.get(url, params) - organization = r.json() - return organization + response = r.json() + if response["status"] != "ok": + raise ValueError(response.msg) + return Organization.from_dict(response["data"]) def modify_organization(self, method: str, organization: Organization) -> Dict: url = self.endpoint + f"/api/{method}" - if organization.owner == "": - organization.owner = self.org_name + # if organization.owner == "": + # organization.owner = self.org_name + organization.owner = self.org_name params = { "id": f"{organization.owner}/{organization.name}", "clientId": self.client_id, @@ -136,7 +190,9 @@ def modify_organization(self, method: str, organization: Organization) -> Dict: organization_info = json.dumps(organization.to_dict()) r = requests.post(url, params=params, data=organization_info) response = r.json() - return response + if response["status"] != "ok": + raise ValueError(response) + return str(response["data"]) def add_organization(self, organization: Organization) -> Dict: response = self.modify_organization("add-organization", organization) diff --git a/src/tests/test_group.py b/src/tests/test_group.py new file mode 100644 index 0000000..2f522b0 --- /dev/null +++ b/src/tests/test_group.py @@ -0,0 +1,90 @@ +# Copyright 2023 The Casdoor Authors. All Rights Reserved. +# +# 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. + +import datetime +import unittest + +from src.casdoor import CasdoorSDK +from src.casdoor.group import Group +from src.tests.test_util import ( + TestApplication, + TestClientId, + TestClientSecret, + TestEndpoint, + TestJwtPublicKey, + TestOrganization, + get_random_name, +) + + +class GroupTest(unittest.TestCase): + def test_group(self): + name = get_random_name("group") + + # Add a new object + group = Group.new(owner="admin", name=name, created_time=datetime.datetime.now().isoformat(), display_name=name) + + sdk = CasdoorSDK( + TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication + ) + + try: + sdk.add_group(group) + except Exception as e: + self.fail(f"Failed to add object: {e}") + + # Get all objects, check if our added object is inside the list + try: + groups = sdk.get_groups() + except Exception as e: + self.fail(f"Failed to get objects: {e}") + names = [item.name for item in groups] + self.assertIn(name, names, "Added object not found in list") + + # Get the object + try: + retrieved_group = sdk.get_group(name) + except Exception as e: + self.fail(f"Failed to get object: {e}") + self.assertEqual(name, retrieved_group.name, "Retrieved object does not match added object") + + # Update the object + updated_display_name = "updated_display_name" + retrieved_group.displayName = updated_display_name + try: + updated_group = sdk.update_group(retrieved_group) + except Exception as e: + self.fail(f"Failed to update object: {e}") + + # Validate the update + try: + updated_group = sdk.get_group(name) + except Exception as e: + self.fail(f"Failed to get object: {e}") + self.assertEqual( + updated_display_name, updated_group.displayName, "Failed to update object, display_name mismatch" + ) + + # Delete the object + try: + sdk.delete_group(group) + except Exception as e: + self.fail(f"Failed to delete object: {e}") + + # Validate the deletion + try: + deleted_group = sdk.get_group(name) + except Exception as e: + self.fail(f"Failed to get object: {e}") + self.assertIsNone(deleted_group, "Failed to delete object, it's still retrievable") diff --git a/src/tests/test_organization.py b/src/tests/test_organization.py new file mode 100644 index 0000000..abb5bf1 --- /dev/null +++ b/src/tests/test_organization.py @@ -0,0 +1,99 @@ +# Copyright 2023 The Casdoor Authors. All Rights Reserved. +# +# 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. + +import datetime +import unittest + +from src.casdoor import CasdoorSDK +from src.casdoor.organization import Organization +from src.tests.test_util import ( + TestApplication, + TestClientId, + TestClientSecret, + TestEndpoint, + TestJwtPublicKey, + TestOrganization, + get_random_name, +) + + +class OrganizationTest(unittest.TestCase): + def test_organization(self): + name = get_random_name("Organization") + + # Add a new object + organization = Organization.new( + owner="admin", + name=name, + created_time=datetime.datetime.now().isoformat(), + display_name=name, + website_url="https://example.com", + password_type="plain", + password_options=["AtLeast6"], + country_codes=["US", "ES", "FR", "DE", "GB", "CN", "JP", "KR", "VN", "ID", "SG", "IN"], + tags=[], + languages=["en", "zh", "es", "fr", "de", "id", "ja", "ko", "ru", "vi", "pt"], + init_score=2000, + enable_soft_deletion=False, + is_profile_public=False, + ) + + sdk = CasdoorSDK( + TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication + ) + + try: + sdk.add_organization(organization) + except Exception as e: + self.fail(f"Failed to add object: {e}") + + # Get all objects, check if our added object is inside the list + try: + organizations = sdk.get_organizations() + except Exception as e: + self.fail(f"Failed to get objects: {e}") + names = [item.name for item in organizations] + self.assertIn(name, names, "Added object not found in list") + + # Get the object + try: + organization = sdk.get_organization(name) + except Exception as e: + self.fail(f"Failed to get object: {e}") + self.assertEqual(organization.name, name) + + # Update the object + updated_display_name = "Updated Casdoor Website" + organization.displayName = updated_display_name + try: + sdk.update_organization(organization) + except Exception as e: + self.fail(f"Failed to update object: {e}") + + # Validate the update + try: + updated_organization = sdk.get_organization(name) + except Exception as e: + self.fail(f"Failed to get object: {e}") + self.assertEqual(updated_organization.displayName, updated_display_name) + + # Delete the object + sdk.delete_organization(organization) + + # Validate the deletion + try: + deleted_organization = sdk.get_organization(name) + except Exception as e: + self.fail(f"Failed to get object: {e}") + self.assertIsNone(deleted_organization, "Failed to delete object, it's still retrievable")