diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2018-04-17 12:04:08 +0200 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2018-06-12 08:41:54 +0200 |
commit | 0666e34337b965e85ce3920363ad04e87958e8e7 (patch) | |
tree | 67d308063f0c78cbf26e3b040821e762fed5b4e3 | |
parent | 022d362b707f0396461a1b32f001baab96a885fc (diff) | |
download | Ishtar-0666e34337b965e85ce3920363ad04e87958e8e7.tar.bz2 Ishtar-0666e34337b965e85ce3920363ad04e87958e8e7.zip |
WIP on account wizard. Wizard: can use switch for deletion. Better display of formsets on done wizard.
-rw-r--r-- | ishtar_common/forms.py | 8 | ||||
-rw-r--r-- | ishtar_common/forms_common.py | 22 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/wizard/confirm_wizard.html | 8 | ||||
-rw-r--r-- | ishtar_common/views.py | 1 | ||||
-rw-r--r-- | ishtar_common/widgets.py | 28 | ||||
-rw-r--r-- | ishtar_common/wizards.py | 128 |
6 files changed, 138 insertions, 57 deletions
diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index 70e144980..c314e4f13 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -193,6 +193,8 @@ class CustomForm(object): class FormSet(CustomForm, BaseFormSet): + delete_widget = widgets.DeleteWidget + def __init__(self, *args, **kwargs): self.readonly = False if 'readonly' in kwargs: @@ -240,7 +242,11 @@ class FormSet(CustomForm, BaseFormSet): setattr(form, clean.__name__, types.MethodType(clean, form)) if self.can_delete: form.fields[DELETION_FIELD_NAME].label = '' - form.fields[DELETION_FIELD_NAME].widget = widgets.DeleteWidget() + form.fields[DELETION_FIELD_NAME].widget = self.delete_widget() + + +class FormSetWithDeleteSwitches(FormSet): + delete_widget = widgets.DeleteSwitchWidget class FieldType(object): diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py index 72b33b4c4..bde5e47ed 100644 --- a/ishtar_common/forms_common.py +++ b/ishtar_common/forms_common.py @@ -37,7 +37,7 @@ import widgets from bootstrap_datepicker.widgets import DatePicker from ishtar_common.templatetags.link_to_window import link_to_window from forms import FinalForm, FormSet, reverse_lazy, name_validator, \ - TableSelect, ManageOldType, CustomForm, FieldType + TableSelect, ManageOldType, CustomForm, FieldType, FormSetWithDeleteSwitches def get_town_field(label=_(u"Town"), required=True): @@ -721,6 +721,26 @@ class AccountForm(forms.Form): return cleaned_data +class ProfileForm(ManageOldType): + form_label = _("Profiles") + base_model = 'profile' + associated_models = {'profile_type': models.ProfileType} + profile_type = forms.ChoiceField(label=_(u"Type"), choices=[], + required=False) + pk = forms.IntegerField(label=" ", widget=forms.HiddenInput, required=False) + + TYPES = [ + FieldType('profile_type', models.ProfileType), + ] + + +ProfileFormset = formset_factory(ProfileForm, can_delete=True, + formset=FormSetWithDeleteSwitches) +ProfileFormset.form_label = _("Profiles") +ProfileFormset.form_admin_name = _(u"Profiles") +ProfileFormset.form_slug = "profiles" + + class FinalAccountForm(forms.Form): final = True form_label = _("Confirm") diff --git a/ishtar_common/templates/ishtar/wizard/confirm_wizard.html b/ishtar_common/templates/ishtar/wizard/confirm_wizard.html index 1128e9561..401fe570c 100644 --- a/ishtar_common/templates/ishtar/wizard/confirm_wizard.html +++ b/ishtar_common/templates/ishtar/wizard/confirm_wizard.html @@ -9,7 +9,7 @@ <form action="." method="post">{% csrf_token %} <div class='form'> {% block "warning_informations" %}{% endblock %} - <p>{%if confirm_msg %}{{confirm_msg|safe}}{%else%}{% trans "You have entered the following informations:" %}{%endif%}</p> + <p>{% if confirm_msg %}{{confirm_msg|safe}}{%else%}{% trans "You have entered the following informations:" %}{%endif%}</p> {% for form_label, form_data in datas %} <div class="card"> @@ -20,7 +20,7 @@ <div class="card-body form-row"> <table class='table'> {% for data in form_data %} - <tr{%if data.2%} class='{{data.2}}'{%endif%}><th>{{data.0}}</th><td>{{data.1}}</td></tr> + <tr{% if data.2 %} class='{{data.2}}'{%endif%}><th>{{data.0}}</th><td>{{data.1}}</td></tr> {% endfor %} </table> @@ -29,8 +29,8 @@ {% endfor %} -{{wizard.management_form}} - {%if not wizard.form.is_hidden %} + {{wizard.management_form}} + {% if not wizard.form.is_hidden %} <table> {{ wizard.form.as_table }} </table> diff --git a/ishtar_common/views.py b/ishtar_common/views.py index 863722ac8..2023df305 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -193,6 +193,7 @@ organization_deletion_wizard = wizards.OrganizationDeletionWizard.as_view( account_wizard_steps = [ ('selec-account_management', forms.PersonUserFormSelection), ('account-account_management', forms.AccountForm), + ('profile-account_management', forms.ProfileFormset), ('final-account_management', forms.FinalAccountForm)] account_management_wizard = wizards.AccountWizard.as_view( diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py index 2df06cf21..60e5fc016 100644 --- a/ishtar_common/widgets.py +++ b/ishtar_common/widgets.py @@ -261,19 +261,35 @@ class DeleteWidget(forms.CheckboxInput): class SwitchWidget(forms.CheckboxInput): + extra_class = "" + extra_label = "" + def render(self, name, value, attrs=None, renderer=None): + extra_class = (" " + self.extra_class) if self.extra_class else "" + default = {"name": name, "value": "1", + 'class': "switch" + extra_class, + 'type': 'checkbox'} + if value: + default['checked'] = 'checked' attrs = self.build_attrs( - attrs, {"name": name, "value": '0', - 'class': "switch", - 'type': 'checkbox'} + attrs, default ) final_attrs = flatatt(attrs) - output = u"""<span class="switch"> - <input{}> -</span>""".format(final_attrs, attrs['id']) + extra_label = "" + if self.extra_label: + extra_label = '<label for="{}">{}</label>'.format(attrs['id'], + self.extra_label) + output = u"""<span class="switch{}"> + <input{}>{} +</span>""".format(extra_class, final_attrs, extra_label) return mark_safe(output) +class DeleteSwitchWidget(SwitchWidget): + extra_class = "danger" + extra_label = _(u"Delete") + + class ImageFileInput(ClearableFileInput): template_name = 'widgets/image_input.html' NO_FORM_CONTROL = True diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py index d486474d8..68ca640a0 100644 --- a/ishtar_common/wizards.py +++ b/ishtar_common/wizards.py @@ -39,6 +39,7 @@ from django.forms import ValidationError from django.shortcuts import redirect, render from django.template import loader from django.utils.translation import ugettext_lazy as _ +from django.utils.safestring import mark_safe from ishtar_common import models from ishtar_common.forms import CustomForm @@ -136,6 +137,7 @@ class Wizard(NamedUrlWizardView): ignore_init_steps = [] file_storage = default_storage main_item_select_keys = ('selec-',) + formset_pop_deleted = True saved_args = {} # argument to pass on object save @@ -347,7 +349,8 @@ class Wizard(NamedUrlWizardView): """Get the data to present in the last page""" datas = [] for form in forms: - base_form = hasattr(form, 'forms') and form.forms[0] or form + is_formset = hasattr(form, 'forms') + base_form = is_formset and form.forms[0] or form associated_models = hasattr(base_form, 'associated_models') and \ base_form.associated_models or {} if not hasattr(form, 'cleaned_data') and hasattr(form, 'forms'): @@ -368,10 +371,10 @@ class Wizard(NamedUrlWizardView): for cleaned_data in cleaned_datas: if not cleaned_data: continue - if form_datas: - form_datas.append(("", "", "spacer")) + current_form_data = [] items = hasattr(base_form, 'fields') and \ base_form.fields.keys() or cleaned_data.keys() + is_deleted = False for key in items: lbl = None if key.startswith('hidden_'): @@ -382,10 +385,13 @@ class Wizard(NamedUrlWizardView): if hasattr(base_form, 'associated_labels') \ and key in base_form.associated_labels: lbl = base_form.associated_labels[key] - if not lbl or key not in cleaned_data: + if key not in cleaned_data: # no value continue value = cleaned_data[key] - if value is None or value == '': + if key == "DELETE" and value: + is_deleted = True + # no display when no label or no value + if not lbl.strip() or value is None or value == '': continue if key in self.translated_keys: value = _(value) @@ -412,9 +418,32 @@ class Wizard(NamedUrlWizardView): value = unicode(item) rendered_values.append(value) value = u" ; ".join(rendered_values) - form_datas.append((lbl, value, '')) - if form_datas: - datas.append((form.form_label, form_datas)) + current_form_data.append((lbl, value, '')) + + if is_formset: + # regroup each line + displayed_values = [] + for lbl, value, cls in current_form_data: + displayed_value = u"" + if lbl.strip(): + displayed_value = u"<strong>{}{}</strong> ".format( + lbl, _(u":")) + displayed_value += unicode(value) + displayed_values.append(displayed_value) + value = u" ; ".join(displayed_values) + if is_deleted: + value = u"<span class='text-danger'>{}</span>".format( + value) + deleted = u"<span class='text-danger'>{}</span>".format( + _(u"Deleted")) if is_deleted else "" + form_datas.append((mark_safe(deleted), mark_safe(value), + '')) + else: + form_datas += current_form_data + + if not form_datas: + continue + datas.append((form.form_label, form_datas)) return datas def get_extra_model(self, dct, form_list): @@ -832,24 +861,25 @@ class Wizard(NamedUrlWizardView): # manage deletion to_delete, not_to_delete = self.get_deleted(data.keys()) # raz deleted fields - for key in data.keys(): - items = key.split('-') - if len(items) < 2 or items[-2] not in to_delete: - continue - data.pop(key) - if to_delete: - # reorganize - for idx, number in enumerate(sorted(not_to_delete, - key=lambda x: int(x))): - idx = unicode(idx) - if idx == number: + if self.formset_pop_deleted: + for key in data.keys(): + items = key.split('-') + if len(items) < 2 or items[-2] not in to_delete: continue - for key in data.keys(): - items = key.split('-') - if len(items) > 2 and number == items[-2]: - items[-2] = unicode(idx) - k = u'-'.join(items) - data[k] = data.pop(key)[0] + data.pop(key) + if to_delete: + # reorganize + for idx, number in enumerate( + sorted(not_to_delete, key=lambda x: int(x))): + idx = unicode(idx) + if idx == number: + continue + for key in data.keys(): + items = key.split('-') + if len(items) > 2 and number == items[-2]: + items[-2] = unicode(idx) + k = u'-'.join(items) + data[k] = data.pop(key)[0] # get a form key frm = form.form if callable(frm): @@ -914,7 +944,6 @@ class Wizard(NamedUrlWizardView): if frm.fields[key].widget.source_full is not None: frm.fields[key].widget.source_full = unicode( frm.fields[key].widget.source_full) + "own/" - return form def render_next_step(self, form, **kwargs): @@ -926,8 +955,9 @@ class Wizard(NamedUrlWizardView): request = self.request if request.POST.get('formset_modify') \ or request.POST.get('formset_add') \ - or [key for key in request.POST.keys() - if key.endswith('DELETE') and request.POST[key]]: + or (self.formset_pop_deleted and [ + key for key in request.POST.keys() + if key.endswith('DELETE') and request.POST[key]]): return self.render(form) elif 'validate_and_end' in request.POST \ and request.POST['validate_and_end']: @@ -1382,6 +1412,7 @@ class OrganizationDeletionWizard(DeletionWizard): class AccountWizard(Wizard): + formset_pop_deleted = False model = models.Person def get_formated_datas(self, forms): @@ -1398,23 +1429,26 @@ class AccountWizard(Wizard): """ Save the account """ + form_dict = kwargs['form_dict'] + + main_form = form_dict['account-account_management'] + if not main_form.is_valid(): + return self.render(main_form) + dct = {} - for form in form_list: - if not form.is_valid(): - return self.render(form) - associated_models = hasattr(form, 'associated_models') and \ - form.associated_models or {} - if type(form.cleaned_data) == dict: - for key in form.cleaned_data: - if key == 'pk': - continue - value = form.cleaned_data[key] - if key in associated_models and value: - value = associated_models[key].objects.get(pk=value) - dct[key] = value + associated_models = main_form.associated_models + if type(main_form.cleaned_data) == dict: + for key in main_form.cleaned_data: + if key == 'pk': + continue + value = main_form.cleaned_data[key] + if key in associated_models and value: + value = associated_models[key].objects.get(pk=value) + dct[key] = value person = self.get_current_object() if not person: - return self.render(form) + return self.render(form_dict['selec-account_management']) + for key in dct.keys(): if key.startswith('hidden_password'): dct['password'] = dct.pop(key) @@ -1441,10 +1475,14 @@ class AccountWizard(Wizard): account.set_password(dct['password']) account.save() - if 'send_password' in dct and dct['send_password'] and \ - settings.ADMINS: - site = Site.objects.get_current() + profile_form = form_dict['profile-account_management'] + for form in profile_form: + print(form.cleaned_data) + final_form = form_dict['final-account_management'] + if settings.ADMINS and type(final_form.cleaned_data) == dict and \ + final_form.cleaned_data.get('send_password', None): + site = Site.objects.get_current() app_name = site and ("Ishtar - " + site.name) \ or "Ishtar" context = { |