def role_update_(request, callback=None, renderers=None, validators=None, values=None): role = get_item_from_request(request) # Store the name of the role in the request to make it # available in the callback request._oldname = role.name _ = request.translate uniqueness_validator = Validator('name', _('This name is already in use, ' 'please use something unique.'), role_name_update_validator, {'pk': role.id, 'db': request.db}) if validators is None: validators = [] validators.append(uniqueness_validator) callbacks = [] if callback: if isinstance(callback, list): callbacks.extend(callback) else: callbacks.append(callback) return update(request, values=values, validators=validators, callback=callbacks)
def handle_redirect_on_success(request, backurl=None): """Will return a redirect. If there has been a saved "backurl" the redirect will on on this url. In all other cases the function will try to determine if the item in the request can be opened in edit mode or not. If the current user is allowed to open the item in edit mode then the update view is called. Else the read view is called. :request: Current request :backurl: Optional. Set backurl manually. This will overwrite backurls saved in the session. :returns: Redirect """ item = get_item_from_request(request) clazz = request.context.__model__ backurl = backurl or request.session.get("%s.backurl" % clazz) if backurl: # Redirect to the configured backurl. if request.session.get("%s.backurl" % clazz): del request.session["%s.backurl" % clazz] request.session.save() return HTTPFound(location=backurl) else: # Handle redirect after success. # Check if the user is allowed to call the url after saving if has_permission("update", item, request): route_name = get_action_routename(item, "update") url = request.route_path(route_name, id=item.id) else: route_name = get_action_routename(item, "read") url = request.route_path(route_name, id=item.id) return HTTPFound(location=url)
def handle_callback(request, callbacks, item=None, mode=None): """Will call the given `callbacks`. If callbacks is a list all of the defined callbacks are called. The `mode` attribute is a comma sperated list of string and works as some kind of filter on the given callbacks and defines which callbacks are actually called. :class:Callback instances can be configured to be called "pre" or "post" the actual action of the view. The mode will only execute matching callback instances. There is a special mode "default" which is used to maintain the old behaviour of the handling of the callbacks. Adding "default" as mode will execute either simple callables as callbacks (old style) or new style callbacks with undefined mode. :request: Current request :callback: Callable function or list of callable functions :item: item for which the callback will be called. :mode: Filter on the given callbacks. Defines which callbacks are actually called. :returns: item """ if mode is None: mode = [None] else: modes = mode.split(",") if not item: item = get_item_from_request(request) if callbacks is None: return item if not isinstance(callbacks, list): callbacks = [callbacks] for cb in callbacks: # Handle callback objects. if isinstance(cb, Callback) and ( (cb.mode in modes) or (cb.mode is None and "default" in modes)): # New callback objects. Only call the callback if the mode # matches or if the mode of the callback is non but we are # in "default" mode. item = cb(request, item) elif not isinstance(cb, Callback) and ("default" in modes or None in modes): # Old simple callabel. Only call the callback if we are in # default mode or no mode is given. # None. item = cb(request, item) else: # Otherwise ignore the callback continue return item
def get_return_value(request): """Will return a dictionary of values used as context in the templates. The dictionary will include: * clazz: clazz of the current request * item: item of the current request :request: Current request :returns: Dictionary with values as context """ rvalues = {} clazz = request.context.__model__ item = get_item_from_request(request) rvalues["clazz"] = clazz rvalues["item"] = item return rvalues
def setstandin(request, allowed_users=None): """Setting members in the default usergroup of the current user. Technically this is adding a standin for this user.""" # Check authentification # As this view has now security configured it is # generally callable by all users. For this reason we first check if # the user is authenticated. If the user is not authenticated the # raise an 401 (unauthorized) exception. if not request.user: raise HTTPUnauthorized # Check authorisation # For normal users users shall only be allowed to set the standin # for their own usergroup. So check this and otherwise raise an exception. usergroup = get_item_from_request(request) if (usergroup.id != request.user.default_gid and not has_permission("update", usergroup, request)): raise HTTPForbidden() clazz = Usergroup request.session['%s.form' % clazz] = "membersonly" request.session.save() values = {} if allowed_users: values['_allowedusers'] = [u.login for u in allowed_users] # Result may be a HTTPFOUND object. result = update(request, values=values) if isinstance(result, dict): # If the standing is set by an administrational user then the id # of the usergroup´s user is stored in the the backurl. if request.GET.get('backurl'): user_id = urlparse.urlparse( request.GET.get('backurl')).path.split('/')[-1] user = request.db.query(User).get(user_id) if not user: raise HTTPBadRequest() # Otherwise the user sets the standin of his own group. In this # case the user is already in the request. else: user = request.user result['user'] = user # Reset form value in session handle_caching(request) return result
def handle_callback(request, callback, item=None): """Will call the given callback :request: Current request :callback: Callable function or list of callable functions :item: item for which the callback will be called. :returns: item """ if not item: item = get_item_from_request(request) if isinstance(callback, list): for cb in callback: item = cb(request, item) elif callback: item = callback(request, item) return item
def setstandin(request, allowed_users=None): """Setting members in the default usergroup of the current user. Technically this is adding a standin for this user.""" # Check authentification # As this view has now security configured it is # generally callable by all users. For this reason we first check if # the user is authenticated. If the user is not authenticated the # raise an 401 (unauthorized) exception. if not request.user: raise HTTPUnauthorized # Check authorisation # For normal users users shall only be allowed to set the standin # for their own usergroup. So check this and otherwise raise an exception. usergroup = get_item_from_request(request) if (usergroup.id != request.user.default_gid and not has_permission("update", usergroup, request)): raise HTTPForbidden() clazz = Usergroup request.session['%s.form' % clazz] = "membersonly" request.session['%s.backurl' % clazz] = request.current_route_path() request.session.save() values = {} if allowed_users: values['_allowedusers'] = [u.login for u in allowed_users] # Result may be a HTTPFOUND object. result = update(request, values=values) if isinstance(result, dict): # If the standing is set by an administrational user then the id # of the usergroup´s user is stored in the the backurl. if request.GET.get('backurl'): user_id = urlparse.urlparse( request.GET.get('backurl')).path.split('/')[-1] user = request.db.query(User).filter(User.id == user_id).one() # Otherwise the user sets the standin of his own group. In this # case the user is already in the request. else: user = request.user result['user'] = user # Reset form value in session handle_caching(request) return result
def get_return_value(request): """Will return a dictionary of values used as context in the templates. The dictionary will include: * clazz: clazz of the current request * item: item of the current request :request: Current request :returns: Dictionary with values as context """ rvalues = {} clazz = request.context.__model__ item = get_item_from_request(request) rvalues['clazz'] = clazz rvalues['item'] = item rvalues['request'] = request return rvalues
def handle_redirect_on_success(request, backurl=None): """Will return a redirect. If there has been a saved "backurl" the redirect will on on this URL. In all other cases the function will try to determine if the item in the request can be opened in edit mode or not. If the current user is allowed to open the item in edit mode then the update view is called. Else the read view is called. :request: Current request :backurl: Optional. Set backurl manually. This will overwrite backurl saved in the session. :returns: Redirect """ item = get_item_from_request(request) clazz = request.context.__model__ backurl = backurl or request.session.get('%s.backurl' % clazz) if request.session.get('%s.backurl' % clazz): del request.session['%s.backurl' % clazz] request.session.save() if backurl and (request.params.get("_submit") not in ["stay", "nextpage"]): # Ignore the redirect to the backurl if the user clicks on # "Save" and "Save and proceed" Buttons. In this case a special # value is part of the form. In case of "Save and return" or # the default submittbuttons with no special value we keep the # old behavior. return HTTPFound(location=backurl) elif request.path.find("/create") > -1 or request.path.find( "/update") > -1: # Handle redirect after success.in case of a create. # Check if the user is allowed to call the url after saving if has_permission("update", item, request): route_name = get_action_routename(item, 'update') url = request.route_path(route_name, id=item.id) else: route_name = get_action_routename(item, 'read') url = request.route_path(route_name, id=item.id) return HTTPFound(location=url) else: # Handle all other variants of the redirect and stay on the # current url. return HTTPFound(location=request.url)
def update_(request, callback=None, renderers=None, validators=None, values=None): user = get_item_from_request(request) # Store the login name of the user in the request to make it # available in the callback request._oldlogin = user.login _ = request.translate uniqueness_validator = Validator( 'login', _('This name is already in use, ' 'please use something unique.'), user_name_update_validator, { 'pk': user.id, 'db': request.db }) pw_len_validator = Validator( 'password', _('Password must be at least 12 characters ' 'long.'), password_minlength_validator) pw_nonchar_validator = Validator( 'password', _('Password must contain at least 2 ' 'non-letters.'), password_nonletter_validator) if validators is None: validators = [] validators.append(uniqueness_validator) validators.append(pw_len_validator) validators.append(pw_nonchar_validator) callbacks = [] callbacks.append(user_update_callback) if callback: if isinstance(callback, list): callbacks.extend(callback) else: callbacks.append(callback) return update(request, values=values, validators=validators, callback=callbacks)
def update_(request, callback=None, renderers=None, validators=None, values=None): user = get_item_from_request(request) # Store the login name of the user in the request to make it # available in the callback request._oldlogin = user.login _ = request.translate uniqueness_validator = Validator('login', _('This name is already in use, ' 'please use something unique.'), user_name_update_validator, {'pk': user.id, 'db': request.db}) pw_len_validator = Validator('password', _('Password must be at least 12 characters ' 'long.'), password_minlength_validator) pw_nonchar_validator = Validator('password', _('Password must contain at least 2 ' 'non-letters.'), password_nonletter_validator) if validators is None: validators = [] validators.append(uniqueness_validator) validators.append(pw_len_validator) validators.append(pw_nonchar_validator) callbacks = [] callbacks.append(user_update_callback) if callback: if isinstance(callback, list): callbacks.extend(callback) else: callbacks.append(callback) return update(request, values=values, validators=validators, callback=callbacks)
def export(request): handle_history(request) handle_params(request) item = get_item_from_request(request) return _handle_export_request(request, [item])
def handle_POST_request(form, request, callback, event="", renderers=None): """@todo: Docstring for handle_POST_request. :name: @todo :request: @todo :callback: @todo :renderers: @todo :event: Name of the event (update, create...) Used for the event handler :returns: True or False """ _ = request.translate clazz = request.context.__model__ item_label = get_item_modul(request, clazz).get_label() item = get_item_from_request(request) mapping = {"item_type": item_label, "item": item} # Add a *special* validator to the form to trigger rendering a # permanent info pane at the top of the form in case of errors on # validation. This info has been added because users reported data # loss because of formbar/ringo default behaviour of not saving # anything in case of errors. Users seems to expect that the valid # part of the data has been saved. This info should make the user # aware of the fact that nothing has been saved in case of errors. error_message = _( "The information contained errors. " "<strong>All entries (including error-free) were not " "saved!</strong> Please correct your entries in the " "fields marked in red and resave." ) form.add_validator(Validator(None, literal(error_message), callback=form_has_errors, context=form)) # Begin a nested transaction. In case an error occours while saving # the data the nested transaction will be rolled back. The parent # session will be still ok. request.db.begin_nested() if form.validate(request.params) and "blobforms" not in request.params: checker = ValueChecker() try: if event == "create": try: factory = clazz.get_item_factory(request) except TypeError: # Old version of get_item_factory method which does # not take an request parameter. factory = clazz.get_item_factory() factory._request = request checker.check(clazz, form.data, request) item = factory.create(request.user, form.data) item.save({}, request) request.context.item = item handle_add_relation(request, item) else: values = checker.check(clazz, form.data, request, item) item.save(values, request) handle_event(request, item, event) handle_callback(request, callback) handle_caching(request) if event == "create": msg = _("Created new ${item_type} successfully.", mapping=mapping) log_msg = u"User {user.login} created {item_label} {item.id}".format( item_label=item_label, item=item, user=request.user ) else: msg = _('Edited ${item_type} "${item}" successfully.', mapping=mapping) log_msg = u"User {user.login} edited {item_label} {item.id}".format( item_label=item_label, item=item, user=request.user ) log.info(log_msg) request.session.flash(msg, "success") # Set next form page. if request.params.get("_submit") == "nextpage": table = clazz.__table__ itemid = item.id page = get_next_form_page(form, get_current_form_page(clazz, request)) set_current_form_page(table, itemid, page, request) # In case all is ok merge the nested session. request.db.merge(item) return True except Exception as error: request.db.rollback() mapping["error"] = unicode(error.message) if event == "create": msg = _("Error while saving new " "${item_type}: ${error}.", mapping=mapping) else: msg = _("Error while saving " '${item_type} "${item}": ${error}.', mapping=mapping) log.exception(msg) request.session.flash(msg, "critical") return False elif "blobforms" in request.params: pass else: request.db.rollback() if event == "create": msg = _("Error on validation new " "${item_type}.", mapping=mapping) else: msg = _("Error on validation " '${item_type} "${item}".', mapping=mapping) log.debug(msg) request.session.flash(msg, "error") return False
def handle_POST_request(form, request, callback, event="", renderers=None): """@todo: Docstring for handle_POST_request. :name: @todo :request: @todo :callback: @todo :renderers: @todo :event: Name of the event (update, create...) Used for the event handler :returns: True or False """ _ = request.translate clazz = request.context.__model__ item_label = get_item_modul(request, clazz).get_label() item = get_item_from_request(request) mapping = {'item_type': item_label, 'item': item} # Add a *special* validator to the form to trigger rendering a # permanent info pane at the top of the form in case of errors on # validation. This info has been added because users reported data # loss because of formbar/ringo default behaviour of not saving # anything in case of errors. Users seems to expect that the valid # part of the data has been saved. This info should make the user # aware of the fact that nothing has been saved in case of errors. error_message = _("The information contained errors. " "<strong>All entries (including error-free) were not " "saved!</strong> Please correct your entries in the " "fields marked in red and resave.") form.add_validator( Validator(None, literal(error_message), callback=form_has_errors, context=form)) # Begin a nested transaction. In case an error occours while saving # the data the nested transaction will be rolled back. The parent # session will be still ok. request.db.begin_nested() if form.validate(request.params) and "blobforms" not in request.params: checker = ValueChecker() try: # Handle new callback objects wich are configured to be # called previous the origin action. Old simple callbacks # are ignored. handle_callback(request, callback, mode="pre") if event == "create": try: factory = clazz.get_item_factory(request) except TypeError: # Old version of get_item_factory method which does # not take an request parameter. factory = clazz.get_item_factory() factory._request = request checker.check(clazz, form.data, request) item = factory.create(request.user, form.data) handle_add_relation(request, item) item.save({}, request) request.context.item = item else: values = checker.check(clazz, form.data, request, item) item.save(values, request) handle_event(request, item, event) # Maintain old behaviour of callbacks. Callback are called # post the origin action of the view. Therefor the callback # must either be an instance of :class:Callback with mode # "post" or it is a simple callable. handle_callback(request, callback, mode="post,default") handle_caching(request) if event == "create": msg = _('Created new ${item_type} successfully.', mapping=mapping) log_msg = u'User {user.login} created {item_label} {item.id}'\ .format(item_label=item_label, item=item, user=request.user) else: msg = _('Edited ${item_type} "${item}" successfully.', mapping=mapping) log_msg = u'User {user.login} edited {item_label} {item.id}'\ .format(item_label=item_label, item=item, user=request.user) log.info(log_msg) request.session.flash(msg, 'success') # Set next form page. if request.params.get("_submit") == "nextpage": table = clazz.__table__ itemid = item.id page = get_next_form_page( form, get_current_form_page(clazz, request)) set_current_form_page(table, itemid, page, request) # In case all is ok merge the nested session. request.db.merge(item) return True except Exception as error: request.db.rollback() mapping['error'] = unicode(error.message) if event == "create": log_msg = _(u'User {user.login} created' '{item_label}').format(item_label=item_label, user=request.user) msg = _('Error while saving new ' '${item_type}: ${error}.', mapping=mapping) else: log_msg = _(u'User {user.login} edited ' '{item_label} {item.id}').format( item_label=item_label, item=item, user=request.user) msg = _( 'Error while saving ' '${item_type} "${item}": ${error}.', mapping=mapping) log.exception(log_msg) request.session.flash(msg, 'critical') return False elif "blobforms" in request.params: pass else: request.db.rollback() if event == "create": msg = _('Error on validation new ' '${item_type}.', mapping=mapping) else: msg = _('Error on validation ' '${item_type} "${item}".', mapping=mapping) log.debug(msg) request.session.flash(msg, 'error') return False
def export(request): item = get_item_from_request(request) return _handle_export_request(request, [item])