Allow creating archived bookmark through REST API (#268)

* Add POST archived API endpoint

* Update API docs

* Expose is_archived in existing POST endpoint

* Add test to verify bookmark not archived by default

* Fix JSON payload in API docs

Co-authored-by: Sascha Ißbrücker <sascha.issbruecker@googlemail.com>
This commit is contained in:
kenc 2022-05-26 10:10:36 +08:00 committed by GitHub
parent 2de6d8151b
commit 792a19d15e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 4 deletions

View file

@ -19,6 +19,7 @@ class BookmarkSerializer(serializers.ModelSerializer):
'description',
'website_title',
'website_description',
'is_archived',
'tag_names',
'date_added',
'date_modified'
@ -33,6 +34,7 @@ class BookmarkSerializer(serializers.ModelSerializer):
# 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='')
is_archived = 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=[])
@ -41,6 +43,7 @@ class BookmarkSerializer(serializers.ModelSerializer):
bookmark.url = validated_data['url']
bookmark.title = validated_data['title']
bookmark.description = validated_data['description']
bookmark.is_archived = validated_data['is_archived']
tag_string = build_tag_string(validated_data['tag_names'])
return create_bookmark(bookmark, tag_string, self.context['user'])

View file

@ -34,6 +34,7 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
expectation['description'] = bookmark.description
expectation['website_title'] = bookmark.website_title
expectation['website_description'] = bookmark.website_description
expectation['is_archived'] = bookmark.is_archived
expectation['tag_names'] = tag_names
expectation['date_added'] = bookmark.date_added.isoformat().replace('+00:00', 'Z')
expectation['date_modified'] = bookmark.date_modified.isoformat().replace('+00:00', 'Z')
@ -49,6 +50,7 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
'url': 'https://example.com/',
'title': 'Test title',
'description': 'Test description',
'is_archived': False,
'tag_names': ['tag1', 'tag2']
}
self.post(reverse('bookmarks:bookmark-list'), data, status.HTTP_201_CREATED)
@ -56,6 +58,7 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
self.assertEqual(bookmark.url, data['url'])
self.assertEqual(bookmark.title, data['title'])
self.assertEqual(bookmark.description, data['description'])
self.assertFalse(bookmark.is_archived, data['is_archived'])
self.assertEqual(bookmark.tags.count(), 2)
self.assertEqual(bookmark.tags.filter(name=data['tag_names'][0]).count(), 1)
self.assertEqual(bookmark.tags.filter(name=data['tag_names'][1]).count(), 1)
@ -92,6 +95,30 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
response = self.get(reverse('bookmarks:bookmark-archived') + '?q=#' + self.tag1.name, expected_status_code=status.HTTP_200_OK)
self.assertBookmarkListEqual(response.data['results'], [self.archived_bookmark1])
def test_create_archived_bookmark(self):
data = {
'url': 'https://example.com/',
'title': 'Test title',
'description': 'Test description',
'is_archived': True,
'tag_names': ['tag1', 'tag2']
}
self.post(reverse('bookmarks:bookmark-list'), data, status.HTTP_201_CREATED)
bookmark = Bookmark.objects.get(url=data['url'])
self.assertEqual(bookmark.url, data['url'])
self.assertEqual(bookmark.title, data['title'])
self.assertEqual(bookmark.description, data['description'])
self.assertTrue(bookmark.is_archived)
self.assertEqual(bookmark.tags.count(), 2)
self.assertEqual(bookmark.tags.filter(name=data['tag_names'][0]).count(), 1)
self.assertEqual(bookmark.tags.filter(name=data['tag_names'][1]).count(), 1)
def test_create_bookmark_minimal_payload_does_not_archive(self):
data = {'url': 'https://example.com/'}
self.post(reverse('bookmarks:bookmark-list'), data, status.HTTP_201_CREATED)
bookmark = Bookmark.objects.get(url=data['url'])
self.assertFalse(bookmark.is_archived)
def test_get_bookmark(self):
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
response = self.get(url, expected_status_code=status.HTTP_200_OK)

View file

@ -24,7 +24,7 @@ The following resources are available:
GET /api/bookmarks/
```
List bookmarks.
List bookmarks.
Parameters:
@ -65,7 +65,7 @@ Example response:
GET /api/bookmarks/archived/
```
List archived bookmarks.
List archived bookmarks.
Parameters and response are the same as for the regular list endpoint.
@ -83,7 +83,8 @@ Retrieves a single bookmark by ID.
POST /api/bookmarks/
```
Creates a new bookmark. Tags are simply assigned using their names.
Creates a new bookmark. Tags are simply assigned using their names. Including
`is_archived: true` saves a bookmark directly to the archive.
Example payload:
@ -92,6 +93,7 @@ Example payload:
"url": "https://example.com",
"title": "Example title",
"description": "Example description",
"is_archived": false,
"tag_names": [
"tag1",
"tag2"
@ -201,4 +203,3 @@ Example payload:
"name": "example"
}
```