summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--archaeological_finds/forms.py40
-rw-r--r--archaeological_finds/ishtar_menu.py19
-rw-r--r--archaeological_finds/migrations/0037_auto_20181018_1756.py41
-rw-r--r--archaeological_finds/models_finds.py14
-rw-r--r--archaeological_finds/templates/ishtar/sheet_findbasket.html23
-rw-r--r--archaeological_finds/urls.py19
-rw-r--r--archaeological_finds/views.py54
-rw-r--r--archaeological_finds/wizards.py4
-rw-r--r--ishtar_common/models.py22
-rw-r--r--ishtar_common/views_item.py14
10 files changed, 202 insertions, 48 deletions
diff --git a/archaeological_finds/forms.py b/archaeological_finds/forms.py
index 610c309d0..370f29cad 100644
--- a/archaeological_finds/forms.py
+++ b/archaeological_finds/forms.py
@@ -26,6 +26,7 @@ import logging
from django import forms
from django.core import validators
from django.core.exceptions import PermissionDenied
+from django.db.models import Q
from django.forms.formsets import formset_factory
from django.utils.translation import ugettext_lazy as _
@@ -71,7 +72,7 @@ __all__ = [
'AdministrativeActTreatmentFileModifForm',
'DashboardTreatmentForm', 'DashboardTreatmentFileForm',
'RecordFormSelection', 'FindForm', 'DateForm', 'DatingFormSet',
- 'PreservationForm',
+ 'PreservationForm', 'FindBasketFormSelection',
'FindSelect', 'FindFormSelection', 'FindFormSelectionWarehouseModule',
'MultipleFindFormSelection', 'MultipleFindFormSelectionWarehouseModule',
'FindMultipleFormSelection', 'check_form', 'check_exist', 'check_not_exist',
@@ -918,6 +919,34 @@ class UpstreamFindFormSelection(FindFormSelection):
self.fields['resulting_pk'] = self.fields.pop('pk')
+class FindBasketSelect(CustomForm, TableSelect):
+ _model = models.FindBasket
+
+ form_admin_name = _(u"Find basket - 001 - Search")
+ form_slug = "findbasket-001-search"
+ search_vector = forms.CharField(
+ label=_(u"Full text search"), widget=widgets.SearchWidget(
+ 'archaeological-finds', 'findbasket'
+ ))
+
+ label = forms.CharField(label=_(u"Denomination"))
+
+
+class FindBasketFormSelection(CustomFormSearch):
+ SEARCH_AND_SELECT = True
+ form_label = _("Basket search")
+ associated_models = {'pk': models.FindBasket}
+ currents = {'pk': models.FindBasket}
+
+ pk = forms.IntegerField(
+ label="", required=False,
+ widget=widgets.DataTable(
+ reverse_lazy('get-findbasket'),
+ FindBasketSelect, models.FindBasket,
+ ),
+ validators=[valid_id(models.FindBasket)])
+
+
class NewFindBasketForm(forms.ModelForm):
class Meta:
model = models.FindBasket
@@ -959,7 +988,9 @@ class SelectFindBasketForm(IshtarForm):
return
self.fields['basket'].choices = [('', '--')] + [
(b.pk, unicode(b))
- for b in models.FindBasket.objects.filter(user=self.user)]
+ for b in models.FindBasket.objects.filter(
+ Q(user=self.user) | Q(shared_with=self.user)
+ )]
class DeleteFindBasketForm(SelectFindBasketForm):
@@ -979,8 +1010,9 @@ class FindBasketAddItemForm(forms.Form):
def save(self, user):
try:
- basket = models.FindBasket.objects.get(
- pk=self.cleaned_data['basket_id'], user=user)
+ basket = models.FindBasket.objects.filter(
+ Q(user=user) | Q(shared_with=user)
+ ).get(pk=self.cleaned_data['basket_id'])
item = models.Find.objects.get(
pk=self.cleaned_data['item_id'])
except models.FindBasket.DoesNotExist or\
diff --git a/archaeological_finds/ishtar_menu.py b/archaeological_finds/ishtar_menu.py
index c72e9c089..3dd98bdbd 100644
--- a/archaeological_finds/ishtar_menu.py
+++ b/archaeological_finds/ishtar_menu.py
@@ -24,7 +24,7 @@ from ishtar_common.menu_base import SectionItem, MenuItem
from archaeological_operations.models import AdministrativeAct
import models
-# be carreful: each access_controls must be relevant with check_rights in urls
+# be careful: each access_controls must be relevant with check_rights in urls
MENU_SECTIONS = [
(50,
@@ -56,22 +56,27 @@ MENU_SECTIONS = [
SectionItem(
'find_basket', _(u"Basket"),
childs=[
+ MenuItem('find_basket_search',
+ _(u"Search"),
+ model=models.FindBasket,
+ access_controls=['view_find',
+ 'view_own_find']),
MenuItem('find_basket_creation',
_(u"Creation"),
model=models.FindBasket,
- access_controls=['change_find',
- 'change_own_find']),
+ access_controls=['view_find',
+ 'view_own_find']),
MenuItem('find_basket_modification_add',
_(u"Manage items"),
model=models.FindBasket,
access_controls=[
- 'change_find',
- 'change_own_find']),
+ 'view_find',
+ 'view_own_find']),
MenuItem('find_basket_deletion',
_(u"Deletion"),
model=models.FindBasket,
- access_controls=['change_find',
- 'change_own_find']),
+ access_controls=['view_find',
+ 'view_own_find']),
]),
# MenuItem(
# 'treatment_creation', _(u"Add a treatment"),
diff --git a/archaeological_finds/migrations/0037_auto_20181018_1756.py b/archaeological_finds/migrations/0037_auto_20181018_1756.py
new file mode 100644
index 000000000..0a91b860c
--- /dev/null
+++ b/archaeological_finds/migrations/0037_auto_20181018_1756.py
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.10 on 2018-10-18 17:56
+from __future__ import unicode_literals
+
+import django.contrib.postgres.search
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ishtar_common', '0074_auto_20181017_1854'),
+ ('archaeological_finds', '0036_auto_20181017_1854'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='findbasket',
+ options={'permissions': (('view_find', 'Can view all Finds'), ('view_own_find', 'Can view own Find'))},
+ ),
+ migrations.AddField(
+ model_name='findbasket',
+ name='search_vector',
+ field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto filled at save', null=True, verbose_name='Search vector'),
+ ),
+ migrations.AddField(
+ model_name='findbasket',
+ name='shared_with',
+ field=models.ManyToManyField(blank=True, related_name='shared_findbaskets', to='ishtar_common.IshtarUser', verbose_name='Shared with'),
+ ),
+ migrations.AlterField(
+ model_name='findbasket',
+ name='user',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='findbaskets', to='ishtar_common.IshtarUser', verbose_name='Owner'),
+ ),
+ migrations.AlterUniqueTogether(
+ name='findbasket',
+ unique_together=set([]),
+ ),
+ ]
diff --git a/archaeological_finds/models_finds.py b/archaeological_finds/models_finds.py
index e0ba9206a..f6c8c6bf6 100644
--- a/archaeological_finds/models_finds.py
+++ b/archaeological_finds/models_finds.py
@@ -566,9 +566,19 @@ WEIGHT_UNIT = (('g', _(u"g")),
('kg', _(u"kg")),)
-class FindBasket(Basket):
+class FindBasket(Basket, OwnPerms):
items = models.ManyToManyField('Find', blank=True, related_name='basket')
+ class Meta:
+ permissions = (
+ ("view_find", u"Can view all Finds"),
+ ("view_own_find", u"Can view own Find"),
+ )
+
+ @classmethod
+ def get_query_owns(cls, ishtaruser):
+ return Q(user=ishtaruser)
+
class FirstBaseFindView(object):
CREATE_SQL = """
@@ -708,7 +718,7 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms,
'base_finds__find__description':
'base_finds__find__description__icontains',
'base_finds__batch': 'base_finds__batch',
- 'basket': 'basket',
+ 'basket_id': 'basket__pk',
'denomination': 'denomination',
'cached_label': 'cached_label__icontains',
'documents__image__isnull': 'documents__image__isnull',
diff --git a/archaeological_finds/templates/ishtar/sheet_findbasket.html b/archaeological_finds/templates/ishtar/sheet_findbasket.html
index b6d4ffd42..c9c442ccd 100644
--- a/archaeological_finds/templates/ishtar/sheet_findbasket.html
+++ b/archaeological_finds/templates/ishtar/sheet_findbasket.html
@@ -1,13 +1,24 @@
{% extends "ishtar/sheet.html" %}
{% load i18n window_tables window_header from_dict window_field %}
-{% block head_title %}{% trans "Find basket" %}{% endblock %}
+{% block head_title %}{% trans "Basket" %} - {{item.label}}{% endblock %}
+
+{% block toolbar %}
+{% window_nav item window_id 'show-findbasket' 'select_itemsinbasket' %}
+{% endblock %}
{% block content %}
-{% window_nav item window_id 'show-findbasket' 'select_itemsinbasket' %}
-<p class="window-refs">{{ item.label|default:"" }}</p>
-{% field "Owned by" item.user %}
-{% field "Comment" item.comment %}
-{% dynamic_table_document finds 'finds_for_ope' 'basket' item.pk 'TABLE_COLS_FOR_OPE' output %}
+<div class='row'>
+ {% field_flex "Label" item.label %}
+ {% field_flex_detail "Owned by" item.user.person %}
+ {% field_flex_multiple "Shared_with" item.shared_with %}
+ {% field_flex "Comment" item.comment %}
+</div>
+
+<h3>{% trans "Content" %}</h3>
+
+{% dynamic_table_document finds 'finds' 'basket_id' item.pk 'TABLE_COLS' output %}
+
+
{% endblock %}
diff --git a/archaeological_finds/urls.py b/archaeological_finds/urls.py
index 9629a3f38..afc9bcba7 100644
--- a/archaeological_finds/urls.py
+++ b/archaeological_finds/urls.py
@@ -43,32 +43,37 @@ urlpatterns = [
views.find_deletion_wizard), name='find_deletion'),
url(r'find_modify/(?P<pk>.+)/$',
views.find_modify, name='find_modify'),
+ url(r'get-findbasket/$', views.get_find_basket,
+ name='get-findbasket'),
+ url(r'find_basket_search/(?P<step>.+)?$',
+ check_rights(['view_find', 'view_own_find'])(
+ views.basket_search_wizard), name='find_basket_search'),
url(r'^find_basket_creation/$',
- check_rights(['change_find', 'change_own_find'])(
+ check_rights(['view_find', 'view_own_find'])(
views.NewFindBasketView.as_view()), name='new_findbasket'),
url(r'^find_basket_modification_add/$',
- check_rights(['change_find', 'change_own_find'])(
+ check_rights(['view_find', 'view_own_find'])(
views.SelectBasketForManagement.as_view()),
name='select_findbasketforadd'),
url(r'^find_basket_modification_add/(?P<pk>[0-9]+)?/$',
- check_rights(['change_find', 'change_own_find'])(
+ check_rights(['view_find', 'view_own_find'])(
views.SelectItemsInBasket.as_view()),
name='select_itemsinbasket'),
url(r'^find_basket_modification_add_item/$',
- check_rights(['change_find', 'change_own_find'])(
+ check_rights(['view_find', 'view_own_find'])(
views.FindBasketAddItemView.as_view()),
name='add_iteminbasket'),
url(r'^find_basket_modification_delete_item/(?P<basket>[0-9]+)?'
r'/(?P<find_pk>[0-9]+)?/$',
- check_rights(['change_find', 'change_own_find'])(
+ check_rights(['view_find', 'view_own_find'])(
views.FindBasketDeleteItemView.as_view()),
name='delete_iteminbasket'),
url(r'^find_basket_list/(?P<pk>[0-9]+)?/$',
- check_rights(['change_find', 'change_own_find'])(
+ check_rights(['view_find', 'view_own_find'])(
views.FindBasketListView.as_view()),
name='list_iteminbasket'),
url(r'^find_basket_deletion/$',
- check_rights(['change_find', 'change_own_find'])(
+ check_rights(['view_find', 'view_own_find'])(
views.DeleteFindBasketView.as_view()), name='delete_findbasket'),
url(r'^find-qa-bulk-update/(?P<pks>[0-9-]+)?/$',
diff --git a/archaeological_finds/views.py b/archaeological_finds/views.py
index 7855b5099..7523df145 100644
--- a/archaeological_finds/views.py
+++ b/archaeological_finds/views.py
@@ -113,6 +113,16 @@ show_findbasket = show_item(models.FindBasket, 'findbasket')
display_findbasket = display_item(models.FindBasket,
show_url='show-find/basket-')
+get_find_basket = get_item(
+ models.FindBasket, 'get_findbasket', 'findbasket',
+)
+
+basket_search_wizard = FindBasketSearch.as_view(
+ [('general-basket_search', FindBasketFormSelection)],
+ label=_(u"Basket search"),
+ url_name='find_basket_search',
+)
+
def check_preservation_module(self):
return get_current_profile().preservation
@@ -234,6 +244,16 @@ class NewFindBasketView(IshtarMixin, LoginRequiredMixin, CreateView):
return HttpResponseRedirect(self.get_success_url())
+class OwnBasket(object):
+ def get_basket(self, user, pk):
+ try:
+ return models.FindBasket.objects.filter(
+ Q(user=user) | Q(shared_with=user)
+ ).get(pk=pk)
+ except models.FindBasket.DoesNotExist:
+ raise PermissionDenied
+
+
class SelectBasketForManagement(IshtarMixin, LoginRequiredMixin, FormView):
template_name = 'ishtar/form.html'
form_class = SelectFindBasketForm
@@ -255,7 +275,8 @@ class SelectBasketForManagement(IshtarMixin, LoginRequiredMixin, FormView):
form.cleaned_data['basket']))
-class SelectItemsInBasket(IshtarMixin, LoginRequiredMixin, TemplateView):
+class SelectItemsInBasket(OwnBasket, IshtarMixin, LoginRequiredMixin,
+ TemplateView):
template_name = 'ishtar/manage_basket.html'
page_name = _(u"Manage basket")
@@ -263,11 +284,9 @@ class SelectItemsInBasket(IshtarMixin, LoginRequiredMixin, TemplateView):
context = super(SelectItemsInBasket, self).get_context_data(
*args, **kwargs)
self.user = IshtarUser.objects.get(pk=self.request.user.pk)
- try:
- self.basket = models.FindBasket.objects.get(
- pk=self.kwargs['pk'], user=self.user)
- except models.FindBasket.DoesNotExist:
- raise PermissionDenied
+ self.basket = self.get_basket(
+ user=self.user, pk=self.kwargs['pk']
+ )
context['basket'] = self.basket
if get_current_profile().warehouse:
context['form'] = MultipleFindFormSelectionWarehouseModule()
@@ -296,18 +315,17 @@ class FindBasketAddItemView(IshtarMixin, LoginRequiredMixin, FormView):
return HttpResponseRedirect(self.get_success_url(basket))
-class FindBasketListView(IshtarMixin, LoginRequiredMixin, TemplateView):
+class FindBasketListView(OwnBasket, IshtarMixin, LoginRequiredMixin,
+ TemplateView):
template_name = 'ishtar/basket_list.html'
def get_context_data(self, *args, **kwargs):
context = super(FindBasketListView, self).get_context_data(
*args, **kwargs)
self.user = IshtarUser.objects.get(pk=self.request.user.pk)
- try:
- self.basket = models.FindBasket.objects.get(
- pk=self.kwargs['pk'], user=self.user)
- except models.FindBasket.DoesNotExist:
- raise PermissionDenied
+ self.basket = self.get_basket(
+ user=self.user, pk=self.kwargs['pk']
+ )
context['basket'] = self.basket
context['item_url'] = '/'.join(
reverse(models.Find.SHOW_URL, args=[1]).split('/')[:-1])
@@ -316,7 +334,8 @@ class FindBasketListView(IshtarMixin, LoginRequiredMixin, TemplateView):
return context
-class FindBasketDeleteItemView(IshtarMixin, LoginRequiredMixin, TemplateView):
+class FindBasketDeleteItemView(OwnBasket, IshtarMixin, LoginRequiredMixin,
+ TemplateView):
template_name = 'ishtar/simple_form.html'
def get_success_url(self, basket):
@@ -330,11 +349,10 @@ class FindBasketDeleteItemView(IshtarMixin, LoginRequiredMixin, TemplateView):
pk=self.kwargs['find_pk'])
except models.Find.DoesNotExist:
raise PermissionDenied
- try:
- basket = models.FindBasket.objects.get(
- pk=self.kwargs['basket'], user=ishtaruser)
- except models.FindBasket.DoesNotExist:
- raise PermissionDenied
+
+ basket = self.get_basket(
+ user=ishtaruser, pk=self.kwargs['basket']
+ )
if not user.is_superuser and \
not ishtaruser.has_right('view_find') and \
not (ishtaruser.has_right('view_own_find')
diff --git a/archaeological_finds/wizards.py b/archaeological_finds/wizards.py
index 6486e5da1..ef51d85d1 100644
--- a/archaeological_finds/wizards.py
+++ b/archaeological_finds/wizards.py
@@ -230,3 +230,7 @@ class TreatmentFileEditAdministrativeActWizard(
def get_associated_item(self, dct):
return self.get_current_object().treatment_file
+
+
+class FindBasketSearch(SearchWizard):
+ model = models.FindBasket
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index a1bae96c2..82c754fa0 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -3408,7 +3408,7 @@ class IshtarUser(FullSearch):
return self.person.full_label()
-class Basket(models.Model):
+class Basket(FullSearch):
"""
Abstract class for a basket
Subclass must be defined with an "items" ManyToManyField
@@ -3416,8 +3416,19 @@ class Basket(models.Model):
IS_BASKET = True
label = models.CharField(_(u"Label"), max_length=1000)
comment = models.TextField(_(u"Comment"), blank=True, null=True)
- user = models.ForeignKey(IshtarUser, blank=True, null=True)
+ user = models.ForeignKey(
+ IshtarUser, blank=True, null=True, related_name='%(class)ss',
+ verbose_name=_(u"Owner"))
available = models.BooleanField(_(u"Available"), default=True)
+ shared_with = models.ManyToManyField(
+ IshtarUser, verbose_name=_(u"Shared with"), blank=True,
+ related_name='shared_%(class)ss'
+ )
+
+ TABLE_COLS = ['label', 'user']
+
+ BASE_SEARCH_VECTORS = ['label', 'comment']
+ M2M_SEARCH_VECTORS = ['items']
class Meta:
abstract = True
@@ -3426,6 +3437,13 @@ class Basket(models.Model):
def __unicode__(self):
return self.label
+ @classmethod
+ def BASE_REQUEST(cls, request):
+ if not request.user or not getattr(request.user, 'ishtaruser', None):
+ return Q(pk=None)
+ ishtaruser = request.user.ishtaruser
+ return Q(user=ishtaruser) | Q(shared_with=ishtaruser)
+
@property
def cached_label(self):
return unicode(self)
diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py
index 5cd3eb826..7c6cbc24a 100644
--- a/ishtar_common/views_item.py
+++ b/ishtar_common/views_item.py
@@ -902,7 +902,10 @@ def get_item(model, func_name, default_name, extra_request_keys=[],
else:
my_extra_request_keys = copy(extra_request_keys)
if base_request is None and hasattr(model, 'BASE_REQUEST'):
- my_base_request = copy(model.BASE_REQUEST)
+ if callable(model.BASE_REQUEST):
+ my_base_request = model.BASE_REQUEST(request)
+ else:
+ my_base_request = copy(model.BASE_REQUEST)
elif base_request is not None:
my_base_request = copy(base_request)
else:
@@ -987,7 +990,12 @@ def get_item(model, func_name, default_name, extra_request_keys=[],
request_items = dct_request_items
- dct = my_base_request
+ base_query = None
+ if isinstance(my_base_request, Q):
+ base_query = my_base_request
+ dct = {}
+ else:
+ dct = my_base_request
excluded_dct = {}
and_reqs, or_reqs = [], []
exc_and_reqs, exc_or_reqs = [], []
@@ -1099,6 +1107,8 @@ def get_item(model, func_name, default_name, extra_request_keys=[],
# print(query)
items = model.objects.filter(query)
+ if base_query:
+ items = items.filter(base_query)
if exc_query:
items = items.exclude(exc_query)