Skip to content

Commit

Permalink
Merge pull request #1044 from mattburnett-repo/1006.2
Browse files Browse the repository at this point in the history
1006.2 Partial
  • Loading branch information
andrewtavis authored Jan 29, 2025
2 parents cb32688 + ecd5d7b commit 8fc3154
Show file tree
Hide file tree
Showing 56 changed files with 957 additions and 441 deletions.
24 changes: 23 additions & 1 deletion backend/communities/groups/factories.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
import datetime
import random

import factory

from communities.groups.models import Group, GroupImage, GroupMember, GroupText
from communities.groups.models import (
Group,
GroupImage,
GroupMember,
GroupSocialLink,
GroupText,
)

# MARK: Main Tables

Expand Down Expand Up @@ -43,6 +50,21 @@ class Meta:
is_admin = factory.Faker("boolean")


class GroupSocialLinkFactory(factory.django.DjangoModelFactory):
class Meta:
model = GroupSocialLink

link = "https://www.activist.org"
label = "social link"
order = random.randint(0, 10)
creation_date = factory.LazyFunction(
lambda: datetime.datetime.now(tz=datetime.timezone.utc)
)
last_updated = factory.LazyFunction(
lambda: datetime.datetime.now(tz=datetime.timezone.utc)
)


class GroupTextFactory(factory.django.DjangoModelFactory):
class Meta:
model = GroupText
Expand Down
11 changes: 10 additions & 1 deletion backend/communities/groups/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from django.db import models

from content.models import SocialLink
from utils.models import ISO_CHOICES

# MARK: Main Tables
Expand All @@ -32,7 +33,6 @@ class Group(models.Model):
terms_checked = models.BooleanField(default=False)
creation_date = models.DateTimeField(auto_now_add=True)

social_links = models.ManyToManyField("content.SocialLink", blank=True)
topics = models.ManyToManyField("content.Topic", blank=True)
faqs = models.ManyToManyField("content.Faq", blank=True)
events = models.ManyToManyField("events.Event", blank=True)
Expand Down Expand Up @@ -71,6 +71,12 @@ def __str__(self) -> str:
return f"{self.id}"


class GroupSocialLink(SocialLink):
group = models.ForeignKey(
Group, on_delete=models.CASCADE, null=True, related_name="social_links"
)


class GroupText(models.Model):
group = models.ForeignKey(
Group, on_delete=models.CASCADE, null=True, related_name="texts"
Expand All @@ -80,3 +86,6 @@ class GroupText(models.Model):
description = models.TextField(max_length=500)
get_involved = models.TextField(max_length=500, blank=True)
donate_prompt = models.TextField(max_length=500, blank=True)

def __str__(self) -> str:
return f"{self.group} - {self.iso}"
8 changes: 8 additions & 0 deletions backend/communities/groups/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
Group,
GroupImage,
GroupMember,
GroupSocialLink,
GroupText,
)
from communities.organizations.models import Organization
Expand All @@ -20,6 +21,12 @@
# MARK: Main Tables


class GroupSocialLinkSerializer(serializers.ModelSerializer[GroupSocialLink]):
class Meta:
model = GroupSocialLink
fields = "__all__"


class GroupTextSerializer(serializers.ModelSerializer[GroupText]):
class Meta:
model = GroupText
Expand All @@ -34,6 +41,7 @@ class Meta:

class GroupSerializer(serializers.ModelSerializer[Group]):
texts = GroupTextSerializer(many=True, read_only=True)
social_links = GroupSocialLinkSerializer(many=True, read_only=True)
location = LocationSerializer(read_only=True)
resources = ResourceSerializer(many=True, read_only=True)
org = GroupOrganizationSerializer(read_only=True)
Expand Down
57 changes: 55 additions & 2 deletions backend/communities/groups/views.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
# mypy: disable-error-code="override"
import json
from typing import Dict, List
from uuid import UUID

from django.db import transaction
from rest_framework import status, viewsets
from rest_framework.request import Request
from rest_framework.response import Response

from communities.groups.models import Group, GroupText
from communities.groups.serializers import GroupSerializer, GroupTextSerializer
from communities.groups.models import Group, GroupSocialLink, GroupText
from communities.groups.serializers import (
GroupSerializer,
GroupSocialLinkSerializer,
GroupTextSerializer,
)
from core.paginator import CustomPagination

# MARK: Main Tables
Expand Down Expand Up @@ -119,6 +128,50 @@ def destroy(self, request: Request, *args: str, **kwargs: int) -> Response:
)


class GroupSocialLinkViewSet(viewsets.ModelViewSet[GroupSocialLink]):
queryset = GroupSocialLink.objects.all()
serializer_class = GroupSocialLinkSerializer

def update(self, request: Request, pk: UUID | str) -> Response:
group = Group.objects.filter(id=pk).first()
if not group:
return Response(
{"error": "Group not found"}, status=status.HTTP_404_NOT_FOUND
)

data = request.data
if isinstance(data, str):
data = json.loads(data)

try:
# Use transaction.atomic() to ensure nothing is saved if an error occurs.
with transaction.atomic():
# Delete all existing social links for this group.
GroupSocialLink.objects.filter(group=group).delete()

# Create new social links from the submitted data.
social_links: List[Dict[str, str]] = []
for link_data in data:
if isinstance(link_data, dict):
social_link = GroupSocialLink.objects.create(
group=group,
order=link_data.get("order"),
link=link_data.get("link"),
label=link_data.get("label"),
)
social_links.append(social_link)

serializer = self.get_serializer(social_links, many=True)

return Response(serializer.data, status=status.HTTP_200_OK)

except Exception as e:
return Response(
{"error": f"Failed to update social links: {str(e)}"},
status=status.HTTP_400_BAD_REQUEST,
)


class GroupTextViewSet(viewsets.ModelViewSet[GroupText]):
queryset = GroupText.objects.all()
serializer_class = GroupTextSerializer
17 changes: 17 additions & 0 deletions backend/communities/organizations/factories.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
import datetime
import random

import factory

Expand All @@ -9,6 +10,7 @@
OrganizationApplicationStatus,
OrganizationImage,
OrganizationMember,
OrganizationSocialLink,
OrganizationTask,
OrganizationText,
)
Expand Down Expand Up @@ -81,6 +83,21 @@ class Meta:
is_comms = factory.Faker("boolean")


class OrganizationSocialLinkFactory(factory.django.DjangoModelFactory):
class Meta:
model = OrganizationSocialLink

link = "https://www.activist.org"
label = "social link"
order = random.randint(0, 10)
creation_date = factory.LazyFunction(
lambda: datetime.datetime.now(tz=datetime.timezone.utc)
)
last_updated = factory.LazyFunction(
lambda: datetime.datetime.now(tz=datetime.timezone.utc)
)


class OrganizationTaskFactory(factory.django.DjangoModelFactory):
class Meta:
model = OrganizationTask
Expand Down
11 changes: 10 additions & 1 deletion backend/communities/organizations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from django.db import models

from authentication import enums
from content.models import SocialLink
from utils.models import ISO_CHOICES

# MARK: Main Tables
Expand Down Expand Up @@ -43,7 +44,6 @@ class Organization(models.Model):
acceptance_date = models.DateTimeField(blank=True, null=True)
deletion_date = models.DateTimeField(blank=True, null=True)

social_links = models.ManyToManyField("content.SocialLink", blank=True)
topics = models.ManyToManyField("content.Topic", blank=True)
faqs = models.ManyToManyField("content.Faq", blank=True)
resources = models.ManyToManyField("content.Resource", blank=True)
Expand Down Expand Up @@ -99,6 +99,12 @@ def __str__(self) -> str:
return f"{self.id}"


class OrganizationSocialLink(SocialLink):
org = models.ForeignKey(
Organization, on_delete=models.CASCADE, null=True, related_name="social_links"
)


class OrganizationTask(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
org = models.ForeignKey(Organization, on_delete=models.CASCADE)
Expand All @@ -120,3 +126,6 @@ class OrganizationText(models.Model):
description = models.TextField(max_length=2500)
get_involved = models.TextField(max_length=500, blank=True)
donate_prompt = models.TextField(max_length=500, blank=True)

def __str__(self) -> str:
return f"{self.org} - {self.iso}"
10 changes: 10 additions & 0 deletions backend/communities/organizations/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
OrganizationApplication,
OrganizationImage,
OrganizationMember,
OrganizationSocialLink,
OrganizationTask,
OrganizationText,
)
Expand All @@ -22,6 +23,14 @@
# MARK: Main Tables


class OrganizationSocialLinkSerializer(
serializers.ModelSerializer[OrganizationSocialLink]
):
class Meta:
model = OrganizationSocialLink
fields = "__all__"


class OrganizationTextSerializer(serializers.ModelSerializer[OrganizationText]):
class Meta:
model = OrganizationText
Expand All @@ -30,6 +39,7 @@ class Meta:

class OrganizationSerializer(serializers.ModelSerializer[Organization]):
texts = OrganizationTextSerializer(many=True, read_only=True)
social_links = OrganizationSocialLinkSerializer(many=True, read_only=True)
location = LocationSerializer(read_only=True)
resources = ResourceSerializer(many=True, read_only=True)
groups = GroupSerializer(many=True, read_only=True)
Expand Down
51 changes: 51 additions & 0 deletions backend/communities/organizations/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
# mypy: disable-error-code="override"
import json
from typing import Dict, List
from uuid import UUID

from django.db import transaction
from django.utils import timezone
from rest_framework import status, viewsets
from rest_framework.request import Request
Expand All @@ -9,10 +14,12 @@
from communities.organizations.models import (
Organization,
OrganizationApplication,
OrganizationSocialLink,
OrganizationText,
)
from communities.organizations.serializers import (
OrganizationSerializer,
OrganizationSocialLinkSerializer,
OrganizationTextSerializer,
)
from core.paginator import CustomPagination
Expand Down Expand Up @@ -137,6 +144,50 @@ def destroy(self, request: Request, pk: str | None = None) -> Response:
)


class OrganizationSocialLinkViewSet(viewsets.ModelViewSet[OrganizationSocialLink]):
queryset = OrganizationSocialLink.objects.all()
serializer_class = OrganizationSocialLinkSerializer

def update(self, request: Request, pk: UUID | str) -> Response:
org = Organization.objects.filter(id=pk).first()
if not org:
return Response(
{"error": "Organization not found"}, status=status.HTTP_404_NOT_FOUND
)

data = request.data
if isinstance(data, str):
data = json.loads(data)

try:
# Use transaction.atomic() to ensure nothing is saved if an error occurs.
with transaction.atomic():
# Delete all existing social links for this org.
OrganizationSocialLink.objects.filter(org=org).delete()

# Create new social links from the submitted data.
social_links: List[Dict[str, str]] = []
for link_data in data:
if isinstance(link_data, dict):
social_link = OrganizationSocialLink.objects.create(
org=org,
order=link_data.get("order"),
link=link_data.get("link"),
label=link_data.get("label"),
)
social_links.append(social_link)

serializer = self.get_serializer(social_links, many=True)

return Response(serializer.data, status=status.HTTP_200_OK)

except Exception as e:
return Response(
{"error": f"Failed to update social links: {str(e)}"},
status=status.HTTP_400_BAD_REQUEST,
)


class OrganizationTextViewSet(viewsets.ModelViewSet[OrganizationText]):
queryset = OrganizationText.objects.all()
serializer_class = OrganizationTextSerializer
Loading

0 comments on commit 8fc3154

Please sign in to comment.