diff --git a/openbook_communities/schema/queries.py b/openbook_communities/schema/queries.py index f4e290f232bbea9421dcabc01ac45db9fbf73c6e..96f75e76bcf4437ef6eed0efbbced40e14468903 100644 --- a/openbook_communities/schema/queries.py +++ b/openbook_communities/schema/queries.py @@ -5,7 +5,7 @@ import strawberry import strawberry_django from asgiref.sync import async_to_sync from django.core.exceptions import PermissionDenied -from django.db.models import Count, Prefetch, F, Q, Case, When, Value, IntegerField +from django.db.models import Count, Prefetch, F, Q, Case, When, Value, IntegerField, OuterRef, Exists from django.db.models.lookups import IContains from django.utils.translation import gettext_lazy as _ from strawberry.django.context import StrawberryDjangoContext @@ -32,6 +32,7 @@ from openbook_communities.schema.types import ( Space, Task, ) +from openbook_terms.models import Skill as SkillModel Info: TypeAlias = StrawberryInfo[StrawberryDjangoContext, Any] @@ -241,10 +242,11 @@ class Query: is_member = False is_anonymous = user.is_anonymous - if not is_anonymous and is_uuid(id_or_name): - is_member = user.is_member_of_community_with_id(community_id=id_or_name) - elif not is_anonymous: - is_member = user.is_member_of_community_with_name(community_name=id_or_name) + if not is_anonymous: + if is_uuid(id_or_name): + is_member = user.is_member_of_community_with_id(community_id=id_or_name) + else: + is_member = user.is_member_of_community_with_name(community_name=id_or_name) query = Q(id=uuid.UUID(id_or_name)) if is_uuid(id_or_name) else Q(name=id_or_name) @@ -302,13 +304,18 @@ class Query: whens = [] locations_match = Q(geolocation__within=current_user.profile.geolocation) + # We need to use a skill exists query, because we want to check that at least one skill from the user profile exists for the task. + skill_exists_subquery = SkillModel.objects.filter(id__in=[skill.id for skill in skills], tasks=OuterRef("id")) if skills and current_user.profile.geolocation: - whens.append(When(Q(skills__in=skills) & (locations_match | Q(location_type="REMOTE")), then=Value(10))) + whens.append( + When(Q(Exists(skill_exists_subquery)) & (locations_match | Q(location_type="REMOTE")), then=Value(10)) + ) if skills: whens.append(When(skills__in=skills, then=Value(20))) if current_user.profile.geolocation: whens.append(When(locations_match, then=Value(30))) + return Paged.of( TaskModel.objects.annotate( custom_order=Case( diff --git a/openbook_communities/tests/test_graphql_tasks.py b/openbook_communities/tests/test_graphql_tasks.py index 6c3ff5f972c63e9413941cd4476df5d4c0de2a04..8d741fd20f9c1479aed67b4f5754c219c35e5fea 100644 --- a/openbook_communities/tests/test_graphql_tasks.py +++ b/openbook_communities/tests/test_graphql_tasks.py @@ -1192,6 +1192,9 @@ class TestTaskRecommendations: task_onsite_other_skill = self.create_task( skills=[other_skill.id], location_type="ONSITE", geolocation=geolocation1 ) + task_onsite_skill_1_and_other_skill = self.create_task( + skills=[skill1.id, other_skill.id], location_type="ONSITE", geolocation=geolocation1 + ) task_outside_onsite_other_skill = self.create_task( skills=[other_skill.id], location_type="ONSITE", geolocation=geolocation3 ) @@ -1207,14 +1210,15 @@ class TestTaskRecommendations: # member only tasks are not visible to non-members self.create_task(skills=[skill1.id], location_type="REMOTE", visibility=VisibilityType.MEMBERS) + # when the user has no profile information, the last five tasks are returned self.assert_filtered_tasks( {}, [ task_remote_other_skill, task_outside_onsite_other_skill, + task_onsite_skill_1_and_other_skill, task_onsite_other_skill, task_outside_onsite_skill_2, - task_remote_skill_2, ], ) @@ -1226,6 +1230,7 @@ class TestTaskRecommendations: {"limit": 10}, [ # skill matches and geo matches or remote + task_onsite_skill_1_and_other_skill, task_remote_skill_2, task_onsite_skill_1, task_onsite_2_skills, @@ -1233,6 +1238,7 @@ class TestTaskRecommendations: # only skill matches task_outside_onsite_skill_2, # only geo matches + # NOT task_onsite_skill_1_and_other_skill, since it's already found in skill matches and geo matches and there should be no duplicates task_onsite_other_skill, # everything else task_remote_other_skill,