Skip to content

Commit 2735076

Browse files
authored
Merge pull request #572 from PROCOLLAB-github/dev
Dev
2 parents d120787 + fc691d1 commit 2735076

13 files changed

Lines changed: 127 additions & 28 deletions

File tree

feed/views.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ def get_queryset(self) -> QuerySet[News]:
4848
)
4949
.order_by("-datetime_created")
5050
)
51+
52+
existing_object_filters = {
53+
"project": Project.objects.values_list("id", flat=True),
54+
"vacancy": Vacancy.objects.values_list("id", flat=True),
55+
}
56+
for model_name, ids_queryset in existing_object_filters.items():
57+
queryset = queryset.exclude(
58+
Q(content_type__model=model_name)
59+
& ~Q(object_id__in=ids_queryset)
60+
)
61+
5162
return queryset
5263

5364
def get(self, *args, **kwargs):

invites/filters.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,14 @@ class InviteFilter(filters.FilterSet):
1919
"""
2020

2121
def __init__(self, *args, **kwargs):
22-
"""if user filter is not passed, default to request.user"""
2322
super().__init__(*args, **kwargs)
24-
if self.data.get("user") is None:
25-
# default filtering by current user
26-
self.data = dict(self.data)
27-
self.data["user"] = kwargs.get("request").user.id
28-
# if user == "any", remove the filter
29-
if self.data.get("user") == "any":
30-
self.data = dict(self.data)
31-
self.data.pop("user")
23+
self.data = dict(self.data)
24+
request = kwargs.get("request")
25+
if request and request.user.is_authenticated:
26+
self.data["user"] = request.user.id
3227

3328
project = filters.Filter(method=project_id_filter)
29+
user = filters.NumberFilter(field_name="user_id")
3430

3531
class Meta:
3632
model = Invite

invites/serializers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class Meta:
1919
"specialization",
2020
"is_accepted",
2121
]
22+
read_only_fields = ["is_accepted"]
2223

2324
def validate(self, attrs):
2425
project = attrs["project"]

invites/tests.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ def setUp(self) -> None:
2929
"user": None,
3030
"motivational_letter": "hello",
3131
"role": "Developer",
32-
"is_accepted": False,
3332
}
3433

3534
self.project_create_data = {
@@ -59,7 +58,7 @@ def test_invites_creation(self):
5958
)
6059
self.assertEqual(response.data["project"]["id"], create_user["project"])
6160
self.assertEqual(response.data["role"], create_user["role"])
62-
self.assertEqual(response.data["is_accepted"], create_user["is_accepted"])
61+
self.assertIsNone(response.data["is_accepted"])
6362

6463
def test_invites_creation_with_empty_text(self):
6564
user_main = self._user_create("example@gmail.com")

invites/views.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010

1111
class InviteList(generics.ListCreateAPIView):
12-
queryset = Invite.objects.get_invite_for_list_view()
12+
queryset = Invite.objects.get_invite_for_list_view().filter(is_accepted__isnull=True)
1313
serializer_class = InviteDetailSerializer
1414
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
1515
filter_backends = (filters.DjangoFilterBackend,)
@@ -47,13 +47,30 @@ def post(self, request, *args, **kwargs):
4747
invite = self.get_object() # type: Invite
4848
if invite.user != request.user:
4949
return Response(status=status.HTTP_403_FORBIDDEN)
50+
if invite.is_accepted is True:
51+
return Response(
52+
{"detail": "Invite has already been accepted."},
53+
status=status.HTTP_409_CONFLICT,
54+
)
55+
if invite.is_accepted is False:
56+
return Response(
57+
{"detail": "Invite has already been declined."},
58+
status=status.HTTP_409_CONFLICT,
59+
)
5060
# add user to project collaborators
51-
Collaborator.objects.create(
61+
collaborator, created = Collaborator.objects.get_or_create(
5262
user=invite.user,
5363
project=invite.project,
54-
role=invite.role,
55-
specialization=invite.specialization,
64+
defaults={
65+
"role": invite.role,
66+
"specialization": invite.specialization,
67+
},
5668
)
69+
if not created:
70+
return Response(
71+
{"detail": "User is already a collaborator of this project."},
72+
status=status.HTTP_409_CONFLICT,
73+
)
5774
invite.is_accepted = True
5875
invite.save()
5976
return Response(status=status.HTTP_200_OK)

partner_programs/serializers.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ def count_views(self, program):
2929
return get_views_count(program)
3030

3131
def get_short_description(self, program):
32+
if not program.description:
33+
return ""
3234
return program.description[:125]
3335

3436
def get_is_user_liked(self, obj):

partner_programs/views.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,24 @@ class PartnerProgramList(generics.ListCreateAPIView):
6565
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
6666
pagination_class = PartnerProgramPagination
6767

68+
def get_queryset(self):
69+
base_qs = super().get_queryset()
70+
participating_flag = self.request.query_params.get("participating")
71+
if not participating_flag:
72+
return base_qs
73+
74+
if not self.request.user.is_authenticated:
75+
return PartnerProgram.objects.none()
76+
77+
now = timezone.now()
78+
return (
79+
base_qs.filter(
80+
partner_program_profiles__user=self.request.user,
81+
datetime_finished__gte=now,
82+
)
83+
.distinct()
84+
)
85+
6886

6987
class PartnerProgramDetail(generics.RetrieveAPIView):
7088
queryset = PartnerProgram.objects.prefetch_related("materials", "managers").all()

project_rates/serializers.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class ProjectListForRateSerializer(serializers.ModelSerializer):
6161
views_count = serializers.SerializerMethodField()
6262
criterias = serializers.SerializerMethodField()
6363
scored = serializers.SerializerMethodField()
64+
scored_expert_id = serializers.IntegerField(read_only=True, allow_null=True)
6465

6566
class Meta:
6667
model = Project
@@ -75,6 +76,7 @@ class Meta:
7576
"region",
7677
"views_count",
7778
"scored",
79+
"scored_expert_id",
7880
"criterias",
7981
]
8082

project_rates/views.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from django.contrib.auth import get_user_model
2-
from django.db.models import QuerySet, Count
2+
from django.db.models import QuerySet, Count, OuterRef, Subquery, IntegerField
33

44
from rest_framework import generics, status
55
from rest_framework.response import Response
@@ -98,6 +98,13 @@ def get_queryset(self) -> QuerySet[Project]:
9898
project__isnull=False, partner_program__id=self.kwargs.get("program_id")
9999
).values_list("project__id", flat=True)
100100
# `Count` the easiest way to check for rate exist (0 -> does not exist).
101+
scored_expert_subquery = ProjectScore.objects.filter(
102+
project=OuterRef("pk")
103+
).values("user_id")[:1]
104+
101105
return Project.objects.filter(draft=False, id__in=projects_ids).annotate(
102-
scored=Count("scores")
106+
scored=Count("scores"),
107+
scored_expert_id=Subquery(
108+
scored_expert_subquery, output_field=IntegerField()
109+
),
103110
)

projects/managers.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,18 @@ def get_draft_projects_for_user(self):
1616

1717
class ProjectManager(Manager):
1818
def get_projects_for_list_view(self):
19-
return self.get_queryset().filter(draft=False).prefetch_related("program_links")
19+
return (
20+
self.get_queryset()
21+
.filter(draft=False)
22+
.prefetch_related("program_links__partner_program")
23+
)
2024

2125
def get_user_projects_for_list_view(self):
22-
return self.get_queryset().distinct()
26+
return (
27+
self.get_queryset()
28+
.prefetch_related("program_links__partner_program")
29+
.distinct()
30+
)
2331

2432
def get_projects_for_detail_view(self):
2533
return (

0 commit comments

Comments
 (0)