Skip to content
Merged
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
9 changes: 8 additions & 1 deletion apps/accounts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
HasMultipleIDs,
HasOwner,
HasPermissionsSetup,
HasRelatedLocationContent,
HasRelatedModules,
OrganizationRelated,
)
Expand All @@ -44,7 +45,9 @@
from services.translator.mixins import HasAutoTranslatedFields


class PeopleGroupLocation(OrganizationRelated, AbstractLocation):
class PeopleGroupLocation(
OrganizationRelated, HasRelatedLocationContent, AbstractLocation
):
"""base location for group"""

people_group = models.ForeignKey(
Expand All @@ -53,6 +56,10 @@ class PeopleGroupLocation(OrganizationRelated, AbstractLocation):
related_name="locations",
)

@classmethod
def get_related_content(cls):
return cls.people_group.field.name

def get_related_organizations(self) -> list["Organization"]:
return [self.people_group.organization]

Expand Down
15 changes: 11 additions & 4 deletions apps/accounts/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
MultipleIDViewsetMixin,
NestedOrganizationViewMixins,
NestedPeopleGroupViewMixins,
QuerySerializersMixin,
)
from apps.files.models import Image
from apps.files.views import ImageStorageView
Expand Down Expand Up @@ -90,6 +91,7 @@
PeopleGroupRemoveFeaturedProjectsSerializer,
PeopleGroupRemoveTeamMembersSerializer,
PeopleGroupSerializer,
PeopleGroupSuperLightSerializer,
PrivacySettingsSerializer,
UserAdminListSerializer,
UserLighterSerializer,
Expand Down Expand Up @@ -519,7 +521,9 @@ def refresh_keycloak_actions_link(self, request, *args, **kwargs):
)


class PeopleGroupViewSet(MultipleIDViewsetMixin, viewsets.ModelViewSet):
class PeopleGroupViewSet(
QuerySerializersMixin, MultipleIDViewsetMixin, viewsets.ModelViewSet
):
queryset = PeopleGroup.objects.all()
serializer_class = PeopleGroupSerializer
filterset_class = PeopleGroupFilter
Expand All @@ -531,6 +535,10 @@ class PeopleGroupViewSet(MultipleIDViewsetMixin, viewsets.ModelViewSet):
OrderingFilter,
)
multiple_lookup_fields = [(PeopleGroup, "id")]
query_serializers = {
"light": PeopleGroupLightSerializer,
"superlight": PeopleGroupSuperLightSerializer,
}

def get_permissions(self):
codename = map_action_to_permission(self.action, "peoplegroup")
Expand All @@ -557,9 +565,8 @@ def get_queryset(self) -> QuerySet:
return PeopleGroup.objects.none()

def get_serializer_class(self):
if self.action == "list":
return PeopleGroupLightSerializer
return self.serializer_class
query = "light" if self.action == "list" else None
return super().get_serializer_class(query)

def get_serializer_context(self):
context = super().get_serializer_context()
Expand Down
5 changes: 5 additions & 0 deletions apps/commons/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,3 +491,8 @@ def similars(self, threshold: float = 0.15) -> QuerySet[Self]:
pk=self.pk
)
return type(self).objects.none()


class HasRelatedLocationContent:
def get_related_content(self):
raise NotImplementedError
28 changes: 27 additions & 1 deletion apps/commons/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

from django.db.models import QuerySet
from django.shortcuts import get_object_or_404
from rest_framework import mixins, viewsets
from drf_spectacular.utils import OpenApiParameter as _OpenApiParameter
from rest_framework import mixins, serializers, viewsets
from rest_framework.response import Response
from rest_framework.settings import api_settings

Expand Down Expand Up @@ -193,3 +194,28 @@ def initial(self, request, *args, **kwargs):
)

super().initial(request, *args, **kwargs)


class QuerySerializersMixin:
"""return specified serializer from queryparams"""

query_serializers: dict[str, serializers.Serializer] = {}

def get_serializer_class(self, query=None) -> serializers.Serializer:
query = query or self.request.query_params.get("serializer")
serializer = None
if query:
serializer = self.query_serializers.get(query)

return serializer or super().get_serializer_class()

@classmethod
def OpenApiParameter( # noqa: N802
cls, serializers: dict[str, serializers.Serializer]
) -> _OpenApiParameter:
return _OpenApiParameter(
name="serializer",
description="change output serializer",
required=False,
enum=serializers.keys(),
)
18 changes: 15 additions & 3 deletions apps/newsfeed/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
from django.db import models

from apps.commons.enums import Language
from apps.commons.mixins import HasOwner, OrganizationRelated
from apps.commons.mixins import (
HasOwner,
HasRelatedLocationContent,
OrganizationRelated,
)
from apps.projects.models import AbstractLocation
from services.translator.mixins import HasAutoTranslatedFields

Expand Down Expand Up @@ -62,7 +66,7 @@ class NewsfeedType(models.TextChoices):
)


class NewsLocation(AbstractLocation):
class NewsLocation(HasRelatedLocationContent, AbstractLocation):
news = models.OneToOneField(
"newsfeed.News",
related_name="location",
Expand All @@ -71,6 +75,10 @@ class NewsLocation(AbstractLocation):
blank=True,
)

@classmethod
def get_related_content(cls):
return cls.news.field.name

def get_related_organizations(self) -> list["Organization"]:
"""Return the organizations related to this model."""
return self.news.get_related_organizations()
Expand Down Expand Up @@ -199,7 +207,7 @@ def is_owned_by(self, user: "ProjectUser") -> bool:
return self.owner == user


class EventLocation(AbstractLocation):
class EventLocation(HasRelatedLocationContent, AbstractLocation):
event = models.OneToOneField(
"newsfeed.Event",
related_name="location",
Expand All @@ -208,6 +216,10 @@ class EventLocation(AbstractLocation):
blank=False,
)

@classmethod
def get_related_content(cls):
return cls.event.field.name

def get_related_organizations(self) -> list["Organization"]:
"""Return the organizations related to this model."""
return self.event.get_related_organizations()
Expand Down
14 changes: 11 additions & 3 deletions apps/newsfeed/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@
from apps.accounts.permissions import HasBasePermission
from apps.commons.permissions import ReadOnly
from apps.commons.utils import map_action_to_permission
from apps.commons.views import ListViewSet, NestedOrganizationViewMixins
from apps.commons.views import (
ListViewSet,
NestedOrganizationViewMixins,
QuerySerializersMixin,
)
from apps.files.models import Image
from apps.files.views import ImageStorageView
from apps.organizations.permissions import HasOrganizationPermission
Expand All @@ -22,9 +26,11 @@
from .filters import EventFilter, InstructionFilter, NewsFilter
from .models import Event, Instruction, News, Newsfeed
from .serializers import (
EventLightSerializer,
EventSerializer,
InstructionSerializer,
NewsfeedSerializer,
NewsLightSerializer,
NewsSerializer,
)

Expand Down Expand Up @@ -119,7 +125,7 @@ def get_queryset(self):
return self.merge_querysets(announcements, news, projects)


class NewsViewSet(viewsets.ModelViewSet):
class NewsViewSet(QuerySerializersMixin, viewsets.ModelViewSet):
"""Main endpoints for news."""

serializer_class = NewsSerializer
Expand All @@ -128,6 +134,7 @@ class NewsViewSet(viewsets.ModelViewSet):
ordering_fields = ("updated_at", "created_at", "publication_date")
lookup_field = "id"
lookup_value_regex = "[^/]+"
query_serializers = {"light": NewsLightSerializer}

def get_permissions(self):
codename = map_action_to_permission(self.action, "news")
Expand Down Expand Up @@ -319,7 +326,7 @@ def add_image_to_model(self, image):
return None


class EventViewSet(viewsets.ModelViewSet):
class EventViewSet(QuerySerializersMixin, viewsets.ModelViewSet):
"""Main endpoints for projects."""

serializer_class = EventSerializer
Expand All @@ -328,6 +335,7 @@ class EventViewSet(viewsets.ModelViewSet):
ordering_fields = ("start_date", "end_date", "updated_at", "created_at")
lookup_field = "id"
lookup_value_regex = "[^/]+"
query_serializers = {"light": EventLightSerializer}

def get_permissions(self):
codename = map_action_to_permission(self.action, "event")
Expand Down
51 changes: 27 additions & 24 deletions apps/organizations/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
from apps.accounts.permissions import HasBasePermission
from apps.accounts.serializers import (
PeopleGroupHierarchySerializer,
PeopleGroupLocationSuperLightSerializer,
UserSerializer,
)
from apps.commons.cache import clear_cache_with_key, redis_cache_view
Expand All @@ -35,12 +34,12 @@
from apps.files.views import ImageStorageView
from apps.modules.group import PeopleGroupModules
from apps.newsfeed.models import EventLocation, NewsLocation
from apps.newsfeed.serializers import (
EventLocationSerializerLight,
NewsLocationSerializerLight,
)
from apps.projects.models import Location, Project
from apps.projects.serializers import LocationSerializer, ProjectLightSerializer
from apps.projects.serializers import (
GeneralLocationSerializer,
ProjectLightSerializer,
)
from apps.projects.utils import annotate_queryset_location

from .exceptions import (
MissingLifeStatusParameterError,
Expand Down Expand Up @@ -736,31 +735,35 @@ def get(self, request):
class GeneralLocationView(NestedOrganizationViewMixins, viewsets.GenericViewSet):
http_method_names = ["get", "list"]

def list(self, request, *args, **kwargs):
qs_project = (
request.user.get_project_related_queryset(Location.objects)
.select_related("project")
.filter(project__organizations__in=self.organizations)
def get_queryset_project(self) -> QuerySet[Location]:
return self.request.user.get_project_related_queryset(Location.objects).filter(
project__organizations__in=self.organizations
)

qs_group = request.user.get_people_group_related_queryset(
def get_queryset_groups(self) -> QuerySet[PeopleGroupLocation]:
return self.request.user.get_people_group_related_queryset(
PeopleGroupLocation.objects.filter(
people_group__organization__in=self.organizations
)
).select_related("people_group")
)

qs_news = request.user.get_news_related_queryset(
def get_queryset_news(self) -> QuerySet[NewsLocation]:
return self.request.user.get_news_related_queryset(
NewsLocation.objects.filter(news__organization__in=self.organizations)
).select_related("news")
)

qs_event = request.user.get_event_related_queryset(
def get_queryset_event(self) -> QuerySet[EventLocation]:
return self.request.user.get_event_related_queryset(
EventLocation.objects.filter(event__organization__in=self.organizations)
).select_related("event")

data = {
"groups": PeopleGroupLocationSuperLightSerializer(qs_group, many=True).data,
"projects": LocationSerializer(qs_project, many=True).data,
"news": NewsLocationSerializerLight(qs_news, many=True).data,
"event": EventLocationSerializerLight(qs_event, many=True).data,
}
)

def list(self, request, *args, **kwargs):
qs_project = self.get_queryset_project()
qs_groups = self.get_queryset_groups()
qs_news = self.get_queryset_news()
qs_event = self.get_queryset_event()

qs = annotate_queryset_location(qs_project, qs_groups, qs_news, qs_event)

data = GeneralLocationSerializer(list(qs), many=True).data
return Response(data, status=status.HTTP_200_OK)
7 changes: 6 additions & 1 deletion apps/projects/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
HasMultipleIDs,
HasOwner,
HasPermissionsSetup,
HasRelatedLocationContent,
HasRelatedModules,
ProjectRelated,
)
Expand Down Expand Up @@ -901,7 +902,7 @@ class Meta:


# TODO(remi): rename to ProjectLocation ?
class Location(ProjectRelated, AbstractLocation):
class Location(ProjectRelated, HasRelatedLocationContent, AbstractLocation):
"""A project location on Earth.

Attributes
Expand All @@ -916,6 +917,10 @@ class Location(ProjectRelated, AbstractLocation):
Project, on_delete=models.CASCADE, related_name="locations"
)

@classmethod
def get_related_content(cls):
return cls.project.field.name

def get_related_project(self) -> Optional["Project"]:
"""Return the projects related to this model."""
return self.project
Expand Down
17 changes: 16 additions & 1 deletion apps/projects/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@
)
from apps.skills.models import Tag
from apps.skills.serializers import TagRelatedField
from services.translator.serializers import auto_translated
from services.translator.serializers import (
auto_translated,
generate_translated_fields,
)

from .exceptions import (
AddProjectToOrganizationPermissionError,
Expand Down Expand Up @@ -963,3 +966,15 @@ def get_string_images_kwargs(
"project_id": instance.tab.project.id,
"tab_id": instance.tab.id,
}


@generate_translated_fields(("title", "description"))
class GeneralLocationSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField()
description = serializers.CharField()
content_id = serializers.CharField()
content_type = serializers.CharField()
lat = serializers.FloatField()
lng = serializers.FloatField()
type = serializers.CharField()
Loading
Loading