Commit c03a1d25 authored by Adrien Di Mascio's avatar Adrien Di Mascio
Browse files

autopep8

parent 063a9da8bde5
...@@ -24,4 +24,4 @@ classifiers = [ ...@@ -24,4 +24,4 @@ classifiers = [
'Framework :: CubicWeb', 'Framework :: CubicWeb',
'Programming Language :: Python', 'Programming Language :: Python',
'Programming Language :: JavaScript', 'Programming Language :: JavaScript',
] ]
...@@ -20,7 +20,7 @@ from cubicweb.toolsutils import Command ...@@ -20,7 +20,7 @@ from cubicweb.toolsutils import Command
from cubicweb.cwctl import CWCTL from cubicweb.cwctl import CWCTL
from .utils import SECTIONSPEC, extract_stats_dict, eid_from_url, \ from .utils import SECTIONSPEC, extract_stats_dict, eid_from_url, \
get_or_create_statperiod, compress_old_hits get_or_create_statperiod, compress_old_hits
def url_count_from_stats(cnx, stats_dict): def url_count_from_stats(cnx, stats_dict):
...@@ -50,7 +50,7 @@ def url_count_from_stats(cnx, stats_dict): ...@@ -50,7 +50,7 @@ def url_count_from_stats(cnx, stats_dict):
def parse_input_date(date, periodicity): def parse_input_date(date, periodicity):
input_formats = {'month':'%m/%Y', input_formats = {'month': '%m/%Y',
'day': '%d/%m/%Y', 'day': '%d/%m/%Y',
'hour': '%d/%m/%Y-%Hh'} 'hour': '%d/%m/%Y-%Hh'}
try: try:
...@@ -72,6 +72,7 @@ def track_progress(iterable, nb_ops=None, pb_size=20, pb_title=''): ...@@ -72,6 +72,7 @@ def track_progress(iterable, nb_ops=None, pb_size=20, pb_title=''):
class StatsUpdater(object): class StatsUpdater(object):
def __init__(self, cnx, start, stop): def __init__(self, cnx, start, stop):
self.cnx = cnx self.cnx = cnx
self.config = cnx.vreg.config self.config = cnx.vreg.config
...@@ -90,12 +91,12 @@ class StatsUpdater(object): ...@@ -90,12 +91,12 @@ class StatsUpdater(object):
hit_key = (hit.stats_about[0].eid, hit.period[0].eid, hit.hit_type) hit_key = (hit.stats_about[0].eid, hit.period[0].eid, hit.hit_type)
self.all_hits[hit_key] = hit self.all_hits[hit_key] = hit
## internal utilities ##################################################### # internal utilities #####################################################
def awstats_filepath(self, date): def awstats_filepath(self, date):
config = self.config config = self.config
date_formats = {'month': '%m%Y', date_formats = {'month': '%m%Y',
'day': '%m%Y%d', 'day': '%m%Y%d',
'hour':'%m%Y%d%H'} 'hour': '%m%Y%d%H'}
domain = config['awstats-domain'] domain = config['awstats-domain']
if config['awstats-domain']: if config['awstats-domain']:
domain_ext = '.' + config['awstats-domain'] domain_ext = '.' + config['awstats-domain']
...@@ -114,13 +115,16 @@ class StatsUpdater(object): ...@@ -114,13 +115,16 @@ class StatsUpdater(object):
stop = last_day(start) stop = last_day(start)
elif periodicity == 'day': elif periodicity == 'day':
start = datetime(chosendate.year, chosendate.month, chosendate.day) start = datetime(chosendate.year, chosendate.month, chosendate.day)
stop = datetime(chosendate.year, chosendate.month, chosendate.day, 23, 59, 59) stop = datetime(
chosendate.year, chosendate.month, chosendate.day, 23, 59, 59)
elif periodicity == 'hour': elif periodicity == 'hour':
start = datetime(chosendate.year, chosendate.month, chosendate.day, chosendate.hour) start = datetime(
stop = datetime(chosendate.year, chosendate.month, chosendate.day, chosendate.hour, 59, 59) chosendate.year, chosendate.month, chosendate.day, chosendate.hour)
stop = datetime(
chosendate.year, chosendate.month, chosendate.day, chosendate.hour, 59, 59)
return get_or_create_statperiod(self.cnx, start, stop, stats_report) return get_or_create_statperiod(self.cnx, start, stop, stats_report)
## update API ############################################################# # update API #############################################################
def update_stats(self, skip_compress=False): def update_stats(self, skip_compress=False):
''' parses awstats and creates or updates the corresponding ''' parses awstats and creates or updates the corresponding
data in the cubicweb instance data in the cubicweb instance
...@@ -131,7 +135,7 @@ class StatsUpdater(object): ...@@ -131,7 +135,7 @@ class StatsUpdater(object):
stats_report = dict.fromkeys(('updated', 'created', 'exists no change', stats_report = dict.fromkeys(('updated', 'created', 'exists no change',
'skipped', 'ignored', 'periods', 'compressed'), 0) 'skipped', 'ignored', 'periods', 'compressed'), 0)
for chosendate in track_progress(date_range(self.start, self.stop), for chosendate in track_progress(date_range(self.start, self.stop),
(self.stop-self.start).days, (self.stop - self.start).days,
pb_size=70, pb_title='Import'): pb_size=70, pb_title='Import'):
self._update_stats_for_date(chosendate, stats_report) self._update_stats_for_date(chosendate, stats_report)
if not skip_compress: if not skip_compress:
...@@ -162,9 +166,10 @@ class StatsUpdater(object): ...@@ -162,9 +166,10 @@ class StatsUpdater(object):
return 'ignored' return 'ignored'
try: try:
hit = self.all_hits[(eid, stats_period.eid, hit_type)] hit = self.all_hits[(eid, stats_period.eid, hit_type)]
except KeyError: # no hit yet, create one except KeyError: # no hit yet, create one
status = 'created' status = 'created'
hit = self.cnx.create_entity('Hits', count=total_hits, hit_type=hit_type, hit = self.cnx.create_entity(
'Hits', count=total_hits, hit_type=hit_type,
period=stats_period, stats_about=entity) period=stats_period, stats_about=entity)
# append it to the cache # append it to the cache
self.all_hits[(eid, stats_period.eid, hit_type)] = hit self.all_hits[(eid, stats_period.eid, hit_type)] = hit
...@@ -178,6 +183,7 @@ class StatsUpdater(object): ...@@ -178,6 +183,7 @@ class StatsUpdater(object):
class UpdateWebstatsCommand(Command): class UpdateWebstatsCommand(Command):
""" Update cubicweb web stats from awstats processed files. """ Update cubicweb web stats from awstats processed files.
If startdate is not entered, the update will be done on the previous If startdate is not entered, the update will be done on the previous
...@@ -199,12 +205,12 @@ class UpdateWebstatsCommand(Command): ...@@ -199,12 +205,12 @@ class UpdateWebstatsCommand(Command):
max_args = 3 max_args = 3
options = [ options = [
("skip-compress", {"action": 'store_true', ("skip-compress", {"action": 'store_true',
'help' : u'Skip the compression of old daily hits into month stats'}), 'help': u'Skip the compression of old daily hits into month stats'}),
("today", {"action": 'store_true', ("today", {"action": 'store_true',
'help' : u'Process stats for the current day (for testing)'}), 'help': u'Process stats for the current day (for testing)'}),
] ]
## command / initial setup API ############################################ # command / initial setup API ############################################
def run(self, args): def run(self, args):
# args = (appid, start[, stop]) # args = (appid, start[, stop])
appid = args.pop(0) appid = args.pop(0)
...@@ -217,17 +223,19 @@ class UpdateWebstatsCommand(Command): ...@@ -217,17 +223,19 @@ class UpdateWebstatsCommand(Command):
if self.config.today: if self.config.today:
chosendate = datetime.now() chosendate = datetime.now()
else: else:
chosendate = datetime.now()-timedelta(1) chosendate = datetime.now() - timedelta(1)
start = datetime(chosendate.year, chosendate.month, chosendate.day) start = datetime(
chosendate.year, chosendate.month, chosendate.day)
if len(args) > 1: if len(args) > 1:
stop = parse_input_date(args[1], periodicity) stop = parse_input_date(args[1], periodicity)
if stop is None: if stop is None:
stop = start stop = start
if start is None or stop is None: if start is None or stop is None:
sys.exit(1) # parse_input_date failed to parse date sys.exit(1) # parse_input_date failed to parse date
stop += ONEDAY # date_range() excludes stop boundary stop += ONEDAY # date_range() excludes stop boundary
stats_updater = StatsUpdater(cnx, start, stop) stats_updater = StatsUpdater(cnx, start, stop)
stats_report = stats_updater.update_stats(self.config.skip_compress) stats_report = stats_updater.update_stats(
self.config.skip_compress)
print '''=== Update Report === print '''=== Update Report ===
Number of periods imported : %(periods)s Number of periods imported : %(periods)s
Number of stat objects created : %(created)s Number of stat objects created : %(created)s
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
from cubicweb.entities import AnyEntity from cubicweb.entities import AnyEntity
class StatPeriod(AnyEntity): class StatPeriod(AnyEntity):
__regid__ = 'StatPeriod' __regid__ = 'StatPeriod'
......
...@@ -21,5 +21,4 @@ You could setup site properties or a workflow here for example. ...@@ -21,5 +21,4 @@ You could setup site properties or a workflow here for example.
""" """
# Example of site property change # Example of site property change
#set_property('ui.site-title', "<sitename>") # set_property('ui.site-title', "<sitename>")
...@@ -16,27 +16,32 @@ ...@@ -16,27 +16,32 @@
"""cubicweb-awstats schema""" """cubicweb-awstats schema"""
from yams.buildobjs import (EntityType, String, Int, BigInt, Date, Datetime, Boolean, from yams.buildobjs import (
EntityType, String, Int, BigInt, Date, Datetime, Boolean,
SubjectRelation, RelationDefinition, RelationType) SubjectRelation, RelationDefinition, RelationType)
_ = unicode _ = unicode
MANAGER_PERMISSIONS = { MANAGER_PERMISSIONS = {
'read': ('managers', ), 'read': ('managers', ),
'update': ('managers', 'owners',), 'update': ('managers', 'owners',),
'delete': ('managers', 'owners'), 'delete': ('managers', 'owners'),
'add': ('managers',) 'add': ('managers',)
} }
class StatPeriod(EntityType): class StatPeriod(EntityType):
__permissions__ = MANAGER_PERMISSIONS __permissions__ = MANAGER_PERMISSIONS
# XXX periodicity for hour cannot work with Date, when it is implemented switch to DateTime # XXX periodicity for hour cannot work with Date, when it is implemented
# switch to DateTime
start = Date(indexed=True) start = Date(indexed=True)
stop = Date(indexed=True) stop = Date(indexed=True)
class Hits(EntityType): class Hits(EntityType):
__permissions__ = MANAGER_PERMISSIONS __permissions__ = MANAGER_PERMISSIONS
hit_type = String(maxsize=128, indexed=True) hit_type = String(maxsize=128, indexed=True)
count = Int() #BigInt() count = Int() # BigInt()
class period(RelationType): class period(RelationType):
subject = 'Hits' subject = 'Hits'
...@@ -45,9 +50,7 @@ class period(RelationType): ...@@ -45,9 +50,7 @@ class period(RelationType):
composite = 'object' composite = 'object'
inlined = True inlined = True
class stats_about(RelationType): class stats_about(RelationType):
inlined = True inlined = True
cardinality = '?*' cardinality = '?*'
options = ( options = (
('awstats-dir', ('awstats-dir',
{'type' : 'string', {'type': 'string',
'default': '/var/lib/awstats', 'default': '/var/lib/awstats',
'help': 'directory where the files produced by awstats are stored on the filesystem. ', 'help': 'directory where the files produced by awstats are stored on the filesystem. ',
'group': 'awstats', 'level': 0, 'group': 'awstats', 'level': 0,
}), }),
('awstats-domain', ('awstats-domain',
{'type' : 'string', {'type': 'string',
'default': '', 'default': '',
'help': 'domain of the website (eg. example.org). ', 'help': 'domain of the website (eg. example.org). ',
'group': 'awstats', 'level': 0, 'group': 'awstats', 'level': 0,
}), }),
('awstats-periodicity', ('awstats-periodicity',
{'type' : 'choice', {'type': 'choice',
'choices' : ('hour', 'day', 'month'), 'choices': ('hour', 'day', 'month'),
'default': 'day', 'default': 'day',
'help': 'stats periodicity', 'help': 'stats periodicity',
'group': 'awstats', 'level': 0, 'group': 'awstats', 'level': 0,
......
...@@ -32,9 +32,9 @@ from cubicweb.devtools.fake import FakeRequest ...@@ -32,9 +32,9 @@ from cubicweb.devtools.fake import FakeRequest
from psycopg2 import DataError from psycopg2 import DataError
SECTIONSPEC = { SECTIONSPEC = {
# commented sections are not usefull to view # commented sections are not usefull to view
# 'MAP' : ['section', 'offset'], # 'MAP' : ['section', 'offset'],
# 'GENERAL': ['key', None], # 'GENERAL': ['key', None],
'TIME': ['hour', 'pages', 'hits', 'bandwidth', 'not viewed pages', 'not viewed hits', 'not viewed bandwidth'], 'TIME': ['hour', 'pages', 'hits', 'bandwidth', 'not viewed pages', 'not viewed hits', 'not viewed bandwidth'],
'VISITOR': ['host', 'pages', 'hits', 'bandwidth', 'last visit date', 'start date of last visit', 'last page of last visit'], 'VISITOR': ['host', 'pages', 'hits', 'bandwidth', 'last visit date', 'start date of last visit', 'last page of last visit'],
'DAY': ['date', 'pages', 'hits', 'bandwidth', 'visits'], 'DAY': ['date', 'pages', 'hits', 'bandwidth', 'visits'],
...@@ -94,12 +94,12 @@ SECTIONLABELS = { ...@@ -94,12 +94,12 @@ SECTIONLABELS = {
} }
ORIGIN_LABELS = { ORIGIN_LABELS = {
'From0':'Direct address / Bookmark / Link in email...', 'From0': 'Direct address / Bookmark / Link in email...',
'From1':'Unknown Origin', 'From1': 'Unknown Origin',
'From2':'Links from an Internet Search Engine', 'From2': 'Links from an Internet Search Engine',
'From3':'Links from an external page (other web sites except search engines)', 'From3': 'Links from an external page (other web sites except search engines)',
'From4':'Internal Link', 'From4': 'Internal Link',
} }
def extract_stats_dict(filepath): def extract_stats_dict(filepath):
...@@ -129,13 +129,15 @@ def extract_stats_dict(filepath): ...@@ -129,13 +129,15 @@ def extract_stats_dict(filepath):
section_name, nb_of_lines = line.split('_', 1)[1].split() section_name, nb_of_lines = line.split('_', 1)[1].split()
if section_name in SECTIONSPEC: if section_name in SECTIONSPEC:
stats_dict.setdefault(section_name, {}) stats_dict.setdefault(section_name, {})
parsed_countdown = int(nb_of_lines)-1 if int(nb_of_lines) else 0 parsed_countdown = int(
nb_of_lines) - 1 if int(nb_of_lines) else 0
elif section_name and parsed_countdown: elif section_name and parsed_countdown:
for index, value in enumerate(line.split()): for index, value in enumerate(line.split()):
key = line.split()[0] key = line.split()[0]
stats_dict[section_name].setdefault(key, {}) stats_dict[section_name].setdefault(key, {})
try: try:
stats_dict[section_name][key][SECTIONSPEC[section_name][index]] = value stats_dict[section_name][key][
SECTIONSPEC[section_name][index]] = value
except IndexError: except IndexError:
pass pass
parsed_countdown -= 1 parsed_countdown -= 1
...@@ -161,11 +163,12 @@ def eid_from_url(cnx, value): ...@@ -161,11 +163,12 @@ def eid_from_url(cnx, value):
except (NotFound, DataError, Redirect): except (NotFound, DataError, Redirect):
pass pass
def get_or_create_statperiod(cnx, start, stop, stats_report={}): def get_or_create_statperiod(cnx, start, stop, stats_report={}):
rql = 'Any P WHERE P is StatPeriod, P start "%(start_date)s", P stop "%(end_date)s"' rql = 'Any P WHERE P is StatPeriod, P start "%(start_date)s", P stop "%(end_date)s"'
rset = cnx.execute(rql % rset = cnx.execute(rql %
{'start_date':start, {'start_date': start,
'end_date':stop}) 'end_date': stop})
if rset: if rset:
return rset.get_entity(0, 0) return rset.get_entity(0, 0)
else: else:
...@@ -173,9 +176,11 @@ def get_or_create_statperiod(cnx, start, stop, stats_report={}): ...@@ -173,9 +176,11 @@ def get_or_create_statperiod(cnx, start, stop, stats_report={}):
stats_report['periods'] += 1 stats_report['periods'] += 1
return cnx.create_entity('StatPeriod', start=start, stop=stop) return cnx.create_entity('StatPeriod', start=start, stop=stop)
def time_params(cnx): def time_params(cnx):
params = [] params = []
rset = cnx.execute('Any START ORDERBY START LIMIT 1 WHERE P is StatPeriod, P start START, P stop STOP HAVING STOP-START <= 2') rset = cnx.execute(
'Any START ORDERBY START LIMIT 1 WHERE P is StatPeriod, P start START, P stop STOP HAVING STOP-START <= 2')
for (item,) in rset: for (item,) in rset:
for first_day in date_range(previous_month(item), previous_month(datetime.now(), 5), incmonth=True): for first_day in date_range(previous_month(item), previous_month(datetime.now(), 5), incmonth=True):
delta = 2 delta = 2
...@@ -200,21 +205,23 @@ def compress_old_hits(cnx, update_stats={}, progressbar=True): ...@@ -200,21 +205,23 @@ def compress_old_hits(cnx, update_stats={}, progressbar=True):
results[hit_type] = cnx.execute(rql, results[hit_type] = cnx.execute(rql,
{'start': start, {'start': start,
'stop': stop, 'stop': stop,
'hit_type':hit_type, 'hit_type': hit_type,
'timedelta': delta}) 'timedelta': delta})
if not any(results.values()): if not any(results.values()):
continue continue
# deleting statperiod deletes all associated hits # deleting statperiod deletes all associated hits
drset = cnx.execute('DELETE StatPeriod P WHERE P start >= %(start)s, P stop <= %(stop)s', drset = cnx.execute(
'DELETE StatPeriod P WHERE P start >= %(start)s, P stop <= %(stop)s',
{'start': start, {'start': start,
'stop': stop,}) 'stop': stop, })
update_stats['compressed'] += len(drset) update_stats['compressed'] += len(drset)
stp = get_or_create_statperiod(cnx, start, stop) stp = get_or_create_statperiod(cnx, start, stop)
for hit_type, rset in results.items(): for hit_type, rset in results.items():
for eid, count in rset: for eid, count in rset:
content_entity = cnx.entity_from_eid(eid) content_entity = cnx.entity_from_eid(eid)
# FIXME if Hits for period and content exist, update it ? # FIXME if Hits for period and content exist, update it ?
cnx.create_entity('Hits', hit_type=hit_type, period=stp, count=count, cnx.create_entity(
'Hits', hit_type=hit_type, period=stp, count=count,
stats_about=content_entity) stats_about=content_entity)
if progressbar: if progressbar:
pb.finish() pb.finish()
...@@ -21,6 +21,7 @@ except ImportError: ...@@ -21,6 +21,7 @@ except ImportError:
from cubicweb.web import action from cubicweb.web import action
from cubicweb.predicates import match_user_groups from cubicweb.predicates import match_user_groups
class AwstatsAccessAction(action.Action): class AwstatsAccessAction(action.Action):
__regid__ = 'awstats-action' __regid__ = 'awstats-action'
__select__ = match_user_groups('managers') __select__ = match_user_groups('managers')
...@@ -41,4 +42,3 @@ class WebStatsAccessAction(action.Action): ...@@ -41,4 +42,3 @@ class WebStatsAccessAction(action.Action):
def url(self): def url(self):
return self._cw.build_url('view', vid='webstats') return self._cw.build_url('view', vid='webstats')
...@@ -23,7 +23,9 @@ from cubicweb.view import EntityView ...@@ -23,7 +23,9 @@ from cubicweb.view import EntityView
from cubicweb.web.views import primary, navigation from cubicweb.web.views import primary, navigation
from cubicweb.predicates import is_instance from cubicweb.predicates import is_instance
class StatPeriodPrimaryView(primary.PrimaryView): class StatPeriodPrimaryView(primary.PrimaryView):
""" """
`column_types_aggr` enables you to combine results by type `column_types_aggr` enables you to combine results by type
...@@ -33,7 +35,7 @@ class StatPeriodPrimaryView(primary.PrimaryView): ...@@ -33,7 +35,7 @@ class StatPeriodPrimaryView(primary.PrimaryView):
('Card')) ('Card'))
""" """
__select__ = is_instance('StatPeriod') __select__ = is_instance('StatPeriod')
column_types_aggr = None #tuple of tuples of types column_types_aggr = None # tuple of tuples of types
def cell_call(self, row, col): def cell_call(self, row, col):
_ = self._cw._ _ = self._cw._
...@@ -41,10 +43,13 @@ class StatPeriodPrimaryView(primary.PrimaryView): ...@@ -41,10 +43,13 @@ class StatPeriodPrimaryView(primary.PrimaryView):
self.w(u'<div id="primarystatperiod">') self.w(u'<div id="primarystatperiod">')
entity = self.cw_rset.get_entity(row, col) entity = self.cw_rset.get_entity(row, col)
self.w(u'<h1>%s %s - %s (%s %s)</h1>' % (_('Statistics for period :'), self.w(u'<h1>%s %s - %s (%s %s)</h1>' % (_('Statistics for period :'),
entity.printable_value('start'), entity.printable_value(
entity.printable_value('stop'), 'start'),
(entity.stop - entity.start).days, entity.printable_value(
_('days')) ) 'stop'),
(entity.stop -
entity.start).days,
_('days')))
rset = self._cw.execute('DISTINCT Any C WHERE X is Hits, X hit_type C') rset = self._cw.execute('DISTINCT Any C WHERE X is Hits, X hit_type C')
self.w(u'<a href="%s">%s</a>' % (entity.absolute_url(showall=1), self.w(u'<a href="%s">%s</a>' % (entity.absolute_url(showall=1),
_('show all results'))) _('show all results')))
...@@ -52,28 +57,30 @@ class StatPeriodPrimaryView(primary.PrimaryView): ...@@ -52,28 +57,30 @@ class StatPeriodPrimaryView(primary.PrimaryView):
self.w(u'<h3>%s</h3>' % hit_type) self.w(u'<h3>%s</h3>' % hit_type)
rql = 'Any X, C ORDERBY C DESC %(limit)s WHERE H stats_about X, H hit_type "%(type)s",'\ rql = 'Any X, C ORDERBY C DESC %(limit)s WHERE H stats_about X, H hit_type "%(type)s",'\
'H count C, H period P, P eid %%(e)s' % {'type': hit_type, 'H count C, H period P, P eid %%(e)s' % {'type': hit_type,
'limit': req.form.get('showall') and ' ' or 'LIMIT 20' } 'limit': req.form.get('showall') and ' ' or 'LIMIT 20'}
if self.column_types_aggr: if self.column_types_aggr:
self.w(u'<table><tr>') self.w(u'<table><tr>')
for types in self.column_types_aggr: for types in self.column_types_aggr:
self.w(u'<td>') self.w(u'<td>')
typedrql = rql + ', X is in (%s)' % ','.join(types) typedrql = rql + ', X is in (%s)' % ','.join(types)
rset = self._cw.execute(typedrql, {'e':entity.eid}) rset = self._cw.execute(typedrql, {'e': entity.eid})
self.wview('table', rset, 'null') self.wview('table', rset, 'null')
# cf rql/editextensions.py unset_limit # cf rql/editextensions.py unset_limit
nolimit_rql = typedrql.replace('LIMIT 20', '') nolimit_rql = typedrql.replace('LIMIT 20', '')
self.w(u'<a href="%s">Export CSV</a>' % xml_escape(self._cw.build_url('', rql=nolimit_rql % {'e':entity.eid}, self.w(
vid='csvexport'))) u'<a href="%s">Export CSV</a>' % xml_escape(self._cw.build_url('', rql=nolimit_rql % {'e': entity.eid},
#FIXME TODO not working right now vid='csvexport')))
# FIXME TODO not working right now
self.wview('piechart', rset, 'null') self.wview('piechart', rset, 'null')
self.w(u'</td>') self.w(u'</td>')
self.w(u'</tr></table>') self.w(u'</tr></table>')
else: else:
rset = self._cw.execute(rql, {'e':entity.eid}) rset = self._cw.execute(rql, {'e': entity.eid})
self.wview('table', rset, 'null') self.wview('table', rset, 'null')
nolimit_rql = rql.replace('LIMIT 20', '') nolimit_rql = rql.replace('LIMIT 20', '')
self.w(u'<a href="%s">Export CSV</a>' % xml_escape(self._cw.build_url('', rql=nolimit_rql % {'e':entity.eid}, self.w(
vid='csvexport'))) u'<a href="%s">Export CSV</a>' % xml_escape(self._cw.build_url('', rql=nolimit_rql % {'e': entity.eid},
vid='csvexport')))
self.w(u'</div>') self.w(u'</div>')