Merge branch 'dev'

This commit is contained in:
Grégory Soutadé 2016-04-13 17:29:38 +02:00
commit a7c817b7f5
303 changed files with 911 additions and 261 deletions

View File

@ -1,4 +1,4 @@
v0.3 (13/07/2015)
v0.3 (12/04/2016)
** User **
Add referers_diff display plugin
Add year statistics in month details
@ -15,15 +15,20 @@ v0.3 (13/07/2015)
Add gz files support
Add -z option (don't compress databases)
Add own search enfines files
Do reverse DNS on feeds parsers
Add IPToGeo plugin
** Dev **
Add istats_diff interface
Sort documentation output
Add debug traces in robots plugin
Update awstats data
Remove double slashes at the end of URL
Remove final slashes for referrers
Add alt attribute for all img tag
** Bugs **
Forgot <body> tag
Bad UTC time computation
Hits/pages in the same second where not analyzed
Hits/pages in the same second were not analyzed
Last day of month was skipped

File diff suppressed because one or more lines are too long

View File

@ -10,8 +10,8 @@ display_visitor_ip = True
# Hooks used
pre_analysis_hooks = ['page_to_hit', 'robots']
post_analysis_hooks = ['referers', 'top_pages', 'top_downloads', 'operating_systems', 'browsers', 'feeds', 'hours_stats', 'reverse_dns']
display_hooks = ['track_users', 'top_visitors', 'all_visits', 'referers', 'top_pages', 'top_downloads', 'referers_diff', 'operating_systems', 'browsers', 'feeds', 'hours_stats', 'top_downloads_diff']
post_analysis_hooks = ['referers', 'top_pages', 'top_downloads', 'operating_systems', 'browsers', 'feeds', 'hours_stats', 'reverse_dns', 'ip_to_geo']
display_hooks = ['track_users', 'top_visitors', 'all_visits', 'referers', 'top_pages', 'top_downloads', 'referers_diff', 'ip_to_geo', 'operating_systems', 'browsers', 'feeds', 'hours_stats', 'top_downloads_diff']
# Reverse DNS timeout
reverse_dns_timeout = 0.2

View File

@ -41,7 +41,7 @@ viewed_http_codes = [200, 304]
count_hit_only_visitors = True
# Multimedia extensions (not accounted as downloaded files)
multimedia_files = ['png', 'jpg', 'jpeg', 'gif', 'ico',
multimedia_files = ['png', 'jpg', 'jpeg', 'gif', 'ico', 'svg',
'css', 'js']
# Default resources path (will be symlinked in DISPLAY_OUTPUT)

View File

@ -48,10 +48,18 @@ class DisplayHTMLRaw(object):
def _build(self, f, html):
if html: f.write(html)
def build(self, f):
def build(self, f, filters=None):
if filters: self.filter(filters)
self._buildHTML()
self._build(f, self.html)
def _filter(self, function, **kwargs):
pass
def filter(self, filters):
for (args, function) in filters:
self._filter(function, **args)
def getTitle(self):
return ''
@ -189,6 +197,18 @@ class DisplayHTMLBlockTable(DisplayHTMLBlock):
val = r[column] and int(r[column]) or 0
self.setCellValue(index, column_insertion, '%.1f%%' % (float(val*100)/float(total)))
def _filter(self, function, column, args):
target_col = None
for col in range(0, len(self.cols)):
if self.cols[col] == column:
target_col = col
break
if target_col is None: return
for row in self.rows:
res = function(row[target_col], **args)
if res:
row[target_col] = res
def _buildHTML(self):
style = u''
if self.table_css: style = u' class="%s"' % (self.table_css)
@ -315,11 +335,14 @@ class DisplayHTMLPage(object):
if title == b.getTitle():
return b
return None
def getAllBlocks(self):
return self.blocks
def appendBlock(self, block):
self.blocks.append(block)
def build(self, root, displayVersion=True):
def build(self, root, displayVersion=True, filters=None):
filename = os.path.join(root, self.filename)
base = os.path.dirname(filename)
@ -339,9 +362,9 @@ class DisplayHTMLPage(object):
f.write(u'<title>%s</title>' % (self.title))
f.write(u'</head><body>')
for block in self.blocks:
block.build(f)
block.build(f, filters=filters)
if displayVersion:
f.write(u'<center>Generated by <a href="%s">IWLA %s</a></center>' %
f.write(u'<div style="text-align:center;width:100%%">Generated by <a href="%s">IWLA %s</a></div>' %
("http://indefero.soutade.fr/p/iwla", self.iwla.getVersion()))
f.write(u'</body></html>')
f.close()
@ -349,8 +372,12 @@ class DisplayHTMLPage(object):
class DisplayHTMLBuild(object):
def __init__(self, iwla):
self.pages = []
self.iwla = iwla
self.filters = []
self.clear()
def clear(self):
self.pages = []
def createPage(self, *args):
return DisplayHTMLPage(self.iwla, *args)
@ -364,6 +391,9 @@ class DisplayHTMLBuild(object):
return page
return None
def getAllPages(self):
return self.pages
def addPage(self, page):
self.pages.append(page)
@ -378,7 +408,11 @@ class DisplayHTMLBuild(object):
os.symlink(target, link_name)
for page in self.pages:
page.build(root)
page.build(root, filters=self.filters)
def addColumnFilter(self, column, function, args):
self.filters.append(({'column':column, 'args':args}, function))
#
# Global functions
@ -417,4 +451,3 @@ def createCurTitle(iwla, title):
if domain_name:
title += u' - %s' % (domain_name)
return title

View File

@ -103,12 +103,13 @@ Optional configuration values ends with *.
* plugins/display/browsers.py
* plugins/display/feeds.py
* plugins/display/hours_stats.py
* plugins/display/ip_to_geo.py
* plugins/display/istats_diff.py
* plugins/display/operating_systems.py
* plugins/display/referers.py
* plugins/display/referers_diff.py
* plugins/display/top_downloads.py
* plugins/display/referers.py
* plugins/display/top_downloads_diff.py
* plugins/display/top_downloads.py
* plugins/display/top_hits.py
* plugins/display/top_pages.py
* plugins/display/top_visitors.py
@ -116,6 +117,8 @@ Optional configuration values ends with *.
* plugins/post_analysis/browsers.py
* plugins/post_analysis/feeds.py
* plugins/post_analysis/hours_stats.py
* plugins/post_analysis/ip_to_geo.py
* plugins/post_analysis/iptogeo.py
* plugins/post_analysis/operating_systems.py
* plugins/post_analysis/referers.py
* plugins/post_analysis/reverse_dns.py
@ -323,6 +326,32 @@ plugins.display.hours_stats
None
plugins.display.ip_to_geo
-------------------------
Display hook
Add geo statistics
Plugin requirements :
post_analysis/ip_to_geo
Conf values needed :
create_geo_page*
Output files :
OUTPUT_ROOT/year/month/index.html
Statistics creation :
None
Statistics update :
None
Statistics deletion :
None
plugins.display.istats_diff
---------------------------
@ -375,6 +404,32 @@ plugins.display.operating_systems
None
plugins.display.referers_diff
-----------------------------
Display hook
Enlight new and updated key phrases in in all_key_phrases.html
Plugin requirements :
display/referers
Conf values needed :
None
Output files :
None
Statistics creation :
None
Statistics update :
None
Statistics deletion :
None
plugins.display.referers
------------------------
@ -406,15 +461,15 @@ plugins.display.referers
None
plugins.display.referers_diff
-----------------------------
plugins.display.top_downloads_diff
----------------------------------
Display hook
Enlight new and updated key phrases in in all_key_phrases.html
Enlight new and updated downloads in in top_downloads.html
Plugin requirements :
display/referers
display/top_downloads
Conf values needed :
None
@ -460,32 +515,6 @@ plugins.display.top_downloads
None
plugins.display.top_downloads_diff
----------------------------------
Display hook
Enlight new and updated downloads in in top_downloads.html
Plugin requirements :
display/top_downloads
Conf values needed :
None
Output files :
None
Statistics creation :
None
Statistics update :
None
Statistics deletion :
None
plugins.display.top_hits
------------------------
@ -695,6 +724,41 @@ plugins.post_analysis.hours_stats
None
plugins.post_analysis.ip_to_geo
-------------------------------
Post analysis hook
Get country code from IP address
Plugin requirements :
None
Conf values needed :
iptogeo_remote_addr*
iptogeo_remote_port*
Output files :
None
Statistics creation :
geo =>
country_code => count
None
Statistics update :
valid_visitors:
country_code
Statistics deletion :
None
plugins.post_analysis.iptogeo
-----------------------------
plugins.post_analysis.operating_systems
---------------------------------------

View File

@ -3,12 +3,13 @@
* plugins/display/browsers.py
* plugins/display/feeds.py
* plugins/display/hours_stats.py
* plugins/display/ip_to_geo.py
* plugins/display/istats_diff.py
* plugins/display/operating_systems.py
* plugins/display/referers.py
* plugins/display/referers_diff.py
* plugins/display/top_downloads.py
* plugins/display/referers.py
* plugins/display/top_downloads_diff.py
* plugins/display/top_downloads.py
* plugins/display/top_hits.py
* plugins/display/top_pages.py
* plugins/display/top_visitors.py
@ -16,6 +17,8 @@
* plugins/post_analysis/browsers.py
* plugins/post_analysis/feeds.py
* plugins/post_analysis/hours_stats.py
* plugins/post_analysis/ip_to_geo.py
* plugins/post_analysis/iptogeo.py
* plugins/post_analysis/operating_systems.py
* plugins/post_analysis/referers.py
* plugins/post_analysis/reverse_dns.py
@ -223,6 +226,32 @@ plugins.display.hours_stats
None
plugins.display.ip_to_geo
-------------------------
Display hook
Add geo statistics
Plugin requirements :
post_analysis/ip_to_geo
Conf values needed :
create_geo_page*
Output files :
OUTPUT_ROOT/year/month/index.html
Statistics creation :
None
Statistics update :
None
Statistics deletion :
None
plugins.display.istats_diff
---------------------------
@ -275,6 +304,32 @@ plugins.display.operating_systems
None
plugins.display.referers_diff
-----------------------------
Display hook
Enlight new and updated key phrases in in all_key_phrases.html
Plugin requirements :
display/referers
Conf values needed :
None
Output files :
None
Statistics creation :
None
Statistics update :
None
Statistics deletion :
None
plugins.display.referers
------------------------
@ -306,15 +361,15 @@ plugins.display.referers
None
plugins.display.referers_diff
-----------------------------
plugins.display.top_downloads_diff
----------------------------------
Display hook
Enlight new and updated key phrases in in all_key_phrases.html
Enlight new and updated downloads in in top_downloads.html
Plugin requirements :
display/referers
display/top_downloads
Conf values needed :
None
@ -360,32 +415,6 @@ plugins.display.top_downloads
None
plugins.display.top_downloads_diff
----------------------------------
Display hook
Enlight new and updated downloads in in top_downloads.html
Plugin requirements :
display/top_downloads
Conf values needed :
None
Output files :
None
Statistics creation :
None
Statistics update :
None
Statistics deletion :
None
plugins.display.top_hits
------------------------
@ -595,6 +624,41 @@ plugins.post_analysis.hours_stats
None
plugins.post_analysis.ip_to_geo
-------------------------------
Post analysis hook
Get country code from IP address
Plugin requirements :
None
Conf values needed :
iptogeo_remote_addr*
iptogeo_remote_port*
Output files :
None
Statistics creation :
geo =>
country_code => count
None
Statistics update :
valid_visitors:
country_code
Statistics deletion :
None
plugins.post_analysis.iptogeo
-----------------------------
plugins.post_analysis.operating_systems
---------------------------------------

127
iwla.pot
View File

@ -5,7 +5,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2015-03-02 19:44+CET\n"
"POT-Creation-Date: 2016-04-12 08:34+CEST\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -35,11 +35,11 @@ msgstr ""
msgid "March"
msgstr ""
#: display.py:32 iwla.py:440
#: display.py:32 iwla.py:472
msgid "June"
msgstr ""
#: display.py:32 iwla.py:440
#: display.py:32 iwla.py:472
msgid "May"
msgstr ""
@ -63,143 +63,146 @@ msgstr ""
msgid "September"
msgstr ""
#: display.py:187
#: display.py:195
msgid "Ratio"
msgstr ""
#: iwla.py:381
#: iwla.py:413
msgid "Statistics"
msgstr ""
#: iwla.py:389 iwla.py:442
#: iwla.py:421 iwla.py:474
msgid "Not viewed Bandwidth"
msgstr ""
#: iwla.py:389 iwla.py:442
#: iwla.py:421 iwla.py:474
msgid "Visits"
msgstr ""
#: iwla.py:389 iwla.py:442 plugins/display/all_visits.py:70
#: plugins/display/feeds.py:75 plugins/display/hours_stats.py:73
#: iwla.py:421 iwla.py:474 plugins/display/all_visits.py:70
#: plugins/display/feeds.py:76 plugins/display/hours_stats.py:73
#: plugins/display/hours_stats.py:83 plugins/display/referers.py:95
#: plugins/display/referers.py:153 plugins/display/top_downloads.py:97
#: plugins/display/top_visitors.py:72 plugins/display/track_users.py:113
msgid "Hits"
msgstr ""
#: iwla.py:389 iwla.py:442 plugins/display/all_visits.py:70
#: plugins/display/feeds.py:75 plugins/display/hours_stats.py:73
#: iwla.py:421 iwla.py:474 plugins/display/all_visits.py:70
#: plugins/display/feeds.py:76 plugins/display/hours_stats.py:73
#: plugins/display/hours_stats.py:83 plugins/display/referers.py:95
#: plugins/display/referers.py:153 plugins/display/top_visitors.py:72
#: plugins/display/track_users.py:77 plugins/display/track_users.py:113
msgid "Pages"
msgstr ""
#: iwla.py:389 iwla.py:442 plugins/display/all_visits.py:70
#: iwla.py:421 iwla.py:474 plugins/display/all_visits.py:70
#: plugins/display/hours_stats.py:73 plugins/display/hours_stats.py:83
#: plugins/display/top_visitors.py:72
msgid "Bandwidth"
msgstr ""
#: iwla.py:389 plugins/display/hours_stats.py:71
#: iwla.py:421 plugins/display/hours_stats.py:71
msgid "By day"
msgstr ""
#: iwla.py:389 plugins/display/hours_stats.py:73
#: iwla.py:421 plugins/display/hours_stats.py:73
msgid "Day"
msgstr ""
#: iwla.py:426
#: iwla.py:458
msgid "Average"
msgstr ""
#: iwla.py:431 iwla.py:476
#: iwla.py:463 iwla.py:508
msgid "Total"
msgstr ""
#: iwla.py:440
#: iwla.py:472
msgid "Apr"
msgstr ""
#: iwla.py:440
#: iwla.py:472
msgid "Aug"
msgstr ""
#: iwla.py:440
#: iwla.py:472
msgid "Dec"
msgstr ""
#: iwla.py:440
#: iwla.py:472
msgid "Feb"
msgstr ""
#: iwla.py:440
#: iwla.py:472
msgid "Jan"
msgstr ""
#: iwla.py:440
#: iwla.py:472
msgid "Jul"
msgstr ""
#: iwla.py:440
#: iwla.py:472
msgid "Mar"
msgstr ""
#: iwla.py:440
#: iwla.py:472
msgid "Nov"
msgstr ""
#: iwla.py:440
#: iwla.py:472
msgid "Oct"
msgstr ""
#: iwla.py:440
#: iwla.py:472
msgid "Sep"
msgstr ""
#: iwla.py:441
#: iwla.py:473
msgid "Summary"
msgstr ""
#: iwla.py:442
#: iwla.py:474
msgid "Month"
msgstr ""
#: iwla.py:442
msgid "Visitors"
msgstr ""
#: iwla.py:442 iwla.py:454 plugins/display/feeds.py:98
#: plugins/display/operating_systems.py:90 plugins/display/track_users.py:108
#: iwla.py:474 iwla.py:486 plugins/display/feeds.py:99
#: plugins/display/ip_to_geo.py:109 plugins/display/operating_systems.py:90
#: plugins/display/track_users.py:108
msgid "Details"
msgstr ""
#: iwla.py:490
#: iwla.py:474 plugins/display/ip_to_geo.py:96
#: plugins/display/ip_to_geo.py:114
msgid "Visitors"
msgstr ""
#: iwla.py:522
msgid "Statistics for"
msgstr ""
#: iwla.py:497
#: iwla.py:529
msgid "Last update"
msgstr ""
#: iwla.py:501
#: iwla.py:533
msgid "Time analysis"
msgstr ""
#: iwla.py:503
#: iwla.py:535
msgid "hours"
msgstr ""
#: iwla.py:504
#: iwla.py:536
msgid "minutes"
msgstr ""
#: iwla.py:504
#: iwla.py:536
msgid "seconds"
msgstr ""
#: plugins/display/all_visits.py:70 plugins/display/feeds.py:75
#: plugins/display/top_visitors.py:72
#: plugins/display/all_visits.py:70 plugins/display/feeds.py:76
#: plugins/display/ip_to_geo.py:64 plugins/display/top_visitors.py:72
#: plugins/display/track_users.py:113
msgid "Host"
msgstr ""
@ -242,27 +245,35 @@ msgstr ""
msgid "Others"
msgstr ""
#: plugins/display/browsers.py:105
msgid "Top Browsers"
msgstr ""
#: plugins/display/browsers.py:107
msgid "All Browsers"
msgstr ""
#: plugins/display/feeds.py:69
#: plugins/display/browsers.py:123
msgid "Unknown"
msgstr ""
#: plugins/display/feeds.py:70
msgid "All Feeds parsers"
msgstr ""
#: plugins/display/feeds.py:75
#: plugins/display/feeds.py:76
msgid "All feeds parsers"
msgstr ""
#: plugins/display/feeds.py:91
#: plugins/display/feeds.py:92
msgid "Merged feeds parsers"
msgstr ""
#: plugins/display/feeds.py:96
#: plugins/display/feeds.py:97
msgid "Feeds parsers"
msgstr ""
#: plugins/display/feeds.py:103
#: plugins/display/feeds.py:104
msgid "Found"
msgstr ""
@ -302,6 +313,15 @@ msgstr ""
msgid "Hours"
msgstr ""
#: plugins/display/ip_to_geo.py:96
msgid "Country"
msgstr ""
#: plugins/display/ip_to_geo.py:96 plugins/display/ip_to_geo.py:107
#: plugins/display/ip_to_geo.py:114
msgid "Countries"
msgstr ""
#: plugins/display/operating_systems.py:78
#: plugins/display/operating_systems.py:88
msgid "Operating Systems"
@ -344,10 +364,6 @@ msgstr ""
msgid "All Key Phrases"
msgstr ""
#: plugins/display/referers.py:200
msgid "Key phrases"
msgstr ""
#: plugins/display/referers.py:200 plugins/display/referers.py:216
msgid "Key phrase"
msgstr ""
@ -356,6 +372,10 @@ msgstr ""
msgid "Search"
msgstr ""
#: plugins/display/referers.py:200 plugins/display/referers_diff.py:56
msgid "Key phrases"
msgstr ""
#: plugins/display/referers.py:210
msgid "Top key phrases"
msgstr ""
@ -369,6 +389,7 @@ msgid "Hit"
msgstr ""
#: plugins/display/top_downloads.py:71 plugins/display/top_downloads.py:91
#: plugins/display/top_downloads_diff.py:56
msgid "All Downloads"
msgstr ""
@ -402,7 +423,3 @@ msgstr ""
msgid "Last Access"
msgstr ""
#: plugins/display/track_users.py:113
msgid "IP"
msgstr ""

47
iwla.py
View File

@ -131,7 +131,7 @@ class IWLA(object):
ANALYSIS_CLASS = 'HTTP'
API_VERSION = 1
IWLA_VERSION = '0.2'
IWLA_VERSION = '0.3'
def __init__(self, logLevel):
self.meta_infos = {}
@ -148,6 +148,7 @@ class IWLA(object):
self.log_re = re.compile(self.log_format_extracted)
self.uri_re = re.compile(r'(?P<extract_uri>[^\?#]+)(\?(?P<extract_parameters>[^#]+))?(#.*)?')
self.domain_name_re = re.compile(r'.*%s' % conf.domain_name)
self.final_slashes_re = re.compile(r'/+$')
self.plugins = [(conf.PRE_HOOK_DIRECTORY , conf.pre_analysis_hooks),
(conf.POST_HOOK_DIRECTORY , conf.post_analysis_hooks),
(conf.DISPLAY_HOOK_DIRECTORY , conf.display_hooks)]
@ -187,7 +188,7 @@ class IWLA(object):
def getMonthStats(self):
return self.current_analysis['month_stats']
def getCurrentVisists(self):
def getCurrentVisits(self):
return self.current_analysis['visits']
def getValidVisitors(self):
@ -229,7 +230,7 @@ class IWLA(object):
return self.meta_infos
def _clearDisplay(self):
self.display = DisplayHTMLBuild(self)
self.display.clear()
return self.display
def getDBFilename(self, time):
@ -288,6 +289,13 @@ class IWLA(object):
self.logger.debug("False")
return False
def isValidVisitor(self, hit):
if hit['robot']: return False
if not (conf.count_hit_only_visitors or\
hit['viewed_pages']):
return False
return True
def _appendHit(self, hit):
remote_addr = hit['remote_addr']
@ -334,6 +342,20 @@ class IWLA(object):
super_hit['robot'] = False
super_hit['hit_only'] = 0
def _normalizeURI(self, uri):
if uri == '/': return uri
uri = self.final_slashes_re.sub('/', uri)
return uri
def _removeFinalSlashes(self, uri):
if uri == '/': return uri
return self.final_slashes_re.sub('', uri)
def _normalizeParameters(self, parameters):
# No parameters
if parameters == '?': return None
return parameters
def _decodeHTTPRequest(self, hit):
if not 'request' in hit.keys(): return False
@ -344,9 +366,11 @@ class IWLA(object):
uri_groups = self.uri_re.match(hit['extract_request']['http_uri'])
if uri_groups:
d = uri_groups.groupdict()
hit['extract_request']['extract_uri'] = d['extract_uri']
hit['extract_request']['extract_uri'] = self._normalizeURI(d['extract_uri'])
if 'extract_parameters' in d.keys():
hit['extract_request']['extract_parameters'] = d['extract_parameters']
parameters = self._normalizeParameters(d['extract_parameters'])
if parameters:
hit['extract_request']['extract_parameters'] = parameters
else:
self.logger.warning("Bad request extraction %s" % (hit['request']))
return False
@ -355,6 +379,8 @@ class IWLA(object):
referer_groups = self.uri_re.match(hit['http_referer'])
if referer_groups:
hit['extract_referer'] = referer_groups.groupdict()
hit['extract_referer']['extract_uri'] = self._removeFinalSlashes(hit['extract_referer']['extract_uri'])
hit['extract_referer']['extract_parameters'] = self._normalizeParameters(hit['extract_referer']['extract_parameters'])
return True
def _decodeTime(self, hit):
@ -577,11 +603,8 @@ class IWLA(object):
self.valid_visitors = {}
for (k,v) in visits.items():
if v['robot']: continue
if not (conf.count_hit_only_visitors or\
v['viewed_pages']):
continue
self.valid_visitors[k] = v
if self.isValidVisitor(v):
self.valid_visitors[k] = v
duplicated_stats['nb_visitors'] = stats['nb_visitors'] = len(self.valid_visitors.keys())
@ -619,7 +642,7 @@ class IWLA(object):
for (k, super_hit) in visits.items():
if super_hit['last_access'].tm_mday != cur_time.tm_mday:
continue
viewed_page = False
viewed_pages = False
for hit in super_hit['requests'][::-1]:
if hit['time_decoded'].tm_mday != cur_time.tm_mday:
break
@ -804,7 +827,7 @@ if __name__ == '__main__':
default='INFO', type=str,
help='Loglevel in %s, default : %s' % (['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], 'INFO'))
parser.add_argument('-r', '--reset', dest='reset', action='store_true',
parser.add_argument('-r', '--reset', dest='reset',
default=False,
help='Reset analysis to a specific date (month/year)')

Binary file not shown.

View File

@ -5,8 +5,8 @@
msgid ""
msgstr ""
"Project-Id-Version: iwla\n"
"POT-Creation-Date: 2015-03-02 19:44+CET\n"
"PO-Revision-Date: 2015-03-02 19:45+0100\n"
"POT-Creation-Date: 2016-04-12 08:34+CEST\n"
"PO-Revision-Date: 2016-04-12 08:39+0100\n"
"Last-Translator: Soutadé <soutade@gmail.com>\n"
"Language-Team: iwla\n"
"Language: fr_FR\n"
@ -37,11 +37,13 @@ msgstr "Juillet"
msgid "March"
msgstr "Mars"
#: display.py:32 iwla.py:440
#: display.py:32
#: iwla.py:472
msgid "June"
msgstr "Juin"
#: display.py:32 iwla.py:440
#: display.py:32
#: iwla.py:472
msgid "May"
msgstr "Mai"
@ -65,147 +67,177 @@ msgstr "Octobre"
msgid "September"
msgstr "Septembre"
#: display.py:187
#: display.py:195
msgid "Ratio"
msgstr "Pourcentage"
#: iwla.py:381
#: iwla.py:413
msgid "Statistics"
msgstr "Statistiques"
#: iwla.py:389 iwla.py:442
#: iwla.py:421
#: iwla.py:474
msgid "Not viewed Bandwidth"
msgstr "Traffic non vu"
#: iwla.py:389 iwla.py:442
#: iwla.py:421
#: iwla.py:474
msgid "Visits"
msgstr "Visites"
#: iwla.py:389 iwla.py:442 plugins/display/all_visits.py:70
#: plugins/display/feeds.py:75 plugins/display/hours_stats.py:73
#: plugins/display/hours_stats.py:83 plugins/display/referers.py:95
#: plugins/display/referers.py:153 plugins/display/top_downloads.py:97
#: plugins/display/top_visitors.py:72 plugins/display/track_users.py:113
#: iwla.py:421
#: iwla.py:474
#: plugins/display/all_visits.py:70
#: plugins/display/feeds.py:76
#: plugins/display/hours_stats.py:73
#: plugins/display/hours_stats.py:83
#: plugins/display/referers.py:95
#: plugins/display/referers.py:153
#: plugins/display/top_downloads.py:97
#: plugins/display/top_visitors.py:72
#: plugins/display/track_users.py:113
msgid "Hits"
msgstr "Hits"
#: iwla.py:389 iwla.py:442 plugins/display/all_visits.py:70
#: plugins/display/feeds.py:75 plugins/display/hours_stats.py:73
#: plugins/display/hours_stats.py:83 plugins/display/referers.py:95
#: plugins/display/referers.py:153 plugins/display/top_visitors.py:72
#: plugins/display/track_users.py:77 plugins/display/track_users.py:113
#: iwla.py:421
#: iwla.py:474
#: plugins/display/all_visits.py:70
#: plugins/display/feeds.py:76
#: plugins/display/hours_stats.py:73
#: plugins/display/hours_stats.py:83
#: plugins/display/referers.py:95
#: plugins/display/referers.py:153
#: plugins/display/top_visitors.py:72
#: plugins/display/track_users.py:77
#: plugins/display/track_users.py:113
msgid "Pages"
msgstr "Pages"
#: iwla.py:389 iwla.py:442 plugins/display/all_visits.py:70
#: plugins/display/hours_stats.py:73 plugins/display/hours_stats.py:83
#: iwla.py:421
#: iwla.py:474
#: plugins/display/all_visits.py:70
#: plugins/display/hours_stats.py:73
#: plugins/display/hours_stats.py:83
#: plugins/display/top_visitors.py:72
msgid "Bandwidth"
msgstr "Bande passante"
#: iwla.py:389 plugins/display/hours_stats.py:71
#: iwla.py:421
#: plugins/display/hours_stats.py:71
msgid "By day"
msgstr "Par jour"
#: iwla.py:389 plugins/display/hours_stats.py:73
#: iwla.py:421
#: plugins/display/hours_stats.py:73
msgid "Day"
msgstr "Jour"
#: iwla.py:426
#: iwla.py:458
msgid "Average"
msgstr "Moyenne"
#: iwla.py:431 iwla.py:476
#: iwla.py:463
#: iwla.py:508
msgid "Total"
msgstr "Total"
#: iwla.py:440
#: iwla.py:472
msgid "Apr"
msgstr "Avr"
#: iwla.py:440
#: iwla.py:472
msgid "Aug"
msgstr "Août"
#: iwla.py:440
#: iwla.py:472
msgid "Dec"
msgstr "Déc"
#: iwla.py:440
#: iwla.py:472
msgid "Feb"
msgstr "Fév"
#: iwla.py:440
#: iwla.py:472
msgid "Jan"
msgstr "Jan"
#: iwla.py:440
#: iwla.py:472
msgid "Jul"
msgstr "Jui"
#: iwla.py:440
#: iwla.py:472
msgid "Mar"
msgstr "Mars"
#: iwla.py:440
#: iwla.py:472
msgid "Nov"
msgstr "Nov"
#: iwla.py:440
#: iwla.py:472
msgid "Oct"
msgstr "Oct"
#: iwla.py:440
#: iwla.py:472
msgid "Sep"
msgstr "Sep"
#: iwla.py:441
#: iwla.py:473
msgid "Summary"
msgstr "Résumé"
#: iwla.py:442
#: iwla.py:474
msgid "Month"
msgstr "Mois"
#: iwla.py:442
msgid "Visitors"
msgstr "Visiteurs"
#: iwla.py:442 iwla.py:454 plugins/display/feeds.py:98
#: plugins/display/operating_systems.py:90 plugins/display/track_users.py:108
#: iwla.py:474
#: iwla.py:486
#: plugins/display/feeds.py:99
#: plugins/display/ip_to_geo.py:109
#: plugins/display/operating_systems.py:90
#: plugins/display/track_users.py:108
msgid "Details"
msgstr "Détails"
#: iwla.py:490
#: iwla.py:474
#: plugins/display/ip_to_geo.py:96
#: plugins/display/ip_to_geo.py:114
msgid "Visitors"
msgstr "Visiteurs"
#: iwla.py:522
msgid "Statistics for"
msgstr "Statistiques pour"
#: iwla.py:497
#: iwla.py:529
msgid "Last update"
msgstr "Dernière mise à jour"
#: iwla.py:501
#: iwla.py:533
msgid "Time analysis"
msgstr "Durée de l'analyse"
#: iwla.py:503
#: iwla.py:535
msgid "hours"
msgstr "heures "
#: iwla.py:504
#: iwla.py:536
msgid "minutes"
msgstr "minutes"
#: iwla.py:504
#: iwla.py:536
msgid "seconds"
msgstr "secondes"
#: plugins/display/all_visits.py:70 plugins/display/feeds.py:75
#: plugins/display/all_visits.py:70
#: plugins/display/feeds.py:76
#: plugins/display/ip_to_geo.py:64
#: plugins/display/top_visitors.py:72
#: plugins/display/track_users.py:113
msgid "Host"
msgstr "Hôte"
#: plugins/display/all_visits.py:70 plugins/display/top_visitors.py:72
#: plugins/display/all_visits.py:70
#: plugins/display/top_visitors.py:72
msgid "Last seen"
msgstr "Dernière visite"
@ -213,7 +245,8 @@ msgstr "Dernière visite"
msgid "All visits"
msgstr "Toutes les visites"
#: plugins/display/all_visits.py:93 plugins/display/top_visitors.py:72
#: plugins/display/all_visits.py:93
#: plugins/display/top_visitors.py:72
msgid "Top visitors"
msgstr "Top visiteurs"
@ -221,50 +254,70 @@ msgstr "Top visiteurs"
msgid "Browsers"
msgstr "Navigateurs"
#: plugins/display/browsers.py:79 plugins/display/browsers.py:113
#: plugins/display/browsers.py:79
#: plugins/display/browsers.py:113
msgid "Browser"
msgstr "Navigateur"
#: plugins/display/browsers.py:79 plugins/display/browsers.py:113
#: plugins/display/browsers.py:79
#: plugins/display/browsers.py:113
#: plugins/display/operating_systems.py:78
#: plugins/display/operating_systems.py:95 plugins/display/top_hits.py:71
#: plugins/display/top_hits.py:97 plugins/display/top_pages.py:71
#: plugins/display/operating_systems.py:95
#: plugins/display/top_hits.py:71
#: plugins/display/top_hits.py:97
#: plugins/display/top_pages.py:71
#: plugins/display/top_pages.py:96
msgid "Entrance"
msgstr "Entrées"
#: plugins/display/browsers.py:98 plugins/display/browsers.py:128
#: plugins/display/referers.py:110 plugins/display/referers.py:125
#: plugins/display/referers.py:140 plugins/display/referers.py:163
#: plugins/display/referers.py:174 plugins/display/referers.py:185
#: plugins/display/referers.py:222 plugins/display/top_downloads.py:83
#: plugins/display/top_downloads.py:103 plugins/display/top_hits.py:82
#: plugins/display/top_hits.py:103 plugins/display/top_pages.py:82
#: plugins/display/top_pages.py:102 plugins/display/top_visitors.py:92
#: plugins/display/browsers.py:98
#: plugins/display/browsers.py:128
#: plugins/display/referers.py:110
#: plugins/display/referers.py:125
#: plugins/display/referers.py:140
#: plugins/display/referers.py:163
#: plugins/display/referers.py:174
#: plugins/display/referers.py:185
#: plugins/display/referers.py:222
#: plugins/display/top_downloads.py:83
#: plugins/display/top_downloads.py:103
#: plugins/display/top_hits.py:82
#: plugins/display/top_hits.py:103
#: plugins/display/top_pages.py:82
#: plugins/display/top_pages.py:102
#: plugins/display/top_visitors.py:92
msgid "Others"
msgstr "Autres"
#: plugins/display/browsers.py:105
msgid "Top Browsers"
msgstr "Top Navigateurs"
#: plugins/display/browsers.py:107
msgid "All Browsers"
msgstr "Tous les navigateurs"
#: plugins/display/feeds.py:69
#: plugins/display/browsers.py:123
msgid "Unknown"
msgstr "Inconnu"
#: plugins/display/feeds.py:70
msgid "All Feeds parsers"
msgstr "Tous les agrégateurs"
#: plugins/display/feeds.py:75
#: plugins/display/feeds.py:76
msgid "All feeds parsers"
msgstr "Tous les agrégateurs"
#: plugins/display/feeds.py:91
#: plugins/display/feeds.py:92
msgid "Merged feeds parsers"
msgstr "Agrégateurs fusionnés"
#: plugins/display/feeds.py:96
#: plugins/display/feeds.py:97
msgid "Feeds parsers"
msgstr "Agrégateurs"
#: plugins/display/feeds.py:103
#: plugins/display/feeds.py:104
msgid "Found"
msgstr "Trouvé"
@ -304,6 +357,16 @@ msgstr "Par heures"
msgid "Hours"
msgstr "Heures"
#: plugins/display/ip_to_geo.py:96
msgid "Country"
msgstr "Pays"
#: plugins/display/ip_to_geo.py:96
#: plugins/display/ip_to_geo.py:107
#: plugins/display/ip_to_geo.py:114
msgid "Countries"
msgstr "Pays"
#: plugins/display/operating_systems.py:78
#: plugins/display/operating_systems.py:88
msgid "Operating Systems"
@ -318,19 +381,23 @@ msgstr "Système d'exploitation"
msgid "Connexion from"
msgstr "Connexion depuis"
#: plugins/display/referers.py:95 plugins/display/referers.py:153
#: plugins/display/referers.py:95
#: plugins/display/referers.py:153
msgid "Origin"
msgstr "Origine"
#: plugins/display/referers.py:99 plugins/display/referers.py:156
#: plugins/display/referers.py:99
#: plugins/display/referers.py:156
msgid "Search Engine"
msgstr "Moteur de recherche"
#: plugins/display/referers.py:114 plugins/display/referers.py:167
#: plugins/display/referers.py:114
#: plugins/display/referers.py:167
msgid "External URL"
msgstr "URL externe"
#: plugins/display/referers.py:129 plugins/display/referers.py:178
#: plugins/display/referers.py:129
#: plugins/display/referers.py:178
msgid "External URL (robot)"
msgstr "URL externe (robot)"
@ -347,17 +414,20 @@ msgid "All Key Phrases"
msgstr "Toutes les phrases clé"
#: plugins/display/referers.py:200
msgid "Key phrases"
msgstr "Phrases clé"
#: plugins/display/referers.py:200 plugins/display/referers.py:216
#: plugins/display/referers.py:216
msgid "Key phrase"
msgstr "Phrase clé"
#: plugins/display/referers.py:200 plugins/display/referers.py:216
#: plugins/display/referers.py:200
#: plugins/display/referers.py:216
msgid "Search"
msgstr "Recherche"
#: plugins/display/referers.py:200
#: plugins/display/referers_diff.py:56
msgid "Key phrases"
msgstr "Phrases clé"
#: plugins/display/referers.py:210
msgid "Top key phrases"
msgstr "Top phrases clé"
@ -370,13 +440,18 @@ msgstr "Toutes les phrases clé"
msgid "Hit"
msgstr "Hit"
#: plugins/display/top_downloads.py:71 plugins/display/top_downloads.py:91
#: plugins/display/top_downloads.py:71
#: plugins/display/top_downloads.py:91
#: plugins/display/top_downloads_diff.py:56
msgid "All Downloads"
msgstr "Tous les téléchargements"
#: plugins/display/top_downloads.py:71 plugins/display/top_downloads.py:97
#: plugins/display/top_hits.py:71 plugins/display/top_hits.py:97
#: plugins/display/top_pages.py:71 plugins/display/top_pages.py:96
#: plugins/display/top_downloads.py:71
#: plugins/display/top_downloads.py:97
#: plugins/display/top_hits.py:71
#: plugins/display/top_hits.py:97
#: plugins/display/top_pages.py:71
#: plugins/display/top_pages.py:96
msgid "URI"
msgstr "URI"
@ -384,11 +459,13 @@ msgstr "URI"
msgid "Top Downloads"
msgstr "Top Téléchargements"
#: plugins/display/top_hits.py:71 plugins/display/top_hits.py:91
#: plugins/display/top_hits.py:71
#: plugins/display/top_hits.py:91
msgid "All Hits"
msgstr "Tous les hits"
#: plugins/display/top_pages.py:71 plugins/display/top_pages.py:90
#: plugins/display/top_pages.py:71
#: plugins/display/top_pages.py:90
msgid "All Pages"
msgstr "Toutes les pages"
@ -396,17 +473,18 @@ msgstr "Toutes les pages"
msgid "Top Pages"
msgstr "Top Pages"
#: plugins/display/track_users.py:77 plugins/display/track_users.py:106
#: plugins/display/track_users.py:77
#: plugins/display/track_users.py:106
msgid "Tracked users"
msgstr "Utilisateurs traqués"
#: plugins/display/track_users.py:77 plugins/display/track_users.py:113
#: plugins/display/track_users.py:77
#: plugins/display/track_users.py:113
msgid "Last Access"
msgstr "Dernière visite"
#: plugins/display/track_users.py:113
msgid "IP"
msgstr "IP"
#~ msgid "IP"
#~ msgstr "IP"
#~ msgid "Page"
#~ msgstr "Page"

View File

@ -83,11 +83,12 @@ class IWLADisplayBrowsers(IPlugin):
for (browser, entrance) in new_list:
if browser != 'unknown':
try:
icon = '<img src="/%s/browser/%s.png"/>' % (self.icon_path, awstats_data.browsers_icons[self.icon_names[browser]])
name = awstats_data.browsers_icons[self.icon_names[browser]]
icon = '<img alt="%s icon" src="/%s/browser/%s.png"/>' % (name, self.icon_path, name)
except:
icon = '<img src="/%s/browser/unknown.png"/>' % (self.icon_path)
icon = '<img alt="Unknown browser icon" src="/%s/browser/unknown.png"/>' % (self.icon_path)
else:
icon = '<img src="/%s/browser/unknown.png"/>' % (self.icon_path)
icon = '<img alt="Unknown browser icon" src="/%s/browser/unknown.png"/>' % (self.icon_path)
browser = 'Unknown'
table.appendRow([icon, browser, entrance])
total_browsers[2] += entrance
@ -115,11 +116,12 @@ class IWLADisplayBrowsers(IPlugin):
for (browser, entrance) in browsers[:10]:
if browser != 'unknown':
try:
icon = '<img src="/%s/browser/%s.png"/>' % (self.icon_path, awstats_data.browsers_icons[self.icon_names[browser]])
name = awstats_data.browsers_icons[self.icon_names[browser]]
icon = '<img alt="%s icon" src="/%s/browser/%s.png"/>' % (name, self.icon_path, name)
except:
icon = '<img src="/%s/browser/unknown.png"/>' % (self.icon_path)
icon = '<img alt="Unknown browser icon" src="/%s/browser/unknown.png"/>' % (self.icon_path)
else:
icon = '<img src="/%s/browser/unknown.png"/>' % (self.icon_path)
icon = '<img alt="Unknown browser icon" src="/%s/browser/unknown.png"/>' % (self.icon_path)
browser = self.iwla._(u'Unknown')
table.appendRow([icon, browser, entrance])
total_browsers[2] -= entrance

View File

@ -62,7 +62,7 @@ class IWLADisplayFeeds(IPlugin):
from plugins.post_analysis.feeds import IWLAPostAnalysisFeeds
display = self.iwla.getDisplay()
hits = self.iwla.getCurrentVisists()
hits = self.iwla.getCurrentVisits()
nb_feeds_parsers = 0
# All in a page

View File

@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
#
# Copyright Grégory Soutadé 2016
# This file is part of iwla
# iwla is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# iwla is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with iwla. If not, see <http://www.gnu.org/licenses/>.
#
import re
from iwla import IWLA
from iplugin import IPlugin
from display import *
import awstats_data
"""
Display hook
Add geo statistics
Plugin requirements :
post_analysis/ip_to_geo
Conf values needed :
create_geo_page*
Output files :
OUTPUT_ROOT/year/month/index.html
Statistics creation :
None
Statistics update :
None
Statistics deletion :
None
"""
class IWLADisplayTopGeo(IPlugin):
def __init__(self, iwla):
super(IWLADisplayTopGeo, self).__init__(iwla)
self.API_VERSION = 1
#self.requires = ['IWLAPostAnalysisIPToGeo']
def load(self):
self.icon_path = self.iwla.getConfValue('icon_path', '/')
self.create_geo_page = self.iwla.getConfValue('create_geo_page_page', True)
display = self.iwla.getDisplay()
display.addColumnFilter(self.iwla._(u'Host'), self.FlagFilter, {'self':self})
return True
@staticmethod # Needed to have unbound method
def FlagFilter(host, self):
cc = None
host_name = host.split(' ')[0] # hostname or ip
if host_name in self.valid_visitors.keys():
cc = self.valid_visitors[host_name].get('country_code', None)
else:
for visitor in self.valid_visitors.values():
if visitor['remote_addr'] == host_name:
cc = visitor.get('country_code', None)
break
if not cc or cc == 'ip': return None
icon = '<img alt="%s flag" src="/%s/flags/%s.png"/>' % (cc, self.icon_path, cc)
return '%s %s' % (icon ,host)
def hook(self):
display = self.iwla.getDisplay()
geo = self.iwla.getMonthStats()['geo']
geo = sorted(geo.items(), key=lambda t: t[1], reverse=True)
self.valid_visitors = self.iwla.getValidVisitors()
# All in a page
if self.create_geo_page:
title = createCurTitle(self.iwla, u'All Coutries')
filename = 'geo.html'
path = self.iwla.getCurDisplayPath(filename)
page = display.createPage(title, path, self.iwla.getConfValue('css_path', []))
table = display.createBlock(DisplayHTMLBlockTable, self.iwla._(u'Countries'), ['', self.iwla._(u'Country'), self.iwla._(u'Visitors')])
table.setColsCSSClass(['', '', 'iwla_hit'])
for (cc, visitors) in geo:
icon = '<img alt="%s flag" src="/%s/flags/%s.png"/>' % (cc, self.icon_path, cc)
table.appendRow([icon, cc, visitors])
table.computeRatio(2)
page.appendBlock(table)
display.addPage(page)
# Countries in index
title = self.iwla._(u'Countries')
if self.create_geo_page:
link = '<a href=\'%s\'>%s</a>' % (filename, self.iwla._(u'Details'))
title = '%s - %s' % (title, link)
index = self.iwla.getDisplayIndex()
table = display.createBlock(DisplayHTMLBlockTable, title, ['', self.iwla._(u'Countries'), self.iwla._(u'Visitors')])
table.setColsCSSClass(['', '', 'iwla_hit'])
for (cc, visitors) in geo[:10]:
icon = '<img alt="%s flag" src="/%s/flags/%s.png"/>' % (cc, self.icon_path, cc)
table.appendRow([icon, cc, visitors])
table.computeRatio(2)
index.appendBlock(table)

View File

@ -78,7 +78,7 @@ class IWLADisplayTopOperatingSystems(IPlugin):
table = display.createBlock(DisplayHTMLBlockTable, self.iwla._(u'Operating Systems'), ['', self.iwla._(u'Operating System'), self.iwla._(u'Entrance')])
table.setColsCSSClass(['', '', 'iwla_hit'])
for (os_name, entrance) in operating_systems:
icon = '<img src="/%s/os/%s.png"/>' % (self.icon_path, os_name)
icon = '<img alt="%s icon" src="/%s/os/%s.png"/>' % (os_name, self.icon_path, os_name)
table.appendRow([icon, os_name, entrance])
page.appendBlock(table)
@ -95,7 +95,7 @@ class IWLADisplayTopOperatingSystems(IPlugin):
table = display.createBlock(DisplayHTMLBlockTable, title, ['', self.iwla._(u'Operating System'), self.iwla._(u'Entrance')])
table.setColsCSSClass(['', '', 'iwla_hit'])
for (family, entrance) in os_families:
icon = '<img src="/%s/os/%s.png"/>' % (self.icon_path, self.icon_names[family])
icon = '<img alt="%s icon" src="/%s/os/%s.png"/>' % (self.icon_names[family], self.icon_path, self.icon_names[family])
table.appendRow([icon, family, entrance])
table.computeRatio(2)
index.appendBlock(table)

View File

@ -64,7 +64,7 @@ class IWLADisplayTrackUsers(IPlugin):
def hook(self):
display = self.iwla.getDisplay()
hits = self.iwla.getCurrentVisists()
hits = self.iwla.getCurrentVisits()
stats = {}
# All in a page
@ -110,7 +110,7 @@ class IWLADisplayTrackUsers(IPlugin):
index = self.iwla.getDisplayIndex()
table = display.createBlock(DisplayHTMLBlockTable, title, [self.iwla._(u'IP'), self.iwla._(u'Last Access'), self.iwla._(u'Pages'), self.iwla._(u'Hits')])
table = display.createBlock(DisplayHTMLBlockTable, title, [self.iwla._(u'Host'), self.iwla._(u'Last Access'), self.iwla._(u'Pages'), self.iwla._(u'Hits')])
table.setColsCSSClass(['', '', 'iwla_page', 'iwla_hit'])
for ip in self.tracked_ip:
if not ip in hits.keys(): continue

View File

@ -85,7 +85,7 @@ class IWLAPostAnalysisFeeds(IPlugin):
hit['feed_parser'] = isFeedParser
def hook(self):
hits = self.iwla.getCurrentVisists()
hits = self.iwla.getCurrentVisits()
one_hit_only = {}
for hit in hits.values():
isFeedParser = hit.get('feed_parser', None)

View File

@ -62,7 +62,7 @@ class IWLAPostAnalysisHoursStats(IPlugin):
self.API_VERSION = 1
def hook(self):
stats = self.iwla.getCurrentVisists()
stats = self.iwla.getCurrentVisits()
month_stats = self.iwla.getMonthStats()
hours_stats = month_stats.get('hours_stats', {})

View File

@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
#
# Copyright Grégory Soutadé 2016
# This file is part of iwla
# iwla is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# iwla is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with iwla. If not, see <http://www.gnu.org/licenses/>.
#
from iwla import IWLA
from iplugin import IPlugin
from iptogeo import IPToGeo
"""
Post analysis hook
Get country code from IP address
Plugin requirements :
None
Conf values needed :
iptogeo_remote_addr*
iptogeo_remote_port*
Output files :
None
Statistics creation :
geo =>
country_code => count
None
Statistics update :
valid_visitors:
country_code
Statistics deletion :
None
"""
class IWLAPostAnalysisIPToGeo(IPlugin):
def __init__(self, iwla):
super(IWLAPostAnalysisIPToGeo, self).__init__(iwla)
self.API_VERSION = 1
def load(self):
remote_addr = self.iwla.getConfValue('iptogeo_remote_addr',
None)
remote_port = self.iwla.getConfValue('iptogeo_remote_port',
None)
args = {}
if remote_addr: args['remote_addr'] = remote_addr
if remote_port: args['remote_port'] = remote_port
self.iptogeo = IPToGeo(**args)
return True
def hook(self):
visitors = self.iwla.getValidVisitors()
month_stats = self.iwla.getMonthStats()
geo = month_stats.get('geo', {})
for (ip, visitor) in visitors.items():
if visitor.get('country_code', False): continue
try:
(_, cc) = self.iptogeo.ip_to_geo(ip)
cc = cc and cc or 'ip'
visitor['country_code'] = cc
if cc in geo.keys():
geo[cc] += 1
else:
geo[cc] = 1
except Exception, e:
print e
month_stats['geo'] = geo

View File

@ -0,0 +1,143 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2016 Grégory Soutadé
#
# This file is part of iptogeo.
#
# iptogeo is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# iptogeo is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with iptogeo. If not, see <http://www.gnu.org/licenses/>.
#
import socket
import struct
class IPToGeoException(Exception):
pass
class IPToGeo(object):
MAGIC = 0x179E08EF
VERSION = 1
REQ = 1
RESP = 0
IPV4 = 4
IPV6 = 16
IP_NOT_FOUND = 6
PACKET_SIZE = 32
ERRORS = {1 : 'Bad magic',
2 : 'Bad version',
3 : 'Bad request field' ,
4 : 'Bad IP version',
5 : 'Unsupported IP version',
6 : 'IP not found'}
def __init__(self, remote_addr='127.0.0.1', remote_port=53333, timeout=None, family=socket.AF_INET):
self._remote_addr = remote_addr
self._remote_port = remote_port
self._timeout = timeout
self._family = family
self._create_socket()
def _create_socket(self):
self._socket = socket.socket(self._family, socket.SOCK_STREAM)
if not self._timeout is None:
self._socket.settimeout(self._timeout)
self._socket.connect((self._remote_addr, self._remote_port))
def _extend_ipv6(self, ipv6):
tmp = ''
for s in ipv6.split(':'):
if not s: break
while len(s) != 4:
s = '0' + s
tmp += s
while len(tmp) < 16*2:
tmp += '0'
res = ''
for i in range(0, 15*2, 2):
res += tmp[i] + tmp[i+1] + ':'
res += tmp[30] + tmp[31]
return res
def _create_request(self, ip, ip_type):
packet = ''
packet += struct.pack('<IBBBBI', IPToGeo.MAGIC, IPToGeo.VERSION, IPToGeo.REQ,
0, #err
ip_type, # ip type
0) # flags
for i in ip:
packet += struct.pack('<B', i) # ipv4
packet += struct.pack('<III', 0, 0, 0) # ipv6
packet += struct.pack('<I', 0) # country code
return packet
def _check_request(self, packet):
(magic, version, req, err, ip_type, flags, ipv4, ipv6b, ipv6c, ipv6d) = struct.unpack_from('<IBBBBIIIII', packet, 0)
if magic != IPToGeo.MAGIC:
raise IPToGeoException('Invalid magic %08x' % (magic))
ip_res = '%08x' % (ipv4)
if ip_type == IPToGeo.IPV6:
ip_res += '%08x' % (ipv6b)
ip_res += '%08x' % (ipv6c)
ip_res += '%08x' % (ipv6d)
if err == IPToGeo.IP_NOT_FOUND: return (ip_res, None) # IP not found
if err != 0:
raise IPToGeoException(IPToGeo.ERRORS[err])
(cc0, cc1, cc2, cc3) = struct.unpack_from('BBBB', packet, 7*4)
return (ip_res, '%c%c%c%c' % (cc0, cc1, cc2, cc3))
def ip_to_geo(self, ip):
ip_type = IPToGeo.IPV4
if ip.find('.') >= 0:
splitted_ip = [int(a) for a in ip.split('.')]
if len(splitted_ip) != 4:
raise Exception('Bad IP %s' % (ip))
elif ip.find(':') >= 0:
splitted_ip = [int(a, 16) for a in self._extend_ipv6(ip).split(':')]
if len(splitted_ip) != 16:
raise Exception('Bad IP %s' % (ip))
ip_type = IPToGeo.IPV6
else:
raise Exception('Bad IP %s' % (ip))
packet = self._create_request(splitted_ip, ip_type)
try:
self._socket.send(packet)
except IOError, e:
# Give another chance (we may have been disconnected due to timeout)
self._create_socket()
self._socket.send(packet)
packet = self._socket.recv(IPToGeo.PACKET_SIZE)
if not packet:
raise IPToGeoException('Error, empty packet')
(ip, country_code) = self._check_request(packet)
if country_code:
# convert to string
country_code = '%c%c' % (country_code[0], country_code[1])
return (ip, country_code)
def close(self):
self._socket.close()

View File

@ -120,7 +120,7 @@ class IWLAPostAnalysisReferers(IPlugin):
break
def hook(self):
stats = self.iwla.getCurrentVisists()
stats = self.iwla.getCurrentVisits()
month_stats = self.iwla.getMonthStats()
referers = month_stats.get('referers', {})

View File

@ -64,9 +64,12 @@ class IWLAPostAnalysisReverseDNS(IPlugin):
return True
def hook(self):
hits = self.iwla.getValidVisitors()
hits = self.iwla.getCurrentVisits()
for (k, hit) in hits.items():
if hit.get('dns_analysed', False): continue
if not hit['feed_parser'] and\
not self.iwla.isValidVisitor(hit):
continue
try:
name, _, _ = socket.gethostbyaddr(k)
hit['remote_addr'] = name.lower()

View File

@ -53,7 +53,7 @@ class IWLAPostAnalysisTopHits(IPlugin):
self.API_VERSION = 1
def hook(self):
stats = self.iwla.getCurrentVisists()
stats = self.iwla.getCurrentVisits()
month_stats = self.iwla.getMonthStats()
top_hits = month_stats.get('top_hits', {})

View File

@ -59,7 +59,7 @@ class IWLAPostAnalysisTopPages(IPlugin):
return True
def hook(self):
stats = self.iwla.getCurrentVisists()
stats = self.iwla.getCurrentVisits()
month_stats = self.iwla.getMonthStats()
top_pages = month_stats.get('top_pages', {})

View File

@ -69,7 +69,7 @@ class IWLAPreAnalysisPageToHit(IPlugin):
return True
def hook(self):
hits = self.iwla.getCurrentVisists()
hits = self.iwla.getCurrentVisits()
for (k, super_hit) in hits.items():
if super_hit['robot']: continue

View File

@ -76,7 +76,7 @@ class IWLAPreAnalysisRobots(IPlugin):
# Basic rule to detect robots
def hook(self):
hits = self.iwla.getCurrentVisists()
hits = self.iwla.getCurrentVisits()
for (k, super_hit) in hits.items():
if super_hit['robot']:
self.logger.debug('%s is a robot' % (k))

BIN
resources/icon/flags/a2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

BIN
resources/icon/flags/ac.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 B

BIN
resources/icon/flags/ad.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

BIN
resources/icon/flags/ae.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

BIN
resources/icon/flags/af.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

BIN
resources/icon/flags/ag.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

BIN
resources/icon/flags/ai.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

BIN
resources/icon/flags/al.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

BIN
resources/icon/flags/am.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 B

BIN
resources/icon/flags/an.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

BIN
resources/icon/flags/ao.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

BIN
resources/icon/flags/aq.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

BIN
resources/icon/flags/ar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

BIN
resources/icon/flags/as.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 B

BIN
resources/icon/flags/at.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

BIN
resources/icon/flags/au.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

BIN
resources/icon/flags/aw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 B

BIN
resources/icon/flags/ax.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 B

BIN
resources/icon/flags/az.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

BIN
resources/icon/flags/ba.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

BIN
resources/icon/flags/bb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

BIN
resources/icon/flags/bd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 B

BIN
resources/icon/flags/be.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

BIN
resources/icon/flags/bf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

BIN
resources/icon/flags/bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

BIN
resources/icon/flags/bh.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

BIN
resources/icon/flags/bi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

BIN
resources/icon/flags/bj.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

BIN
resources/icon/flags/bm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

BIN
resources/icon/flags/bn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

BIN
resources/icon/flags/bo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

BIN
resources/icon/flags/br.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

BIN
resources/icon/flags/bs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

BIN
resources/icon/flags/bt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 B

BIN
resources/icon/flags/bv.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

BIN
resources/icon/flags/bw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 B

BIN
resources/icon/flags/by.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

BIN
resources/icon/flags/bz.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

BIN
resources/icon/flags/ca.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

BIN
resources/icon/flags/cc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

BIN
resources/icon/flags/cd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

BIN
resources/icon/flags/cf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

BIN
resources/icon/flags/cg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

BIN
resources/icon/flags/ch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

BIN
resources/icon/flags/ci.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

BIN
resources/icon/flags/ck.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 B

BIN
resources/icon/flags/cl.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

BIN
resources/icon/flags/cm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

BIN
resources/icon/flags/cn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

BIN
resources/icon/flags/co.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

BIN
resources/icon/flags/cr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

BIN
resources/icon/flags/cs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

BIN
resources/icon/flags/cu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

BIN
resources/icon/flags/cv.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

BIN
resources/icon/flags/cx.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

BIN
resources/icon/flags/cy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

BIN
resources/icon/flags/cz.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

BIN
resources/icon/flags/de.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

BIN
resources/icon/flags/dj.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

BIN
resources/icon/flags/dk.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

BIN
resources/icon/flags/dm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

BIN
resources/icon/flags/do.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

BIN
resources/icon/flags/dz.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

BIN
resources/icon/flags/ec.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

BIN
resources/icon/flags/ee.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

BIN
resources/icon/flags/eg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

BIN
resources/icon/flags/eh.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 B

BIN
resources/icon/flags/en.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 B

Some files were not shown because too many files have changed in this diff Show More