# HG changeset patch # User Sylvain Thénault # Date 1317057848 -7200 # Node ID 39a54b88906d7a7c89062cd3abe94d9b1093b4ea # Parent 15809afe093b4b3da1662582a764e1c1bdcfebc0# Parent 0abed94a9859bbd4b5232b27fdabd71cf980e0c2 backport stable diff -r 15809afe093b -r 39a54b88906d .hgtags --- a/.hgtags Mon Sep 26 18:03:38 2011 +0200 +++ b/.hgtags Mon Sep 26 19:24:08 2011 +0200 @@ -223,3 +223,7 @@ a62f24e1497e953fbaed5894f6064a64f7ac0be3 cubicweb-version-3.10.x 20d9c550c57eb6f9adcb0cfab1c11b6b8793afb6 cubicweb-version-3.13.5 2e9dd7d945557c210d3b79153c65f6885e755315 cubicweb-debian-version-3.13.5-1 +074c848a3712a77737d9a1bfbb618c75f5c0cbfa cubicweb-version-3.12.10 +9dfd21fa0a8b9f121a08866ad3e2ebd1dd06790d cubicweb-debian-version-3.12.10-1 +17c007ad845abbac82e12146abab32a634657574 cubicweb-version-3.13.6 +8a8949ca5351d48c5cf795ccdff06c1d4aab2ce0 cubicweb-debian-version-3.13.6-1 diff -r 15809afe093b -r 39a54b88906d __pkginfo__.py --- a/__pkginfo__.py Mon Sep 26 18:03:38 2011 +0200 +++ b/__pkginfo__.py Mon Sep 26 19:24:08 2011 +0200 @@ -22,7 +22,11 @@ modname = distname = "cubicweb" +<<<<<<< /home/syt/src/cubicweb/__pkginfo__.py numversion = (3, 14, 0) +======= +numversion = (3, 13, 6) +>>>>>>> /tmp/__pkginfo__.py~other.Prvgd6 version = '.'.join(str(num) for num in numversion) description = "a repository of entities / relations for knowledge management" diff -r 15809afe093b -r 39a54b88906d debian/changelog --- a/debian/changelog Mon Sep 26 18:03:38 2011 +0200 +++ b/debian/changelog Mon Sep 26 19:24:08 2011 +0200 @@ -1,3 +1,9 @@ +cubicweb (3.13.6-1) unstable; urgency=low + + * new upstream release + + -- Sylvain Thénault Mon, 26 Sep 2011 18:36:00 +0200 + cubicweb (3.13.5-1) unstable; urgency=low * new upstream release @@ -28,6 +34,12 @@ -- Sylvain Thénault Tue, 12 Jul 2011 12:23:54 +0200 +cubicweb (3.12.10-1) unstable; urgency=low + + * new upstream release + + -- Sylvain Thénault Mon, 26 Sep 2011 17:22:29 +0200 + cubicweb (3.12.9-1) unstable; urgency=low * new upstream release diff -r 15809afe093b -r 39a54b88906d devtools/__init__.py --- a/devtools/__init__.py Mon Sep 26 18:03:38 2011 +0200 +++ b/devtools/__init__.py Mon Sep 26 19:24:08 2011 +0200 @@ -260,8 +260,9 @@ Example usage:: class MyTests(CubicWebTC): - _config = RealDatabseConfiguration('myapp', - sourcefile='/path/to/sources') + _config = RealDatabaseConfiguration('myapp', + sourcefile='/path/to/sources') + def test_something(self): rset = self.execute('Any X WHERE X is CWUser') self.view('foaf', rset) diff -r 15809afe093b -r 39a54b88906d devtools/fake.py --- a/devtools/fake.py Mon Sep 26 18:03:38 2011 +0200 +++ b/devtools/fake.py Mon Sep 26 19:24:08 2011 +0200 @@ -63,8 +63,8 @@ self._session_data = {} self._headers_in = Headers() - def set_cookie(self, cookie, key, maxage=300, expires=None): - super(FakeRequest, self).set_cookie(cookie, key, maxage=300, expires=None) + def set_cookie(self, name, value, maxage=300, expires=None, secure=False): + super(FakeRequest, self).set_cookie(name, value, maxage, expires, secure) cookie = self.get_response_header('Set-Cookie') self._headers_in.setHeader('Cookie', cookie) diff -r 15809afe093b -r 39a54b88906d devtools/repotest.py --- a/devtools/repotest.py Mon Sep 26 18:03:38 2011 +0200 +++ b/devtools/repotest.py Mon Sep 26 19:24:08 2011 +0200 @@ -329,9 +329,10 @@ # monkey patch some methods to get predicatable results ####################### -from cubicweb.rqlrewrite import RQLRewriter -_orig_insert_snippets = RQLRewriter.insert_snippets -_orig_build_variantes = RQLRewriter.build_variantes +from cubicweb import rqlrewrite +_orig_iter_relations = rqlrewrite.iter_relations +_orig_insert_snippets = rqlrewrite.RQLRewriter.insert_snippets +_orig_build_variantes = rqlrewrite.RQLRewriter.build_variantes def _insert_snippets(self, snippets, varexistsmap=None): _orig_insert_snippets(self, sorted(snippets, snippet_cmp), varexistsmap) @@ -415,9 +416,13 @@ def _syntax_tree_search(*args, **kwargs): return deepcopy(_orig_syntax_tree_search(*args, **kwargs)) +def _ordered_iter_relations(stinfo): + return sorted(_orig_iter_relations(stinfo), key=lambda x:x.r_type) + def do_monkey_patch(): - RQLRewriter.insert_snippets = _insert_snippets - RQLRewriter.build_variantes = _build_variantes + rqlrewrite.iter_relations = _ordered_iter_relations + rqlrewrite.RQLRewriter.insert_snippets = _insert_snippets + rqlrewrite.RQLRewriter.build_variantes = _build_variantes ExecutionPlan._check_permissions = _check_permissions ExecutionPlan.tablesinorder = None ExecutionPlan.init_temp_table = _init_temp_table @@ -426,8 +431,9 @@ PyroRQLSource.syntax_tree_search = _syntax_tree_search def undo_monkey_patch(): - RQLRewriter.insert_snippets = _orig_insert_snippets - RQLRewriter.build_variantes = _orig_build_variantes + rqlrewrite.iter_relations = _orig_iter_relations + rqlrewrite.RQLRewriter.insert_snippets = _orig_insert_snippets + rqlrewrite.RQLRewriter.build_variantes = _orig_build_variantes ExecutionPlan._check_permissions = _orig_check_permissions ExecutionPlan.init_temp_table = _orig_init_temp_table PartPlanInformation.merge_input_maps = _orig_merge_input_maps diff -r 15809afe093b -r 39a54b88906d doc/book/en/devrepo/testing.rst --- a/doc/book/en/devrepo/testing.rst Mon Sep 26 18:03:38 2011 +0200 +++ b/doc/book/en/devrepo/testing.rst Mon Sep 26 19:24:08 2011 +0200 @@ -337,13 +337,12 @@ sourcefile='/path/to/realdb_sources') def test_blog_rss(self): - req = self.request() - rset = req.execute('Any B ORDERBY D DESC WHERE B is BlogEntry, ' - 'B created_by U, U login "logilab", B creation_date D') + req = self.request() + rset = req.execute('Any B ORDERBY D DESC WHERE B is BlogEntry, ' + 'B created_by U, U login "logilab", B creation_date D') self.view('rss', rset) - Testing with other cubes ------------------------ diff -r 15809afe093b -r 39a54b88906d etwist/http.py --- a/etwist/http.py Mon Sep 26 18:03:38 2011 +0200 +++ b/etwist/http.py Mon Sep 26 19:24:08 2011 +0200 @@ -1,7 +1,7 @@ """twisted server for CubicWeb web instances :organization: Logilab -:copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. +:copyright: 2001-2011 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses """ @@ -25,25 +25,14 @@ def _init_headers(self): if self._headers_out is None: return - - # initialize cookies - cookies = self._headers_out.getHeader('set-cookie') or [] - for cookie in cookies: - self._twreq.addCookie(cookie.name, cookie.value, cookie.expires, - cookie.domain, cookie.path, #TODO max-age - comment = cookie.comment, secure=cookie.secure) - self._headers_out.removeHeader('set-cookie') - - # initialize other headers - for k, v in self._headers_out.getAllRawHeaders(): - self._twreq.setHeader(k, v[0]) - + # initialize headers + for k, values in self._headers_out.getAllRawHeaders(): + self._twreq.responseHeaders.setRawHeaders(k, values) # add content-length if not present if (self._headers_out.getHeader('content-length') is None and self._stream is not None): self._twreq.setHeader('content-length', len(self._stream)) - def _finalize(self): # we must set code before writing anything, else it's too late if self._code is not None: diff -r 15809afe093b -r 39a54b88906d i18n/de.po --- a/i18n/de.po Mon Sep 26 18:03:38 2011 +0200 +++ b/i18n/de.po Mon Sep 26 19:24:08 2011 +0200 @@ -225,6 +225,9 @@ "können ein vollständiges Schema mit Meta-Daten anzeigen." +msgid "" +msgstr "" + msgid "" msgstr "" @@ -3595,9 +3598,6 @@ msgid "searching for" msgstr "Suche nach" -msgid "secondary" -msgstr "sekundär" - msgid "security" msgstr "Sicherheit" @@ -4461,9 +4461,12 @@ #, python-format msgid "you should un-inline relation %s which is supported and may be crossed " msgstr "" +<<<<<<< /home/syt/src/cubicweb/i18n/de.po #~ msgid "Schema of the data model" #~ msgstr "Schema des Datenmodells" #~ msgid "instance schema" #~ msgstr "Schema der Instanz" +======= +>>>>>>> /tmp/de.po~other.fn7YK0 diff -r 15809afe093b -r 39a54b88906d i18n/en.po --- a/i18n/en.po Mon Sep 26 18:03:38 2011 +0200 +++ b/i18n/en.po Mon Sep 26 19:24:08 2011 +0200 @@ -214,6 +214,9 @@ "can also display a complete schema with meta-data." msgstr "" +msgid "" +msgstr "" + msgid "" msgstr "" @@ -1041,9 +1044,6 @@ msgid "add a CWRType" msgstr "add a relation type" -msgid "add a CWSource" -msgstr "add a source" - msgctxt "inlined:CWUser.use_email.subject" msgid "add a EmailAddress" msgstr "add an email address" @@ -3508,9 +3508,6 @@ msgid "searching for" msgstr "" -msgid "secondary" -msgstr "" - msgid "security" msgstr "" @@ -4349,9 +4346,12 @@ #, python-format msgid "you should un-inline relation %s which is supported and may be crossed " msgstr "" +<<<<<<< /home/syt/src/cubicweb/i18n/en.po #~ msgid "add a CWSourceSchemaConfig" #~ msgstr "add an item to mapping " #~ msgid "siteinfo" #~ msgstr "site information" +======= +>>>>>>> /tmp/en.po~other.NvgtGM diff -r 15809afe093b -r 39a54b88906d i18n/es.po --- a/i18n/es.po Mon Sep 26 18:03:38 2011 +0200 +++ b/i18n/es.po Mon Sep 26 19:24:08 2011 +0200 @@ -226,6 +226,9 @@ "pero se puede ver a un modelo completo con meta-datos." +msgid "" +msgstr "" + msgid "" msgstr "" @@ -1091,9 +1094,12 @@ msgid "add a CWRType" msgstr "Agregar un tipo de relación" +<<<<<<< /home/syt/src/cubicweb/i18n/es.po msgid "add a CWSource" msgstr "agregar una fuente" +======= +>>>>>>> /tmp/es.po~other.Yb6Y5q msgctxt "inlined:CWUser.use_email.subject" msgid "add a EmailAddress" msgstr "Agregar correo electrónico" @@ -3645,9 +3651,6 @@ msgid "searching for" msgstr "Buscando" -msgid "secondary" -msgstr "Secundaria" - msgid "security" msgstr "Seguridad" @@ -4512,6 +4515,7 @@ msgstr "" "usted debe quitar la puesta en línea de la relación %s que es aceptada y " "puede ser cruzada" +<<<<<<< /home/syt/src/cubicweb/i18n/es.po #~ msgid "Schema of the data model" #~ msgstr "Esquema del modelo de datos" @@ -4524,3 +4528,5 @@ #~ msgid "siteinfo" #~ msgstr "información" +======= +>>>>>>> /tmp/es.po~other.Yb6Y5q diff -r 15809afe093b -r 39a54b88906d i18n/fr.po --- a/i18n/fr.po Mon Sep 26 18:03:38 2011 +0200 +++ b/i18n/fr.po Mon Sep 26 19:24:08 2011 +0200 @@ -226,6 +226,9 @@ "
Ce schéma du modèle de données exclue les méta-données, mais " "vous pouvez afficher un schéma complet.
" +msgid "" +msgstr "" + msgid "" msgstr "" @@ -1091,9 +1094,12 @@ msgid "add a CWRType" msgstr "ajouter un type de relation" +<<<<<<< /home/syt/src/cubicweb/i18n/fr.po msgid "add a CWSource" msgstr "ajouter une source" +======= +>>>>>>> /tmp/fr.po~other.KbuYNx msgctxt "inlined:CWUser.use_email.subject" msgid "add a EmailAddress" msgstr "ajouter une adresse électronique" @@ -3651,9 +3657,6 @@ msgid "searching for" msgstr "Recherche de" -msgid "secondary" -msgstr "secondaire" - msgid "security" msgstr "sécurité" diff -r 15809afe093b -r 39a54b88906d rqlrewrite.py --- a/rqlrewrite.py Mon Sep 26 18:03:38 2011 +0200 +++ b/rqlrewrite.py Mon Sep 26 19:24:08 2011 +0200 @@ -119,6 +119,10 @@ return newsolutions +def iter_relations(stinfo): + # this is a function so that test may return relation in a predictable order + return stinfo['relations'] - stinfo['rhsrelations'] + class Unsupported(Exception): """raised when an rql expression can't be inserted in some rql query because it create an unresolvable query (eg no solutions found) @@ -349,7 +353,7 @@ while todo: varname, stinfo = todo.pop() done.add(varname) - for rel in stinfo['relations'] - stinfo['rhsrelations']: + for rel in iter_relations(stinfo): if rel in done: continue done.add(rel) @@ -380,7 +384,7 @@ if vref.name not in done and rschema.inlined: # we can use vref here define in above for loop ostinfo = vref.variable.stinfo - for orel in ostinfo['relations'] - ostinfo['rhsrelations']: + for orel in iter_relations(ostinfo): orschema = get_rschema(orel.r_type) if orschema.final or orschema.inlined: todo.append( (vref.name, ostinfo) ) diff -r 15809afe093b -r 39a54b88906d skeleton/test/realdb_test_CUBENAME.py --- a/skeleton/test/realdb_test_CUBENAME.py Mon Sep 26 18:03:38 2011 +0200 +++ b/skeleton/test/realdb_test_CUBENAME.py Mon Sep 26 19:24:08 2011 +0200 @@ -18,8 +18,8 @@ """ """ -from cubicweb.devtools import buildconfig, loadconfig -from cubicweb.devtools.testlib import RealDBTest +from cubicweb.devtools.testlib import CubicWebTC +from cubicweb.devtools.realdbtest import buildconfig, loadconfig def setUpModule(options): if options.source: @@ -32,7 +32,8 @@ options.epassword) RealDatabaseTC.configcls = configcls -class RealDatabaseTC(RealDBTest): + +class RealDatabaseTC(CubicWebTC): configcls = None # set by setUpModule() def test_all_primaries(self): diff -r 15809afe093b -r 39a54b88906d test/unittest_rqlrewrite.py --- a/test/unittest_rqlrewrite.py Mon Sep 26 18:03:38 2011 +0200 +++ b/test/unittest_rqlrewrite.py Mon Sep 26 19:24:08 2011 +0200 @@ -21,9 +21,8 @@ from yams import BadSchemaDefinition from rql import parse, nodes, RQLHelper -from cubicweb import Unauthorized +from cubicweb import Unauthorized, rqlrewrite from cubicweb.schema import RRQLExpression, ERQLExpression -from cubicweb.rqlrewrite import RQLRewriter from cubicweb.devtools import repotest, TestServerConfiguration @@ -62,9 +61,10 @@ @staticmethod def simplify(mainrqlst, needcopy=False): rqlhelper.simplify(rqlst, needcopy) - rewriter = RQLRewriter(mock_object(vreg=FakeVReg, user=(mock_object(eid=1)))) + rewriter = rqlrewrite.RQLRewriter( + mock_object(vreg=FakeVReg, user=(mock_object(eid=1)))) snippets = [] - for v, exprs in snippets_map.items(): + for v, exprs in sorted(snippets_map.items()): rqlexprs = [isinstance(snippet, basestring) and mock_object(snippet_rqlst=parse('Any X WHERE '+snippet).children[0], expression='Any X WHERE '+snippet) @@ -210,11 +210,11 @@ }, {}) # XXX suboptimal self.assertEqual(rqlst.as_string(), - "Any C,A,R WITH A,R,C BEING " - "(Any A,R,C WHERE A ref R, A? inlined_card C, " - "(A is NULL) OR (EXISTS(A inlined_card B, B require_permission D, " - "B is Card, D is CWPermission)), " - "A is Affaire, C is Card, EXISTS(C require_permission E, E is CWPermission))") + "Any C,A,R WITH A,C,R BEING " + "(Any A,C,R WHERE A? inlined_card C, A ref R, " + "(A is NULL) OR (EXISTS(A inlined_card B, B require_permission D, " + "B is Card, D is CWPermission)), " + "A is Affaire, C is Card, EXISTS(C require_permission E, E is CWPermission))") # def test_optional_var_inlined_has_perm(self): # c1 = ('X require_permission P') diff -r 15809afe093b -r 39a54b88906d web/application.py --- a/web/application.py Mon Sep 26 18:03:38 2011 +0200 +++ b/web/application.py Mon Sep 26 19:24:08 2011 +0200 @@ -236,12 +236,10 @@ def open_session(self, req, allow_no_cnx=True): session = self.session_manager.open_session(req, allow_no_cnx=allow_no_cnx) - cookie = req.get_cookie() sessioncookie = self.session_cookie(req) - cookie[sessioncookie] = session.sessionid - if req.https and req.base_url().startswith('https://'): - cookie[sessioncookie]['secure'] = True - req.set_cookie(cookie, sessioncookie, maxage=None) + secure = req.https and req.base_url().startswith('https://') + req.set_cookie(sessioncookie, session.sessionid, + maxage=None, secure=secure) if not session.anonymous_session: self.session_manager.postlogin(req) return session @@ -251,8 +249,7 @@ `AuthenticationError` """ self.session_manager.close_session(req.session) - sessioncookie = self.session_cookie(req) - req.remove_cookie(req.get_cookie(), sessioncookie) + req.remove_cookie(self.session_cookie(req)) raise LogOut(url=goto_url) # these are overridden by set_log_methods below diff -r 15809afe093b -r 39a54b88906d web/data/cubicweb.facets.css --- a/web/data/cubicweb.facets.css Mon Sep 26 18:03:38 2011 +0200 +++ b/web/data/cubicweb.facets.css Mon Sep 26 19:24:08 2011 +0200 @@ -15,7 +15,7 @@ color: #000; margin-bottom: 2px; cursor: pointer; - font: bold 100% Georgia; + font: %(facet_titleFont)s; } div.facetTitle a { @@ -30,8 +30,8 @@ color: #000 !important; } -div.overflowed{ - height: 12em; +div.overflowed { + height: %(facet_overflowedHeight)s; overflow-y: auto; } diff -r 15809afe093b -r 39a54b88906d web/data/uiprops.py --- a/web/data/uiprops.py Mon Sep 26 18:03:38 2011 +0200 +++ b/web/data/uiprops.py Mon Sep 26 19:24:08 2011 +0200 @@ -165,3 +165,9 @@ infoMsgBgImg = 'url("information.png") 5px center no-repeat' errorMsgBgImg = 'url("error.png") 100% 50% no-repeat' errorMsgColor = '#ed0d0d' + +# facets +facet_titleFont = 'bold 100% Georgia' +facet_overflowedHeight = '12em' + + diff -r 15809afe093b -r 39a54b88906d web/facet.py --- a/web/facet.py Mon Sep 26 18:03:38 2011 +0200 +++ b/web/facet.py Mon Sep 26 19:24:08 2011 +0200 @@ -587,7 +587,7 @@ _select_target_entity = True title = property(rtype_facet_title) - no_relation_label = '' + no_relation_label = _('') def __repr__(self): return '<%s on (%s-%s)>' % (self.__class__.__name__, self.rtype, self.role) @@ -991,7 +991,7 @@ class AgencyFacet(RQLPathFacet): __regid__ = 'agency' # this facet should only be selected when visualizing offices - __select__ = RelationFacet.__select__ & is_instance('Office') + __select__ = is_instance('Office') # this facet is a filter on the 'Agency' entities linked to the office # through the 'proposed_by' relation, where the office is the subject # of the relation @@ -1002,7 +1002,7 @@ class PostalCodeFacet(RQLPathFacet): __regid__ = 'postalcode' # this facet should only be selected when visualizing offices - __select__ = RelationAttributeFacet.__select__ & is_instance('Office') + __select__ = is_instance('Office') # this facet is a filter on the PostalAddress entities linked to the # office through the 'has_address' relation, where the office is the # subject of the relation @@ -1336,6 +1336,24 @@ ## html widets ################################################################ +_DEFAULT_CONSTANT_VOCAB_WIDGET_HEIGHT = 9 + +@cached +def _css_height_to_line_count(vreg): + cssprop = vreg.config.uiprops['facet_overflowedHeight'].lower().strip() + # let's talk a bit ... + # we try to deduce a number of displayed lines from a css property + # there is a linear (rough empiric coefficient == 0.73) relation between + # css _em_ value and line qty + # if we get another unit we're out of luck and resort to one constant + # hence, it is strongly advised not to specify but ems for this css prop + if cssprop.endswith('em'): + try: + return int(cssprop[:-2]) * .73 + except Exception: + vreg.warning('css property facet_overflowedHeight looks malformed (%r)', + cssprop) + return _DEFAULT_CONSTANT_VOCAB_WIDGET_HEIGHT class FacetVocabularyWidget(htmlwidgets.HTMLWidget): @@ -1343,8 +1361,10 @@ self.facet = facet self.items = [] + @cached def height(self): - return len(self.items) + 1 + maxheight = _css_height_to_line_count(self.facet._cw.vreg) + return 1 + min(len(self.items), maxheight) + int(self.facet._support_and_compat()) def append(self, item): self.items.append(item) diff -r 15809afe093b -r 39a54b88906d web/http_headers.py --- a/web/http_headers.py Mon Sep 26 18:03:38 2011 +0200 +++ b/web/http_headers.py Mon Sep 26 19:24:08 2011 +0200 @@ -1354,9 +1354,25 @@ raw_header.append(value) self._headers[name] = _RecalcNeeded + def addHeader(self, name, value): + """ + Add a parsed representatoin to a header that may or may not already exist. + If it exists, add it as a separate header to output; do not + replace anything. + """ + name=name.lower() + header = self._headers.get(name) + if header is None: + # No header yet + header = [] + self._headers[name] = header + elif header is _RecalcNeeded: + header = self._toParsed(name) + header.append(value) + self._raw_headers[name] = _RecalcNeeded + def removeHeader(self, name): """Removes the header named.""" - name=name.lower() if self._raw_headers.has_key(name): del self._raw_headers[name] diff -r 15809afe093b -r 39a54b88906d web/request.py --- a/web/request.py Mon Sep 26 18:03:38 2011 +0200 +++ b/web/request.py Mon Sep 26 19:24:08 2011 +0200 @@ -19,11 +19,12 @@ __docformat__ = "restructuredtext en" -import Cookie import hashlib import time import random import base64 +from Cookie import SimpleCookie +from calendar import timegm from datetime import date from urlparse import urlsplit from itertools import count @@ -42,7 +43,8 @@ from cubicweb.view import STRICT_DOCTYPE, TRANSITIONAL_DOCTYPE_NOEXT from cubicweb.web import (INTERNAL_FIELD_VALUE, LOGGER, NothingToEdit, RequestError, StatusResponse) -from cubicweb.web.http_headers import Headers +from cubicweb.web.httpcache import GMTOFFSET +from cubicweb.web.http_headers import Headers, Cookie _MARKER = object() @@ -518,30 +520,44 @@ def get_cookie(self): """retrieve request cookies, returns an empty cookie if not found""" + # XXX use http_headers implementation try: - return Cookie.SimpleCookie(self.get_header('Cookie')) + return SimpleCookie(self.get_header('Cookie')) except KeyError: - return Cookie.SimpleCookie() + return SimpleCookie() - def set_cookie(self, cookie, key, maxage=300, expires=None): - """set / update a cookie key + def set_cookie(self, name, value, maxage=300, expires=None, secure=False): + """set / update a cookie by default, cookie will be available for the next 5 minutes. Give maxage = None to have a "session" cookie expiring when the client close its browser """ - morsel = cookie[key] - if maxage is not None: - morsel['Max-Age'] = maxage - if expires: - morsel['expires'] = expires.strftime('%a, %d %b %Y %H:%M:%S %z') + if isinstance(name, SimpleCookie): + warn('[3.13] set_cookie now takes name and value as two first ' + 'argument, not anymore cookie object and name', + DeprecationWarning, stacklevel=2) + secure = name[value]['secure'] + name, value = value, name[value].value + if maxage: # don't check is None, 0 may be specified + assert expires is None, 'both max age and expires cant be specified' + expires = maxage + time.time() + elif expires: + expires = timegm((expires + GMTOFFSET).timetuple()) + else: + expires = None # make sure cookie is set on the correct path - morsel['path'] = self.base_url_path() - self.add_header('Set-Cookie', morsel.OutputString()) + cookie = Cookie(name, value, self.base_url_path(), expires=expires, + secure=secure) + self.headers_out.addHeader('Set-cookie', cookie) - def remove_cookie(self, cookie, key): + def remove_cookie(self, name, bwcompat=None): """remove a cookie by expiring it""" - self.set_cookie(cookie, key, maxage=0, expires=date(1970, 1, 1)) + if bwcompat is not None: + warn('[3.13] remove_cookie now take only a name as argument', + DeprecationWarning, stacklevel=2) + name = bwcompat + self.set_cookie(key, '', maxage=0, expires=date(1970, 1, 1)) def set_content_type(self, content_type, filename=None, encoding=None): """set output content type for this request. An optional filename diff -r 15809afe093b -r 39a54b88906d web/views/basecontrollers.py --- a/web/views/basecontrollers.py Mon Sep 26 18:03:38 2011 +0200 +++ b/web/views/basecontrollers.py Mon Sep 26 19:24:08 2011 +0200 @@ -535,24 +535,20 @@ statename = treecookiename(treeid) treestate = cookies.get(statename) if treestate is None: - cookies[statename] = nodeeid - self._cw.set_cookie(cookies, statename) + self._cw.set_cookie(statename, nodeeid) else: marked = set(filter(None, treestate.value.split(':'))) if nodeeid in marked: marked.remove(nodeeid) else: marked.add(nodeeid) - cookies[statename] = ':'.join(marked) - self._cw.set_cookie(cookies, statename) + self._cw.set_cookie(statename, ':'.join(marked)) @jsonize @deprecated("[3.13] use jQuery.cookie(cookiename, cookievalue, {path: '/'}) in js land instead") def js_set_cookie(self, cookiename, cookievalue): cookiename, cookievalue = str(cookiename), str(cookievalue) - cookies = self._cw.get_cookie() - cookies[cookiename] = cookievalue - self._cw.set_cookie(cookies, cookiename) + self._cw.set_cookie(cookiename, cookievalue) # relations edition stuff ################################################## diff -r 15809afe093b -r 39a54b88906d web/views/cwproperties.py --- a/web/views/cwproperties.py Mon Sep 26 18:03:38 2011 +0200 +++ b/web/views/cwproperties.py Mon Sep 26 19:24:08 2011 +0200 @@ -102,8 +102,7 @@ cookiename = self._cookie_name(group) cookie = cookies.get(cookiename) if cookie is None: - cookies[cookiename] = default - self._cw.set_cookie(cookies, cookiename, maxage=None) + self._cw.set_cookie(cookiename, default, maxage=None) status = default else: status = cookie.value diff -r 15809afe093b -r 39a54b88906d web/views/cwsources.py --- a/web/views/cwsources.py Mon Sep 26 18:03:38 2011 +0200 +++ b/web/views/cwsources.py Mon Sep 26 19:24:08 2011 +0200 @@ -263,12 +263,8 @@ def call(self, **kwargs): self.w('

%s

' % self._cw._(self.title)) - eschema = self._cw.vreg.schema.eschema('CWSource') - if eschema.has_perm(self._cw, 'add'): - self.w(u'%s' % ( - self._cw.build_url('add/%s' % eschema), - self._cw._('add a CWSource'))) - self.w(u'
') + self.w(add_etype_button(self._cw, 'CWSource')) + self.w(u'
') self.wview('table', self._cw.execute(self.rql), displaycols=range(4)) diff -r 15809afe093b -r 39a54b88906d web/views/facets.py --- a/web/views/facets.py Mon Sep 26 18:03:38 2011 +0200 +++ b/web/views/facets.py Mon Sep 26 19:24:08 2011 +0200 @@ -206,7 +206,6 @@ class FilterTable(FacetFilterMixIn, AnyRsetView): __regid__ = 'facet.filtertable' __select__ = has_facets() - wdg_stack_size = 8 compact_layout_threshold = 5 def call(self, vid, divid, vidargs, cssclass=''): @@ -235,10 +234,11 @@ w(u'\n') widget_queue = [] queue_height = 0 + wdg_stack_size = max(wdgs, key=lambda wdg:wdg.height()).height() w(u'\n') for wdg in wdgs: height = wdg.height() - if queue_height + height <= self.wdg_stack_size: + if queue_height + height <= wdg_stack_size: widget_queue.append(wdg) queue_height += height continue diff -r 15809afe093b -r 39a54b88906d web/views/sessions.py --- a/web/views/sessions.py Mon Sep 26 18:03:38 2011 +0200 +++ b/web/views/sessions.py Mon Sep 26 19:24:08 2011 +0200 @@ -99,10 +99,10 @@ for forminternal_key in ('__form_id', '__domid', '__errorurl'): args.pop(forminternal_key, None) path = req.relative_path(False) - if path == 'login': + if path in ('login', 'logout') or req.form.get('vid') == 'loggedout': path = 'view' args['__message'] = req._('welcome %s !') % req.user.login - if 'vid' in req.form: + if 'vid' in req.form and req.form['vid'] != 'loggedout': args['vid'] = req.form['vid'] if 'rql' in req.form: args['rql'] = req.form['rql'] diff -r 15809afe093b -r 39a54b88906d web/views/tabs.py --- a/web/views/tabs.py Mon Sep 26 18:03:38 2011 +0200 +++ b/web/views/tabs.py Mon Sep 26 19:24:08 2011 +0200 @@ -93,8 +93,7 @@ activetab = cookies.get(cookiename) if activetab is None: domid = uilib.domid(default) - cookies[cookiename] = domid - self._cw.set_cookie(cookies, cookiename) + self._cw.set_cookie(cookiename, domid) return domid return activetab.value