Skip to content

Commit

Permalink
Expand social links to also work for groups and events + test fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewtavis committed Jan 29, 2025
1 parent 41283e0 commit ecd5d7b
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 63 deletions.
44 changes: 44 additions & 0 deletions backend/communities/groups/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 rest_framework import status, viewsets
from rest_framework.request import Request
from rest_framework.response import Response
Expand Down Expand Up @@ -127,6 +132,45 @@ 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()
Expand Down
29 changes: 16 additions & 13 deletions backend/communities/organizations/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# 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
Expand Down Expand Up @@ -146,8 +148,7 @@ class OrganizationSocialLinkViewSet(viewsets.ModelViewSet[OrganizationSocialLink
queryset = OrganizationSocialLink.objects.all()
serializer_class = OrganizationSocialLinkSerializer

def update(self, request: Request, pk: str | None = None) -> Response:
# Get the organization
def update(self, request: Request, pk: UUID | str) -> Response:
org = Organization.objects.filter(id=pk).first()
if not org:
return Response(
Expand All @@ -159,23 +160,25 @@ def update(self, request: Request, pk: str | None = None) -> Response:
data = json.loads(data)

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

# Create new social links from the submitted data
social_links = []
# Create new social links from the submitted data.
social_links: List[Dict[str, str]] = []
for link_data in data:
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)
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:
Expand Down
10 changes: 9 additions & 1 deletion backend/events/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from django.urls import include, path
from rest_framework.routers import DefaultRouter

from events.views import EventTextViewSet, EventViewSet
from events.views import EventSocialLinkViewSet, EventTextViewSet, EventViewSet

app_name = "events"

Expand All @@ -11,6 +11,14 @@
# MARK: Main Tables

router.register(prefix=r"events", viewset=EventViewSet, basename="events")

# MARK: Bridge Tables

router.register(
prefix=r"event_social_links",
viewset=EventSocialLinkViewSet,
basename="event-social-links",
)
router.register(prefix=r"event_texts", viewset=EventTextViewSet, basename="event-text")

urlpatterns = [
Expand Down
44 changes: 44 additions & 0 deletions backend/events/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
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
Expand Down Expand Up @@ -123,6 +128,45 @@ class EventSocialLinkViewSet(viewsets.ModelViewSet[EventSocialLink]):
queryset = EventSocialLink.objects.all()
serializer_class = EventSocialLinkSerializer

def update(self, request: Request, pk: UUID | str) -> Response:
event = Event.objects.filter(id=pk).first()
if not event:
return Response(
{"error": "Event 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 event.
EventSocialLink.objects.filter(event=event).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 = EventSocialLink.objects.create(
event=event,
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 EventTextViewSet(viewsets.ModelViewSet[EventText]):
queryset = EventText.objects.all()
Expand Down
51 changes: 28 additions & 23 deletions frontend/stores/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,33 +236,38 @@ export const useEventStore = defineStore("event", {

const token = localStorage.getItem("accessToken");

for (const socialLinkData of formData) {
const responseSocialLinks = await useFetch(
`${BASE_BACKEND_URL}/communities/event_social_links/`,
{
method: "PUT",
body: JSON.stringify({
link: socialLinkData.link,
label: socialLinkData.label,
order: socialLinkData.order,
event: event.id,
}),
headers: {
Authorization: `Token ${token}`,
},
}
);

const responseSocialLinksData = responseSocialLinks.data
.value as unknown as Event;
if (responseSocialLinksData) {
responses.push(true);
} else {
responses.push(false);
// Endpoint needs socialLink id's but they are not available here.
// 'update()' in the viewset 'class EventSocialLinkViewSet' handles this
// by using the event.id from the end of the URL.
const responseSocialLinks = await useFetch(
`${BASE_BACKEND_URL}/events/event_social_links/${event.id}/`,
{
method: "PUT",
// Send entire formData array/dict in order to make a single API request.
body: JSON.stringify(
formData.map((data) => ({
link: data.link,
label: data.label,
order: data.order,
}))
),
headers: {
Authorization: `Token ${token}`,
},
}
);

const responseSocialLinksData = responseSocialLinks.data
.value as unknown as Event;
if (responseSocialLinksData) {
responses.push(true);
} else {
responses.push(false);
}

if (responses.every((r) => r === true)) {
// Fetch updated event data after successful updates, to update the frontend.
await this.fetchById(event.id);
this.loading = false;
return true;
} else {
Expand Down
51 changes: 28 additions & 23 deletions frontend/stores/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,33 +228,38 @@ export const useGroupStore = defineStore("group", {

const token = localStorage.getItem("accessToken");

for (const socialLinkData of formData) {
const responseSocialLinks = await useFetch(
`${BASE_BACKEND_URL}/communities/group_social_links/`,
{
method: "PUT",
body: JSON.stringify({
link: socialLinkData.link,
label: socialLinkData.label,
order: socialLinkData.order,
group: group.id,
}),
headers: {
Authorization: `Token ${token}`,
},
}
);

const responseSocialLinksData = responseSocialLinks.data
.value as unknown as Group;
if (responseSocialLinksData) {
responses.push(true);
} else {
responses.push(false);
// Endpoint needs socialLink id's but they are not available here.
// 'update()' in the viewset 'class GroupSocialLinkViewSet' handles this
// by using the group.id from the end of the URL.
const responseSocialLinks = await useFetch(
`${BASE_BACKEND_URL}/communities/group_social_links/${group.id}/`,
{
method: "PUT",
// Send entire formData array/dict in order to make a single API request.
body: JSON.stringify(
formData.map((data) => ({
link: data.link,
label: data.label,
order: data.order,
}))
),
headers: {
Authorization: `Token ${token}`,
},
}
);

const responseSocialLinksData = responseSocialLinks.data
.value as unknown as Group;
if (responseSocialLinksData) {
responses.push(true);
} else {
responses.push(false);
}

if (responses.every((r) => r === true)) {
// Fetch updated group data after successful updates, to update the frontend.
await this.fetchById(group.id);
this.loading = false;
return true;
} else {
Expand Down
4 changes: 2 additions & 2 deletions frontend/stores/organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,8 @@ export const useOrganizationStore = defineStore("organization", {
const token = localStorage.getItem("accessToken");

// Endpoint needs socialLink id's but they are not available here.
// 'update()' in the viewset 'class OrganizationSocialLinkViewSet' handles this,
// using the org.id from the end of the URL.
// 'update()' in the viewset 'class OrganizationSocialLinkViewSet' handles this
// by using the org.id from the end of the URL.
const responseSocialLinks = await useFetch(
`${BASE_BACKEND_URL}/communities/organization_social_links/${org.id}/`,
{
Expand Down
2 changes: 1 addition & 1 deletion frontend/types/events/event.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,5 +87,5 @@ export interface EventCreateFormData {
export interface EventUpdateTextFormData {
description: string;
getInvolved: string;
getInvolvedUrl: string;
getInvolvedUrl: string | undefined;
}

0 comments on commit ecd5d7b

Please sign in to comment.