From f40324e9ea187cc74357f9d7934d9f6c6a2a526f Mon Sep 17 00:00:00 2001 From: Joschka Thurner Date: Fri, 30 Jun 2023 11:32:44 +0200 Subject: [PATCH] Cosmos-DB compatability (#25) Cosmos-DB compatability (#25) Azure Cosmos DB for MongoDB neither supports creating unique index on non-empty collections nor collation, which leads to exceptions in fastapi-users. Introduce a setting COSMOSDB_COMPAT which, when set, replaces MongoDBUserDatabase with a subclass with the incompatible function calls patched out: only set indexes if they do not exist on the collection (so they are set only once, before documents are inserted) do not use collation when storing/querying the email field Skipping the collation means that email addressess (usernames) are not case-insensitive anymore - i.e. my@user.de and My@user.de are treated as different accounts. --- pandahub/api/internal/db.py | 23 ++++++++++++++++++++++- pandahub/api/internal/settings.py | 1 + 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/pandahub/api/internal/db.py b/pandahub/api/internal/db.py index a39c07d..236f40d 100644 --- a/pandahub/api/internal/db.py +++ b/pandahub/api/internal/db.py @@ -21,8 +21,29 @@ async def get_user_db(): - yield MongoDBUserDatabase(UserDB, collection) + if settings.COSMOSDB_COMPAT: + yield MongoDBUserDatabaseCosmos(UserDB, collection) + else: + yield MongoDBUserDatabase(UserDB, collection) async def get_access_token_db(): yield MongoDBAccessTokenDatabase(AccessToken, access_tokens_collection) + +class MongoDBUserDatabaseCosmos(MongoDBUserDatabase): + from typing import Optional + from fastapi_users.models import UD + async def get_by_email(self, email: str) -> Optional[UD]: + await self._initialize() + + user = await self.collection.find_one( + {"email": email} + ) + return self.user_db_model(**user) if user else None + + async def _initialize(self): + if not self.initialized: + if "email_1" not in await self.collection.index_information(): + await self.collection.create_index("id", unique=True) + await self.collection.create_index("email", unique=True) + self.initialized = True diff --git a/pandahub/api/internal/settings.py b/pandahub/api/internal/settings.py index c151cf4..07ed322 100644 --- a/pandahub/api/internal/settings.py +++ b/pandahub/api/internal/settings.py @@ -48,3 +48,4 @@ def get_secret(key, default=None): REGISTRATION_ADMIN_APPROVAL = settings_bool("REGISTRATION_ADMIN_APPROVAL", default=False) DATATYPES_MODULE = os.getenv("DATATYPES_MODULE") or "pandahub.lib.datatypes" +COSMOSDB_COMPAT = settings_bool("COSMOSDB_COMPAT", default=False)