# HG changeset patch # User Christophe de Vienne # Date 1433842457 -7200 # Node ID 1f2570f1d72aad44decc5499c7f20f1e807dc182 # Parent 9ab8c7100fc0f0815cf24757782115988e43cd83 [routes] Add a 'cwentities' route with traversal The route uses a factory that produces ETypeResource and EntityResource as a context. A 'delete' view serve as a test and demonstration. The module being experimental, it has to be explicitely included. diff -r 9ab8c7100fc0 -r 1f2570f1d72a pyramid_cubicweb/entities.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pyramid_cubicweb/entities.py Tue Jun 09 11:34:17 2015 +0200 @@ -0,0 +1,85 @@ +from __future__ import absolute_import + +from rql import TypeResolverException + +from pyramid.decorator import reify +from pyramid.httpexceptions import HTTPNotFound +from pyramid.view import view_config + + +class EntityResource(object): + def __init__(self, request, cls, attrname, value): + self.request = request + self.cls = cls + self.attrname = attrname + self.value = value + + @reify + def rset(self): + st = self.cls.fetch_rqlst(self.request.cw_cnx.user, ordermethod=None) + st.add_constant_restriction(st.get_variable('X'), self.attrname, + 'x', 'Substitute') + if self.attrname == 'eid': + try: + rset = self.request.cw_cnx.execute( + st.as_string(), {'x': int(self.value)}) + except (ValueError, TypeResolverException): + # conflicting eid/type + raise HTTPNotFound() + else: + rset = self.request.cw_cnx.execute( + st.as_string(), {'x': unicode(self.value)}) + return rset + + +class ETypeResource(object): + @classmethod + def from_match(cls, matchname): + def factory(request): + return cls(request, request.matchdict[matchname]) + return factory + + def __init__(self, request, etype): + vreg = request.registry['cubicweb.registry'] + + self.request = request + self.etype = vreg.case_insensitive_etypes[etype.lower()] + self.cls = vreg['etypes'].etype_class(self.etype) + + def __getitem__(self, value): + attrname = self.cls.cw_rest_attr_info()[0] + return EntityResource(self.request, self.cls, attrname, value) + + +class MatchIsETypePredicate(object): + def __init__(self, matchname, config): + self.matchname = matchname + self.etypes = frozenset( + k.lower() for k in config.registry['cubicweb.registry']['etypes']) + + def text(self): + return 'match_is_etype = %s' % self.matchname + + phash = text + + def __call__(self, info, request): + return info['match'][self.matchname].lower() in \ + request.registry['cubicweb.registry'].case_insensitive_etypes + + +@view_config( + route_name='cwentities', + context=EntityResource, + request_method='DELETE') +def delete_entity(context, request): + context.rset.one().cw_delete() + request.response.status_int = 204 + return request.response + + +def includeme(config): + config.add_route_predicate('match_is_etype', MatchIsETypePredicate) + config.add_route( + 'cwentities', '/{etype}/*traverse', + factory=ETypeResource.from_match('etype'), match_is_etype='etype') + config.scan(__name__) diff -r 9ab8c7100fc0 -r 1f2570f1d72a pyramid_cubicweb/tests/test_entities.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pyramid_cubicweb/tests/test_entities.py Tue Jun 09 11:34:17 2015 +0200 @@ -0,0 +1,20 @@ +from __future__ import absolute_import + +from . import PyramidCWTest + + +class EntitiesTest(PyramidCWTest): + def includeme(self, config): + config.include('pyramid_cubicweb.entities') + + def test_delete(self): + with self.admin_access.repo_cnx() as cnx: + cnx.create_entity('CWGroup', name=u'tmp') + cnx.commit() + + self.login() + res = self.webapp.delete('/cwgroup/tmp') + self.assertEqual(res.status_int, 204) + + with self.admin_access.repo_cnx() as cnx: + self.assertEqual(cnx.find('CWGroup', name=u'tmp').rowcount, 0)