From de4ff61d3d53ca6dc20c7dd623af29d61cd36657 Mon Sep 17 00:00:00 2001 From: Jose Buitron Date: Thu, 15 Aug 2024 12:37:31 -0500 Subject: [PATCH 1/2] refactor: Async execution of update profile image --- terraso_backend/apps/auth/services.py | 3 +- terraso_backend/apps/storage/tasks.py | 54 +++++++++++++++++++++ terraso_backend/tests/auth/test_services.py | 5 +- 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 terraso_backend/apps/storage/tasks.py diff --git a/terraso_backend/apps/auth/services.py b/terraso_backend/apps/auth/services.py index d92349140..a651154cc 100644 --- a/terraso_backend/apps/auth/services.py +++ b/terraso_backend/apps/auth/services.py @@ -36,6 +36,7 @@ USER_PREFS_KEYS, ) from apps.storage.services import ProfileImageService +from apps.storage.tasks import start_update_profile_image_task from .providers import AppleProvider, GoogleProvider, MicrosoftProvider from .signals import user_signup_signal @@ -103,7 +104,7 @@ def _persist_user(self, email, first_name="", last_name="", profile_image_url=No raise ValueError("Could not create account, user email is empty") user, created = User.objects.get_or_create(email=email) - self._update_profile_image(user, profile_image_url) + start_update_profile_image_task(user.id, profile_image_url) if not created: return user, False diff --git a/terraso_backend/apps/storage/tasks.py b/terraso_backend/apps/storage/tasks.py new file mode 100644 index 000000000..e6b3e7fe5 --- /dev/null +++ b/terraso_backend/apps/storage/tasks.py @@ -0,0 +1,54 @@ +# Copyright © 2023 Technology Matters +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see https://www.gnu.org/licenses/. + +import threading + +import structlog +from django.contrib.auth import get_user_model + +from apps.storage.services import ProfileImageService + +User = get_user_model() + +logger = structlog.get_logger(__name__) + + +class AsyncTaskHandler: + def start_task(self, method, args): + t = threading.Thread(target=method, args=[*args], daemon=True) + t.start() + + +def start_update_profile_image_task(user_id, profile_image_url): + AsyncTaskHandler().start_task(_update_profile_image, [user_id, profile_image_url]) + + +def _update_profile_image(user_id, profile_image_url): + if not profile_image_url: + return + + try: + user = User.objects.get(pk=user_id) + except User.DoesNotExist: + logger.error("User not found when updating profile image", extra={"user_id": user_id}) + return + + profile_image_service = ProfileImageService() + + try: + user.profile_image = profile_image_service.upload_url(user_id, profile_image_url) + user.save() + except Exception: + logger.exception("Failed to upload profile image. User ID: {}".format(user_id)) diff --git a/terraso_backend/tests/auth/test_services.py b/terraso_backend/tests/auth/test_services.py index 8bb8a0fbc..3fdcb5637 100644 --- a/terraso_backend/tests/auth/test_services.py +++ b/terraso_backend/tests/auth/test_services.py @@ -37,9 +37,12 @@ def user(): @mock_aws @mock.patch("urllib.request.urlopen", mock.mock_open(read_data="file content")) +# Mocked Model get because of multithreading context +@mock.patch("apps.storage.tasks.User.objects.get") @mock.patch("apps.storage.services.ProfileImageService.upload_url") -def test_sign_up_with_google_creates_user(mock_upload, respx_mock, access_tokens_google): +def test_sign_up_with_google_creates_user(mock_upload, mock_get, respx_mock, access_tokens_google): mock_upload.return_value = "https://test.com/user-id/image-path" + mock_get.return_value = User(id="test_id") respx_mock.post(GoogleProvider.GOOGLE_TOKEN_URI).mock( return_value=Response(200, json=access_tokens_google) ) From 10eb7d089633025745ef52b280b733eda8d92db4 Mon Sep 17 00:00:00 2001 From: Paul Schreiber Date: Thu, 15 Aug 2024 16:55:42 -0400 Subject: [PATCH 2/2] Update terraso_backend/apps/storage/tasks.py --- terraso_backend/apps/storage/tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraso_backend/apps/storage/tasks.py b/terraso_backend/apps/storage/tasks.py index e6b3e7fe5..fd6411dae 100644 --- a/terraso_backend/apps/storage/tasks.py +++ b/terraso_backend/apps/storage/tasks.py @@ -1,4 +1,4 @@ -# Copyright © 2023 Technology Matters +# Copyright © 2024 Technology Matters # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published