diff options
Diffstat (limited to 'ishtar_common')
-rw-r--r-- | ishtar_common/forms.py | 31 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/forms/qa_form.html | 9 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/manage_basket.html | 4 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/wizard/default_wizard.html | 12 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/wizard/search.html | 2 | ||||
-rw-r--r-- | ishtar_common/urls_converters.py | 14 | ||||
-rw-r--r-- | ishtar_common/utils.py | 7 | ||||
-rw-r--r-- | ishtar_common/views.py | 9 | ||||
-rw-r--r-- | ishtar_common/views_item.py | 42 | ||||
-rw-r--r-- | ishtar_common/widgets.py | 2 | ||||
-rw-r--r-- | ishtar_common/wizards.py | 4 |
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> {% 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 |