linkding/bookmarks/api/serializers.py
Sascha Ißbrücker 3e4f08f51b
Add user profile endpoint (#541)
* feat: Implement UserProfile serializer and add API endpoint per #457

* chore: Document API addition

* Address review comments

---------

Co-authored-by: fkulla <mail@florian.direct>
2023-10-01 21:57:32 +02:00

109 lines
3.9 KiB
Python

from django.db.models import prefetch_related_objects
from rest_framework import serializers
from rest_framework.serializers import ListSerializer
from bookmarks.models import Bookmark, Tag, build_tag_string, UserProfile
from bookmarks.services.bookmarks import create_bookmark, update_bookmark
from bookmarks.services.tags import get_or_create_tag
class TagListField(serializers.ListField):
child = serializers.CharField()
class BookmarkListSerializer(ListSerializer):
def to_representation(self, data):
# Prefetch nested relations to avoid n+1 queries
prefetch_related_objects(data, 'tags')
return super().to_representation(data)
class BookmarkSerializer(serializers.ModelSerializer):
class Meta:
model = Bookmark
fields = [
'id',
'url',
'title',
'description',
'notes',
'website_title',
'website_description',
'is_archived',
'unread',
'shared',
'tag_names',
'date_added',
'date_modified'
]
read_only_fields = [
'website_title',
'website_description',
'date_added',
'date_modified'
]
list_serializer_class = BookmarkListSerializer
# Override optional char fields to provide default value
title = serializers.CharField(required=False, allow_blank=True, default='')
description = serializers.CharField(required=False, allow_blank=True, default='')
notes = serializers.CharField(required=False, allow_blank=True, default='')
is_archived = serializers.BooleanField(required=False, default=False)
unread = serializers.BooleanField(required=False, default=False)
shared = serializers.BooleanField(required=False, default=False)
# Override readonly tag_names property to allow passing a list of tag names to create/update
tag_names = TagListField(required=False, default=[])
def create(self, validated_data):
bookmark = Bookmark()
bookmark.url = validated_data['url']
bookmark.title = validated_data['title']
bookmark.description = validated_data['description']
bookmark.notes = validated_data['notes']
bookmark.is_archived = validated_data['is_archived']
bookmark.unread = validated_data['unread']
bookmark.shared = validated_data['shared']
tag_string = build_tag_string(validated_data['tag_names'])
return create_bookmark(bookmark, tag_string, self.context['user'])
def update(self, instance: Bookmark, validated_data):
# Update fields if they were provided in the payload
for key in ['url', 'title', 'description', 'notes', 'unread', 'shared']:
if key in validated_data:
setattr(instance, key, validated_data[key])
# Use tag string from payload, or use bookmark's current tags as fallback
tag_string = build_tag_string(instance.tag_names)
if 'tag_names' in validated_data:
tag_string = build_tag_string(validated_data['tag_names'])
return update_bookmark(instance, tag_string, self.context['user'])
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ['id', 'name', 'date_added']
read_only_fields = ['date_added']
def create(self, validated_data):
return get_or_create_tag(validated_data['name'], self.context['user'])
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = [
"theme",
"bookmark_date_display",
"bookmark_link_target",
"web_archive_integration",
"tag_search",
"enable_sharing",
"enable_public_sharing",
"enable_favicons",
"display_url",
"permanent_notes",
"search_preferences",
]