summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2018-06-04 16:41:41 +0200
committerÉtienne Loks <etienne.loks@iggdrasil.net>2018-06-12 09:57:24 +0200
commite7418c19b122c5ac0505ad2be5350068d3bf6f6b (patch)
tree735cd414c9dd45334a08f5e8c93224257548aa53 /ishtar_common
parent202fb132953d115c2b1983f5f50d2f4b62bb9d5d (diff)
downloadIshtar-e7418c19b122c5ac0505ad2be5350068d3bf6f6b.tar.bz2
Ishtar-e7418c19b122c5ac0505ad2be5350068d3bf6f6b.zip
Rebase migrations
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/forms_common.py72
-rw-r--r--ishtar_common/ishtar_menu.py15
-rw-r--r--ishtar_common/migrations/0056_auto_20180601_1555.py2
-rw-r--r--ishtar_common/migrations/0057_document_cache_related_label.py20
-rw-r--r--ishtar_common/models.py41
-rw-r--r--ishtar_common/templates/ishtar/sheet_document.html (renamed from ishtar_common/templates/ishtar/sheet_source.html)32
-rw-r--r--ishtar_common/templates/ishtar/sheet_document_pdf.html14
-rw-r--r--ishtar_common/templates/ishtar/sheet_document_window.html3
-rw-r--r--ishtar_common/urls.py23
-rw-r--r--ishtar_common/utils.py63
-rw-r--r--ishtar_common/views.py43
-rw-r--r--ishtar_common/wizards.py49
12 files changed, 287 insertions, 90 deletions
diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py
index 854fe2a71..0473d19b6 100644
--- a/ishtar_common/forms_common.py
+++ b/ishtar_common/forms_common.py
@@ -1052,27 +1052,35 @@ def get_image_help():
'height': settings.IMAGE_MAX_SIZE[1]}
-######################
-# Sources management #
-######################
-class SourceForm(CustomForm, ManageOldType):
+#######################
+# Document management #
+#######################
+
+
+class DocumentForm(CustomForm, ManageOldType):
form_label = _(u"Documentation informations")
- form_admin_name = _("Source - General")
+ form_admin_name = _("Document - General")
file_upload = True
associated_models = {'source_type': models.SourceType}
- title = forms.CharField(label=_(u"Title"),
+ title = forms.CharField(label=_(u"Title"), required=False,
validators=[validators.MaxLengthValidator(200)])
- source_type = forms.ChoiceField(label=_(u"Source type"), choices=[])
+ source_type = forms.ChoiceField(label=_(u"Source type"), choices=[],
+ required=False)
+ image = forms.ImageField(
+ label=_(u"Image"), help_text=mark_safe(get_image_help()),
+ max_length=255, required=False, widget=widgets.ImageFileInput())
+ associated_file = forms.FileField(
+ label=_(u"File"), max_length=255, required=False)
+ associated_url = forms.URLField(
+ max_length=1000, required=False,
+ label=_(u"Numerical ressource (web address)"))
reference = forms.CharField(
label=_(u"Reference"),
validators=[validators.MaxLengthValidator(100)], required=False)
internal_reference = forms.CharField(
label=_(u"Internal reference"),
validators=[validators.MaxLengthValidator(100)], required=False)
- associated_url = forms.URLField(
- max_length=1000, required=False,
- label=_(u"Numerical ressource (web address)"))
receipt_date = forms.DateField(label=_(u"Receipt date"), required=False,
widget=DatePicker)
creation_date = forms.DateField(label=_(u"Creation date"), required=False,
@@ -1089,16 +1097,24 @@ class SourceForm(CustomForm, ManageOldType):
required=False)
duplicate = forms.BooleanField(label=_(u"Has a duplicate"),
required=False)
- image = forms.ImageField(
- label=_(u"Image"), help_text=mark_safe(get_image_help()),
- max_length=255, required=False, widget=widgets.ImageFileInput())
TYPES = [
FieldType('source_type', models.SourceType),
]
+ def clean(self):
+ cleaned_data = self.cleaned_data
+ if not cleaned_data.get('title', None) and \
+ not cleaned_data.get('image', None) and \
+ not cleaned_data.get('associated_file', None) and \
+ not cleaned_data.get('associated_url', None):
+ raise forms.ValidationError(_(u"You should at least fill one of "
+ u"this field: title, url, image or "
+ u"file."))
+ return cleaned_data
+
-class SourceSelect(TableSelect):
+class DocumentSelect(TableSelect):
search_vector = forms.CharField(label=_(u"Full text search"),
widget=widgets.SearchWidget)
authors = forms.IntegerField(
@@ -1118,10 +1134,30 @@ class SourceSelect(TableSelect):
label=_(u"Additional informations"))
duplicate = forms.NullBooleanField(label=_(u"Has a duplicate"))
- def __init__(self, *args, **kwargs):
- super(SourceSelect, self).__init__(*args, **kwargs)
- self.fields['source_type'].choices = models.SourceType.get_types()
- self.fields['source_type'].help_text = models.SourceType.get_help()
+ TYPES = [
+ FieldType('source_type', models.SourceType),
+ ]
+
+
+class DocumentFormSelection(forms.Form):
+ SEARCH_AND_SELECT = True
+ form_label = _(u"Document search")
+ associated_models = {'pk': models.Document}
+ currents = {'pk': models.Document}
+
+ pk = forms.IntegerField(
+ label="", required=False,
+ widget=widgets.DataTable(
+ reverse_lazy('get-document'), DocumentSelect,
+ models.Document,
+ ),
+ validators=[models.valid_id(models.Document)])
+
+ def clean(self):
+ cleaned_data = self.cleaned_data
+ if 'pk' not in cleaned_data or not cleaned_data['pk']:
+ raise forms.ValidationError(_(u"You should select an item."))
+ return cleaned_data
class SourceDeletionForm(FinalForm):
diff --git a/ishtar_common/ishtar_menu.py b/ishtar_common/ishtar_menu.py
index 6e61ede74..fbd65c103 100644
--- a/ishtar_common/ishtar_menu.py
+++ b/ishtar_common/ishtar_menu.py
@@ -122,6 +122,21 @@ MENU_SECTIONS = [
model=models.Import,
access_controls=['change_import']),
])),
+ (250, SectionItem(
+ 'document', _(u"Documentation / Images"),
+ childs=[
+ MenuItem('document_search',
+ _(u"Search"),
+ model=models.Document,
+ access_controls=['view_document',
+ 'view_own_document']),
+ MenuItem('document_creation',
+ _(u"Creation"),
+ model=models.Document,
+ access_controls=['add_document',
+ 'add_own_document']),
+ ])
+ )
]
"""
SectionItem(
diff --git a/ishtar_common/migrations/0056_auto_20180601_1555.py b/ishtar_common/migrations/0056_auto_20180601_1555.py
index fee995df9..71def216e 100644
--- a/ishtar_common/migrations/0056_auto_20180601_1555.py
+++ b/ishtar_common/migrations/0056_auto_20180601_1555.py
@@ -10,7 +10,7 @@ class Migration(migrations.Migration):
dependencies = [
('archaeological_warehouse', '0021_auto_20180601_1555'),
- ('archaeological_context_records', '0026_auto_20180601_1555'),
+ ('archaeological_context_records', '0027_auto_20180601_1555'),
('archaeological_finds', '0029_auto_20180601_1555'),
('archaeological_operations', '0032_auto_20180601_1555'),
('ishtar_common', '0055_auto_20180530_1900'),
diff --git a/ishtar_common/migrations/0057_document_cache_related_label.py b/ishtar_common/migrations/0057_document_cache_related_label.py
new file mode 100644
index 000000000..61a8ea329
--- /dev/null
+++ b/ishtar_common/migrations/0057_document_cache_related_label.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.10 on 2018-06-04 11:52
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ishtar_common', '0056_auto_20180601_1555'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='document',
+ name='cache_related_label',
+ field=models.TextField(blank=True, db_index=True, help_text='Cached value - do not edit', null=True, verbose_name='Related'),
+ ),
+ ]
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index 76f16eaae..de34a2b9c 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -3093,9 +3093,21 @@ class Document(OwnPerms, ImageModel, FullSearch):
'treatment_files', 'treatments', 'finds', 'context_records',
'operations', 'sites', 'warehouses',
]
-
+ SLUG = 'document'
LINK_SPLIT = u"<||>"
+ TABLE_COLS = ['title', 'source_type', 'cache_related_label', 'authors',
+ 'associated_url']
+ COL_LINK = ['associated_url']
+ BASE_SEARCH_VECTORS = ['title', 'source_type__label', 'external_id',
+ 'reference', 'description', 'comment',
+ 'additional_information']
+ PARENT_SEARCH_VECTORS = ['authors', ]
+
+ BOOL_FIELDS = ['duplicate']
+
+ CACHED_LABELS = ['cache_related_label']
+
title = models.TextField(_(u"Title"), blank=True, default='')
associated_file = models.FileField(
upload_to=get_image_path, blank=True, null=True, max_length=255)
@@ -3137,13 +3149,9 @@ class Document(OwnPerms, ImageModel, FullSearch):
duplicate = models.BooleanField(_(u"Has a duplicate"), default=False)
associated_links = models.TextField(_(u"Symbolic links"), blank=True,
null=True)
-
- TABLE_COLS = ['title', 'source_type', 'authors', 'associated_url']
- COL_LINK = ['associated_url']
- BASE_SEARCH_VECTORS = ['title', 'source_type__label', 'external_id',
- 'reference', 'description', 'comment',
- 'additional_information']
- PARENT_SEARCH_VECTORS = ['authors', ]
+ cache_related_label = models.TextField(
+ _(u"Related"), blank=True, null=True, db_index=True,
+ help_text=_(u"Cached value - do not edit"))
class Meta:
verbose_name = _(u"Document")
@@ -3199,7 +3207,7 @@ class Document(OwnPerms, ImageModel, FullSearch):
for related_model in self.RELATED_MODELS:
q = getattr(self, related_model).all()
if q.count():
- item = q.all()[0].item
+ item = q.all()[0]
yield item._get_base_image_path()
def _get_base_image_path(self):
@@ -3259,7 +3267,7 @@ class Document(OwnPerms, ImageModel, FullSearch):
for related_model in self.RELATED_MODELS:
q = getattr(self, related_model).all()
if q.count():
- item = q.all()[0].item
+ item = q.all()[0]
base_path = item._get_base_image_path()
new_path = base_path + u"/" + filename
if not reference_path:
@@ -3295,6 +3303,16 @@ class Document(OwnPerms, ImageModel, FullSearch):
os.symlink(reference_path, new_path)
return links
+ def related_label(self):
+ items = []
+ for rel_attr in reversed(self.RELATED_MODELS):
+ for item in getattr(self, rel_attr).all():
+ items.append(unicode(item))
+ return u" ; ".join(items)
+
+ def _generate_cache_related_label(self):
+ return self.related_label()
+
def save(self, *args, **kwargs):
no_path_change = 'no_path_change' in kwargs \
and kwargs.pop('no_path_change')
@@ -3309,6 +3327,9 @@ class Document(OwnPerms, ImageModel, FullSearch):
self.save(no_path_change=True)
+post_save.connect(cached_label_changed, sender=Document)
+
+
class Arrondissement(models.Model):
name = models.CharField(u"Nom", max_length=30)
department = models.ForeignKey(Department, verbose_name=u"Département")
diff --git a/ishtar_common/templates/ishtar/sheet_source.html b/ishtar_common/templates/ishtar/sheet_document.html
index bedcb587e..3d48963a2 100644
--- a/ishtar_common/templates/ishtar/sheet_source.html
+++ b/ishtar_common/templates/ishtar/sheet_document.html
@@ -1,11 +1,18 @@
{% extends "ishtar/sheet.html" %}
-{% load i18n window_field link_to_window %}
+{% load i18n window_field window_header link_to_window %}
+
+{% block head_title %}<strong>{% trans "Document" %}</strong> - {{item.title}}{% endblock %}
{% block content %}
-{% block window_nav %}{% endblock %}
+{% block window_nav %}
+{# {% window_nav item window_id 'show-document' 'document_modify' %} #}
+{% window_nav item window_id 'show-document' %}
+{% endblock %}
+
+
{% block general %}
-{% if item.image %}
+{% if item.images.count %}
<div class="row">
<div class="offset-lg-4 col-lg-4 offset-md-3 col-md-6 offset-sm-1 col-sm-10 col-12">
<div class="card">
@@ -16,10 +23,6 @@
{% endif %}
<div class="row">
- {% block related %}
- {% trans "Related item" as related_item_label %}
- {% field_flex related_item_label item.owner %}
- {% endblock %}
{% field_flex "Title" item.title %}
{% field_flex "Index" item.index %}
{% field_flex "Source type" item.source_type %}
@@ -40,6 +43,19 @@
{% field_flex_full "Authors" item.authors|add_links:'person' %}
</div>
-{% endblock %}
+{% block related %}
+<h2>{% trans "Related items" %}</h2>
+{% if item.operations.count %}
+{% field_flex_full "Sites" item.sites|add_links %}
+{% field_flex_full "Operations" item.operations|add_links %}
+{% field_flex_full "Context records" item.context_records|add_links %}
+{% field_flex_full "Finds" item.finds|add_links %}
+{% field_flex_full "Treatments" item.treatments|add_links %}
+{% field_flex_full "Treatment files" item.treatment_files|add_links %}
+{% field_flex_full "Warehouses" item.warehouses|add_links %}
+{% endif %}
+
{% endblock %}
+{% endblock %}
+{% endblock %}
diff --git a/ishtar_common/templates/ishtar/sheet_document_pdf.html b/ishtar_common/templates/ishtar/sheet_document_pdf.html
new file mode 100644
index 000000000..3a40fac44
--- /dev/null
+++ b/ishtar_common/templates/ishtar/sheet_document_pdf.html
@@ -0,0 +1,14 @@
+{% extends "ishtar/sheet_document.html" %}
+{% block header %}
+{% endblock %}
+{% block main_head %}
+{{ block.super }}
+<div id="pdfheader">
+Ishtar &ndash; {{APP_NAME}} &ndash; {{item}}
+</div>
+{% endblock %}
+{%block head_sheet%}{%endblock%}
+{%block main_foot%}
+</body>
+</html>
+{%endblock%}
diff --git a/ishtar_common/templates/ishtar/sheet_document_window.html b/ishtar_common/templates/ishtar/sheet_document_window.html
new file mode 100644
index 000000000..c739722e7
--- /dev/null
+++ b/ishtar_common/templates/ishtar/sheet_document_window.html
@@ -0,0 +1,3 @@
+{% extends "ishtar/sheet_document.html" %}
+{% block main_head %}{%endblock%}
+{% block main_foot %}{%endblock%}
diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py
index a64e6ab24..787c72aba 100644
--- a/ishtar_common/urls.py
+++ b/ishtar_common/urls.py
@@ -24,8 +24,8 @@ from django.views.generic import TemplateView
from menus import Menu
-from ishtar_common import views
-from ishtar_common.wizards import check_rights
+from ishtar_common import views, models
+from ishtar_common.utils import check_rights, get_urls_for_model
# be careful: each check_rights must be relevant with ishtar_menu
@@ -223,8 +223,27 @@ urlpatterns += [
name='hide-shortcut-menu'),
url(r'show-shortcut-menu/$', views.show_shortcut_menu,
name='show-shortcut-menu'),
+
+ url(r'document_search/(?P<step>.+)?$',
+ check_rights(['view_document', 'view_own_document'])(
+ views.document_search_wizard),
+ name='document_search'),
+ url(r'document_creation/(?P<step>.+)?$',
+ check_rights(['add_document', 'add_own_document'])(
+ views.NewDocumentFormView.as_view()),
+ name='document_creation'),
+ url(r'document_modification/(?P<step>.+)?$',
+ check_rights(['change_document', 'change_own_document'])(
+ views.NewDocumentFormView.as_view()),
+ name='document_modification'),
+]
+
+urlpatterns += get_urls_for_model(models.Document, views)
+
+urlpatterns += [
url(r'(?P<action_slug>' + actions + r')/$', views.action, name='action'),
]
+
"""
url(r'operation_source_search/(?P<step>.+)?$',
check_rights(['view_operation', 'view_own_operation'])(
diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py
index 6c77563ef..0b5b1bd57 100644
--- a/ishtar_common/utils.py
+++ b/ishtar_common/utils.py
@@ -30,6 +30,7 @@ import tempfile
from django import forms
from django.conf import settings
+from django.conf.urls import url
from django.contrib.contenttypes.models import ContentType
from django.contrib.gis.geos import GEOSGeometry
from django.contrib.sessions.backends.db import SessionStore
@@ -56,6 +57,52 @@ class BColors:
UNDERLINE = '\033[4m'
+def check_rights(rights=[], redirect_url='/'):
+ """
+ Decorator that checks the rights to access the view.
+ """
+
+ def decorator(view_func):
+ def _wrapped_view(request, *args, **kwargs):
+ if not rights:
+ return view_func(request, *args, **kwargs)
+ if hasattr(request.user, 'ishtaruser'):
+ if request.user.ishtaruser.has_right('administrator',
+ request.session):
+ kwargs['current_right'] = 'administrator'
+ return view_func(request, *args, **kwargs)
+ for right in rights:
+ # be careful to put the more permissive rights first
+ # if granted it can allow more
+ if request.user.ishtaruser.has_right(right,
+ request.session):
+ kwargs['current_right'] = right
+ return view_func(request, *args, **kwargs)
+ put_session_message(
+ request.session.session_key,
+ _(u"You don't have sufficient permissions to do this action."),
+ 'warning'
+ )
+ return HttpResponseRedirect(redirect_url)
+ return _wrapped_view
+ return decorator
+
+
+def check_rights_condition(rights):
+ """
+ To be used to check in wizard condition_dict
+ """
+ def func(self):
+ request = self.request
+ if request.user.ishtaruser.has_right('administrator', request.session):
+ return True
+ for right in rights:
+ if request.user.ishtaruser.has_right(right, request.session):
+ return True
+ return False
+ return func
+
+
class MultiValueDict(BaseMultiValueDict):
def get(self, *args, **kwargs):
v = super(MultiValueDict, self).getlist(*args, **kwargs)
@@ -703,3 +750,19 @@ def create_default_json_fields(model):
}
)
+
+def get_urls_for_model(model, views):
+ """
+ Generate get and show url for a model
+ """
+ urls = [
+ url(r'show-{}(?:/(?P<pk>.+))?/(?P<type>.+)?$'.format(model.SLUG),
+ check_rights(['view_' + model.SLUG, 'view_own_' + model.SLUG])(
+ getattr(views, 'show_' + model.SLUG)),
+ name="show-" + model.SLUG),
+ url(r'get-{}/(?P<type>.+)?$'.format(model.SLUG),
+ check_rights(['view_' + model.SLUG, 'view_own_' + model.SLUG])(
+ getattr(views, 'get_' + model.SLUG)),
+ name="get-" + model.SLUG),
+ ]
+ return urls
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index 5d2b442bf..187712676 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/views.py
@@ -2483,12 +2483,49 @@ class OrganizationPersonEdit(LoginRequiredMixin, UpdateView):
def get_success_url(self):
return reverse('organization_person_edit', args=[self.object.pk])
+
+# documents
+
+show_document = show_item(models.Document, 'document')
+get_document = get_item(models.Document, 'get_document', 'document')
+
+
+document_search_wizard = wizards.SearchWizard.as_view(
+ [('selec-document_search', forms.DocumentFormSelection)],
+ label=_(u"Document: search"),
+ url_name='document_search',
+)
+
+
+class NewDocumentFormView(IshtarMixin, LoginRequiredMixin,
+ FormView):
+ form_class = forms.DocumentForm
+ template_name = 'ishtar/form.html'
+ success_url = 'document_search'
+
"""
+class DocumentSelectMixin(IshtarMixin, LoginRequiredMixin,
+ FormView):
+ form_class = forms.PersonMergeFormSelection
+ template_name = 'ishtar/form.html'
+ redir_url = 'person_manual_merge_items'
+
+ def form_valid(self, form):
+ self.item = form.get_item()
+ return super(ManualMergeMixin, self).form_valid(form)
+
+ def get_success_url(self):
+ return reverse(self.redir_url, args=[self.item.pk])
-show_operationsource = show_item(models.OperationSource, 'operationsource')
-get_operationsource = get_item(models.OperationSource, 'get_operationsource',
- 'operationsource')
+class DocumentSelectView(DocumentSelectMixin, IshtarMixin, LoginRequiredMixin,
+ FormView):
+ page_name = _(u"Merge persons")
+ current_url = 'person-manual-merge'
+ redir_url = 'person_manual_merge_items'
+"""
+
+"""
# operation sources
operation_source_search_wizard = SearchWizard.as_view([
diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py
index b98c698ac..69f7c4c8e 100644
--- a/ishtar_common/wizards.py
+++ b/ishtar_common/wizards.py
@@ -44,57 +44,10 @@ from django.utils.safestring import mark_safe
from ishtar_common import models
from ishtar_common.forms import CustomForm, reverse_lazy
-from ishtar_common.utils import get_all_field_names, MultiValueDict, \
- put_session_message
+from ishtar_common.utils import get_all_field_names, MultiValueDict
logger = logging.getLogger(__name__)
-
-def check_rights(rights=[], redirect_url='/'):
- """
- Decorator that checks the rights to access the view.
- """
-
- def decorator(view_func):
- def _wrapped_view(request, *args, **kwargs):
- if not rights:
- return view_func(request, *args, **kwargs)
- if hasattr(request.user, 'ishtaruser'):
- if request.user.ishtaruser.has_right('administrator',
- request.session):
- kwargs['current_right'] = 'administrator'
- return view_func(request, *args, **kwargs)
- for right in rights:
- # be careful to put the more permissive rights first
- # if granted it can allow more
- if request.user.ishtaruser.has_right(right,
- request.session):
- kwargs['current_right'] = right
- return view_func(request, *args, **kwargs)
- put_session_message(
- request.session.session_key,
- _(u"You don't have sufficient permissions to do this action."),
- 'warning'
- )
- return HttpResponseRedirect(redirect_url)
- return _wrapped_view
- return decorator
-
-
-def check_rights_condition(rights):
- """
- To be used to check in wizard condition_dict
- """
- def func(self):
- request = self.request
- if request.user.ishtaruser.has_right('administrator', request.session):
- return True
- for right in rights:
- if request.user.ishtaruser.has_right(right, request.session):
- return True
- return False
- return func
-
# buggy and unecessary at least for the moment...
"""
def _check_right(step, condition=True):