mirror of
https://github.com/sissbruecker/linkding.git
synced 2025-08-07 02:48:27 +02:00
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:
@@ -19,6 +19,7 @@ class BookmarkSerializer(serializers.ModelSerializer):
|
|||||||
'description',
|
'description',
|
||||||
'website_title',
|
'website_title',
|
||||||
'website_description',
|
'website_description',
|
||||||
|
'is_archived',
|
||||||
'tag_names',
|
'tag_names',
|
||||||
'date_added',
|
'date_added',
|
||||||
'date_modified'
|
'date_modified'
|
||||||
@@ -33,6 +34,7 @@ class BookmarkSerializer(serializers.ModelSerializer):
|
|||||||
# Override optional char fields to provide default value
|
# Override optional char fields to provide default value
|
||||||
title = serializers.CharField(required=False, allow_blank=True, default='')
|
title = serializers.CharField(required=False, allow_blank=True, default='')
|
||||||
description = 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
|
# Override readonly tag_names property to allow passing a list of tag names to create/update
|
||||||
tag_names = TagListField(required=False, default=[])
|
tag_names = TagListField(required=False, default=[])
|
||||||
|
|
||||||
@@ -41,6 +43,7 @@ class BookmarkSerializer(serializers.ModelSerializer):
|
|||||||
bookmark.url = validated_data['url']
|
bookmark.url = validated_data['url']
|
||||||
bookmark.title = validated_data['title']
|
bookmark.title = validated_data['title']
|
||||||
bookmark.description = validated_data['description']
|
bookmark.description = validated_data['description']
|
||||||
|
bookmark.is_archived = validated_data['is_archived']
|
||||||
tag_string = build_tag_string(validated_data['tag_names'])
|
tag_string = build_tag_string(validated_data['tag_names'])
|
||||||
return create_bookmark(bookmark, tag_string, self.context['user'])
|
return create_bookmark(bookmark, tag_string, self.context['user'])
|
||||||
|
|
||||||
|
@@ -34,6 +34,7 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
|||||||
expectation['description'] = bookmark.description
|
expectation['description'] = bookmark.description
|
||||||
expectation['website_title'] = bookmark.website_title
|
expectation['website_title'] = bookmark.website_title
|
||||||
expectation['website_description'] = bookmark.website_description
|
expectation['website_description'] = bookmark.website_description
|
||||||
|
expectation['is_archived'] = bookmark.is_archived
|
||||||
expectation['tag_names'] = tag_names
|
expectation['tag_names'] = tag_names
|
||||||
expectation['date_added'] = bookmark.date_added.isoformat().replace('+00:00', 'Z')
|
expectation['date_added'] = bookmark.date_added.isoformat().replace('+00:00', 'Z')
|
||||||
expectation['date_modified'] = bookmark.date_modified.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/',
|
'url': 'https://example.com/',
|
||||||
'title': 'Test title',
|
'title': 'Test title',
|
||||||
'description': 'Test description',
|
'description': 'Test description',
|
||||||
|
'is_archived': False,
|
||||||
'tag_names': ['tag1', 'tag2']
|
'tag_names': ['tag1', 'tag2']
|
||||||
}
|
}
|
||||||
self.post(reverse('bookmarks:bookmark-list'), data, status.HTTP_201_CREATED)
|
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.url, data['url'])
|
||||||
self.assertEqual(bookmark.title, data['title'])
|
self.assertEqual(bookmark.title, data['title'])
|
||||||
self.assertEqual(bookmark.description, data['description'])
|
self.assertEqual(bookmark.description, data['description'])
|
||||||
|
self.assertFalse(bookmark.is_archived, data['is_archived'])
|
||||||
self.assertEqual(bookmark.tags.count(), 2)
|
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'][0]).count(), 1)
|
||||||
self.assertEqual(bookmark.tags.filter(name=data['tag_names'][1]).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)
|
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])
|
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):
|
def test_get_bookmark(self):
|
||||||
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
|
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
|
||||||
response = self.get(url, expected_status_code=status.HTTP_200_OK)
|
response = self.get(url, expected_status_code=status.HTTP_200_OK)
|
||||||
|
@@ -24,7 +24,7 @@ The following resources are available:
|
|||||||
GET /api/bookmarks/
|
GET /api/bookmarks/
|
||||||
```
|
```
|
||||||
|
|
||||||
List bookmarks.
|
List bookmarks.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ Example response:
|
|||||||
GET /api/bookmarks/archived/
|
GET /api/bookmarks/archived/
|
||||||
```
|
```
|
||||||
|
|
||||||
List archived bookmarks.
|
List archived bookmarks.
|
||||||
|
|
||||||
Parameters and response are the same as for the regular list endpoint.
|
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/
|
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:
|
Example payload:
|
||||||
|
|
||||||
@@ -92,6 +93,7 @@ Example payload:
|
|||||||
"url": "https://example.com",
|
"url": "https://example.com",
|
||||||
"title": "Example title",
|
"title": "Example title",
|
||||||
"description": "Example description",
|
"description": "Example description",
|
||||||
|
"is_archived": false,
|
||||||
"tag_names": [
|
"tag_names": [
|
||||||
"tag1",
|
"tag1",
|
||||||
"tag2"
|
"tag2"
|
||||||
@@ -201,4 +203,3 @@ Example payload:
|
|||||||
"name": "example"
|
"name": "example"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user