Sith/core/schemas.py

113 lines
2.9 KiB
Python
Raw Normal View History

2024-10-20 21:25:56 +00:00
from pathlib import Path
from typing import Annotated
from annotated_types import MinLen
from django.contrib.staticfiles.storage import staticfiles_storage
from django.db.models import Q
2024-12-06 16:40:18 +00:00
from django.urls import reverse
from django.utils.text import slugify
from haystack.query import SearchQuerySet
from ninja import FilterSchema, ModelSchema, Schema
from pydantic import AliasChoices, Field
2024-07-18 18:23:30 +00:00
from core.models import Group, SithFile, User
2024-07-18 18:23:30 +00:00
class SimpleUserSchema(ModelSchema):
"""A schema with the minimum amount of information to represent a user."""
class Meta:
model = User
fields = ["id", "nick_name", "first_name", "last_name"]
class UserProfileSchema(ModelSchema):
"""The necessary information to show a user profile"""
class Meta:
model = User
fields = ["id", "nick_name", "first_name", "last_name"]
display_name: str
profile_url: str
profile_pict: str
@staticmethod
def resolve_display_name(obj: User) -> str:
return obj.get_display_name()
@staticmethod
def resolve_profile_url(obj: User) -> str:
2024-12-06 16:40:18 +00:00
return reverse("core:user_profile", kwargs={"user_id": obj.pk})
@staticmethod
def resolve_profile_pict(obj: User) -> str:
if obj.profile_pict_id is None:
return staticfiles_storage.url("core/img/unknown.jpg")
2024-12-06 16:40:18 +00:00
return reverse("core:download", kwargs={"file_id": obj.profile_pict_id})
class SithFileSchema(ModelSchema):
class Meta:
model = SithFile
fields = ["id", "name"]
2024-10-20 21:25:56 +00:00
path: str
@staticmethod
def resolve_path(obj: SithFile) -> str:
return str(Path(obj.get_parent_path()) / obj.name)
class GroupSchema(ModelSchema):
class Meta:
model = Group
fields = ["id", "name"]
class UserFilterSchema(FilterSchema):
search: Annotated[str, MinLen(1)]
exclude: list[int] | None = Field(
None, validation_alias=AliasChoices("exclude", "exclude[]")
)
def filter_search(self, value: str | None) -> Q:
if not value:
return Q()
if len(value) < 3:
# For small queries, full text search isn't necessary
return (
Q(first_name__istartswith=value)
| Q(last_name__istartswith=value)
| Q(nick_name__istartswith=value)
)
return Q(
id__in=list(
SearchQuerySet()
.models(User)
.autocomplete(auto=slugify(value).replace("-", " "))
.values_list("pk", flat=True)
)
)
def filter_exclude(self, value: set[int] | None) -> Q:
if not value:
return Q()
return ~Q(id__in=value)
class MarkdownSchema(Schema):
text: str
class FamilyGodfatherSchema(Schema):
godfather: int
godchild: int
class UserFamilySchema(Schema):
"""Represent a graph of a user's family"""
users: list[UserProfileSchema]
relationships: list[FamilyGodfatherSchema]