--- a/doc/book/en/devweb/views/startup.rst Fri Sep 30 18:10:28 2011 +0200
+++ b/doc/book/en/devweb/views/startup.rst Tue Oct 04 12:23:52 2011 +0200
@@ -1,15 +1,18 @@
Startup views
-------------
-(:mod:`cubicweb.web.views.startup`)
+Startup views are views requiring no context, from which you usually start
+browsing (for instance the index page). The usual selectors are
+:class:`~cubicweb.selectors.none_rset` or :class:`~cubicweb.selectors.yes`.
-The usual selectors are no_rset or yes. These views don't apply to a
-result set.
+You'll find here a description of startup views provided by the framework.
-*index*
- This view defines the home page of your application. It does not require
- a result set to apply to.
+.. automodule:: cubicweb.web.views.startup
+
+
+Other startup views:
*schema*
A view dedicated to the display of the schema of the instance
+.. XXX to be continued
\ No newline at end of file
--- a/server/repository.py Fri Sep 30 18:10:28 2011 +0200
+++ b/server/repository.py Tue Oct 04 12:23:52 2011 +0200
@@ -1177,8 +1177,7 @@
# delete remaining relations: if user can delete the entity, he can
# delete all its relations without security checking
with security_enabled(session, read=False, write=False):
- eids = [_e.eid for _e in entities]
- in_eids = ','.join((str(eid) for eid in eids))
+ in_eids = ','.join([str(_e.eid) for _e in entities])
for rschema, _, role in entities[0].e_schema.relation_definitions():
rtype = rschema.type
if rtype in schema.VIRTUAL_RTYPES or rtype in pendingrtypes:
@@ -1423,7 +1422,11 @@
source = self.sources_by_uri[sourceuri]
if source.should_call_hooks:
self.hm.call_hooks('before_delete_entity', session, entities=entities)
- self._delete_info_multi(session, entities, sourceuri)
+ if session.deleted_in_transaction(source.eid):
+ # source is being deleted, think to give scleanup argument
+ self._delete_info_multi(session, entities, sourceuri, scleanup=source.eid)
+ else:
+ self._delete_info_multi(session, entities, sourceuri)
source.delete_entities(session, entities)
if source.should_call_hooks:
self.hm.call_hooks('after_delete_entity', session, entities=entities)
--- a/server/sources/pyrorql.py Fri Sep 30 18:10:28 2011 +0200
+++ b/server/sources/pyrorql.py Tue Oct 04 12:23:52 2011 +0200
@@ -445,7 +445,7 @@
def delete_entity(self, session, entity):
"""delete an entity from the source"""
- if session.deleted_in_transaction (self.eid):
+ if session.deleted_in_transaction(self.eid):
# source is being deleted, don't propagate
self._query_cache.clear()
return
@@ -466,7 +466,7 @@
def delete_relation(self, session, subject, rtype, object):
"""delete a relation from the source"""
- if session.deleted_in_transaction (self.eid):
+ if session.deleted_in_transaction(self.eid):
# source is being deleted, don't propagate
self._query_cache.clear()
return
--- a/server/sources/rql2sql.py Fri Sep 30 18:10:28 2011 +0200
+++ b/server/sources/rql2sql.py Tue Oct 04 12:23:52 2011 +0200
@@ -1426,10 +1426,18 @@
return sql
leftvars = cmp.children[0].get_nodes(VariableRef)
assert len(leftvars) == 1
- leftalias = self._var_table(leftvars[0].variable.stinfo['attrvar'])
+ if leftvars[0].variable.stinfo['attrvar'] is None:
+ assert isinstance(leftvars[0].variable, ColumnAlias)
+ leftalias = leftvars[0].variable._q_sqltable
+ else:
+ leftalias = self._var_table(leftvars[0].variable.stinfo['attrvar'])
rightvars = cmp.children[1].get_nodes(VariableRef)
assert len(rightvars) == 1
- rightalias = self._var_table(rightvars[0].variable.stinfo['attrvar'])
+ if rightvars[0].variable.stinfo['attrvar'] is None:
+ assert isinstance(rightvars[0].variable, ColumnAlias)
+ rightalias = rightvars[0].variable._q_sqltable
+ else:
+ rightalias = self._var_table(rightvars[0].variable.stinfo['attrvar'])
if optional == 'right':
self._state.replace_tables_by_outer_join(
leftalias, rightalias, 'LEFT', sql)
--- a/server/sqlutils.py Fri Sep 30 18:10:28 2011 +0200
+++ b/server/sqlutils.py Tue Oct 04 12:23:52 2011 +0200
@@ -338,6 +338,17 @@
return _limit_size(text, maxsize)
cnx.create_function("TEXT_LIMIT_SIZE", 2, limit_size2)
+ from logilab.common.date import strptime
+ def weekday(ustr):
+ try:
+ dt = strptime(ustr, '%Y-%m-%d %H:%M:%S')
+ except:
+ dt = strptime(ustr, '%Y-%m-%d')
+ # expect sunday to be 1, saturday 7 while weekday method return 0 for
+ # monday
+ return (dt.weekday() + 1) % 7
+ cnx.create_function("WEEKDAY", 1, weekday)
+
import yams.constraints
yams.constraints.patch_sqlite_decimal()
--- a/server/test/unittest_querier.py Fri Sep 30 18:10:28 2011 +0200
+++ b/server/test/unittest_querier.py Tue Oct 04 12:23:52 2011 +0200
@@ -443,7 +443,7 @@
self.execute("INSERT Personne X: X nom 'foo', X datenaiss %(d)s",
{'d': datetime(2001, 2,3, 12,13)})
test_data = [('YEAR', 2001), ('MONTH', 2), ('DAY', 3),
- ('HOUR', 12), ('MINUTE', 13)]
+ ('HOUR', 12), ('MINUTE', 13), ('WEEKDAY', 6)]
for funcname, result in test_data:
rset = self.execute('Any %s(D) WHERE X is Personne, X datenaiss D'
% funcname)
--- a/server/test/unittest_rql2sql.py Fri Sep 30 18:10:28 2011 +0200
+++ b/server/test/unittest_rql2sql.py Tue Oct 04 12:23:52 2011 +0200
@@ -1396,6 +1396,11 @@
'''SELECT CAST(EXTRACT(MONTH from _P.cw_creation_date) AS INTEGER)
FROM cw_Personne AS _P''')
+ def test_weekday_extraction(self):
+ self._check("Any WEEKDAY(D) WHERE P is Personne, P creation_date D",
+ '''SELECT (CAST(EXTRACT(DOW from _P.cw_creation_date) AS INTEGER) + 1)
+FROM cw_Personne AS _P''')
+
def test_substring(self):
self._check("Any SUBSTRING(N, 1, 1) WHERE P nom N, P is Personne",
'''SELECT SUBSTR(_P.cw_nom, 1, 1)
@@ -1524,6 +1529,12 @@
FROM (SELECT MAX(_A.cw_ordernum) AS C0
FROM cw_CWAttribute AS _A) AS _T0, cw_CWAttribute AS _A
WHERE _A.cw_ordernum=_T0.C0'''),
+
+ ('Any O1 HAVING O1=O2? WITH O1 BEING (Any MAX(O) WHERE A ordernum O, A is CWAttribute), O2 BEING (Any MAX(O) WHERE A ordernum O, A is CWRelation)',
+ '''SELECT _T0.C0
+FROM (SELECT MAX(_A.cw_ordernum) AS C0
+FROM cw_CWAttribute AS _A) AS _T0 LEFT OUTER JOIN (SELECT MAX(_A.cw_ordernum) AS C0
+FROM cw_CWRelation AS _A) AS _T1 ON (_T0.C0=_T1.C0)'''),
)):
yield t
@@ -1749,11 +1760,16 @@
self._check('Any X WHERE X is CWUser, X creation_date D HAVING YEAR(D) = "2010" OR D = NULL',
'''SELECT _X.cw_eid
FROM cw_CWUser AS _X
-WHERE ((YEAR(_X.cw_creation_date)=2010) OR (_X.cw_creation_date IS NULL))''')
+WHERE ((DATEPART(YEAR, _X.cw_creation_date)=2010) OR (_X.cw_creation_date IS NULL))''')
def test_date_extraction(self):
self._check("Any MONTH(D) WHERE P is Personne, P creation_date D",
- '''SELECT MONTH(_P.cw_creation_date)
+ '''SELECT DATEPART(MONTH, _P.cw_creation_date)
+FROM cw_Personne AS _P''')
+
+ def test_weekday_extraction(self):
+ self._check("Any WEEKDAY(D) WHERE P is Personne, P creation_date D",
+ '''SELECT DATEPART(WEEKDAY, _P.cw_creation_date)
FROM cw_Personne AS _P''')
def test_symmetric(self):
@@ -1893,9 +1909,9 @@
'GROUPBY YEAR(XECT),MONTH(XECT) ORDERBY 1 '
'WHERE X creation_date XSCT, X modification_date XECT, '
'X ordernum XCE, X is CWAttribute',
- '''SELECT ((YEAR(_X.cw_modification_date) * 100) + MONTH(_X.cw_modification_date)), COUNT(_X.cw_eid), SUM(_X.cw_ordernum), AVG((_X.cw_creation_date - _X.cw_modification_date))
+ '''SELECT ((DATEPART(YEAR, _X.cw_modification_date) * 100) + DATEPART(MONTH, _X.cw_modification_date)), COUNT(_X.cw_eid), SUM(_X.cw_ordernum), AVG((_X.cw_creation_date - _X.cw_modification_date))
FROM cw_CWAttribute AS _X
-GROUP BY YEAR(_X.cw_modification_date),MONTH(_X.cw_modification_date)
+GROUP BY DATEPART(YEAR, _X.cw_modification_date),DATEPART(MONTH, _X.cw_modification_date)
ORDER BY 1'''),
@@ -1910,6 +1926,12 @@
'''SELECT MONTH(_P.cw_creation_date)
FROM cw_Personne AS _P''')
+ def test_weekday_extraction(self):
+ # custom impl. in cw.server.sqlutils
+ self._check("Any WEEKDAY(D) WHERE P is Personne, P creation_date D",
+ '''SELECT WEEKDAY(_P.cw_creation_date)
+FROM cw_Personne AS _P''')
+
def test_regexp(self):
self._check("Any X WHERE X login REGEXP '[0-9].*'",
'''SELECT _X.cw_eid
@@ -2068,6 +2090,11 @@
'''SELECT EXTRACT(MONTH from _P.cw_creation_date)
FROM cw_Personne AS _P''')
+ def test_weekday_extraction(self):
+ self._check("Any WEEKDAY(D) WHERE P is Personne, P creation_date D",
+ '''SELECT DAYOFWEEK(_P.cw_creation_date)
+FROM cw_Personne AS _P''')
+
def test_cast(self):
self._check("Any CAST(String, P) WHERE P is Personne",
'''SELECT CAST(_P.cw_eid AS mediumtext)
--- a/web/uicfg.py Fri Sep 30 18:10:28 2011 +0200
+++ b/web/uicfg.py Tue Oct 04 12:23:52 2011 +0200
@@ -30,6 +30,16 @@
* ``schema``
* ``subobject`` (not displayed by default)
+ By default only entities on the ``application`` category are shown.
+
+.. sourcecode:: python
+
+ from cubicweb.web import uicfg
+ # force hiding
+ uicfg.indexview_etype_section['HideMe'] = 'subobject'
+ # force display
+ uicfg.indexview_etype_section['ShowMe'] = 'application'
+
Actions box configuration
`````````````````````````
--- a/web/views/pyviews.py Fri Sep 30 18:10:28 2011 +0200
+++ b/web/views/pyviews.py Tue Oct 04 12:23:52 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -24,18 +24,29 @@
class PyValTableView(View):
- """display a list of list of values into an html table.
+ """display a list of list of values into an HTML table.
Take care, content is NOT xml-escaped.
+
+ If `headers` is specfied, it is expected to be a list of headers to be
+ inserted as first row (in <thead>).
+
+ If `colheaders` is True, the first column will be considered as an headers
+ column an its values will be inserted inside <th> instead of <td>.
+
+ `cssclass` is the CSS class used on the <table> tag, and default to
+ 'listing' (so that the table will look similar to those generated by the
+ table view).
"""
__regid__ = 'pyvaltable'
__select__ = match_kwargs('pyvalue')
- def call(self, pyvalue, headers=None):
+ def call(self, pyvalue, headers=None, colheaders=False,
+ cssclass='listing'):
if headers is None:
headers = self._cw.form.get('headers')
w = self.w
- w(u'<table class="listing">\n')
+ w(u'<table class="%s">\n' % cssclass)
if headers:
w(u'<thead>')
w(u'<tr>')
@@ -46,6 +57,9 @@
w(u'<tbody>')
for row in pyvalue:
w(u'<tr>')
+ if colheaders:
+ w(u'<th>%s</th>' % row[0])
+ row = row[1:]
for cell in row:
w(u'<td>%s</td>' % cell)
w(u'</tr>\n')
--- a/web/views/startup.py Fri Sep 30 18:10:28 2011 +0200
+++ b/web/views/startup.py Tue Oct 04 12:23:52 2011 +0200
@@ -15,8 +15,10 @@
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-"""Set of HTML startup views. A startup view is global, e.g. doesn't apply to a
-result set.
+"""This module contains the default index page and management view.
+
+.. autoclass:: IndexView
+.. autoclass:: ManageView
"""
__docformat__ = "restructuredtext en"
@@ -32,6 +34,19 @@
from cubicweb.web import ajax_replace_url, uicfg, httpcache
class ManageView(StartupView):
+ """:__regid__: *manage*
+
+ The manage view, display some information about what's contained by your
+ site and provides access to administration stuff such as user and groups
+ management.
+
+ Regarding the section displaying link to entity type, notice by default it
+ won't display entity types which are related to another one using a
+ mandatory (cardinality == 1) composite relation.
+
+ You can still configure that behaviour manually using the
+ `indexview_etype_section` as explained in :mod:`cubicweb.web.uicfg`.
+ """
__regid__ = 'manage'
title = _('manage')
http_cache_manager = httpcache.EtagHTTPCacheManager
@@ -149,6 +164,13 @@
class IndexView(ManageView):
+ """:__regid__: *index*
+
+ The default index view, that you'll get when accessing your site's root url.
+ It's by default indentical to the
+ :class:`~cubicweb.web.views.startup.ManageView`, but you'll usually want to
+ customize this one.
+ """
__regid__ = 'index'
title = _('view_index')
--- a/web/views/tableview.py Fri Sep 30 18:10:28 2011 +0200
+++ b/web/views/tableview.py Tue Oct 04 12:23:52 2011 +0200
@@ -372,6 +372,7 @@
def cell_call(self, row, col):
_ = self._cw._
entity = self.cw_rset.get_entity(row, col)
+ entity.complete()
infos = {}
for col in self.columns:
meth = getattr(self, 'build_%s_cell' % col, None)