def decimal_validator(node, value): v = unicode(value) sep = kw['separator'] prec = kw['precision'] try: x = float(v.replace(',', '.')) except ValueError: raise c.Invalid(node, _('Please enter a number.')) # if needed, at this point x is the float value to be saved. if (sep == '.' and v.find(',') != -1) or \ (sep == ',' and v.find('.') != -1): raise c.Invalid( node, _('Wrong separator. Try swapping dot (.) and comma (,).')) try: dec = v.split(sep)[1] # capture decimal part except IndexError: return None # validation succeeded if len(dec) > prec: raise c.Invalid(node, \ _("Maximum of %(p)d decimals.") % {'p': prec})
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 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 create_csv(self, encoding='utf-8'): '''Exports one entry to a form as csv file and initializes download from the server. ''' entry_id = self.request.matchdict['id'] # Assign name of the file dynamically according to form name and # creation date entry, form = self._get_entry_and_form_if_belongs_to_user( entry_id=entry_id) name = self.tr(_('Entry_{0}_{1}_of_{2}.csv')) \ .format(entry.entry_number, unicode(entry.created)[:10], unicode(form.name[:200]).replace(' ', '_')) file = StringIO() csvWriter = csv.writer(file, delimiter=b',', quotechar=b'"', quoting=csv.QUOTE_NONNUMERIC) 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) # get the data of the fields of one entry e in a list of lists fields_data = [entry.entry_number, str(entry.created)[:16]] + \ [f.value(entry).format(url=self.request.application_url). \ encode(encoding) for f in form.fields] csvWriter.writerow(fields_data) entryfile = file.getvalue() return Response(status='200 OK', headerlist=[(b'Content-Type', b'text/comma-separated-values'), (b'Content-Disposition', b'attachment; filename={0}' \ .format (name.encode(encoding)))], body=entryfile)
def web_url(node, val): '''Checks whether the value is an http or https URL.''' pieces = urlparse(val) if not all([pieces.scheme, pieces.netloc]): raise c.Invalid(node, _('The URL must include http or https.\nFor example, http://www.example.com')) if pieces.scheme not in ('http', 'https'): raise c.Invalid(node, _('The URL must include http or https.')) domain, error_message = domain_validator.validate(pieces.netloc) if error_message: raise c.Invalid(node, error_message)
def create_category_schema(user): '''Returns a schema for creation of a category, imperatively built''' schema = c.SchemaNode(c.Mapping()) schema.add(c.SchemaNode(c.Str(), name="name", title=_('Name'), validator=c.All(c.Length(**LEN_NAME), validate_based_on_user(user)))) schema.add(c.SchemaNode(c.Str(), name="description", title=_('Description'), missing='', validator=c.Length(**LEN_DESCRIPTION))) return schema
def integer_validator(node, value): v = unicode(value) try: x = float(v.replace(',', '.')) except ValueError: raise c.Invalid(node, _('Please enter a number.')) # if needed, at this point x is the float value to be saved. if v.find('.') != -1 or v.find(',') != -1: raise c.Invalid(node, _('Please enter an integer number.'))
class ContactFormSchema(c.MappingSchema): name = c.SchemaNode(c.Str(), title=_('Name'), validator=c.Length(**LEN_NAME)) email = c.SchemaNode(c.Str(), title=_('Email'), validator=c.Email()) subject = c.SchemaNode(c.Str(), title=_('Subject'), validator=c.Length(**LEN_SUBJECT)) message = c.SchemaNode(c.Str(), title=_('Message'), widget=TextAreaWidget(cols=40, rows=12), validator=c.Length(**LEN_MESSAGE))
def copy(self): form = self._get_form_if_belongs_to_user() if form: form_copy = form.copy() form_copy.name += " " + _("(copy)") sas.flush() error = "" else: error = _("This form does not exist.") user = self.request.user all_data = user.all_categories_and_forms() return {"errors": error, "all_data": all_data, "form_copy_id": form_copy.id}
class TextAreaField(TextBase): name = _('Multiline text') brief = _("multiline text") defaultValue = dict(defaul='', required=False) def get_widget(self): f = self.field return d.widget.TextAreaWidget( template='form_textarea', style='width:{}px; height: {}px;'.format(f.get_option('width'), f.get_option('height'))) _special_options = 'defaul enableLength minLength maxLength enableWords ' \ 'minWords maxWords height width'.split()
def copy(self): form = self._get_form_if_belongs_to_user() if form: form_copy = form.copy() form_copy.name += " " + _("(copy)") sas.flush() error = '' else: error = _("This form does not exist.") user = self.request.user all_data = user.all_categories_and_forms() return {'errors': error, 'all_data': all_data, 'form_copy_id': form_copy.id}
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 date_validation(node, val): try: date = datetime.strptime(val, df.formats[int(self.field.get_option \ ('input_date_format'))]['py']) except ValueError: raise c.Invalid(node, _("Invalid date format"))
def show_contact_form(self): '''Displays the contact form''' # "action" defines where the form POSTs to contact_form = d.Form(contact_form_schema, buttons=('submit',), action=self.url('contact'), formid='contactform') return dict(pagetitle=_("Contact"), contact_form=contact_form.render())
def save_website_code(self): '''Responds to the AJAX request and saves a collector.''' request = self.request posted = request.POST id = request.matchdict['id'] form_id = request.matchdict['form_id'] form = FormView(request)._get_form_if_belongs_to_user(form_id=form_id) if not form: return dict(error=_("Form not found.")) # Validate `posted` with colander: try: posted = website_code_schema.deserialize(posted) except c.Invalid as e: return e.asdict() # Validation passes, so create or update the model. if id == 'new': collector = WebsiteCodeCollector(form=form) sas.add(collector) else: collector = self._get_collector_if_belongs_to_user(id) # Copy the data self._parse_start_and_end_date(posted) for k, v in posted.items(): setattr(collector, k, v) sas.flush() return collector.to_dict()
def _send_email_entry(self, entry): sender = self.request.registry.settings.get('mail.message.author', '*****@*****.**') recipient = entry.form.user.email subject = _("[MootiroForm] Entry #%(entry_number)d for the form %(form_title)s") \ % {"entry_number": entry.entry_number, "form_title": entry.form.name} labels = [f.label for f in entry.form.fields] value = [f.value(entry) for f in entry.form.fields] fields = [{ 'label': labels[i], 'value': value[i] } for i in range(len(labels))] try: rendered = self.request.registry.settings['genshi_renderer'] \ .fragment('email_entry.genshi', dict(entry=entry, fields=fields, url=self.url)) except KeyError as e: raise KeyError( "Simon says: cd mootiro_web; git pull; ./setup.py develop") # TODO: Remove this except block after developers have updated. # 2011-08-11 msg = Message(sender, recipient, self.tr(subject)) msg.rich = rendered msg.plain = "We've collected an entry for you form. Visit us to see." msg.send()
def export_json(self): form_dict = dict(form_name=self.name or _('Untitled form'), form_description=self.description, fields=[f.to_dict(to_export=True) \ for f in self.fields]) for field in form_dict['fields']: field.pop('field_id') return json.dumps(form_dict, indent=4)
def image_validation(node, val): mimetype = val['mimetype'] size = val['size'] configured = f.get_option('mimeTypes').split('|') for allowed in [m for m in mt.mimetypes]: if allowed['desc'] in configured and mimetype in allowed['py']: return raise c.Invalid(node, _("Invalid image format"))
def valid_interval(node, value): if value['start_date']: start_date = datetime.strptime(value['start_date'], "%Y-%m-%d %H:%M") if value['end_date']: end_date = datetime.strptime(value['end_date'], "%Y-%m-%d %H:%M") if start_date > end_date: raise c.Invalid(node, _('The start date must be before' ' the end date'))
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 show_contact_form(self): '''Displays the contact form''' # "action" defines where the form POSTs to contact_form = d.Form(contact_form_schema, buttons=('submit', ), action=self.url('contact'), formid='contactform') return dict(pagetitle=_("Contact"), contact_form=contact_form.render())
def _get_schema_and_form(self, form): form_schema = create_form_schema(form) entry_form = make_form( form_schema, i_template="form_mapping_item", buttons=[form.submit_label if form.submit_label else _("Submit")], action=(self.url("form", action="view", id=form.id)), ) return form_schema, entry_form
def valid_interval(node, value): if value['start_date']: start_date = datetime.strptime(value['start_date'], "%Y-%m-%d %H:%M") if value['end_date']: end_date = datetime.strptime(value['end_date'], "%Y-%m-%d %H:%M") if start_date > end_date: raise c.Invalid( node, _('The start date must be before' ' the end date'))
def in_the_future(node, value): '''Checks whether the date is in the future''' if value: try: date = datetime.strptime(value, "%Y-%m-%d %H:%M") except: return if date and date < datetime.utcnow(): raise c.Invalid(node, _('The end date must be in the future'))
def create_category_schema(user): '''Returns a schema for creation of a category, imperatively built''' schema = c.SchemaNode(c.Mapping()) schema.add( c.SchemaNode(c.Str(), name="name", title=_('Name'), validator=c.All(c.Length(**LEN_NAME), validate_based_on_user(user)))) schema.add( c.SchemaNode(c.Str(), name="description", title=_('Description'), missing='', validator=c.Length(**LEN_DESCRIPTION))) return schema
def _get_schema_and_form(self, form, slug=None): if not slug: slug = self.request.matchdict['slug'] form_schema = create_form_schema(form) entry_form = make_form(form_schema, i_template='form_mapping_item', buttons=[form.submit_label if form.submit_label else _('Submit')], action=(self.url('entry_form_slug', action='save_entry', slug=slug))) return form_schema, entry_form
def delete(self): collector = self._get_collector_if_belongs_to_user() if collector: sas.delete(collector) sas.flush() error = '' else: error = _("This collector does not exist.") return {'errors': error}
def date_string(node, value): '''Checks whether the date is of the correct format to transform it into a datetime object''' if value: try: datetime.strptime(value, "%Y-%m-%d %H:%M") except: raise c.Invalid(node, _('Please enter a valid date of the format' ' yyyy-mm-dd hh:mm'))
def collectors(self): '''Displays all collectors of a form.''' # TODO Don't convert to int here, use the regex in Pyramid routes form_id = int(self.request.matchdict['id']) form = FormView(self.request)._get_form_if_belongs_to_user(form_id=form_id) collectors = [c.to_dict(translator=self.tr) for c in form.collectors] collectors_json = safe_json_dumps(collectors) return dict(form=form, collectors_json=collectors_json, pagetitle=_('Collectors for {0}').format(form.name))
def delete_entry(self): entry_id = self.request.matchdict['id'] entry, form = self._get_entry_and_form_if_belongs_to_user( entry_id=entry_id) if entry and form: if entry.new: form.new_entries -= 1 entry.delete_entry() return dict(errors=None, entry=entry_id) return _("You cannot delete this entry.")
def list(self): '''Displays a list of the entries of a form.''' form_id = int(self.request.matchdict['id']) form = FormView(self.request)._get_form_if_belongs_to_user(form_id) entries = [e.to_dict() for e in entry.pagination(form_id)] entries_json = safe_json_dumps(entries) return dict(form=form, form_id=form.id, entries_json=entries_json, entries=form.entries, pagetitle=_('Entries for {0}').format(form.name))
def delete_entry(self): entry_id = self.request.matchdict['id'] entry, form = self._get_entry_and_form_if_belongs_to_user( entry_id=entry_id) if entry and form: if entry.new: form.new_entries -= 1 entry.delete_entry() return dict(errors=None,entry=entry_id) return _("You cannot delete this entry.")
def min_and_max_words_validator(node, val): '''This is a colander validator that checks the number of words in the value. A colander validator is a callable which accepts two positional arguments: node and value. It returns None if the value is valid. It raises a colander.Invalid exception if the value is not valid. ''' word_count = len(val.split()) # TODO Pluralize these error messages if word_count < node.min_words: raise c.Invalid(node, _('Text contains {} words, the minimum is {}.') \ .format(word_count, node.min_words)) if word_count > node.max_words: raise c.Invalid(node, _('Text contains {} words, the maximum is {}.') \ .format(word_count, node.max_words)) return None
def file_validation(node, val): mimetype = val['mimetype'] size = val['size'] is_mimetype_allowed = False for allowed in mt.mimetypes: if mimetype == allowed['py']: is_mimetype_allowed = True if not is_mimetype_allowed: raise c.Invalid(node, _("Invalid file format"))
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 entry_data(self): entry_id = self.request.matchdict['id'] entry, form = self._get_entry_and_form_if_belongs_to_user( entry_id=entry_id) if entry and form: if entry.new: entry.new = False form.new_entries -= 1 return entry.fields_data(field_idx="FIELD_LABEL", request=self.request) return _("Access denied")
def date_string(node, value): '''Checks whether the date is of the correct format to transform it into a datetime object''' if value: try: datetime.strptime(value, "%Y-%m-%d %H:%M") except: raise c.Invalid( node, _('Please enter a valid date of the format' ' yyyy-mm-dd hh:mm'))
def _get_schema_and_form(self, form, slug=None): if not slug: slug = self.request.matchdict['slug'] form_schema = create_form_schema(form) entry_form = make_form( form_schema, i_template='form_mapping_item', buttons=[form.submit_label if form.submit_label else _('Submit')], action=(self.url('entry_form_slug', action='save_entry', slug=slug))) return form_schema, entry_form
def delete(self): form = self._get_form_if_belongs_to_user() if form: sas.delete(form) sas.flush() error = '' else: error = _("This form does not exist.") user = self.request.user all_data = user.all_categories_and_forms() return {'error': error, 'all_data': all_data}
def delete(self): form = self._get_form_if_belongs_to_user() if form: sas.delete(form) sas.flush() error = "" else: error = _("This form does not exist.") user = self.request.user all_data = user.all_categories_and_forms() return {"error": error, "all_data": all_data}
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))
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 decimal_validator(node, value): v = unicode(value) sep = kw['separator'] prec = kw['precision'] try: x = float(v.replace(',', '.')) except ValueError: raise c.Invalid(node, _('Please enter a number.')) # if needed, at this point x is the float value to be saved. if (sep == '.' and v.find(',') != -1) or \ (sep == ',' and v.find('.') != -1): raise c.Invalid(node, _('Wrong separator. Try swapping dot (.) and comma (,).')) try: dec = v.split(sep)[1] # capture decimal part except IndexError: return None # validation succeeded if len(dec) > prec: raise c.Invalid(node, \ _("Maximum of %(p)d decimals.") % {'p': prec})