diff options
| -rw-r--r-- | ishtar/ishtar_base/forms.py | 597 | ||||
| -rw-r--r-- | ishtar/ishtar_base/forms_common.py | 25 | ||||
| -rw-r--r-- | ishtar/ishtar_base/forms_main.py | 8 | ||||
| -rw-r--r-- | ishtar/ishtar_base/management/commands/generate_rights.py | 12 | ||||
| -rw-r--r-- | ishtar/ishtar_base/urls.py | 159 | ||||
| -rw-r--r-- | ishtar/ishtar_base/views.py | 627 | ||||
| -rw-r--r-- | ishtar/templates/ishtar/wizard/confirm_wizard.html (renamed from ishtar/templates/confirm_wizard.html) | 5 | ||||
| -rw-r--r-- | ishtar/templates/ishtar/wizard/default_wizard.html (renamed from ishtar/templates/default_wizard.html) | 12 | ||||
| -rw-r--r-- | ishtar/urls.py | 2 | 
9 files changed, 750 insertions, 697 deletions
diff --git a/ishtar/ishtar_base/forms.py b/ishtar/ishtar_base/forms.py index d947b43ae..3d6f3f503 100644 --- a/ishtar/ishtar_base/forms.py +++ b/ishtar/ishtar_base/forms.py @@ -40,7 +40,18 @@ from django.forms.formsets import formset_factory, BaseFormSet, \  from django.contrib.auth.models import User  from django.contrib.sites.models import Site -from formwizard.forms import NamedUrlSessionFormWizard +# from formwizard.forms import NamedUrlSessionFormWizard + +class NamedUrlSessionFormWizard(forms.Form): +    def __init__(self, form_list, condition_list={}, url_name=''): +        self.form_list = dict(form_list) +        self.condition_list = condition_list +        self.url_name = url_name +        super(NamedUrlSessionFormWizard, self).__init__(self) + + +    def rindex(self, idx): +        return self.url_name.rindex(idx)  import models  import widgets @@ -90,6 +101,7 @@ class FormSet(BaseFormSet):          form.fields[DELETION_FIELD_NAME].label = ''          form.fields[DELETION_FIELD_NAME].widget = widgets.DeleteWidget() +'''  class SearchWizard(NamedUrlSessionFormWizard):      model = None @@ -103,587 +115,6 @@ class SearchWizard(NamedUrlSessionFormWizard):          templates = ['search.html']          return templates -class Wizard(NamedUrlSessionFormWizard): -    model = None -    modification = None # True when the wizard modify an item - -    @staticmethod -    def _check_right(step, condition=True): -        '''Return a method to check the right for a specific step''' -        def check_right(self, request, storage): -            cond = condition -            if callable(condition): -                cond = condition(self, request, storage) -            if not cond: -                return False -            person_type = request.user.ishtaruser.person.person_type -            if person_type.txt_idx == 'administrator': -                return True -            if person_type.rights.filter(url_name=step).count(): -                return True -        return check_right - -    def __init__(self, *args, **kwargs): -        """Check right for each step of the wizard""" -        super(Wizard, self).__init__(*args, **kwargs) -        for form_key in self.form_list.keys()[:-1]: -            condition = True -            if form_key in self.condition_list: -                condition = self.condition_list.get(form_key, True) -            cond = self._check_right(form_key, condition) -            self.condition_list[form_key] = cond - -    def get_wizard_name(self): -        """As the class name can interfere when reused, use the url_name""" -        return self.url_name - -    def get_template(self, request, storage): -        templates = ['default_wizard.html'] -        current_step = storage.get_current_step() or self.get_first_step( -                                                            request, storage) -        if current_step == self.get_last_step(request, storage): -            templates = ['confirm_wizard.html'] + templates -        return templates - -    def get_template_context(self, request, storage, form=None): -        """Add previous, next and current steps to manage the wizard path""" -        context = super(Wizard, self).get_template_context(request, storage, -                                                           form) -        step = self.get_first_step(request, storage) -        current_step = storage.get_current_step() or self.get_first_step( -                                                            request, storage) -        context.update({'current_step':self.form_list[current_step]}) -        if step == current_step: -            return context -        previous_steps, next_steps, previous_step_counter = [], [], 0 -        while step: -            if step == current_step: -                break -            previous_steps.append(self.form_list[step]) -            step = self.get_next_step(request, storage, step) -            previous_step_counter += 1 -        context.update({'previous_steps':previous_steps, -                        'previous_step_counter':previous_step_counter}) -        # if modification: show the next steps -        if self.modification: -            next_step = step -            while next_step: -                # check if the form is initialized otherwise initialize it -                if not storage.get_step_data(next_step): -                    values = self.get_form_initial(request, storage, next_step) -                    prefixed_values = {} -                    if not isinstance(values, list): -                        for key in values: -                            form_key = next_step + '-' + key -                            prefixed_values[form_key] = values[key] -                    else: -                        for formset_idx, v in enumerate(values): -                            prefix = u"-%d-" % formset_idx -                            for key in v: -                                form_key = next_step + prefix + key -                                prefixed_values[form_key] = v[key] -                    storage.set_step_data(next_step, prefixed_values) -                if step != next_step: # if not current step -                    next_steps.append(self.form_list[next_step]) -                next_step = self.get_next_step(request, storage, next_step) -        context.update({'next_steps':next_steps}) -        # not last step: validation -        if step != self.get_last_step(request, storage): -            return context -        final_form_list = [] -        for form_key in self.get_form_list(request, storage).keys(): -            form_obj = self.get_form(request, storage, step=form_key, -                    data=storage.get_step_data(form_key), -                    files=storage.get_step_files(form_key)) -            form_obj.is_valid() -            final_form_list.append(form_obj) -        last_form = final_form_list[-1] -        context.update({'datas':self.get_formated_datas(final_form_list)}) -        if hasattr(last_form, 'confirm_msg'): -            context.update({'confirm_msg':last_form.confirm_msg}) -        if hasattr(last_form, 'confirm_end_msg'): -            context.update({'confirm_end_msg':last_form.confirm_end_msg}) -        return context - -    def get_formated_datas(self, forms): -        """Get the data to present in the last page""" -        datas = [] -        for form in forms: -            form_datas = [] -            base_form = hasattr(form, 'forms') 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'): -                cleaned_datas = [frm.cleaned_data for frm in form.forms -                                                  if frm.is_valid()] -                if not cleaned_datas: -                    continue -            elif not hasattr(form, 'cleaned_data'): -                continue -            else: -                cleaned_datas = type(form.cleaned_data) == list and \ -                                              form.cleaned_data \ -                            or [form.cleaned_data] -            for cleaned_data in cleaned_datas: -                if not cleaned_data: -                    continue -                if form_datas: -                    form_datas.append(("", "", "spacer")) -                items = hasattr(base_form, 'fields') and \ -                        base_form.fields.keyOrder or cleaned_data.keys() -                for key in items: -                    lbl = None -                    if key.startswith('hidden_'): -                        continue -                    if hasattr(base_form, 'fields') and key in base_form.fields: -                        lbl = base_form.fields[key].label -                        if hasattr(base_form, 'associated_labels') \ -                           and key in base_form.associated_labels: -                            lbl = base_form.associated_labels[key] -                    if not lbl: -                        continue -                    value = cleaned_data[key] -                    if not value and value != False: -                        continue -                    if type(value) == bool: -                        if value == True: -                            value = _(u"Yes") -                        elif value == False: -                            value = _(u"No") -                    elif key in associated_models: -                        values = [] -                        if "," in unicode(value): -                            values = unicode(value).split(",") -                        else: -                            values = [value] -                        rendered_values = [] -                        for val in values: -                            item = associated_models[key].objects.get(pk=val) -                            if hasattr(item, 'short_label'): -                                value = item.short_label() -                            else: -                                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)) -        return datas - -    def get_extra_model(self, dct, request, storage, form_list): -        dct['history_modifier'] = request.user -        return dct - -    def done(self, request, storage, form_list, return_object=False, **kwargs): -        """Save to the model""" -        dct, m2m, whole_associated_models = {}, [], [] -        for form in form_list: -            if not form.is_valid(): -                return self.render(request, storage, form) -            base_form = hasattr(form, 'forms') and form.forms[0] or form -            associated_models = hasattr(base_form, 'associated_models') and \ -                                base_form.associated_models or {} -            if hasattr(form, 'forms'): -                multi = False -                if form.forms: -                    frm = form.forms[0] -                    if hasattr(frm, 'base_model') and frm.base_model: -                        whole_associated_models.append(frm.base_model) -                    else: -                        whole_associated_models += associated_models.keys() -                    fields = frm.fields.copy() -                    if 'DELETE' in fields: -                        fields.pop('DELETE') -                    multi = len(fields) > 1 -                    if multi: -                        assert hasattr(frm, 'base_model'), \ -                       u"Must define a base_model for " + unicode(frm.__class__) -                for frm in form.forms: -                    if not frm.is_valid(): -                        continue -                    vals = {} -                    if "DELETE" in frm.cleaned_data: -                        if frm.cleaned_data["DELETE"]: -                            continue -                        frm.cleaned_data.pop('DELETE') -                    for key in frm.cleaned_data: -                        value = frm.cleaned_data[key] -                        if not value and value != False: -                            continue -                        if key in associated_models: -                            value = associated_models[key].objects.get(pk=value) -                        if multi: -                            vals[key] = value -                        else: -                            m2m.append((key, value)) -                    if multi and vals: -                        m2m.append((frm.base_model, vals)) -            elif type(form.cleaned_data) == dict: -                for key in form.cleaned_data: -                    if key.startswith('hidden_'): -                        continue -                    value = form.cleaned_data[key] -                    if key in associated_models: -                        if value: -                            model = associated_models[key] -                            if isinstance(value, unicode) \ -                             or isinstance(value, str) and "," in value: -                                value = value.split(",") -                            if isinstance(value, list) \ -                             or isinstance(value, tuple): -                                value = [model.objects.get(pk=val) -                                         for val in value if val] -                                if len(value) == 1: -                                    value = value[0] -                            else: -                                value = model.objects.get(pk=value) -                        else: -                            value = None -                    dct[key] = value -        return self.save_model(dct, m2m, whole_associated_models, request, -                               storage, form_list, return_object) - -    def get_saved_model(self): -        """Permit a distinguo when saved model is not the base selected model""" -        return self.model - -    def get_current_saved_object(self, request, storage): -        """Permit a distinguo when saved model is not the base selected model""" -        return self.get_current_object(request, storage) - -    def save_model(self, dct, m2m, whole_associated_models, request, storage, -                   form_list, return_object): -        dct = self.get_extra_model(dct, request, storage, form_list) -        obj = self.get_current_saved_object(request, storage) -        # manage dependant items -        other_objs = {} -        for k in dct.keys(): -            if '__' not in k: -                continue -            vals = k.split('__') -            assert len(vals) == 2, "Only one level of dependant item is managed" -            dependant_item, key = vals -            if dependant_item not in other_objs: -                other_objs[dependant_item] = {} -            other_objs[dependant_item][key] = dct.pop(k) -        if obj: -            for k in dct: -                if k.startswith('pk'): -                    continue -                setattr(obj, k, dct[k]) -            try: -                obj.full_clean() -            except forms.ValidationError, msg: -                return self.render(request, storage, form_list[-1]) -            for dependant_item in other_objs: -                c_item = getattr(obj, dependant_item) -                # manage ManyToMany if only one associated -                if hasattr(c_item, "all"): -                    c_items = c_item.all() -                    if len(c_items) != 1: -                        continue -                    c_item = c_items[0] -                if c_item: -                    # to check # -                    for k in other_objs[dependant_item]: -                        setattr(c_item, k, other_objs[dependant_item][k]) -                    c_item.save() -                else: -                    m = getattr(self.model, dependant_item) -                    if hasattr(m, 'related'): -                        c_item = m.related.model(**other_objs[dependant_item]) -                        setattr(obj, dependant_item, c_item) -                    obj.save() -            obj.save() -        else: -            adds = {} -            for dependant_item in other_objs: -                m = getattr(self.model, dependant_item) -                model = m.field.rel.to -                c_dct = other_objs[dependant_item].copy() -                if issubclass(model, models.BaseHistorizedItem): -                    c_dct['history_modifier'] = request.user -                c_item = model(**c_dct) -                c_item.save() -                if hasattr(m, 'through'): -                    adds[dependant_item] = c_item -                elif hasattr(m, 'field'): -                    dct[dependant_item] = c_item -            if 'pk' in dct: -                dct.pop('pk') -            obj = self.get_saved_model()(**dct) -            try: -                obj.full_clean() -            except forms.ValidationError, msg: -                return self.render(request, storage, form_list[-1]) -            obj.save() -            for k in adds: -                getattr(obj, k).add(adds[k]) -            # necessary to manage interaction between models like -            # material_index management for baseitems -            obj.save() -        m2m_items = {} -        for model in whole_associated_models: -            getattr(obj, model+'s').clear() -        for key, value in m2m: -            if key not in m2m_items: -                if type(key) == dict: -                    vals = [] -                    for item in getattr(obj, key+'s').all(): -                        v = {} -                        for k in value.keys(): -                            v[k] = getattr(item, k) -                        vals.append(v) -                    m2m_items[key] = vals -                else: -                    m2m_items[key] = getattr(obj, key+'s').all() -            if value not in m2m_items[key]: -                if type(value) == dict: -                    model = getattr(obj, key+'s').model -                    if issubclass(model, models.BaseHistorizedItem): -                        value['history_modifier'] = request.user -                    value = model.objects.create(**value) -                    value.save() -                getattr(obj, key+'s').add(value) -                # necessary to manage interaction between models like -                # material_index management for baseitems -                obj.save() -        res = render_to_response('wizard_done.html', {}, -                                  context_instance=RequestContext(request)) -        return return_object and (obj, res) or res - -    def get_deleted(self, keys): -        """Get the deleted and non-deleted items in formsets""" -        not_to_delete, to_delete = set(), set() -        for key in keys: -            items = key.split('-') -            if len(items) < 2 or items[-2] in to_delete: -                continue -            idx = items[-2] -            try: -                int(idx) -            except: -                continue -            if items[-1] == u'DELETE': -                to_delete.add(idx) -                if idx in not_to_delete: -                    not_to_delete.remove(idx) -            elif idx not in not_to_delete: -                not_to_delete.add(idx) -        return (to_delete, not_to_delete) - -    def get_form(self, request, storage, step=None, data=None, files=None): -        """Manage formset""" -        if data: -            data = data.copy() -            if not step: -                step = self.determine_step(request, storage) -            form = self.get_form_list(request, storage)[step] -            if hasattr(form, 'management_form'): -                # 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)): -                        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 -                base_key = form.form.base_fields.keys()[0] -                init = self.get_form_initial(request, storage, step) -                total_field = len([key for key in data.keys() -                                        if base_key in key.split('-') -                                           and data[key]]) -                if init and not to_delete: -                    total_field = max((total_field, len(init))) -                data[step + u'-INITIAL_FORMS'] = unicode(total_field) -                data[step + u'-TOTAL_FORMS'] = unicode(total_field + 1) -        data = data or None -        form = super(Wizard, self).get_form(request, storage, step, data, files) -        return form - -    def render_next_step(self, request, storage, form, **kwargs): -        """ -        Manage: -         - modify or delete button in formset: next step = current step -         - validate and end: nextstep = last step -        """ -        if request.POST.has_key('formset_modify') \ -           and request.POST['formset_modify'] \ -           or [key for key in request.POST.keys() -               if key.endswith('DELETE') and request.POST[key]]: -            return self.render(request, storage, form, **kwargs) -        elif request.POST.has_key('validate_and_end') \ -           and request.POST['validate_and_end']: -            last_step = self.get_last_step(request, storage) -            new_form = self.get_form(request, storage, last_step, -                data=storage.get_step_data(last_step), -                files=storage.get_step_files(last_step)) -            storage.set_current_step(last_step) -            return self.render(request, storage, new_form, **kwargs) -        return super(Wizard, self).render_next_step(request, storage, form, -                                                    **kwargs) - -    def process_post_request(self, request, storage, *args, **kwargs): -        """Convert numerical step number to step name""" -        post_data = request.POST.copy() -        if request.POST.has_key('form_prev_step'): -            try: -                step_number = int(request.POST['form_prev_step']) -                post_data['form_prev_step'] = self.get_form_list(request, -                                                   storage).keys()[step_number] -            except ValueError: -                pass -        request.POST = post_data -        return super(Wizard, self).process_post_request(request, storage, *args, -                                                        **kwargs) - -    @classmethod -    def session_has_key(cls, request, storage, form_key, key=None, multi=None): -        """Check if the session has value of a specific form and (if provided) -        of a key -        """ -        test = storage.prefix in request.session \ -          and 'step_data' in request.session[storage.prefix] \ -          and form_key in request.session[storage.prefix]['step_data'] -        if not key or not test: -            return test -        key = key.startswith(form_key) and key or \ -              not multi and form_key + '-' + key or \ -              form_key + '-0-' + key #only check if the first field is available -        return key in request.session[storage.prefix]['step_data'][form_key] - -    @classmethod -    def session_get_value(cls, request, storage, form_key, key, multi=False): -        """Get the value of a specific form""" -        if not cls.session_has_key(request, storage, form_key, key, multi): -            return -        if not multi: -            key = key.startswith(form_key) and key or form_key + '-' + key -            return request.session[storage.prefix]['step_data'][form_key][key] -        vals = [] -        for k in request.session[storage.prefix]['step_data'][form_key]: -            if k.startswith(form_key) and k.endswith(key) and \ -               request.session[storage.prefix]['step_data'][form_key][k]: -                vals.append(request.session[storage.prefix]['step_data']\ -                                           [form_key][k]) -        return vals - -    def get_current_object(self, request, storage): -        """Get the current object for an instancied wizard""" -        current_obj = None -        main_form_key = 'selec-' + self.url_name -        try: -            idx = int(self.session_get_value(request, storage, main_form_key, -                                             'pk')) -            current_obj = self.model.objects.get(pk=idx) -        except(TypeError, ValueError, ObjectDoesNotExist): -            pass -        return current_obj - -    def get_form_initial(self, request, storage, step): -        current_obj = self.get_current_object(request, storage) -        current_step = storage.get_current_step() or self.get_first_step( -                                                            request, storage) -        if step.startswith('selec-') and step in self.form_list \ -           and 'pk' in self.form_list[step].associated_models: -            model_name = self.form_list[step].associated_models['pk' -                                              ].__name__.lower() -            if step == current_step: -                self.reset_wizard(request, storage) -            val = model_name in request.session and request.session[model_name] -            if val: -                return {'pk':val} -        elif current_obj: -            return self.get_instanced_init(current_obj, request, storage, -                                           step) -        current_form = self.form_list[current_step] -        if hasattr(current_form, 'currents'): -            initial = {} -            for key in current_form.currents: -                model_name = current_form.currents[key].__name__.lower() -                val = model_name in request.session and \ -                      request.session[model_name] -                if val: -                    initial[key] = val -            if initial: -                return initial -        return super(Wizard, self).get_form_initial(request, storage, step) - -    def get_instanced_init(self, obj, request, storage, step=None): -        """Get initial data from an init""" -        current_step = step or  storage.get_current_step() \ -                       or self.get_first_step(request, storage) -        c_form = self.form_list[current_step] -        # make the current object the default item for the session -        obj_name = obj.__class__.__name__.lower() -        # prefer a specialized name if available -        prefixes = storage.prefix.split('_') -        if len(prefixes) > 1 and prefixes[-2].startswith(obj_name): -            obj_name = prefixes[-2] -        request.session[obj_name] = unicode(obj.pk) -        initial = {} -        if request.POST or (step in request.session[storage.prefix] and\ -           request.session[storage.prefix]['step_data'][step]): -            return {} -        if hasattr(c_form, 'base_fields'): -            for base_field in c_form.base_fields.keys(): -                fields = base_field.split('__') -                value = obj -                for field in fields: -                    if not hasattr(value, field) or \ -                       getattr(value, field) == None: -                        value = obj -                        break -                    value = getattr(value, field) -                if value == obj: -                    continue -                if hasattr(value, 'pk'): -                    value = value.pk -                if value in (True, False): -                    initial[base_field] = value -                elif value != None: -                    initial[base_field] = unicode(value) -        elif hasattr(c_form, 'management_form'): -            initial = [] -            if hasattr(c_form.form, 'base_model'): -                key = c_form.form.base_model + 's' -            else: -                key = current_step.split('-')[0] -            if not hasattr(obj, key): -                return initial -            keys = c_form.form.base_fields.keys() -            for child_obj in getattr(obj, key).order_by('pk').all(): -                if not keys: -                    break -                vals = {} -                if len(keys) == 1: -                    # only one field: must be the id of the object -                    vals[keys[0]] = unicode(child_obj.pk) -                else: -                    for field in keys: -                        if hasattr(child_obj, field): -                            value = getattr(child_obj, field) -                            if hasattr(value, 'pk'): -                                value = value.pk -                            if value != None: -                                vals[field] = unicode(value) -                if vals: -                    initial.append(vals) -        return initial -  def get_now():      format = formats.get_format('DATE_INPUT_FORMATS')[0]      value = datetime.datetime.now().strftime(format) @@ -815,4 +246,4 @@ def get_form_selection(class_name, label, key, model, base_form, get_url,          return cleaned_data      attrs['clean'] = clean      return type(class_name, (forms.Form,), attrs) - +''' diff --git a/ishtar/ishtar_base/forms_common.py b/ishtar/ishtar_base/forms_common.py index 68ab9be5f..7ef1d4070 100644 --- a/ishtar/ishtar_base/forms_common.py +++ b/ishtar/ishtar_base/forms_common.py @@ -38,8 +38,7 @@ from ishtar import settings  import models  import widgets -from forms import Wizard, SearchWizard, FinalForm, FormSet, reverse_lazy, \ -                  name_validator +from forms import FinalForm, FormSet, reverse_lazy, name_validator  def get_town_field(label=_(u"Town"), required=True):      help_text = _(u"<p>Type name, department code and/or postal code of the " @@ -152,9 +151,6 @@ class OrganizationForm(forms.Form):          new_item.save()          return new_item -class PersonWizard(Wizard): -    model = models.Person -  class PersonFormSelection(forms.Form):      form_label = _(u"Person search")      associated_models = {'pk':models.Person} @@ -199,14 +195,11 @@ class PersonForm(forms.Form):          new_item.save()          return new_item +'''  person_search_wizard = SearchWizard([                      ('general-person_search', PersonFormSelection)],                       url_name='person_search',) -person_creation_wizard = PersonWizard([ -                        ('identity-person_creation', PersonForm), -                        ('final-person_creation', FinalForm)], -                         url_name='person_creation',)  person_modification_wizard = PersonWizard([ @@ -228,9 +221,9 @@ class AccountWizard(Wizard):          return datas      def done(self, request, storage, form_list, **kwargs): -        ''' +        """          Save the account -        ''' +        """          dct = {}          for form in form_list:              if not form.is_valid(): @@ -299,7 +292,7 @@ class AccountWizard(Wizard):              form.is_hidden = False          return form - +'''  class AccountForm(forms.Form):      form_label = _("Account")      associated_models = {'pk':models.Person} @@ -355,13 +348,13 @@ class FinalAccountForm(forms.Form):      def __init__(self, *args, **kwargs):          self.is_hidden = True          return super(FinalAccountForm, self).__init__(*args, **kwargs) - +'''  account_management_wizard = AccountWizard([                          ('selec-account_management', PersonFormSelection),                          ('account-account_management', AccountForm),                          ('final-account_management', FinalAccountForm)],                           url_name='account_management',) - +'''  class TownForm(forms.Form):      form_label = _("Towns")      base_model = 'town' @@ -432,7 +425,7 @@ ParcelFormSet.form_label = _(u"Parcels")  ######################  # Sources management #  ###################### - +'''  class SourceWizard(Wizard):      model = None      def get_extra_model(self, dct, request, storage, form_list): @@ -441,7 +434,7 @@ class SourceWizard(Wizard):          if 'history_modifier' in dct:              dct.pop('history_modifier')          return dct - +'''  class SourceForm(forms.Form):      form_label = _(u"Documentation informations")      associated_models = {'source_type':models.SourceType} diff --git a/ishtar/ishtar_base/forms_main.py b/ishtar/ishtar_base/forms_main.py index 723b80d83..29253f284 100644 --- a/ishtar/ishtar_base/forms_main.py +++ b/ishtar/ishtar_base/forms_main.py @@ -18,9 +18,9 @@  # See the file COPYING for details.  from forms_common import * -from forms_files import * -from forms_operations import * -from forms_context_records import * -from forms_items import * +#from forms_files import * +#from forms_operations import * +#from forms_context_records import * +#from forms_items import *  from forms import * diff --git a/ishtar/ishtar_base/management/commands/generate_rights.py b/ishtar/ishtar_base/management/commands/generate_rights.py index 9bf2776a8..75b1cf807 100644 --- a/ishtar/ishtar_base/management/commands/generate_rights.py +++ b/ishtar/ishtar_base/management/commands/generate_rights.py @@ -17,6 +17,8 @@  # See the file COPYING for details. +import sys +  from django.core.management.base import BaseCommand, CommandError  from django.core.exceptions import ObjectDoesNotExist @@ -40,7 +42,8 @@ class Command(BaseCommand):              except ObjectDoesNotExist:                  wizard_obj = models.Wizard.objects.create(url_name=url_name)                  wizard_obj.save() -                self.stdout.write('* Wizard "%s" added\n' % url_name) +                #self.stdout.write('* Wizard "%s" added\n' % url_name) +                sys.stdout.write('* Wizard "%s" added\n' % url_name)              wizard_steps[url_name] = []              for idx, step_url_name in enumerate(wizard.form_list.keys()):                  form = wizard.form_list[step_url_name] @@ -59,7 +62,10 @@ class Command(BaseCommand):                                          'url_name':step_url_name})                      step_obj = models.WizardStep.objects.create(**step_values)                      step_obj.save() -                    self.stdout.write('* Wizard step "%s" added\n' \ +                    #self.stdout.write('* Wizard step "%s" added\n' \ +                    #                  % unicode(form.form_label)) +                    sys.stdout.write('* Wizard step "%s" added\n' \                                        % unicode(form.form_label))                  wizard_steps[url_name].append(step_url_name) -        self.stdout.write('Successfully regeneration of wizard rights\n') +        #self.stdout.write('Successfully regeneration of wizard rights\n') +        sys.stdout.write('Successfully regeneration of wizard rights\n') diff --git a/ishtar/ishtar_base/urls.py b/ishtar/ishtar_base/urls.py index 8f511cf39..a5b1f5efa 100644 --- a/ishtar/ishtar_base/urls.py +++ b/ishtar/ishtar_base/urls.py @@ -19,9 +19,10 @@  from django.conf.urls.defaults import * -from ishtar.urls import BASE_URL  from menus import menu -import forms_main as ishtar_forms +#import forms_main as ishtar_forms + +import views  urlpatterns, actions = [], [] @@ -29,102 +30,106 @@ urlpatterns, actions = [], []  # forms  urlpatterns = patterns('',         # General -       url(BASE_URL + r'person_creation/(?P<step>.+)$', -           ishtar_forms.person_creation_wizard, name='person_creation'), -       url(BASE_URL + r'person_modification/(?P<step>.+)$', +       url(r'person_creation/(?P<step>.+)$', +           views.person_creation_wizard, name='person_creation_step'), +       url(r'person_creation/$', +           views.person_creation_wizard, name='person_creation'), +       ) +""" +       url(r'person_modification/(?P<step>.+)$',             ishtar_forms.person_modification_wizard, name='person_modification'), -       url(BASE_URL + r'account_management/(?P<step>.+)$', +       url(r'account_management/(?P<step>.+)$',             ishtar_forms.account_management_wizard, name='account_management'),         # Archaelogical files -       url(BASE_URL + r'file_search/(?P<step>.+)$', +       url(r'file_search/(?P<step>.+)$',             ishtar_forms.file_search_wizard, name='file_search'), -       url(BASE_URL + r'file_creation/(?P<step>.+)$', +       url(r'file_creation/(?P<step>.+)$',             ishtar_forms.file_creation_wizard, name='file_creation'), -       url(BASE_URL + r'file_modification/(?P<step>.+)$', +       url(r'file_modification/(?P<step>.+)$',             ishtar_forms.file_modification_wizard, name='file_modification'), -       url(BASE_URL + r'file_closing/(?P<step>.+)$', +       url(r'file_closing/(?P<step>.+)$',             ishtar_forms.file_closing_wizard, name='file_closing'), -       url(BASE_URL + r'file_deletion/(?P<step>.+)$', +       url(r'file_deletion/(?P<step>.+)$',             ishtar_forms.file_deletion_wizard, name='file_deletion'), -       url(BASE_URL + r'file_administrativeactfile/(?P<step>.+)$', +       url(r'file_administrativeactfile/(?P<step>.+)$',             ishtar_forms.file_administrativeactfile_wizard,             name='file_administrativeactfile'), -       url(BASE_URL + r'file_administrativeactfile_modification/(?P<step>.+)$', +       url(r'file_administrativeactfile_modification/(?P<step>.+)$',             ishtar_forms.file_administrativeactfile_modification_wizard,             name='file_administrativeactfile_modification'), -       url(BASE_URL + r'file_administrativeactfile_deletion/(?P<step>.+)$', +       url(r'file_administrativeactfile_deletion/(?P<step>.+)$',             ishtar_forms.file_administrativeactfile_deletion_wizard,             name='file_administrativeactfile_deletion'),         # Operations -       url(BASE_URL + r'operation_search/(?P<step>.+)$', +       url(r'operation_search/(?P<step>.+)$',             ishtar_forms.operation_search_wizard, name='operation_search'), -       url(BASE_URL + r'operation_creation/(?P<step>.+)$', +       url(r'operation_creation/(?P<step>.+)$',             ishtar_forms.operation_creation_wizard, name='operation_creation'), -       url(BASE_URL + r'operation_modification/(?P<step>.+)$', +       url(r'operation_modification/(?P<step>.+)$',             ishtar_forms.operation_modification_wizard,             name='operation_modification'), -       url(BASE_URL + r'operation_closing/(?P<step>.+)$', +       url(r'operation_closing/(?P<step>.+)$',             ishtar_forms.operation_closing_wizard, name='operation_closing'), -       url(BASE_URL + r'operation_deletion/(?P<step>.+)$', +       url(r'operation_deletion/(?P<step>.+)$',             ishtar_forms.operation_deletion_wizard, name='operation_deletion'), -       url(BASE_URL + r'operation_administrativeactop/(?P<step>.+)$', +       url(r'operation_administrativeactop/(?P<step>.+)$',             ishtar_forms.operation_administrativeactop_wizard,             name='operation_administrativeactop'), -       url(BASE_URL + r'operation_administrativeactop_modification/(?P<step>.+)$', +       url(r'operation_administrativeactop_modification/(?P<step>.+)$',             ishtar_forms.operation_administrativeactop_modification_wizard,             name='operation_administrativeactop_modification'), -       url(BASE_URL + r'operation_administrativeactop_deletion/(?P<step>.+)$', +       url(r'operation_administrativeactop_deletion/(?P<step>.+)$',             ishtar_forms.operation_administrativeactop_deletion_wizard,             name='operation_administrativeactop_deletion'), -       url(BASE_URL + r'operation_source_creation/(?P<step>.+)$', +       url(r'operation_source_creation/(?P<step>.+)$',             ishtar_forms.operation_source_creation_wizard,             name='operation_source_creation'), -       url(BASE_URL + r'operation_source_modification/(?P<step>.+)$', +       url(r'operation_source_modification/(?P<step>.+)$',             ishtar_forms.operation_source_modification_wizard,             name='operation_source_modification'), -       url(BASE_URL + r'operation_source_deletion/(?P<step>.+)$', +       url(r'operation_source_deletion/(?P<step>.+)$',             ishtar_forms.operation_source_deletion_wizard,             name='operation_source_deletion'),         # Context records -       url(BASE_URL + r'record_search/(?P<step>.+)$', +       url(r'record_search/(?P<step>.+)$',             ishtar_forms.record_search_wizard, name='record_search'), -       url(BASE_URL + r'record_creation/(?P<step>.+)$', +       url(r'record_creation/(?P<step>.+)$',             ishtar_forms.record_creation_wizard, name='record_creation'), -       url(BASE_URL + r'record_modification/(?P<step>.+)$', +       url(r'record_modification/(?P<step>.+)$',             ishtar_forms.record_modification_wizard, name='record_modification'), -       url(BASE_URL + r'record_deletion/(?P<step>.+)$', +       url(r'record_deletion/(?P<step>.+)$',             ishtar_forms.record_deletion_wizard, name='record_deletion'), -       url(BASE_URL + r'record_source_creation/(?P<step>.+)$', +       url(r'record_source_creation/(?P<step>.+)$',             ishtar_forms.record_source_creation_wizard,             name='record_source_creation'), -       url(BASE_URL + r'record_source_modification/(?P<step>.+)$', +       url(r'record_source_modification/(?P<step>.+)$',             ishtar_forms.record_source_modification_wizard,             name='record_source_modification'), -       url(BASE_URL + r'record_source_deletion/(?P<step>.+)$', +       url(r'record_source_deletion/(?P<step>.+)$',             ishtar_forms.record_source_deletion_wizard,             name='record_source_deletion'),         # Finds -       url(BASE_URL + r'item_search/(?P<step>.+)$', +       url(r'item_search/(?P<step>.+)$',             ishtar_forms.item_search_wizard, name='item_search'), -       url(BASE_URL + r'item_creation/(?P<step>.+)$', +       url(r'item_creation/(?P<step>.+)$',             ishtar_forms.item_creation_wizard, name='item_creation'), -       url(BASE_URL + r'item_modification/(?P<step>.+)$', +       url(r'item_modification/(?P<step>.+)$',             ishtar_forms.item_modification_wizard, name='item_modification'), -       url(BASE_URL + r'item_source_creation/(?P<step>.+)$', +       url(r'item_source_creation/(?P<step>.+)$',             ishtar_forms.item_source_creation_wizard,             name='item_source_creation'), -       url(BASE_URL + r'item_source_modification/(?P<step>.+)$', +       url(r'item_source_modification/(?P<step>.+)$',             ishtar_forms.item_source_modification_wizard,             name='item_source_modification'), -       url(BASE_URL + r'item_source_deletion/(?P<step>.+)$', +       url(r'item_source_deletion/(?P<step>.+)$',             ishtar_forms.item_source_deletion_wizard,             name='item_source_deletion'),         # Treatments -       url(BASE_URL + r'treatment_creation/(?P<step>.+)$', +       url(r'treatment_creation/(?P<step>.+)$',             ishtar_forms.treatment_creation_wizard, name='treatment_creation'), -       url(BASE_URL + r'warehouse_packaging/(?P<step>.+)$', +       url(r'warehouse_packaging/(?P<step>.+)$',             ishtar_forms.warehouse_packaging_wizard, name='warehouse_packaging'), -         ) +         )"""  for section in menu.childs:      for menu_item in section.childs:          if hasattr(menu_item, 'childs'): @@ -137,82 +142,82 @@ actions = r"|".join(actions)  # other views  urlpatterns += patterns('ishtar.ishtar_base.views',       # General -     url(BASE_URL + r'(?P<action_slug>' + actions + r')/$', 'action', +     url(r'(?P<action_slug>' + actions + r')/$', 'action',             name='action'), -     url(BASE_URL + r'new-person/(?P<parent_name>.+)?/$', +     url(r'new-person/(?P<parent_name>.+)?/$',             'new_person', name='new-person'), -     url(BASE_URL + r'autocomplete-person/([0-9_]+)?$', 'autocomplete_person', +     url(r'autocomplete-person/([0-9_]+)?$', 'autocomplete_person',             name='autocomplete-person'), -     url(BASE_URL + r'autocomplete-town/$', 'autocomplete_town', +     url(r'autocomplete-town/$', 'autocomplete_town',             name='autocomplete-town'), -     url(BASE_URL + r'new-author/(?P<parent_name>.+)?/$', +     url(r'new-author/(?P<parent_name>.+)?/$',             'new_author', name='new-author'), -     url(BASE_URL + r'autocomplete-author/$', 'autocomplete_author', +     url(r'autocomplete-author/$', 'autocomplete_author',             name='autocomplete-author'), -     url(BASE_URL + r'new-organization/(?P<parent_name>.+)?/$', +     url(r'new-organization/(?P<parent_name>.+)?/$',             'new_organization', name='new-organization'), -     url(BASE_URL + r'autocomplete-organization/([0-9_]+)?$', +     url(r'autocomplete-organization/([0-9_]+)?$',             'autocomplete_organization', name='autocomplete-organization'), -     url(BASE_URL + r'new-warehouse/(?P<parent_name>.+)?/$', +     url(r'new-warehouse/(?P<parent_name>.+)?/$',             'new_warehouse', name='new-warehouse'), -     url(BASE_URL + r'autocomplete-warehouse/$', 'autocomplete_warehouse', +     url(r'autocomplete-warehouse/$', 'autocomplete_warehouse',             name='autocomplete-warehouse'),       # Archaelogical files -     url(BASE_URL + r'autocomplete-file/$', 'autocomplete_file', +     url(r'autocomplete-file/$', 'autocomplete_file',             name='autocomplete-file'), -     url(BASE_URL + r'get-file/(?P<type>.+)?$', 'get_file', +     url(r'get-file/(?P<type>.+)?$', 'get_file',             name='get-file'), -     url(BASE_URL + r'get-file-full/(?P<type>.+)?$', 'get_file', +     url(r'get-file-full/(?P<type>.+)?$', 'get_file',             name='get-file-full', kwargs={'full':True}), -     url(BASE_URL + r'get-administrativeactfile/(?P<type>.+)?$', +     url(r'get-administrativeactfile/(?P<type>.+)?$',             'get_administrativeactfile', name='get-administrativeactfile'), -     url(BASE_URL + r'show-file/(?P<pk>.+)?/(?P<type>.+)?$', 'show_file', +     url(r'show-file/(?P<pk>.+)?/(?P<type>.+)?$', 'show_file',             name='show-file'), -     url(BASE_URL + r'show-historized-file/(?P<pk>.+)?/(?P<date>.+)?$', +     url(r'show-historized-file/(?P<pk>.+)?/(?P<date>.+)?$',             'show_file', name='show-historized-file'), -     url(BASE_URL + r'revert-file/(?P<pk>.+)/(?P<date>.+)$', +     url(r'revert-file/(?P<pk>.+)/(?P<date>.+)$',             'revert_file', name='revert-file'),       # Operations -     url(BASE_URL + r'autocomplete-operation/$', 'autocomplete_operation', +     url(r'autocomplete-operation/$', 'autocomplete_operation',             name='autocomplete-operation'), -     url(BASE_URL + r'get-operation/(?P<type>.+)?$', 'get_operation', +     url(r'get-operation/(?P<type>.+)?$', 'get_operation',             name='get-operation'), -     url(BASE_URL + r'get-operation-full/(?P<type>.+)?$', 'get_operation', +     url(r'get-operation-full/(?P<type>.+)?$', 'get_operation',             name='get-operation-full', kwargs={'full':True}), -     url(BASE_URL + r'get-available-operation-code/(?P<year>.+)?$', +     url(r'get-available-operation-code/(?P<year>.+)?$',             'get_available_operation_code', name='get_available_operation_code'), -     url(BASE_URL + r'revert-operation/(?P<pk>.+)/(?P<date>.+)$', +     url(r'revert-operation/(?P<pk>.+)/(?P<date>.+)$',             'revert_operation', name='revert-operation'), -     url(BASE_URL + r'show-operation/(?P<pk>.+)?/(?P<type>.+)?$', +     url(r'show-operation/(?P<pk>.+)?/(?P<type>.+)?$',             'show_operation', name='show-operation'), -     url(BASE_URL + r'get-administrativeactop/(?P<type>.+)?$', +     url(r'get-administrativeactop/(?P<type>.+)?$',             'get_administrativeactop', name='get-administrativeactop'), -     url(BASE_URL + r'get-operationsource/(?P<type>.+)?$', +     url(r'get-operationsource/(?P<type>.+)?$',             'get_operationsource', name='get-operationsource'),       # Context records -     url(BASE_URL + r'show-contextrecord/(?P<pk>.+)?/(?P<type>.+)?$', +     url(r'show-contextrecord/(?P<pk>.+)?/(?P<type>.+)?$',             'show_contextrecord', name='show-contextrecord'), -     url(BASE_URL + r'get-contextrecord/(?P<type>.+)?$', 'get_contextrecord', +     url(r'get-contextrecord/(?P<type>.+)?$', 'get_contextrecord',             name='get-contextrecord'), -     url(BASE_URL + r'get-contextrecord-full/(?P<type>.+)?$', +     url(r'get-contextrecord-full/(?P<type>.+)?$',             'get_contextrecord', name='get-contextrecord-full',             kwargs={'full':True}), -     url(BASE_URL + r'get-contexrecordsource/(?P<type>.+)?$', +     url(r'get-contexrecordsource/(?P<type>.+)?$',             'get_contextrecordsource', name='get-contextrecordsource'),       # Finds -     url(BASE_URL + r'update-current-item/$', 'update_current_item', +     url(r'update-current-item/$', 'update_current_item',             name='update-current-item'), -     url(BASE_URL + r'get-item/(?P<type>.+)?$', 'get_archaeologicalitem', +     url(r'get-item/(?P<type>.+)?$', 'get_archaeologicalitem',             name='get-item'), -     url(BASE_URL + r'get-item-full/(?P<type>.+)?$', 'get_archaeologicalitem', +     url(r'get-item-full/(?P<type>.+)?$', 'get_archaeologicalitem',             name='get-item-full', kwargs={'full':True}), -     url(BASE_URL + r'get-itemsource/(?P<type>.+)?$', +     url(r'get-itemsource/(?P<type>.+)?$',             'get_itemsource', name='get-itemsource'), -     url(BASE_URL + r'get-container/$', 'get_container', +     url(r'get-container/$', 'get_container',             name='get-container'),       # Treatments -     url(BASE_URL + r'autocomplete-container/?$', +     url(r'autocomplete-container/?$',             'autocomplete_container', name='autocomplete-container'), -     url(BASE_URL + r'new-container/(?P<parent_name>.+)?/$', +     url(r'new-container/(?P<parent_name>.+)?/$',             'new_container', name='new-container'),  ) diff --git a/ishtar/ishtar_base/views.py b/ishtar/ishtar_base/views.py index 94a37d46e..4a7f276fb 100644 --- a/ishtar/ishtar_base/views.py +++ b/ishtar/ishtar_base/views.py @@ -17,7 +17,11 @@  # See the file COPYING for details. -import tidy +try: +    import tidy +except: +    from tidylib import tidy_document as tidy +  import re  import csv  import json @@ -27,15 +31,16 @@ import cStringIO as StringIO  from tempfile import NamedTemporaryFile  import ho.pisa as pisa +from django.contrib.formtools.wizard.views import NamedUrlWizardView +from django.core import serializers +from django.core.exceptions import ObjectDoesNotExist +from django.core.urlresolvers import reverse, NoReverseMatch +from django.db.models import Q  from django.http import HttpResponse, Http404 +from django.shortcuts import render_to_response, redirect  from django.template import RequestContext, loader  from django.template.defaultfilters import slugify -from django.shortcuts import render_to_response, redirect  from django.utils.translation import ugettext, ugettext_lazy as _ -from django.core.exceptions import ObjectDoesNotExist -from django.core.urlresolvers import reverse, NoReverseMatch -from django.db.models import Q -from django.core import serializers  from ishtar import settings  if settings.XHTML2ODT_PATH: @@ -45,6 +50,9 @@ if settings.XHTML2ODT_PATH:  from menus import menu  import forms_main as ishtar_forms + +from ishtar.ishtar_base.forms import FinalForm +from ishtar.ishtar_base.forms_common import PersonForm  import models  CSV_OPTIONS = {'delimiter':';', 'quotechar':'"', 'quoting':csv.QUOTE_ALL} @@ -58,6 +66,613 @@ def index(request):      return render_to_response('index.html', dct,                                context_instance=RequestContext(request)) +class Wizard(NamedUrlWizardView): +    model = None +    modification = None # True when the wizard modify an item +    storage_name = 'django.contrib.formtools.wizard.storage.session.SessionStorage' + +    @staticmethod +    def _check_right(step, condition=True): +        '''Return a method to check the right for a specific step''' +        """ +        def check_right(self, request, storage): +            cond = condition +            if callable(condition): +                cond = condition(self, request, storage) +            if not cond: +                return False +            person_type = request.user.ishtaruser.person.person_type +            if person_type.txt_idx == 'administrator': +                return True +            if person_type.rights.filter(url_name=step).count(): +                return True""" +        def check_right(self): +            cond = condition +            if callable(condition): +                cond = condition(self) +            if not cond: +                return False +            person_type = self.request.user.ishtaruser.person.person_type +            if person_type.txt_idx == 'administrator': +                return True +            if person_type.rights.filter(url_name=step).count(): +                return True +        return check_right + +    def __init__(self, *args, **kwargs): +        """Check right for each step of the wizard""" +        super(Wizard, self).__init__(*args, **kwargs) +        for form_key in self.form_list.keys()[:-1]: +            condition = True +            if form_key in self.condition_dict: +                condition = self.condition_dict.get(form_key, True) +            cond = self._check_right(form_key, condition) +            self.condition_dict[form_key] = cond +        """ +        for form_key in self.form_list.keys()[:-1]: +            condition = True +            if form_key in self.condition_list: +                condition = self.condition_list.get(form_key, True) +            cond = self._check_right(form_key, condition) +            self.condition_list[form_key] = cond""" + +    def get_wizard_name(self): +        """As the class name can interfere when reused, use the url_name""" +        return self.url_name + +    def get_template_names(self): +        templates = ['ishtar/wizard/default_wizard.html'] +        current_step = self.steps.current +        if current_step == self.steps.last: +            templates = ['ishtar/wizard/confirm_wizard.html'] + templates +        return templates + +    def get_context_data(self, form, **kwargs): +        """Add previous, next and current steps to manage the wizard path""" +        context = super(Wizard, self).get_context_data(form) +        step = self.steps.first +        current_step = self.steps.current +        context.update({'current_step':self.form_list[current_step]}) +        if step == current_step: +            return context +        previous_steps, next_steps, previous_step_counter = [], [], 0 +        while step: +            if step == current_step: +                break +            previous_steps.append(self.form_list[step]) +            step = self.steps.next +            previous_step_counter += 1 +        context.update({'previous_steps':previous_steps, +                        'previous_step_counter':previous_step_counter}) +        # if modification: show the next steps +        if self.modification: +            next_step = step +            while next_step: +                # check if the form is initialized otherwise initialize it +                if not storage.get_step_data(next_step): +                    values = self.get_form_initial(request, storage, next_step) +                    prefixed_values = {} +                    if not isinstance(values, list): +                        for key in values: +                            form_key = next_step + '-' + key +                            prefixed_values[form_key] = values[key] +                    else: +                        for formset_idx, v in enumerate(values): +                            prefix = u"-%d-" % formset_idx +                            for key in v: +                                form_key = next_step + prefix + key +                                prefixed_values[form_key] = v[key] +                    storage.set_step_data(next_step, prefixed_values) +                if step != next_step: # if not current step +                    next_steps.append(self.form_list[next_step]) +                next_step = self.get_next_step(request, storage, next_step) +        context.update({'next_steps':next_steps}) +        # not last step: validation +        if current_step != self.steps.last: +            return context +        final_form_list = [] +        for form_key in self.get_form_list().keys(): +            form_obj = self.get_form(step=form_key, +                    data=self.storage.get_step_data(form_key), +                    files=self.storage.get_step_files(form_key)) +            form_obj.is_valid() +            final_form_list.append(form_obj) +        last_form = final_form_list[-1] +        context.update({'datas':self.get_formated_datas(final_form_list)}) +        if hasattr(last_form, 'confirm_msg'): +            context.update({'confirm_msg':last_form.confirm_msg}) +        if hasattr(last_form, 'confirm_end_msg'): +            context.update({'confirm_end_msg':last_form.confirm_end_msg}) +        return context + +    def get_formated_datas(self, forms): +        """Get the data to present in the last page""" +        datas = [] +        for form in forms: +            form_datas = [] +            base_form = hasattr(form, 'forms') 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'): +                cleaned_datas = [frm.cleaned_data for frm in form.forms +                                                  if frm.is_valid()] +                if not cleaned_datas: +                    continue +            elif not hasattr(form, 'cleaned_data'): +                continue +            else: +                cleaned_datas = type(form.cleaned_data) == list and \ +                                              form.cleaned_data \ +                            or [form.cleaned_data] +            for cleaned_data in cleaned_datas: +                if not cleaned_data: +                    continue +                if form_datas: +                    form_datas.append(("", "", "spacer")) +                items = hasattr(base_form, 'fields') and \ +                        base_form.fields.keyOrder or cleaned_data.keys() +                for key in items: +                    lbl = None +                    if key.startswith('hidden_'): +                        continue +                    if hasattr(base_form, 'fields') and key in base_form.fields: +                        lbl = base_form.fields[key].label +                        if hasattr(base_form, 'associated_labels') \ +                           and key in base_form.associated_labels: +                            lbl = base_form.associated_labels[key] +                    if not lbl: +                        continue +                    value = cleaned_data[key] +                    if not value and value != False: +                        continue +                    if type(value) == bool: +                        if value == True: +                            value = _(u"Yes") +                        elif value == False: +                            value = _(u"No") +                    elif key in associated_models: +                        values = [] +                        if "," in unicode(value): +                            values = unicode(value).split(",") +                        else: +                            values = [value] +                        rendered_values = [] +                        for val in values: +                            item = associated_models[key].objects.get(pk=val) +                            if hasattr(item, 'short_label'): +                                value = item.short_label() +                            else: +                                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)) +        return datas + +    def get_extra_model(self, dct, form_list): +        dct['history_modifier'] = self.request.user +        return dct + +    def done(self, form_list, return_object=False, **kwargs): +        """Save to the model""" +        dct, m2m, whole_associated_models = {}, [], [] +        for form in form_list: +            if not form.is_valid(): +                return self.render(form) +            base_form = hasattr(form, 'forms') and form.forms[0] or form +            associated_models = hasattr(base_form, 'associated_models') and \ +                                base_form.associated_models or {} +            if hasattr(form, 'forms'): +                multi = False +                if form.forms: +                    frm = form.forms[0] +                    if hasattr(frm, 'base_model') and frm.base_model: +                        whole_associated_models.append(frm.base_model) +                    else: +                        whole_associated_models += associated_models.keys() +                    fields = frm.fields.copy() +                    if 'DELETE' in fields: +                        fields.pop('DELETE') +                    multi = len(fields) > 1 +                    if multi: +                        assert hasattr(frm, 'base_model'), \ +                       u"Must define a base_model for " + unicode(frm.__class__) +                for frm in form.forms: +                    if not frm.is_valid(): +                        continue +                    vals = {} +                    if "DELETE" in frm.cleaned_data: +                        if frm.cleaned_data["DELETE"]: +                            continue +                        frm.cleaned_data.pop('DELETE') +                    for key in frm.cleaned_data: +                        value = frm.cleaned_data[key] +                        if not value and value != False: +                            continue +                        if key in associated_models: +                            value = associated_models[key].objects.get(pk=value) +                        if multi: +                            vals[key] = value +                        else: +                            m2m.append((key, value)) +                    if multi and vals: +                        m2m.append((frm.base_model, vals)) +            elif type(form.cleaned_data) == dict: +                for key in form.cleaned_data: +                    if key.startswith('hidden_'): +                        continue +                    value = form.cleaned_data[key] +                    if key in associated_models: +                        if value: +                            model = associated_models[key] +                            if isinstance(value, unicode) \ +                             or isinstance(value, str) and "," in value: +                                value = value.split(",") +                            if isinstance(value, list) \ +                             or isinstance(value, tuple): +                                value = [model.objects.get(pk=val) +                                         for val in value if val] +                                if len(value) == 1: +                                    value = value[0] +                            else: +                                value = model.objects.get(pk=value) +                        else: +                            value = None +                    dct[key] = value +        return self.save_model(dct, m2m, whole_associated_models, form_list, +                               return_object) + +    def get_saved_model(self): +        """Permit a distinguo when saved model is not the base selected model""" +        return self.model + +    def get_current_saved_object(self): +        """Permit a distinguo when saved model is not the base selected model""" +        return self.get_current_object() + +    def save_model(self, dct, m2m, whole_associated_models, form_list, +                   return_object): +        dct = self.get_extra_model(dct, form_list) +        obj = self.get_current_saved_object() +        # manage dependant items +        other_objs = {} +        for k in dct.keys(): +            if '__' not in k: +                continue +            vals = k.split('__') +            assert len(vals) == 2, "Only one level of dependant item is managed" +            dependant_item, key = vals +            if dependant_item not in other_objs: +                other_objs[dependant_item] = {} +            other_objs[dependant_item][key] = dct.pop(k) +        if obj: +            for k in dct: +                if k.startswith('pk'): +                    continue +                setattr(obj, k, dct[k]) +            try: +                obj.full_clean() +            except forms.ValidationError, msg: +                return self.render(form_list[-1]) +            for dependant_item in other_objs: +                c_item = getattr(obj, dependant_item) +                # manage ManyToMany if only one associated +                if hasattr(c_item, "all"): +                    c_items = c_item.all() +                    if len(c_items) != 1: +                        continue +                    c_item = c_items[0] +                if c_item: +                    # to check # +                    for k in other_objs[dependant_item]: +                        setattr(c_item, k, other_objs[dependant_item][k]) +                    c_item.save() +                else: +                    m = getattr(self.model, dependant_item) +                    if hasattr(m, 'related'): +                        c_item = m.related.model(**other_objs[dependant_item]) +                        setattr(obj, dependant_item, c_item) +                    obj.save() +            obj.save() +        else: +            adds = {} +            for dependant_item in other_objs: +                m = getattr(self.model, dependant_item) +                model = m.field.rel.to +                c_dct = other_objs[dependant_item].copy() +                if issubclass(model, models.BaseHistorizedItem): +                    c_dct['history_modifier'] = self.request.user +                c_item = model(**c_dct) +                c_item.save() +                if hasattr(m, 'through'): +                    adds[dependant_item] = c_item +                elif hasattr(m, 'field'): +                    dct[dependant_item] = c_item +            if 'pk' in dct: +                dct.pop('pk') +            obj = self.get_saved_model()(**dct) +            try: +                obj.full_clean() +            except forms.ValidationError, msg: +                return self.render(form_list[-1]) +            obj.save() +            for k in adds: +                getattr(obj, k).add(adds[k]) +            # necessary to manage interaction between models like +            # material_index management for baseitems +            obj.save() +        m2m_items = {} +        for model in whole_associated_models: +            getattr(obj, model+'s').clear() +        for key, value in m2m: +            if key not in m2m_items: +                if type(key) == dict: +                    vals = [] +                    for item in getattr(obj, key+'s').all(): +                        v = {} +                        for k in value.keys(): +                            v[k] = getattr(item, k) +                        vals.append(v) +                    m2m_items[key] = vals +                else: +                    m2m_items[key] = getattr(obj, key+'s').all() +            if value not in m2m_items[key]: +                if type(value) == dict: +                    model = getattr(obj, key+'s').model +                    if issubclass(model, models.BaseHistorizedItem): +                        value['history_modifier'] = self.request.user +                    value = model.objects.create(**value) +                    value.save() +                getattr(obj, key+'s').add(value) +                # necessary to manage interaction between models like +                # material_index management for baseitems +                obj.save() +        res = render_to_response('wizard_done.html', {}, +                                  context_instance=RequestContext(self.request)) +        return return_object and (obj, res) or res + +    def get_deleted(self, keys): +        """Get the deleted and non-deleted items in formsets""" +        not_to_delete, to_delete = set(), set() +        for key in keys: +            items = key.split('-') +            if len(items) < 2 or items[-2] in to_delete: +                continue +            idx = items[-2] +            try: +                int(idx) +            except: +                continue +            if items[-1] == u'DELETE': +                to_delete.add(idx) +                if idx in not_to_delete: +                    not_to_delete.remove(idx) +            elif idx not in not_to_delete: +                not_to_delete.add(idx) +        return (to_delete, not_to_delete) + +    def get_form(self, step=None, data=None, files=None): +        """Manage formset""" +        request = self.request +        storage = self.storage +        if data: +            data = data.copy() +            if not step: +                step = self.steps.current +            form = self.get_form_list()[step] +            if hasattr(form, 'management_form'): +                # 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)): +                        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 +                base_key = form.form.base_fields.keys()[0] +                init = self.get_form_initial(request, storage, step) +                total_field = len([key for key in data.keys() +                                        if base_key in key.split('-') +                                           and data[key]]) +                if init and not to_delete: +                    total_field = max((total_field, len(init))) +                data[step + u'-INITIAL_FORMS'] = unicode(total_field) +                data[step + u'-TOTAL_FORMS'] = unicode(total_field + 1) +        data = data or None +        form = super(Wizard, self).get_form(step, data, files) +        return form + +    def render_next_step(self, form, **kwargs): +        """ +        Manage: +         - modify or delete button in formset: next step = current step +         - validate and end: nextstep = last step +        """ +        request = self.request +        if request.POST.has_key('formset_modify') \ +           and request.POST['formset_modify'] \ +           or [key for key in request.POST.keys() +               if key.endswith('DELETE') and request.POST[key]]: +            return self.render(form) +        elif request.POST.has_key('validate_and_end') \ +           and request.POST['validate_and_end']: +            last_step = self.steps.last +            new_form = self.get_form(last_step, +                data=self.storage.get_step_data(last_step), +                files=self.storage.get_step_files(last_step)) +            self.storage.current_step = last_step +            return self.render(new_form) +        return super(Wizard, self).render_next_step(form, **kwargs) + +    def post(self, *args, **kwargs): +        """Convert numerical step number to step name""" +        request = self.request +        post_data = request.POST.copy() +        if request.POST.has_key('form_prev_step'): +            try: +                step_number = int(request.POST['form_prev_step']) +                post_data['wizard_goto_step'] = self.get_form_list().keys( +                                                                 )[step_number] +            except ValueError: +                pass +        request.POST = post_data +        return super(Wizard, self).post(*args, **kwargs) + +    @classmethod +    def session_has_key(cls, request, storage, form_key, key=None, multi=None): +        """Check if the session has value of a specific form and (if provided) +        of a key +        """ +        test = storage.prefix in request.session \ +          and 'step_data' in request.session[storage.prefix] \ +          and form_key in request.session[storage.prefix]['step_data'] +        if not key or not test: +            return test +        key = key.startswith(form_key) and key or \ +              not multi and form_key + '-' + key or \ +              form_key + '-0-' + key #only check if the first field is available +        return key in request.session[storage.prefix]['step_data'][form_key] + +    @classmethod +    def session_get_value(cls, request, storage, form_key, key, multi=False): +        """Get the value of a specific form""" +        if not cls.session_has_key(request, storage, form_key, key, multi): +            return +        if not multi: +            key = key.startswith(form_key) and key or form_key + '-' + key +            return request.session[storage.prefix]['step_data'][form_key][key] +        vals = [] +        for k in request.session[storage.prefix]['step_data'][form_key]: +            if k.startswith(form_key) and k.endswith(key) and \ +               request.session[storage.prefix]['step_data'][form_key][k]: +                vals.append(request.session[storage.prefix]['step_data']\ +                                           [form_key][k]) +        return vals + +    def get_current_object(self): +        """Get the current object for an instancied wizard""" +        current_obj = None +        main_form_key = 'selec-' + self.url_name +        try: +            idx = int(self.session_get_value(self.request, self.storage, +                                             main_form_key, 'pk')) +            current_obj = self.model.objects.get(pk=idx) +        except(TypeError, ValueError, ObjectDoesNotExist): +            pass +        return current_obj + +    def get_form_initial(self, step): +        current_obj = self.get_current_object() +        current_step = self.steps.current +        if step.startswith('selec-') and step in self.form_list \ +           and 'pk' in self.form_list[step].associated_models: +            model_name = self.form_list[step].associated_models['pk' +                                              ].__name__.lower() +            if step == current_step: +                self.reset_wizard(request, storage) +            val = model_name in request.session and request.session[model_name] +            if val: +                return {'pk':val} +        elif current_obj: +            return self.get_instanced_init(current_obj, step) +        current_form = self.form_list[current_step] +        if hasattr(current_form, 'currents'): +            initial = {} +            for key in current_form.currents: +                model_name = current_form.currents[key].__name__.lower() +                val = model_name in request.session and \ +                      request.session[model_name] +                if val: +                    initial[key] = val +            if initial: +                return initial +        return super(Wizard, self).get_form_initial(step) + +    def get_instanced_init(self, obj, step=None): +        """Get initial data from an init""" +        current_step = step or self.steps.current +        c_form = self.form_list[current_step] +        # make the current object the default item for the session +        obj_name = obj.__class__.__name__.lower() +        # prefer a specialized name if available +        prefixes = self.storage.prefix.split('_') +        if len(prefixes) > 1 and prefixes[-2].startswith(obj_name): +            obj_name = prefixes[-2] +        self.request.session[obj_name] = unicode(obj.pk) +        initial = {} +        if self.request.POST or \ +          (step in self.request.session[self.storage.prefix] and\ +           self.request.session[self.storage.prefix]['step_data'][step]): +            return {} +        if hasattr(c_form, 'base_fields'): +            for base_field in c_form.base_fields.keys(): +                fields = base_field.split('__') +                value = obj +                for field in fields: +                    if not hasattr(value, field) or \ +                       getattr(value, field) == None: +                        value = obj +                        break +                    value = getattr(value, field) +                if value == obj: +                    continue +                if hasattr(value, 'pk'): +                    value = value.pk +                if value in (True, False): +                    initial[base_field] = value +                elif value != None: +                    initial[base_field] = unicode(value) +        elif hasattr(c_form, 'management_form'): +            initial = [] +            if hasattr(c_form.form, 'base_model'): +                key = c_form.form.base_model + 's' +            else: +                key = current_step.split('-')[0] +            if not hasattr(obj, key): +                return initial +            keys = c_form.form.base_fields.keys() +            for child_obj in getattr(obj, key).order_by('pk').all(): +                if not keys: +                    break +                vals = {} +                if len(keys) == 1: +                    # only one field: must be the id of the object +                    vals[keys[0]] = unicode(child_obj.pk) +                else: +                    for field in keys: +                        if hasattr(child_obj, field): +                            value = getattr(child_obj, field) +                            if hasattr(value, 'pk'): +                                value = value.pk +                            if value != None: +                                vals[field] = unicode(value) +                if vals: +                    initial.append(vals) +        return initial + +class PersonWizard(Wizard): +    model = models.Person + +person_creation_wizard = PersonWizard.as_view([ +                        ('identity-person_creation', PersonForm), +                        ('final-person_creation', FinalForm)], +                         url_name='person_creation_step',) + +  def update_current_item(request):      if not request.is_ajax() and not request.method == 'POST':          raise Http404 diff --git a/ishtar/templates/confirm_wizard.html b/ishtar/templates/ishtar/wizard/confirm_wizard.html index 371de39c3..bd80e3967 100644 --- a/ishtar/templates/confirm_wizard.html +++ b/ishtar/templates/ishtar/wizard/confirm_wizard.html @@ -19,9 +19,10 @@      {% endfor %}    </table>    {% endfor %} -  {%if not form.is_hidden %} +{{wizard.management_form}} +  {%if not wizard.form.is_hidden %}    <table> -    {{ form.as_table }} +    {{ wizard.form.as_table }}     </table>    {%endif%}    <p>{%if confirm_end_msg %}{{confirm_end_msg|safe}}{%else%}{% trans "Would you like to save them?" %}{%endif%}</p> diff --git a/ishtar/templates/default_wizard.html b/ishtar/templates/ishtar/wizard/default_wizard.html index a71565b6e..1996f4e46 100644 --- a/ishtar/templates/default_wizard.html +++ b/ishtar/templates/ishtar/wizard/default_wizard.html @@ -18,19 +18,21 @@  </ul>  <div class='form'>  {% if reminder %}<div class='reminder'>{{ reminder }}</div>{%endif%} -{% if form.forms %} +{{ wizard.form.media }} +{{ wizard.management_form }} +{% if wizard.form.forms %} +  {{ wizard.form.management_form }}  <div class='top_button'><input type="submit" id="submit_form" value="{% trans "Validate" %}"/></div>  <table class='formset'> -  {%if form.non_form_errors%}<tr class='error'><th colspan='2'>{{form.non_form_errors}}</th></tr>{%endif%} -  {{ form.management_form }} -  {% for formsetform in form.forms %} +  {%if wizard.form.non_form_errors%}<tr class='error'><th colspan='2'>{{wizard.form.non_form_errors}}</th></tr>{%endif%} +  {% for formsetform in wizard.form.forms %}    {% table_form formsetform %}    {% endfor %}    <tr class='modify'><td colspan="2"><button name="formset_modify" value="{{form_step}}">{% trans "Add/Modify" %}</button></td></tr></li>  </table>  {% else %}  <table> -{% table_form form %} +{% table_form wizard.form %}  </table>  {% endif %}  <input type="hidden" name="{{ step_field }}" value="{{ step0 }}" /> diff --git a/ishtar/urls.py b/ishtar/urls.py index baa906979..2723eb1cf 100644 --- a/ishtar/urls.py +++ b/ishtar/urls.py @@ -3,7 +3,7 @@ from django.conf.urls.defaults import *  from django.contrib.auth.models import User  from django.contrib import admin  admin.autodiscover() -admin.site.unregister(User) +#admin.site.unregister(User)  from settings import URL_PATH  | 
