--- a/__pkginfo__.py Wed Sep 09 16:11:07 2009 +0200
+++ b/__pkginfo__.py Wed Sep 09 16:48:39 2009 +0200
@@ -7,7 +7,7 @@
distname = "cubicweb"
modname = "cubicweb"
-numversion = (3, 4, 6)
+numversion = (3, 4, 7)
version = '.'.join(str(num) for num in numversion)
license = 'LGPL v2'
--- a/common/mail.py Wed Sep 09 16:11:07 2009 +0200
+++ b/common/mail.py Wed Sep 09 16:48:39 2009 +0200
@@ -21,6 +21,7 @@
return 'XXX'
from cubicweb.view import EntityView
+from cubicweb.entity import Entity
def header(ustring):
return Header(ustring.encode('UTF-8'), 'UTF-8')
@@ -141,14 +142,6 @@
msgid_timestamp = True
- def user_login(self):
- try:
- # if req is actually a session (we are on the server side), and we
- # have to prevent nested internal session
- return self.req.actual_session().user.login
- except AttributeError:
- return self.req.user.login
-
def recipients(self):
finder = self.vreg['components'].select('recipients_finder', self.req,
rset=self.rset,
@@ -161,7 +154,7 @@
subject = self.req._(self.message)
etype = entity.dc_type()
eid = entity.eid
- login = self.user_login()
+ login = self.user_data['login']
return self.req._('%(subject)s %(etype)s #%(eid)s (%(login)s)') % locals()
def context(self, **kwargs):
@@ -169,7 +162,7 @@
for key, val in kwargs.iteritems():
if val and isinstance(val, unicode) and val.strip():
kwargs[key] = self.req._(val)
- kwargs.update({'user': self.user_login(),
+ kwargs.update({'user': self.user_data['login'],
'eid': entity.eid,
'etype': entity.dc_type(),
'url': entity.absolute_url(),
@@ -183,18 +176,12 @@
return construct_message_id(self.config.appid, eid, self.msgid_timestamp)
def render_emails(self, **kwargs):
- """generate and send an email message for this view"""
+ """generate and send emails for this view (one per recipient)"""
self._kwargs = kwargs
recipients = self.recipients()
if not recipients:
self.info('skipping %s notification, no recipients', self.id)
return
- if not isinstance(recipients[0], tuple):
- from warnings import warn
- warn('recipients should now return a list of 2-uple (email, language)',
- DeprecationWarning, stacklevel=1)
- lang = self.vreg.property_value('ui.language')
- recipients = zip(recipients, repeat(lang))
if self.rset is not None:
entity = self.entity(self.row or 0, self.col or 0)
# if the view is using timestamp in message ids, no way to reference
@@ -208,22 +195,32 @@
else:
refs = ()
msgid = None
- userdata = self.req.user_data()
- origlang = self.req.lang
- for emailaddr, lang in recipients:
- self.req.set_language(lang)
+ req = self.req
+ self.user_data = req.user_data()
+ origlang = req.lang
+ for something in recipients:
+ if isinstance(something, Entity):
+ # hi-jack self.req to get a session for the returned user
+ self.req = self.req.hijack_user(something)
+ emailaddr = something.get_email()
+ else:
+ emailaddr, lang = something
+ self.req.set_language(lang)
# since the same view (eg self) may be called multiple time and we
# need a fresh stream at each iteration, reset it explicitly
self.w = None
# XXX call render before subject to set .row/.col attributes on the
# view
- content = self.render(row=0, col=0, **kwargs)
- subject = self.subject()
- msg = format_mail(userdata, [emailaddr], content, subject,
+ try:
+ content = self.render(row=0, col=0, **kwargs)
+ subject = self.subject()
+ except SkipEmail:
+ continue
+ msg = format_mail(self.user_data, [emailaddr], content, subject,
config=self.config, msgid=msgid, references=refs)
yield [emailaddr], msg
# restore language
- self.req.set_language(origlang)
+ req.set_language(origlang)
def render_and_send(self, **kwargs):
"""generate and send an email message for this view"""
@@ -243,3 +240,7 @@
raise NotImplementedError
send = send_now
+
+
+class SkipEmail(Exception):
+ """raise this if you decide to skip an email during its generation"""
--- a/dbapi.py Wed Sep 09 16:11:07 2009 +0200
+++ b/dbapi.py Wed Sep 09 16:48:39 2009 +0200
@@ -284,6 +284,12 @@
# server session compat layer #############################################
+ def hijack_user(self, user):
+ """return a fake request/session using specified user"""
+ req = DBAPIRequest(self.vreg)
+ req.set_connection(self.cnx, user)
+ return req
+
@property
def user(self):
if self._user is None and self.cnx:
--- a/debian/changelog Wed Sep 09 16:11:07 2009 +0200
+++ b/debian/changelog Wed Sep 09 16:48:39 2009 +0200
@@ -1,3 +1,9 @@
+cubicweb (3.4.7-1) unstable; urgency=low
+
+ * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr> Wed, 09 Sep 2009 14:08:41 +0200
+
cubicweb (3.4.6-1) unstable; urgency=low
* new upstream release
--- a/entity.py Wed Sep 09 16:11:07 2009 +0200
+++ b/entity.py Wed Sep 09 16:48:39 2009 +0200
@@ -689,14 +689,16 @@
self.set_related_cache(rtype, role, rset)
return self.related(rtype, role, limit, entities)
- def related_rql(self, rtype, role='subject'):
+ def related_rql(self, rtype, role='subject', targettypes=None):
rschema = self.schema[rtype]
if role == 'subject':
- targettypes = rschema.objects(self.e_schema)
+ if targettypes is None:
+ targettypes = rschema.objects(self.e_schema)
restriction = 'E eid %%(x)s, E %s X' % rtype
card = greater_card(rschema, (self.e_schema,), targettypes, 0)
else:
- targettypes = rschema.subjects(self.e_schema)
+ if targettypes is None:
+ targettypes = rschema.subjects(self.e_schema)
restriction = 'E eid %%(x)s, X %s E' % rtype
card = greater_card(rschema, targettypes, (self.e_schema,), 1)
if len(targettypes) > 1:
--- a/i18n/en.po Wed Sep 09 16:11:07 2009 +0200
+++ b/i18n/en.po Wed Sep 09 16:48:39 2009 +0200
@@ -1646,12 +1646,13 @@
msgid "download"
msgstr ""
+#, python-format
+msgid "download %s"
+msgstr ""
+
msgid "download icon"
msgstr ""
-msgid "download image"
-msgstr ""
-
msgid "download schema as owl"
msgstr ""
@@ -2052,6 +2053,12 @@
msgid "invalid date"
msgstr ""
+msgid "invalid float value"
+msgstr ""
+
+msgid "invalid integer value"
+msgstr ""
+
msgid "is"
msgstr ""
--- a/i18n/es.po Wed Sep 09 16:11:07 2009 +0200
+++ b/i18n/es.po Wed Sep 09 16:48:39 2009 +0200
@@ -1708,12 +1708,13 @@
msgid "download"
msgstr "Descargar"
+#, python-format
+msgid "download %s"
+msgstr ""
+
msgid "download icon"
msgstr "ícono de descarga"
-msgid "download image"
-msgstr ""
-
msgid "download schema as owl"
msgstr "Descargar esquema en OWL"
@@ -2128,6 +2129,12 @@
msgid "invalid date"
msgstr "Esta fecha no es válida"
+msgid "invalid float value"
+msgstr ""
+
+msgid "invalid integer value"
+msgstr ""
+
msgid "is"
msgstr "es"
--- a/i18n/fr.po Wed Sep 09 16:11:07 2009 +0200
+++ b/i18n/fr.po Wed Sep 09 16:48:39 2009 +0200
@@ -1721,12 +1721,13 @@
msgid "download"
msgstr "télécharger"
+#, python-format
+msgid "download %s"
+msgstr "télécharger %s"
+
msgid "download icon"
msgstr "icône de téléchargement"
-msgid "download image"
-msgstr "image de téléchargement"
-
msgid "download schema as owl"
msgstr "télécharger le schéma OWL"
@@ -2141,6 +2142,12 @@
msgid "invalid date"
msgstr "cette date n'est pas valide"
+msgid "invalid float value"
+msgstr "nombre flottant non valide"
+
+msgid "invalid integer value"
+msgstr "nombre entier non valide"
+
msgid "is"
msgstr "de type"
@@ -3199,3 +3206,6 @@
msgid "you should probably delete that property"
msgstr "vous devriez probablement supprimer cette propriété"
+
+#~ msgid "download image"
+#~ msgstr "image de téléchargement"
--- a/server/migractions.py Wed Sep 09 16:11:07 2009 +0200
+++ b/server/migractions.py Wed Sep 09 16:48:39 2009 +0200
@@ -166,14 +166,20 @@
% (self.config.appid, backupfile)):
return
# unpack backup
- bkup = tarfile.open(backupfile, 'r|gz')
- for name in bkup.getnames():
- if name[0] in '/.':
- raise Exception('Security check failed, path starts with "/" or "."')
- bkup.close() # XXX seek error if not close+open !?!
- bkup = tarfile.open(backupfile, 'r|gz')
tmpdir = tempfile.mkdtemp()
- bkup.extractall(path=tmpdir)
+ try:
+ bkup = tarfile.open(backupfile, 'r|gz')
+ except tarfile.ReadError:
+ # assume restoring old backup
+ shutil.copy(backupfile, osp.join(tmpdir, 'system'))
+ else:
+ for name in bkup.getnames():
+ if name[0] in '/.':
+ raise Exception('Security check failed, path starts with "/" or "."')
+ bkup.close() # XXX seek error if not close+open !?!
+ bkup = tarfile.open(backupfile, 'r|gz')
+ bkup.extractall(path=tmpdir)
+ bkup.close()
self.config.open_connections_pools = False
repo = self.repo_connect()
@@ -186,7 +192,6 @@
print '-> error trying to restore [%s]' % exc
if not self.confirm('Continue anyway?', default='n'):
raise SystemExit(1)
- bkup.close()
shutil.rmtree(tmpdir)
# call hooks
repo.open_connections_pools()
--- a/server/querier.py Wed Sep 09 16:11:07 2009 +0200
+++ b/server/querier.py Wed Sep 09 16:48:39 2009 +0200
@@ -608,6 +608,8 @@
# return an empty result instead of raising UnknownEid
return empty_rset(session, rql, args)
cachekey.append(etype)
+ # ensure eid is correctly typed in args
+ args[key] = typed_eid(args[key])
cachekey = tuple(cachekey)
else:
cachekey = rql
--- a/server/session.py Wed Sep 09 16:11:07 2009 +0200
+++ b/server/session.py Wed Sep 09 16:48:39 2009 +0200
@@ -78,16 +78,51 @@
def schema(self):
return self.repo.schema
- def add_relation(self, fromeid, rtype, toeid):
+ def hijack_user(self, user):
+ """return a fake request/session using specified user"""
+ session = Session(user, self.repo)
+ session._threaddata = self._threaddata
+ return session
+
+ def _change_relation(self, cb, fromeid, rtype, toeid):
if self.is_super_session:
- self.repo.glob_add_relation(self, fromeid, rtype, toeid)
+ cb(self, fromeid, rtype, toeid)
return
self.is_super_session = True
try:
- self.repo.glob_add_relation(self, fromeid, rtype, toeid)
+ cb(self, fromeid, rtype, toeid)
finally:
self.is_super_session = False
+ def add_relation(self, fromeid, rtype, toeid):
+ """provide direct access to the repository method to add a relation.
+
+ This is equivalent to the following rql query:
+
+ SET X rtype Y WHERE X eid fromeid, T eid toeid
+
+ without read security check but also all the burden of rql execution.
+ You may use this in hooks when you know both eids of the relation you
+ want to add.
+ """
+ self._change_relation(self.repo.glob_add_relation,
+ fromeid, rtype, toeid)
+ def delete_relation(self, fromeid, rtype, toeid):
+ """provide direct access to the repository method to delete a relation.
+
+ This is equivalent to the following rql query:
+
+ DELETE X rtype Y WHERE X eid fromeid, T eid toeid
+
+ without read security check but also all the burden of rql execution.
+ You may use this in hooks when you know both eids of the relation you
+ want to delete.
+ """
+ self._change_relation(self.repo.glob_delete_relation,
+ fromeid, rtype, toeid)
+
+ # relations cache handling #################################################
+
def update_rel_cache_add(self, subject, rtype, object, symetric=False):
self._update_entity_rel_cache_add(subject, rtype, 'subject', object)
if symetric:
@@ -129,8 +164,11 @@
if row[0] == targeteid:
break
else:
- raise Exception('cache inconsistency for %s %s %s %s' %
- (eid, rtype, role, targeteid))
+ # this may occurs if the cache has been filed by a hook
+ # after the database update
+ self.debug('cache inconsistency for %s %s %s %s', eid, rtype,
+ role, targeteid)
+ return
del rset.rows[idx]
if isinstance(rset.description, list): # else description not set
del rset.description[idx]
--- a/server/test/unittest_querier.py Wed Sep 09 16:11:07 2009 +0200
+++ b/server/test/unittest_querier.py Wed Sep 09 16:48:39 2009 +0200
@@ -210,6 +210,11 @@
# should return an empty result set
self.failIf(self.execute('Any X WHERE X eid 99999999'))
+ def test_typed_eid(self):
+ # should return an empty result set
+ rset = self.execute('Any X WHERE X eid %(x)s', {'x': '1'}, 'x')
+ self.assertIsInstance(rset[0][0], (int, long))
+
def test_bytes_storage(self):
feid = self.execute('INSERT File X: X name "foo.pdf", X data_format "text/plain", X data %(data)s',
{'data': Binary("xxx")})[0][0]
--- a/sobjects/notification.py Wed Sep 09 16:11:07 2009 +0200
+++ b/sobjects/notification.py Wed Sep 09 16:48:39 2009 +0200
@@ -21,7 +21,7 @@
from cubicweb.server.hookhelper import SendMailOp
from cubicweb.server.hooksmanager import Hook
-parse_message_id = deprecated('parse_message_id is now defined in cubicweb.common.mail')
+parse_message_id = deprecated('parse_message_id is now defined in cubicweb.common.mail')(parse_message_id)
class RecipientsFinder(Component):
@@ -190,6 +190,6 @@
def subject(self):
entity = self.entity(self.row or 0, self.col or 0)
return u'%s #%s (%s)' % (self.req.__('New %s' % entity.e_schema),
- entity.eid, self.user_login())
+ entity.eid, self.user_data['login'])
NormalizedTextView = class_renamed('NormalizedTextView', ContentAddedView)
--- a/sobjects/supervising.py Wed Sep 09 16:11:07 2009 +0200
+++ b/sobjects/supervising.py Wed Sep 09 16:48:39 2009 +0200
@@ -23,6 +23,8 @@
accepts = ('Any',)
def call(self, session, *args):
+ if session.is_super_session or session.repo.config.repairing:
+ return # ignore changes triggered by hooks or maintainance shell
dest = self.config['supervising-addrs']
if not dest: # no supervisors, don't do this for nothing...
return
--- a/test/unittest_entity.py Wed Sep 09 16:11:07 2009 +0200
+++ b/test/unittest_entity.py Wed Sep 09 16:48:39 2009 +0200
@@ -132,7 +132,8 @@
seschema.subject_relation('evaluee').set_rproperty(seschema, Note.e_schema, 'cardinality', '1*')
# testing basic fetch_attrs attribute
self.assertEquals(Personne.fetch_rql(user),
- 'Any X,AA,AB,AC ORDERBY AA ASC WHERE X is Personne, X nom AA, X prenom AB, X modification_date AC')
+ 'Any X,AA,AB,AC ORDERBY AA ASC '
+ 'WHERE X is Personne, X nom AA, X prenom AB, X modification_date AC')
pfetch_attrs = Personne.fetch_attrs
sfetch_attrs = Societe.fetch_attrs
try:
@@ -142,18 +143,21 @@
# testing one non final relation
Personne.fetch_attrs = ('nom', 'prenom', 'travaille')
self.assertEquals(Personne.fetch_rql(user),
- 'Any X,AA,AB,AC,AD ORDERBY AA ASC WHERE X is Personne, X nom AA, X prenom AB, X travaille AC, AC nom AD')
+ 'Any X,AA,AB,AC,AD ORDERBY AA ASC '
+ 'WHERE X is Personne, X nom AA, X prenom AB, X travaille AC?, AC nom AD')
# testing two non final relations
Personne.fetch_attrs = ('nom', 'prenom', 'travaille', 'evaluee')
self.assertEquals(Personne.fetch_rql(user),
- 'Any X,AA,AB,AC,AD,AE,AF ORDERBY AA ASC,AF DESC WHERE X is Personne, X nom AA, '
- 'X prenom AB, X travaille AC, AC nom AD, X evaluee AE, AE modification_date AF')
+ 'Any X,AA,AB,AC,AD,AE,AF ORDERBY AA ASC,AF DESC '
+ 'WHERE X is Personne, X nom AA, X prenom AB, X travaille AC?, AC nom AD, '
+ 'X evaluee AE?, AE modification_date AF')
# testing one non final relation with recursion
Personne.fetch_attrs = ('nom', 'prenom', 'travaille')
Societe.fetch_attrs = ('nom', 'evaluee')
self.assertEquals(Personne.fetch_rql(user),
- 'Any X,AA,AB,AC,AD,AE,AF ORDERBY AA ASC,AF DESC WHERE X is Personne, X nom AA, X prenom AB, '
- 'X travaille AC, AC nom AD, AC evaluee AE, AE modification_date AF'
+ 'Any X,AA,AB,AC,AD,AE,AF ORDERBY AA ASC,AF DESC '
+ 'WHERE X is Personne, X nom AA, X prenom AB, X travaille AC?, AC nom AD, '
+ 'AC evaluee AE?, AE modification_date AF'
)
# testing symetric relation
Personne.fetch_attrs = ('nom', 'connait')
@@ -178,15 +182,16 @@
from cubicweb.entities import fetch_config
Personne = self.vreg['etypes'].etype_class('Personne')
Note = self.vreg['etypes'].etype_class('Note')
+ self.failUnless(issubclass(self.vreg['etypes'].etype_class('SubNote'), Note))
Personne.fetch_attrs, Personne.fetch_order = fetch_config(('nom', 'type'))
Note.fetch_attrs, Note.fetch_order = fetch_config(('type',))
- aff = self.add_entity('Personne', nom=u'pouet')
- self.assertEquals(aff.related_rql('evaluee'),
+ p = self.add_entity('Personne', nom=u'pouet')
+ self.assertEquals(p.related_rql('evaluee'),
'Any X,AA,AB ORDERBY AA ASC WHERE E eid %(x)s, E evaluee X, '
'X type AA, X modification_date AB')
Personne.fetch_attrs, Personne.fetch_order = fetch_config(('nom', ))
# XXX
- self.assertEquals(aff.related_rql('evaluee'),
+ self.assertEquals(p.related_rql('evaluee'),
'Any X,AA ORDERBY Z DESC WHERE X modification_date Z, E eid %(x)s, E evaluee X, X modification_date AA')
def test_entity_unrelated(self):
--- a/utils.py Wed Sep 09 16:11:07 2009 +0200
+++ b/utils.py Wed Sep 09 16:48:39 2009 +0200
@@ -7,6 +7,8 @@
"""
__docformat__ = "restructuredtext en"
+from logilab.mtconverter import xml_escape
+
import locale
from md5 import md5
from datetime import datetime, timedelta, date
@@ -262,17 +264,18 @@
# 2/ css files
for cssfile, media in self.cssfiles:
w(u'<link rel="stylesheet" type="text/css" media="%s" href="%s"/>\n' %
- (media, cssfile))
+ (media, xml_escape(cssfile)))
# 3/ ie css if necessary
if self.ie_cssfiles:
w(u'<!--[if lt IE 8]>\n')
for cssfile, media in self.ie_cssfiles:
w(u'<link rel="stylesheet" type="text/css" media="%s" href="%s"/>\n' %
- (media, cssfile))
+ (media, xml_escape(cssfile)))
w(u'<![endif]--> \n')
# 4/ js files
for jsfile in self.jsfiles:
- w(u'<script type="text/javascript" src="%s"></script>\n' % jsfile)
+ w(u'<script type="text/javascript" src="%s"></script>\n' %
+ xml_escape(jsfile))
# 5/ post inlined scripts (i.e. scripts depending on other JS files)
if self.post_inlined_scripts:
w(u'<script type="text/javascript">\n')
@@ -305,7 +308,8 @@
self.htmltag = u'<html xmlns="http://www.w3.org/1999/xhtml" ' \
'xmlns:cubicweb="http://www.logilab.org/2008/cubicweb" ' \
'xml:lang="%s" lang="%s">' % (req.lang, req.lang)
-
+ # keep main_stream's reference on req for easier text/html demoting
+ req.main_stream = self
def write(self, data):
"""StringIO interface: this method will be assigned to self.w
--- a/web/data/cubicweb.ajax.js Wed Sep 09 16:11:07 2009 +0200
+++ b/web/data/cubicweb.ajax.js Wed Sep 09 16:48:39 2009 +0200
@@ -387,24 +387,30 @@
return stripped;
}
-/* convenience function that returns a DOM node based on req's result. */
+/* convenience function that returns a DOM node based on req's result.
+ * XXX clarify the need to clone
+ * */
function getDomFromResponse(response) {
if (typeof(response) == 'string') {
- return html2dom(response);
+ var doc = html2dom(response);
+ } else {
+ var doc = response.documentElement;
}
- var doc = response.documentElement;
var children = doc.childNodes;
if (!children.length) {
// no child (error cases) => return the whole document
- return doc.cloneNode(true);
+ return jQuery(doc).clone().context;
}
children = stripEmptyTextNodes(children);
if (children.length == 1) {
// only one child => return it
- return children[0].cloneNode(true);
+ return jQuery(children[0]).clone().context;
}
// several children => wrap them in a single node and return the wrap
- return DIV(null, map(methodcaller('cloneNode', true), children));
+ return DIV(null, map(function(node) {
+ return jQuery(node).clone().context;
+ },
+ children));
}
function postJSON(url, data, callback) {
--- a/web/data/cubicweb.edition.js Wed Sep 09 16:11:07 2009 +0200
+++ b/web/data/cubicweb.edition.js Wed Sep 09 16:48:39 2009 +0200
@@ -255,6 +255,11 @@
updateInlinedEntitiesCounters(rtype);
reorderTabindex();
form.trigger('inlinedform-added');
+ // if the inlined form contains a file input, we must force
+ // the form enctype to multipart/form-data
+ if (form.find('input:file').length) {
+ form.closest('form').attr('enctype', 'multipart/form-data');
+ }
postAjaxLoad(dom);
});
d.addErrback(function (xxx) {
--- a/web/data/cubicweb.facets.js Wed Sep 09 16:11:07 2009 +0200
+++ b/web/data/cubicweb.facets.js Wed Sep 09 16:48:39 2009 +0200
@@ -66,6 +66,7 @@
extraparams['divid'] = divid;
copyParam(zipped, extraparams, 'divid');
copyParam(zipped, extraparams, 'subvid');
+ copyParam(zipped, extraparams, 'fromformfilter');
// paginate used to know if the filter box is acting, in which case we
// want to reload action box to match current selection (we don't want
// this from a table filter)
--- a/web/request.py Wed Sep 09 16:11:07 2009 +0200
+++ b/web/request.py Wed Sep 09 16:48:39 2009 +0200
@@ -26,7 +26,7 @@
from cubicweb.common.mail import header
from cubicweb.common.uilib import remove_html_tags
from cubicweb.utils import SizeConstrainedList, HTMLHead
-from cubicweb.view import STRICT_DOCTYPE
+from cubicweb.view import STRICT_DOCTYPE, TRANSITIONAL_DOCTYPE_NOEXT
from cubicweb.web import (INTERNAL_FIELD_VALUE, LOGGER, NothingToEdit,
RequestError, StatusResponse)
@@ -663,6 +663,16 @@
"""
raise NotImplementedError()
+ def demote_to_html(self):
+ """helper method to dynamically set request content type to text/html
+
+ The global doctype and xmldec must also be changed otherwise the browser
+ will display '<[' at the beginning of the page
+ """
+ self.set_content_type('text/html')
+ self.main_stream.doctype = TRANSITIONAL_DOCTYPE_NOEXT
+ self.main_stream.xmldecl = u''
+
# page data management ####################################################
def get_page_data(self, key, default=None):
--- a/web/uicfg.py Wed Sep 09 16:11:07 2009 +0200
+++ b/web/uicfg.py Wed Sep 09 16:48:39 2009 +0200
@@ -164,23 +164,28 @@
def init_autoform_section(rtag, sschema, rschema, oschema, role):
if rtag.get(sschema, rschema, oschema, role) is None:
- if role == 'subject':
- card = rschema.rproperty(sschema, oschema, 'cardinality')[0]
- composed = rschema.rproperty(sschema, oschema, 'composite') == 'object'
- else:
- card = rschema.rproperty(sschema, oschema, 'cardinality')[1]
- composed = rschema.rproperty(sschema, oschema, 'composite') == 'subject'
- if sschema.is_metadata(rschema):
+ if autoform_is_inlined.get(sschema, rschema, oschema, role):
+ section = 'generated'
+ elif sschema.is_metadata(rschema):
section = 'metadata'
- elif card in '1+':
- if not rschema.is_final() and composed:
- section = 'generated'
+ else:
+ if role == 'subject':
+ card = rschema.rproperty(sschema, oschema, 'cardinality')[0]
+ composed = rschema.rproperty(sschema, oschema, 'composite') == 'object'
else:
- section = 'primary'
- elif rschema.is_final():
- section = 'secondary'
- else:
- section = 'generic'
+ card = rschema.rproperty(sschema, oschema, 'cardinality')[1]
+ composed = rschema.rproperty(sschema, oschema, 'composite') == 'subject'
+ if card in '1+':
+ if not rschema.is_final() and composed:
+ # XXX why? probably because we want it unlined, though this
+ # is not the case by default
+ section = 'generated'
+ else:
+ section = 'primary'
+ elif rschema.is_final():
+ section = 'secondary'
+ else:
+ section = 'generic'
rtag.tag_relation((sschema, rschema, oschema, role), section)
autoform_section = RelationTags('autoform_section', init_autoform_section,
--- a/web/views/editcontroller.py Wed Sep 09 16:11:07 2009 +0200
+++ b/web/views/editcontroller.py Wed Sep 09 16:48:39 2009 +0200
@@ -191,7 +191,22 @@
return
attrtype = rschema.objects(entity.e_schema)[0].type
# on checkbox or selection, the field may not be in params
- if attrtype == 'Boolean':
+ # NOTE: raising ValidationError here is not a good solution because
+ # we can't gather all errors at once. Hopefully, the new 3.6.x
+ # form handling will fix that
+ if attrtype == 'Int':
+ try:
+ value = int(value)
+ except ValueError:
+ raise ValidationError(entity.eid,
+ {attr: self.req._("invalid integer value")})
+ elif attrtype == 'Float':
+ try:
+ value = float(value)
+ except ValueError:
+ raise ValidationError(entity.eid,
+ {attr: self.req._("invalid float value")})
+ elif attrtype == 'Boolean':
value = bool(value)
elif attrtype == 'Decimal':
value = Decimal(value)
--- a/web/views/editforms.py Wed Sep 09 16:11:07 2009 +0200
+++ b/web/views/editforms.py Wed Sep 09 16:48:39 2009 +0200
@@ -20,7 +20,8 @@
from cubicweb.utils import make_uid
from cubicweb.view import EntityView
from cubicweb.common import tags
-from cubicweb.web import INTERNAL_FIELD_VALUE, stdmsgs, eid_param, uicfg
+from cubicweb.web import INTERNAL_FIELD_VALUE, RequestError, stdmsgs, eid_param
+from cubicweb.web import uicfg
from cubicweb.web.form import FormViewMixIn, FieldNotFound
from cubicweb.web.formfields import guess_field
from cubicweb.web.formwidgets import Button, SubmitButton, ResetButton
@@ -327,13 +328,13 @@
"""creation view for an entity"""
etype = kwargs.pop('etype', self.req.form.get('etype'))
try:
- entity = self.vreg['etypes'].etype_class(etype)(self.req)
- except:
- self.w(self.req._('no such entity type %s') % etype)
- else:
- self.initialize_varmaker()
- entity.eid = self.varmaker.next()
- self.render_form(entity)
+ etype = self.vreg.case_insensitive_etypes[etype.lower()]
+ except KeyError:
+ raise RequestError(self.req._('no such entity type %s') % etype)
+ entity = self.vreg['etypes'].etype_class(etype)(self.req)
+ self.initialize_varmaker()
+ entity.eid = self.varmaker.next()
+ self.render_form(entity)
def form_title(self, entity):
"""the form view title"""
--- a/web/views/igeocodable.py Wed Sep 09 16:11:07 2009 +0200
+++ b/web/views/igeocodable.py Wed Sep 09 16:48:39 2009 +0200
@@ -74,6 +74,7 @@
need_navigation = False
def call(self, gmap_key, width=400, height=400, uselabel=True, urlparams=None):
+ self.req.demote_to_html()
# remove entities that don't define latitude and longitude
self.rset = self.rset.filtered_rset(lambda e: e.latitude and e.longitude)
self.req.add_js('http://maps.google.com/maps?sensor=false&file=api&v=2&key=%s' % gmap_key,
--- a/web/views/tableview.py Wed Sep 09 16:11:07 2009 +0200
+++ b/web/views/tableview.py Wed Sep 09 16:48:39 2009 +0200
@@ -51,6 +51,7 @@
"""display a form to filter table's content. This should only
occurs when a context eid is given
"""
+ self.req.add_css('cubicweb.facets.css')
self.req.add_js( ('cubicweb.ajax.js', 'cubicweb.facets.js'))
# drop False / None values from vidargs
vidargs = dict((k, v) for k, v in vidargs.iteritems() if v)
@@ -58,7 +59,9 @@
xml_escape(dumps([divid, 'table', False, vidargs])))
self.w(u'<fieldset id="%sForm" class="%s">' % (divid, hidden and 'hidden' or ''))
self.w(u'<input type="hidden" name="divid" value="%s" />' % divid)
- filter_hiddens(self.w, facets=','.join(wdg.facet.id for wdg in fwidgets), baserql=baserql)
+ self.w(u'<input type="hidden" name="fromformfilter" value="1" />')
+ filter_hiddens(self.w, facets=','.join(wdg.facet.id for wdg in fwidgets),
+ baserql=baserql)
self.w(u'<table class="filter">\n')
self.w(u'<tr>\n')
for wdg in fwidgets:
@@ -138,7 +141,6 @@
actions += self.form_filter(divid, displaycols, displayfilter,
displayactions)
elif displayfilter:
- req.add_css('cubicweb.facets.css')
actions += self.show_hide_actions(divid, True)
self.w(u'<div id="%s"' % divid)
if displayactions: