# HG changeset patch # User Alexandre Segura # Date 1495031888 -7200 # Node ID 4e18e1f69db92ec23afd6279c1ca4257494fb29a # Parent bf5439a77a8dadc6ddbc4b4cfdf8b19cfdbce529 Introduce bookmarks feature. diff -r bf5439a77a8d -r 4e18e1f69db9 src/iconolab/forms/bookmarks.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/iconolab/forms/bookmarks.py Wed May 17 16:38:08 2017 +0200 @@ -0,0 +1,52 @@ +from django import forms +from iconolab.models import Bookmark, BookmarkCategory +import json, logging + +logger = logging.getLogger(__name__) + +class BookmarkForm(forms.ModelForm): + + bookmark_category = forms.ChoiceField(required=False) + bookmark_category_new = forms.CharField(required=False) + + class Meta: + model = Bookmark + fields = ('bookmark_category', 'bookmark_category_new') + + def __init__(self, *args, **kwargs): + + user = kwargs.pop('user', None) + super(BookmarkForm, self).__init__(*args, **kwargs) + + if user.is_authenticated(): + + self.user = user + + # Create the default category if not exists + try: + default_category = BookmarkCategory.objects.get(user=user, name='Favoris') + except BookmarkCategory.DoesNotExist: + default_category = BookmarkCategory( + user=user, + name='Favoris' + ) + default_category.save() + + bookmark_categories = BookmarkCategory.objects.filter(user=user).all() + choices = [(bookmark_category.id, bookmark_category.name) for bookmark_category in bookmark_categories] + for choice in choices: + self.fields['bookmark_category'].choices.append(choice) + + def clean(self, *args, **kwargs): + cleaned_data = super(BookmarkForm, self).clean(*args, **kwargs) + + if cleaned_data['bookmark_category_new']: + bookmark_category = BookmarkCategory( + user=self.user, + name=cleaned_data['bookmark_category_new'] + ) + bookmark_category.save() + else: + bookmark_category = BookmarkCategory.objects.get(id=cleaned_data['bookmark_category']) + + cleaned_data['category'] = bookmark_category diff -r bf5439a77a8d -r 4e18e1f69db9 src/iconolab/migrations/0022_auto_20170516_1538.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/iconolab/migrations/0022_auto_20170516_1538.py Wed May 17 16:38:08 2017 +0200 @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-05-16 15:38 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('iconolab', '0021_folder_display_image'), + ] + + operations = [ + migrations.CreateModel( + name='Bookmark', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name='BookmarkCategory', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('created', models.DateTimeField(auto_now_add=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.AddField( + model_name='bookmark', + name='category', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='iconolab.BookmarkCategory'), + ), + migrations.AddField( + model_name='bookmark', + name='image', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='iconolab.Image'), + ), + ] diff -r bf5439a77a8d -r 4e18e1f69db9 src/iconolab/models.py --- a/src/iconolab/models.py Tue May 16 12:36:38 2017 +0200 +++ b/src/iconolab/models.py Wed May 17 16:38:08 2017 +0200 @@ -1004,3 +1004,14 @@ def __str__(self): return "profile:" + self.user.username + + +class BookmarkCategory(models.Model): + user = models.ForeignKey(User) + name = models.CharField(max_length=255) + created = models.DateTimeField(auto_now_add=True) + +class Bookmark(models.Model): + category = models.ForeignKey(BookmarkCategory) + image = models.ForeignKey(Image) + created = models.DateTimeField(auto_now_add=True) diff -r bf5439a77a8d -r 4e18e1f69db9 src/iconolab/templates/iconolab/collection_home.html --- a/src/iconolab/templates/iconolab/collection_home.html Tue May 16 12:36:38 2017 +0200 +++ b/src/iconolab/templates/iconolab/collection_home.html Wed May 17 16:38:08 2017 +0200 @@ -139,4 +139,83 @@ + {% endblock %} + +{% block footer_js %} + +{% endblock %} diff -r bf5439a77a8d -r 4e18e1f69db9 src/iconolab/templates/iconolab/user_base.html --- a/src/iconolab/templates/iconolab/user_base.html Tue May 16 12:36:38 2017 +0200 +++ b/src/iconolab/templates/iconolab/user_base.html Wed May 17 16:38:08 2017 +0200 @@ -17,6 +17,10 @@ class="list-group-item {% if request.resolver_match.url_name == 'user_annotations' %}active{% endif%}"> Annotations + + Favoris +
{% if profile_user == request.user %} diff -r bf5439a77a8d -r 4e18e1f69db9 src/iconolab/templates/iconolab/user_bookmarks.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/iconolab/templates/iconolab/user_bookmarks.html Wed May 17 16:38:08 2017 +0200 @@ -0,0 +1,61 @@ +{% extends 'iconolab/user_base.html' %} + +{% load thumbnail %} +{% load humanize %} + +{% block user_content %} + + + + + + + + + + {% for bookmark in bookmarks %} + + + + + + + + {% endfor %} + +
CollectionCatégorie
+ {% thumbnail bookmark.image.media "100x100" crop=False as thumbnail %} + + + + {% endthumbnail %} + {{ bookmark.image.item.collection.verbose_name }} + {% if request.user.is_authenticated and profile_user == request.user %} +
+ {% csrf_token %} + +
+ {% else %} + {{ bookmark.category.name }} + {% endif %} +
{{ bookmark.created|naturaltime }} + {% if request.user.is_authenticated and profile_user == request.user %} +
+ {% csrf_token %} + +
+ {% endif %} +
+{% endblock %} + +{% block footer_js %} + +{% endblock %} diff -r bf5439a77a8d -r 4e18e1f69db9 src/iconolab/templates/partials/item_images_preview.html --- a/src/iconolab/templates/partials/item_images_preview.html Tue May 16 12:36:38 2017 +0200 +++ b/src/iconolab/templates/partials/item_images_preview.html Wed May 17 16:38:08 2017 +0200 @@ -10,6 +10,11 @@ {% endthumbnail %} +
{% if item.images.count > 1 %} diff -r bf5439a77a8d -r 4e18e1f69db9 src/iconolab/urls.py --- a/src/iconolab/urls.py Tue May 16 12:36:38 2017 +0200 +++ b/src/iconolab/urls.py Wed May 17 16:38:08 2017 +0200 @@ -36,6 +36,7 @@ url(r'^collections/(?P[a-z0-9\-]+)/items/?$', django_views.generic.RedirectView.as_view(pattern_name="collection_home")), url(r'^collections/(?P[a-z0-9\-]+)/images/?$', django_views.generic.RedirectView.as_view(pattern_name="collection_home")), url(r'^collections/(?P[a-z0-9\-]+)/images/(?P[^/]+)$', views.objects.ShowImageView.as_view(), name='image_detail'), + url(r'^collections/(?P[a-z0-9\-]+)/images/(?P[^/]+)/bookmark/?$', views.objects.BookmarkImageView.as_view(), name='image_bookmark'), url(r'^collections/(?P[a-z0-9\-]+)/images/(?P[^/]+)/annotations/?$', django_views.generic.RedirectView.as_view(pattern_name="image_detail")), url(r'^collections/(?P[a-z0-9\-]+)/images/(?P[^/]+)/annotations/create$', login_required(views.objects.CreateAnnotationView.as_view()), name='annotation_create'), url(r'^collections/(?P[a-z0-9\-]+)/images/(?P[^/]+)/annotations/(?P[^/]+)/?$', views.objects.ShowAnnotationView.as_view(), name='annotation_detail'), @@ -53,6 +54,9 @@ url(r'^user/(?P[a-z0-9\-]+)/commented/?$', views.userpages.UserCommentedView.as_view(), name="user_commented"), url(r'^user/(?P[a-z0-9\-]+)/contributed/?$', views.userpages.UserContributedView.as_view(), name="user_contributed"), url(r'^user/(?P[a-z0-9\-]+)/annotations/?$', views.userpages.UserAnnotationsView.as_view(), name="user_annotations"), + url(r'^user/(?P[a-z0-9\-]+)/bookmarks/?$', views.userpages.UserBookmarksView.as_view(), name="user_bookmarks"), + url(r'^bookmarks/(?P[0-9]+)/delete/?$', views.userpages.BookmarkDeleteView.as_view(), name="bookmark_delete"), + url(r'^bookmarks/(?P[0-9]+)/edit/?$', views.userpages.BookmarkEditView.as_view(), name="bookmark_edit"), url(r'^user/adminpanel/(?P[a-z0-9\-]+)/$', views.userpages.UserCollectionAdminView.as_view(), name="user_admin_panel"), url(r'^user/notifications/all/?$', login_required(views.userpages.UserNotificationsView.as_view()), name="user_notifications"), diff -r bf5439a77a8d -r 4e18e1f69db9 src/iconolab/views/objects.py --- a/src/iconolab/views/objects.py Tue May 16 12:36:38 2017 +0200 +++ b/src/iconolab/views/objects.py Wed May 17 16:38:08 2017 +0200 @@ -13,8 +13,9 @@ from django.contrib.sites.models import Site from django.conf import settings from notifications.models import Notification -from iconolab.models import Annotation, AnnotationRevision, Collection, Folder, Item, Image, IconolabComment, MetaCategory, MetaCategoryInfo +from iconolab.models import Annotation, AnnotationRevision, Collection, Folder, Item, Image, IconolabComment, MetaCategory, MetaCategoryInfo, BookmarkCategory, Bookmark from iconolab.forms.annotations import AnnotationRevisionForm +from iconolab.forms.bookmarks import BookmarkForm from iconolab.serializers import AnnotationRevisionSerializer import logging @@ -309,6 +310,8 @@ +"&revised_perpage="+str(revised_per_page) ) + context['bookmark_form'] = BookmarkForm(user=request.user) + return render(request, 'iconolab/collection_home.html', context) @@ -410,6 +413,30 @@ context['form'] = AnnotationRevisionForm() return render(request, 'iconolab/detail_image.html', context) +class BookmarkImageView(View, ContextMixin, IconolabObjectView): + def post(self, request, *args, **kwargs): + success, result = self.check_kwargs(kwargs) + if success: + (collection, image) = result + else: + return result(request) + + context = super(BookmarkImageView, self).get_context_data(**kwargs) + + bookmark_form = BookmarkForm(request.POST, user=request.user) + if bookmark_form.is_valid(): + bookmark = Bookmark( + image=image, + category=bookmark_form.cleaned_data['category'] + ) + bookmark.save() + + context['bookmark_form'] = bookmark_form + + redirect_url = reverse('collection_home', kwargs={'collection_name': self.kwargs.get('collection_name', '')}) + + return redirect(redirect_url) + class CreateAnnotationView(View, ContextMixin, IconolabObjectView): """ View that displays annotation forms and handles annotation creation diff -r bf5439a77a8d -r 4e18e1f69db9 src/iconolab/views/userpages.py --- a/src/iconolab/views/userpages.py Tue May 16 12:36:38 2017 +0200 +++ b/src/iconolab/views/userpages.py Wed May 17 16:38:08 2017 +0200 @@ -9,7 +9,7 @@ from django.conf import settings from django.urls import reverse from notifications.models import Notification -from iconolab.models import Collection, Annotation, AnnotationRevision, IconolabComment, Image, MetaCategoriesCountInfo +from iconolab.models import Collection, Annotation, AnnotationRevision, IconolabComment, Image, MetaCategoriesCountInfo, Bookmark, BookmarkCategory from iconolab.auth.forms import UserForm from itertools import chain from uuid import UUID @@ -113,6 +113,61 @@ context['profile_user'] = profile_user return render(request, 'iconolab/user_annotations.html', context) +class UserBookmarksView(DetailView): + + model = User + slug_field = 'username' + + def get_context_data(self, **kwargs): + context = super(UserBookmarksView, self).get_context_data(**kwargs) + return context + + def get(self, request, *args, **kwargs): + self.object = self.get_object() + profile_user = self.object + context = self.get_context_data() + + context['profile_user'] = profile_user + context['bookmarks'] = Bookmark.objects.filter(category__user=profile_user).all() + + if (request.user.is_authenticated()): + context['bookmark_categories'] = BookmarkCategory.objects.filter(user=request.user).all() + + return render(request, 'iconolab/user_bookmarks.html', context) + +class BookmarkDeleteView(View): + + def post(self, request, *args, **kwargs): + + if request.user.is_authenticated(): + bookmark_id = kwargs.get('bookmark') + bookmark = Bookmark.objects.get(id=bookmark_id) + if bookmark.category.user == request.user: + bookmark.delete() + else: + return redirect(reverse('home')) + else: + return redirect(reverse('home')) + + return redirect(reverse('user_bookmarks', kwargs={'slug': request.user.username})) + +class BookmarkEditView(View): + + def post(self, request, *args, **kwargs): + + if request.user.is_authenticated(): + bookmark_id = kwargs.get('bookmark') + bookmark = Bookmark.objects.get(id=bookmark_id) + if bookmark.category.user == request.user: + bookmark.category = BookmarkCategory.objects.get(id=request.POST.get('category')) + bookmark.save() + else: + return redirect(reverse('home')) + else: + return redirect(reverse('home')) + + return redirect(reverse('user_bookmarks', kwargs={'slug': request.user.username})) + class UserCommentedView(DetailView): """ View that displays the full paginated list of annotations on which the considered user has commented diff -r bf5439a77a8d -r 4e18e1f69db9 src_js/iconolab-bundle/src/iconolab.scss --- a/src_js/iconolab-bundle/src/iconolab.scss Tue May 16 12:36:38 2017 +0200 +++ b/src_js/iconolab-bundle/src/iconolab.scss Wed May 17 16:38:08 2017 +0200 @@ -40,9 +40,20 @@ } } .main-image { + position: relative; a { display: block; } + .bookmark { + color: #E67E22; + position: absolute; + top: 10px; + right: 10px; + &:hover, + &:active { + color: darken(#E67E22, 10%); + } + } } .item-image-stats { display: flex;