# HG changeset patch # User Sylvain Thénault # Date 1282755358 -7200 # Node ID 57e956441ca4ef73b446cb8f003c7216cf72292d # Parent 95c604ec89bfa6e0167f8b180b6ec00ee94d5481# Parent 59c446a813b5a220f35247acdbf971972a3256db backport stable diff -r 95c604ec89bf -r 57e956441ca4 cwconfig.py --- a/cwconfig.py Wed Aug 25 18:29:55 2010 +0200 +++ b/cwconfig.py Wed Aug 25 18:55:58 2010 +0200 @@ -998,7 +998,7 @@ """check given directory path exists, belongs to the user running the server process and is writeable. - If not, try to fix this, leting exception propagate when not possible. + If not, try to fix this, letting exception propagate when not possible. """ if not exists(path): os.makedirs(path) @@ -1009,7 +1009,10 @@ from pwd import getpwnam uid = getpwnam(self['uid']).pw_uid else: - uid = os.getuid() + try: + uid = os.getuid() + except AttributeError: # we are on windows + return fstat = os.stat(path) if fstat.st_uid != uid: os.chown(path, uid, os.getgid()) diff -r 95c604ec89bf -r 57e956441ca4 cwctl.py --- a/cwctl.py Wed Aug 25 18:29:55 2010 +0200 +++ b/cwctl.py Wed Aug 25 18:55:58 2010 +0200 @@ -329,7 +329,7 @@ """run the command with its specific arguments""" from logilab.common.textutils import splitstrip configname = self.config.config - appid, cubes = args + cubes, appid = args cubes = splitstrip(cubes) # get the configuration and helper config = cwcfg.config_for(appid, configname) @@ -573,7 +573,7 @@ print '*'*72 if not ASK.confirm('%s instance %r ?' % (self.name, appid)): continue - StopInstanceCommand().stop_instance(appid) + StopInstanceCommand(self.logger).stop_instance(appid) forkcmd = [w for w in sys.argv if not w in args] forkcmd[1] = 'start' forkcmd = ' '.join(forkcmd) @@ -583,7 +583,7 @@ sys.exit(status) def restart_instance(self, appid): - StopInstanceCommand().stop_instance(appid) + StopInstanceCommand(self.logger).stop_instance(appid) self.start_instance(appid) @@ -742,7 +742,7 @@ print '-> migration needed from %s to %s for %s' % (fromversion, toversion, cube) # only stop once we're sure we have something to do if not (CWDEV or self.config.nostartstop): - StopInstanceCommand().stop_instance(appid) + StopInstanceCommand(self.logger).stop_instance(appid) # run cubicweb/componants migration scripts mih.migrate(vcconf, reversed(toupgrade), self.config) # rewrite main configuration file diff -r 95c604ec89bf -r 57e956441ca4 dataimport.py --- a/dataimport.py Wed Aug 25 18:29:55 2010 +0200 +++ b/dataimport.py Wed Aug 25 18:55:58 2010 +0200 @@ -34,7 +34,7 @@ ] def gen_users(ctl): - for row in ctl.get_data('utilisateurs'): + for row in ctl.iter_and_commit('utilisateurs'): entity = mk_entity(row, USERS) entity['upassword'] = u'motdepasse' ctl.check('login', entity['login'], None) @@ -125,13 +125,15 @@ for row in it: yield [item.decode(encoding) for item in row] -def commit_every(nbit, store, it): - for i, x in enumerate(it): - yield x - if nbit is not None and i % nbit: - store.commit() - if nbit is not None: - store.commit() +def callfunc_every(func, number, iterable): + """yield items of `iterable` one by one and call function `func` + every `number` iterations. Always call function `func` at the end. + """ + for idx, item in enumerate(iterable): + yield item + if idx % number: + func() + func() def lazytable(reader): """The first row is taken to be the header of the table and @@ -230,7 +232,7 @@ return None def required(value): - """raise ValueError is value is empty + """raise ValueError if value is empty This check should be often found in last position in the chain. """ @@ -571,7 +573,10 @@ def iter_and_commit(self, datakey): """iter rows, triggering commit every self.commitevery iterations""" - return commit_every(self.commitevery, self.store, self.get_data(datakey)) + if self.commitevery is None: + return self.get_data(datakey) + else: + return callfunc_every(self.commitevery, self.store.commit, self.get_data(datakey)) diff -r 95c604ec89bf -r 57e956441ca4 doc/book/en/devrepo/datamodel/definition.rst --- a/doc/book/en/devrepo/datamodel/definition.rst Wed Aug 25 18:29:55 2010 +0200 +++ b/doc/book/en/devrepo/datamodel/definition.rst Wed Aug 25 18:55:58 2010 +0200 @@ -297,36 +297,38 @@ For *CubicWeb* in particular: * we associate rights at the entities/relations schema level -* for each entity, we distinguish four kinds of permissions: `read`, - `add`, `update` and `delete` -* for each relation, we distinguish three kinds of permissions: `read`, - `add` and `delete` (it is not possible to `modify` a relation) + * the default groups are: `administrators`, `users` and `guests` -* by default, users belong to the `users` group -* there is a virtual group called `owners` to which we - can associate only `delete` and `update` permissions + +* users belong to the `users` group + +* there is a virtual group called `owners` to which we can associate only + `delete` and `update` permissions - * we can not add users to the `Owners` group, they are - implicitly added to it according to the context of the objects - they own - * the permissions of this group are only checked on `update`/`delete` - actions if all the other groups the user belongs to do not provide - those permissions + * we can not add users to the `owners` group, they are implicitly added to it + according to the context of the objects they own + + * the permissions of this group are only checked on `update`/`delete` actions + if all the other groups the user belongs to do not provide those permissions Setting permissions is done with the attribute `__permissions__` of entities and -relation types. The value of this attribute is a dictionary where the keys are the access types -(action), and the values are the authorized groups or expressions. +relation definition. The value of this attribute is a dictionary where the keys +are the access types (action), and the values are the authorized groups or +expressions. For an entity type, the possible actions are `read`, `add`, `update` and `delete`. -For a relation type, the possible actions are `read`, `add`, and `delete`. +For a relation, the possible actions are `read`, `add`, and `delete`. + +For an attribute, the possible actions are `read`, and `update`. For each access type, a tuple indicates the name of the authorized groups and/or one or multiple RQL expressions to satisfy to grant access. The access is provided if the user is in one of the listed groups or if one of the RQL condition is satisfied. + The standard user groups ```````````````````````` @@ -340,66 +342,77 @@ This can only be used for the actions `update` and `delete` of an entity type. -It is also possible to use specific groups if they are defined in the -precreate script of the cube (``migration/precreate.py``). Defining groups in -postcreate script or later makes them unavailable for security -purposes (in this case, an `sync_schema_props_perms` command has to -be issued in a CubicWeb shell). +It is also possible to use specific groups if they are defined in the precreate +script of the cube (``migration/precreate.py``). Defining groups in postcreate +script or later makes them unavailable for security purposes (in this case, an +`sync_schema_props_perms` command has to be issued in a CubicWeb shell). Use of RQL expression for write permissions ``````````````````````````````````````````` -It is possible to define RQL expression to provide update permission -(`add`, `delete` and `update`) on relation and entity types. -RQL expression for entity type permission: +It is possible to define RQL expression to provide update permission (`add`, +`delete` and `update`) on entity type / relation definitions. An rql expression +is a piece of query (corresponds to the WHERE statement of an RQL query), and the +expression will be considered as satisfied if it returns some results. They can +not be used in `read` permission. -* you have to use the class `ERQLExpression` +To use RQL expression in entity type permission: -* the used expression corresponds to the WHERE statement of an RQL query +* you have to use the class :class:`~cubicweb.schema.ERQLExpression` * in this expression, the variables `X` and `U` are pre-defined references - respectively on the current entity (on which the action is verified) and - on the user who send the request + respectively on the current entity (on which the action is verified) and on the + user who send the request + +For RQL expressions on a relation type, the principles are the same except for +the following: -* it is possible to use, in this expression, a special relation - "has__permission" where the subject is the user and the - object is any variable, meaning that the user needs to have - permission to execute the action on the entities related - to this variable +* you have to use the class :class:`~cubicweb.schema.RRQLExpression` instead of + :class:`~cubicweb.schema.ERQLExpression` -For RQL expressions on a relation type, the principles are the same except -for the following: +* in the expression, the variables `S`, `O` and `U` are pre-defined references to + respectively the subject and the object of the current relation (on which the + action is being verified) and the user who executed the query + +To define security for attributes of an entity (non-final relation), you have to +use the class :class:`~cubicweb.schema.ERQLExpression` in which `X` represents +the entity the attribute belongs to. -* you have to use the class `RRQLExpression` in the case of a non-final relation +It is possible to use in those expression a special relation +`has__permission` where the subject is the user (eg 'U') and the object +is any variable representing an entity (usually 'X' in +:class:`~cubicweb.schema.ERQLExpression`, 'S' or 'O' in +:class:`~cubicweb.schema.RRQLExpression`), meaning that the user needs to have +permission to execute the action on the entities represented by this +variable. It's recommanded to use this feature whenever possible since it +simplify greatly complex security definition and upgrade. -* in the expression, the variables `S`, `O` and `U` are pre-defined references - to respectively the subject and the object of the current relation (on - which the action is being verified) and the user who executed the query -* we can also define rights over attributes of an entity (non-final relation), - knowing that: +.. sourcecode:: python - - to define RQL expression, we have to use the class `ERQLExpression` - in which `X` represents the entity the attribute belongs to + class my_relation(RelationDefinition): + __permissions__ = {'read': ('managers', 'users'), + 'add': ('managers', RRQLExpression('U has_update_permission S')), + 'delete': ('managers', RRQLExpression('U has_update_permission S')) + } - - the permissions `add` and `delete` are equivalent. Only `add`/`read` - are actually taken in consideration. +In the above example, user will be allowed to add/delete `my_relation` if he has +the `update` permission on the subject of the relation. .. note:: - Potentially, the `use of an RQL expression to add an entity or a - relation` can cause problems for the user interface, because if the - expression uses the entity or the relation to create, then we are - not able to verify the permissions before we actually add the entity - (please note that this is not a problem for the RQL server at all, - because the permissions checks are done after the creation). In such - case, the permission check methods (CubicWebEntitySchema.check_perm - and has_perm) can indicate that the user is not allowed to create - this entity but can obtain the permission. To compensate this - problem, it is usually necessary, for such case, to use an action - that reflects the schema permissions but which enables to check - properly the permissions so that it would show up if necessary. + Potentially, the `use of an RQL expression to add an entity or a relation` can + cause problems for the user interface, because if the expression uses the + entity or the relation to create, we are not able to verify the permissions + before we actually added the entity (please note that this is not a problem for + the RQL server at all, because the permissions checks are done after the + creation). In such case, the permission check methods + (CubicWebEntitySchema.check_perm and has_perm) can indicate that the user is + not allowed to create this entity while it would obtain the permission. To + compensate this problem, it is usually necessary in such case to use an action + that reflects the schema permissions but which check properly the permissions + so that it would show up only if possible. Use of RQL expression for reading rights @@ -407,9 +420,11 @@ The principles are the same but with the following restrictions: -* we can not use `RRQLExpression` on relation types for reading +* you can not use rql expression for the `read` permission of relations and + attributes, -* special relations "has__permission" can not be used +* you can not use special `has__permission` relation in the rql + expression. Important notes about write permissions checking diff -r 95c604ec89bf -r 57e956441ca4 goa/goactl.py --- a/goa/goactl.py Wed Aug 25 18:29:55 2010 +0200 +++ b/goa/goactl.py Wed Aug 25 18:55:58 2010 +0200 @@ -15,15 +15,14 @@ # # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . -"""cubicweb on appengine plugins for cubicweb-ctl +"""cubicweb on appengine plugins for cubicweb-ctl""" -""" __docformat__ = "restructuredtext en" from os.path import exists, join, split, basename, normpath, abspath -from logilab.common.clcommands import register_commands from cubicweb import CW_SOFTWARE_ROOT, BadCommandUsage +from cubicweb.cwctl import CWCTL from cubicweb.toolsutils import (Command, copy_skeleton, create_symlink, create_dir) from cubicweb.cwconfig import CubicWebConfiguration @@ -250,5 +249,4 @@ config.save() -register_commands((NewGoogleAppCommand, - )) +CWCTL.register(NewGoogleAppCommand) diff -r 95c604ec89bf -r 57e956441ca4 utils.py --- a/utils.py Wed Aug 25 18:29:55 2010 +0200 +++ b/utils.py Wed Aug 25 18:55:58 2010 +0200 @@ -369,7 +369,7 @@ json_dumps = None else: - + from logilab.common.date import ustrftime class CubicWebJsonEncoder(json.JSONEncoder): """define a json encoder to be able to encode yams std types""" @@ -379,9 +379,9 @@ d['eid'] = obj.eid return d if isinstance(obj, datetime.datetime): - return obj.strftime('%Y/%m/%d %H:%M:%S') + return ustrftime(obj, '%Y/%m/%d %H:%M:%S') elif isinstance(obj, datetime.date): - return obj.strftime('%Y/%m/%d') + return ustrftime(obj, '%Y/%m/%d') elif isinstance(obj, datetime.time): return obj.strftime('%H:%M:%S') elif isinstance(obj, datetime.timedelta): diff -r 95c604ec89bf -r 57e956441ca4 web/data/cubicweb.css --- a/web/data/cubicweb.css Wed Aug 25 18:29:55 2010 +0200 +++ b/web/data/cubicweb.css Wed Aug 25 18:55:58 2010 +0200 @@ -649,6 +649,7 @@ float: right; padding-left: 24px; position: relative; + z-index: 10; } div.toolbarButton { display: inline;