--- 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: