Skip to content

Commit

Permalink
refactor: quiblet serializer and add related quibs
Browse files Browse the repository at this point in the history
  • Loading branch information
moonlitgrace committed Dec 18, 2024
1 parent ad9f4d0 commit 9d2c1f6
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 14 deletions.
6 changes: 6 additions & 0 deletions backend/apps/quib/api/v1/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,9 @@ class QuibSlimSerializer(serializers.ModelSerializer):
class Meta:
model = Quib
exclude = ('quibber',)

def get_cover(self, obj):
request = self.context.get('request')
if obj.cover:
return request.build_absolute_uri(obj.cover) if request else obj.cover
return None
32 changes: 24 additions & 8 deletions backend/apps/quiblet/api/v1/serializers.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
from rest_framework import exceptions, serializers
from rest_framework import serializers

from apps.user.models import Profile

from ...models import Quiblet


class QuibletSerializer(serializers.ModelSerializer):
class RangerSerializer(serializers.ModelSerializer):
name = serializers.SerializerMethodField()

class Meta:
model = Profile
fields = ('username', 'avatar', 'name')

def get_name(self, obj):
if obj.first_name or obj.last_name:
truthy_fields = filter(None, [obj.first_name, obj.last_name])
return " ".join(truthy_fields)
return None


class QuibletDetailSerializer(serializers.ModelSerializer):
rangers = RangerSerializer(many=True)

class Meta:
model = Quiblet
fields = '__all__'

def validate_name(self, name):
if Quiblet.objects.filter(name__iexact=name).exists():
raise exceptions.ValidationError(
f"Quiblet with name {name} already exists (case-insensitive)."
)

return name
class QuibletSerializer(serializers.ModelSerializer):
class Meta:
model = Quiblet
fields = '__all__'


class QuibletSlimSerializer(serializers.ModelSerializer):
Expand Down
28 changes: 25 additions & 3 deletions backend/apps/quiblet/api/v1/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,34 @@
from typing import cast

from django.db.models import QuerySet
from drf_spectacular.utils import extend_schema
from rest_framework import exceptions, response, viewsets
from rest_framework.decorators import action

from apps.quib.api.v1.serializers import QuibSlimSerializer
from common.patches.request import PatchedHttpRequest

from ...models import Quiblet
from .serializers import QuibletExistsSerializer, QuibletSerializer
from .serializers import (
QuibletDetailSerializer,
QuibletExistsSerializer,
QuibletSerializer,
)


class QuibletViewSet(viewsets.ModelViewSet):
queryset = Quiblet.objects.all()
# default serializer
serializer_class = QuibletSerializer
lookup_field = 'name'

# extra custom serializers
serializer_classes = {
'exists': QuibletExistsSerializer,
'quibs': QuibSlimSerializer,
'retrieve': QuibletDetailSerializer,
}

def get_queryset(self) -> QuerySet[Quiblet]: # pyright: ignore
return super().get_queryset()

Expand All @@ -31,8 +45,8 @@ def get_object(self) -> Quiblet: # pyright: ignore
return obj

def get_serializer_class(self): # pyright: ignore
if self.action == 'exists':
return QuibletExistsSerializer
if self.action in self.serializer_classes:
return self.serializer_classes[self.action]
return super().get_serializer_class()

@action(detail=True, methods=[HTTPMethod.GET])
Expand All @@ -46,6 +60,14 @@ def exists(self, request, name=None):

return response.Response(res)

@extend_schema(responses=QuibSlimSerializer(many=True))
@action(detail=True, methods=[HTTPMethod.GET])
def quibs(self, request, name=None):
quibs = self.get_object().quibs.all() # pyright: ignore
serializer = QuibSlimSerializer(quibs, many=True, context={'request': request})

return response.Response(serializer.data)

def perform_create(self, serializer):
patched_request = cast(PatchedHttpRequest, self.request)

Expand Down
80 changes: 79 additions & 1 deletion frontend/src/lib/clients/v1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,22 @@ export interface paths {
patch?: never;
trace?: never;
};
'/api/v1/quiblets/{name}/quibs/': {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get: operations['quiblets_quibs_list'];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
'/api/v1/quibs/': {
parameters: {
query?: never;
Expand Down Expand Up @@ -772,6 +788,24 @@ export interface components {
members?: number[];
rangers?: number[];
};
QuibletDetail: {
readonly id: number;
rangers: components['schemas']['Ranger'][];
/**
* Create at
* Format: date-time
*/
readonly created_at: string;
/** Format: uri */
avatar?: string | null;
is_public?: boolean;
name: string;
description: string;
title?: string | null;
/** Format: uri */
banner?: string | null;
members?: number[];
};
QuibletExists: {
exists: boolean;
name: string;
Expand Down Expand Up @@ -1960,6 +1994,13 @@ export interface components {
type: components['schemas']['ValidationErrorEnum'];
errors: components['schemas']['QuibsUpdateError'][];
};
Ranger: {
/** @description Required. 25 characters or fewer. Letters, digits and ./_ only. */
username: string;
/** Format: uri */
avatar?: string | null;
readonly name: string;
};
/**
* @description * `server_error` - Server Error
* @enum {string}
Expand Down Expand Up @@ -2780,7 +2821,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
'application/json': components['schemas']['Quiblet'];
'application/json': components['schemas']['QuibletDetail'];
};
};
404: {
Expand Down Expand Up @@ -2976,6 +3017,43 @@ export interface operations {
};
};
};
quiblets_quibs_list: {
parameters: {
query?: never;
header?: never;
path: {
name: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
200: {
headers: {
[name: string]: unknown;
};
content: {
'application/json': components['schemas']['QuibSlim'][];
};
};
404: {
headers: {
[name: string]: unknown;
};
content: {
'application/json': components['schemas']['ErrorResponse404'];
};
};
500: {
headers: {
[name: string]: unknown;
};
content: {
'application/json': components['schemas']['ErrorResponse500'];
};
};
};
};
quibs_list: {
parameters: {
query?: never;
Expand Down
23 changes: 23 additions & 0 deletions frontend/src/routes/(app)/q/[name]/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import type { PageData } from './$types';
import { FormatDate } from '$lib/functions/date';
import { pluralize } from '$lib/functions/pluralize';
import Avatar from '$lib/components/ui/avatar.svelte';
const { data, children }: { data: PageData; children: Snippet } = $props();
const { quiblet } = data;
Expand Down Expand Up @@ -35,5 +36,27 @@
>
</div>
</div>
<div class="divider my-0 before:h-px after:h-px"></div>
<div class="flex items-center gap-2">
<h3 class="text-sm font-medium">Rangers</h3>
<div class="tooltip tooltip-right flex" data-tip="Moderators">
<coreicons-shape-help-circle class="size-[0.85rem]"></coreicons-shape-help-circle>
</div>
</div>
{#if quiblet?.rangers}
<div class="flex flex-col gap-2">
{#each quiblet?.rangers as ranger}
<div class="flex items-center gap-2">
<Avatar src={ranger.avatar} />
<div class="flex flex-col">
<a href="/u/{ranger.username}" class="text-sm font-medium"
>u/{ranger.username}</a
>
<span class="text-xs text-base-content/75">{ranger.name}</span>
</div>
</div>
{/each}
</div>
{/if}
</div>
</div>
16 changes: 16 additions & 0 deletions frontend/src/routes/(app)/q/[name]/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import client from '$lib/clients/client';
import type { PageServerLoad } from './$types';

export const load: PageServerLoad = async ({ params }) => {
const { data, error, response } = await client.GET('/api/v1/quiblets/{name}/quibs/', {
params: {
path: { name: params.name }
}
});

if (response.ok && data) {
return { quibs: data };
} else if (error) {
console.error(error);
}
};
13 changes: 11 additions & 2 deletions frontend/src/routes/(app)/q/[name]/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<script lang="ts">
import Quib from '$lib/components/pages/home/quib.svelte';
import QuibsHeader from '$lib/components/pages/home/quibs_header.svelte';
import Avatar from '$lib/components/ui/avatar.svelte';
import { cn } from '$lib/functions/classnames';
import type { PageData } from './$types';
const { data }: { data: PageData } = $props();
const { quiblet } = data;
const { quiblet, quibs } = data;
</script>

<svelte:head>
Expand All @@ -22,7 +24,7 @@
<div class="absolute inset-x-0 -bottom-12 flex items-end justify-between px-4">
<div class="flex items-end gap-2">
<Avatar class="!size-20 outline outline-8 outline-base-300" src={quiblet?.avatar} />
<h3 class="text-3xl font-bold text-info">q/{quiblet?.name}</h3>
<h3 class="text-2xl font-bold text-info">q/{quiblet?.name}</h3>
</div>
<div class="flex items-center gap-2">
<button class="btn btn-primary h-10 px-3" aria-label="Create a Post">
Expand All @@ -38,3 +40,10 @@
</div>
</div>
</div>
<div class="h-12"></div>
<QuibsHeader />
{#if quibs}
{#each quibs as quib}
<Quib {...quib} />
{/each}
{/if}

0 comments on commit 9d2c1f6

Please sign in to comment.