merge stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Mon, 28 Sep 2009 11:09:50 +0200
branchstable
changeset 3501 3ef4ce396066
parent 3500 ab10d1cb53ff (diff)
parent 3488 ab9e7bcfc764 (current diff)
child 3502 9638213410e9
merge
--- a/etwist/server.py	Sun Sep 27 14:37:55 2009 +0200
+++ b/etwist/server.py	Mon Sep 28 11:09:50 2009 +0200
@@ -10,10 +10,10 @@
 import sys
 import os
 import select
+import hotshot
 from time import mktime
 from datetime import date, timedelta
 from urlparse import urlsplit, urlunsplit
-import hotshot
 
 from twisted.application import strports
 from twisted.internet import reactor, task, threads
@@ -55,20 +55,9 @@
 
 def start_task(interval, func):
     lc = task.LoopingCall(func)
-    lc.start(interval)
-
-def start_looping_tasks(repo):
-    for interval, func, args in repo._looping_tasks:
-        repo.info('starting twisted task %s with interval %.2fs',
-                  func.__name__, interval)
-        def catch_error_func(repo=repo, func=func, args=args):
-            try:
-                func(*args)
-            except:
-                repo.exception('error in looping task')
-        start_task(interval, catch_error_func)
-    # ensure no tasks will be further added
-    repo._looping_tasks = ()
+    # wait until interval has expired to actually start the task, else we have
+    # to wait all task to be finished for the server to be actually started
+    lc.start(interval, now=False)
 
 def host_prefixed_baseurl(baseurl, host):
     scheme, netloc, url, query, fragment = urlsplit(baseurl)
@@ -122,14 +111,14 @@
             reactor.addSystemEventTrigger('before', 'shutdown',
                                           self.shutdown_event)
             # monkey patch start_looping_task to get proper reactor integration
-            self.appli.repo.__class__.start_looping_tasks = start_looping_tasks
+            #self.appli.repo.__class__.start_looping_tasks = start_looping_tasks
             if config.pyro_enabled():
                 # if pyro is enabled, we have to register to the pyro name
                 # server, create a pyro daemon, and create a task to handle pyro
                 # requests
                 self.pyro_daemon = self.appli.repo.pyro_register()
                 self.pyro_listen_timeout = 0.02
-                start_task(1, self.pyro_loop_event)
+                self.repo.looping_task(1, self.pyro_loop_event)
             self.appli.repo.start_looping_tasks()
         self.set_url_rewriter()
         CW_EVENT_MANAGER.bind('after-registry-reload', self.set_url_rewriter)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/migration/3.5.3_Any.py	Mon Sep 28 11:09:50 2009 +0200
@@ -0,0 +1,2 @@
+sync_schema_props_perms('state_of')
+sync_schema_props_perms('transition_of')
--- a/schemas/workflow.py	Sun Sep 27 14:37:55 2009 +0200
+++ b/schemas/workflow.py	Mon Sep 28 11:09:50 2009 +0200
@@ -57,7 +57,7 @@
     allowed_transition = SubjectRelation('BaseTransition', cardinality='**',
                                          constraints=[RQLConstraint('S state_of WF, O transition_of WF')],
                                          description=_('allowed transitions from this state'))
-    state_of = SubjectRelation('Workflow', cardinality='1*',
+    state_of = SubjectRelation('Workflow', cardinality='1*', composite='object',
                                description=_('workflow to which this state belongs'),
                                constraints=[RQLUniqueConstraint('S name N, Y state_of O, Y name N')])
 
@@ -80,7 +80,7 @@
     require_group = SubjectRelation('CWGroup', cardinality='**',
                                     description=_('group in which a user should be to be '
                                                   'allowed to pass this transition'))
-    transition_of = SubjectRelation('Workflow', cardinality='1*',
+    transition_of = SubjectRelation('Workflow', cardinality='1*', composite='object',
                                     description=_('workflow to which this transition belongs'),
                                     constraints=[RQLUniqueConstraint('S name N, Y transition_of O, Y name N')])
 
--- a/server/sources/native.py	Sun Sep 27 14:37:55 2009 +0200
+++ b/server/sources/native.py	Mon Sep 28 11:09:50 2009 +0200
@@ -554,7 +554,7 @@
         """
         try:
             self.indexer.cursor_unindex_object(eid, session.pool['system'])
-        except:
+        except Exception: # let KeyboardInterrupt / SystemExit propagate
             if self.indexer is not None:
                 self.exception('error while unindexing %s', eid)
 
@@ -565,7 +565,7 @@
         try:
             self.indexer.cursor_reindex_object(entity.eid, entity,
                                                session.pool['system'])
-        except:
+        except Exception: # let KeyboardInterrupt / SystemExit propagate
             if self.indexer is not None:
                 self.exception('error while reindexing %s', entity)
         # update entities.mtime
--- a/skeleton/__pkginfo__.py.tmpl	Sun Sep 27 14:37:55 2009 +0200
+++ b/skeleton/__pkginfo__.py.tmpl	Mon Sep 28 11:09:50 2009 +0200
@@ -43,8 +43,8 @@
 # Note: here, you'll need to add subdirectories if you want
 # them to be included in the debian package
 
-
-cube_eid = None # <=== FIXME if you need direct bug-subscription
+__depends_cubes__ = {}
+__depends__ = {'cubicweb': '>= 3.5.0'}
 __use__ = (%(dependancies)s)
 __recommend__ = ()
 
--- a/skeleton/migration/precreate.py	Sun Sep 27 14:37:55 2009 +0200
+++ b/skeleton/migration/precreate.py	Mon Sep 28 11:09:50 2009 +0200
@@ -7,4 +7,4 @@
 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
 """
 # You could create your own groups here, like in :
-#   add_entity('CWGroup', name=u'mygroup')
+#   create_entity('CWGroup', name=u'mygroup')
--- a/web/data/cubicweb.css	Sun Sep 27 14:37:55 2009 +0200
+++ b/web/data/cubicweb.css	Mon Sep 28 11:09:50 2009 +0200
@@ -482,22 +482,6 @@
   padding-right: 1em;
 }
 
-div.boxPref {
-  margin: 10px 0px 0px;
-}
-
-div.boxPrefTitle {
-  font-weight: bold;
-  background: #cfceb7;
-  margin-bottom: 6px;
-  padding-bottom: 0.2em;
-  overflow: hidden;
-}
-
-div.boxPrefTitle span{
- padding:0px 5px;
-}
-
 input.rqlsubmit{
   background: #fffff8 url("go.png") 50% 50% no-repeat;
   width: 20px;
--- a/web/data/cubicweb.htmlhelpers.js	Sun Sep 27 14:37:55 2009 +0200
+++ b/web/data/cubicweb.htmlhelpers.js	Mon Sep 28 11:09:50 2009 +0200
@@ -154,7 +154,7 @@
 
 CubicWeb.rounded = [
 		    ['div.sideBoxBody', 'bottom 6px'],
-		    ['div.boxTitle, div.boxPrefTitle, div.sideBoxTitle, th.month', 'top 6px']
+		    ['div.boxTitle, div.sideBoxTitle, th.month', 'top 6px']
 		    ];
 
 function roundedCorners(node) {
--- a/web/formfields.py	Sun Sep 27 14:37:55 2009 +0200
+++ b/web/formfields.py	Mon Sep 28 11:09:50 2009 +0200
@@ -320,10 +320,12 @@
     widget = FileInput
     needs_multipart = True
 
-    def __init__(self, format_field=None, encoding_field=None, **kwargs):
+    def __init__(self, format_field=None, encoding_field=None, name_field=None,
+                 **kwargs):
         super(FileField, self).__init__(**kwargs)
         self.format_field = format_field
         self.encoding_field = encoding_field
+        self.name_field = name_field
 
     def actual_fields(self, form):
         yield self
@@ -331,6 +333,8 @@
             yield self.format_field
         if self.encoding_field:
             yield self.encoding_field
+        if self.name_field:
+            yield self.name_field
 
     def render(self, form, renderer):
         wdgs = [self.get_widget(form).render(form, self, renderer)]
@@ -342,6 +346,8 @@
                          xml_escape(form.req.build_url('data/puce_down.png')),
                          form.req._('show advanced fields')))
             wdgs.append(u'<div id="%s" class="hidden">' % divid)
+            if self.name_field:
+                wdgs.append(self.render_subfield(form, self.name_field, renderer))
             if self.format_field:
                 wdgs.append(self.render_subfield(form, self.format_field, renderer))
             if self.encoding_field:
@@ -563,7 +569,7 @@
                     kwargs['max_length'] = cstr.max
             return StringField(**kwargs)
         if fieldclass is FileField:
-            for metadata in ('format', 'encoding'):
+            for metadata in ('format', 'encoding', 'name'):
                 metaschema = eschema.has_metadata(rschema, metadata)
                 if metaschema is not None:
                     kwargs['%s_field' % metadata] = guess_field(eschema, metaschema,
--- a/web/uicfg.py	Sun Sep 27 14:37:55 2009 +0200
+++ b/web/uicfg.py	Mon Sep 28 11:09:50 2009 +0200
@@ -157,7 +157,11 @@
                            'CWGroup': 'system',
                            'CWPermission': 'system',
                            'CWCache': 'system',
+                           'Workflow': 'system',
+                           'State': 'hidden',
                            'BaseTransition': 'hidden',
+                           'Transition': 'hidden',
+                           'WorkflowTransition': 'hidden',
                            }
 
 
--- a/web/views/actions.py	Sun Sep 27 14:37:55 2009 +0200
+++ b/web/views/actions.py	Mon Sep 28 11:09:50 2009 +0200
@@ -9,7 +9,7 @@
 _ = unicode
 
 from cubicweb.appobject import objectify_selector
-from cubicweb.selectors import (EntitySelector,
+from cubicweb.selectors import (EntitySelector, yes,
     one_line_rset, two_lines_rset, one_etype_rset, relation_possible,
     nonempty_rset, non_final_entity,
     authenticated_user, match_user_groups, match_search_state,
@@ -359,6 +359,18 @@
     __select__ = match_user_groups('users','managers')
 
 
+class PoweredByAction(Action):
+    id = 'poweredby'
+    __select__ = yes()
+
+    category = 'footer'
+    order = 3
+    title = _('powered by CubicWeb')
+
+    def url(self):
+        return 'http://www.cubicweb.org'
+
+
 from logilab.common.deprecation import class_moved
 from cubicweb.web.views.bookmark import FollowAction
 FollowAction = class_moved(FollowAction)
--- a/web/views/basetemplates.py	Sun Sep 27 14:37:55 2009 +0200
+++ b/web/views/basetemplates.py	Mon Sep 28 11:09:50 2009 +0200
@@ -425,14 +425,13 @@
     def call(self, **kwargs):
         req = self.req
         self.w(u'<div class="footer">')
-        # XXX Take object from the registry if in there? would be
-        #     better anyway
-        from cubicweb.web.views.wdoc import ChangeLogView
-        self.w(u'<a href="%s">%s</a> | ' % (req.build_url('changelog'),
-                                            req._(ChangeLogView.title).lower()))
-        self.w(u'<a href="%s">%s</a> | ' % (req.build_url('doc/about'),
-                                            req._('about this site')))
-        self.w(u'<a href="http://www.cubicweb.org">%s</a>' % req._('powered by CubicWeb'))
+        actions = self.vreg['actions'].possible_actions(self.req, rset=self.rset)
+        footeractions = actions.get('footer', ())
+        for i, action in enumerate(footeractions):
+            self.w(u'<a href="%s">%s</a>' % (action.url(),
+                                             self.req._(action.title)))
+            if i < (len(footeractions) - 1):
+                self.w(u' | ')
         self.w(u'</div>')
 
 
@@ -529,8 +528,3 @@
     if config.get('https-url'):
         return req.url().replace(req.base_url(), config['https-url'])
     return req.url()
-
-
-## vregistry registration callback ############################################
-def registration_callback(vreg):
-    vreg.register_all(globals().values(), __name__)
--- a/web/views/startup.py	Sun Sep 27 14:37:55 2009 +0200
+++ b/web/views/startup.py	Mon Sep 28 11:09:50 2009 +0200
@@ -21,6 +21,7 @@
     id = 'manage'
     title = _('manage')
     http_cache_manager = httpcache.EtagHTTPCacheManager
+    add_etype_links = ()
 
     @classmethod
     def vreg_initialization_completed(cls):
@@ -78,6 +79,16 @@
         self.w(u'<h4>%s</h4>\n' % self.req._('Browse by category'))
         self.vreg['views'].select('tree', self.req).render(w=self.w)
 
+    def create_links(self):
+        self.w(u'<ul class="createLink">')
+        for etype in self.add_etype_links:
+            eschema = self.schema.eschema(etype)
+            if eschema.has_perm(self.req, 'add'):
+                self.w(u'<li><a href="%s">%s</a></li>' % (
+                        self.req.build_url('add/%s' % eschema),
+                        self.req.__('add a %s' % eschema).capitalize()))
+        self.w(u'</ul>')
+
     def startup_views(self):
         self.w(u'<h4>%s</h4>\n' % self.req._('Startup views'))
         self.startupviews_table()
--- a/web/views/wdoc.py	Sun Sep 27 14:37:55 2009 +0200
+++ b/web/views/wdoc.py	Mon Sep 28 11:09:50 2009 +0200
@@ -15,12 +15,11 @@
 from logilab.common.changelog import ChangeLog
 from logilab.mtconverter import CHARSET_DECL_RGX
 
-from cubicweb.selectors import match_form_params
+from cubicweb.selectors import match_form_params, yes
 from cubicweb.view import StartupView
 from cubicweb.utils import strptime, todate
 from cubicweb.common.uilib import rest_publish
-from cubicweb.web import NotFound
-
+from cubicweb.web import NotFound, action
 _ = unicode
 
 # table of content management #################################################
@@ -235,3 +234,28 @@
                     break
         w('') # blank line
         self.w(rest_publish(self, '\n'.join(restdata)))
+
+
+class ChangeLogAction(action.Action):
+    id = 'changelog'
+    __select__ = yes()
+
+    category = 'footer'
+    order = 1
+    title = ChangeLogView.title
+
+    def url(self):
+        return self.req.build_url('changelog')
+
+
+class AboutAction(action.Action):
+    id = 'about'
+    __select__ = yes()
+
+    category = 'footer'
+    order = 2
+    title = _('about this site')
+
+    def url(self):
+        return self.req.build_url('doc/about')
+