def get_open_url(request, item): """Convinience method to the a URL to 'open' the item.""" from ringo.lib.security import has_permission if has_permission("update", item, request): return request.route_path(get_action_routename(item, "update"), id=item.id) elif has_permission("read", item, request): return request.route_path(get_action_routename(item, "read"), id=item.id) return None
def render(self, request): """Initialize renderer""" # Get the bundles_actions. # If bundle_actions is True, display checkboxes and more in the table. bundled_actions = [] for action in get_item_actions(request, self.listing.clazz): if action.bundle and security.has_permission( action.name.lower(), request.context, request): bundled_actions.append(action) table_id = self._get_table_id() table_config = self._render_js_config(request, table_id, bundled_actions) values = { 'items': self.listing.items, 'clazz': self.listing.clazz, 'listing': self.listing, 'request': request, '_': request.translate, 's': security, 'h': ringo.lib.helpers, 'bundled_actions': bundled_actions, 'tableconfig': self.config, 'tableid': table_id, 'dtconfig': table_config } return literal(self.template.render(**values))
def filter_itemlist_for_user(request, baselist): """Returns a filterd baselist. The items are filterd based on the permission of the current user in the request. Only items are included where the given user has read access. This means: 1. The user has aproriate role (read access) 2. Is owner or member of the items group :request: Current request :baselist: BaseList instance :returns: Filtered BaseList instance """ from ringo.lib.security import has_permission filtered_items = [] if request.user and not request.user.has_role("admin"): # Iterate over all items and check if the user has generally # access to the item. for item in baselist.items: # Only check ownership if the item provides a uid. if has_permission('read', item, request): filtered_items.append(item) baselist.items = filtered_items # Mark this listing to be prefilterd for a user. baselist._user = request.user return baselist
def render(self, request): """Initialize renderer""" # Get the bundles_actions. # If bundle_actions is True, display checkboxes and more in the table. bundled_actions = [] for action in get_item_actions(request, self.listing.clazz): if action.bundle and security.has_permission(action.name.lower(), request.context, request): bundled_actions.append(action) table_id = self._get_table_id() table_config = self._render_js_config(request, table_id) values = {'items': self.listing.items, 'clazz': self.listing.clazz, 'listing': self.listing, 'request': request, '_': request.translate, 's': security, 'h': ringo.lib.helpers, 'bundled_actions': bundled_actions, 'tableconfig': self.config, 'tableid': table_id, 'dtconfig': table_config} return literal(self.template.render(**values))
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 get_link_url(item, request, actionname=None, backurl=False): """Return a url to the given item. On default the link will be a link to the update or read view of the item depending on the permission. If the application is configured to open items in read mode on default the update action will not be checked. If the user does not have enough permissions than None is returned. Optionally you can provide the name of a action. In this case the url will be build for the given actionname if the user has enough permissions.""" readmode = request.registry.settings.get("app.readmode") in [ "True", "true" ] if isinstance(item, BaseItem): if actionname: from ringo.views.helpers import get_item_modul modul = get_item_modul(request, item) action = modul.get_action(actionname) if action is None: # This can happen if the action is not part of the modul # but a custum userdefined view. No permission checks # are done here yet. route_name = get_action_routename(item, actionname) else: permission = action.permission or action.name.lower() if security.has_permission(permission, item, request): route_name = get_action_routename(item, action.name.lower()) else: return None elif not readmode and security.has_permission("update", item, request): route_name = get_action_routename(item, 'update') elif security.has_permission("read", item, request): route_name = get_action_routename(item, 'read') else: return None query = {} if backurl: clazz = request.context.__model__ query['backurl'] = request.session.get( '%s.backurl' % clazz) or request.current_route_path() return request.route_path(route_name, id=item.id, _query=query) return None
def get_modules(request, display): # FIXME: Circular import (ti) <2015-05-11 21:52> from ringo.lib.security import has_permission user_moduls = [] # The modules has been load already and are cached. So get them from # the cache for modul in request.cache_item_modul.all().values(): # Only show the modul if it matches the desired display location # and if the modul has an "list" action which usually is used as # entry point into a modul. if (modul.display == display and modul.has_action('list')): clazz = dynamic_import(modul.clazzpath) if has_permission('list', clazz, request): user_moduls.append(modul) return user_moduls
def _get_template_values(self): values = FieldRenderer._get_template_values(self) comments = [] for comment in self._field._form._item.comments: if security.has_permission('read', comment, self._field._form._request): comments.append(comment) if self._field._form.has_errors(): last_comment = self._field._form.submitted_data.get("comment", "") else: last_comment = "" values['last_comment'] = last_comment values['comments'] = comments return values
def get_link_url(item, request, actionname=None, backurl=False): """Return a url to the given item. On default the link will be a link to the update or read view of the item depending on the permission. If the user does not have enough permissions than None is returned. Optionally you can provide the name of a action. In this case the url will be build for the given actionname if the user has enough permissions.""" if isinstance(item, BaseItem): if actionname: from ringo.views.helpers import get_item_modul modul = get_item_modul(request, item) action = modul.get_action(actionname) if action is None: # This can happen if the action is not part of the modul # but a custum userdefined view. No permission checks # are done here yet. route_name = get_action_routename(item, actionname) else: permission = action.permission or action.name.lower() if security.has_permission(permission, item, request): route_name = get_action_routename(item, action.name.lower()) else: return None elif security.has_permission("update", item, request): route_name = get_action_routename(item, 'update') elif security.has_permission("read", item, request): route_name = get_action_routename(item, 'read') else: return None query = {} if backurl: query['backurl'] = request.current_route_path() return request.route_path(route_name, id=item.id, _query=query) return None
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 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 filter_options_on_permissions(request, options): """Will filter the given options based on the permissions on the current user of the request. After filtering the options will only have items where the user is allowed to at least read it. :request: current request :options: list of tuple of options (item, value, filtered) :returns: filtered list of option tuples. """ filtered_options = [] for option in options: visible = False if (option[2] and (security.has_permission('read', option[0], request) or not hasattr(option[0], 'owner'))): visible = True filtered_options.append((option[0], option[1], visible)) return filtered_options
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 get_open_url(request, item): """Convinience method to the a URL to 'open' the item.""" from ringo.lib.security import has_permission permissions = ['read'] # If the application is configured to open items in readmode on # default then we will not add the update action to the actions to # check. if not request.registry.settings.get("app.readmode") in ["True", "true"]: permissions.append('update') url = None for permission in permissions: if has_permission(permission, item, request): route_name = get_action_routename(item, permission) url = request.route_path(route_name, id=item.id) else: break return url
def render(self, request): """Initialize renderer""" # TODO: Enabled sorting of lists. Mind that these lists might be # presorted if the user clicked on the header. In this case some # get params with sort configurations are in the session. This # logic is currently in base/view. (ti) <2014-01-23 23:15> # sort_field = self.config.get_default_sort_column() # sort_order = self.config.get_default_sort_order() # self.listing.sort(sort_field, sort_order) if len(self.listing.search_filter) > 0: search = self.listing.search_filter[-1][0] search_field = self.listing.search_filter[-1][1] regexpr = self.listing.search_filter[-1][2] else: search = "" search_field = "" regexpr = False ssearch = get_saved_searches(request, self.listing.clazz.__tablename__) bundled_actions = [] for action in get_item_actions(request, self.listing.clazz): if action.bundle and security.has_permission(action.name.lower(), request.context, request): bundled_actions.append(action) values = {'items': self.listing.items, 'clazz': self.listing.clazz, 'listing': self.listing, 'request': request, '_': request.translate, 'h': ringo.lib.helpers, 's': security, 'bundled_actions': bundled_actions, 'search': search, 'regexpr': regexpr, 'search_field': search_field, 'saved_searches': ssearch, 'tableconfig': self.config} return literal(self.template.render(**values))
def render(self, request): """Initialize renderer""" # TODO: Enabled sorting of lists. Mind that these lists might be # presorted if the user clicked on the header. In this case some # get params with sort configurations are in the session. This # logic is currently in base/view. (ti) <2014-01-23 23:15> # sort_field = self.config.get_default_sort_column() # sort_order = self.config.get_default_sort_order() # self.listing.sort(sort_field, sort_order) if len(self.listing.search_filter) > 0: search = self.listing.search_filter[-1][0] search_field = self.listing.search_filter[-1][1] regexpr = self.listing.search_filter[-1][2] else: search = "" search_field = "" regexpr = False ssearch = get_saved_searches(request, self.listing.clazz.__tablename__) bundled_actions = [] for action in get_item_actions(request, self.listing.clazz): if action.bundle and security.has_permission( action.name.lower(), request.context, request): bundled_actions.append(action) values = { 'items': self.listing.items, 'clazz': self.listing.clazz, 'listing': self.listing, 'request': request, '_': request.translate, 'h': ringo.lib.helpers, 's': security, 'bundled_actions': bundled_actions, 'search': search, 'regexpr': regexpr, 'search_field': search_field, 'saved_searches': ssearch, 'tableconfig': self.config } return literal(self.template.render(**values))
def filter_options_on_permissions(request, options): """Will iterate over all options and build a tuple for each option with the following information: 1. The option itself 2. The value of the option 3. A flag indicating if the requesting user is allowed to `link` the option. This information is later used on rendering. :request: current request :options: list of tuple of options (item, value, linkable) :returns: filtered list of option tuples. """ filtered_options = [] for option in options: linkable = False if (option[2] and (security.has_permission('link', option[0], request) or not hasattr(option[0], 'owner'))): linkable = True filtered_options.append((option[0], option[1], linkable)) return filtered_options
def get_read_update_url(request, item, clazz, prefilterd=False): """Helper method to get the URL to read or update in item in various overviews. If the user of this request is not allowed to see the item at all, None will be returned as the url.""" permissions = ['read'] # If the application is configured to open items in readmode on # default then we will not add the update action to the actions to # check. if not request.registry.settings.get("app.readmode") in ["True", "true"]: permissions.append('update') is_admin = request.user.has_role("admin") url = None for permission in permissions: if (permission == 'read' and prefilterd) \ or is_admin \ or security.has_permission(permission, item, request): url = request.route_path(get_action_routename(clazz, permission), id=item.id) else: break return url
def filter_itemlist_for_user(request, baselist): """Returns a filterd baselist. The items are filterd based on the permission of the current user in the request. Only items are included where the given user has read access. This means: 1. The user has aproriate role (read access) 2. Is owner or member of the items group :request: Current request :baselist: BaseList instance :returns: Filtered BaseList instance """ from ringo.lib.security import has_permission filtered_items = [] if request.user and not request.user.has_role("admin"): # Iterate over all items and check if the user has generally # access to the item. for item in baselist.items: # Only check ownership if the item provides a uid. if has_permission('read', item, request): filtered_items.append(item) baselist.items = filtered_items return baselist
def bundle_(request): clazz = request.context.__model__ module = get_item_modul(request, clazz) handle_history(request) handle_params(request) _ = request.translate # Handle bundle params. If the request has the bundle_action param # the request is the intial request for a bundled action. In this # case we can delete all previous selected and stored item ids in # the session. params = request.params.mixed() if params.get('bundle_action'): request.session['%s.bundle.action' % clazz] = params.get('bundle_action') try: del request.session['%s.bundle.items' % clazz] except KeyError: pass request.session['%s.bundle.items' % clazz] = params.get('id', []) bundle_action = request.session.get('%s.bundle.action' % clazz) ids = request.session.get('%s.bundle.items' % clazz) # Check if the user selected at least one item. If not show an # dialog informing that the selection is empty. if not ids: title = _("Empty selection") body = _("You have not selected any item in the list. " "Click 'OK' to return to the overview.") renderer = WarningDialogRenderer(request, title, body) rvalue = {} rvalue['dialog'] = literal(renderer.render(url=request.referrer)) return rvalue # If the user only selects one single item it is not a list. So # convert it to a list with one item. if not isinstance(ids, list): ids = [ids] factory = clazz.get_item_factory() items = [] ignored_items = [] for id in ids: # Check if the user is allowed to call the requested action on # the loaded item. If so append it the the bundle, if not ignore # it. item = factory.load(id) if has_permission(bundle_action.lower(), item, request): items.append(item) else: ignored_items.append(item) # After checking the permissions the list of items might be empty. # If so show a warning to the user to inform him that the selected # action is not applicable. if not items: title = _("${action} not applicable", mapping={"action": bundle_action}) body = _("After checking the permissions no items remain " "for which an '${action}' can be performed. " "(${num} items were filtered out.)", mapping={"action": bundle_action, "num": len(ignored_items)}) renderer = WarningDialogRenderer(request, title, body) rvalue = {} rvalue['dialog'] = literal(renderer.render(url=request.referrer)) return rvalue handler = get_bundle_action_handler(_bundle_request_handlers, bundle_action.lower(), module.name) return handler(request, items, None)
def set_values(self, values, use_strict=False, request=None): """Will set the values of the item. The values to be set are provided by a dictionary with key value pairs given with the `values` option. Keys in the dictionary beginning with "_" are considered private and are ignored. This function does not explicit handle saving the changed data! Saving data (E.g making a new instance of an item persistent in the DB) is handled by the :func:`.BaseItkkem.save` method. .. note:: Setting the values for foreign key attributes might not work as expected. This is especially true for foreign keys to already existing items. You are not able to change a existing relation in the items by changing the foreign key value (You must do this by setting the related item). In this case the value for the foreign key seems to be ignored and replaced by the one of the actual related item. In contrast you can set a new relation by setting the foreign key if this is a new relation. :values: Dictionary with values to be set :use_strict: boolean, if true raise a exception if an attribute is missing (default: False). """ for key, value in values.iteritems(): # Ignore private form fields if key.startswith('_'): continue try: oldvalue = getattr(self, key) # If oldvalue is equal to the new value we need no # change at all in the model so continue if oldvalue == value: continue log.debug(u"Setting value '%s' in %s" % (repr(value), key)) if isinstance(value, list) and isinstance(oldvalue, list): # Special handling for relations in NM relations. # See ticket #19 in Ringo issue tracker for more # details. Simply exchaning the relations in this # case seems not to work. I case of the error in # triggering the deleting of items in the # nm-relation from both sides. In this case the # second deletion will fail. # # Regarding to # http://docs.sqlalchemy.org/en/latest/orm/basic_relationships.html#deleting-rows-from-the-many-to-many-table # relations should be removed by using remove(item). # Howver poping the items before adding the new # items seems to work too. I excpet that poping the # items will somehow tweak SQLAlchemy in the way # that it handles deleting items correct now. # Ensure correct relations. # Commit 2b8ccb9 introduces a change for the # Listingfieldrenderer which affects handling # relations. The submitted values does no longer contain # all linked elements. Now the submitted values will # only contain linked elements which can be # read/linked by the user. Because this is often only a # subset of actually linked items, the code now must # ensure that relations to items which where not # included in the submitted values does not get lost. if request: from ringo.lib.security import has_permission # Oldvalue contains all actually linked items. for ov in oldvalue: if not has_permission("link", ov, request): # It the item was linked by the user is # not allowed to link it (is not part of # the submitted values), we must keep # the relation. value.append(ov) # Now value contains all previous linked items # the user is not allowed to change, plus the # current selection of the user. while oldvalue: oldvalue.pop(0) for nvalue in value: oldvalue.append(nvalue) else: setattr(self, key, value) except AttributeError: log.warning(('Not saving "%s". Attribute/Property not' ' found') % key) if use_strict: raise AttributeError(('Not setting "%s".' ' Attribute not found.') % key)
def bundle_(request): clazz = request.context.__model__ module = get_item_modul(request, clazz) _ = request.translate # Handle bundle params. If the request has the bundle_action param # the request is the intial request for a bundled action. In this # case we can delete all previous selected and stored item ids in # the session. params = request.params.mixed() if params.get('bundle_action'): request.session['%s.bundle.action' % clazz] = params.get('bundle_action') try: del request.session['%s.bundle.items' % clazz] except KeyError: pass request.session['%s.bundle.items' % clazz] = params.get('id', []) bundle_action = request.session.get('%s.bundle.action' % clazz) ids = request.session.get('%s.bundle.items' % clazz) # Check if the user selected at least one item. If not show an # dialog informing that the selection is empty. if not ids: title = _("Empty selection") body = _("You have not selected any item in the list. " "Click 'OK' to return to the overview.") renderer = WarningDialogRenderer(request, title, body) rvalue = {} rvalue['dialog'] = literal(renderer.render(url=request.referrer)) return rvalue # If the user only selects one single item it is not a list. So # convert it to a list with one item. if not isinstance(ids, list): ids = [ids] factory = clazz.get_item_factory() items = [] ignored_items = [] for id in ids: # Check if the user is allowed to call the requested action on # the loaded item. If so append it the the bundle, if not ignore # it. item = factory.load(id) if has_permission(bundle_action.lower(), item, request): items.append(item) else: ignored_items.append(item) # After checking the permissions the list of items might be empty. # If so show a warning to the user to inform him that the selected # action is not applicable. if not items: title = _("${action} not applicable", mapping={"action": bundle_action}) body = _( "After checking the permissions no items remain " "for which an '${action}' can be performed. " "(${num} items were filtered out.)", mapping={ "action": bundle_action, "num": len(ignored_items) }) renderer = WarningDialogRenderer(request, title, body) rvalue = {} rvalue['dialog'] = literal(renderer.render(url=request.referrer)) return rvalue handler = get_bundle_action_handler(_bundle_request_handlers, bundle_action.lower(), module.name) return handler(request, items, None)