Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion baseapp-auth/baseapp_auth/graphql/object_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def resolve_profiles(self, info):
return Profile.objects.none()
return Profile.objects.filter(
Q(owner_id=info.context.user.id) | Q(members__user_id=info.context.user.id)
)
).distinct()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ensures that profiles are only displayed once when switching profiles (calling .filter with a condition that involves multiple databases might produce duplicate entries)


interfaces += (UserProfiles, ProfileInterface)

Expand Down
7 changes: 3 additions & 4 deletions baseapp-auth/baseapp_auth/rest_framework/jwt/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,12 @@ def get_claim_serializer_class(cls):
class BaseJwtLoginSerializer(
CustomClaimSerializerMixin, LoginPasswordExpirationMixin, TokenObtainPairSerializer
):
@classmethod
def get_token(cls, user):
def get_token(self, user):
token = super().get_token(user)

# Add custom claims
if cls._claim_serializer_class:
data = cls.get_claim_serializer_class()(user).data
if self._claim_serializer_class:
data = self.get_claim_serializer_class()(user, context=self.context).data
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows relative urls to be converted to absolute urls when serializing the profile image

for key, value in data.items():
token[key] = value

Expand Down
35 changes: 30 additions & 5 deletions baseapp-auth/baseapp_auth/rest_framework/users/serializers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import swapper

from datetime import timedelta

from baseapp_auth.utils.referral_utils import get_user_referral_model, use_referrals
from baseapp_core.graphql import get_obj_relay_id
from baseapp_core.rest_framework.serializers import ModelSerializer
from baseapp_core.rest_framework.fields import ThumbnailImageField
from baseapp_referrals.utils import get_referral_code, get_user_from_referral_code
from constance import config
from django.contrib.auth import get_user_model
Expand All @@ -14,30 +18,51 @@
from .fields import AvatarField

User = get_user_model()
Profile = swapper.load_model("baseapp_profiles", "Profile")

from baseapp_auth.password_validators import apply_password_validators


class JWTProfileSerializer(serializers.ModelSerializer):
"""
Serializes minimal profile data that will be attached to the JWT token as claim
"""
url_path = serializers.SlugField(required=False)
id = serializers.SerializerMethodField()
image = ThumbnailImageField(required=False, sizes={"small": (100,100)})

class Meta:
model = Profile
fields = ("id", "name", "image", "url_path")

def get_id(self, profile):
return get_obj_relay_id(profile)

def to_representation(self, profile):
data = super().to_representation(profile)
if (data['image'] != None):
data['image'] = data['image']['small']
return data
Comment on lines +43 to +45
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix comparison to None

Use is not None instead of != None for Python identity comparison.

-        if (data['image'] != None):
+        if data['image'] is not None:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (data['image'] != None):
data['image'] = data['image']['small']
return data
if data['image'] is not None:
data['image'] = data['image']['small']
return data
🧰 Tools
🪛 Ruff (0.8.0)

43-43: Comparison to None should be cond is not None

Replace with cond is not None

(E711)



class UserBaseSerializer(ModelSerializer):
name = serializers.CharField(required=False, allow_blank=True, source="first_name")
avatar = AvatarField(required=False, allow_null=True)
profile = JWTProfileSerializer(read_only=True)
email_verification_required = serializers.SerializerMethodField()
referral_code = serializers.SerializerMethodField()
referred_by_code = serializers.CharField(required=False, allow_blank=True, write_only=True)

class Meta:
model = User
fields = (
"id",
"profile",
"email",
"is_email_verified",
"email_verification_required",
"new_email",
"is_new_email_confirmed",
"referral_code",
"referred_by_code",
"avatar",
"name",
"phone_number",
"preferred_language",
)
Expand Down
2 changes: 1 addition & 1 deletion baseapp-profiles/baseapp_profiles/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

class ProfileManager(models.Manager):
def filter_user_profiles(self, user):
return self.filter(models.Q(members__user=user) | models.Q(owner=user))
return self.filter(models.Q(members__user=user) | models.Q(owner=user)).distinct()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Similar queries found in the codebase - one missing .distinct()

The codebase scan reveals an inconsistency in the usage of .distinct() with similar Q-object queries:

  • In baseapp_profiles/baseapp_profiles/models.py: A similar query uses .distinct() for profiles_owner and profile_members__profile
  • However, in the same file, another query filter(models.Q(members__user=user) | models.Q(owner=user)) is missing .distinct() in the .exists() check
🔗 Analysis chain

LGTM! The addition of .distinct() prevents duplicate profiles.

The change correctly ensures unique profiles when a user is both a member and owner of a profile, which is essential for accurate JWT claims.

Let's verify the SQL query generation and check for similar patterns in the codebase:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for similar query patterns and potential inconsistencies

# Look for similar Q-object queries that might need .distinct()
rg -A 2 "models\.Q\(.*\)\s*\|.*models\.Q\(" --type py

# Check for other profile-related queries that might need similar treatment
ast-grep --pattern 'filter($$$).distinct()' 

Length of output: 1004


def get_if_member(self, user, **kwargs):
if user.is_superuser:
Expand Down
Loading