Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#23 Prevent bookmark duplicates #29

Merged
merged 4 commits into from
Sep 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions bookmarks/services/bookmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@


def create_bookmark(form: BookmarkForm, current_user: User):
# If URL is already bookmarked, then update it
existing_bookmark = Bookmark.objects.filter(owner=current_user, url=form.data['url']).first()

if existing_bookmark is not None:
update_form = BookmarkForm(data=form.data, instance=existing_bookmark)
update_bookmark(update_form, current_user)
return

bookmark = form.save(commit=False)
# Update website info
_update_website_metadata(bookmark)
Expand Down
11 changes: 11 additions & 0 deletions bookmarks/styles/bookmarks.scss
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,15 @@ ul.bookmark-list {
.form-icon.loading {
visibility: hidden;
}

.form-input-hint.bookmark-exists {
visibility: hidden;
color: $warning-color;

a {
color: $warning-color;
text-decoration: underline;
font-weight: bold;
}
}
}
2 changes: 1 addition & 1 deletion bookmarks/templates/bookmarks/edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<h2>Edit bookmark</h2>
</div>
<form action="{% url 'bookmarks:edit' bookmark_id %}" method="post" class="col-6 col-md-12" novalidate>
{% bookmark_form form all_tags %}
{% bookmark_form form all_tags bookmark_id %}
</form>
</section>
</div>
Expand Down
31 changes: 24 additions & 7 deletions bookmarks/templates/bookmarks/form.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
{{ form.url.errors }}
</div>
{% endif %}
<div class="form-input-hint bookmark-exists">
This URL is already bookmarked. You can <a href="#">edit</a> it or you can overwrite the existing bookmark by saving this form.
</div>
</div>
<div class="form-group">
<label for="{{ form.tag_string.id_for_label }}" class="form-label">Tags</label>
Expand Down Expand Up @@ -77,28 +80,42 @@
</script>
<script type="application/javascript">
/**
* Pre-fill title and description placeholders with metadata from website as soon as URL changes
* - Pre-fill title and description placeholders with metadata from website as soon as URL changes
* - Show hint if URL is already bookmarked
*/
(function init() {
const urlInput = document.getElementById('{{ form.url.id_for_label }}');
const titleInput = document.getElementById('{{ form.title.id_for_label }}');
const descriptionInput = document.getElementById('{{ form.description.id_for_label }}');
const editedBookmarkId = {{ bookmark_id }}

urlInput.addEventListener('input', updateMetadata);
urlInput.addEventListener('input', checkUrl);

function updateMetadata() {
function checkUrl() {
toggleIcon(titleInput, true);
toggleIcon(descriptionInput, true);

const websiteUrl = urlInput.value;
const requestUrl = `{% url 'bookmarks:api.website_metadata' %}?url=${websiteUrl}`;
const websiteUrl = encodeURIComponent(urlInput.value);
const requestUrl = `{% url 'bookmarks:api.check_url' %}?url=${websiteUrl}`;
fetch(requestUrl)
.then(response => response.json())
.then(metadata => {
.then(data => {
const metadata = data.metadata
titleInput.setAttribute('placeholder', metadata.title || '');
descriptionInput.setAttribute('placeholder', metadata.description || '');
toggleIcon(titleInput, false);
toggleIcon(descriptionInput, false);

// Display hint if URL is already bookmarked
const bookmarkExistsHint = document.querySelector('.form-input-hint.bookmark-exists')
const editExistingBookmarkLink = bookmarkExistsHint.querySelector('a')

if(data.bookmark && data.bookmark.id !== editedBookmarkId) {
bookmarkExistsHint.style['visibility'] = 'visible'
editExistingBookmarkLink.href = data.bookmark.edit_url
} else {
bookmarkExistsHint.style['visibility'] = 'hidden'
}
});
}

Expand All @@ -107,7 +124,7 @@
icon.style['visibility'] = show ? 'visible' : 'hidden';
}

if (urlInput.value) updateMetadata();
if (urlInput.value) checkUrl();
})();
</script>
</div>
2 changes: 1 addition & 1 deletion bookmarks/templates/bookmarks/new.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<h2>New bookmark</h2>
</div>
<form action="{% url 'bookmarks:new' %}" method="post" class="col-6 col-md-12" novalidate>
{% bookmark_form form all_tags auto_close %}
{% bookmark_form form all_tags auto_close=auto_close %}
</form>
</section>
</div>
Expand Down
5 changes: 3 additions & 2 deletions bookmarks/templatetags/bookmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@


@register.inclusion_tag('bookmarks/form.html', name='bookmark_form')
def bookmark_form(form: BookmarkForm, all_tags: List[Tag], auto_close: bool = False):
def bookmark_form(form: BookmarkForm, all_tags: List[Tag], bookmark_id: int = 0, auto_close: bool = False):

all_tag_names = [tag.name for tag in all_tags]
all_tags_string = build_tag_string(all_tag_names, ' ')

return {
'form': form,
'auto_close': auto_close,
'all_tags': all_tags_string
'all_tags': all_tags_string,
'bookmark_id': bookmark_id
}


Expand Down
2 changes: 1 addition & 1 deletion bookmarks/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@
path('settings/import', views.settings.bookmark_import, name='settings.import'),
path('settings/export', views.settings.bookmark_export, name='settings.export'),
# API
path('api/website_metadata', views.api.website_metadata, name='api.website_metadata'),
path('api/check_url', views.api.check_url, name='api.check_url'),
]
20 changes: 18 additions & 2 deletions bookmarks/views/api.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
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 website_metadata(request):
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(metadata.to_dict())

return JsonResponse({
'bookmark': existing_bookmark_data,
'metadata': metadata.to_dict()
})