backport stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Wed, 25 Aug 2010 18:55:58 +0200
changeset 6149 57e956441ca4
parent 6147 95c604ec89bf (current diff)
parent 6148 59c446a813b5 (diff)
child 6151 f910c60b84ff
backport stable
dataimport.py
utils.py
web/data/cubicweb.css
--- 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())
--- 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
--- 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))
 
 
 
--- 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_<ACTION>_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 <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_<ACTION>_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 <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_<ACTION>_permission" can not be used
+* you can not use special `has_<ACTION>_permission` relation in the rql
+  expression.
 
 
 Important notes about write permissions checking
--- 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 <http://www.gnu.org/licenses/>.
-"""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)
--- 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):
--- 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;