Skip to content

Commit e8a449c

Browse files
committed
feat: add modules groups
1 parent e26bb5d commit e8a449c

File tree

7 files changed

+143
-44
lines changed

7 files changed

+143
-44
lines changed

apps/accounts/models.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
)
2626
from apps.commons.enums import SDG, Language
2727
from apps.commons.mixins import (
28+
HasModulesRelated,
2829
HasMultipleIDs,
2930
HasOwner,
3031
HasPermissionsSetup,
@@ -41,6 +42,7 @@
4142

4243

4344
class PeopleGroup(
45+
HasModulesRelated,
4446
HasAutoTranslatedFields,
4547
HasMultipleIDs,
4648
HasPermissionsSetup,

apps/accounts/serializers.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,16 @@ class Meta:
237237
fields = read_only_fields
238238

239239

240+
class ModulesSerializers(serializers.ModelSerializer):
241+
modules = serializers.SerializerMethodField()
242+
243+
def get_modules(self, instance):
244+
request = self.context.get("request")
245+
246+
cls = instance.get_related_module()
247+
return cls(instance, user=request.user).count()
248+
249+
240250
class PeopleGroupLightSerializer(
241251
AutoTranslatedModelSerializer, serializers.ModelSerializer
242252
):
@@ -402,7 +412,10 @@ def create(self, validated_data):
402412

403413

404414
class PeopleGroupSerializer(
405-
StringsImagesSerializer, AutoTranslatedModelSerializer, serializers.ModelSerializer
415+
ModulesSerializers,
416+
StringsImagesSerializer,
417+
AutoTranslatedModelSerializer,
418+
serializers.ModelSerializer,
406419
):
407420

408421
string_images_forbid_fields: List[str] = [
@@ -527,7 +540,7 @@ def save(self, **kwargs):
527540

528541
class Meta:
529542
model = PeopleGroup
530-
read_only_fields = ["is_root", "slug"]
543+
read_only_fields = ["is_root", "slug", "modules"]
531544
fields = read_only_fields + [
532545
"id",
533546
"name",

apps/accounts/views.py

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
from apps.files.views import ImageStorageView
4141
from apps.organizations.models import Organization
4242
from apps.organizations.permissions import HasOrganizationPermission
43-
from apps.projects.models import Project
4443
from apps.projects.serializers import ProjectLightSerializer
4544
from apps.skills.models import Skill
4645
from services.google.models import GoogleAccount, GoogleGroup
@@ -682,27 +681,10 @@ def remove_member(self, request, *args, **kwargs):
682681
)
683682
def member(self, request, *args, **kwargs):
684683
group = self.get_object()
685-
managers_ids = group.managers.all().values_list("id", flat=True)
686-
leaders_ids = group.leaders.all().values_list("id", flat=True)
687-
skills_prefetch = Prefetch(
688-
"skills", queryset=Skill.objects.select_related("tag")
689-
)
690-
queryset = (
691-
group.get_all_members()
692-
.distinct()
693-
.annotate(
694-
is_leader=Case(
695-
When(id__in=leaders_ids, then=True), default=Value(False)
696-
)
697-
)
698-
.annotate(
699-
is_manager=Case(
700-
When(id__in=managers_ids, then=True), default=Value(False)
701-
)
702-
)
703-
.order_by("-is_leader", "-is_manager")
704-
.prefetch_related(skills_prefetch, "groups")
705-
)
684+
685+
cls = group.get_related_module()
686+
module = cls(group, request.user)
687+
queryset = module.members()
706688

707689
page = self.paginate_queryset(queryset)
708690
if page is not None:
@@ -790,26 +772,10 @@ def remove_featured_project(self, request, *args, **kwargs):
790772
)
791773
def project(self, request, *args, **kwargs):
792774
group = self.get_object()
793-
group_projects_ids = (
794-
Project.objects.filter(groups__people_groups=group)
795-
.distinct()
796-
.values_list("id", flat=True)
797-
)
798-
queryset = (
799-
self.request.user.get_project_queryset()
800-
.filter(Q(groups__people_groups=group) | Q(people_groups=group))
801-
.annotate(
802-
is_group_project=Case(
803-
When(id__in=group_projects_ids, then=True), default=Value(False)
804-
),
805-
is_featured=Case(
806-
When(people_groups=group, then=True), default=Value(False)
807-
),
808-
)
809-
.distinct()
810-
.order_by("-is_featured", "-is_group_project")
811-
.prefetch_related("categories")
812-
)
775+
cls = group.get_related_module()
776+
module = cls(group, request.user)
777+
queryset = module.featured_projects()
778+
813779
page = self.paginate_queryset(queryset)
814780
if page is not None:
815781
project_serializer = ProjectLightSerializer(

apps/commons/mixins.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,3 +408,12 @@ def get_slug(self) -> str:
408408
if self.get_id_field_name(slug) != "slug":
409409
slug = f"{self.slug_prefix}-{slug}"
410410
return slug
411+
412+
413+
class HasModulesRelated:
414+
"""Mixins for related modules class"""
415+
416+
def get_related_module(self):
417+
from apps.modules.base import get_module
418+
419+
return get_module(type(self))

apps/modules/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .group import PeopleGroupModules
2+
3+
__all__ = ["PeopleGroupModules"]

apps/modules/base.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import inspect
2+
3+
from django.db import models
4+
5+
6+
class AbstractModules:
7+
"""abstract class for modules/queryset declarations"""
8+
9+
def __init__(self, instance, /, user, **kw):
10+
self.instance = instance
11+
self.user = user
12+
13+
def count(self):
14+
members = inspect.getmembers(
15+
self,
16+
predicate=inspect.ismethod,
17+
)
18+
19+
modules = {}
20+
for name, func in members:
21+
# ignore private_method and "count" method (this method :D)
22+
if name.startswith("_") or name in ("count",):
23+
continue
24+
25+
# func return queryset
26+
modules[name] = func().count()
27+
28+
return modules
29+
30+
31+
_modules: dict[models.Model] = {}
32+
33+
34+
def register_module(model: models.Model):
35+
"""decorator to register modules assoiate on models
36+
37+
:param model: _description_
38+
"""
39+
40+
def _wrap(cls):
41+
_modules[model] = cls
42+
return cls
43+
44+
return _wrap
45+
46+
47+
def get_module(model: models.Model):
48+
"""get regisered module"""
49+
return _modules[model]

apps/modules/group.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from django.db.models import Case, Prefetch, Q, QuerySet, Value, When
2+
3+
from apps.accounts.models import PeopleGroup, ProjectUser
4+
from apps.modules.base import AbstractModules, register_module
5+
from apps.projects.models import Project
6+
from apps.skills.models import Skill
7+
8+
9+
@register_module(PeopleGroup)
10+
class PeopleGroupModules(AbstractModules):
11+
def members(self) -> QuerySet[ProjectUser]:
12+
managers_ids = self.instance.managers.all().values_list("id", flat=True)
13+
leaders_ids = self.instance.leaders.all().values_list("id", flat=True)
14+
skills_prefetch = Prefetch(
15+
"skills", queryset=Skill.objects.select_related("tag")
16+
)
17+
return (
18+
self.instance.get_all_members()
19+
.distinct()
20+
.annotate(
21+
is_leader=Case(
22+
When(id__in=leaders_ids, then=True), default=Value(False)
23+
)
24+
)
25+
.annotate(
26+
is_manager=Case(
27+
When(id__in=managers_ids, then=True), default=Value(False)
28+
)
29+
)
30+
.order_by("-is_leader", "-is_manager")
31+
.prefetch_related(skills_prefetch, "groups")
32+
)
33+
34+
def featured_projects(self) -> QuerySet[Project]:
35+
group_projects_ids = (
36+
Project.objects.filter(groups__people_groups=self.instance)
37+
.distinct()
38+
.values_list("id", flat=True)
39+
)
40+
41+
return (
42+
self.user.get_project_queryset()
43+
.filter(
44+
Q(groups__people_groups=self.instance) | Q(people_groups=self.instance)
45+
)
46+
.annotate(
47+
is_group_project=Case(
48+
When(id__in=group_projects_ids, then=True), default=Value(False)
49+
),
50+
is_featured=Case(
51+
When(people_groups=self.instance, then=True), default=Value(False)
52+
),
53+
)
54+
.distinct()
55+
.order_by("-is_featured", "-is_group_project")
56+
.prefetch_related("categories")
57+
)

0 commit comments

Comments
 (0)