backport stable branch
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Wed, 27 May 2009 16:41:51 +0200
changeset 1970 c519a37193e1
parent 1966 87ce7d336393 (diff)
parent 1969 f14f8465269d (current diff)
child 1976 851e08142873
backport stable branch
web/formwidgets.py
--- a/etwist/server.py	Wed May 27 16:41:24 2009 +0200
+++ b/etwist/server.py	Wed May 27 16:41:51 2009 +0200
@@ -196,7 +196,7 @@
         if self.url_rewriter is not None:
             # XXX should occur before authentication?
             try:
-                path = self.url_rewriter.rewrite(host, origpath)
+                path = self.url_rewriter.rewrite(host, origpath, req)
             except Redirect, ex:
                 return self.redirect(req, ex.location)
             request.uri.replace(origpath, path, 1)
--- a/server/serverctl.py	Wed May 27 16:41:24 2009 +0200
+++ b/server/serverctl.py	Wed May 27 16:41:51 2009 +0200
@@ -6,6 +6,7 @@
 """
 __docformat__ = "restructuredtext en"
 
+import sys
 import os
 
 from logilab.common.configuration import REQUIRED, Configuration, ini_format_section
@@ -418,6 +419,51 @@
             cnx.commit()
             print 'grants given to %s on application %s' % (appid, user)
 
+class ResetAdminPasswordCommand(Command):
+    """Reset the administrator password.
+
+    <application>
+      the identifier of the application
+    """
+    name = 'reset-admin-pwd'
+    arguments = '<application>'
+
+    def run(self, args):
+        """run the command with its specific arguments"""
+        from cubicweb.server.sqlutils import sqlexec, SQL_PREFIX
+        from cubicweb.server.utils import crypt_password, manager_userpasswd
+        appid = pop_arg(args, 1, msg="No application specified !")
+        config = ServerConfiguration.config_for(appid)
+        sourcescfg = config.sources()
+        try:
+            adminlogin = sourcescfg['admin']['login']
+        except KeyError:
+            print 'could not get cubicweb administrator login'
+            sys.exit(1)
+        cnx = source_cnx(sourcescfg['system'])
+        cursor = cnx.cursor()
+        _, passwd = manager_userpasswd(adminlogin, confirm=True,
+                                       passwdmsg='new password for %s' % adminlogin)
+        try:
+            sqlexec("UPDATE %(sp)sCWUser SET %(sp)supassword='%(p)s' WHERE %(sp)slogin='%(l)s'"
+                    % {'sp': SQL_PREFIX,
+                       'p': crypt_password(passwd), 'l': adminlogin},
+                    cursor, withpb=False)
+            sconfig = Configuration(options=USER_OPTIONS)
+            sconfig['login'] = adminlogin
+            sconfig['password'] = passwd
+            sourcescfg['admin'] = sconfig
+            sourcesfile = config.sources_file()
+            generate_sources_file(sourcesfile, sourcescfg)
+            restrict_perms_to_user(sourcesfile)
+        except Exception, ex:
+            cnx.rollback()
+            import traceback
+            traceback.print_exc()
+            print 'An error occured:', ex
+        else:
+            cnx.commit()
+            print 'password reset, sources file regenerated'
 
 
 class StartRepositoryCommand(Command):
@@ -735,6 +781,7 @@
 register_commands( (CreateApplicationDBCommand,
                     InitApplicationCommand,
                     GrantUserOnApplicationCommand,
+                    ResetAdminPasswordCommand,
                     StartRepositoryCommand,
                     DBDumpCommand,
                     DBRestoreCommand,
--- a/server/utils.py	Wed May 27 16:41:24 2009 +0200
+++ b/server/utils.py	Wed May 27 16:41:51 2009 +0200
@@ -63,23 +63,21 @@
 DEFAULT_MSG = 'we need a manager connection on the repository \
 (the server doesn\'t have to run, even should better not)'
 
-def manager_userpasswd(user=None, passwd=None, msg=DEFAULT_MSG, confirm=False):
+def manager_userpasswd(user=None, msg=DEFAULT_MSG, confirm=False,
+                       passwdmsg='password'):
     if not user:
         print msg
         while not user:
             user = raw_input('login: ')
-        passwd = getpass('password: ')
-        if confirm:
-            while True:
-                passwd2 = getpass('confirm password: ')
-                if passwd == passwd2:
-                    break
-                print 'password doesn\'t match'
-                passwd = getpass('password: ')
         user = unicode(user, sys.stdin.encoding)
-    elif not passwd:
-        assert not confirm
-        passwd = getpass('password for %s: ' % user)
+    passwd = getpass('%s: ' % passwdmsg)
+    if confirm:
+        while True:
+            passwd2 = getpass('confirm password: ')
+            if passwd == passwd2:
+                break
+            print 'password doesn\'t match'
+            passwd = getpass('password: ')
     # XXX decode password using stdin encoding then encode it using appl'encoding
     return user, passwd
 
--- a/web/facet.py	Wed May 27 16:41:24 2009 +0200
+++ b/web/facet.py	Wed May 27 16:41:51 2009 +0200
@@ -576,11 +576,15 @@
 	min: %(minvalue)s,
 	max: %(maxvalue)s,
         values: [%(minvalue)s, %(maxvalue)s],
+        stop: function(event, ui) { // submit when the user stops sliding
+           var form = $('#%(sliderid)s').closest('form');
+           buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
+        },
     	slide: function(event, ui) {
-	    $('#%(sliderid)s_inf').html(ui.values[0]);
-	    $('#%(sliderid)s_sup').html(ui.values[1]);
-	    $('input[name=%(facetid)s_inf]').val(ui.values[0]);
-	    $('input[name=%(facetid)s_sup]').val(ui.values[1]);
+            $('#%(sliderid)s_inf').html(ui.values[0]);
+            $('#%(sliderid)s_sup').html(ui.values[1]);
+            $('input[name=%(facetid)s_inf]').val(ui.values[0]);
+            $('input[name=%(facetid)s_sup]').val(ui.values[1]);
     	}
    });
 '''
--- a/web/form.py	Wed May 27 16:41:24 2009 +0200
+++ b/web/form.py	Wed May 27 16:41:51 2009 +0200
@@ -261,15 +261,19 @@
             self.restore_previous_post(self.session_key())
 
     @iclassmethod
+    def _fieldsattr(cls_or_self):
+        if isinstance(cls_or_self, type):
+            fields = cls_or_self._fields_
+        else:
+            fields = cls_or_self.fields
+        return fields
+
+    @iclassmethod
     def field_by_name(cls_or_self, name, role='subject'):
         """return field with the given name and role.
         Raise FieldNotFound if the field can't be found.
         """
-        if isinstance(cls_or_self, type):
-            fields = cls_or_self._fields_
-        else:
-            fields = cls_or_self.fields
-        for field in fields:
+        for field in cls_or_self._fieldsattr():
             if field.name == name and field.role == role:
                 return field
         raise FieldNotFound(name)
@@ -277,30 +281,30 @@
     @iclassmethod
     def fields_by_name(cls_or_self, name, role='subject'):
         """return a list of fields with the given name and role"""
-        if isinstance(cls_or_self, type):
-            fields = cls_or_self._fields_
-        else:
-            fields = cls_or_self.fields
-        return [field for field in fields
+        return [field for field in cls_or_self._fieldsattr()
                 if field.name == name and field.role == role]
 
     @iclassmethod
     def remove_field(cls_or_self, field):
         """remove a field from form class or instance"""
-        if isinstance(cls_or_self, type):
-            fields = cls_or_self._fields_
-        else:
-            fields = cls_or_self.fields
-        fields.remove(field)
+        cls_or_self._fieldsattr().remove(field)
 
     @iclassmethod
     def append_field(cls_or_self, field):
         """append a field to form class or instance"""
-        if isinstance(cls_or_self, type):
-            fields = cls_or_self._fields_
-        else:
-            fields = cls_or_self.fields
-        fields.append(field)
+        cls_or_self._fieldsattr().append(field)
+
+    @iclassmethod
+    def insert_field_before(cls_or_self, new_field, name, role='subject'):
+        field = cls_or_self.field_by_name(name, role)
+        fields = cls_or_self._fieldsattr()
+        fields.insert(fields.index(field), new_field)
+
+    @iclassmethod
+    def insert_field_after(cls_or_self, new_field, name, role='subject'):
+        field = cls_or_self.field_by_name(name, role)
+        fields = cls_or_self._fieldsattr()
+        fields.insert(fields.index(field)+1, new_field)
 
     @property
     def form_needs_multipart(self):
--- a/web/formwidgets.py	Wed May 27 16:41:24 2009 +0200
+++ b/web/formwidgets.py	Wed May 27 16:41:51 2009 +0200
@@ -7,6 +7,7 @@
 __docformat__ = "restructuredtext en"
 
 from datetime import date
+from warnings import warn
 
 from cubicweb.common import tags
 from cubicweb.web import stdmsgs, INTERNAL_FIELD_VALUE
@@ -109,6 +110,11 @@
         return u'\n'.join(inputs)
 
 
+class PasswordSingleInput(Input):
+    """<input type='password'> without a confirmation field"""
+    type = 'password'
+
+
 class FileInput(Input):
     """<input type='file'>"""
     type = 'file'
@@ -299,6 +305,17 @@
     wdgtype = 'SuggestField'
     loadtype = 'auto'
 
+    def __init__(self, *args, **kwargs):
+        try:
+            self.autocomplete_initfunc = kwargs.pop('autocomplete_initfunc')
+        except KeyError:
+            warn('use autocomplete_initfunc argument of %s constructor '
+                 'instead of relying on autocomplete_initfuncs dictionary on '
+                 'the entity class' % self.__class__.__name__,
+                 DeprecationWarning)
+            self.autocomplete_initfunc = None
+        super(AutoCompletionWidget, self).__init__(*args, **kwargs)
+
     def _render_attrs(self, form, field):
         name, values, attrs = super(AutoCompletionWidget, self)._render_attrs(form, field)
         init_ajax_attributes(attrs, self.wdgtype, self.loadtype)
@@ -307,7 +324,11 @@
         return name, values, attrs
 
     def _get_url(self, entity, field):
-        fname = entity.autocomplete_initfuncs[field.name]
+        if self.autocomplete_initfunc is None:
+            # XXX for bw compat
+            fname = entity.autocomplete_initfuncs[field.name]
+        else:
+            fname = self.autocomplete_initfunc
         return entity.req.build_url('json', fname=fname, mode='remote',
                                     pageid=entity.req.pageid)
 
@@ -317,7 +338,12 @@
     wdgtype = 'StaticFileSuggestField'
 
     def _get_url(self, entity, field):
-        return entity.req.datadir_url + entity.autocomplete_initfuncs[field.name]
+        if self.autocomplete_initfunc is None:
+            # XXX for bw compat
+            fname = entity.autocomplete_initfuncs[field.name]
+        else:
+            fname = self.autocomplete_initfunc
+        return entity.req.datadir_url + fname
 
 
 class RestrictedAutoCompletionWidget(AutoCompletionWidget):
--- a/web/views/apacherewrite.py	Wed May 27 16:41:24 2009 +0200
+++ b/web/views/apacherewrite.py	Wed May 27 16:41:51 2009 +0200
@@ -87,7 +87,8 @@
     id = 'urlrewriter'
     rules = []
 
-    def rewrite(self, host, path):
+    def rewrite(self, host, path, req):
+        self.req = req
         for cond in self.rules:
             if cond.match(host=host, path=path):
                 return cond.process(path)
--- a/web/views/plots.py	Wed May 27 16:41:24 2009 +0200
+++ b/web/views/plots.py	Wed May 27 16:41:51 2009 +0200
@@ -87,7 +87,7 @@
      lines: {show: true},
      grid: {hoverable: true},
      xaxis: {mode: %(mode)s}});
-jQuery('#%(figid)s').bind('plothover', onPlotHover);
+jQuery("#%(figid)s").bind("plothover", onPlotHover);
 '''
 
     def __init__(self, labels, plots, timemode=False):
@@ -177,10 +177,22 @@
 
         __select__ = at_least_two_columns() & second_column_is_number()
 
+        def _guess_vid(self, row):
+            etype = self.rset.description[row][0]
+            if self.schema.eschema(etype).is_final():
+                return 'final'
+            return 'textincontext'
+
         def call(self, title=None, width=None, height=None):
-            labels = ['%s: %s' % (row[0].encode(self.req.encoding), row[1])
-                      for row in self.rset]
-            values = [(row[1] or 0) for row in self.rset]
+            labels = []
+            values = []
+            for rowidx, (_, value) in enumerate(self.rset):
+                if value is not None:
+                    vid = self._guess_vid(rowidx)
+                    label = '%s: %s' % (self.view(vid, self.rset, row=rowidx, col=0),
+                                        value)
+                    labels.append(label.encode(self.req.encoding))
+                    values.append(value)
             pie = PieChartWidget(labels, values, pieclass=self.pieclass,
                                  title=title)
             if width is not None: