From 0e7d1b4582f60ac7dc0f40cb3710a31f465fd86e Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Sat, 18 May 2019 14:17:33 +0200 Subject: [PATCH 4/7] add new action create-formdata (#33186) --- wcs/wf/create_formdata.py | 421 ++++++++++++++++++++++++++++++++++++++ wcs/workflows.py | 1 + 2 files changed, 422 insertions(+) create mode 100644 wcs/wf/create_formdata.py diff --git a/wcs/wf/create_formdata.py b/wcs/wf/create_formdata.py new file mode 100644 index 00000000..f5e653b4 --- /dev/null +++ b/wcs/wf/create_formdata.py @@ -0,0 +1,421 @@ +# w.c.s. - web application for online forms +# Copyright (C) 2005-2016 Entr'ouvert +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . + +import collections +import copy +import time +import xml.etree.ElementTree as ET + +from quixote import get_request, get_session + +from django.utils.functional import cached_property + +from wcs.qommon import _ +from wcs.qommon.form import (WidgetListAsTable, CompositeWidget, + SingleSelectWidget, ComputedExpressionWidget, + CheckboxWidget, StringWidget, VarnameWidget) + +from wcs.logged_errors import LoggedError +from wcs.workflows import WorkflowStatusItem, register_item_class +from wcs.formdef import FormDef +from wcs.variables import LazyFormData + + +Mapping = collections.namedtuple('Mapping', ['varname', 'expression']) + + +class MappingWidget(CompositeWidget): + def __init__(self, name, value=None, to_formdef=None, **kwargs): + value = value or Mapping(None, '') + super(MappingWidget, self).__init__(name, value, **kwargs) + + to_fields = self._fields_to_options(to_formdef) + + self.add(SingleSelectWidget, + name='varname', + title=_('Field'), + value=value.varname, + options=to_fields) + + self.add(ComputedExpressionWidget, + name='expression', + title=_('Expression'), + value=value.expression) + + def _fields_to_options(self, formdef): + return [(None, '---', '')] + [ + (field.varname, field.label, field.varname) for field in formdef.get_all_varname_fields()] + + def _parse(self, request): + super(MappingWidget, self)._parse(request) + if self.get('varname') is not None and self.get('expression') is not None: + self.value = Mapping(varname=self.get('varname'), expression=self.get('expression')) + else: + self.value = None + + +class MappingsWidget(WidgetListAsTable): + readonly = False + + # widget_list.js does not work with ComputedExpressionWidget, + # so we revert to quixote behabiour for adding a line + def add_media(self): + pass + + def __init__(self, name, to_formdef=None, **kwargs): + self.to_formdef = to_formdef + + value = kwargs.get('value') + if value: + # reorder mappings based on to_formdef fields order + value.sort(key=lambda mapping: self.ranks.get(mapping.varname, 9999)) + + super(MappingsWidget, self).__init__( + name, + element_type=MappingWidget, + element_kwargs={ + 'to_formdef': to_formdef, + }, + **kwargs) + + @cached_property + def ranks(self): + return {field.varname: i for i, field in enumerate( + field for field in self.to_formdef.get_all_varname_fields())} + + def _parse(self, request): + super(MappingsWidget, self)._parse(request) + + if self.value: + # prevent many mappings to the same field + if len(set(mapping.varname for mapping in self.value)) != len(self.value): + self.error = _('Some destination fields are duplicated') + return + + # reorder mappings based on to_formdef fields order + self.value.sort(key=lambda mapping: self.ranks.get(mapping.varname, 9999)) + + +class LazyLinkedFormData(object): + def __init__(self, part): + self.__part = part + + def __getattr__(self, name): + formdata = self.__part.formdata + if formdata is not None: + return getattr(LazyFormData(self.__part.formdata), name) + raise AttributeError(name) + + @property + def url(self): + formdata = self.__part.formdata + if formdata is None: + return None + if self.__part.formdata.is_draft(): + return self.__part.url + else: + return self.__getattr__('url') + + +class LinkedFormdataSubstitutionProxy(object): + def __init__(self, parts): + self.__parts = parts + self.__formdatas = [(part.varname, part, LazyLinkedFormData(part)) for part in parts] + self.__formdatas.reverse() + self.__varnames = set(varname for varname, _1, _2 in self.__formdatas) + self.__varname = None + + def __iter__(self): + for varname, part, formdata in self.__formdatas: + if self.__varname is None or self.__varname == varname: + yield formdata + + def __getitem__(self, idx): + return list(self)[idx] + + def __getattr__(self, name): + if self.__varname or name not in self.__varnames: + try: + first = self[0] + except KeyError: + raise AttributeError(name) + return getattr(first, name) + elif name in self.__varnames: + new_sub = copy.copy(self) + new_sub.varname = name + return new_sub + + def __repr__(self): + s = '