def _model_tree_iteration(self, model, visited, context): model = IModel(model) if model in visited: self.log('Skiping already validated model: %r', model) return visited.append(model) yield self._validate_model(model, context) if IQueryModel.providedBy(model): querymodel = yield model.query_items(offset=0, limit=10) items = yield querymodel.fetch_items() else: try: items = yield model.fetch_items() except NotSupported: self.info('Not iteration further down the model %r because ' 'it doesnt support fetching items', model) return for item in items: try: submodel = yield item.fetch() except Unauthorized: continue if IModel.providedBy(submodel): subcontext = context.descend(submodel) yield self._model_tree_iteration(submodel, visited, subcontext)
def _model_tree_iteration(self, model, visited, context): model = IModel(model) if model in visited: self.log('Skiping already validated model: %r', model) return visited.append(model) yield self._validate_model(model, context) items = yield model.fetch_items() for item in items: submodel = yield item.fetch() if IModel.providedBy(submodel): subcontext = context.descend(submodel) yield self._model_tree_iteration(submodel, visited, subcontext)
def write_query_result(doc, obj, *args, **kwargs): # This type of object is used as a result of 'select' query of dbmodels api result = list() if IModel.implementedBy(obj._item_model): model_factory = obj._item_model else: model_factory = model.get_factory(obj._item_model) if model_factory is None: # use the adapter model_factory = IModel items = obj.get_items() for child in items: if obj.query_target == 'view': instance = model_factory(obj.source) d = instance.initiate(view=child) else: instance = model_factory(child) d = instance.initiate(view=obj.view) d.addCallback(applicationjson.render_inline_model, *args, **kwargs) result.append(d) r = applicationjson.AsyncDict() d = defer.DeferredList(result) d.addCallback(applicationjson.unpack_deferred_list_result) d.addCallback(list) r.add('rows', d) r.add('total_count', items.total_count) r.add('aggregations', items.aggregations) d = r.wait() d.addCallback(applicationjson.render_json, doc) d.addCallback(defer.override_result, None) return d
def _format_attribute_item(self, item, context): model = yield safe_fetch(item) if not IModel.providedBy(model): defer.returnValue("") result = yield self._format_attribute(model, context.descend(model), context, html_links(item)) defer.returnValue(result)
def _build_tree(self, tree, model, limit, context): if not IModel.providedBy(model): return items = yield model.fetch_items() # [dict of attributes added by this level, list of child rows] tree.append([dict(), list()]) for item in items: submodel = yield safe_fetch(item) if not submodel: continue if not IAttribute.providedBy(submodel): if limit > 0: if IModel.providedBy(submodel): subcontext = context.descend(submodel) yield self._build_tree(tree[-1][1], submodel, limit - 1, subcontext) else: column_name = item.label or item.name tree[-1][0][(column_name, limit)] = (item, context)
def _build_tree(self, tree, model, limit, context): if not IModel.providedBy(model): return items = yield model.fetch_items() #FIXME: column ordering do not work ordered = self._order_items(model, items) # [dict of attributes added by this level, list of child rows] tree.append([dict(), list()]) for item in ordered: #FIXME: should not need to fetch model for this m = yield item.fetch() if not IAttribute.providedBy(m): if limit > 0: submodel = yield item.fetch() if IModel.providedBy(submodel): subcontext = context.descend(submodel) yield self._build_tree(tree[-1][1], submodel, limit - 1, subcontext) else: column_name = item.label or item.name tree[-1][0][(column_name, limit)] = (item, context)
def _wrap_source(self, source, view, model_factory): if source is None: return source if IReference.providedBy(source): return source if IModel.providedBy(source): return self._init_model(source, view) if not IModelFactory.providedBy(model_factory): if callable(model_factory): ctx = self.model.make_context(key=self.name, view=view) d = model_factory(source, ctx) d.addCallback(self._got_model_factory, source, view) return d return self._got_model_factory(model_factory, source, view)
def _render_items(self, model, markup, context): try: items = yield model.fetch_items() if not items: return except NotSupported: return array_deepness = render_array(model) if array_deepness: markup.div(_class='array')( self._render_array(model, array_deepness, context)).close() else: ordered = self._order_items(model, items) ul = markup.ul(_class="items") for item in ordered: submodel = yield safe_fetch(item) li = markup.li() if item.reference: url = item.reference.resolve(context) markup.span(_class='name')( html.tags.a(href=url)(item.label or item.name)).close() else: markup.span(_class='name')(item.label or item.name).close() if IAttribute.providedBy(submodel): li.append(self._format_attribute_item(item, context)) else: markup.span(_class="value").close() if item.desc: markup.span(_class='desc')(item.desc).close() array_deepness = render_array(item) if submodel and array_deepness: if IModel.providedBy(submodel): array = self._render_array( submodel, array_deepness, context) markup.div(_class='array')(array).close() li.close() ul.close()
def _render_items(self, model, markup, context): items = yield model.fetch_items() if not items: return array_deepness = render_array(model) if array_deepness: markup.div(_class='array')( self._render_array(model, array_deepness, context)).close() else: ordered = self._order_items(model, items) ul = markup.ul(_class="items") for item in ordered: li = markup.li() url = item.reference.resolve(context) markup.span(_class='name')( html.tags.a(href=url)(item.label or item.name)).close() #FIXME: shouldn't need to fetch the model for that m = yield item.fetch() if IAttribute.providedBy(m): li.append(self._format_attribute_item(item, context)) else: markup.span(_class="value").close() if item.desc: markup.span(_class='desc')(item.desc).close() array_deepness = render_array(item) if array_deepness: submodel = yield item.fetch() if IModel.providedBy(submodel): array = self._render_array(submodel, array_deepness, context) markup.div(_class='array')(array).close() li.close() ul.close() markup.hr()
def __init__(self, model, name=None, models=[], names=[]): self.model = IModel(model) self._model_history = list(models) + [self.model] self._name_history = list(names) + [name] self._methods = set([]) # set([http.Methods])
class ModelResource(BaseResource): __slots__ = ("model", "_methods", "_model_history", "_name_history") implements(webserver.IWebResource) action_methods = {u"set": http.Methods.PUT, u"del": http.Methods.DELETE, u"post": http.Methods.POST} method_actions = {http.Methods.DELETE: u"del", http.Methods.PUT: u"set", http.Methods.POST: u"post"} def __init__(self, model, name=None, models=[], names=[]): self.model = IModel(model) self._model_history = list(models) + [self.model] self._name_history = list(names) + [name] self._methods = set([]) # set([http.Methods]) def __repr__(self): return "<%s %s '%s'>" % (type(self).__name__, self.model.identity, self.model.name) def __str__(self): return repr(self) def initiate(self): """ Initiate the resource retrieving all the asynchronous information needed to support the IWebResource interface. """ def deduce_methods(actions): self._methods.add(http.Methods.GET) for action in actions: method = self.action_methods.get(action.name) if method is not None: self._methods.add(method) d = self.model.fetch_actions() d.addCallback(deduce_methods) d.addCallback(defer.override_result, self) return d def make_context(self, request, remaining=None): return Context(scheme=request.scheme, models=self._model_history, names=self._name_history, remaining=remaining, arguments=request.arguments) ### webserver.IWebResource ### def is_method_allowed(self, request, location, method): return method in self._methods def get_allowed_methods(self, request, location): return list(self._methods) def locate_resource(self, request, location, remaining): def locate_model(model_name): d = defer.succeed(self.model) d.addCallback(retrieve_model, model_name) d.addCallback(check_model) d.addCallback(wrap_model) return d def locate_action(action_name): d = defer.succeed(self.model) d.addCallback(retrieve_action, action_name) d.addCallback(wrap_action) return d def locate_default_action(model_name, action_name): d = defer.succeed(self.model) d.addCallback(retrieve_model, model_name) d.addCallback(check_model) d.addCallback(retrieve_action, action_name) d.addCallback(wrap_action, fallback=True) return d def retrieve_model(model, model_name): d = model.fetch_item(model_name) d.addCallback(got_model_item) return d def got_model_item(item): if item is None: raise http.NotFoundError() rem = remaining[1:] if rem and rem != (u"", ): return item.browse() return item.fetch() def check_model(model): if model is None: raise http.NotFoundError() if IReference.providedBy(model): return process_reference(model) if model.reference is not None: return process_reference(model.reference) return model def process_reference(reference): reference = IReference(reference) context = self.make_context(request, remaining[1:]) address = reference.resolve(context) raise http.MovedPermanently(location=address) def wrap_model(model): if model is None: raise http.NotFoundError() res = ModelResource(model, model.name, self._model_history, self._name_history) return res.initiate(), remaining[1:] def retrieve_action(model, action_name): d = model.fetch_action(action_name) d.addCallback(lambda a: (model, a)) return d def wrap_action(model_action, fallback=False): model, action = model_action if action is None: if fallback: return wrap_model(model) raise http.NotFoundError() context = self.make_context(request) return ActionResource(action, context) if not remaining or (remaining == (u'', )): if self.model.reference is not None: return process_reference(self.model.reference) return self resource_name = remaining[0] if len(remaining) == 1: if resource_name.startswith('_'): return locate_action(resource_name[1:]) action_name = self.method_actions.get(request.method) return locate_default_action(resource_name, action_name) return locate_model(resource_name) def action_GET(self, request, response, location): response.set_header("Cache-Control", "no-cache") response.set_header("connection", "close") context = self.make_context(request) if location[-1] == u"": return self.render_action("get", request, response, context) return self.render_model(request, response, context) def render_action(self, action_name, request, response, context): def got_data(data): #FIXME: passing query arguments without validation is not safe return response.write_object(data, context=context, **request.arguments) def got_action(action): if action is None: return self.render_model(request, response, context) request.log("Performing action %r on %s model %r", action_name, self.model.identity, self.model.name) d = action.perform() d.addCallback(got_data) return d d = self.model.fetch_action(action_name) d.addCallback(got_action) return d def render_model(self, request, response, context): #FIXME: passing query arguments without validation is not safe return response.write_object(self.model, context=context, **request.arguments)