mirror of
https://github.com/pinry/pinry.git
synced 2025-11-12 16:15:43 +01:00
263 lines
7.6 KiB
Python
263 lines
7.6 KiB
Python
from django.conf import settings
|
|
from django.db.models import Q
|
|
from rest_framework import serializers
|
|
from rest_framework.exceptions import ValidationError
|
|
from taggit.models import Tag
|
|
|
|
from core.models import Image, Board
|
|
from core.models import Pin
|
|
from django_images.models import Thumbnail
|
|
from users.serializers import UserSerializer
|
|
|
|
|
|
def filter_private_pin(request, query):
|
|
if request.user.is_authenticated:
|
|
query = query.exclude(~Q(submitter=request.user), private=True)
|
|
else:
|
|
query = query.exclude(private=True)
|
|
return query.select_related('image', 'submitter')
|
|
|
|
|
|
def filter_private_board(request, query):
|
|
if request.user.is_authenticated:
|
|
query = query.exclude(~Q(submitter=request.user), private=True)
|
|
else:
|
|
query = query.exclude(private=True)
|
|
return query
|
|
|
|
|
|
class ThumbnailSerializer(serializers.HyperlinkedModelSerializer):
|
|
class Meta:
|
|
model = Thumbnail
|
|
fields = (
|
|
"image",
|
|
"width",
|
|
"height",
|
|
)
|
|
|
|
|
|
class ImageSerializer(serializers.ModelSerializer):
|
|
class Meta:
|
|
model = Image
|
|
fields = (
|
|
"id",
|
|
"image",
|
|
"width",
|
|
"height",
|
|
"standard",
|
|
"thumbnail",
|
|
"square",
|
|
)
|
|
extra_kwargs = {
|
|
"width": {"read_only": True},
|
|
"height": {"read_only": True},
|
|
}
|
|
|
|
standard = ThumbnailSerializer(read_only=True)
|
|
thumbnail = ThumbnailSerializer(read_only=True)
|
|
square = ThumbnailSerializer(read_only=True)
|
|
|
|
def create(self, validated_data):
|
|
image = super(ImageSerializer, self).create(validated_data)
|
|
Thumbnail.objects.get_or_create_at_sizes(image, settings.IMAGE_SIZES.keys())
|
|
return image
|
|
|
|
|
|
class TagSerializer(serializers.SlugRelatedField):
|
|
class Meta:
|
|
model = Tag
|
|
fields = ("name",)
|
|
|
|
queryset = Tag.objects.all()
|
|
|
|
def __init__(self, **kwargs):
|
|
super(TagSerializer, self).__init__(
|
|
slug_field="name",
|
|
**kwargs
|
|
)
|
|
|
|
def to_internal_value(self, data):
|
|
obj, _ = self.get_queryset().get_or_create(
|
|
defaults={self.slug_field: data, "slug": data},
|
|
**{self.slug_field: data}
|
|
)
|
|
return obj
|
|
|
|
|
|
class PinSerializer(serializers.HyperlinkedModelSerializer):
|
|
class Meta:
|
|
model = Pin
|
|
fields = (
|
|
settings.DRF_URL_FIELD_NAME,
|
|
"private",
|
|
"id",
|
|
"submitter",
|
|
"url",
|
|
"description",
|
|
"referer",
|
|
"image",
|
|
"image_by_id",
|
|
"tags",
|
|
)
|
|
|
|
submitter = UserSerializer(read_only=True)
|
|
tags = TagSerializer(
|
|
many=True,
|
|
source="tag_list",
|
|
required=False,
|
|
)
|
|
image = ImageSerializer(required=False, read_only=True)
|
|
image_by_id = serializers.PrimaryKeyRelatedField(
|
|
queryset=Image.objects.all(),
|
|
write_only=True,
|
|
required=False,
|
|
)
|
|
|
|
def create(self, validated_data):
|
|
if 'url' not in validated_data and\
|
|
'image_by_id' not in validated_data:
|
|
raise ValidationError(
|
|
detail={
|
|
"url-or-image": "Either url or image_by_id is required."
|
|
},
|
|
)
|
|
|
|
submitter = self.context['request'].user
|
|
if 'url' in validated_data and validated_data['url']:
|
|
url = validated_data['url']
|
|
image = Image.objects.create_for_url(
|
|
url,
|
|
validated_data.get('referer', url),
|
|
)
|
|
else:
|
|
image = validated_data.pop("image_by_id")
|
|
tags = validated_data.pop('tag_list', [])
|
|
pin = Pin.objects.create(submitter=submitter, image=image, **validated_data)
|
|
if tags:
|
|
pin.tags.set(*tags)
|
|
return pin
|
|
|
|
def update(self, instance, validated_data):
|
|
tags = validated_data.pop('tag_list', None)
|
|
if tags:
|
|
instance.tags.set(*tags)
|
|
# change for image-id or image is not allowed
|
|
validated_data.pop('image_by_id', None)
|
|
return super(PinSerializer, self).update(instance, validated_data)
|
|
|
|
|
|
class PinIdListField(serializers.ListField):
|
|
child = serializers.IntegerField(
|
|
min_value=1
|
|
)
|
|
|
|
|
|
class BoardAutoCompleteSerializer(serializers.HyperlinkedModelSerializer):
|
|
class Meta:
|
|
model = Board
|
|
fields = (
|
|
settings.DRF_URL_FIELD_NAME,
|
|
'id',
|
|
'name',
|
|
)
|
|
|
|
|
|
class BoardSerializer(serializers.HyperlinkedModelSerializer):
|
|
class Meta:
|
|
model = Board
|
|
fields = (
|
|
settings.DRF_URL_FIELD_NAME,
|
|
"id",
|
|
"name",
|
|
"private",
|
|
"pins",
|
|
"pins_detail",
|
|
"published",
|
|
"submitter",
|
|
"pins_to_add",
|
|
"pins_to_remove",
|
|
)
|
|
read_only_fields = ('submitter', 'published')
|
|
extra_kwargs = {
|
|
'submitter': {"view_name": "users:user-detail"},
|
|
}
|
|
|
|
submitter = UserSerializer(read_only=True)
|
|
pins_detail = serializers.SerializerMethodField(
|
|
read_only=True,
|
|
)
|
|
pins = serializers.HyperlinkedRelatedField(
|
|
write_only=True,
|
|
queryset=Pin.objects.all(),
|
|
view_name="pin-detail",
|
|
many=True,
|
|
required=False,
|
|
)
|
|
pins_to_add = PinIdListField(
|
|
max_length=10,
|
|
write_only=True,
|
|
required=False,
|
|
allow_empty=False,
|
|
help_text="only patch method works for this field",
|
|
)
|
|
pins_to_remove = PinIdListField(
|
|
max_length=10,
|
|
write_only=True,
|
|
required=False,
|
|
allow_empty=False,
|
|
help_text="only patch method works for this field"
|
|
)
|
|
|
|
def get_pins_detail(self, instance):
|
|
query = instance.pins.all()
|
|
request = self.context['request']
|
|
query = filter_private_pin(request, query)
|
|
return [PinSerializer(pin, context=self.context).data for pin in query]
|
|
|
|
@staticmethod
|
|
def _get_list(pins_id):
|
|
return tuple(Pin.objects.filter(id__in=pins_id))
|
|
|
|
def update(self, instance: Board, validated_data):
|
|
pins_to_add = validated_data.pop("pins_to_add", [])
|
|
pins_to_remove = validated_data.pop("pins_to_remove", [])
|
|
board = Board.objects.filter(
|
|
submitter=instance.submitter,
|
|
name=validated_data.get('name', None)
|
|
).first()
|
|
if board and board.id != instance.id:
|
|
raise ValidationError(
|
|
detail={'name': "Board with this name already exists"}
|
|
)
|
|
instance = super(BoardSerializer, self).update(instance, validated_data)
|
|
changed = False
|
|
if pins_to_add:
|
|
changed = True
|
|
for pin in self._get_list(pins_to_add):
|
|
instance.pins.add(pin)
|
|
if pins_to_remove:
|
|
changed = True
|
|
for pin in self._get_list(pins_to_remove):
|
|
instance.pins.remove(pin)
|
|
if changed:
|
|
instance.save()
|
|
return instance
|
|
|
|
def create(self, validated_data):
|
|
validated_data.pop('pins_to_remove', None)
|
|
validated_data.pop('pins_to_add', None)
|
|
user = self.context['request'].user
|
|
if Board.objects.filter(name=validated_data['name'], submitter=user).exists():
|
|
raise ValidationError(
|
|
detail={"name": "board with this name already exists."}
|
|
)
|
|
validated_data['submitter'] = user
|
|
return super(BoardSerializer, self).create(validated_data)
|
|
|
|
|
|
class TagAutoCompleteSerializer(serializers.ModelSerializer):
|
|
|
|
class Meta:
|
|
model = Tag
|
|
fields = ('name', )
|