diff options
-rw-r--r-- | core/Config.php | 3 | ||||
-rw-r--r-- | core/Config/ConfigNotFoundException.php | 16 | ||||
-rw-r--r-- | core/Console.php | 6 | ||||
-rw-r--r-- | js/piwik.js | 3 | ||||
-rw-r--r-- | piwik.js | 14 | ||||
-rw-r--r-- | plugins/Live/API.php | 47 | ||||
-rw-r--r-- | plugins/Live/Controller.php | 4 | ||||
-rw-r--r-- | plugins/Live/Model.php | 113 | ||||
-rw-r--r-- | plugins/Live/Reports/GetSimpleLastVisitCount.php | 3 | ||||
-rw-r--r-- | plugins/Live/tests/System/APITest.php | 32 | ||||
m--------- | tests/UI/expected-ui-screenshots | 0 | ||||
-rw-r--r-- | tests/javascript/index.php | 9 |
12 files changed, 198 insertions, 52 deletions
diff --git a/core/Config.php b/core/Config.php index e28f581ea8..f0b5c3ed26 100644 --- a/core/Config.php +++ b/core/Config.php @@ -10,6 +10,7 @@ namespace Piwik; use Exception; +use Piwik\Config\ConfigNotFoundException; use Piwik\Ini\IniReader; use Piwik\Ini\IniReadingException; use Piwik\Ini\IniWriter; @@ -370,7 +371,7 @@ class Config extends Singleton public function checkLocalConfigFound() { if (!$this->existsLocalConfig()) { - throw new Exception(Piwik::translate('General_ExceptionConfigurationFileNotFound', array($this->pathLocal))); + throw new ConfigNotFoundException(Piwik::translate('General_ExceptionConfigurationFileNotFound', array($this->pathLocal))); } } diff --git a/core/Config/ConfigNotFoundException.php b/core/Config/ConfigNotFoundException.php new file mode 100644 index 0000000000..5860367ba7 --- /dev/null +++ b/core/Config/ConfigNotFoundException.php @@ -0,0 +1,16 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +namespace Piwik\Config; + +/** + * Exception thrown when the config file doesn't exist. + */ +class ConfigNotFoundException extends \Exception +{ +} diff --git a/core/Console.php b/core/Console.php index 02e5f86871..fac27d8036 100644 --- a/core/Console.php +++ b/core/Console.php @@ -8,6 +8,7 @@ */ namespace Piwik; +use Piwik\Config\ConfigNotFoundException; use Piwik\Container\StaticContainer; use Piwik\Plugin\Manager as PluginManager; use Symfony\Bridge\Monolog\Handler\ConsoleHandler; @@ -43,10 +44,9 @@ class Console extends Application try { self::initPlugins(); - } catch(\Exception $e) { + } catch (ConfigNotFoundException $e) { // Piwik not installed yet, no config file? - - Log::debug("Could not initialize plugins: " . $e->getMessage() . "\n" . $e->getTraceAsString()); + Log::warning($e->getMessage()); } $commands = $this->getAvailableCommands(); diff --git a/js/piwik.js b/js/piwik.js index 27413028ff..0f4f5d253a 100644 --- a/js/piwik.js +++ b/js/piwik.js @@ -4245,6 +4245,9 @@ if (typeof Piwik !== 'object') { * @param string User ID */ setUserId: function (userId) { + if(!isDefined(userId) || !userId.length) { + return; + } configUserId = userId; visitorUUID = hash(configUserId).substr(0, 16); }, @@ -43,12 +43,12 @@ cf.push(cc)}return cf}function aW(cc){var cb=m.collectContent(cc);return aB(cb,c aZ(cc,bn)}function bO(ce,cb,ci,ch,cd){var cg=cb+"="+l(bY(ce));var cc=aR(cd,"click",ce);if(cc){cg+="&"+cc}var cf=aT(cg,ci,"link");aZ(cf,(ch?0:bn),ch)}function bV(cc,cb){if(cc!==""){return cc+cb.charAt(0).toUpperCase()+cb.slice(1)}return cb}function aM(cg){var cf,cb,ce=["","webkit","ms","moz"],cd;if(!a0){for(cb=0;cb<ce.length;cb++){cd=ce[cb];if(Object.prototype.hasOwnProperty.call(u,bV(cd,"hidden"))){if(u[bV(cd,"visibilityState")]==="prerender"){cf=true}break}}}if(cf){U(u,cd+"visibilitychange",function cc(){u.removeEventListener(cd+"visibilitychange",cc,false);cg()});return}cg()}function aQ(cb){if(u.readyState==="complete"){cb()}else{if(G.addEventListener){G.addEventListener("load",cb)}else{if(G.attachEvent){G.attachEvent("onLoad",cb)}}}}function aA(cc){var cb=false;if(u.attachEvent){cb=u.readyState==="complete"}else{cb=u.readyState!=="loading"}if(cb){cc()}else{if(u.addEventListener){u.addEventListener("DOMContentLoaded",cc)}else{if(u.attachEvent){u.attachEvent("onreadystatechange",cc)}}}}function bE(cb){var cc=bi(cb); if(cc&&cc.type){cc.href=h(cc.href);bO(cc.href,cc.type,undefined,null,cb)}}function b9(cb){var cc,cd;cb=cb||G.event;cc=cb.which||cb.button;cd=cb.target||cb.srcElement;if(cb.type==="click"){if(cd){bE(cd)}}else{if(cb.type==="mousedown"){if((cc===1||cc===2)&&cd){bj=cc;at=cd}else{bj=at=null}}else{if(cb.type==="mouseup"){if(cc===bj&&cd===at){bE(cd)}bj=at=null}}}}function bA(cc,cb){if(cb){U(cc,"mouseup",b9,false);U(cc,"mousedown",b9,false)}else{U(cc,"click",b9,false)}}function bd(cc){if(!bz){bz=true;var cd,cb=aH(ai,"ignore"),ce=u.links;if(ce){for(cd=0;cd<ce.length;cd++){if(!cb.test(ce[cd].className)){bA(ce[cd],cc)}}}}}function bv(cd,cf,cg){if(ay){return true}ay=true;var ch=false;var ce,cc;function cb(){ch=true}aQ(function(){function ci(ck){setTimeout(function(){if(!ay){return}ch=false;cg.trackVisibleContentImpressions();ci(ck)},ck)}function cj(ck){setTimeout(function(){if(!ay){return}if(ch){ch=false;cg.trackVisibleContentImpressions()}cj(ck)},ck)}if(cd){ce=["scroll","resize"];for(cc=0;cc<ce.length; cc++){if(u.addEventListener){u.addEventListener(ce[cc],cb)}else{G.attachEvent("on"+ce[cc],cb)}}cj(100)}if(cf&&cf>0){cf=parseInt(cf,10);ci(cf)}})}function b0(){var cc,cd,ce={pdf:"application/pdf",qt:"video/quicktime",realp:"audio/x-pn-realaudio-plugin",wma:"application/x-mplayer2",dir:"application/x-director",fla:"application/x-shockwave-flash",java:"application/x-java-vm",gears:"application/x-googlegears",ag:"application/x-silverlight"},cb=(new RegExp("Mac OS X.*Safari/")).test(e.userAgent)?G.devicePixelRatio||1:1;if(!((new RegExp("MSIE")).test(e.userAgent))){if(e.mimeTypes&&e.mimeTypes.length){for(cc in ce){if(Object.prototype.hasOwnProperty.call(ce,cc)){cd=e.mimeTypes[ce[cc]];bT[cc]=(cd&&cd.enabledPlugin)?"1":"0"}}}if(typeof navigator.javaEnabled!=="unknown"&&w(e.javaEnabled)&&e.javaEnabled()){bT.java="1"}if(q(G.GearsFactory)){bT.gears="1"}bT.cookie=ae()}bT.res=K.width*cb+"x"+K.height*cb}b0();bk();am();return{getVisitorId:function(){return bB().uuid},getVisitorInfo:function(){return Y() -},getAttributionInfo:function(){return X()},getAttributionCampaignName:function(){return X()[0]},getAttributionCampaignKeyword:function(){return X()[1]},getAttributionReferrerTimestamp:function(){return X()[2]},getAttributionReferrerUrl:function(){return X()[3]},setTrackerUrl:function(cb){aa=cb},getTrackerUrl:function(){return aa},getSiteId:function(){return bS},setSiteId:function(cb){b7(cb)},setUserId:function(cb){aJ=cb;a2=aX(aJ).substr(0,16)},getUserId:function(){return aJ},setCustomData:function(cb,cc){if(J(cb)){an=cb}else{if(!an){an={}}an[cb]=cc}},getCustomData:function(){return an},setCustomRequestProcessing:function(cb){au=cb},appendToTrackingUrl:function(cb){bo=cb},getRequest:function(cb){return aT(cb)},addPlugin:function(cb,cc){a[cb]=cc},setCustomVariable:function(cc,cb,cf,cd){var ce;if(!w(cd)){cd="visit"}if(!w(cb)){return}if(!w(cf)){cf=""}if(cc>0){cb=!n(cb)?String(cb):cb;cf=!n(cf)?String(cf):cf;ce=[cb.slice(0,bX),cf.slice(0,bX)];if(cd==="visit"||cd===2){Z();ag[cc]=ce}else{if(cd==="page"||cd===3){bg[cc]=ce -}else{if(cd==="event"){ab[cc]=ce}}}}},getCustomVariable:function(cc,cd){var cb;if(!w(cd)){cd="visit"}if(cd==="page"||cd===3){cb=bg[cc]}else{if(cd==="event"){cb=ab[cc]}else{if(cd==="visit"||cd===2){Z();cb=ag[cc]}}}if(!w(cb)||(cb&&cb[0]==="")){return false}return cb},deleteCustomVariable:function(cb,cc){if(this.getCustomVariable(cb,cc)){this.setCustomVariable(cb,"","",cc)}},storeCustomVariablesInCookie:function(){a6=true},setLinkTrackingTimer:function(cb){bn=cb},setDownloadExtensions:function(cb){aU=cb},addDownloadExtensions:function(cb){aU+="|"+cb},setDomains:function(cb){bp=n(cb)?[cb]:cb;bp.push(bM)},setIgnoreClasses:function(cb){ai=n(cb)?[cb]:cb},setRequestMethod:function(cb){bs=cb||bq},setRequestContentType:function(cb){aK=cb||bc},setReferrerUrl:function(cb){bu=cb},setCustomUrl:function(cb){a7=bL(b4,cb)},setDocumentTitle:function(cb){aS=cb},setAPIUrl:function(cb){ax=cb},setDownloadClasses:function(cb){bf=n(cb)?[cb]:cb},setLinkClasses:function(cb){aC=n(cb)?[cb]:cb},setCampaignNameKey:function(cb){aY=n(cb)?[cb]:cb -},setCampaignKeywordKey:function(cb){aP=n(cb)?[cb]:cb},discardHashTag:function(cb){ak=cb},setCookieNamePrefix:function(cb){b2=cb;ag=ar()},setCookieDomain:function(cb){aq=y(cb);bk()},setCookiePath:function(cb){b3=cb;bk()},setVisitorCookieTimeout:function(cb){aw=cb*1000},setSessionCookieTimeout:function(cb){az=cb*1000},setReferralCookieTimeout:function(cb){ba=cb*1000},setConversionAttributionFirstReferrer:function(cb){a5=cb},disableCookies:function(){ao=true;bT.cookie="0"},deleteCookies:function(){W()},setDoNotTrack:function(cc){var cb=e.doNotTrack||e.msDoNotTrack;bW=cc&&(cb==="yes"||cb==="1");if(bW){this.disableCookies()}},addListener:function(cc,cb){bA(cc,cb)},enableLinkTracking:function(cb){bU=true;if(p){bd(cb)}else{E.push(function(){bd(cb)})}},enableJSErrorTracking:function(){if(b8){return}b8=true;var cb=G.onerror;G.onerror=function(cg,ce,cd,cf,cc){aM(function(){var ch="JavaScript Errors";var ci=ce+":"+cd;if(cf){ci+=":"+cf}al(ch,ci,cg)});if(cb){return cb(cg,ce,cd,cf,cc)}return false}},disablePerformanceTracking:function(){a1=false -},setGenerationTimeMs:function(cb){aI=parseInt(cb,10)},setHeartBeatTimer:function(cd,cc){var cb=new Date();aj=cb.getTime()+cd*1000;aG=cc*1000},killFrame:function(){if(G.location!==G.top.location){G.top.location=G.location}},redirectFile:function(cb){if(G.location.protocol==="file:"){G.location=cb}},setCountPreRendered:function(cb){a0=cb},trackGoal:function(cb,cd,cc){aM(function(){bl(cb,cd,cc)})},trackLink:function(cc,cb,ce,cd){aM(function(){bO(cc,cb,ce,cd)})},trackPageView:function(cb,cc){ah=[];if(A(bS)){aM(function(){M(aa,ax,bS)})}else{aM(function(){be(cb,cc)})}},trackAllContentImpressions:function(){if(A(bS)){return}aM(function(){aA(function(){var cb=m.findContentNodes();var cc=aW(cb);ap(cc,bn)})})},trackVisibleContentImpressions:function(cb,cc){if(A(bS)){return}if(!w(cb)){cb=true}if(!w(cc)){cc=750}bv(cb,cc,this);aM(function(){aQ(function(){var cd=m.findContentNodes();var ce=bC(cd);ap(ce,bn)})})},trackContentImpression:function(cd,cb,cc){if(A(bS)){return}if(!cd){return}cb=cb||"Unknown"; -aM(function(){var ce=bN(cd,cb,cc);aZ(ce,bn)})},trackContentImpressionsWithinNode:function(cb){if(A(bS)||!cb){return}aM(function(){if(ay){aQ(function(){var cc=m.findContentNodesWithinNode(cb);var cd=bC(cc);ap(cd,bn)})}else{aA(function(){var cc=m.findContentNodesWithinNode(cb);var cd=aW(cc);ap(cd,bn)})}})},trackContentInteraction:function(cd,ce,cb,cc){if(A(bS)){return}if(!cd||!ce){return}cb=cb||"Unknown";aM(function(){var cf=b6(cd,ce,cb,cc);aZ(cf,bn)})},trackContentInteractionNode:function(cc,cb){if(A(bS)||!cc){return}aM(function(){var cd=aV(cc,cb);aZ(cd,bn)})},trackEvent:function(cc,ce,cb,cd){aM(function(){al(cc,ce,cb,cd)})},trackSiteSearch:function(cb,cd,cc){aM(function(){aN(cb,cd,cc)})},setEcommerceView:function(ce,cb,cd,cc){if(!w(cd)||!cd.length){cd=""}else{if(cd instanceof Array){cd=JSON2.stringify(cd)}}bg[5]=["_pkc",cd];if(w(cc)&&String(cc).length){bg[2]=["_pkp",cc]}if((!w(ce)||!ce.length)&&(!w(cb)||!cb.length)){return}if(w(ce)&&ce.length){bg[3]=["_pks",ce]}if(!w(cb)||!cb.length){cb="" -}bg[4]=["_pkn",cb]},addEcommerceItem:function(cf,cb,cd,cc,ce){if(cf.length){bF[cf]=[cf,cb,cd,cc,ce]}},trackEcommerceOrder:function(cb,cf,ce,cd,cc,cg){bJ(cb,cf,ce,cd,cc,cg)},trackEcommerceCartUpdate:function(cb){b1(cb)}}}function v(){return{push:R}}U(G,"beforeunload",S,false);o();Date.prototype.getTimeAlias=Date.prototype.getTime;L=new D();var r={setTrackerUrl:1,setAPIUrl:1,setUserId:1,setSiteId:1,disableCookies:1,enableLinkTracking:1};var d;for(t=0;t<_paq.length;t++){d=_paq[t][0];if(r[d]){R(_paq[t]);delete _paq[t];if(r[d]>1){if(console!==undefined&&console&&console.error){console.error("The method "+d+' is registered more than once in "_paq" variable. Only the last call has an effect. Please have a look at the multiple Piwik trackers documentation: http://developer.piwik.org/guides/tracking-javascript-guide#multiple-piwik-trackers')}}r[d]++}}for(t=0;t<_paq.length;t++){if(_paq[t]){R(_paq[t])}}_paq=new v();c={addPlugin:function(W,X){a[W]=X},getTracker:function(W,X){if(!w(X)){X=this.getAsyncTracker().getSiteId() -}if(!w(W)){W=this.getAsyncTracker().getTrackerUrl()}return new D(W,X)},getAsyncTracker:function(){return L}};if(typeof define==="function"&&define.amd){define("piwik",[],function(){return c})}return c}())}if(window&&window.piwikAsyncInit){window.piwikAsyncInit()}(function(){var a=(typeof AnalyticsTracker);if(a==="undefined"){AnalyticsTracker=Piwik}}());if(typeof piwik_log!=="function"){piwik_log=function(b,f,d,g){function a(h){try{return eval("piwik_"+h)}catch(i){}return}var c,e=Piwik.getTracker(d,f);e.setDocumentTitle(b);e.setCustomData(g);c=a("tracker_pause");if(c){e.setLinkTrackingTimer(c)}c=a("download_extensions");if(c){e.setDownloadExtensions(c)}c=a("hosts_alias");if(c){e.setDomains(c)}c=a("ignore_classes");if(c){e.setIgnoreClasses(c)}e.trackPageView();if(a("install_tracker")){piwik_track=function(i,k,j,h){e.setSiteId(k);e.setTrackerUrl(j);e.trackLink(i,h)};e.enableLinkTracking()}}; +},getAttributionInfo:function(){return X()},getAttributionCampaignName:function(){return X()[0]},getAttributionCampaignKeyword:function(){return X()[1]},getAttributionReferrerTimestamp:function(){return X()[2]},getAttributionReferrerUrl:function(){return X()[3]},setTrackerUrl:function(cb){aa=cb},getTrackerUrl:function(){return aa},getSiteId:function(){return bS},setSiteId:function(cb){b7(cb)},setUserId:function(cb){if(!w(cb)||!cb.length){return}aJ=cb;a2=aX(aJ).substr(0,16)},getUserId:function(){return aJ},setCustomData:function(cb,cc){if(J(cb)){an=cb}else{if(!an){an={}}an[cb]=cc}},getCustomData:function(){return an},setCustomRequestProcessing:function(cb){au=cb},appendToTrackingUrl:function(cb){bo=cb},getRequest:function(cb){return aT(cb)},addPlugin:function(cb,cc){a[cb]=cc},setCustomVariable:function(cc,cb,cf,cd){var ce;if(!w(cd)){cd="visit"}if(!w(cb)){return}if(!w(cf)){cf=""}if(cc>0){cb=!n(cb)?String(cb):cb;cf=!n(cf)?String(cf):cf;ce=[cb.slice(0,bX),cf.slice(0,bX)];if(cd==="visit"||cd===2){Z(); +ag[cc]=ce}else{if(cd==="page"||cd===3){bg[cc]=ce}else{if(cd==="event"){ab[cc]=ce}}}}},getCustomVariable:function(cc,cd){var cb;if(!w(cd)){cd="visit"}if(cd==="page"||cd===3){cb=bg[cc]}else{if(cd==="event"){cb=ab[cc]}else{if(cd==="visit"||cd===2){Z();cb=ag[cc]}}}if(!w(cb)||(cb&&cb[0]==="")){return false}return cb},deleteCustomVariable:function(cb,cc){if(this.getCustomVariable(cb,cc)){this.setCustomVariable(cb,"","",cc)}},storeCustomVariablesInCookie:function(){a6=true},setLinkTrackingTimer:function(cb){bn=cb},setDownloadExtensions:function(cb){aU=cb},addDownloadExtensions:function(cb){aU+="|"+cb},setDomains:function(cb){bp=n(cb)?[cb]:cb;bp.push(bM)},setIgnoreClasses:function(cb){ai=n(cb)?[cb]:cb},setRequestMethod:function(cb){bs=cb||bq},setRequestContentType:function(cb){aK=cb||bc},setReferrerUrl:function(cb){bu=cb},setCustomUrl:function(cb){a7=bL(b4,cb)},setDocumentTitle:function(cb){aS=cb},setAPIUrl:function(cb){ax=cb},setDownloadClasses:function(cb){bf=n(cb)?[cb]:cb},setLinkClasses:function(cb){aC=n(cb)?[cb]:cb +},setCampaignNameKey:function(cb){aY=n(cb)?[cb]:cb},setCampaignKeywordKey:function(cb){aP=n(cb)?[cb]:cb},discardHashTag:function(cb){ak=cb},setCookieNamePrefix:function(cb){b2=cb;ag=ar()},setCookieDomain:function(cb){aq=y(cb);bk()},setCookiePath:function(cb){b3=cb;bk()},setVisitorCookieTimeout:function(cb){aw=cb*1000},setSessionCookieTimeout:function(cb){az=cb*1000},setReferralCookieTimeout:function(cb){ba=cb*1000},setConversionAttributionFirstReferrer:function(cb){a5=cb},disableCookies:function(){ao=true;bT.cookie="0"},deleteCookies:function(){W()},setDoNotTrack:function(cc){var cb=e.doNotTrack||e.msDoNotTrack;bW=cc&&(cb==="yes"||cb==="1");if(bW){this.disableCookies()}},addListener:function(cc,cb){bA(cc,cb)},enableLinkTracking:function(cb){bU=true;if(p){bd(cb)}else{E.push(function(){bd(cb)})}},enableJSErrorTracking:function(){if(b8){return}b8=true;var cb=G.onerror;G.onerror=function(cg,ce,cd,cf,cc){aM(function(){var ch="JavaScript Errors";var ci=ce+":"+cd;if(cf){ci+=":"+cf}al(ch,ci,cg) +});if(cb){return cb(cg,ce,cd,cf,cc)}return false}},disablePerformanceTracking:function(){a1=false},setGenerationTimeMs:function(cb){aI=parseInt(cb,10)},setHeartBeatTimer:function(cd,cc){var cb=new Date();aj=cb.getTime()+cd*1000;aG=cc*1000},killFrame:function(){if(G.location!==G.top.location){G.top.location=G.location}},redirectFile:function(cb){if(G.location.protocol==="file:"){G.location=cb}},setCountPreRendered:function(cb){a0=cb},trackGoal:function(cb,cd,cc){aM(function(){bl(cb,cd,cc)})},trackLink:function(cc,cb,ce,cd){aM(function(){bO(cc,cb,ce,cd)})},trackPageView:function(cb,cc){ah=[];if(A(bS)){aM(function(){M(aa,ax,bS)})}else{aM(function(){be(cb,cc)})}},trackAllContentImpressions:function(){if(A(bS)){return}aM(function(){aA(function(){var cb=m.findContentNodes();var cc=aW(cb);ap(cc,bn)})})},trackVisibleContentImpressions:function(cb,cc){if(A(bS)){return}if(!w(cb)){cb=true}if(!w(cc)){cc=750}bv(cb,cc,this);aM(function(){aQ(function(){var cd=m.findContentNodes();var ce=bC(cd);ap(ce,bn) +})})},trackContentImpression:function(cd,cb,cc){if(A(bS)){return}if(!cd){return}cb=cb||"Unknown";aM(function(){var ce=bN(cd,cb,cc);aZ(ce,bn)})},trackContentImpressionsWithinNode:function(cb){if(A(bS)||!cb){return}aM(function(){if(ay){aQ(function(){var cc=m.findContentNodesWithinNode(cb);var cd=bC(cc);ap(cd,bn)})}else{aA(function(){var cc=m.findContentNodesWithinNode(cb);var cd=aW(cc);ap(cd,bn)})}})},trackContentInteraction:function(cd,ce,cb,cc){if(A(bS)){return}if(!cd||!ce){return}cb=cb||"Unknown";aM(function(){var cf=b6(cd,ce,cb,cc);aZ(cf,bn)})},trackContentInteractionNode:function(cc,cb){if(A(bS)||!cc){return}aM(function(){var cd=aV(cc,cb);aZ(cd,bn)})},trackEvent:function(cc,ce,cb,cd){aM(function(){al(cc,ce,cb,cd)})},trackSiteSearch:function(cb,cd,cc){aM(function(){aN(cb,cd,cc)})},setEcommerceView:function(ce,cb,cd,cc){if(!w(cd)||!cd.length){cd=""}else{if(cd instanceof Array){cd=JSON2.stringify(cd)}}bg[5]=["_pkc",cd];if(w(cc)&&String(cc).length){bg[2]=["_pkp",cc]}if((!w(ce)||!ce.length)&&(!w(cb)||!cb.length)){return +}if(w(ce)&&ce.length){bg[3]=["_pks",ce]}if(!w(cb)||!cb.length){cb=""}bg[4]=["_pkn",cb]},addEcommerceItem:function(cf,cb,cd,cc,ce){if(cf.length){bF[cf]=[cf,cb,cd,cc,ce]}},trackEcommerceOrder:function(cb,cf,ce,cd,cc,cg){bJ(cb,cf,ce,cd,cc,cg)},trackEcommerceCartUpdate:function(cb){b1(cb)}}}function v(){return{push:R}}U(G,"beforeunload",S,false);o();Date.prototype.getTimeAlias=Date.prototype.getTime;L=new D();var r={setTrackerUrl:1,setAPIUrl:1,setUserId:1,setSiteId:1,disableCookies:1,enableLinkTracking:1};var d;for(t=0;t<_paq.length;t++){d=_paq[t][0];if(r[d]){R(_paq[t]);delete _paq[t];if(r[d]>1){if(console!==undefined&&console&&console.error){console.error("The method "+d+' is registered more than once in "_paq" variable. Only the last call has an effect. Please have a look at the multiple Piwik trackers documentation: http://developer.piwik.org/guides/tracking-javascript-guide#multiple-piwik-trackers')}}r[d]++}}for(t=0;t<_paq.length;t++){if(_paq[t]){R(_paq[t])}}_paq=new v();c={addPlugin:function(W,X){a[W]=X +},getTracker:function(W,X){if(!w(X)){X=this.getAsyncTracker().getSiteId()}if(!w(W)){W=this.getAsyncTracker().getTrackerUrl()}return new D(W,X)},getAsyncTracker:function(){return L}};if(typeof define==="function"&&define.amd){define("piwik",[],function(){return c})}return c}())}if(window&&window.piwikAsyncInit){window.piwikAsyncInit()}(function(){var a=(typeof AnalyticsTracker);if(a==="undefined"){AnalyticsTracker=Piwik}}());if(typeof piwik_log!=="function"){piwik_log=function(b,f,d,g){function a(h){try{return eval("piwik_"+h)}catch(i){}return}var c,e=Piwik.getTracker(d,f);e.setDocumentTitle(b);e.setCustomData(g);c=a("tracker_pause");if(c){e.setLinkTrackingTimer(c)}c=a("download_extensions");if(c){e.setDownloadExtensions(c)}c=a("hosts_alias");if(c){e.setDomains(c)}c=a("ignore_classes");if(c){e.setIgnoreClasses(c)}e.trackPageView();if(a("install_tracker")){piwik_track=function(i,k,j,h){e.setSiteId(k);e.setTrackerUrl(j);e.trackLink(i,h)};e.enableLinkTracking()}}; /*! @license-end */ };
\ No newline at end of file diff --git a/plugins/Live/API.php b/plugins/Live/API.php index ed11c6c277..9fc5b82b16 100644 --- a/plugins/Live/API.php +++ b/plugins/Live/API.php @@ -60,13 +60,56 @@ class API extends \Piwik\Plugin\API * @param int $idSite Id Site * @param int $lastMinutes Number of minutes to look back at * @param bool|string $segment + * @param array $showColumns The columns to show / not to request. Eg 'visits', 'actions', ... + * @param array $hideColumns The columns to hide / not to request. Eg 'visits', 'actions', ... * @return array( visits => N, actions => M, visitsConverted => P ) */ - public function getCounters($idSite, $lastMinutes, $segment = false) + public function getCounters($idSite, $lastMinutes, $segment = false, $showColumns = array(), $hideColumns = array()) { Piwik::checkUserHasViewAccess($idSite); $model = new Model(); - return $model->queryCounters($idSite, $lastMinutes, $segment); + + $counters = array(); + + $hasVisits = true; + if ($this->shouldColumnBePresentInResponse('visits', $showColumns, $hideColumns)) { + $counters['visits'] = $model->getNumVisits($idSite, $lastMinutes, $segment); + $hasVisits = !empty($counters['visits']); + } + + if ($this->shouldColumnBePresentInResponse('actions', $showColumns, $hideColumns)) { + if ($hasVisits) { + $counters['actions'] = $model->getNumActions($idSite, $lastMinutes, $segment); + } else { + $counters['actions'] = 0; + } + } + + if ($this->shouldColumnBePresentInResponse('visitors', $showColumns, $hideColumns)) { + if ($hasVisits) { + $counters['visitors'] = $model->getNumVisitors($idSite, $lastMinutes, $segment); + } else { + $counters['visitors'] = 0; + } + } + + if ($this->shouldColumnBePresentInResponse('visitsConverted', $showColumns, $hideColumns)) { + if ($hasVisits) { + $counters['visitsConverted'] = $model->getNumVisitsConverted($idSite, $lastMinutes, $segment); + } else { + $counters['visitsConverted'] = 0; + } + } + + return array($counters); + } + + private function shouldColumnBePresentInResponse($column, $showColumns, $hideColumns) + { + $show = (empty($showColumns) || in_array($column, $showColumns)); + $hide = in_array($column, $hideColumns); + + return $show && !$hide; } /** diff --git a/plugins/Live/Controller.php b/plugins/Live/Controller.php index 421a0afb62..a2d3e44026 100644 --- a/plugins/Live/Controller.php +++ b/plugins/Live/Controller.php @@ -88,9 +88,9 @@ class Controller extends \Piwik\Plugin\Controller private function setCounters($view) { $segment = Request::getRawSegmentFromRequest(); - $last30min = API::getInstance()->getCounters($this->idSite, $lastMinutes = 30, $segment); + $last30min = API::getInstance()->getCounters($this->idSite, $lastMinutes = 30, $segment, array('visits', 'actions')); $last30min = $last30min[0]; - $today = API::getInstance()->getCounters($this->idSite, $lastMinutes = 24 * 60, $segment); + $today = API::getInstance()->getCounters($this->idSite, $lastMinutes = 24 * 60, $segment, array('visits', 'actions')); $today = $today[0]; $view->visitorsCountHalfHour = $last30min['visits']; $view->visitorsCountToday = $today['visits']; diff --git a/plugins/Live/Model.php b/plugins/Live/Model.php index 19a44ba1d6..0d1b0318fe 100644 --- a/plugins/Live/Model.php +++ b/plugins/Live/Model.php @@ -201,58 +201,101 @@ class Model * @param $idSite * @param $lastMinutes * @param $segment - * @return array + * @return int * @throws Exception */ - public function queryCounters($idSite, $lastMinutes, $segment) + public function getNumActions($idSite, $lastMinutes, $segment) { - $lastMinutes = (int)$lastMinutes; + return $this->getLastMinutesCounterForQuery( + $idSite, + $lastMinutes, + $segment, + 'COUNT(*)', + 'log_link_visit_action', + 'log_link_visit_action.server_time >= ?' + ); + } - $counters = array( - 'visits' => 0, - 'actions' => 0, - 'visitors' => 0, - 'visitsConverted' => 0, + /** + * @param $idSite + * @param $lastMinutes + * @param $segment + * @return int + * @throws Exception + */ + public function getNumVisitsConverted($idSite, $lastMinutes, $segment) + { + return $this->getLastMinutesCounterForQuery( + $idSite, + $lastMinutes, + $segment, + 'COUNT(*)', + 'log_conversion', + 'log_conversion.server_time >= ?' ); + } + + /** + * @param $idSite + * @param $lastMinutes + * @param $segment + * @return int + * @throws Exception + */ + public function getNumVisits($idSite, $lastMinutes, $segment) + { + return $this->getLastMinutesCounterForQuery( + $idSite, + $lastMinutes, + $segment, + 'COUNT(log_visit.visit_last_action_time)', + 'log_visit', + 'log_visit.visit_last_action_time >= ?' + ); + } + + /** + * @param $idSite + * @param $lastMinutes + * @param $segment + * @return int + * @throws Exception + */ + public function getNumVisitors($idSite, $lastMinutes, $segment) + { + return $this->getLastMinutesCounterForQuery( + $idSite, + $lastMinutes, + $segment, + 'COUNT(DISTINCT log_visit.idvisitor)', + 'log_visit', + 'log_visit.visit_last_action_time >= ?' + ); + } + + private function getLastMinutesCounterForQuery($idSite, $lastMinutes, $segment, $select, $from, $where) + { + $lastMinutes = (int)$lastMinutes; if (empty($lastMinutes)) { - return array($counters); + return 0; } - list($whereIdSites, $idSites) = $this->getIdSitesWhereClause($idSite); + list($whereIdSites, $idSites) = $this->getIdSitesWhereClause($idSite, $from); - $select = "count(*) as visits, COUNT(DISTINCT log_visit.idvisitor) as visitors"; - $where = $whereIdSites . "AND log_visit.visit_last_action_time >= ?"; - $bind = $idSites; + $bind = $idSites; $bind[] = Date::factory(time() - $lastMinutes * 60)->toString('Y-m-d H:i:s'); - $segment = new Segment($segment, $idSite); - $query = $segment->getSelectQuery($select, 'log_visit', $where, $bind); - - $data = Db::fetchAll($query['sql'], $query['bind']); - - $counters['visits'] = $data[0]['visits']; - $counters['visitors'] = $data[0]['visitors']; + $where = $whereIdSites . "AND " . $where; - $select = "count(*)"; - $from = 'log_link_visit_action'; - list($whereIdSites) = $this->getIdSitesWhereClause($idSite, $from); - $where = $whereIdSites . "AND log_link_visit_action.server_time >= ?"; - $query = $segment->getSelectQuery($select, $from, $where, $bind); - $counters['actions'] = Db::fetchOne($query['sql'], $query['bind']); + $segment = new Segment($segment, $idSite); + $query = $segment->getSelectQuery($select, $from, $where, $bind); - $select = "count(*)"; - $from = 'log_conversion'; - list($whereIdSites) = $this->getIdSitesWhereClause($idSite, $from); - $where = $whereIdSites . "AND log_conversion.server_time >= ?"; - $query = $segment->getSelectQuery($select, $from, $where, $bind); - $counters['visitsConverted'] = Db::fetchOne($query['sql'], $query['bind']); + $numVisitors = Db::fetchOne($query['sql'], $query['bind']); - return array($counters); + return $numVisitors; } - - /** * @param $idSite * @param string $table diff --git a/plugins/Live/Reports/GetSimpleLastVisitCount.php b/plugins/Live/Reports/GetSimpleLastVisitCount.php index 34ba773fa9..e2a17135c5 100644 --- a/plugins/Live/Reports/GetSimpleLastVisitCount.php +++ b/plugins/Live/Reports/GetSimpleLastVisitCount.php @@ -30,7 +30,8 @@ class GetSimpleLastVisitCount extends Base { $lastMinutes = Config::getInstance()->General[Controller::SIMPLE_VISIT_COUNT_WIDGET_LAST_MINUTES_CONFIG_KEY]; - $lastNData = Request::processRequest('Live.getCounters', array('lastMinutes' => $lastMinutes)); + $params = array('lastMinutes' => $lastMinutes, 'showColumns' => array('visits', 'visitors', 'actions')); + $lastNData = Request::processRequest('Live.getCounters', $params); $formatter = new Formatter(); diff --git a/plugins/Live/tests/System/APITest.php b/plugins/Live/tests/System/APITest.php index 2c85088a19..4b65a5ae4e 100644 --- a/plugins/Live/tests/System/APITest.php +++ b/plugins/Live/tests/System/APITest.php @@ -70,6 +70,38 @@ class APITest extends SystemTestCase $this->assertEquals($this->buildCounter(0, 0, 0, 0), $counters); } + public function test_GetCounters_ShouldHideAllColumnsIfRequested() + { + $exampleCounter = $this->buildCounter(0, 0, 0, 0); + $counters = $this->api->getCounters($this->idSite, 5, false, array(), array_keys($exampleCounter[0])); + $this->assertEquals(array(array()), $counters); + } + + public function test_GetCounters_ShouldHideSomeColumnsIfRequested() + { + $counters = $this->api->getCounters($this->idSite, 20, false, array(), array('visitsConverted', 'visitors')); + $this->assertEquals(array(array('visits' => 24, 'actions' => 60)), $counters); + } + + public function test_GetCounters_ShouldShowAllColumnsIfRequested() + { + $counter = $this->buildCounter(24, 60, 20, 40); + $counters = $this->api->getCounters($this->idSite, 20, false, array_keys($counter[0])); + $this->assertEquals($counter, $counters); + } + + public function test_GetCounters_ShouldShowSomeColumnsIfRequested() + { + $counters = $this->api->getCounters($this->idSite, 20, false, array('visits', 'actions')); + $this->assertEquals(array(array('visits' => 24, 'actions' => 60)), $counters); + } + + public function test_GetCounters_ShouldHideColumnIfGivenInShowAndHide() + { + $counters = $this->api->getCounters($this->idSite, 20, false, array('visits', 'actions'), array('actions')); + $this->assertEquals(array(array('visits' => 24)), $counters); + } + private function trackSomeVisits() { $nowTimestamp = time(); diff --git a/tests/UI/expected-ui-screenshots b/tests/UI/expected-ui-screenshots -Subproject 75ef889b855f7b410e6778702ee0a4dc10cabf6 +Subproject a214a89b26cd11c12c7544d624a017a502f83ed diff --git a/tests/javascript/index.php b/tests/javascript/index.php index 20fade48ea..072dd42538 100644 --- a/tests/javascript/index.php +++ b/tests/javascript/index.php @@ -2370,7 +2370,7 @@ function PiwikTest() { } test("User ID and Visitor UUID", function() { - expect(16); + expect(19); deleteCookies(); var userIdString = 'userid@mydomain.org'; @@ -2396,6 +2396,13 @@ function PiwikTest() { var visitorId = tracker.getVisitorId(); equal(visitorId, tracker.getVisitorId(), "Visitor ID is the same when called multiple times"); + // Check that setting an empty user id will not change the visitor ID + var userId = ''; + equal(userId, tracker.getUserId(), "by default user ID is set to empty string"); + tracker.setUserId(userId); + equal(userId, tracker.getUserId(), "after setting to empty string, user id is still empty"); + equal(visitorId, tracker.getVisitorId(), "visitor id was not changed after setting empty user id"); + // Building another 'tracker2' object so we can compare behavior to 'tracker' var tracker2 = Piwik.getTracker(); equal(tracker.getVisitorId(), tracker2.getVisitorId(), "Visitor ID " + tracker.getVisitorId() + " is the same as Visitor ID 2 " + tracker2.getVisitorId()); |