diff --git a/action.php b/action.php index 0535472..982c9f5 100644 --- a/action.php +++ b/action.php @@ -121,7 +121,7 @@ class action_plugin_botmon extends DokuWiki_Action_Plugin { private function getCountryCode() { - $country = ( $this->ipAddress == 'localhost' ? 'AA' : 'ZZ' ); // default if no geoip is available! + $country = ( $this->ipAddress == 'localhost' ? 'local' : 'ZZ' ); // default if no geoip is available! $lib = $this->getConf('geoiplib'); /* which library to use? (can only be phpgeoip or disabled) */ diff --git a/admin.php b/admin.php index ade38a3..edfef34 100644 --- a/admin.php +++ b/admin.php @@ -56,7 +56,7 @@ class admin_plugin_botmon extends AdminPlugin {
Bot overview (page views) -
+
@@ -64,10 +64,11 @@ class admin_plugin_botmon extends AdminPlugin {
Web metrics -
+
+
diff --git a/img/flags.png b/img/flags.png index 12a2346..2c5d318 100644 Binary files a/img/flags.png and b/img/flags.png differ diff --git a/img/referers.png b/img/referers.png new file mode 100644 index 0000000..2fed645 Binary files /dev/null and b/img/referers.png differ diff --git a/script.js b/script.js index 91aa057..e8946e3 100644 --- a/script.js +++ b/script.js @@ -566,6 +566,11 @@ BotMon.live = { // add browser and platform statistics: me.addBrowserPlatform(v); + + // add + v._pageViews.forEach( pv => { + me.addToRefererList(pv._ref); + }); } }); @@ -573,85 +578,76 @@ BotMon.live = { BotMon.live.gui.status.hideBusy('Done.'); }, - // visits from IP ranges: - /*_ipRange: { - ip4: [], - ip6: [] - },*/ - /** - * Adds a visit to the IP range statistics. - * - * This helps to identify IP ranges that are used by bots. - * - * @param {string} ip The IP address to add. - */ - /*addToIPRanges: function(ip) { + // Referer List: + _refererList: [], + _refererListCount: 0, + + addToRefererList: function(ref) { + //console.log('BotMon.live.data.analytics.addToRefererList',ref); - // #TODO: handle nestled ranges! const me = BotMon.live.data.analytics; - const ipv = (ip.indexOf(':') > 0 ? 6 : 4); + + // ignore internal references: + if (ref && ref.host == 'denkfehler.online') { + return; + } + + // find the referer ID: + let refId = 'null'; + if (ref && ref.host) { + const hArr = ref.host.split('.'); + const tld = hArr[hArr.length-1]; + refId = ( tld == 'localhost' ? tld : hArr[hArr.length-2] + ( tld.length > 3 ? '.' + tld : '' ) ); + } - const ipArr = ip.split( ipv == 6 ? ':' : '.'); - const maxSegments = (ipv == 6 ? 4 : 3); - - let arr = (ipv == 6 ? me._ipRange.ip6 : me._ipRange.ip4); - - // find any existing segment entry: - it = null; - for (let i=0; i < arr.length; i++) { - const sig = arr[i]; - if (sig.seg == ipArr[0]) { - it = sig; + // already exists? + let refObj = null; + for (let i = 0; i < me._refererList.length; i++) { + if (me._refererList[i].id == refId) { + refObj = me._refererList[i]; break; } } - - // create if not found: - if (!it) { - it = {seg: ipArr[0], count: 1}; - //if (i { - if (it.count > kMinHits) { - it.type = ipType; - tmpList.push(it); - } - }); - tmpList.sort( (a,b) => b.count - a.count); - } + // sort the list: + me._refererList.sort( (a,b) => { + return b.count - a.count; + }); - // reduce to only the top (max) items and create the target format: - // #TODO: handle nestled ranges! - let rList = []; - for (let j=0; Math.min(max, tmpList.length) > j; j++) { - const rangeInfo = tmpList[j]; - rList.push({ - 'ip': rangeInfo.seg + ( rangeInfo.type == 4 ? '.x.x.x' : '::x'), - 'typ': rangeInfo.type, - 'num': rangeInfo.count - }); + // get the top: + for (let i = 0; i < max; i++) { + const it = me._refererList[i]; + const rIt = { + id: it.id, + count: it.count, + pct: (it.count / me._refererListCount * 100).toFixed(0) + } + rList.push(rIt); } return rList; - },*/ + }, /* countries of visits */ _countries: { @@ -1609,7 +1605,7 @@ BotMon.live = { const wmclients = document.getElementById('botmon__today__wm_clients'); if (wmclients) { - wmclients.appendChild(makeElement('dt', {}, "Top browsers (humans only)")); + wmclients.appendChild(makeElement('dt', {}, "Top browsers")); const clientList = BotMon.live.data.analytics.getTopBrowsers(5); if (clientList) { @@ -1629,7 +1625,7 @@ BotMon.live = { const wmplatforms = document.getElementById('botmon__today__wm_platforms'); if (wmplatforms) { - wmplatforms.appendChild(makeElement('dt', {}, "Top platforms (humans only)")); + wmplatforms.appendChild(makeElement('dt', {}, "Top platforms")); const pfList = BotMon.live.data.analytics.getTopPlatforms(5); if (pfList) { @@ -1645,6 +1641,25 @@ BotMon.live = { } } + // update the top referrers; + const wmreferers = document.getElementById('botmon__today__wm_referers'); + if (wmreferers) { + + wmreferers.appendChild(makeElement('dt', {}, "Top Referers")); + + const refList = BotMon.live.data.analytics.getTopReferers(5); + if (refList) { + refList.forEach( (rInfo) => { + const rDd = makeElement('dd'); + rDd.appendChild(makeElement('span', {'class': 'has_icon referer ref_' + rInfo.id }, rInfo.id)); + rDd.appendChild(makeElement('span', { + 'class': 'count', + 'title': rInfo.count + " references" + }, Math.round(rInfo.pct) + '%')); + wmreferers.appendChild(rDd); + }); + } + } } }, @@ -1978,7 +1993,7 @@ BotMon.live = { /* add bot evaluation details: */ if (data._eval) { - dl.appendChild(make('dt', {}, "Bot evaluation details:")); + dl.appendChild(make('dt', {}, "Bot evaluation:")); const evalDd = make('dd'); const testList = make('ul',{ 'class': 'eval' diff --git a/style.less b/style.less index 1aabda2..a112e57 100644 --- a/style.less +++ b/style.less @@ -40,7 +40,8 @@ /* Bot icons */ &.bot::before { background-image: url('img/bots.png') } - &.bot_googlebot::before, &.bot_googleads::before, &.bot_googleapi::before, &.bot_googleother::before, &.bot_googinspct::before { background-position-y: -20px } + &.bot_googlebot::before, &.bot_googleads::before, &.bot_googleapi::before, + &.bot_googleother::before, &.bot_googinspct::before { background-position-y: -20px } &.bot_bingbot::before { background-position-y: -40px } &.bot_applebot::before { background-position-y: -60px } &.bot_openai::before { background-position-y: -80px } @@ -341,13 +342,23 @@ &.extlink::before { background-image: url('img/links.png') } &.extlink.dnscheck::before { background-position-y: -20px } &.extlink.ipinfo::before { background-position-y: -40px } + + /* Common referers icons */ + &.referer::before { background-image: url('img/referers.png') } + &.ref_null::before { background-position-y: -20px } + &.ref_google::before { background-position-y: -40px } + &.ref_bing::before { background-position-y: -60px } + &.ref_yahoo::before { background-position-y: -80px } + &.ref_dokuwiki::before { background-position-y: -100px } + &.ref_duckduckgo::before { background-position-y: -120px } + &.ref_ecosia::before { background-position-y: -140px } + &.ref_yandex::before { background-position-y: -160px } } /* grid layout for the overview: */ - .botmon_overview_grid { + .botmon_bots_grid, .botmon_webmetrics_grid { & { display: grid; - grid-template-columns: 1fr 1fr 1fr; grid-gap: 0 .33em; } dl { @@ -358,6 +369,12 @@ } } } + .botmon_bots_grid { + grid-template-columns: 1fr 1fr 1fr; + } + .botmon_webmetrics_grid { + grid-template-columns: 1fr 1fr 1fr 1fr; + } /* the "today" tab: */ #botmon__today { @@ -750,7 +767,7 @@ /* layout overrides for narrow screens: */ @media (max-width: 670px) { #botmon__admin { - .botmon_overview_grid { + .botmon_bots_grid, .botmon_webmetrics_grid { grid-template-columns: 100%; } }