diff --git a/src/vaultwarden/models/bitwarden.py b/src/vaultwarden/models/bitwarden.py index 8a092c6..9fe0e72 100644 --- a/src/vaultwarden/models/bitwarden.py +++ b/src/vaultwarden/models/bitwarden.py @@ -1,6 +1,7 @@ from typing import Generic, Literal, TypeVar, cast from uuid import UUID +from httpx import Response from pydantic import AliasChoices, Field, TypeAdapter, field_validator from pydantic_core.core_schema import FieldValidationInfo @@ -483,6 +484,22 @@ def user_search( return None return users[0] + def change_user_type( + self, user: OrganizationUserDetails, premissions: OrganizationUserType + ) -> Response: + payload = { + "collections": [], + "groups": [], + "permissions": {"response": None}, + "type": premissions, + "accessSecretsManager": False, + } + + resp = self.api_client.api_request( + "PUT", f"api/organizations/{self.Id}/users/{user.Id}", json=payload + ) + return resp + def _get_collections(self) -> list[OrganizationCollection]: resp = self.api_client.api_request( "GET", f"api/organizations/{self.Id}/collections" diff --git a/tests/e2e/test_bitwarden.py b/tests/e2e/test_bitwarden.py index ff59ad5..fe1042a 100644 --- a/tests/e2e/test_bitwarden.py +++ b/tests/e2e/test_bitwarden.py @@ -3,6 +3,7 @@ from vaultwarden.clients.bitwarden import BitwardenAPIClient from vaultwarden.models.bitwarden import get_organization +from vaultwarden.models.enum import OrganizationUserType # Get Bitwarden credentials from environment variables url = os.environ.get("BITWARDEN_URL", None) @@ -40,7 +41,7 @@ def setUp(self) -> None: ).users() def test_get_organization_users(self): - self.assertEqual(len(self.test_users), 2) + self.assertEqual(len(self.test_users), 3) def test_get_organization_items(self): self.assertEqual(len(self.test_org_ciphers), 1) @@ -62,6 +63,13 @@ def test_get_users_of_collection_1(self): def test_get_users_of_collection_2(self): self.assertEqual(len(self.test_collection_2_users), 1) + def test_change_user_type_organization(self): + user = self.organization.user_search("test-account-3@example.com") + resp = self.organization.change_user_type(user, OrganizationUserType.Admin) + self.assertTrue(resp.is_success) + resp = self.organization.change_user_type(user, OrganizationUserType.User) + self.assertTrue(resp.is_success) + def test_create_delete_collection(self): len_old_colls = len(self.organization.collections(force_refresh=True)) new_coll = self.organization.create_collection("create_delete_test") diff --git a/tests/fixtures/server/db.sqlite3 b/tests/fixtures/server/db.sqlite3 index bf27515..5d3df05 100644 --- a/tests/fixtures/server/db.sqlite3 +++ b/tests/fixtures/server/db.sqlite3 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c8c11a331ba097f1644b297885cd09b4ac5fc975ed5605176c880bc5cf08a813 -size 245760 +oid sha256:2d5cad9198a9acfb3e8d861456a3c8b97d730bc9cc0e685c965a2597d9ed7a33 +size 262144 diff --git a/tests/fixtures/test-accout-3/profile_camel.json b/tests/fixtures/test-accout-3/profile_camel.json new file mode 100644 index 0000000..e25a1c0 --- /dev/null +++ b/tests/fixtures/test-accout-3/profile_camel.json @@ -0,0 +1,101 @@ +{ + "ciphers": [], + "collections": [], + "domains": null, + "folders": [], + "object": "sync", + "policies": [], + "profile": { + "_status": 0, + "avatarColor": null, + "creationDate": "2025-09-17T12:16:51.538080Z", + "culture": "en-US", + "email": "test-account-3@example.com", + "emailVerified": true, + "forcePasswordReset": false, + "id": "73f2a96c-7718-4e7c-9aa1-0f4e319ad01f", + "key": "2.7NJ7sUyRw82IIAEtFK++ow==|LN+cuL+YiO4XoiGAsOXoE3dXyHPTzq6G+/etMtbnCOyo7FvONmMH7+61n3VTruxMCpaZLQ7d3GxIWy2YsNp1WpxMMu0XxOUxtH82ZOQkLRI=|3Dq09MHhvbHWunlxeLpodpVWRiSIYPR4/U1Mp2hnG1U=", + "name": "test-account-3", + "object": "profile", + "organizations": [ + { + "accessSecretsManager": false, + "allowAdminAccessToAllCollectionItems": true, + "enabled": true, + "familySponsorshipAvailable": false, + "familySponsorshipFriendlyName": null, + "familySponsorshipLastSyncDate": null, + "familySponsorshipToDelete": null, + "familySponsorshipValidUntil": null, + "hasPublicAndPrivateKeys": true, + "id": "cda840d2-1de0-4f31-bd49-b30dacd7e8b0", + "identifier": null, + "key": "4.DDwoeFcsONwgnd9AJubUqEnzRoqRdHz5GluDPX4te+8FrlnVB35RNMkB9xQ76n0eIP3HbzXFixNZDh7rENd6D4RHeu4V8SA3dhZb9Y6wcfArCg2As8QBHmnbFPvdJWyLTWSbNDs9/SwawMdFpRUuDaPTHV7kWjmW4H5xIfKbN6YIpNo3C1pi2bXSqUZRuGbA01bnvn1xtL2cToEc8pDx52C8MSKCCRW3dysM6ob3I6zOwR911C6Ympd1rzXBFfBdrSTQlTA3RHo0tnTko/TmYil6vgcdo8NrfIwQOcSX/fzbcpgYaMwGYwZ5YxCMW+N9neu2YvXYmhvDwMXNsijv3Q==", + "keyConnectorEnabled": false, + "keyConnectorUrl": null, + "limitCollectionCreation": true, + "limitCollectionDeletion": true, + "limitItemDeletion": false, + "maxCollections": null, + "maxStorageGb": 32767, + "name": "Test Organization", + "object": "profileOrganization", + "organizationUserId": "2a9297d1-2619-47df-aa26-ee7721257570", + "permissions": { + "accessEventLogs": false, + "accessImportExport": false, + "accessReports": false, + "createNewCollections": false, + "deleteAnyCollection": false, + "editAnyCollection": false, + "manageGroups": false, + "managePolicies": false, + "manageResetPassword": false, + "manageScim": false, + "manageSso": false, + "manageUsers": false + }, + "productTierType": 3, + "providerId": null, + "providerName": null, + "providerType": null, + "resetPasswordEnrolled": false, + "seats": null, + "selfHost": true, + "ssoBound": false, + "status": 2, + "type": 2, + "use2fa": true, + "useActivateAutofillPolicy": false, + "useAdminSponsoredFamilies": false, + "useApi": true, + "useCustomPermissions": true, + "useDirectory": false, + "useEvents": false, + "useGroups": false, + "useKeyConnector": false, + "usePasswordManager": true, + "usePolicies": true, + "useResetPassword": false, + "useRiskInsights": false, + "useScim": false, + "useSecretsManager": false, + "useSso": false, + "useTotp": true, + "userId": "73f2a96c-7718-4e7c-9aa1-0f4e319ad01f", + "userIsClaimedByOrganization": false, + "userIsManagedByOrganization": false, + "usersGetPremium": true + } + ], + "premium": true, + "premiumFromOrganization": false, + "privateKey": "2.Ps14TCZ66rbYU+xXCrfkHQ==|Ms1SQM0GAs258Ls1RNoHoE6zTLy/MRXqJzPT/E8cfig2Tn0vfrYoVwppTJNOExDTzoS02yG73KFsOM83YvsiB7E5MeM445Q18EUGKdIW6WyIeYBCVxm+TmeyEWBW6r9tGhxV8iv+RRpdxPQVQYFZbqP92/ugzleSnh2rrUU02hIr9dxMQADtEyLu2VqTu2YH63Ljh6AWOtzUcvFgG/5izNjfZFgoIb0rdAn9oGQwxXF06LA/htClgCw59S0kEwVJqOC54VDYYDfLb66HbG4eogVvIsRbMrbgxuuwoTThW88frJyMIun2Z1eLNkx73LThA83g1N6fK1ko0zNR94E2y2+VgeWmZvZnKr579dXxc47Xe+5eauZ4AYBHDrhLs9sLXVNGr4wCtszUaJ00GFHPBlATsl2TjQyyq47dDRKm7UtiOBox/zOEKuyYAn4XkmPxDo6+/ltCIMqUuR3rdpbk9CmjUW41bO09+LysTleeYoMumVJYpz/03IP11oHKLbmqjCDnT6WfcfdEmlbFROgTuJxEn4lLncN9102qJxXsYWRyVLrymEFS3cwOml0urrutiQkizR5V9U1LtJ4uuJTRFE9/hbv4m/pcdTNbN+vP/66C6rOB3ZTEyhQ3CPD9b7bRONsJtVAP03LrRqp57uejkqh4G02zWLfSBqHzKVryvBRzETIQEiXesvXdftY+zeEm2XtHQRFOmw5syJK75wS76uxRcrLh3vOQzI19tkqKrvaLgW9CgCsET3P13ZEzM+6JZ33P3W4I3NortjBX/fBDFjsQn6fXLipLKraf2sizURCVcKsaw09qlSgxD+E7ynedXGGnG82L7IpWahKtL3TxbPSm+xS3XUICpFHS8hEmL5kFdzF+JmNe8Oh5MwIL3+H4K6sKx2ebjc5UfZmAZs9q+RaJdvOQupvGHaB28OOGUmdr2g3d4s8vTGOiIMfkoUmDYlUwTXrO3izWtA0ojJ3NJ32up63m0rpSByUkSlvcTor3V+MpVjg4PQjZCFTfSgalwyzu+sI/MjZ3R9EvTXPV3lOmvu3PtE6sEPby0s2qNg11KUGz2qPT1D2Y0YjTYF/TLjcTmeYrTgdDXzu/s34prHCJsAWfVtENc12R8KUVfmzmpf31YCoXrdgZHlcQ1LcC2S/2cT6kc059tcth4v7uTbg+IdMMB1RBUCcH1/ELCUSDhszy4daWRwcAaCyVImRFclP6nISYheQH7iTOHXQEb0KN20WozqJT1LXhKAoBPhOoMOemTExGvn291nTt9SnVtY+a1FJLtxymySBr/QggWnYItzXY2nRFTPpYcOTU3YOoYnMvLTnSEJA++lsleHHcuL2yu1XvZcX4jt6kSjXn375/G8Wj1d1VY194sl006TU5u1KjUuziq1vvg6M5/XIUQszvFdKz11qahWiUK2IIIEvC+NF3cC9YkodxgwVs4D4d0bpoVKDX2dadJFJpzW/Vfu9mM2w4P7TBKPl4fhzaS8BRledfohh+w9cOzZRHbHLxx3P4X8fkomVhFZxifP59JDwce/GO6VawyXPoKtATMc2rkdohrSC2H1Ic3mH5DZuvozEIwk710h+Jyo0K61QQ2Jf+EMbnj1tuAbS184TcgHIk70oGJOmcvnHsgVROt/I=|fa6RVD5+omu4W2K/f5GlyCq8vhWe3zfUbcRBpvCLPaQ=", + "providerOrganizations": [], + "providers": [], + "securityStamp": "b0cf4238-a77a-424c-8ff2-176f314e1378", + "twoFactorEnabled": false, + "usesKeyConnector": false + }, + "sends": [] +}