def to_dict(self, to_export=False): field_id = self.field.id # Approved list options list_optionsObj = sas.query(ListOption) \ .filter(ListOption.field_id == self.field.id) \ .filter(or_(ListOption.status == 'Approved', \ ListOption.status == 'Form owner')) \ .order_by(ListOption.position).all() # Waiting moderation list options list_optionsModerationObj = sas.query(ListOption) \ .filter(ListOption.field_id == self.field.id) \ .filter(ListOption.status == 'Awaiting moderation') \ .order_by(ListOption.position).all() list_options = [{'label':lo.label, 'value':lo.value, \ 'opt_default': lo.opt_default,'option_id':lo.id, \ 'position': lo.position, 'status': lo.status} for lo in list_optionsObj] # Remove option_id from options list if to_export: map(lambda o: o.pop('option_id'), list_options) list_options_moderation = [{'label':lo.label, 'value':lo.value, \ 'opt_default': lo.opt_default,'option_id':lo.id, \ 'position': lo.position, 'status': lo.status} for lo in list_optionsModerationObj] field_dict = super(ListField, self).base_dict() field_dict.update( list_type=self.field.get_option('list_type'), multiple_choice=True if self.field.get_option('multiple_choice') \ == 'true' else False, sort_choices = self.field.get_option('sort_choices'), size_options= self.field.get_option('size_options'), min_num=self.field.get_option('min_num'), max_num=self.field.get_option('max_num'), new_option= True if self.field.get_option('new_option') == 'true' \ else False, new_option_label=self.field.get_option('new_option_label'), moderated= True if self.field.get_option('moderated') == 'true' \ else False, case_sensitive= True if self.field.get_option('case_sensitive') \ == 'true' else False, opt_restrictions= True if self.field.get_option('opt_restrictions') \ == 'true' else False, options=list_options, options_moderation=list_options_moderation, defaul=self.field.get_option('defaul'), #export_in_columns=True if \ # self.field.get_option('export_in_columns') == 'true' else False, ) # TODO Don't pop, use the inverse logic if to_export: field_dict.pop('options_moderation') return field_dict
def save_data(self, entry, value): list_type = self.field.get_option('list_type') if value: if value['option'] and value['option'] != c.null: if list_type != 'radio': for opt in filter(lambda o: o != '', value['option']): self.data = ListData() # TODO: Check if is a valid value self.data.value = opt self.data.entry_id = entry.id self.data.field_id = self.field.id sas.add(self.data) else: self.data = ListData() # TODO: Check if is a valid value self.data.value = value['option'] self.data.entry_id = entry.id self.data.field_id = self.field.id sas.add(self.data) if value.has_key('other') and value['other'] != '': moderated = self.field.get_option('moderated') case_sensitive = self.field.get_option('case_sensitive') if case_sensitive == 'true': option = sas.query(ListOption) \ .filter(ListOption.label == value['other']) \ .filter(ListOption.field_id == self.field.id) \ .first() else: option = sas.query(ListOption) \ .filter(ListOption.label.ilike(value['other'])) \ .filter(ListOption.field_id == self.field.id) \ .first() no_options = sas.query(ListOption) \ .filter(ListOption.field_id == self.field.id).count() if not option: lo = ListOption() lo.label = value['other'] lo.value = lo.label lo.field = self.field lo.position = no_options lo.status = 'Approved' if moderated == 'false' \ else 'Awaiting moderation' sas.add(lo) sas.flush() else: lo = option data = ListData() # TODO: Check if is a valid value data.value = lo.id data.entry_id = entry.id data.field_id = self.field.id sas.add(data)
def edit_category(self): '''Receives and validates POSTed data. If data is okay, creates the category. Otherwise, returns the form with errors. ''' user = self.request.user controls = self.request.POST.items() try: appstruct = new_category_form(user).validate(controls) except d.ValidationFailure as e: self.request.override_renderer = 'create_category.genshi' return dict(pagetitle=_("New category"), new_category_form=e.render()) user = self.request.user cat_name = appstruct['name'] cat_desc = appstruct['description'] if cat_name != '': category = sas.query(FormCategory) \ .filter(FormCategory.name==cat_name) \ .filter(FormCategory.user==user) \ .first() if category: # If the system found a category, don't create errors = _("That category already exists.") return {'errors': errors} else: # Create a category! new_category = FormCategory(name=cat_name, description=cat_desc, user=user) sas.add(new_category) sas.flush() all_data = user.all_categories_and_forms() return dict(changed=True, all_data=all_data)
def validate_user(node, value): cat = sas.query(FormCategory) \ .filter(FormCategory.user_id==user.id) \ .filter(FormCategory.name==value).first() if cat: raise c.Invalid(node, _('There is already a category with this name.'))
def value(self, entry): date_format = df.formats[int(self.field.get_option ('export_date_format'))]['py'] data = sas.query(DateData) \ .filter(DateData.field_id == self.field.id) \ .filter(DateData.entry_id == entry.id).first() return data.value.strftime(date_format) if data else ''
def __setitem__(self, name, value): if not value or not 'uid' in value: return uid = value['uid'] if not uid: return path = os.path.join(self.upload_temp_dir, uid) fp = value['fp'] if not fp or fp.closed or (hasattr(fp, 'name') and fp.name == path): return f = open(path, 'wb') try: f.write(fp.read()) finally: f.close() fp.close() data = sas.query(FileUploadTempStore) \ .filter(FileUploadTempStore.uid == unicode(uid)).first() if not data: data = FileUploadTempStore() data.created = datetime.datetime.utcnow() data.uid = unicode(uid) data.mimetype = unicode(value['mimetype']) data.filename = unicode(value['filename']) data.size = int(value['size']) data.path = unicode(path) data.thumbnail_path = unicode('') sas.add(data)
def value(self, entry): data = sas.query(NumberData) \ .filter(NumberData.field_id == self.field.id) \ .filter(NumberData.entry_id == entry.id) \ .first() if not data: return '' value = unicode(data.value) prec = int(self.field.get_option('precision')) sep = self.field.get_option('separator') if prec != 0: if value.split('.')[1] == "0": value = value.split('.')[0] elif sep == ',': value = value.replace('.', ',') else: # convert to integer string value = value.split('.')[0] prefix = self.field.get_option('prefix') if prefix != '': value = prefix + ' ' + value suffix = self.field.get_option('suffix') if suffix != '': value = value + ' ' + suffix return value
def _get_form_if_belongs_to_user(self, form_id=None, key="id"): """Returns the form instance indicated by matchdict[key], as long as it belongs to the current user. """ if not form_id: form_id = self.request.matchdict[key] return sas.query(Form).filter(Form.id == form_id).filter(Form.user == self.request.user).first()
def _csv_generator(self, form_id, encoding='utf-8'): '''A generator that returns the entries of a form line by line. ''' form = sas.query(Form).filter(Form.id == form_id).one() file = StringIO() csvWriter = csv.writer(file, delimiter=b',', quotechar=b'"', quoting=csv.QUOTE_NONNUMERIC) # write column names column_names = [self.tr(_('Entry')).encode(encoding), self.tr(_('Submissions (Date, Time)')) \ .encode(encoding)] + \ [f.label.encode(encoding) for f in form.fields] csvWriter.writerow(column_names) for e in form.entries: # get the data of the fields of the entry e in a list fields_data = [e.entry_number, str(e.created)[:16]] + \ [f.value(e).format(url=self.request.application_url) \ .encode(encoding) for f in form.fields] # generator which returns one row of the csv file (=data of the # fields of the entry e) csvWriter.writerow(fields_data) row = file.getvalue() file.seek(0) file.truncate() yield row sas.remove()
def _csv_generator(self, form_id, encoding="utf-8"): """A generator that returns the entries of a form line by line. """ form = sas.query(Form).filter(Form.id == form_id).one() file = StringIO() csvWriter = csv.writer(file, delimiter=b",", quotechar=b'"', quoting=csv.QUOTE_NONNUMERIC) # write column names column_names = [ self.tr(_("Entry")).encode(encoding), self.tr(_("Submissions (Date, Time)")).encode(encoding), ] + [f.label.encode(encoding) for f in form.fields] csvWriter.writerow(column_names) for e in form.entries: # get the data of the fields of the entry e in a list fields_data = [e.entry_number, str(e.created)[:16]] + [ f.value(e).format(url=self.request.application_url).encode(encoding) for f in form.fields ] # generator which returns one row of the csv file (=data of the # fields of the entry e) csvWriter.writerow(fields_data) row = file.getvalue() file.seek(0) file.truncate() yield row sas.remove()
def value(self, entry): date_format = df.formats[int( self.field.get_option('export_date_format'))]['py'] data = sas.query(DateData) \ .filter(DateData.field_id == self.field.id) \ .filter(DateData.entry_id == entry.id).first() return data.value.strftime(date_format) if data else ''
def show_edit(self): '''Displays the form editor, for new or existing forms.''' form_id = self.request.matchdict['id'] fields_config_json = json.dumps({ft[0]: ft[1](Field()).initJson() \ for ft in fields_dict.items()}) if form_id == 'new': form = Form() fields_json = json.dumps([]) else: form = self._get_form_if_belongs_to_user(form_id=form_id) fields_json = safe_json_dumps([f.to_dict() for f in form.fields]) # (indent=1 causes the serialization to be much prettier.) dform = d.Form(form_schema, formid='FirstPanel') \ .render(self.model_to_dict(form, ('name', 'description', 'rich', 'use_rich', 'submit_label'))) # TODO: Consider a caching alternative; this query might be # too expensive to stay in this view. # List of all system templates system_templates = sas.query(FormTemplate) \ .filter(FormTemplate.system_template_id != None) \ .order_by(FormTemplate.system_template_id).all() # Field types class names fieldtypes_json = json.dumps([typ.__class__.__name__ \ for typ in all_fieldtypes]) return dict(pagetitle=self._pagetitle, form=form, dform=dform, action=self.url('form', action='edit', id=form_id), system_templates=system_templates, fields_json=fields_json, all_fieldtypes=all_fieldtypes, fieldtypes_json=fieldtypes_json, fields_config_json=fields_config_json)
def save_options(self, options): '''Persists specific field properties.''' self.save_option('default', options['defaul']) # the default value for key in ('list_type', 'multiple_choice', 'sort_choices', 'new_option_label', 'min_num', # minimum number of choices 'max_num', # maximum number of choices 'size_options', # number of choices 'moderated', # other moderated 'new_option', # possible to add a new option 'case_sensitive', # other case sensitive 'opt_restrictions', # restricted number of options # 'export_in_columns', # when creating a CSV ): self.save_option(key, options[key]) inserted_options = {} for option_id, opt in options['options'].items(): if opt['option_id'] != 'new': lo = sas.query(ListOption).get(opt['option_id']) lo.label = opt['label'] lo.value = opt['value'] lo.opt_default = opt['opt_default'] lo.position = opt['position'] # lo.status = opt['status'] # To prevent KeyError, Nando changed the above line to: lo.status = opt.get('status', 'Form owner') else: lo = ListOption() lo.label = opt['label'] lo.value = opt['value'] lo.opt_default = opt['opt_default'] lo.field = self.field lo.position = opt['position'] lo.status = 'Form owner' sas.add(lo) sas.flush() inserted_options[option_id] = lo.id # Delete options for list_option_id in options['deleteOptions']: lo = sas.query(ListOption).get(list_option_id) if lo: sas.delete(lo) return {'insertedOptions': inserted_options}
def get_option(self, option): opt = sas.query(FieldOption)\ .filter(FieldOption.field_id == self.id) \ .filter(FieldOption.option == option).first() if opt: return opt.value else: return self.fieldtype.defaultValue[option]
def _get_form_if_belongs_to_user(self, form_id=None, key='id'): '''Returns the form instance indicated by matchdict[key], as long as it belongs to the current user. ''' if not form_id: form_id = self.request.matchdict[key] return sas.query(Form).filter(Form.id == form_id) \ .filter(Form.user == self.request.user).first()
def thumbnail_path(self, entry): data = sas.query(FileData) \ .filter(FileData.field_id == self.field.id) \ .filter(FileData.entry_id == entry.id).first() if data: return data.thumbnail_path else: return ''
def value(self, entry): data = sas.query(FileData) \ .filter(FileData.field_id == self.field.id) \ .filter(FileData.entry_id == entry.id).first() if data: return '{url}/file/view/%d/%d' % (data.entry_id, data.field_id) else: return ''
def _clear(self): data = sas.query(FileUploadTempStore) \ .filter(FileUploadTempStore.created < datetime.datetime.utcnow() - datetime.timedelta(minutes=30)).all() for d in data: sas.delete(d) path = os.path.join(self.upload_temp_dir, d.uid) try: os.remove(path) except OSError: pass # what to do if fail?
def rename(self): cat_id = self.request.matchdict.get('id') cat_name = self.request.POST['category_name'] if cat_name != '': category = sas.query(FormCategory).filter(FormCategory.id==cat_id)\ .one() if category: category.name = cat_name sas.flush() errors = '' else: errors = _("Error finding category") return {'errors': errors}
def value(self, entry): data = sas.query(ListOption).join(ListData) \ .filter(ListOption.field_id == self.field.id) \ .filter(ListData.entry_id == entry.id) \ .filter(ListOption.id == ListData.value).all() values = "" if data: for a in data[:-1]: values += a.label values += ", " values += data[-1].label return values
def delete(self): user = self.request.user cat_id = int(self.request.matchdict.get('id')) category = sas.query(FormCategory).filter(FormCategory.id == cat_id) \ .filter(FormCategory.user==user).one() if category: sas.delete(category) sas.flush() errors = '' else: errors = _("This category does not exist.") if user.categories: categories_data = [cat.to_dict() for cat in user.categories] return {'errors': errors, 'categories': categories_data}
def to_dict(self): return {'form_id': self.id, 'form_name': self.name or _('Untitled form'), 'form_entries': self.num_entries, 'form_new_entries': self.new_entries, 'form_description': self.description, 'form_rich': self.rich, 'form_use_rich': self.use_rich, 'form_created': unicode(self.created)[:16], 'form_modified': unicode(self.modified)[:16], 'form_status': self.status[0], 'form_status_num': self.status[1], 'form_questions': sas.query(Field) \ .filter(Field.form_id == self.id).count(), }
def __getitem__(self, name): self._clear() data = sas.query(FileUploadTempStore) \ .filter(FileUploadTempStore.uid == unicode(name)).first() if not data: raise AttributeError, "Name '{0}' does not exists".format(name) value = data.to_dict() path = os.path.join(self.upload_temp_dir, value['uid']) value['preview_url'] = self.preview_url(value['uid']) value['path'] = path value['fp'] = open(path, 'rb') if value: return value else: raise AttributeError, "Name '{0}' does not exists".format(name)
def save_thumbnail(self, entry, value): from PIL import Image f = self.field path = self.path(entry) thumbnail_path = path[:path.rfind('.')] + ".thumbnail.jpg" size = max(int(f.get_option('width')), int(f.get_option('height'))) size = size, size if not path: return img = Image.open(path) img.thumbnail(size, Image.ANTIALIAS) img.save(thumbnail_path, "JPEG") data = sas.query(FileData) \ .filter(FileData.field_id == f.id) \ .filter(FileData.entry_id == entry.id).first() if data: data.thumbnail_path = thumbnail_path sas.add(data)
def show_edit(self): """Displays the form editor, for new or existing forms.""" form_id = self.request.matchdict["id"] fields_config_json = json.dumps({ft[0]: ft[1](Field()).initJson() for ft in fields_dict.items()}) if form_id == "new": form = Form() fields_json = json.dumps([]) else: form = self._get_form_if_belongs_to_user(form_id=form_id) fields_json = safe_json_dumps([f.to_dict() for f in form.fields]) # (indent=1 causes the serialization to be much prettier.) dform = d.Form(form_schema, formid="FirstPanel").render( self.model_to_dict(form, ("name", "description", "rich", "use_rich", "submit_label")) ) # TODO: Consider a caching alternative; this query might be # too expensive to stay in this view. # List of all system templates system_templates = ( sas.query(FormTemplate) .filter(FormTemplate.system_template_id != None) .order_by(FormTemplate.system_template_id) .all() ) # Field types class names fieldtypes_json = json.dumps([typ.__class__.__name__ for typ in all_fieldtypes]) return dict( pagetitle=self._pagetitle, form=form, dform=dform, action=self.url("form", action="edit", id=form_id), system_templates=system_templates, fields_json=fields_json, all_fieldtypes=all_fieldtypes, fieldtypes_json=fieldtypes_json, fields_config_json=fields_config_json, )
def thumbnail(self): entry_id = self.request.matchdict['id'] field_id = self.request.matchdict['field'] entryview = EntryView(self.request) try: entry, form = entryview._get_entry_and_form_if_belongs_to_user( entry_id=entry_id) except TypeError: return HTTPNotFound() if entry and form: data = sas.query(FileData) \ .filter(FileData.entry_id == entry_id) \ .filter(FileData.field_id == field_id).first() path = data.thumbnail_path if not path or not os.path.isfile(path): return HTTPNotFound() try: response = Response(content_type=data.mimetype, app_iter=open(path, 'rb')) except: return HTTPNotFound() finally: return response return _("Access denied")
def value(self, entry): data = sas.query(TextData) \ .filter(TextData.field_id == self.field.id) \ .filter(TextData.entry_id == entry.id).first() return data.value if data else ''
def category_show(self): categories = sas.query(FormCategory).all() return categories
def num_entries(self): num_entries = sas.query(Entry).filter(Entry.form_id == self.id).count() return num_entries
def get_schema_node(self): title = self.field.label list_type = self.field.get_option('list_type') new_option = self.field.get_option('new_option') == 'true' sort_choices = self.field.get_option('sort_choices') multiple_choice = self.field.get_option('multiple_choice') == 'true' valuesQuery = sas.query(ListOption) \ .filter(ListOption.field_id == self.field.id) \ .filter(ListOption.status != 'Rejected') \ .filter(ListOption.status != 'Awaiting moderation') if sort_choices == 'user_defined': valuesObjs = valuesQuery.order_by(ListOption.position).all() elif sort_choices == 'random': valuesObjs = valuesQuery.all() elif sort_choices == 'alpha_asc': valuesObjs = valuesQuery.order_by(ListOption.label).all() elif sort_choices == 'alpha_desc': valuesObjs = valuesQuery.order_by(ListOption.label.desc()).all() values_tup = [(v.id, v.label) for v in valuesObjs] if sort_choices == 'random': random.shuffle(values_tup) values = tuple(values_tup) opt_restrictions = self.field.get_option('opt_restrictions') min_num = self.field.get_option('min_num') max_num = self.field.get_option('max_num') def valid_require(node, value): if self.field.get_option('new_option') == 'true': if self.field.required: if list_type != 'radio': if not value['option'].difference(set([''])) \ and not value['other']: raise c.Invalid(node, _('Required.')) else: if not value['option'] and not value['other']: raise c.Invalid(node, _('Required.')) elif self.field.required: if list_type != 'radio': if not value['option'].difference(set([''])): raise c.Invalid(node, _('Required.')) elif not value['option']: raise c.Invalid(node, _('Required.')) def min_choices(node, value): try: int(min_num) except ValueError: return if self.field.get_option('new_option') == 'true': add = 1 if value['other'] != '' else 0 else: add = 0 lacking_options = int(min_num) - \ len(value['option'].difference(set(['']))) + add if lacking_options > 0: if lacking_options == 1: raise c.Invalid(node, _('Please select one more option.')) else: raise c.Invalid(node, _('Please select {0} more options.'). \ format(lacking_options)) def max_choices(node, value): try: imax_num = int(max_num) except ValueError: return if self.field.get_option('new_option') == 'true': add = 1 if value['other'] != '' else 0 else: add = 0 excess_number = \ len(value['option'].difference(set(['']))) + \ add - imax_num if imax_num != 0 and excess_number > 0: if excess_number == 1: raise c.Invalid(node, _('Please deselect one option.')) else: raise c.Invalid(node, _('Please deselect {0} options.'). \ format(excess_number)) schema_params = {} if list_type == 'select' or list_type == 'checkbox': if opt_restrictions and multiple_choice: schema_params['validator'] = c.All(valid_require, min_choices, max_choices) schema_params['min_num'] = min_num schema_params['max_num'] = max_num else: schema_params['validator'] = valid_require else: schema_params['validator'] = valid_require if not self.field.required: schema_params['missing'] = {} schema_params['default'] = {} schema_params['multiple_choice'] = multiple_choice # Create the Mapping for select field list_map_schema = c.SchemaNode(c.Mapping(), title=title, name='input-{0}'.format(self.field.id), description=self.field.description, widget=d.widget.MappingWidget(template='form_select_mapping', item_template='form_select_mapping_item', error_class='error'), rich=self.field.rich, use_rich=self.field.use_rich, parent_id=self.field.id, opt_restrictions=self.field.get_option('opt_restrictions'), multiple=self.field.get_option('multiple_choice'), list_type=list_type, **schema_params) options = sas.query(ListOption) \ .filter(ListOption.field_id == self.field.id) \ .filter(ListOption.opt_default == True) \ .all() options_id = [o.id for o in options] req_dict = {'missing': '', 'default': ''} if list_type == 'select': list_schema = c.SchemaNode(d.Set(allow_empty=True), title=title, name='option', widget=d.widget.SelectWidget( values=values, template='form_select'), defaults=options_id, req=self.field.required, has_other=new_option, description=self.field.description, multiple=self.field.get_option('multiple_choice'), size_options=self.field.get_option('size_options'), parent_id=self.field.id, **req_dict) elif list_type == 'radio': option = sas.query(ListOption) \ .filter(ListOption.field_id == self.field.id) \ .filter(ListOption.opt_default == True).first() if option: default_id = option.id else: default_id = '' list_schema = c.SchemaNode(c.Str(), title=title, name='option', widget=d.widget.RadioChoiceWidget( template='form_radio_choice', values=values), description=self.field.description, opt_default=default_id, parent_id=self.field.id, **req_dict) elif list_type == 'checkbox': def_options = sas.query(ListOption) \ .filter(ListOption.field_id == self.field.id) \ .filter(ListOption.opt_default == True).all() list_schema = c.SchemaNode(d.Set(allow_empty=True), title=title, name='option', widget=d.widget.CheckboxChoiceWidget(values=values, template='form_checkbox_choice'), defaults=options_id, description=self.field.description, parent_id=self.field.id, **req_dict) list_map_schema.add(list_schema) if self.field.get_option('new_option') == 'true': other_option_label = self.field.get_option('new_option_label') other_schema_args = dict( title='' , name='other' , default='' , missing='' , widget=d.widget.TextInputWidget( template='form_other' , category='structural') , other_label=other_option_label , list_type=list_type , parent_id=self.field.id) other_option = c.SchemaNode(c.Str(), **other_schema_args) list_map_schema.add(other_option) return list_map_schema
def _get_collector(self, slug=None): if not slug: slug = self.request.matchdict['slug'] return sas.query(Collector).filter(Collector.slug == slug).one()
def _get_entry_and_form_if_belongs_to_user(self, entry_id=None): if not entry_id: entry_id = self.request.matchdict['id'] return sas.query(Entry, Form).join(Form).filter(Entry.id == entry_id) \ .filter(Form.user == self.request.user).first()
def _get_collector_and_form(self, slug=None): if not slug: slug = self.request.matchdict['slug'] return sas.query(Collector, Form).join(Form) \ .filter(Collector.slug == slug).one()
def _get_collector_if_belongs_to_user(self, collector_id=None): if not collector_id: collector_id = self.request.matchdict['id'] return sas.query(Collector).join(Form) \ .filter(Collector.id == collector_id) \ .filter(Form.user == self.request.user).first()
def save_form(self): '''Responds to the AJAX request and saves a form with its fields.''' request = self.request # TODO: Clean the posted json from malicious attacks such as XSS posted = json.loads(request.POST.pop('json')) # Validate the form panel (especially form name length) # TODO: Using deform for this was a mistake. We should use colander # only, and display errors using javascript, as we did on the # following method "rename". form_props = [('_charset_', ''), ('__formid__', 'FirstPanel'), ('name', posted['form_title']), ('description', posted['form_desc']), ('rich', posted['rich']), ('use_rich', posted['use_rich']), ('submit_label', posted['submit_label']) ] dform = d.Form(form_schema, formid='FirstPanel') try: fprops = dform.validate(form_props) except d.ValidationFailure as e: # print(e.args, e.cstruct, e.error, e.field, e.message) return dict(panel_form=e.render(), error=_('Error loading your form')) # the form panel is validated and should always be returned panel_form = dform.render(form_props) # Validation passes, so create or update the form. form_id = posted['form_id'] if form_id == 'new': form = Form(user=request.user) sas.add(form) else: form = self._get_form_if_belongs_to_user(form_id=form_id) if not form: return dict(error=_('Form not found.')) # Set the form tab properties form.name = fprops['name'] form.description = fprops['description'] sl = fprops['submit_label'] form.submit_label = \ self.tr(sl) if isinstance(sl, TranslationString) else sl form.use_rich = posted['use_rich'] # Sanitize / scrub the rich HTML rich = posted['rich'] if rich: rich = self.clnr.clean_html(rich) form.rich = rich # Visual Tab Info st_id = posted['system_template_id'] if st_id: st = sas.query(FormTemplate). \ filter(FormTemplate.system_template_id == st_id).first() form.template = st if form_id == 'new': # TODO: really necessary anymore? sas.flush() # so we get the form id # Get field positions positions = {f[:-len("_container")]: p for p, f in \ enumerate(posted['fields_position'])} # Save/Update the fields # Fields to delete for f_id in posted['deleteFields']: # TODO: check what to do with the field answer data!!! field = sas.query(Field).join(Form).filter(Field.id == f_id)\ .filter(Form.user_id == request.user.id).first() sas.delete(field) new_fields_id = {} save_options_result = {} for f in posted['fields']: # Sanitize / scrub the rich HTML rich = f['rich'] if rich: f['rich'] = rich = self.clnr.clean_html(rich) if not f['field_id']: raise RuntimeError('Cannot instantiate a field of ID {}' \ .format(f['field_id'])) elif f['field_id'] == 'new': field_type = sas.query(FieldType) \ .filter(FieldType.name == f['type']).first() # To solve a bug where field.save_options() would fail because # of a missing field ID, we instantiate the field here and flush field = Field(typ=field_type, form=form, label=f['label'], description=f['description'], help_text=None, use_rich=f['use_rich'], rich=f['rich']) sas.add(field) sas.flush() # TODO: Populating the above instance variables is probably # redundantly done elsewhere, but it must be done here. else: field = sas.query(Field).get(f['field_id']) if not field: return dict(error=_("Sorry, your field could not be found: {}") \ .format(f['field_id'])) f['position'] = positions[f['id']] # Before the following call, the field must have an ID. # If the following line raises a FieldValidationError, Pyramid will # call the field_validation_error action. result = field.validate_and_save(f) if result: save_options_result[f['id']] = result # If is a new field, need to inform the client about # the field id on DB after a flush if f['field_id'] == 'new': sas.flush() new_fields_id[f['id']] = {'field_id': field.id} rdict = {'form_id': form.id, 'new_fields_id': new_fields_id, 'save_options_result': save_options_result, 'panel_form': panel_form, } return rdict
def save_form(self): """Responds to the AJAX request and saves a form with its fields.""" request = self.request # TODO: Clean the posted json from malicious attacks such as XSS posted = json.loads(request.POST.pop("json")) # Validate the form panel (especially form name length) # TODO: Using deform for this was a mistake. We should use colander # only, and display errors using javascript, as we did on the # following method "rename". form_props = [ ("_charset_", ""), ("__formid__", "FirstPanel"), ("name", posted["form_title"]), ("description", posted["form_desc"]), ("rich", posted["rich"]), ("use_rich", posted["use_rich"]), ("submit_label", posted["submit_label"]), ] dform = d.Form(form_schema, formid="FirstPanel") try: fprops = dform.validate(form_props) except d.ValidationFailure as e: # print(e.args, e.cstruct, e.error, e.field, e.message) return dict(panel_form=e.render(), error=_("Error loading your form")) # the form panel is validated and should always be returned panel_form = dform.render(form_props) # Validation passes, so create or update the form. form_id = posted["form_id"] if form_id == "new": form = Form(user=request.user) sas.add(form) else: form = self._get_form_if_belongs_to_user(form_id=form_id) if not form: return dict(error=_("Form not found.")) # Set the form tab properties form.name = fprops["name"] form.description = fprops["description"] sl = fprops["submit_label"] form.submit_label = self.tr(sl) if isinstance(sl, TranslationString) else sl form.use_rich = posted["use_rich"] # Sanitize / scrub the rich HTML rich = posted["rich"] if rich: rich = self.clnr.clean_html(rich) form.rich = rich # Visual Tab Info st_id = posted["system_template_id"] if st_id: st = sas.query(FormTemplate).filter(FormTemplate.system_template_id == st_id).first() form.template = st if form_id == "new": # TODO: really necessary anymore? sas.flush() # so we get the form id # Get field positions positions = {f[: -len("_container")]: p for p, f in enumerate(posted["fields_position"])} # Save/Update the fields # Fields to delete for f_id in posted["deleteFields"]: # TODO: check what to do with the field answer data!!! field = sas.query(Field).join(Form).filter(Field.id == f_id).filter(Form.user_id == request.user.id).first() sas.delete(field) new_fields_id = {} save_options_result = {} for f in posted["fields"]: # Sanitize / scrub the rich HTML rich = f["rich"] if rich: f["rich"] = rich = self.clnr.clean_html(rich) if not f["field_id"]: raise RuntimeError("Cannot instantiate a field of ID {}".format(f["field_id"])) elif f["field_id"] == "new": field_type = sas.query(FieldType).filter(FieldType.name == f["type"]).first() # To solve a bug where field.save_options() would fail because # of a missing field ID, we instantiate the field here and flush field = Field( typ=field_type, form=form, label=f["label"], description=f["description"], help_text=None, use_rich=f["use_rich"], rich=f["rich"], ) sas.add(field) sas.flush() # TODO: Populating the above instance variables is probably # redundantly done elsewhere, but it must be done here. else: field = sas.query(Field).get(f["field_id"]) if not field: return dict(error=_("Sorry, your field could not be found: {}").format(f["field_id"])) f["position"] = positions[f["id"]] # Before the following call, the field must have an ID. # If the following line raises a FieldValidationError, Pyramid will # call the field_validation_error action. result = field.validate_and_save(f) if result: save_options_result[f["id"]] = result # If is a new field, need to inform the client about # the field id on DB after a flush if f["field_id"] == "new": sas.flush() new_fields_id[f["id"]] = {"field_id": field.id} rdict = { "form_id": form.id, "new_fields_id": new_fields_id, "save_options_result": save_options_result, "panel_form": panel_form, } return rdict
def get_system_template(self): st_id = self.request.matchdict['id'] template = sas.query(FormTemplate) \ .filter(FormTemplate.system_template_id == st_id).one() return template.to_dict()