diff options
Diffstat (limited to 'ishtar_common')
| -rw-r--r-- | ishtar_common/context_processors.py | 7 | ||||
| -rw-r--r-- | ishtar_common/forms.py | 7 | ||||
| -rw-r--r-- | ishtar_common/menu_base.py | 8 | ||||
| -rw-r--r-- | ishtar_common/models.py | 35 | ||||
| -rw-r--r-- | ishtar_common/static/js/ishtar.js | 12 | ||||
| -rw-r--r-- | ishtar_common/static/media/style.css | 6 | ||||
| -rw-r--r-- | ishtar_common/templates/base.html | 4 | ||||
| -rw-r--r-- | ishtar_common/templates/blocks/JQueryJqGrid.html | 1 | ||||
| -rw-r--r-- | ishtar_common/templates/ishtar/basket_list.html | 10 | ||||
| -rw-r--r-- | ishtar_common/templates/ishtar/blocks/window_tables/dynamic_documents.html | 1 | ||||
| -rw-r--r-- | ishtar_common/templates/ishtar/form_delete.html | 14 | ||||
| -rw-r--r-- | ishtar_common/templates/ishtar/manage_basket.html | 42 | ||||
| -rw-r--r-- | ishtar_common/templates/ishtar/simple_form.html | 11 | ||||
| -rw-r--r-- | ishtar_common/templatetags/window_tables.py | 27 | ||||
| -rw-r--r-- | ishtar_common/views.py | 12 | ||||
| -rw-r--r-- | ishtar_common/widgets.py | 5 | ||||
| -rw-r--r-- | ishtar_common/wizards.py | 2 |
17 files changed, 180 insertions, 24 deletions
diff --git a/ishtar_common/context_processors.py b/ishtar_common/context_processors.py index 03ba9bc36..76f58bf8e 100644 --- a/ishtar_common/context_processors.py +++ b/ishtar_common/context_processors.py @@ -77,10 +77,13 @@ def get_base_context(request): current = model_name in request.session and request.session[model_name] items = [] for item in model.get_owns(request.user): - selected = unicode(item.pk) == current + pk = unicode(item.pk) + if item.IS_BASKET: + pk = "basket-" + pk + selected = pk == current if selected: cls = item.get_short_menu_class() - items.append((item.pk, shortify(unicode(item), 60), + items.append((pk, shortify(unicode(item), 60), selected, item.get_short_menu_class())) if items: dct['current_menu'].append((lbl, model_name, cls, items)) diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index a5abdddcd..5e0d14eb8 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -128,7 +128,7 @@ class ClosingDateFormSelection(forms.Form): def get_form_selection( class_name, label, key, model, base_form, get_url, not_selected_error=_(u"You should select an item."), new=False, - new_message=_(u"Add a new item")): + new_message=_(u"Add a new item"), get_full_url=None): """ Generate a class selection form class_name -- name of the class @@ -145,11 +145,14 @@ def get_form_selection( 'form_label': label, 'associated_models': {key: model}, 'currents': {key: model}} + widget_kwargs = {"new": new, "new_message": new_message} + if get_full_url: + widget_kwargs['source_full'] = reverse_lazy(get_full_url) attrs[key] = forms.IntegerField( label="", required=False, validators=[models.valid_id(model)], widget=widgets.JQueryJqGrid(reverse_lazy(get_url), base_form, model, - new=new, new_message=new_message)) + **widget_kwargs)) def clean(self): cleaned_data = self.cleaned_data diff --git a/ishtar_common/menu_base.py b/ishtar_common/menu_base.py index d8ee0775c..7c309d376 100644 --- a/ishtar_common/menu_base.py +++ b/ishtar_common/menu_base.py @@ -89,9 +89,9 @@ class MenuItem: for access_control in self.access_controls: access_control = prefix + access_control if hasattr(user, 'ishtaruser') and \ - user.ishtaruser.has_perm(access_control, self.model, - session=session) or \ + user.ishtaruser.has_perm(access_control, self.model) or\ access_control in user.get_group_permissions(): + # session=session) or \ return True # manage by person type if hasattr(user, 'ishtaruser'): @@ -107,8 +107,8 @@ class MenuItem: prefix = (self.model._meta.app_label + '.') if self.model else '' for access_control in self.access_controls: access_control = prefix + access_control - if user.has_perm(access_control, self.model, obj=obj, - session=session): + if user.has_perm(access_control, self.model, obj=obj): + # session=session): return True # manage by person type if hasattr(user, 'ishtaruser'): diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 9509b36a6..f3974d04d 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -243,10 +243,15 @@ class OwnPerms: user = IshtarUser.objects.get(user_ptr=user) if user.is_anonymous(): return cls.objects.filter(pk__isnull=True) + items = [] + if hasattr(cls, 'BASKET_MODEL'): + items = list(cls.BASKET_MODEL.objects.filter(user=user).all()) query = cls.get_query_owns(user) if not query: return cls.objects.filter(pk__isnull=True) - return cls.objects.filter(query).order_by(*cls._meta.ordering) + items += list( + cls.objects.filter(query).order_by(*cls._meta.ordering).all()) + return items class Cached(object): @@ -475,6 +480,33 @@ class GeneralType(models.Model, Cached): item.generate_key() +class Basket(models.Model): + """ + Abstract class for a basket + Subclass must be defined with an "items" ManyToManyField + """ + 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) + available = models.BooleanField(_(u"Available"), default=True) + + class Meta: + abstract = True + unique_together = (('label', 'user'),) + + def __unicode__(self): + return self.label + + def get_short_menu_class(self): + return 'basket' + + @property + def associated_filename(self): + return "{}-{}".format(datetime.date.today().strftime( + "%Y-%m-%d"), slugify(self.label)) + + class ItemKey(models.Model): key = models.CharField(_(u"Key"), max_length=100) content_type = models.ForeignKey(ContentType) @@ -551,6 +583,7 @@ class HistoryError(Exception): class BaseHistorizedItem(Imported): + IS_BASKET = False history_modifier = models.ForeignKey( User, related_name='+', on_delete=models.SET_NULL, verbose_name=_(u"Last editor"), blank=True, null=True) diff --git a/ishtar_common/static/js/ishtar.js b/ishtar_common/static/js/ishtar.js index 9af5cf2b0..f469fc546 100644 --- a/ishtar_common/static/js/ishtar.js +++ b/ishtar_common/static/js/ishtar.js @@ -23,6 +23,15 @@ beforeSend: function(xhr, settings) { } }}); +function manage_async_link(event){ + event.preventDefault(); + var url = $(this).attr('href'); + var target = $(this).attr('data-target'); + $.get(url, function(data) { + $(target).html(data); + }); +} + /* default function to prevent undefined */ function get_next_table_id(){} function get_previous_table_id(){} @@ -63,7 +72,8 @@ $(document).ready(function(){ } $('#current_items select').change(function(){ $(this).attr('class', $(this).children("option:selected").attr('class')); - }) + }); + $("a.async-link").click(manage_async_link); }); $(document).on("click", '#to_bottom_arrow', function(){ diff --git a/ishtar_common/static/media/style.css b/ishtar_common/static/media/style.css index 1590c1738..1d47bcbd9 100644 --- a/ishtar_common/static/media/style.css +++ b/ishtar_common/static/media/style.css @@ -45,6 +45,12 @@ a.add-button, color:#000; } +#context_menu .basket{ + color:#000; + font-weight: bold; + font-style: italic; +} + /* borders */ a.add-button, a.remove, #progress-content, diff --git a/ishtar_common/templates/base.html b/ishtar_common/templates/base.html index 578b3edcc..1bab3d647 100644 --- a/ishtar_common/templates/base.html +++ b/ishtar_common/templates/base.html @@ -74,7 +74,7 @@ <td> <select class='{{main_cls}}' id='current_{{model_name}}'> <option class='normal' value=''>--</option> - {% for val, label, selected, cls in items %}<option class='{{cls}}' value='{{val}}'{%if selected%} selected="selected"{%endif%}>{{label}}</option> + {% for val, label, selected, cls in items %}<option class='{{cls}}' value='{{val}}'{% if selected %} selected="selected"{%endif%}>{{label}}</option> {% endfor %}</select> </td>{% with 'show-'|add:model_name as model_url%} <td><a href='#' onclick='load_current_window("{% url model_url 0 %}", "{{model_name}}");' class='display_details'>{% trans "Details" %}</a></td> @@ -87,7 +87,7 @@ {% endif %}{% endblock %} </div>{% endif %} {% if reminders %}<fieldset id='reminder'><legend>{% trans "Current items" %}</legend> -{% for lbl, value in reminders%} +{% for lbl, value in reminders %} <p><strong class='lbl'>{{lbl}}{% trans ":"%}</strong> <span class='value'>{{value}}</span></p> {% endfor %} </fieldset>{%endif%} diff --git a/ishtar_common/templates/blocks/JQueryJqGrid.html b/ishtar_common/templates/blocks/JQueryJqGrid.html index 063a3c1da..c6a15243a 100644 --- a/ishtar_common/templates/blocks/JQueryJqGrid.html +++ b/ishtar_common/templates/blocks/JQueryJqGrid.html @@ -90,6 +90,7 @@ jQuery(document).ready(function(){ width: null, shrinkToFit: false, rowNum:20, + {% if multiple_select %}multiselect: true,{% endif %} jsonReader : {repeatitems: false}, loadError: function (jqXHR, textStatus, errorThrown) { alert("{% trans "An error as occured during search. Check your query fields." %}"); diff --git a/ishtar_common/templates/ishtar/basket_list.html b/ishtar_common/templates/ishtar/basket_list.html new file mode 100644 index 000000000..a0a0e5d73 --- /dev/null +++ b/ishtar_common/templates/ishtar/basket_list.html @@ -0,0 +1,10 @@ +{% load i18n %} +<table> +<tr>{% for item in basket.items.all %} + <td><a class="display_details" href="#" onclick="load_window('{{item_url}}/{{item.pk}}/');">{% trans 'Details' %}</a></td> + <td>{{item.full_label}}</td> + <td><a class='async-link' data-target='#basket-content' href='{{delete_url}}/{{basket.pk}}/{{item.pk}}/'>{% trans "remove" %}</a></td></tr>{% endfor %} +</table> +<script type='text/javascript'> + $("a.async-link").click(manage_async_link); +</script> diff --git a/ishtar_common/templates/ishtar/blocks/window_tables/dynamic_documents.html b/ishtar_common/templates/ishtar/blocks/window_tables/dynamic_documents.html index 7239b64fc..8850bd34a 100644 --- a/ishtar_common/templates/ishtar/blocks/window_tables/dynamic_documents.html +++ b/ishtar_common/templates/ishtar/blocks/window_tables/dynamic_documents.html @@ -42,6 +42,7 @@ setTimeout( alert("{% trans "An error as occured during search. Check your query fields." %}"); } }); + {% if large %}jQuery("#grid_{{name}}").jqGrid('setGridHeight', 400);{% endif %} }, 200); </script> diff --git a/ishtar_common/templates/ishtar/form_delete.html b/ishtar_common/templates/ishtar/form_delete.html new file mode 100644 index 000000000..6243e9423 --- /dev/null +++ b/ishtar_common/templates/ishtar/form_delete.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} +{% load i18n inline_formset %} +{% block content %} +<h2>{{page_name}}</h2> +<div class='form'> +<form enctype="multipart/form-data" action="." method="post" + onsubmit="return confirm('Do you really want to delete this item?');">{% csrf_token %} +<table> +{{form}} +</table> +<input type="submit" value="{% trans "Delete" %}"/> +</form> +</div> +{% endblock %} diff --git a/ishtar_common/templates/ishtar/manage_basket.html b/ishtar_common/templates/ishtar/manage_basket.html new file mode 100644 index 000000000..6332b326e --- /dev/null +++ b/ishtar_common/templates/ishtar/manage_basket.html @@ -0,0 +1,42 @@ +{% extends "base.html" %} +{% load i18n inline_formset %} +{% block content %} +<h2>{{page_name}}{% trans ":"%} {{basket}}</h2> +<form enctype="multipart/form-data" action="." method="post">{% csrf_token %} +<div class='form'> +<p class='alert'>{% trans 'Checking "Select all" only select the current page.' %}</p> +{{form}} +<button id='add_to' onclick='return false'>{% trans "Add" %}</button> +<h3>{% trans "Basket content" %}</h3> +<div id='basket-content' style='text-align:left'> +</div> +</div> +</form> +<script type='text/javascript' language='javascript'> + +function load_list(data){ + $('#basket-content').html(data); +} + +$('#add_to').click(function(){ + var selected_items = jQuery("#grid_pk").getGridParam('selarrrow'); + if(!selected_items) return false; + for (i = 0, n = selected_items.length; i < n; i++) { + var selected_item = selected_items[i]; + $.ajax({ + type: "POST", + url: '{{add_url}}', + data: { + basket_id: {{basket.pk}}, + item_id: selected_item + }, + success: load_list + }); + } + return false; +}); +jQuery(document).ready(function(){ + $.get('{{list_url}}', load_list); +}); +</script> +{% endblock %} diff --git a/ishtar_common/templates/ishtar/simple_form.html b/ishtar_common/templates/ishtar/simple_form.html new file mode 100644 index 000000000..e3a464459 --- /dev/null +++ b/ishtar_common/templates/ishtar/simple_form.html @@ -0,0 +1,11 @@ +{% load i18n %} +<html> +<body> +<div class='form'> +<form enctype="multipart/form-data" action="." method="post">{% csrf_token %} +{{form}} +<input type="submit" value="{% trans "Validate" %}"/> +</form> +</div> +</body> +</html> diff --git a/ishtar_common/templatetags/window_tables.py b/ishtar_common/templatetags/window_tables.py index cdd681b52..6710672e1 100644 --- a/ishtar_common/templatetags/window_tables.py +++ b/ishtar_common/templatetags/window_tables.py @@ -27,25 +27,28 @@ def table_document(caption, data): ASSOCIATED_MODELS = {} ASSOCIATED_MODELS['files'] = (File, 'get-file', '') -ASSOCIATED_MODELS['operation_docs'] = (OperationSource, - 'get-operationsource', '') +ASSOCIATED_MODELS['operation_docs'] = ( + OperationSource, 'get-operationsource', 'get-operationsource-full') ASSOCIATED_MODELS['operations'] = (Operation, 'get-operation', '') ASSOCIATED_MODELS['context_records'] = (ContextRecord, 'get-contextrecord', 'get-contextrecord-full') ASSOCIATED_MODELS['context_records_for_ope'] = ( ContextRecord, 'get-contextrecord-for-ope', 'get-contextrecord-full') -ASSOCIATED_MODELS['context_records_docs'] = (ContextRecordSource, - 'get-contextrecordsource', '') +ASSOCIATED_MODELS['context_records_docs'] = ( + ContextRecordSource, + 'get-contextrecordsource', 'get-contextrecordsource-full') ASSOCIATED_MODELS['finds'] = (Find, 'get-find', 'get-find-full') ASSOCIATED_MODELS['finds_for_ope'] = ( Find, 'get-find-for-ope', 'get-find-full') -ASSOCIATED_MODELS['finds_docs'] = (FindSource, 'get-findsource', '') +ASSOCIATED_MODELS['finds_docs'] = ( + FindSource, 'get-findsource', 'get-findsource-full') @register.simple_tag(takes_context=True) -def dynamic_table_document(context, caption, associated_model, key, value, - table_cols='TABLE_COLS', output='html'): +def dynamic_table_document( + context, caption, associated_model, key, value, + table_cols='TABLE_COLS', output='html', large=False): if not table_cols: table_cols = 'TABLE_COLS' model, url, url_full = ASSOCIATED_MODELS[associated_model] @@ -68,6 +71,7 @@ def dynamic_table_document(context, caption, associated_model, key, value, 'no_result': unicode(_("No results")), 'loading': unicode(_("Loading...")), 'encoding': settings.ENCODING or 'utf-8', + 'large': large }) return t.render(context) else: @@ -103,3 +107,12 @@ def dynamic_table_document(context, caption, associated_model, key, value, 'data': data }) return t.render(context) + + +@register.simple_tag(takes_context=True) +def dynamic_table_document_large( + context, caption, associated_model, key, + value, table_cols='TABLE_COLS', output='html'): + return dynamic_table_document( + context, caption, associated_model, key, + value, table_cols, output, large=True) diff --git a/ishtar_common/views.py b/ishtar_common/views.py index f4a8d02e2..59cfe6321 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Copyright (C) 2010-2015 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2016 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -350,7 +350,8 @@ def get_item(model, func_name, default_name, extra_request_keys=[], if specific_perms and perm not in specific_perms: continue cperm = model._meta.app_label + '.' + perm - if cperm in request.user.get_all_permissions() \ + if request.user.has_perm(cperm)\ + or cperm in request.user.get_all_permissions() \ or (request.user.is_authenticated() and request.user.ishtaruser.has_right( perm, session=request.session)): @@ -416,7 +417,12 @@ def get_item(model, func_name, default_name, extra_request_keys=[], if 'submited' not in request_items: if default_name in request.session and \ request.session[default_name]: - dct = {"pk": request.session[default_name]} + value = request.session[default_name] + if 'basket-' in value: + dct = {"basket__pk": + request.session[default_name].split('-')[-1]} + else: + dct = {"pk": request.session[default_name]} elif not dct: for name in relative_session_names.keys(): if name in request.session and request.session[name]: diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py index b8b104a61..6d9600d0c 100644 --- a/ishtar_common/widgets.py +++ b/ishtar_common/widgets.py @@ -513,13 +513,15 @@ class JQueryJqGrid(forms.RadioSelect): def __init__(self, source, form, associated_model, attrs={}, table_cols='TABLE_COLS', multiple=False, multiple_cols=[2], - new=False, new_message="", source_full=None): + new=False, new_message="", source_full=None, + multiple_select=False): self.source = source self.form = form self.attrs = attrs self.associated_model = associated_model self.table_cols = table_cols self.multiple = multiple + self.multiple_select = multiple_select self.multiple_cols = multiple_cols self.new, self.new_message = new, new_message self.source_full = source_full @@ -604,6 +606,7 @@ class JQueryJqGrid(forms.RadioSelect): 'remove': unicode(_(u"Remove")), 'sname': name.replace('-', ''), 'multiple': self.multiple, + 'multiple_select': self.multiple_select, 'multi_cols': ",".join((u'"%d"' % col for col in self.multiple_cols))}) t = loader.get_template('blocks/JQueryJqGrid.html') diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py index e974942b7..49abe606f 100644 --- a/ishtar_common/wizards.py +++ b/ishtar_common/wizards.py @@ -510,7 +510,7 @@ class Wizard(NamedUrlWizardView): adds = {} # manage attributes relations if hasattr(self.model, 'ATTRS_EQUIV'): - for k in other_objs: + for k in other_objs.keys(): if k in self.model.ATTRS_EQUIV: new_k = self.model.ATTRS_EQUIV[k] if new_k in other_objs: |
