Back to index

moin  1.9.0~rc2
useragents.py
Go to the documentation of this file.
00001 # -*- coding: iso-8859-1 -*-
00002 """
00003     MoinMoin - User-Agent Statistics
00004 
00005     This macro creates a pie chart of the type of user agents
00006     accessing the wiki.
00007 
00008     TODO: should be refactored after hitcounts.
00009 
00010     @copyright: 2002-2004 Juergen Hermann <jh@web.de>,
00011                 2007 MoinMoin:ThomasWaldmann
00012     @license: GNU GPL, see COPYING for details.
00013 """
00014 
00015 _debug = 0
00016 
00017 from MoinMoin import wikiutil, caching, logfile
00018 from MoinMoin.Page import Page
00019 from MoinMoin.logfile import eventlog
00020 
00021 
00022 def linkto(pagename, request, params=''):
00023     _ = request.getText
00024 
00025     if not request.cfg.chart_options:
00026         return text(pagename, request)
00027     if _debug:
00028         return draw(pagename, request)
00029 
00030     page = Page(request, pagename)
00031 
00032     # Create escaped query string from dict and params
00033     querystr = {'action': 'chart', 'type': 'useragents'}
00034     querystr = wikiutil.makeQueryString(querystr)
00035     querystr = wikiutil.escape(querystr)
00036     if params:
00037         querystr += '&amp;' + params
00038 
00039     data = {'url': page.url(request, querystr)}
00040     data.update(request.cfg.chart_options)
00041     result = ('<img src="%(url)s" width="%(width)d" height="%(height)d"'
00042               ' alt="useragents chart">') % data
00043 
00044     return result
00045 
00046 
00047 def get_data(request):
00048     # get results from cache
00049     cache = caching.CacheEntry(request, 'charts', 'useragents', scope='wiki', use_pickle=True)
00050     cache_date, data = 0, {}
00051     if cache.exists():
00052         try:
00053             cache_date, data = cache.content()
00054         except:
00055             cache.remove() # cache gone bad
00056 
00057     log = eventlog.EventLog(request)
00058     try:
00059         new_date = log.date()
00060     except logfile.LogMissing:
00061         new_date = None
00062 
00063     if new_date is not None:
00064         log.set_filter(['VIEWPAGE', 'SAVEPAGE'])
00065         for event in log.reverse():
00066             if event[0] <= cache_date:
00067                 break
00068             ua = event[2].get('HTTP_USER_AGENT')
00069             if ua:
00070                 try:
00071                     pos = ua.index(" (compatible; ")
00072                     ua = ua[pos:].split(';')[1].strip()
00073                 except ValueError:
00074                     ua = ua.split()[0]
00075                 #ua = ua.replace(';', '\n')
00076                 data[ua] = data.get(ua, 0) + 1
00077 
00078         # write results to cache
00079         cache.update((new_date, data))
00080 
00081     data = [(cnt, ua) for ua, cnt in data.items()]
00082     data.sort()
00083     data.reverse()
00084     return data
00085 
00086 def text(pagename, request):
00087     from MoinMoin.util.dataset import TupleDataset, Column
00088     from MoinMoin.widget.browser import DataBrowserWidget
00089 
00090     _ = request.getText
00091 
00092     data = get_data(request)
00093 
00094     total = 0.0
00095     for cnt, ua in data:
00096         total += cnt
00097 
00098 
00099     agents = TupleDataset()
00100     agents.columns = [Column('agent', label=_("User agent"), align='left'),
00101                       Column('value', label='%', align='right')]
00102 
00103     cnt_printed = 0
00104     data = data[:10]
00105 
00106     if total:
00107         for cnt, ua in data:
00108             try:
00109                 ua = unicode(ua)
00110                 agents.addRow((ua, "%.2f" % (100.0 * cnt / total)))
00111                 cnt_printed += cnt
00112             except UnicodeError:
00113                 pass
00114         if total > cnt_printed:
00115             agents.addRow((_('Others'), "%.2f" % (100 * (total - cnt_printed) / total)))
00116 
00117     table = DataBrowserWidget(request)
00118     table.setData(agents)
00119     return table.render(method="GET")
00120 
00121 def draw(pagename, request):
00122     import shutil, cStringIO
00123     from MoinMoin.stats.chart import Chart, ChartData, Color
00124 
00125     _ = request.getText
00126 
00127     style = Chart.GDC_3DPIE
00128 
00129     # get data
00130     colors = ['red', 'mediumblue', 'yellow', 'deeppink', 'aquamarine', 'purple', 'beige',
00131               'blue', 'forestgreen', 'orange', 'cyan', 'fuchsia', 'lime']
00132     colors = ([Color(c) for c in colors])
00133 
00134     data = get_data(request)
00135 
00136     maxdata = len(colors) - 1
00137     if len(data) > maxdata:
00138         others = [x[0] for x in data[maxdata:]]
00139         data = data[:maxdata] + [(sum(others), _('Others').encode('iso-8859-1', 'replace'))] # gdchart can't do utf-8
00140 
00141     # shift front to end if others is very small
00142     if data[-1][0] * 10 < data[0][0]:
00143         data = data[1:] + data[0:1]
00144 
00145     labels = [x[1] for x in data]
00146     data = [x[0] for x in data]
00147 
00148     # give us a chance to develop this
00149     if _debug:
00150         return "<p>data = %s</p>" % \
00151             '<br>'.join([wikiutil.escape(repr(x)) for x in [labels, data]])
00152 
00153     # create image
00154     image = cStringIO.StringIO()
00155     c = Chart()
00156     c.addData(data)
00157 
00158     title = ''
00159     if request.cfg.sitename: title = "%s: " % request.cfg.sitename
00160     title = title + _('Distribution of User-Agent Types')
00161     c.option(
00162         pie_color=colors,
00163         label_font=Chart.GDC_SMALL,
00164         label_line=1,
00165         label_dist=20,
00166         threed_depth=20,
00167         threed_angle=225,
00168         percent_labels=Chart.GDCPIE_PCT_RIGHT,
00169         title_font=c.GDC_GIANT,
00170         title=title.encode('iso-8859-1', 'replace')) # gdchart can't do utf-8
00171     labels = [label.encode('iso-8859-1', 'replace') for label in labels]
00172     c.draw(style,
00173         (request.cfg.chart_options['width'], request.cfg.chart_options['height']),
00174         image, labels)
00175 
00176     request.content_type = 'image/gif'
00177     request.content_length = len(image.getvalue())
00178 
00179     # copy the image
00180     image.reset()
00181     shutil.copyfileobj(image, request, 8192)
00182