--- a/.hgignore Thu Aug 18 10:57:00 2016 +0200
+++ b/.hgignore Thu Aug 18 10:58:55 2016 +0200
@@ -7,7 +7,7 @@
^src/iconolab/static/iconolab/js/node_modules/
^src/iconolab/static/iconolab/js/iconolab-bundle/node_modules/
^src/iconolab/static/iconolab/js/iconolab-bundle/dist/
-
+\.orig$
^web/*
^\.pydevproject$
--- a/src/iconolab/models.py Thu Aug 18 10:57:00 2016 +0200
+++ b/src/iconolab/models.py Thu Aug 18 10:58:55 2016 +0200
@@ -266,6 +266,10 @@
return self.revisions.filter(state=AnnotationRevision.AWAITING).distinct().count()
@property
+ def collection(self):
+ return self.image.collection
+
+ @property
def tags(self):
return [tag.label for tag in self.current_revision.tags.all()]
--- a/src/iconolab/search_indexes/__init__.py Thu Aug 18 10:57:00 2016 +0200
+++ b/src/iconolab/search_indexes/__init__.py Thu Aug 18 10:58:55 2016 +0200
@@ -1,2 +1,2 @@
from .indexes import AnnotationIndex, ImageIndex
-__all__ = ['AnnotationIndex', 'ImageIndex']
\ No newline at end of file
+__all__ = ['AnnotationIndex', 'ImageIndex', 'RevisionSignalProcessor']
\ No newline at end of file
--- a/src/iconolab/search_indexes/forms.py Thu Aug 18 10:57:00 2016 +0200
+++ b/src/iconolab/search_indexes/forms.py Thu Aug 18 10:58:55 2016 +0200
@@ -5,42 +5,45 @@
-#def get_available_choices():
-
-def get_selected_model(type):
-
- available_models = {
- 'image': Image,
- 'annotation': Annotation
- }
-
- return available_models[type]
-
-
class IconolabSearchForm(SearchForm):
- realm = forms.ChoiceField(required=False, choices=(("image","Image"), ("annotation","Annotation")) )
+ model_type = forms.ChoiceField(required=False, choices=(("images","Image"), ("annotations","Annotation")) )
def __init__(self, *args, **kwargs):
-
+ self.collection_name = kwargs.pop("collection_name")
+ selected_model_type = kwargs.pop("model_type", None)
+
+ if selected_model_type is not None:
+ data = kwargs.get("data", None)
+ if data:
+ data = data.copy()
+ data["model_type"] = selected_model_type
+ kwargs['data'] = data
+
super(IconolabSearchForm, self).__init__(*args, **kwargs)
+
+ def no_query_found(self):
+ print("inside no_query_found")
+ return self.searchqueryset.all()
- def get_realm_queryset(self, qs, realm):
+ def get_model_type_queryset(self, qs, model_type):
- if realm == 'image':
+ if model_type == 'images':
qs = qs.models(Image).load_all_queryset(Image, Image.objects.select_related('item', 'item__metadatas'))
- if realm == 'annotation':
+ if model_type == 'annotations':
qs = qs.models(Annotation).load_all_queryset(Annotation, Annotation.objects.select_related('image', 'stats', 'current_revision', 'author'))
+
+ if self.collection_name is not None:
+ qs = qs.filter(collection = self.collection_name)
+
return qs
def search(self):
-
- selected_realm = self.cleaned_data.get("realm")
- selected_model = get_selected_model(selected_realm)
+ selected_type = self.cleaned_data.get("model_type")
#load all if q empty
qs = super(IconolabSearchForm, self).search()
if qs.count() == 0:
return qs
else:
- qs = self.get_realm_queryset(qs, selected_realm).load_all()
+ qs = self.get_model_type_queryset(qs, selected_type).load_all()
return qs
\ No newline at end of file
--- a/src/iconolab/search_indexes/indexes.py Thu Aug 18 10:57:00 2016 +0200
+++ b/src/iconolab/search_indexes/indexes.py Thu Aug 18 10:58:55 2016 +0200
@@ -5,7 +5,7 @@
class ImageIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
- collection = indexes.CharField(model_attr='collection')
+ collection = indexes.CharField(model_attr="collection")
authors = indexes.CharField(model_attr="authors")
school = indexes.CharField(model_attr="school")
designation = indexes.CharField(model_attr="designation")
@@ -31,10 +31,11 @@
##indexed field
text = indexes.CharField(document=True, use_template=True)
- title = indexes.CharField(model_attr='current_revision__title')
- description = indexes.CharField(model_attr='current_revision__description')
- tags = indexes.MultiValueField(model_attr='tags')
-
+ title = indexes.CharField(model_attr="current_revision__title")
+ description = indexes.CharField(model_attr="current_revision__description")
+ collection = indexes.CharField(model_attr="collection")
+ tags = indexes.MultiValueField(model_attr="tags")
+
## tags
def get_model(self):
return Annotation
--- a/src/iconolab/search_indexes/query.py Thu Aug 18 10:57:00 2016 +0200
+++ b/src/iconolab/search_indexes/query.py Thu Aug 18 10:58:55 2016 +0200
@@ -6,13 +6,15 @@
def __init__(self, using=None, query=None):
super(IconolabRelatedQuerySet, self).__init__(using=using, query=query)
- #def in_bulk(self, ids):
- # results = {}
- # int_ids = [ int(id) for id in ids]
- # # Ne garder que les images
- # annotations = Image.objects.filter(pk__in = int_ids)
- #
- # for annotation in annotations:
- # results[annotation.pk] = annotation
- #
- # return results
+ def in_bulk(self, ids):
+ results = {}
+ int_ids = [ int(id) for id in ids]
+ print("in_bulk")
+ print(int_ids)
+ # Ne garder que les images
+ annotations = Annotation.objects.filter(pk__in = int_ids)
+
+ for annotation in annotations:
+ results[annotation.pk] = annotation
+
+ return results
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/search_indexes/signals.py Thu Aug 18 10:58:55 2016 +0200
@@ -0,0 +1,26 @@
+from iconolab.models import Image, AnnotationRevision, Annotation
+from haystack import signals
+from django.db import models
+from iconolab.signals.handlers import revision_created, revision_accepted
+import logging
+
+logger = logging.getLogger(__name__)
+
+# update / create new index when a new revision is accepted
+# Then update images tags related to this revision
+class RevisionSignalProcessor(signals.BaseSignalProcessor):
+
+ def setup(self):
+ revision_created.connect(self.handle_revision, sender=AnnotationRevision)
+ revision_accepted.connect(self.handle_revision, sender=AnnotationRevision)
+
+ def handle_revision(self, **kwargs):
+ revision_instance = kwargs.get("instance", None)
+ if revision_instance and revision_instance.state in [AnnotationRevision.ACCEPTED]:
+ annotation = revision_instance.annotation
+ image_annotation = revision_instance.annotation.image
+ self.handle_save(Annotation, annotation)
+ self.handle_save(Image, image_annotation)##useful for tag
+
+ def teardown(self):
+ revision_accepted.disconnect(self.handle_accepted_revision, sender=AnnotationRevision)
\ No newline at end of file
--- a/src/iconolab/search_indexes/views.py Thu Aug 18 10:57:00 2016 +0200
+++ b/src/iconolab/search_indexes/views.py Thu Aug 18 10:58:55 2016 +0200
@@ -1,41 +1,98 @@
from haystack.generic_views import SearchView
+from haystack.query import RelatedSearchQuerySet
from iconolab.search_indexes.forms import IconolabSearchForm
from iconolab.search_indexes.query import IconolabRelatedQuerySet
-from django.shortcuts import HttpResponse
+from django.shortcuts import HttpResponse, redirect
+from django.core.urlresolvers import reverse
+from django.views.generic import RedirectView
+from iconolab.models import Collection
from pprint import pprint
#override Search and Related QuerySet here
class IconolabSearchView(SearchView):
form_class = IconolabSearchForm
- queryset = IconolabRelatedQuerySet()
+ queryset = RelatedSearchQuerySet()
template_name = "search/default_search.html"
paginate_by = 10
load_all = True
templates_map = {
- "image": "search/image_search.html",
- "annotation": "search/annotation_search.html"
+ "images": "search/image_search.html",
+ "annotations": "search/annotation_search.html"
}
+ def complete_url(self, url):
+ query = self.request.GET.get("q", None)
+ page = self.request.GET.get("page", None)
+
+ queryargs = []
+ query_string = ""
+
+ if query is not None:
+ queryargs.append("q=" + query)
+
+ if page is not None:
+ queryargs.append("page="+page)
+
+ if len(queryargs):
+ query_string = "&".join(queryargs)
+ url += "?" + query_string
+
+ return url
+
def get(self, request, *args, **kwargs):
- self.current_realm = request.GET['realm']
- return super(IconolabSearchView, self).get(request,*args, **kwargs)
+
+ self.model_type = request.GET.get('model_type', None)
+ collection_name = self.kwargs.get('collection_name', None)
+
+ if self.model_type is not None:
+ if collection_name is None:
+ #redirect to all_model_type
+ redirect_url = reverse('model_search', kwargs={'model_type': self.model_type})
+ return redirect(self.complete_url(redirect_url))
+ else:
+ redirect_url = reverse('collection_with_model_search', kwargs={'collection_name': collection_name, 'model_type':self.model_type})
+ return redirect(self.complete_url(redirect_url))
+ else:
+ has_error, redirectView = self.check_kwargs(**kwargs)
+ if has_error:
+ return redirectView(request)
+ return super(IconolabSearchView, self).get(request, *args, **kwargs)
+
+ def check_kwargs(self, **kwargs):
+ result = (False, None)
+ try:
+ collection_name = kwargs.get('collection_name', None)
+ if collection_name is None:
+ return result
+ collection = Collection.objects.get(name=kwargs.get('collection_name'))
+ except Collection.DoesNotExist:
+ result = (True, RedirectView.as_view(url=reverse('404error')))
+ finally:
+ return result
def get_queryset(self):
qs = super(IconolabSearchView, self).get_queryset()
+ return IconolabSearchView.queryset
return qs
+ def get_form_kwargs(self):
+ kwargs = super(IconolabSearchView, self).get_form_kwargs()
+ kwargs['collection_name'] = self.kwargs.get('collection_name', None)
+ kwargs['model_type'] = self.kwargs.get('model_type', None)
+ return kwargs
+
def get_template_names(self):
- template = IconolabSearchView.templates_map[self.current_realm]
- if template is None:
+ try :
+ model_type = self.kwargs.get('model_type', None)
+ template = IconolabSearchView.templates_map[model_type]
+ except KeyError:
template = IconolabSearchView.template_name
-
- return [template]
+ finally:
+ return [template]
def get_context_data(self, *args, **kwargs):
- print("inside get_context_data", kwargs.get("q"))
- print(kwargs.items())
context = super(IconolabSearchView, self).get_context_data(*args, **kwargs)
context['collection_name'] = self.kwargs.get('collection_name', '')
return context
\ No newline at end of file
--- a/src/iconolab/settings/dev.py.tmpl Thu Aug 18 10:57:00 2016 +0200
+++ b/src/iconolab/settings/dev.py.tmpl Thu Aug 18 10:58:55 2016 +0200
@@ -178,6 +178,9 @@
},
}
+# HAYSTACK_SIGNAL_PROCESSOR
+HAYSTACK_SIGNAL_PROCESSOR = 'iconolab.search_indexes.signals.RevisionSignalProcessor'
+
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
--- a/src/iconolab/templates/partials/header_search_form.html Thu Aug 18 10:57:00 2016 +0200
+++ b/src/iconolab/templates/partials/header_search_form.html Thu Aug 18 10:58:55 2016 +0200
@@ -1,15 +1,20 @@
-<form method="GET" action="{% url 'haystack_search' %}" class="navbar-form navbar-left" role="search">
+
+{% if collection_name %}
+ <form method="GET" action="{% url 'collection_haystack_search' collection_name %}" class="navbar-form navbar-left" role="search">
+ {% else %}
+ <form method="GET" action="{% url 'haystack_search' %}" class="navbar-form navbar-left" role="search">
+{% endif %}
<div class="form-group">
- <input name="q" type="text" class="form-control input-sm" placeholder="Trouver une image...">
+ <input name="q" type="text" class="form-control" placeholder="Trouver une image...">
</div>
<div class="form-group">
- <select name="realm" class="form-control input-sm">
- <option value="image">Images</option>
- <option value="annotation">Annotations</option>
+ <select name="model_type" class="form-control">
+ <option value="images">Images</option>
+ <option value="annotations">Annotations</option>
</select>
</div>
- <button type="submit" class="btn btn-default btn-sm"><i class="fa fa-search" aria-hidden="true"></i></button>
+ <button type="submit" class="btn btn-default">Rechercher</button>
</form>
--- a/src/iconolab/templates/search/annotation_search.html Thu Aug 18 10:57:00 2016 +0200
+++ b/src/iconolab/templates/search/annotation_search.html Thu Aug 18 10:58:55 2016 +0200
@@ -28,21 +28,26 @@
{% thumbnail result.object.image.media "400x400" crop=False as im %}
<div class="annotation-item result" style="position:relative;">
-
- <img v-el:small-image src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
+
+ <a href="{% url 'annotation_detail' result.object.collection result.object.image.image_guid result.object.annotation_guid %}">
+ <img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
<svg width="{{ im.width }}" height="{{ im.height }}" version="1.1" style="position:absolute; top:0px; left: 0px">
<g transform="matrix({% transform_matrix im_width=im.width im_height=im.height max_x=100 max_y=100 %})">
<path d="{{ result.object.current_revision.fragment|clean_path }}" opacity="0.7" fill="orange"></path>
</g>
</svg>
-
+ </a>
</div>
{% endthumbnail %}
+ <p>
+ <a href="{{ result.object.get_absolute_url }}">{{ result.object.current_revision.title }}</a>
+ </p>
- <p>
- <a href="{{ result.object.get_absolute_url }}">{{ result.object.current_revision.title }}</a>
- </p>
+ <div class="fragment-infos">
+ <a class="btn btn-default btn-xs collection-home-btn" href="{% url 'annotation_detail' result.object.collection result.object.image.image_guid result.object.annotation_guid %}"><i class="fa fa-eye"></i> Voir l'annotation</a>
+ </div>
+
{% empty %}
<p>Aucune annotation n'a été trouvée.</p>
{% endfor %}
--- a/src/iconolab/templates/search/image_search.html Thu Aug 18 10:57:00 2016 +0200
+++ b/src/iconolab/templates/search/image_search.html Thu Aug 18 10:58:55 2016 +0200
@@ -28,14 +28,17 @@
{% thumbnail result.object.media "400x400" crop=False as im %}
<div class="annotation-item result" style="position:relative;">
- <img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
+ <a href="{% url 'item_detail' result.object.collection result.object.item.item_guid %}">
+ <img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
+ </a>
</div>
{% endthumbnail %}
<p>
- <a href="{{ result.object.get_absolute_url }}">{{ result.object.title }}</a>
+ <a href="{% url 'item_detail' result.object.collection result.object.item.item_guid %}">{{ result.object.title }}</a>
<span>collection {{result.object.collection}}</span>
</p>
+ {{result.object.item}}
{% empty %}
<p>No results found.</p>
{% endfor %}
--- a/src/iconolab/templates/search/indexes/iconolab/annotation_text.txt Thu Aug 18 10:57:00 2016 +0200
+++ b/src/iconolab/templates/search/indexes/iconolab/annotation_text.txt Thu Aug 18 10:58:55 2016 +0200
@@ -3,3 +3,5 @@
{{ object.current_revision.description }}
{{ object.tags }}
+
+samedi
\ No newline at end of file
--- a/src/iconolab/templates/search/indexes/iconolab/image_text.txt Thu Aug 18 10:57:00 2016 +0200
+++ b/src/iconolab/templates/search/indexes/iconolab/image_text.txt Thu Aug 18 10:58:55 2016 +0200
@@ -9,4 +9,4 @@
{{ object.item.metadatas.discovery_context }}
{{ object.item.metadatas.conservation_location }}
-{{ object.tags }}
+{{ object.tags }}
\ No newline at end of file
--- a/src/iconolab/urls.py Thu Aug 18 10:57:00 2016 +0200
+++ b/src/iconolab/urls.py Thu Aug 18 10:58:55 2016 +0200
@@ -50,6 +50,12 @@
url(r'^comments/', include('django_comments_xtd.urls')),
url(r'^comments/annotation/post', views.comments.post_comment_iconolab, name="post_comment"),
url('^user/notifications/', include(notifications.urls, namespace='notifications')),
+
+ url(r'collections/(?P<collection_name>[a-z0-9\-]+)/search/(?P<model_type>[a-z0-9\-]+)', IconolabSearchView.as_view(), name="collection_with_model_search"),
+
+ url(r'^search/(?P<model_type>[a-z0-9\-]+)', IconolabSearchView.as_view(), name="model_search"),
+
+ url(r'collections/(?P<collection_name>[a-z0-9\-]+)/search', IconolabSearchView.as_view(), name="collection_haystack_search"),
url(r'^search/$', IconolabSearchView.as_view(), name="haystack_search"),
#url(r'^search/', include('haystack.urls'), name="search_iconolab"),
]