Skip to content

Commit

Permalink
feat: highlighted_quibs endpoint and fetch for quiblet
Browse files Browse the repository at this point in the history
  • Loading branch information
moonlitgrace committed Dec 18, 2024
1 parent 02a358b commit 26df17f
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 8 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 @@ -25,3 +25,9 @@ def get_cover(self, obj):
if obj.cover:
return request.build_absolute_uri(obj.cover) if request else obj.cover
return None


class QuibHighlightedSerializer(serializers.ModelSerializer):
class Meta:
model = Quib
fields = ('cover', 'title', 'id', 'slug')
18 changes: 18 additions & 0 deletions backend/apps/quib/migrations/0004_quib_highlighted.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.1.4 on 2024-12-18 05:50

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('quib', '0003_rename_quibmodel_quib'),
]

operations = [
migrations.AddField(
model_name='quib',
name='highlighted',
field=models.BooleanField(default=False, verbose_name='highlighted'),
),
]
1 change: 1 addition & 0 deletions backend/apps/quib/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Quib(CreatedAtMixin, IsPublicMixin, ShortUUIDMixin):
verbose_name=_('quibber'),
on_delete=models.CASCADE,
)
highlighted = models.BooleanField(_('highlighted'), default=False)
title = models.CharField(_('title'), max_length=255)
slug = models.SlugField(_('slug'), editable=False, max_length=25, blank=True)
content = models.TextField(_('content'), blank=True)
Expand Down
16 changes: 14 additions & 2 deletions backend/apps/quiblet/api/v1/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from rest_framework import exceptions, response, viewsets
from rest_framework.decorators import action

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

from ...models import Quiblet
Expand All @@ -25,9 +25,11 @@ class QuibletViewSet(viewsets.ModelViewSet):

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

def get_queryset(self) -> QuerySet[Quiblet]: # pyright: ignore
Expand Down Expand Up @@ -68,6 +70,16 @@ def quibs(self, request, name=None):

return response.Response(serializer.data)

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

return response.Response(serializer.data)

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

Expand Down
108 changes: 108 additions & 0 deletions 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}/highlighted_quibs/': {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get: operations['quiblets_highlighted_quibs_list'];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
'/api/v1/quiblets/{name}/quibs/': {
parameters: {
query?: never;
Expand Down Expand Up @@ -689,6 +705,7 @@ export interface components {
*/
readonly created_at?: string;
is_public?: boolean;
highlighted?: boolean;
title?: string;
readonly slug?: string;
content?: string;
Expand Down Expand Up @@ -742,6 +759,7 @@ export interface components {
*/
readonly created_at: string;
is_public?: boolean;
highlighted?: boolean;
title: string;
readonly slug: string;
content?: string;
Expand All @@ -752,6 +770,13 @@ export interface components {
downvotes?: number[];
comments?: number[];
};
QuibHighlighted: {
/** Format: uri */
cover?: string | null;
title: string;
readonly id: string;
readonly slug: string;
};
QuibSlim: {
readonly id: string;
readonly quiblet: components['schemas']['QuibletSlim'];
Expand All @@ -761,6 +786,7 @@ export interface components {
*/
readonly created_at: string;
is_public?: boolean;
highlighted?: boolean;
title: string;
readonly slug: string;
content?: string;
Expand Down Expand Up @@ -1560,13 +1586,28 @@ export interface components {
QuibsCreateError:
| components['schemas']['QuibsCreateNonFieldErrorsErrorComponent']
| components['schemas']['QuibsCreateIsPublicErrorComponent']
| components['schemas']['QuibsCreateHighlightedErrorComponent']
| components['schemas']['QuibsCreateTitleErrorComponent']
| components['schemas']['QuibsCreateContentErrorComponent']
| components['schemas']['QuibsCreateCoverErrorComponent']
| components['schemas']['QuibsCreateQuibberErrorComponent']
| components['schemas']['QuibsCreateUpvotesErrorComponent']
| components['schemas']['QuibsCreateDownvotesErrorComponent']
| components['schemas']['QuibsCreateCommentsErrorComponent'];
QuibsCreateHighlightedErrorComponent: {
/**
* @description * `highlighted` - highlighted (enum property replaced by openapi-typescript)
* @enum {string}
*/
attr: 'highlighted';
/**
* @description * `invalid` - invalid
* * `null` - null
* @enum {string}
*/
code: 'invalid' | 'null';
detail: string;
};
QuibsCreateIsPublicErrorComponent: {
/**
* @description * `is_public` - is_public (enum property replaced by openapi-typescript)
Expand Down Expand Up @@ -1729,13 +1770,28 @@ export interface components {
QuibsPartialUpdateError:
| components['schemas']['QuibsPartialUpdateNonFieldErrorsErrorComponent']
| components['schemas']['QuibsPartialUpdateIsPublicErrorComponent']
| components['schemas']['QuibsPartialUpdateHighlightedErrorComponent']
| components['schemas']['QuibsPartialUpdateTitleErrorComponent']
| components['schemas']['QuibsPartialUpdateContentErrorComponent']
| components['schemas']['QuibsPartialUpdateCoverErrorComponent']
| components['schemas']['QuibsPartialUpdateQuibberErrorComponent']
| components['schemas']['QuibsPartialUpdateUpvotesErrorComponent']
| components['schemas']['QuibsPartialUpdateDownvotesErrorComponent']
| components['schemas']['QuibsPartialUpdateCommentsErrorComponent'];
QuibsPartialUpdateHighlightedErrorComponent: {
/**
* @description * `highlighted` - highlighted (enum property replaced by openapi-typescript)
* @enum {string}
*/
attr: 'highlighted';
/**
* @description * `invalid` - invalid
* * `null` - null
* @enum {string}
*/
code: 'invalid' | 'null';
detail: string;
};
QuibsPartialUpdateIsPublicErrorComponent: {
/**
* @description * `is_public` - is_public (enum property replaced by openapi-typescript)
Expand Down Expand Up @@ -1898,13 +1954,28 @@ export interface components {
QuibsUpdateError:
| components['schemas']['QuibsUpdateNonFieldErrorsErrorComponent']
| components['schemas']['QuibsUpdateIsPublicErrorComponent']
| components['schemas']['QuibsUpdateHighlightedErrorComponent']
| components['schemas']['QuibsUpdateTitleErrorComponent']
| components['schemas']['QuibsUpdateContentErrorComponent']
| components['schemas']['QuibsUpdateCoverErrorComponent']
| components['schemas']['QuibsUpdateQuibberErrorComponent']
| components['schemas']['QuibsUpdateUpvotesErrorComponent']
| components['schemas']['QuibsUpdateDownvotesErrorComponent']
| components['schemas']['QuibsUpdateCommentsErrorComponent'];
QuibsUpdateHighlightedErrorComponent: {
/**
* @description * `highlighted` - highlighted (enum property replaced by openapi-typescript)
* @enum {string}
*/
attr: 'highlighted';
/**
* @description * `invalid` - invalid
* * `null` - null
* @enum {string}
*/
code: 'invalid' | 'null';
detail: string;
};
QuibsUpdateIsPublicErrorComponent: {
/**
* @description * `is_public` - is_public (enum property replaced by openapi-typescript)
Expand Down Expand Up @@ -3018,6 +3089,43 @@ export interface operations {
};
};
};
quiblets_highlighted_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']['QuibHighlighted'][];
};
};
404: {
headers: {
[name: string]: unknown;
};
content: {
'application/json': components['schemas']['ErrorResponse404'];
};
};
500: {
headers: {
[name: string]: unknown;
};
content: {
'application/json': components['schemas']['ErrorResponse500'];
};
};
};
};
quiblets_quibs_list: {
parameters: {
query?: never;
Expand Down
29 changes: 24 additions & 5 deletions frontend/src/routes/(app)/q/[name]/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,34 @@ 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/', {
const {
data: quibs_data,
error: quibs_error,
response: quibs_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);
const {
data: highlighted_quibs_data,
error: highlighted_quibs_error,
response: highlighted_quibs_response
} = await client.GET('/api/v1/quiblets/{name}/highlighted_quibs/', {
params: {
path: { name: params.name }
}
});

if (
quibs_response.ok &&
quibs_data &&
highlighted_quibs_response &&
highlighted_quibs_data
) {
return { quibs: quibs_data, highlighted_quibs: highlighted_quibs_data };
} else if (quibs_error || highlighted_quibs_error) {
console.error(quibs_error, highlighted_quibs_error);
}
};
31 changes: 30 additions & 1 deletion frontend/src/routes/(app)/q/[name]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import type { PageData } from './$types';
const { data }: { data: PageData } = $props();
const { quiblet, quibs } = data;
const { quiblet, quibs, highlighted_quibs } = data;
</script>

<svelte:head>
Expand Down Expand Up @@ -42,6 +42,35 @@
</div>
<div class="h-12"></div>
<QuibsHeader />
{#if highlighted_quibs}
<div class="flex flex-col gap-4">
<div class="flex items-center gap-2">
<coreicons-shape-hash class="size-5"></coreicons-shape-hash>
<h4 class="text-sm font-medium">Highlights</h4>
</div>
<div class="grid grid-cols-3">
{#each highlighted_quibs as quib}
<div
class="relative h-40 w-full rounded-2xl bg-cover bg-center outline outline-1 outline-offset-[-1px] outline-base-content/50"
class:bg-neutral={!quib.cover}
style="background-image: url({quib.cover});"
>
<div
class="absolute inset-0 bg-gradient-to-t from-base-300/75 to-base-300/25"
></div>
<span class="absolute inset-x-0 bottom-0 p-4 font-medium text-info"
>{quib.title}</span
>
<a
href="./{quiblet?.name}/quibs/{quib.id}/{quib.slug}"
class="absolute inset-0"
aria-label={quib.title}
></a>
</div>
{/each}
</div>
</div>
{/if}
{#if quibs}
{#each quibs as quib}
<Quib {...quib} />
Expand Down

0 comments on commit 26df17f

Please sign in to comment.