# HG changeset patch # User Laurent Peuch # Date 1550771199 -3600 # Node ID 3c66259723d91e86a28ccd25ce89d6c8de0c4d17 # Parent 7b887f7d711f09aa3923cba6d793e6f26f704636 [doc] pep8 and retab in tutorial code example diff -r 7b887f7d711f -r 3c66259723d9 doc/tutorials/advanced/part01_create-cube.rst --- a/doc/tutorials/advanced/part01_create-cube.rst Thu Feb 21 19:08:44 2019 +0100 +++ b/doc/tutorials/advanced/part01_create-cube.rst Thu Feb 21 18:46:39 2019 +0100 @@ -72,11 +72,11 @@ __depends__ = {'cubicweb': '>= 3.26.7', 'cubicweb-file': '>= 1.9.0', - 'cubicweb-folder': '>= 1.1.0', - 'cubicweb-person': '>= 1.2.0', - 'cubicweb-comment': '>= 1.2.0', - 'cubicweb-tag': '>= 1.2.0', - 'cubicweb-zone': None} + 'cubicweb-folder': '>= 1.1.0', + 'cubicweb-person': '>= 1.2.0', + 'cubicweb-comment': '>= 1.2.0', + 'cubicweb-tag': '>= 1.2.0', + 'cubicweb-zone': None} Notice that you can express minimal version of the cube that should be used, `None` meaning whatever version available. All packages starting with 'cubicweb-' @@ -102,27 +102,34 @@ from yams.buildobjs import RelationDefinition + class comments(RelationDefinition): - subject = 'Comment' - object = 'File' - cardinality = '1*' - composite = 'object' + subject = 'Comment' + object = 'File' + # a Comment can be on only one File + # but a File can have several comments + cardinality = '1*' + composite = 'object' + class tags(RelationDefinition): - subject = 'Tag' - object = 'File' + subject = 'Tag' + object = 'File' + class filed_under(RelationDefinition): - subject = 'File' - object = 'Folder' + subject = 'File' + object = 'Folder' + class situated_in(RelationDefinition): - subject = 'File' - object = 'Zone' + subject = 'File' + object = 'Zone' + class displayed_on(RelationDefinition): - subject = 'Person' - object = 'File' + subject = 'Person' + object = 'File' This schema: diff -r 7b887f7d711f -r 3c66259723d9 doc/tutorials/advanced/part02_security.rst --- a/doc/tutorials/advanced/part02_security.rst Thu Feb 21 19:08:44 2019 +0100 +++ b/doc/tutorials/advanced/part02_security.rst Thu Feb 21 18:46:39 2019 +0100 @@ -74,23 +74,25 @@ from yams.constraints import StaticVocabularyConstraint + class visibility(RelationDefinition): - subject = ('Folder', 'File', 'Comment') - object = 'String' - constraints = [StaticVocabularyConstraint(('public', 'authenticated', - 'restricted', 'parent'))] - default = 'parent' - cardinality = '11' # required + subject = ('Folder', 'File', 'Comment') + object = 'String' + constraints = [StaticVocabularyConstraint(('public', 'authenticated', + 'restricted', 'parent'))] + default = 'parent' + cardinality = '11' # required + class may_be_read_by(RelationDefinition): __permissions__ = { - 'read': ('managers', 'users'), - 'add': ('managers',), - 'delete': ('managers',), - } + 'read': ('managers', 'users'), + 'add': ('managers',), + 'delete': ('managers',), + } - subject = ('Folder', 'File', 'Comment',) - object = 'CWUser' + subject = ('Folder', 'File', 'Comment',) + object = 'CWUser' We can note the following points: @@ -203,32 +205,37 @@ from cubicweb.predicates import is_instance from cubicweb.server import hook + class SetVisibilityOp(hook.DataOperationMixIn, hook.Operation): - def precommit_event(self): - for eid in self.get_data(): - entity = self.cnx.entity_from_eid(eid) - if entity.visibility == 'parent': - entity.cw_set(visibility=u'authenticated') + def precommit_event(self): + for eid in self.get_data(): + entity = self.cnx.entity_from_eid(eid) + + if entity.visibility == 'parent': + entity.cw_set(visibility=u'authenticated') + class SetVisibilityHook(hook.Hook): - __regid__ = 'sytweb.setvisibility' - __select__ = hook.Hook.__select__ & is_instance('Folder', 'File', 'Comment') - events = ('after_add_entity',) + __regid__ = 'sytweb.setvisibility' + __select__ = hook.Hook.__select__ & is_instance('Folder', 'File', 'Comment') + events = ('after_add_entity',) - def __call__(self): - SetVisibilityOp.get_instance(self._cw).add_data(self.entity.eid) + def __call__(self): + SetVisibilityOp.get_instance(self._cw).add_data(self.entity.eid) + class SetParentVisibilityHook(hook.Hook): - __regid__ = 'sytweb.setparentvisibility' - __select__ = hook.Hook.__select__ & hook.match_rtype('filed_under', 'comments') - events = ('after_add_relation',) + __regid__ = 'sytweb.setparentvisibility' + __select__ = hook.Hook.__select__ & hook.match_rtype('filed_under', 'comments') + events = ('after_add_relation',) - def __call__(self): - parent = self._cw.entity_from_eid(self.eidto) - child = self._cw.entity_from_eid(self.eidfrom) - if child.visibility == 'parent': - child.cw_set(visibility=parent.visibility) + def __call__(self): + parent = self._cw.entity_from_eid(self.eidto) + child = self._cw.entity_from_eid(self.eidfrom) + + if child.visibility == 'parent': + child.cw_set(visibility=parent.visibility) Notice: @@ -272,29 +279,32 @@ # relations where the "parent" entity is the object O_RELS = set(('filed_under', 'comments',)) + class AddEntitySecurityPropagationHook(hook.PropagateRelationHook): - """propagate permissions when new entity are added""" - __regid__ = 'sytweb.addentity_security_propagation' - __select__ = (hook.PropagateRelationHook.__select__ - & hook.match_rtype_sets(S_RELS, O_RELS)) - main_rtype = 'may_be_read_by' - subject_relations = S_RELS - object_relations = O_RELS + """propagate permissions when new entity are added""" + __regid__ = 'sytweb.addentity_security_propagation' + __select__ = (hook.PropagateRelationHook.__select__ + & hook.match_rtype_sets(S_RELS, O_RELS)) + main_rtype = 'may_be_read_by' + subject_relations = S_RELS + object_relations = O_RELS + class AddPermissionSecurityPropagationHook(hook.PropagateRelationAddHook): - """propagate permissions when new entity are added""" - __regid__ = 'sytweb.addperm_security_propagation' - __select__ = (hook.PropagateRelationAddHook.__select__ - & hook.match_rtype('may_be_read_by',)) - subject_relations = S_RELS - object_relations = O_RELS + """propagate permissions when new entity are added""" + __regid__ = 'sytweb.addperm_security_propagation' + __select__ = (hook.PropagateRelationAddHook.__select__ + & hook.match_rtype('may_be_read_by',)) + subject_relations = S_RELS + object_relations = O_RELS + class DelPermissionSecurityPropagationHook(hook.PropagateRelationDelHook): - __regid__ = 'sytweb.delperm_security_propagation' - __select__ = (hook.PropagateRelationDelHook.__select__ - & hook.match_rtype('may_be_read_by',)) - subject_relations = S_RELS - object_relations = O_RELS + __regid__ = 'sytweb.delperm_security_propagation' + __select__ = (hook.PropagateRelationDelHook.__select__ + & hook.match_rtype('may_be_read_by',)) + subject_relations = S_RELS + object_relations = O_RELS * the `AddEntitySecurityPropagationHook` will propagate the relation when `filed_under` or `comments` relations are added @@ -324,6 +334,7 @@ from cubicweb.devtools import testlib from cubicweb import Binary + class SecurityTC(testlib.CubicWebTC): def test_visibility_propagation(self): @@ -379,6 +390,7 @@ self.assertEquals(2, len(cnx.execute('File X'))) # now toto has access to photo2 self.assertEquals(1, len(cnx.execute('Folder X'))) # and to restricted folder + if __name__ == '__main__': from unittest import main main() diff -r 7b887f7d711f -r 3c66259723d9 doc/tutorials/advanced/part03_bfss.rst --- a/doc/tutorials/advanced/part03_bfss.rst Thu Feb 21 19:08:44 2019 +0100 +++ b/doc/tutorials/advanced/part03_bfss.rst Thu Feb 21 18:46:39 2019 +0100 @@ -22,6 +22,7 @@ from cubicweb.server import hook from cubicweb.server.sources import storages + class ServerStartupHook(hook.Hook): __regid__ = 'sytweb.serverstartup' events = ('server_startup', 'server_maintenance') diff -r 7b887f7d711f -r 3c66259723d9 doc/tutorials/advanced/part04_ui-base.rst --- a/doc/tutorials/advanced/part04_ui-base.rst Thu Feb 21 19:08:44 2019 +0100 +++ b/doc/tutorials/advanced/part04_ui-base.rst Thu Feb 21 18:46:39 2019 +0100 @@ -28,26 +28,27 @@ from cubicweb.web.views import error from cubicweb.predicates import anonymous_user + class FourOhFour(error.FourOhFour): - __select__ = error.FourOhFour.__select__ & anonymous_user() + __select__ = error.FourOhFour.__select__ & anonymous_user() - def call(self): - self.w(u"

%s

" % self._cw._('this resource does not exist')) - self.w(u"

%s

" % self._cw._('have you tried to login?')) + def call(self): + self.w(u"

%s

" % self._cw._('this resource does not exist')) + self.w(u"

%s

" % self._cw._('have you tried to login?')) class LoginBox(component.CtxComponent): - """display a box containing links to all startup views""" - __regid__ = 'sytweb.loginbox' - __select__ = component.CtxComponent.__select__ & anonymous_user() + """display a box containing links to all startup views""" + __regid__ = 'sytweb.loginbox' + __select__ = component.CtxComponent.__select__ & anonymous_user() - title = _('Authenticate yourself') - order = 70 + title = _('Authenticate yourself') + order = 70 - def render_body(self, w): - cw = self._cw - form = cw.vreg['forms'].select('logform', cw) - form.render(w=w, table_class='', display_progress_div=False) + def render_body(self, w): + cw = self._cw + form = cw.vreg['forms'].select('logform', cw) + form.render(w=w, table_class='', display_progress_div=False) The first class provides a new specific implementation of the default page you get on 404 error, to display an adapted message to anonymous user. @@ -86,19 +87,21 @@ from cubicweb.web.views import startup + class IndexView(startup.IndexView): - def call(self, **kwargs): - self.w(u'
\n') - if self._cw.cnx.session.anonymous_session: - self.w(u'

%s

\n' % self._cw._('Public Albums')) - else: - self.w(u'

%s

\n' % self._cw._('Albums for %s') % self._cw.user.login) - self._cw.vreg['views'].select('tree', self._cw).render(w=self.w) - self.w(u'
\n') + def call(self, **kwargs): + self.w(u'
\n') + if self._cw.cnx.session.anonymous_session: + self.w(u'

%s

\n' % self._cw._('Public Albums')) + else: + self.w(u'

%s

\n' % self._cw._('Albums for %s') % self._cw.user.login) + self._cw.vreg['views'].select('tree', self._cw).render(w=self.w) + self.w(u'
\n') + def registration_callback(vreg): - vreg.register_all(globals().values(), __name__, (IndexView,)) - vreg.register_and_replace(IndexView, startup.IndexView) + vreg.register_all(globals().values(), __name__, (IndexView,)) + vreg.register_and_replace(IndexView, startup.IndexView) As you can see, we override the default index view found in `cubicweb.web.views.startup`, geting back nothing but its identifier and selector @@ -149,9 +152,9 @@ .. sourcecode:: python class File(AnyEntity): - """customized class for File entities""" - __regid__ = 'File' - fetch_attrs, cw_fetch_order = fetch_config(['data_name', 'title']) + """customized class for File entities""" + __regid__ = 'File' + fetch_attrs, cw_fetch_order = fetch_config(['data_name', 'title']) By default, `fetch_config` will return a `cw_fetch_order` method that will order @@ -175,16 +178,16 @@ class FolderITreeAdapter(folder.FolderITreeAdapter): - def different_type_children(self, entities=True): - rql = self.entity.cw_related_rql(self.tree_relation, - self.parent_role, ('File',)) - rset = self._cw.execute(rql, {'x': self.entity.eid}) - if entities: - return list(rset.entities()) - return rset + def different_type_children(self, entities=True): + rql = self.entity.cw_related_rql(self.tree_relation, + self.parent_role, ('File',)) + rset = self._cw.execute(rql, {'x': self.entity.eid}) + if entities: + return list(rset.entities()) + return rset def registration_callback(vreg): - vreg.register_and_replace(FolderITreeAdapter, folder.FolderITreeAdapter) + vreg.register_and_replace(FolderITreeAdapter, folder.FolderITreeAdapter) As you can see, we simple inherit from the adapter defined in the `folder` cube, then we override the `different_type_children` method to give a clue to the ORM's @@ -216,23 +219,23 @@ class FileIPrevNextAdapter(navigation.IPrevNextAdapter): - __select__ = is_instance('File') + __select__ = is_instance('File') - def previous_entity(self): - rset = self._cw.execute('File F ORDERBY FDN DESC LIMIT 1 WHERE ' - 'X filed_under FOLDER, F filed_under FOLDER, ' - 'F data_name FDN, X data_name > FDN, X eid %(x)s', - {'x': self.entity.eid}) - if rset: - return rset.get_entity(0, 0) + def previous_entity(self): + rset = self._cw.execute('File F ORDERBY FDN DESC LIMIT 1 WHERE ' + 'X filed_under FOLDER, F filed_under FOLDER, ' + 'F data_name FDN, X data_name > FDN, X eid %(x)s', + {'x': self.entity.eid}) + if rset: + return rset.get_entity(0, 0) - def next_entity(self): - rset = self._cw.execute('File F ORDERBY FDN ASC LIMIT 1 WHERE ' - 'X filed_under FOLDER, F filed_under FOLDER, ' - 'F data_name FDN, X data_name < FDN, X eid %(x)s', - {'x': self.entity.eid}) - if rset: - return rset.get_entity(0, 0) + def next_entity(self): + rset = self._cw.execute('File F ORDERBY FDN ASC LIMIT 1 WHERE ' + 'X filed_under FOLDER, F filed_under FOLDER, ' + 'F data_name FDN, X data_name < FDN, X eid %(x)s', + {'x': self.entity.eid}) + if rset: + return rset.get_entity(0, 0) The `IPrevNext` interface implemented by the adapter simply consist in the @@ -279,11 +282,11 @@ from cubicweb.web.views import ibreadcrumbs class FileIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter): - __select__ = is_instance('File') + __select__ = is_instance('File') - def parent_entity(self): - if self.entity.filed_under: - return self.entity.filed_under[0] + def parent_entity(self): + if self.entity.filed_under: + return self.entity.filed_under[0] In that case, we simply use attribute notation provided by the ORM to get the folder in which the current file (e.g. `self.entity`) is located.