summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/forms.py31
-rw-r--r--ishtar_common/templates/ishtar/forms/qa_form.html9
-rw-r--r--ishtar_common/templates/ishtar/manage_basket.html4
-rw-r--r--ishtar_common/templates/ishtar/wizard/default_wizard.html12
-rw-r--r--ishtar_common/templates/ishtar/wizard/search.html2
-rw-r--r--ishtar_common/urls_converters.py14
-rw-r--r--ishtar_common/utils.py7
-rw-r--r--ishtar_common/views.py9
-rw-r--r--ishtar_common/views_item.py42
-rw-r--r--ishtar_common/widgets.py2
-rw-r--r--ishtar_common/wizards.py4
11 files changed, 101 insertions, 35 deletions
diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py
index ca9f37623..6531ad6bb 100644
--- a/ishtar_common/forms.py
+++ b/ishtar_common/forms.py
@@ -627,15 +627,28 @@ class FormSetWithDeleteSwitches(FormSet):
delete_widget = widgets.DeleteSwitchWidget
-class FieldType(object):
- def __init__(self, key, model, is_multiple=False, extra_args=None):
+class FieldType:
+ """
+ Define field choices, help for SELECT field from a model.
+ :key: fields key for the form
+ :model: associated model
+ :is_multiple: True if multi select
+ :extra_args: extra args for 'get_types' call
+ :empty_first: first entry is empty. True by default. Always False when multiple
+ """
+
+ def __init__(self, key, model, is_multiple=False, extra_args=None,
+ empty_first=True):
self.key = key
self.model = model
self.is_multiple = is_multiple
self.extra_args = extra_args
+ if self.is_multiple:
+ empty_first = False
+ self.empty_first = empty_first
def get_choices(self, initial=None):
- args = {"empty_first": not self.is_multiple, "initial": initial}
+ args = {"empty_first": self.empty_first, "initial": initial}
if self.extra_args:
args.update(self.extra_args)
return self.model.get_types(**args)
@@ -779,6 +792,18 @@ class IshtarForm(BSForm, forms.Form):
self.fields[field.key].choices = field.get_choices()
self.fields[field.key].help_text = field.get_help()
+ def _clean_model_field(self, key, model):
+ """
+ Clean autocomplete field returning integer associated to a model.
+ """
+ value = self.cleaned_data.get(key, None)
+ if not value:
+ return
+ try:
+ return model.objects.get(pk=int(value))
+ except (model.DoesNotExist, ValueError):
+ return
+
def get_headers(self):
if self._headers:
return self._headers
diff --git a/ishtar_common/templates/ishtar/forms/qa_form.html b/ishtar_common/templates/ishtar/forms/qa_form.html
index c843dbd2d..178910215 100644
--- a/ishtar_common/templates/ishtar/forms/qa_form.html
+++ b/ishtar_common/templates/ishtar/forms/qa_form.html
@@ -2,6 +2,15 @@
{% load i18n inline_formset table_form %}
{% block main_form %}
+ {% for message in messages %}
+ <div class="alert alert-{{message.type}} alert-dismissible fade show" role="alert">
+ {% if message.icon %}<i class="{{message.icon}}" aria-hidden="true"></i>&nbsp;&nbsp;{% endif %}
+ {{message.message}}
+ <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+ <span aria-hidden="true">×</span>
+ </button>
+ </div>
+ {% endfor %}
{% for error in form.non_field_errors %}
<p>{{ error }}</p>
{% endfor %}
diff --git a/ishtar_common/templates/ishtar/manage_basket.html b/ishtar_common/templates/ishtar/manage_basket.html
index 5f3bf2c8f..61def50f6 100644
--- a/ishtar_common/templates/ishtar/manage_basket.html
+++ b/ishtar_common/templates/ishtar/manage_basket.html
@@ -69,9 +69,9 @@ jQuery(document).ready(function(){
<div id='validation-bar' class="row text-center">
<div class="col-sm">
<a class="btn btn-success"
- href="{% url 'display-findbasket' basket.id %}"
+ href="{% if back_url %}{{back_url}}{% else %}{% url 'display-findbasket' basket.id %}{% endif %}"
id="validate-button"
- class='button'>{% trans "Close" %}</a>
+ class='button'>{% trans "Back" %}</a>
</div>
</div>
{% include 'ishtar/blocks/footer.html' %}
diff --git a/ishtar_common/templates/ishtar/wizard/default_wizard.html b/ishtar_common/templates/ishtar/wizard/default_wizard.html
index 0d3863af9..b9364d012 100644
--- a/ishtar_common/templates/ishtar/wizard/default_wizard.html
+++ b/ishtar_common/templates/ishtar/wizard/default_wizard.html
@@ -6,16 +6,8 @@
{% block content %}
{% block wizard_head %}
<h3>{{wizard_label}}</h3>
-{% if no_context_cr %}
-<div class="row mb-3">
- <div class="col">
- <a href="/find_create/{{no_context_cr|unlocalize}}/" class="btn btn-success">
- <i class="fa fa-plus" aria-hidden="true"></i> {% trans "find without context" %}
- </a>
- </div>
-</div>
-{% endif %}
-
+{% block wizard_top_button %}
+{% endblock %}
{% include "ishtar/blocks/wizard_breadcrumb.html" %}
{% endblock %}
diff --git a/ishtar_common/templates/ishtar/wizard/search.html b/ishtar_common/templates/ishtar/wizard/search.html
index 9047c47fc..19a6540dd 100644
--- a/ishtar_common/templates/ishtar/wizard/search.html
+++ b/ishtar_common/templates/ishtar/wizard/search.html
@@ -5,6 +5,8 @@
{% endblock %}
{% block content %}
<h3>{{wizard_label}}</h3>
+{% block wizard_top_button %}
+{% endblock %}
{% if default_search_vector or open_url %}
<script type="text/javascript">{% localize off %}
{% if default_search_vector %}
diff --git a/ishtar_common/urls_converters.py b/ishtar_common/urls_converters.py
index 9395af648..b5185fd1f 100644
--- a/ishtar_common/urls_converters.py
+++ b/ishtar_common/urls_converters.py
@@ -17,6 +17,8 @@
# See the file COPYING for details.
+from datetime import datetime
+
class UnderscoreSlug:
regex = '[_0-9a-z]+'
@@ -27,3 +29,15 @@ class UnderscoreSlug:
def to_url(self, value):
return str(value)
+
+class DateTimeConverter:
+ regex = r"\d{4}-\d{1,2}-\d{1,2}T\d{1,2}\:\d{1,2}\:\d{1,2}\.\d{1,6}"
+ date_format = '%Y-%m-%dT%H:%M:%S.%f'
+
+ def to_python(self, value):
+ return datetime.strptime(value, self.date_format)
+
+ def to_url(self, value):
+ if isinstance(value, datetime):
+ return value.strftime(self.date_format)
+ return value
diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py
index 152b78c9c..eb51b6ef4 100644
--- a/ishtar_common/utils.py
+++ b/ishtar_common/utils.py
@@ -1386,6 +1386,13 @@ def get_random_item_image_link(request):
return _get_image_link(q.all()[image_nb])
+class BSMessage:
+ def __init__(self, message, message_type="info", icon=None):
+ self.message = message
+ self.type = message_type
+ self.icon = icon
+
+
def convert_coordinates_to_point(x, y, z=None, srid=4326):
if z:
geom = GEOSGeometry("POINT({} {} {})".format(x, y, z), srid=srid)
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index 21b563bfc..6411441f1 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/views.py
@@ -3128,6 +3128,7 @@ class QAItemForm(IshtarMixin, LoginRequiredMixin, FormView):
success_url = "/success/"
modal_size = None # large, small or None (medium)
icon = "fa fa-pencil"
+ action_name = None
def get_quick_action(self):
# if not listed in QUICK_ACTIONS overload this method
@@ -3139,7 +3140,11 @@ class QAItemForm(IshtarMixin, LoginRequiredMixin, FormView):
self.model = kwargs["model"]
else:
raise NotImplementedError("No attribute model defined.")
- pks = [int(pk) for pk in kwargs.get("pks").split("-")]
+ pks = kwargs.get("pks")
+ if isinstance(pks, int):
+ pks = [pks]
+ else:
+ pks = [int(pk) for pk in kwargs.get("pks").split("-")]
self.items = list(self.model.objects.filter(pk__in=pks))
if not self.items:
raise Http404()
@@ -3182,6 +3187,8 @@ class QAItemForm(IshtarMixin, LoginRequiredMixin, FormView):
data["items"] = self.items
data["modal_size"] = self.modal_size
data["page_name"] = self.get_page_name()
+ if self.action_name:
+ data["action_name"] = self.action_name
return data
diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py
index 8d41d1cc6..345bd0025 100644
--- a/ishtar_common/views_item.py
+++ b/ishtar_common/views_item.py
@@ -55,6 +55,7 @@ from weasyprint.fonts import FontConfiguration
from bootstrap_datepicker.widgets import DateField
+from ishtar_common.urls_converters import DateTimeConverter
from ishtar_common.utils import (
API_MAIN_MODELS,
check_model_access_control,
@@ -368,9 +369,9 @@ def show_source_item(request, source_id, model, name, base_dct, extra_dct):
permissions = ["permission_view_document"]
for p in permissions:
dct[p] = True
- dct["permission_change_own_document"] = False
- dct["permission_change_document"] = False
-
+ for perm in ["document", "findbasket"]:
+ dct[f"permission_change_own_{perm}"] = False
+ dct[f"permission_change_{perm}"] = False
tpl = loader.get_template(f"ishtar/sheet_{name}_window.html")
content = tpl.render(dct, request)
return HttpResponse(content, content_type="application/xhtml")
@@ -477,8 +478,9 @@ def show_item(model, name, extra_dct=None, model_for_perms=None, callback=None):
for perm in Permission.objects.filter(
codename__startswith='view_').values_list("codename", flat=True).all():
dct["permission_" + perm] = False
- dct["permission_change_own_document"] = False
- dct["permission_change_document"] = False
+ for perm in ["document", "findbasket"]:
+ dct[f"permission_change_own_{perm}"] = False
+ dct[f"permission_change_{perm}"] = False
if hasattr(request.user, "ishtaruser") and request.user.ishtaruser:
cache_key = "{}-{}-{}".format(
settings.PROJECT_SLUG,
@@ -503,9 +505,12 @@ def show_item(model, name, extra_dct=None, model_for_perms=None, callback=None):
dct["get_import_updated"] = item.get_imports_updated(request.user, limit=5)
if hasattr(item, "history") and request.user.is_superuser:
+
if date:
try:
- date = datetime.datetime.strptime(date, "%Y-%m-%dT%H:%M:%S.%f")
+ if not isinstance(date, datetime.datetime):
+ date = datetime.datetime.strptime(
+ date, DateTimeConverter.date_format)
dct["IS_HISTORY"] = True
if item.get_last_history_date() != date:
item = item.get_previous(date=date)
@@ -630,7 +635,8 @@ def revert_item(model):
def func(request, pk, date, **dct):
try:
item = model.objects.get(pk=pk)
- date = datetime.datetime.strptime(date, "%Y-%m-%dT%H:%M:%S.%f")
+ if not isinstance(date, datetime.datetime):
+ date = datetime.datetime.strptime(date, "%Y-%m-%dT%H:%M:%S.%f")
item.rollback(date)
except (ObjectDoesNotExist, ValueError, HistoryError):
return HttpResponse(None, content_type="text/plain")
@@ -2897,6 +2903,19 @@ def get_item(
if not no_link:
try:
curl = reverse("show-" + default_name, args=[data[0], ""])
+ except NoReverseMatch:
+ try:
+ curl = reverse("show-" + default_name, args=[data[0]])
+ except NoReverseMatch:
+ logger.warning(
+ '**WARN "show-'
+ + default_name
+ + '" args ('
+ + str(data[0])
+ + ") url not available"
+ )
+ curl, lnk = "", ""
+ if curl:
if not curl.endswith("/"):
curl += "/"
lnk_template = link_template
@@ -2908,15 +2927,6 @@ def get_item(
lnk = lnk.replace("<lock>", lock)
else:
lnk = lnk.replace("<lock>", "")
- except NoReverseMatch:
- logger.warning(
- '**WARN "show-'
- + default_name
- + '" args ('
- + str(data[0])
- + ") url not available"
- )
- lnk = ""
res["link"] = lnk
for idx, value in enumerate(data[1:]):
if not value or idx >= len(table_cols):
diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py
index e131521e0..b9166f361 100644
--- a/ishtar_common/widgets.py
+++ b/ishtar_common/widgets.py
@@ -621,7 +621,7 @@ class SearchWidget(forms.TextInput):
self.app_name = app_name
self.model = model
if not pin_model:
- pin_model = self.model
+ pin_model = self.model.lower()
self.pin_model = pin_model
def get_context(self, name, value, attrs):
diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py
index 740a1c18d..0d23bdcb4 100644
--- a/ishtar_common/wizards.py
+++ b/ishtar_common/wizards.py
@@ -1678,6 +1678,7 @@ class SearchWizard(IshtarWizard):
label = ""
modification = None # True when the wizard modify an item
storage_name = "formtools.wizard.storage.session.SessionStorage"
+ template_name = "ishtar/wizard/search.html"
def get_wizard_name(self):
"""
@@ -1692,8 +1693,7 @@ class SearchWizard(IshtarWizard):
)
def get_template_names(self):
- templates = ["ishtar/wizard/search.html"]
- return templates
+ return [self.template_name]
def get_label(self):
return self.label