Edit bookmark tags

This commit is contained in:
Sascha Ißbrücker 2019-07-01 22:05:38 +02:00
parent 3b753a601f
commit 0e872c754b
6 changed files with 84 additions and 30 deletions

View File

@ -1,3 +1,5 @@
from typing import List
from django import forms from django import forms
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.db import models from django.db import models
@ -12,6 +14,20 @@ class Tag(models.Model):
return self.name return self.name
def parse_tag_string(tag_string: str, delimiter: str = ','):
if not tag_string:
return []
names = tag_string.strip().split(delimiter)
names = [name for name in names if name]
names.sort(key=str.lower)
return names
def build_tag_string(tag_names: List[str], delimiter: str = ','):
return delimiter.join(tag_names)
class Bookmark(models.Model): class Bookmark(models.Model):
url = models.URLField() url = models.URLField()
title = models.CharField(max_length=512) title = models.CharField(max_length=512)
@ -39,9 +55,10 @@ class Bookmark(models.Model):
@property @property
def tag_names(self): def tag_names(self):
tag_names = self.tag_string.strip().split(',') if self.tag_string else [] if self.tag_string:
tag_names.sort(key=str.lower) return parse_tag_string(self.tag_string)
return tag_names else:
return [tag.name for tag in self.tags.all()]
def __str__(self): def __str__(self):
return self.resolved_title + ' (' + self.url[:30] + '...)' return self.resolved_title + ' (' + self.url[:30] + '...)'
@ -53,6 +70,7 @@ auto_fill_placeholder = 'Leave empty to fill from website metadata'
class BookmarkForm(forms.ModelForm): class BookmarkForm(forms.ModelForm):
# Use URLField for URL # Use URLField for URL
url = forms.URLField() url = forms.URLField()
tag_string = forms.CharField(required=False)
# Do not require title and description in form as we fill these automatically if they are empty # Do not require title and description in form as we fill these automatically if they are empty
title = forms.CharField(max_length=512, title = forms.CharField(max_length=512,
required=False) required=False)
@ -61,4 +79,4 @@ class BookmarkForm(forms.ModelForm):
class Meta: class Meta:
model = Bookmark model = Bookmark
fields = ['url', 'title', 'description'] fields = ['url', 'tag_string', 'title', 'description']

View File

@ -3,10 +3,12 @@ from bs4 import BeautifulSoup
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.utils import timezone from django.utils import timezone
from bookmarks.models import Bookmark from bookmarks.models import Bookmark, BookmarkForm, parse_tag_string
from services.tags import get_or_create_tags
def create_bookmark(bookmark: Bookmark, current_user: User): def create_bookmark(form: BookmarkForm, current_user: User):
bookmark = form.save(commit=False)
# Update website info # Update website info
_update_website_metadata(bookmark) _update_website_metadata(bookmark)
# Set currently logged in user as owner # Set currently logged in user as owner
@ -15,11 +17,17 @@ def create_bookmark(bookmark: Bookmark, current_user: User):
bookmark.date_added = timezone.now() bookmark.date_added = timezone.now()
bookmark.date_modified = timezone.now() bookmark.date_modified = timezone.now()
bookmark.save() bookmark.save()
# Update tag list
_update_bookmark_tags(bookmark, form.data['tag_string'], current_user)
bookmark.save()
def update_bookmark(bookmark: Bookmark): def update_bookmark(form: BookmarkForm, current_user: User):
bookmark = form.save(commit=False)
# Update website info # Update website info
_update_website_metadata(bookmark) _update_website_metadata(bookmark)
# Update tag list
_update_bookmark_tags(bookmark, form.data['tag_string'], current_user)
# Update dates # Update dates
bookmark.date_modified = timezone.now() bookmark.date_modified = timezone.now()
bookmark.save() bookmark.save()
@ -42,6 +50,12 @@ def _update_website_metadata(bookmark: Bookmark):
bookmark.website_description = None bookmark.website_description = None
def _update_bookmark_tags(bookmark: Bookmark, tag_string: str, user: User):
tag_names = parse_tag_string(tag_string, ' ')
tags = get_or_create_tags(tag_names, user)
bookmark.tags.set(tags)
def load_page(url: str): def load_page(url: str):
r = requests.get(url) r = requests.get(url)
return r.text return r.text

View File

@ -3,9 +3,9 @@ from datetime import datetime
import bs4 import bs4
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.utils import timezone
from bookmarks.models import Bookmark, Tag from bookmarks.models import Bookmark, parse_tag_string
from services.tags import get_or_create_tags
def import_netscape_html(html: str, user: User): def import_netscape_html(html: str, user: User):
@ -38,9 +38,9 @@ def _import_bookmark_tag(bookmark_tag: bs4.Tag, user: User):
# Set tags # Set tags
tag_string = link_tag['tags'] tag_string = link_tag['tags']
tag_names = tag_string.strip().split(',') tag_names = parse_tag_string(tag_string)
tags = get_or_create_tags(tag_names, user)
tags = [_get_or_create_tag(tag_name, user) for tag_name in tag_names]
bookmark.tags.set(tags) bookmark.tags.set(tags)
bookmark.save() bookmark.save()
@ -50,13 +50,3 @@ def _get_or_create_bookmark(url: str, user: User):
return Bookmark.objects.get(url=url, owner=user) return Bookmark.objects.get(url=url, owner=user)
except Bookmark.DoesNotExist: except Bookmark.DoesNotExist:
return Bookmark() return Bookmark()
def _get_or_create_tag(name: str, user: User):
try:
return Tag.objects.get(name=name, owner=user)
except Tag.DoesNotExist:
tag = Tag(name=name, owner=user)
tag.date_added = timezone.now()
tag.save()
return tag

View File

@ -0,0 +1,19 @@
from typing import List
from django.contrib.auth.models import User
from django.utils import timezone
from bookmarks.models import Tag
def get_or_create_tags(tag_names: List[str], user: User):
return [get_or_create_tag(tag_name, user) for tag_name in tag_names]
def get_or_create_tag(name: str, user: User):
try:
return Tag.objects.get(name=name, owner=user)
except Tag.DoesNotExist:
tag = Tag(name=name, owner=user)
tag.date_added = timezone.now()
tag.save()
return tag

View File

@ -11,13 +11,27 @@
{% endif %} {% endif %}
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="{{ form.title.id_for_label }}" class="form-label">Title</label> <label for="{{ form.title.id_for_label }}" class="form-label">Tags</label>
{{ form.title|add_class:"form-input"|attr:"placeholder: Leave empty to fill from website metadata" }} {{ form.tag_string|add_class:"form-input" }}
<div class="form-input-hint">
Enter any number of tags separated by space and without the hash (#). If a tag does not exist it will be automatically created.
</div>
{{ form.tag_string.errors }}
</div>
<div class="form-group">
<label for="{{ form.title.id_for_label }}" class="form-label">Custom title</label>
{{ form.title|add_class:"form-input" }}
<div class="form-input-hint">
Optional, leave empty to use title from website.
</div>
{{ form.title.errors }} {{ form.title.errors }}
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="{{ form.description.id_for_label }}" class="form-label">Description</label> <label for="{{ form.description.id_for_label }}" class="form-label">Custom description</label>
{{ form.description|add_class:"form-input"|attr:"placeholder: Leave empty to fill from website metadata" }} {{ form.description|add_class:"form-input"|attr:"rows:4" }}
<div class="form-input-hint">
Optional, leave empty to use description from website.
</div>
{{ form.description.errors }} {{ form.description.errors }}
</div> </div>
<div class="form-group mt-2"> <div class="form-group mt-2">

View File

@ -4,7 +4,7 @@ from django.shortcuts import render
from django.urls import reverse from django.urls import reverse
from bookmarks import queries from bookmarks import queries
from bookmarks.models import Bookmark, BookmarkForm from bookmarks.models import Bookmark, BookmarkForm, build_tag_string
from bookmarks.services.bookmarks import create_bookmark, update_bookmark from bookmarks.services.bookmarks import create_bookmark, update_bookmark
_default_page_size = 30 _default_page_size = 30
@ -35,9 +35,8 @@ def new(request):
if request.method == 'POST': if request.method == 'POST':
form = BookmarkForm(request.POST) form = BookmarkForm(request.POST)
if form.is_valid(): if form.is_valid():
bookmark = form.save(commit=False)
current_user = request.user current_user = request.user
create_bookmark(bookmark, current_user) create_bookmark(form, current_user)
return HttpResponseRedirect(reverse('bookmarks:index')) return HttpResponseRedirect(reverse('bookmarks:index'))
else: else:
form = BookmarkForm() form = BookmarkForm()
@ -50,12 +49,12 @@ def edit(request, bookmark_id: int):
if request.method == 'POST': if request.method == 'POST':
form = BookmarkForm(request.POST, instance=bookmark) form = BookmarkForm(request.POST, instance=bookmark)
if form.is_valid(): if form.is_valid():
bookmark = form.save(commit=False) update_bookmark(form, request.user)
update_bookmark(bookmark)
return HttpResponseRedirect(reverse('bookmarks:index')) return HttpResponseRedirect(reverse('bookmarks:index'))
else: else:
form = BookmarkForm(instance=bookmark) form = BookmarkForm(instance=bookmark)
form.initial['tag_string'] = build_tag_string(bookmark.tag_names, ' ')
return render(request, 'bookmarks/edit.html', {'form': form, 'bookmark_id': bookmark_id}) return render(request, 'bookmarks/edit.html', {'form': form, 'bookmark_id': bookmark_id})