Compare commits

..

10 Commits

Author SHA1 Message Date
Sascha Ißbrücker
7a14c6e2d1 Bump version 2021-02-18 07:27:31 +01:00
Sascha Ißbrücker
f7e6fbc588 Fix archive endpoints (#77) 2021-02-18 07:14:44 +01:00
Sascha Ißbrücker
778f1b2ff3 Remove legacy API (#55) 2021-02-16 04:45:21 +01:00
Sascha Ißbrücker
79dd4179d2 Add archive endpoints 2021-02-16 04:24:22 +01:00
Sascha Ißbrücker
0980e6a2b2 Update CHANGELOG.md 2021-02-15 21:11:56 +01:00
Sascha Ißbrücker
83ccf5279f Bump version 2021-02-15 21:11:03 +01:00
Sascha Ißbrücker
3bab7db023 Enhance delete links with inline confirmation (#74) 2021-02-15 21:09:03 +01:00
Sascha Ißbrücker
b6b7d3f662 Update CHANGELOG.md 2021-02-14 18:05:12 +01:00
Sascha Ißbrücker
9c51487d3b Bump version 2021-02-14 18:04:28 +01:00
Sascha Ißbrücker
c61e8ee2cd Implement archive feature (#73)
* Implement archive function (#46)

* Implement archive view (#46)

* Filter tags for archived/unarchived (#46)

* Implement archived bookmarks endpoint (#46)

* Implement archive mode for search component (#46)

* Move bookmarklet to settings (#46)

* Update modified timestamp on archive/unarchive (#46)

* Fix bookmarklet (#46)
2021-02-14 18:00:22 +01:00
11 changed files with 113 additions and 35 deletions

18
API.md
View File

@@ -59,7 +59,7 @@ Example response:
} }
``` ```
**Archived** **List Archived**
``` ```
GET /api/bookmarks/archived/ GET /api/bookmarks/archived/
@@ -121,6 +121,22 @@ Example payload:
} }
``` ```
**Archive**
```
POST /api/bookmarks/<id>/archive/
```
Archives a bookmark.
**Unarchive**
```
POST /api/bookmarks/<id>/unarchive/
```
Unarchives a bookmark.
**Delete** **Delete**
``` ```

View File

@@ -1,5 +1,21 @@
# Changelog # Changelog
## v1.3.1 (15/02/2021)
*No changelog for this release.*
---
## v1.3.0 (14/02/2021)
- [**closed**] Novice help. [#71](https://github.com/sissbruecker/linkding/issues/71)
- [**closed**] Option to create bookmarks public [#70](https://github.com/sissbruecker/linkding/issues/70)
- [**enhancement**] Show URL if title is not available [#64](https://github.com/sissbruecker/linkding/issues/64)
- [**bug**] minor ui nitpicks [#62](https://github.com/sissbruecker/linkding/issues/62)
- [**enhancement**] add an archive function [#46](https://github.com/sissbruecker/linkding/issues/46)
- [**closed**] remove non fqdn check and alert [#36](https://github.com/sissbruecker/linkding/issues/36)
- [**closed**] Add Lotus Notes links [#22](https://github.com/sissbruecker/linkding/issues/22)
---
## v1.2.1 (12/01/2021) ## v1.2.1 (12/01/2021)
- [**bug**] Bug: Two equal tags with different capitalisation lead to 500 server errors [#65](https://github.com/sissbruecker/linkding/issues/65) - [**bug**] Bug: Two equal tags with different capitalisation lead to 500 server errors [#65](https://github.com/sissbruecker/linkding/issues/65)
- [**closed**] Enhancement: category and pagination [#11](https://github.com/sissbruecker/linkding/issues/11) - [**closed**] Enhancement: category and pagination [#11](https://github.com/sissbruecker/linkding/issues/11)

View File

@@ -1,3 +1,4 @@
from django.urls import reverse
from rest_framework import viewsets, mixins, status from rest_framework import viewsets, mixins, status
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.response import Response from rest_framework.response import Response
@@ -6,6 +7,8 @@ from rest_framework.routers import DefaultRouter
from bookmarks import queries from bookmarks import queries
from bookmarks.api.serializers import BookmarkSerializer, TagSerializer from bookmarks.api.serializers import BookmarkSerializer, TagSerializer
from bookmarks.models import Bookmark, Tag from bookmarks.models import Bookmark, Tag
from bookmarks.services.bookmarks import archive_bookmark, unarchive_bookmark
from bookmarks.services.website_loader import load_website_metadata
class BookmarkViewSet(viewsets.GenericViewSet, class BookmarkViewSet(viewsets.GenericViewSet,
@@ -39,6 +42,37 @@ class BookmarkViewSet(viewsets.GenericViewSet,
data = serializer(page, many=True).data data = serializer(page, many=True).data
return self.get_paginated_response(data) return self.get_paginated_response(data)
@action(methods=['post'], detail=True)
def archive(self, request, pk):
bookmark = self.get_object()
archive_bookmark(bookmark)
return Response(status=status.HTTP_204_NO_CONTENT)
@action(methods=['post'], detail=True)
def unarchive(self, request, pk):
bookmark = self.get_object()
unarchive_bookmark(bookmark)
return Response(status=status.HTTP_204_NO_CONTENT)
@action(methods=['get'], detail=False)
def check(self, request):
url = request.GET.get('url')
bookmark = Bookmark.objects.filter(owner=request.user, url=url).first()
existing_bookmark_data = None
if bookmark is not None:
existing_bookmark_data = {
'id': bookmark.id,
'edit_url': reverse('bookmarks:edit', args=[bookmark.id])
}
metadata = load_website_metadata(url)
return Response({
'bookmark': existing_bookmark_data,
'metadata': metadata.to_dict()
}, status=status.HTTP_200_OK)
class TagViewSet(viewsets.GenericViewSet, class TagViewSet(viewsets.GenericViewSet,
mixins.ListModelMixin, mixins.ListModelMixin,

View File

@@ -56,6 +56,13 @@ ul.bookmark-list {
color: darken($gray-color, 10%); color: darken($gray-color, 10%);
} }
} }
.actions .btn-link.bm-remove-confirm {
color: $error-color;
&:hover {
text-decoration: underline;
}
}
} }
.bookmark-pagination { .bookmark-pagination {

View File

@@ -32,8 +32,7 @@
class="btn btn-link btn-sm">Archive</a> class="btn btn-link btn-sm">Archive</a>
{% endif %} {% endif %}
<a href="{% url 'bookmarks:remove' bookmark.id %}?return_url={{ return_url }}" <a href="{% url 'bookmarks:remove' bookmark.id %}?return_url={{ return_url }}"
class="btn btn-link btn-sm" class="btn btn-link btn-sm bm-remove">Remove</a>
onclick="return confirm('Do you really want to delete this bookmark?')">Remove</a>
</div> </div>
</li> </li>
{% endfor %} {% endfor %}
@@ -42,3 +41,38 @@
<div class="bookmark-pagination"> <div class="bookmark-pagination">
{% pagination bookmarks %} {% pagination bookmarks %}
</div> </div>
{# Enhance delete links to show inline confirmation #}
<script type="application/javascript">
window.addEventListener("load", function () {
const linkEls = document.querySelectorAll('.bookmark-list a.bm-remove');
function showConfirmation(linkEl) {
const cancelEl = document.createElement('span');
cancelEl.innerText = 'Cancel';
cancelEl.className = 'btn btn-link btn-sm bm-remove-confirm mr-1';
cancelEl.addEventListener('click', function() {
container.remove();
linkEl.style = '';
});
const confirmEl = document.createElement('a');
confirmEl.innerText = 'Confirm';
confirmEl.className = 'btn btn-link btn-delete btn-sm bm-remove-confirm';
confirmEl.href = linkEl.href;
const container = document.createElement('span');
container.appendChild(cancelEl);
container.appendChild(confirmEl);
linkEl.parentElement.appendChild(container);
linkEl.style = 'display: none';
}
linkEls.forEach(function (linkEl) {
linkEl.addEventListener('click', function (e) {
e.preventDefault();
showConfirmation(linkEl);
});
});
});
</script>

View File

@@ -97,7 +97,7 @@
toggleIcon(descriptionInput, true); toggleIcon(descriptionInput, true);
const websiteUrl = encodeURIComponent(urlInput.value); const websiteUrl = encodeURIComponent(urlInput.value);
const requestUrl = `{% url 'bookmarks:api.check_url' %}?url=${websiteUrl}`; const requestUrl = `{% url 'bookmarks:api-root' %}bookmarks/check?url=${websiteUrl}`;
fetch(requestUrl) fetch(requestUrl)
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {

View File

@@ -23,6 +23,5 @@ urlpatterns = [
path('settings/import', views.settings.bookmark_import, name='settings.import'), path('settings/import', views.settings.bookmark_import, name='settings.import'),
path('settings/export', views.settings.bookmark_export, name='settings.export'), path('settings/export', views.settings.bookmark_export, name='settings.export'),
# API # API
path('api/check_url', views.api.check_url, name='api.check_url'),
path('api/', include(router.urls), name='api') path('api/', include(router.urls), name='api')
] ]

View File

@@ -1,3 +1,2 @@
from .api import *
from .bookmarks import * from .bookmarks import *
from .settings import * from .settings import *

View File

@@ -1,27 +0,0 @@
from django.contrib.auth.decorators import login_required
from django.forms import model_to_dict
from django.http import JsonResponse
from django.urls import reverse
from bookmarks.services.website_loader import load_website_metadata
from bookmarks.models import Bookmark
@login_required
def check_url(request):
url = request.GET.get('url')
bookmark = Bookmark.objects.filter(owner=request.user, url=url).first()
existing_bookmark_data = None
if bookmark is not None:
existing_bookmark_data = {
'id': bookmark.id,
'edit_url': reverse('bookmarks:edit', args=[bookmark.id])
}
metadata = load_website_metadata(url)
return JsonResponse({
'bookmark': existing_bookmark_data,
'metadata': metadata.to_dict()
})

View File

@@ -1,6 +1,6 @@
{ {
"name": "linkding", "name": "linkding",
"version": "1.3.0", "version": "1.3.2",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@@ -1 +1 @@
1.3.0 1.3.2