def add(self, name=None, cls=None, read_groups=None, write_groups=None): auth = request.identity if 'a' not in auth.access(self): return drink.unauthorized("Not authorized") name = name or request.params.get('name').decode('utf-8') if name in self: return drink.unauthorized("%r is already defined!"%name) if None == cls: cls = request.params.get('class') if not cls: return drink.unauthorized("%r incorrect request!"%name) with self._lock(): o = self._add(name, cls, auth.user.default_read_groups, auth.user.default_write_groups) if o is None: return drink.unauthorized("You can't create %r objects!"%name) if request.is_ajax: return o.struct() else: return drink.rdr(o.quoted_path+'edit')
def get_object(current, objpath, no_raise=False): """ Fetch an object from database, looking at permissions to approve :arg current: root object to browse for childrens :type current: :class:`drink.Page` :arg objpath: path to the children :type objpath: str :arg no_raise: (optional) don't raise exceptions :type no_raise: `bool` """ path_list = [drink.omni(p) for p in objpath.split("/") if p] last_idx = len(path_list) - 1 pending_path = False for i, elt in enumerate(path_list): if elt[0] in "._" and elt != "_static": return drink.unauthorized("Not authorized (forbidden character)") if False != pending_path: pending_path.append(elt) elif i == last_idx: # getting try: current = current[elt] if "r" not in drink.request.identity.access(current): if not no_raise: return drink.unauthorized("Not authorized") return except (KeyError, AttributeError, TypeError): try: current = getattr(current, elt) except AttributeError: if callable(current): pending_path = [elt] else: if not no_raise: raise AttributeError(elt) return break # found a matching object else: # traversal try: current = current[elt] if "t" not in drink.request.identity.access(current): if not no_raise: return drink.unauthorized("Not authorized") return except (KeyError, AttributeError): if hasattr(current, elt) and callable(getattr(current, elt)): current = getattr(current, elt) pending_path = [] else: if no_raise: return raise AttributeError(elt) request.pending_path = pending_path return current
def borrow(self, item=None): """ Borrow an external item """ if not item: item = drink.get_object(drink.db.db, request.POST['item']) if item.id in self: return drink.unauthorized("An object with the same id stands here!") if self.path in item.path: return drink.unauthorized("Can't move an object to one if it's children!") try: parent = drink.get_object(drink.db.db, item.rootpath) except Exception, e: return drink.unauthorized("Unhandled error: %r"%e)
def html(self): if 'r' not in request.identity.access(self): return drink.unauthorized() drink.response.content_type = "text/html; charset=utf-8" if self.content: return u'''
def html(self): if 'r' not in request.identity.access(self): return drink.unauthorized() drink.response.content_type = "text/html; charset=utf-8" r = [] if self.content: mime = self.mimetype try: sz = os.stat(self.content.filename).st_size except Exception, e: log.error(repr(e)) sz = 0 # TODO: handle factory here if not sz: r.append(u'<h1>No content :(</h1>') else: r.append(u'<h1 title="%s">%s<a href="raw"><img src="/static/actions/download.png" title="Click here to download (%sB)"/></a></h1>'%(self.description, self.content_name, drink.bytes2human(sz))) r.append(u'<div class="contents">') if mime.startswith('image/'): r.append(u'<img src="raw" style="width: 80%; margin-left: 10%; margin-right: 10%;"/>') elif mime in ('application/xml', ) or mime.startswith('text/'): f = self.content.open('r') r.append(u'<pre>') r.append(unicode(f.read(), 'utf-8')) r.append(u'</pre>') r.append(u"</div>")
def serialize(self, recurse=False): if 'o' not in request.identity.access(self): return drink.unauthorized("You must be the owner to do that") d = Page.serialize(self, recurse=False) d['drink__filename'].self.content.filename return d
def upload(self): if 'w' not in request.identity.access(self): return drink.unauthorized() try: filename = request.GET.get('qqfile', '').decode('utf-8') except UnicodeError: filename = request.GET['qqfile'].decode('latin1') if not filename: return {'error': True, 'code': 400, 'message': 'Incorrect parameters. Action aborted.'} factory = self.upload_map.get(filename.rsplit('.')[-1], 'WebFile') with self._lock(): o = self._add(filename, factory, request.identity.user.default_read_groups, request.identity.user.default_write_groups) o.mimetype = get_type(filename) fake_post_obj = _Mock() fake_post_obj.file = request.body fake_post_obj.filename = filename o._upload(fake_post_obj) data = o.struct() data['success'] = True return data
def _edit(self): """ Implementation of public :meth:`~drink.Page.edit` method, only looks at http environment for now (no useable parameter). .. note:: Use :meth:`.set_field` to set some editable field value. Use : .. rubric:: HTTP parameters (other that the properties' names) :_dk_fields: Field names to edit, separated by a slash ``/`` :embedded: Just transmits this parameter to next page :_recurse: Special mode applying permissions (only) in a recursive way """ if 'w' not in request.identity.access(self): return drink.unauthorized() items = self.editable_fields.items() if request.identity.id == self.owner.id or request.identity.admin: items += self.owner_fields.items() if request.identity.admin: items += self.admin_fields.items() forms = request.forms embedded = bool(request.params.get('embedded', '')) recursive = bool(request.params.get('_recurse', '')) if forms: if '_dk_fields' in forms: editable = forms.get('_dk_fields').split('/') else: editable = forms.keys() files = request.files.keys() for attr, caster in items: if attr in files: caster.set(self, attr, request.files.get(attr)) elif attr in editable: v = forms.get(attr) caster.set(self, attr, v.decode('utf-8') if v else u'') self._update_lookup_engine() if recursive: # apply permissions recursively childs = list(self.values()) for child in childs: try: child.read_groups = self.read_groups child.write_groups = self.write_groups except Exception, e: log.warning('error applying permissionson %r : %r', child, e) else: childs.extend(child.values()) return {'redirect': "%s?embedded=%s"%(self.quoted_path, '1' if embedded else '' )}
def raw(self): if 'r' not in request.identity.access(self): return drink.unauthorized() try: if self.content: root, fname = os.path.split(self.content.filename) return drink.static_file(fname, root, mimetype=self.mimetype, download=self.content_name) except Exception, e: log.error('Error while handling %r', self.path)
def move(self): if 'w' not in request.identity.access(self): return drink.unauthorized() if request.is_ajax: self.forced_order = unquote(request.params.get('set')).decode('utf-8').split('/') else: html = '<input type="text" class="completable" complete_type="objpath" value="/pages/"></input>' return self.view(html=html)
def default_view(self, page='main.html', obj=None, css=None, js=None, html=None, embed=None, classes=None, no_auth=None, **kw): """ Renders the :class:`~drink.Page` as HTML using a template :arg self: the object to render, should contain the following properties: :css: either a list of css http paths (str) or css block :js: either a list of javascript files (str) or javascript code :html: any html <body> content :classes: in case the `classes` parameter is not given .. note:: Additional properties may be required, depending on the template used (default is "main.html") :type self: any `object` :arg page: (defaults to "main.html") template to use for rendering :type page: a :func:`bottle.template` compatible template :arg obj: (optional) overrides `self` for `obj` template parameter. The access checking & so will use `self`. The following `self` attributes may be overriden: :arg css: The list of css files to use (http relative path) or the content itself :type css: `list` of `str` or `str` with newline(s) :arg js: The list of js files to use (http relative path) or the content itself :type js: `list` of `str` or `str` with newline(s) :arg html: HTML content of the `<body>` element :type html: `unicode` :arg classes: A mapping of ``{'Object name': Drink_Page_class}`` usable objects :type classes: `dict` of `str` : :class:`drink.Page` """ if not no_auth and 'r' not in request.identity.access(self): return drink.unauthorized() drink.response.content_type = "text/html; charset=utf-8" if request.is_ajax: return {'html': html or self.html, 'js': js or self.js, 'css': css or self.css, } return bottle.template(page, template_adapter=bottle.Jinja2Template, obj=obj or self, css=css or self.css, js=js or self.js, html=html or self.html, embed=bool(request.params.get('embedded', False)) if embed is None else embed, classes=self.classes if classes is None else classes, isattr=lambda x, name: hasattr(x, name), isstring=lambda x: isinstance(x, basestring), req=request, authenticated=request.identity, **kw )
def set_field(self, name, val): """ Set the field *name* to value *val* :arg name: name of the :data:`~drink.Page.editable_fields` to set :type name: str :arg val: value of the field :type val: depends on the :mod:`~drink.types` """ if name in self.editable_fields: if 'w' in request.identity.access(self): self.editable_fields[name].set(self, name, val) else: return drink.unauthorized("You can't edit %r, ask for more permissions."%name) elif name in self.owner_fields: if 'o' in request.identity.access(self): self.owner_fields[name].set(self, name, val) else: return drink.unauthorized("You can't edit %r, ask for more permissions."%name) else: return drink.unauthorized("%r is not editable."%name)
def reset_items(self): if 'o' not in request.identity.access(self): return drink.unauthorized("You must be the owner to do that") orig_order = [] k = set(Page.keys(self)) for item in self.forced_order: if item not in orig_order and item in k: orig_order.append(item) unlisted = k.difference(orig_order) orig_order.extend(unlisted) self.forced_order = orig_order return {'success': True}
def rm(self): # TODO: ajaxify name = drink.omni(request.GET.get('name')) if not ('a' in request.identity.access(self) and 'w' in request.identity.access(self[name])): return drink.unauthorized("Not authorized") try: parent_path = self.quoted_path except AttributeError: # XXX: unclean parent_path = '.' with self._lock(): old_obj = self[name] del self[name] old_obj._update_lookup_engine(remove=True) drink.transaction.commit() return drink.rdr(parent_path)
def match(self, pattern=None): if 'r' not in request.identity.access(self): return drink.unauthorized() return self._match(pattern or request.params.get('pattern').decode('utf-8') )