def init(self): self.consumer = create_consumer(self.openid_session) if not hasattr(self, 'form_result'): return self._failure('', _("Invalid input.")) openid = self.form_result.get("openid") try: if not openid: raise ValueError(_("No OpenID given!")) authrequest = self.consumer.begin(openid) if not c.user and not model.OpenID.find(openid): axreq = ax.FetchRequest(h.base_url('/openid/update')) axreq.add(ax.AttrInfo(AX_MAIL_SCHEMA, alias="email", required=True)) authrequest.addExtension(axreq) sreq = sreg.SRegRequest(required=['nickname'], optional=['email']) authrequest.addExtension(sreq) redirecturl = authrequest.redirectURL( h.base_url('/'), return_to=h.base_url('/openid/verify'), immediate=False) session['openid_session'] = self.openid_session session.save() return redirect(redirecturl) except HTTPFound: raise except Exception, e: log.exception(e) return self._failure(openid, str(e))
def all(self, format="html"): if c.instance is None: require.perm("event.index_all") events = ( model.Event.all_q( instance=c.instance, include_hidden=False, event_filter=request.params.getall("event_filter") ) .order_by(model.Event.time.desc()) .limit(min(int(request.params.get("count", 50)), 100)) .all() ) if format == "rss": return event.rss_feed( events, _("%s News" % h.site.name()), h.base_url(instance=None), _("News from %s") % h.site.name() ) elif format == "ajax": query_params = request.params.copy() while True: try: query_params.pop("count") except KeyError: break more_url = h.base_url(instance=c.instance, member="event/all", query_params=query_params) return render_def("/event/tiles.html", "carousel", events=events, more_url=more_url) else: c.event_pager = pager.events(events, count=50) if format == "overlay": return render("/event/all.html", overlay=True, overlay_size=OVERLAY_SMALL) else: return render("/event/all.html")
def init(self): self.consumer = create_consumer(self.openid_session) if not hasattr(self, 'form_result'): return self._failure('', _("Invalid input.")) openid = self.form_result.get("openid") try: if not openid: raise ValueError(_("No OpenID given!")) authrequest = self.consumer.begin(openid) if not c.user and not model.OpenID.find(openid): axreq = ax.FetchRequest(h.base_url(c.instance, path='/openid/update')) axreq.add(ax.AttrInfo(AX_MAIL_SCHEMA, alias="email", required=True)) authrequest.addExtension(axreq) sreq = sreg.SRegRequest(required=['nickname'], optional=['email']) authrequest.addExtension(sreq) redirecturl = authrequest.redirectURL( h.base_url(c.instance, path='/'), return_to=h.base_url(c.instance, path='/openid/verify'), immediate=False) session['openid_session'] = self.openid_session session.save() return redirect(redirecturl) except HTTPFound: raise except Exception, e: log.exception(e) return self._failure(openid, str(e))
def new(self, id=None, errors={}, format=u'html'): if id is None: require.perm('global.message') template = '/massmessage/new.html' c.preview_url = h.base_url('/message/preview') else: c.page_instance = InstanceController._get_current_instance(id) require.instance.message(c.page_instance) template = '/instance/message.html' c.preview_url = h.base_url( '/instance/%s/message/preview' % id) defaults = dict(request.params) defaults.setdefault('include_footer', 'on') data = { 'instances': self._get_allowed_instances(c.user), 'sender_options': self._get_allowed_sender_options(c.user), 'userbadges': UserBadge.all(instance=c.instance, include_global=True) } return htmlfill.render(render(template, data, overlay=format == u'overlay'), defaults=defaults, errors=errors, force_defaults=False)
def all(self, format='html'): events = model.Event.all_q( include_hidden=False, event_filter=request.params.getall('event_filter'))\ .order_by(model.Event.time.desc())\ .limit(min(int(request.params.get('count', 50)), 100)).all() if format == 'rss': return event.rss_feed(events, _('%s News' % h.site.name()), h.base_url(instance=None), _("News from %s") % h.site.name()) elif format == 'ajax': query_params = request.params.copy() while True: try: query_params.pop('count') except KeyError: break more_url = h.base_url(instance=None, member='event/all', query_params=query_params) return render_def('/event/tiles.html', 'carousel', events=events, more_url=more_url) else: c.event_pager = pager.events(events, count=50) if format == 'overlay': return render('/event/all.html', overlay=True, overlay_size=OVERLAY_SMALL) else: return render('/event/all.html')
def new(self, id=None, errors={}, format=u'html'): if id is None: require.perm('global.message') template = '/massmessage/new.html' c.preview_url = h.base_url('/message/preview') else: c.page_instance = InstanceController._get_current_instance(id) require.instance.message(c.page_instance) template = '/instance/message.html' c.preview_url = h.base_url('/instance/%s/message/preview' % id) defaults = dict(request.params) defaults.setdefault('include_footer', 'on') data = { 'instances': self._get_allowed_instances(c.user), 'sender_options': self._get_allowed_sender_options(c.user), 'userbadges': UserBadge.all(instance=c.instance, include_global=True) } return htmlfill.render(render(template, data, overlay=format == u'overlay'), defaults=defaults, errors=errors, force_defaults=False)
def init(self): self.consumer = create_consumer(self.openid_session) if not hasattr(self, "form_result"): return self._failure("", _("Invalid input.")) openid = self.form_result.get("openid") try: if not openid: raise ValueError(_("No OpenID given!")) authrequest = self.consumer.begin(openid) if not c.user and not model.OpenID.find(openid): axreq = ax.FetchRequest(h.base_url("/openid/update", absolute=True)) axreq.add(ax.AttrInfo(get_ax_mail_schema(openid), alias="email", required=True)) authrequest.addExtension(axreq) sreq = sreg.SRegRequest(required=["nickname"], optional=["email"]) authrequest.addExtension(sreq) redirecturl = authrequest.redirectURL( h.base_url("/", absolute=True), return_to=h.base_url("/openid/verify", absolute=True), immediate=False ) self.set_session(self.openid_session) session.save() return redirect(redirecturl) except HTTPFound: raise except Exception, e: log.exception(e) return self._failure(openid, str(e))
def post_logout_url(): from adhocracy.lib.helpers import base_url url = config.get('adhocracy.post_logout_url') if url is None: return base_url() instance = config.get('adhocracy.post_logout_instance') if instance is None: return base_url(url) else: return base_url(url, Instance.find(instance))
def post_login_url(user): from adhocracy.lib.helpers import base_url url = config.get('adhocracy.post_login_url') if url is None: return base_url('/user/%s/dashboard' % user.user_name) instance = config.get('adhocracy.post_login_instance') if instance is None: return base_url(url) else: return base_url(url, Instance.find(instance))
def __call__(self, environ, start_response): """Invoke the Controller""" c.instance = model.instance_filter.get_instance() if c.instance is not None: # setup a global variable to mark the current item in # the global navigation c.active_global_nav = 'instances' else: c.active_global_nav = 'home' c.user = environ.get('repoze.who.identity', {}).get('user') # make sure we're not using a detached user object if c.user: c.user = model.meta.Session.merge(c.user) if c.user and (c.user.banned or c.user.delete_time): c.user = None c.active_controller = request.environ.get('pylons.routes_dict')\ .get('controller') c.debug = asbool(config.get('debug')) i18n.handle_request() monitor_page_time_interval = asint( config.get('adhocracy.monitor_page_time_interval', -1)) if monitor_page_time_interval > 0: c.monitor_page_time_interval = monitor_page_time_interval c.monitor_page_time_url = h.base_url('/stats/on_page') if asbool(config.get('adhocracy.monitor_external_links', 'False')): c.monitor_external_links_url = h.base_url('/stats/record_external') h.add_rss("%s News" % h.site.name(), h.base_url('/feed.rss', None)) if c.instance: h.add_rss("%s News" % c.instance.label, h.base_url('/instance/%s.rss' % c.instance.key)) h.add_meta("description", _("A liquid democracy platform for making decisions in " "distributed, open groups by cooperatively creating " "proposals and voting on them to establish their " "support.")) h.add_meta("keywords", _("adhocracy, direct democracy, liquid democracy, liqd, " "democracy, wiki, voting,participation, group decisions, " "decisions, decision-making")) try: return WSGIController.__call__(self, environ, start_response) except Exception, e: log.exception(e) model.meta.Session.rollback() raise
def breadcrumbs(user, dashboard=False): from adhocracy.lib.helpers import base_url items = [] if c.instance is not None: items.append(_url.link(_("Members"), base_url(u'/user'))) elif has('user.index_all'): items.append(_url.link(_("Members"), base_url(u'/user/all'))) if user is not None: items.append(_url.link(user.name, url(user))) if dashboard: items.append(_url.link(_('Dashboard'), base_url('/user/dashboard'))) return _url.root() + _url.BREAD_SEP.join(items)
def breadcrumbs(proposal): from adhocracy.lib.helpers import base_url bc = _url.root() if c.instance.show_proposals_navigation: bc += _url.link(_("Proposals"), base_url(u'/proposal')) elif c.instance.display_category_pages: bc += _url.link(_("Categories"), base_url(u'/category')) if proposal is not None and proposal.category is not None: bc += bc_category(proposal.category) else: # FIXME this case will produce a double BREAD_SEP pass if proposal is not None: bc += bc_entity(proposal) return bc
def create(self): require.user.create() if self.email_is_blacklisted(self.form_result['email']): return ret_abort(_("Sorry, but we don't accept registrations with " "this email address."), category='error', code=403) # SPAM protection recaptcha captacha_enabled = config.get('recaptcha.public_key', "") if captacha_enabled: recaptcha_response = h.recaptcha.submit() if not recaptcha_response.is_valid: c.recaptcha = h.recaptcha.displayhtml( use_ssl=True, error=recaptcha_response.error_code) redirect("/register") # SPAM protection hidden input input_css = self.form_result.get("input_css") input_js = self.form_result.get("input_js") if input_css or input_js: redirect("/") #create user user = model.User.create(self.form_result.get("user_name"), self.form_result.get("email").lower(), password=self.form_result.get("password"), locale=c.locale) model.meta.Session.commit() event.emit(event.T_USER_CREATE, user) libmail.send_activation_link(user) if c.instance: membership = user.instance_membership(c.instance) if membership is None: membership = model.Membership(user, c.instance, c.instance.default_group) model.meta.Session.expunge(membership) model.meta.Session.add(membership) model.meta.Session.commit() # authenticate the new registered member using the repoze.who # api. This is done here and not with an redirect to the login # to omit the generic welcome message who_api = get_api(request.environ) login = self.form_result.get("user_name").encode('utf-8') credentials = { 'login': login, 'password': self.form_result.get("password").encode('utf-8')} authenticated, headers = who_api.login(credentials) if authenticated: # redirect to dashboard with login message session['logged_in'] = True session.save() location = h.base_url('/user/%s/dashboard' % login) raise HTTPFound(location=location, headers=headers) else: raise Exception('We have added the user to the Database ' 'but cannot authenticate him: ' '%s (%s)' % (credentials['login'], user))
def update_index(self): for entity_type in model.refs.TYPES: if hasattr(entity_type, "all"): for entity in entity_type.all(): index.update(entity) flash(_("Solr index updated."), "success") redirect(base_url("/admin"))
def post_login(self): if c.user: session['logged_in'] = True session.save() came_from = session.get('came_from', None) if came_from is not None: del session['came_from'] session.save() redirect(came_from) # redirect to the dashboard inside the instance exceptionally # to be able to link to proposals and norms in the welcome # message. redirect(h.base_url(path='/user/%s/dashboard' % c.user.user_name)) else: login_configuration = h.allowed_login_types() error_message = _("Invalid login") if 'username+password' in login_configuration: if 'email+password' in login_configuration: error_message = _("Invalid email / user name or password") else: error_message = _("Invalid user name or password") else: if 'email+password' in login_configuration: error_message = _("Invalid email or password") return formencode.htmlfill.render( render("/user/login.html"), errors={"login": error_message})
def sitemap_xml(self): if c.instance: redirect(h.base_url(None, path="/sitemap.xml")) c.delegateables = model.Delegateable.all() c.change_time = datetime.utcnow() response.content_type = "text/xml" return render("sitemap.xml")
def fix_autojoin(self): config_autojoin = config.get('adhocracy.instances.autojoin') if not config_autojoin: return ret_abort('autojoin is not enabled') users = model.User.all() instances = model.Instance.all(include_hidden=True) added = 0 if config_autojoin != 'ALL': instance_keys = [key.strip() for key in config_autojoin.split(",")] instances = [ instance for instance in instances if instance.key in instance_keys ] for user in users: to_join = set(instances) for m in user.memberships: to_join.discard(m.instance) for instance in to_join: autojoin_membership = model.Membership(user, instance, instance.default_group) model.meta.Session.add(autojoin_membership) added += 1 if added > 0: model.meta.Session.commit() flash(_('Autojoin fixed - added %s memberships.') % added, 'success') return redirect(base_url('/admin'))
def carousel(self, format=u"html"): if c.instance is None: require.perm("event.index_all") data = {u"data_url": h.base_url("/event/all", query_params=request.params)} return render("/event/carousel.html", data, overlay=format == u"overlay", overlay_size=OVERLAY_SMALL)
def update_index(self): for entity_type in model.refs.TYPES: if hasattr(entity_type, "all"): for entity in entity_type.all(): index.update(entity) flash(_('Solr index updated.'), 'success') redirect(base_url('/admin'))
def breadcrumbs(category): from adhocracy.lib.helpers import base_url bc = _url.root() bc += _url.link(_("Categories"), base_url(u'/category')) if category is not None: bc += bc_entity(category) return bc
def activate(self, id): c.page_user = get_entity_or_abort(model.User, id, instance_filter=False) code = self.form_result.get('c') if c.page_user.activation_code is None: h.flash(_(u'Thank you, The address is already activated.')) redirect(h.entity_url(c.page_user)) elif c.page_user.activation_code != code: h.flash(_("The activation code is invalid. Please have it " "resent."), 'error') redirect(h.entity_url(c.page_user)) c.page_user.activation_code = None model.meta.Session.commit() if code.startswith(model.User.IMPORT_MARKER): # Users imported by admins login_user(c.page_user, request) h.flash(_("Welcome to %s") % h.site.name(), 'success') if c.instance: membership = model.Membership(c.page_user, c.instance, c.instance.default_group) model.meta.Session.expunge(membership) model.meta.Session.add(membership) model.meta.Session.commit() redirect(h.entity_url(c.instance)) else: redirect(h.base_url('/instance', None)) else: h.flash(_("Your email has been confirmed."), 'success') redirect(h.entity_url(c.page_user)) redirect(h.entity_url(c.page_user))
def breadcrumbs(page): from adhocracy.lib.helpers import base_url bc = _url.root() bc += _url.link(_("Norms"), base_url(u'/page')) if page is not None: bc += entity_bc(page) return bc
class BaseController(WSGIController): def __call__(self, environ, start_response): """Invoke the Controller""" c.instance = model.instance_filter.get_instance() if c.instance is not None: # setup a global variable to mark the current item in # the global navigation c.active_global_nav = 'instances' else: c.active_global_nav = 'home' c.user = environ.get('repoze.who.identity', {}).get('user') try: if c.user and (c.user.banned or c.user.delete_time): c.user = None except DetachedInstanceError, e: log.exception(e) c.active_controller = request.environ.get('pylons.routes_dict')\ .get('controller') c.debug = asbool(config.get('debug')) i18n.handle_request() h.add_rss("%s News" % h.site.name(), h.base_url(None, path='/feed.rss')) if c.instance: h.add_rss( "%s News" % c.instance.label, h.base_url(c.instance, '/instance/%s.rss' % c.instance.key)) h.add_meta( "description", _("A liquid democracy platform for making decisions in " "distributed, open groups by cooperatively creating " "proposals and voting on them to establish their " "support.")) h.add_meta( "keywords", _("adhocracy, direct democracy, liquid democracy, liqd, " "democracy, wiki, voting,participation, group decisions, " "decisions, decision-making")) try: return WSGIController.__call__(self, environ, start_response) except Exception, e: log.exception(e) model.meta.Session.rollback() raise
def sitemap_xml(self): if c.instance: redirect(h.base_url('/sitemap.xml', None)) c.proposals = model.Proposal.all() c.pages = model.Page.all(functions=[model.Page.NORM]) c.change_time = datetime.utcnow() response.content_type = "text/xml" return render("sitemap.xml")
def send_activation_link(user): url = h.base_url("/user/%s/activate?c=%s" % (user.user_name, user.activation_code), instance=None, absolute=True) body = _("this email is to check the email address you have provided. " "In order to confirm this email address, please open the link " "below in your browser:") + "\r\n\r\n " + url to_user(user, _("Confirm your email address"), body)
def user_import(_users, email_subject, email_template, creator, instance, reinvite=False): names = [] created = [] mailed = [] errors = False users = [] for user_info in _users: try: name = user_info['user_name'] email = user_info['email'] try: display_name = user_info['display_name'] names.append(name) if reinvite: user = model.User.find(name) else: user = model.User.create(name, email, display_name=display_name, autojoin=False) user.activation_code = user.IMPORT_MARKER + random_token() password = random_token() user_info['password'] = password user.password = password for badge in user_info['user_badges']: badge.assign(user, creator=creator) model.meta.Session.add(user) model.meta.Session.commit() users.append(user) created.append(user.user_name) url = base_url("/user/%s/activate?c=%s" % (user.user_name, user.activation_code), instance=instance, absolute=True) user_info['url'] = url body = email_template.format(*user_info.get('rest', []), **user_info) to_user(user, email_subject, body, decorate_body=False) mailed.append(user.user_name) except Exception, E: log.error('user import for user %s, email %s, exception %s' % (user_info['user_name'], user_info['email'], E)) errors = True continue except Exception, E: log.error('user import invalid user exception %s' % E) errors = True continue
def create(self): t = model.Treatment.create( self.form_result['key'], self.form_result['source_badges'], self.form_result['variant_count'], ) model.meta.Session.commit() h.flash(_("Treatment has been created."), 'success') return redirect(h.base_url('/admin/treatment/'))
def _login(self, user): """ log the user in and redirect him to a sane place. """ login_user(user, request) if c.instance and not user.is_member(c.instance): redirect(h.base_url("/instance/join/%s?%s" % (c.instance.key, h.url_token()))) redirect("/")
def login(self): c.active_global_nav = "login" if c.user: redirect('/') else: session['came_from'] = request.params.get('came_from', h.base_url()) session.save() return render('/user/login.html')
def _login(self, user): """ log the user in and redirect him to a sane place. """ login_user(user, request) if c.instance and not user.is_member(c.instance): redirect(h.base_url(c.instance, path="/instance/join/%s?%s" % (c.instance.key, h.url_token()))) redirect("/")
def set_password(self, id): c.page_user = get_entity_or_abort(model.User, id, instance_filter=False) require.user.edit(c.page_user) c.page_user.password = self.form_result.get('password') model.meta.Session.add(c.page_user) model.meta.Session.commit() h.flash(_('Password has been set. Have fun!'), 'success') redirect(h.base_url('/'))
def link(self): try: if not self.event: return None return self.event.link_path(self) except: from adhocracy.lib import helpers as h if self.instance: return h.entity_url(self.instance) return h.base_url(instance=None)
def new(self): c.active_global_nav = "login" if c.user: redirect('/') else: captacha_enabled = config.get('recaptcha.public_key', "") c.recaptcha = captacha_enabled and h.recaptcha.displayhtml() session['came_from'] = request.params.get('came_from', h.base_url(c.instance)) session.save() return render("/user/register.html")
def user_import(_users, email_subject, email_template, creator, instance, reinvite=False): names = [] created = [] mailed = [] errors = False users = [] for user_info in _users: try: name = user_info['user_name'] email = user_info['email'] try: display_name = user_info['display_name'] names.append(name) if reinvite: user = model.User.find(name) else: user = model.User.create(name, email, display_name=display_name, autojoin=False) user.activation_code = user.IMPORT_MARKER + random_token() password = random_token() user_info['password'] = password user.password = password for badge in user_info['user_badges']: badge.assign(user, creator=creator) model.meta.Session.add(user) model.meta.Session.commit() users.append(user) created.append(user.user_name) url = base_url( "/user/%s/activate?c=%s" % (user.user_name, user.activation_code), instance=instance, absolute=True) user_info['url'] = url body = email_template.format(*user_info.get('rest', []), **user_info) to_user(user, email_subject, body, decorate_body=False) mailed.append(user.user_name) except Exception, E: log.error('user import for user %s, email %s, exception %s' % (user_info['user_name'], user_info['email'], E)) errors = True continue except Exception, E: log.error('user import invalid user exception %s' % E) errors = True continue
def _login(self, user, register=False): """ log the user in and redirect him to a sane place. """ login_user(user, request, response) session["login_type"] = "openid" if c.instance and not user.is_member(c.instance): redirect(h.base_url("/instance/join/%s?%s" % (c.instance.key, h.url_token()))) if register: redirect(h.user.post_register_url(user)) else: redirect(h.user.post_login_url(user))
def post_login(self): if c.user: session['logged_in'] = True session.save() # redirect to the dashboard inside the instance exceptionally # to be able to link to proposals and norms in the welcome # message. redirect(h.base_url(path='/user/%s/dashboard' % c.user.user_name)) else: return formencode.htmlfill.render( render("/user/login.html"), errors={"login": _("Invalid user name or password")})
def carousel(self, format=u'html'): if c.instance is None: require.perm('event.index_all') data = { u'data_url': h.base_url('/event/all', query_params=request.params) } return render('/event/carousel.html', data, overlay=format == u'overlay', overlay_size=OVERLAY_SMALL)
def all(self, format='html'): if c.instance is None: require.perm('event.index_all') events = model.Event.all_q( instance=c.instance, include_hidden=False, event_filter=request.params.getall('event_filter'))\ .order_by(model.Event.time.desc())\ .limit(min(int(request.params.get('count', 50)), 100)).all() if format == 'rss': return event.rss_feed(events, _('%s News' % h.site.name()), h.base_url(instance=None), _("News from %s") % h.site.name()) elif format == 'ajax': query_params = request.params.copy() while True: try: query_params.pop('count') except KeyError: break more_url = h.base_url(instance=c.instance, member='event/all', query_params=query_params) return render_def('/event/tiles.html', 'carousel', events=events, more_url=more_url) else: c.event_pager = pager.events(events, count=50) if format == 'overlay': return render('/event/all.html', overlay=True, overlay_size=OVERLAY_SMALL) else: return render('/event/all.html')
def rewrite_urls(body): from adhocracy.lib.helpers import base_url if not config.get_bool('adhocracy.track_outgoing_links'): return body doc = lxml.etree.fromstring('<body>' + body + '</body>') for a in doc.xpath('.//a[@href]'): if re.match(r'ftps?:|https?:|//', a.attrib['href']): url = a.attrib['href'] # Is it a link to our own site? base = base_url('/', instance=None) if (url.startswith(base) and not (url.startswith('//') and base == '/')): continue encoded_url = base64.urlsafe_b64encode(url.encode('utf-8')) signed_url = sign(encoded_url, salt=REDIRECT_SALT) redirect_url = u'/outgoing_link/' + signed_url.decode('utf-8') a.attrib['href'] = base_url(redirect_url) res = lxml.etree.tostring(doc) return res[len(b'<body>'):-len(b'</body>')]
def post_login(self): if c.user: url = h.base_url(c.instance) if 'came_from' in session: url = session.get('came_from') del session['came_from'] session.save() h.flash(_("You have successfully logged in."), 'success') redirect(str(url)) else: session.delete() return formencode.htmlfill.render( render("/user/login.html"), errors={"login": _("Invalid user name or password")})
def _login(self, user, register=False): """ log the user in and redirect him to a sane place. """ login_user(user, request, response) session['login_type'] = 'openid' if c.instance and not user.is_member(c.instance): redirect( h.base_url("/instance/join/%s?%s" % (c.instance.key, h.url_token()))) if register: redirect(h.user.post_register_url(user)) else: redirect(h.user.post_login_url(user))
def ret_status(type_, message, entity=None, code=200, format='html'): import adhocracy.lib.helpers as h response.status_int = code if code != 200: if format == 'json': return ret_json_status(type_, message, code) abort(code, message) if message: if format == 'json': return ret_json_status(type_, message, code) h.flash(message) if entity is not None: redirect(h.entity_url(entity, format=format)) redirect(h.base_url(c.instance))
def all(self, format='html'): query = model.meta.Session.query(model.Event) query = query.order_by(model.Event.time.desc()) query = query.limit(50) if format == 'rss': events = query.all() return event.rss_feed(events, _('%s News' % h.site.name()), h.base_url(instance=None), _("News from %s") % h.site.name()) c.event_pager = NamedPager('events', query.all(), tiles.event.row, count=50) return render('/event/all.html')
def update(self, key, lang): backend = get_backend() sp = backend.get(key, lang) if not sp: return ret_abort(_('Cannot find static page to edit'), code=404) try: form_result = EditForm().to_python(request.params) except Invalid as i: return self.edit(errors=i.unpack_errors()) sp.title = form_result.get('title') sp.body = form_result.get('body') sp.commit() helpers.flash(_('Page updated'), 'notice') return redirect(helpers.base_url('/static/'))