diff options
58 files changed, 1217 insertions, 1863 deletions
diff --git a/core/CliMulti/Process.php b/core/CliMulti/Process.php index e798b1faba..fbb57cd0a0 100644 --- a/core/CliMulti/Process.php +++ b/core/CliMulti/Process.php @@ -155,8 +155,9 @@ class Process private static function returnsSuccessCode($command) { - system($command . ' > /dev/null 2>&1', $returnCode); - + $exec = $command . ' > /dev/null 2>&1 & echo $?'; + $returnCode = shell_exec($exec); + $returnCode = trim($returnCode); return 0 == (int) $returnCode; } diff --git a/core/CronArchive.php b/core/CronArchive.php index 40866d2983..bbc1ae3c08 100644 --- a/core/CronArchive.php +++ b/core/CronArchive.php @@ -90,7 +90,7 @@ Notes: const OPTION_ARCHIVING_FINISHED_TS = "LastCompletedFullArchiving"; // Show only first N characters from Piwik API output in case of errors - const TRUNCATE_ERROR_MESSAGE_SUMMARY = 4000 ; + const TRUNCATE_ERROR_MESSAGE_SUMMARY = 6000; // archiving will be triggered on all websites with traffic in the last $shouldArchiveOnlySitesWithTrafficSince seconds private $shouldArchiveOnlySitesWithTrafficSince; @@ -1007,7 +1007,7 @@ Notes: private function logInitInfo() { $this->logSection("INIT"); - $this->log("Querying Piwik API at: {$this->piwikUrl}"); + $this->log("Piwik is installed at: {$this->piwikUrl}"); $this->log("Running Piwik " . Version::VERSION . " as Super User: " . $this->login); } diff --git a/core/DataTable/Manager.php b/core/DataTable/Manager.php index 754e28d83a..b9703c14dd 100644 --- a/core/DataTable/Manager.php +++ b/core/DataTable/Manager.php @@ -107,6 +107,24 @@ class Manager extends Singleton } /** + * Deletes all tables starting from the $firstTableId to the most recent table id except the ones that are + * supposed to be ignored. + * + * @param int[] $idsToBeIgnored + * @param int $firstTableId + */ + public function deleteTablesExceptIgnored($idsToBeIgnored, $firstTableId = 0) + { + $lastTableId = $this->getMostRecentTableId(); + + for ($index = $firstTableId; $index <= $lastTableId; $index++) { + if (!in_array($index, $idsToBeIgnored)) { + $this->deleteTable($index); + } + } + } + + /** * Remove the table from the manager (table has already been unset) * * @param int $id diff --git a/core/Twig.php b/core/Twig.php index fd266d0b7b..4da7a364f8 100644 --- a/core/Twig.php +++ b/core/Twig.php @@ -9,6 +9,7 @@ namespace Piwik; use Exception; +use Piwik\Period\Range; use Piwik\Translate; use Piwik\Visualization\Sparkline; use Piwik\View\RenderTokenParser; @@ -63,6 +64,7 @@ class Twig $this->addFilter_truncate(); $this->addFilter_notificiation(); $this->addFilter_percentage(); + $this->addFilter_prettyDate(); $this->twig->addFilter(new Twig_SimpleFilter('implode', 'implode')); $this->twig->addFilter(new Twig_SimpleFilter('ucwords', 'ucwords')); @@ -187,6 +189,14 @@ class Twig $this->twig->addFilter($notificationFunction); } + protected function addFilter_prettyDate() + { + $prettyDate = new Twig_SimpleFilter('prettyDate', function ($dateString, $period) { + return Range::factory($period, $dateString)->getLocalizedShortString(); + }); + $this->twig->addFilter($prettyDate); + } + protected function addFilter_percentage() { $percentage = new Twig_SimpleFilter('percentage', function ($string, $totalValue, $precision = 1) { diff --git a/core/Version.php b/core/Version.php index e19532f099..46b8de03c4 100644 --- a/core/Version.php +++ b/core/Version.php @@ -21,5 +21,5 @@ final class Version * The current Piwik version. * @var string */ - const VERSION = '2.1-rc9'; + const VERSION = '2.1.1-b1'; } diff --git a/js/piwik.js b/js/piwik.js index 5fbee7b4ff..1cbcef4da9 100644 --- a/js/piwik.js +++ b/js/piwik.js @@ -1094,7 +1094,7 @@ if (typeof Piwik !== 'object') { configTitle = documentAlias.title, // Extensions to be treated as download links - configDownloadExtensions = '7z|aac|apk|ar[cj]|as[fx]|avi|bin|csv|deb|dmg|docx?|exe|flv|gif|gz|gzip|hqx|jar|jpe?g|js|mp(2|3|4|e?g)|mov(ie)?|ms[ip]|od[bfgpst]|og[gv]|pdf|phps|png|pptx?|qtm?|ra[mr]?|rpm|sea|sit|tar|t?bz2?|tgz|torrent|txt|wav|wm[av]|wpd||xlsx?|xml|z|zip', + configDownloadExtensions = '7z|aac|apk|ar[cj]|as[fx]|avi|azw3|bin|csv|deb|dmg|docx?|epub|exe|flv|gif|gz|gzip|hqx|jar|jpe?g|js|mobi|mp(2|3|4|e?g)|mov(ie)?|ms[ip]|od[bfgpst]|og[gv]|pdf|phps|png|pptx?|qtm?|ra[mr]?|rpm|sea|sit|tar|t?bz2?|tgz|torrent|txt|wav|wm[av]|wpd||xlsx?|xml|z|zip', // Hosts or alias(es) to not treat as outlinks configHostsAlias = [domainAlias], diff --git a/misc/log-analytics/import_logs.py b/misc/log-analytics/import_logs.py index df2e437476..6b8cdee560 100755 --- a/misc/log-analytics/import_logs.py +++ b/misc/log-analytics/import_logs.py @@ -63,6 +63,7 @@ DOWNLOAD_EXTENSIONS = ( 'jar mpg mp2 mp3 mp4 mpeg mov movie msi msp odb odf odg odp ' 'ods odt ogg ogv pdf phps ppt qt qtm ra ram rar rpm sea sit tar tbz ' 'bz2 tbz tgz torrent txt wav wma wmv wpd xls xml xsd z zip' + 'azw3 epub mobi' ).split() @@ -14,7 +14,7 @@ return typeof f==="function"?m({"":n},""):n}throw new SyntaxError("JSON2.parse") }while(O.getTimeAlias()<h)}}function I(){var O;if(!m){m=true;H("load");for(O=0;O<y.length;O++){y[O]()}}return true}function l(){var P;if(q.addEventListener){M(q,"DOMContentLoaded",function O(){q.removeEventListener("DOMContentLoaded",O,false);I()})}else{if(q.attachEvent){q.attachEvent("onreadystatechange",function O(){if(q.readyState==="complete"){q.detachEvent("onreadystatechange",O);I()}});if(q.documentElement.doScroll&&A===A.top){(function O(){if(!m){try{q.documentElement.doScroll("left")}catch(Q){setTimeout(O,0);return}I()}}())}}}if((new RegExp("WebKit")).test(d.userAgent)){P=setInterval(function(){if(m||/loaded|complete/.test(q.readyState)){clearInterval(P);I()}},10)}M(A,"load",I,false)}function g(Q,P){var O=q.createElement("script");O.type="text/javascript";O.src=Q;if(O.readyState){O.onreadystatechange=function(){var R=this.readyState;if(R==="loaded"||R==="complete"){O.onreadystatechange=null;P()}}}else{O.onload=P}q.getElementsByTagName("head")[0].appendChild(O)}function t(){var O=""; try{O=A.top.document.referrer}catch(Q){if(A.parent){try{O=A.parent.document.referrer}catch(P){O=""}}}if(O===""){O=q.referrer}return O}function i(O){var Q=new RegExp("^([a-z]+):"),P=Q.exec(O);return P?P[1]:null}function b(O){var Q=new RegExp("^(?:(?:https?|ftp):)/*(?:[^@]+@)?([^:/#]+)"),P=Q.exec(O);return P?P[1]:O}function B(Q,P){var O="[\\?&#]"+P+"=([^&#]*)";var S=new RegExp(O);var R=S.exec(Q);return R?z(R[1]):""}function o(O){return f(j(O))}function L(ae){var Q=function(aj,W){return(aj<<W)|(aj>>>(32-W))},af=function(al){var aj="",ak,W;for(ak=7;ak>=0;ak--){W=(al>>>(ak*4))&15;aj+=W.toString(16)}return aj},T,ah,ag,P=[],Y=1732584193,V=4023233417,U=2562383102,S=271733878,R=3285377520,ad,ac,ab,aa,Z,ai,O,X=[];ae=o(ae);O=ae.length;for(ah=0;ah<O-3;ah+=4){ag=ae.charCodeAt(ah)<<24|ae.charCodeAt(ah+1)<<16|ae.charCodeAt(ah+2)<<8|ae.charCodeAt(ah+3);X.push(ag)}switch(O&3){case 0:ah=2147483648;break;case 1:ah=ae.charCodeAt(O-1)<<24|8388608;break;case 2:ah=ae.charCodeAt(O-2)<<24|ae.charCodeAt(O-1)<<16|32768; break;case 3:ah=ae.charCodeAt(O-3)<<24|ae.charCodeAt(O-2)<<16|ae.charCodeAt(O-1)<<8|128;break}X.push(ah);while((X.length&15)!==14){X.push(0)}X.push(O>>>29);X.push((O<<3)&4294967295);for(T=0;T<X.length;T+=16){for(ah=0;ah<16;ah++){P[ah]=X[T+ah]}for(ah=16;ah<=79;ah++){P[ah]=Q(P[ah-3]^P[ah-8]^P[ah-14]^P[ah-16],1)}ad=Y;ac=V;ab=U;aa=S;Z=R;for(ah=0;ah<=19;ah++){ai=(Q(ad,5)+((ac&ab)|(~ac&aa))+Z+P[ah]+1518500249)&4294967295;Z=aa;aa=ab;ab=Q(ac,30);ac=ad;ad=ai}for(ah=20;ah<=39;ah++){ai=(Q(ad,5)+(ac^ab^aa)+Z+P[ah]+1859775393)&4294967295;Z=aa;aa=ab;ab=Q(ac,30);ac=ad;ad=ai}for(ah=40;ah<=59;ah++){ai=(Q(ad,5)+((ac&ab)|(ac&aa)|(ab&aa))+Z+P[ah]+2400959708)&4294967295;Z=aa;aa=ab;ab=Q(ac,30);ac=ad;ad=ai}for(ah=60;ah<=79;ah++){ai=(Q(ad,5)+(ac^ab^aa)+Z+P[ah]+3395469782)&4294967295;Z=aa;aa=ab;ab=Q(ac,30);ac=ad;ad=ai}Y=(Y+ad)&4294967295;V=(V+ac)&4294967295;U=(U+ab)&4294967295;S=(S+aa)&4294967295;R=(R+Z)&4294967295}ai=af(Y)+af(V)+af(U)+af(S)+af(R);return ai.toLowerCase()}function G(Q,O,P){if(Q==="translate.googleusercontent.com"){if(P===""){P=O -}O=B(O,"u");Q=b(O)}else{if(Q==="cc.bingj.com"||Q==="webcache.googleusercontent.com"||Q.slice(0,5)==="74.6."){O=q.links[0].href;Q=b(O)}}return[Q,O,P]}function u(P){var O=P.length;if(P.charAt(--O)==="."){P=P.slice(0,O)}if(P.slice(0,2)==="*."){P=P.slice(1)}return P}function N(P){P=P&&P.text?P.text:P;if(!k(P)){var O=q.getElementsByTagName("title");if(O&&s(O[0])){P=O[0].text}}return P}function w(O,P){if(P){return P}if(O.slice(-9)==="piwik.php"){O=O.slice(0,O.length-9)}return O}function v(S){var O="Piwik_Overlay";var V=new RegExp("index\\.php\\?module=Overlay&action=startOverlaySession&idSite=([0-9]+)&period=([^&]+)&date=([^&]+)$");var Q=V.exec(q.referrer);if(Q){var R=Q[1];if(R!==String(S)){return false}var U=Q[2],P=Q[3];A.name=O+"###"+U+"###"+P}var T=A.name.split("###");return T.length===3&&T[0]===O}function F(P,U,R){var T=A.name.split("###"),S=T[1],O=T[2],Q=w(P,U);g(Q+"plugins/Overlay/client/client.js?v=1",function(){Piwik_Overlay_Client.initialize(Q,R,S,O)})}function x(am,aN){var U=G(q.domain,A.location.href,t()),a7=u(U[0]),bm=U[1],aU=U[2],aS="GET",S=am||"",aj="",aP="",bc=aN||"",aE,au=q.title,aw="7z|aac|apk|ar[cj]|as[fx]|avi|bin|csv|deb|dmg|docx?|exe|flv|gif|gz|gzip|hqx|jar|jpe?g|js|mp(2|3|4|e?g)|mov(ie)?|ms[ip]|od[bfgpst]|og[gv]|pdf|phps|png|pptx?|qtm?|ra[mr]?|rpm|sea|sit|tar|t?bz2?|tgz|torrent|txt|wav|wm[av]|wpd||xlsx?|xml|z|zip",aQ=[a7],X=[],aI=[],al=[],aO=500,Y,an,Z,ab,ay=["pk_campaign","piwik_campaign","utm_campaign","utm_source","utm_medium"],at=["pk_kwd","piwik_kwd","utm_term"],bk="_pk_",ae,bl,ac=false,bf,aA,aD,ai=63072000000,ak=1800000,aF=15768000000,aB=true,ap=0,W=false,aJ={},T={},bg=200,a0={},bd={},aX=false,aV=false,aT,aK,af,ax=L,aW,aC; +}O=B(O,"u");Q=b(O)}else{if(Q==="cc.bingj.com"||Q==="webcache.googleusercontent.com"||Q.slice(0,5)==="74.6."){O=q.links[0].href;Q=b(O)}}return[Q,O,P]}function u(P){var O=P.length;if(P.charAt(--O)==="."){P=P.slice(0,O)}if(P.slice(0,2)==="*."){P=P.slice(1)}return P}function N(P){P=P&&P.text?P.text:P;if(!k(P)){var O=q.getElementsByTagName("title");if(O&&s(O[0])){P=O[0].text}}return P}function w(O,P){if(P){return P}if(O.slice(-9)==="piwik.php"){O=O.slice(0,O.length-9)}return O}function v(S){var O="Piwik_Overlay";var V=new RegExp("index\\.php\\?module=Overlay&action=startOverlaySession&idSite=([0-9]+)&period=([^&]+)&date=([^&]+)$");var Q=V.exec(q.referrer);if(Q){var R=Q[1];if(R!==String(S)){return false}var U=Q[2],P=Q[3];A.name=O+"###"+U+"###"+P}var T=A.name.split("###");return T.length===3&&T[0]===O}function F(P,U,R){var T=A.name.split("###"),S=T[1],O=T[2],Q=w(P,U);g(Q+"plugins/Overlay/client/client.js?v=1",function(){Piwik_Overlay_Client.initialize(Q,R,S,O)})}function x(am,aN){var U=G(q.domain,A.location.href,t()),a7=u(U[0]),bm=U[1],aU=U[2],aS="GET",S=am||"",aj="",aP="",bc=aN||"",aE,au=q.title,aw="7z|aac|apk|ar[cj]|as[fx]|avi|azw3|bin|csv|deb|dmg|docx?|epub|exe|flv|gif|gz|gzip|hqx|jar|jpe?g|js|mobi|mp(2|3|4|e?g)|mov(ie)?|ms[ip]|od[bfgpst]|og[gv]|pdf|phps|png|pptx?|qtm?|ra[mr]?|rpm|sea|sit|tar|t?bz2?|tgz|torrent|txt|wav|wm[av]|wpd||xlsx?|xml|z|zip",aQ=[a7],X=[],aI=[],al=[],aO=500,Y,an,Z,ab,ay=["pk_campaign","piwik_campaign","utm_campaign","utm_source","utm_medium"],at=["pk_kwd","piwik_kwd","utm_term"],bk="_pk_",ae,bl,ac=false,bf,aA,aD,ai=63072000000,ak=1800000,aF=15768000000,aB=true,ap=0,W=false,aJ={},T={},bg=200,a0={},bd={},aX=false,aV=false,aT,aK,af,ax=L,aW,aC; function a2(bv,bs,br,bu,bq,bt){if(ac){return}var bp;if(br){bp=new Date();bp.setTime(bp.getTime()+br)}q.cookie=bv+"="+j(bs)+(br?";expires="+bp.toGMTString():"")+";path="+(bu||"/")+(bq?";domain="+bq:"")+(bt?";secure":"")}function ah(br){if(ac){return 0}var bp=new RegExp("(^|;)[ ]*"+br+"=([^;]*)"),bq=bp.exec(q.cookie);return bq?z(bq[2]):0}function bh(bp){var bq;if(Z){bq=new RegExp("#.*");return bp.replace(bq,"")}return bp}function a6(br,bp){var bs=i(bp),bq;if(bs){return bp}if(bp.slice(0,1)==="/"){return i(br)+"://"+b(br)+bp}br=bh(br);bq=br.indexOf("?");if(bq>=0){br=br.slice(0,bq)}bq=br.lastIndexOf("/");if(bq!==br.length-1){br=br.slice(0,bq+1)}return br+bp}function aR(bs){var bq,bp,br;for(bq=0;bq<aQ.length;bq++){bp=u(aQ[bq].toLowerCase());if(bs===bp){return true}if(bp.slice(0,1)==="."){if(bs===bp.slice(1)){return true}br=bs.length-bp.length;if((br>0)&&(bs.slice(br)===bp)){return true}}}return false}function bo(bp){var bq=new Image(1,1);bq.onload=function(){p=0};bq.src=S+(S.indexOf("?")<0?"?":"&")+bp }function a3(bp){try{var br=A.XMLHttpRequest?new A.XMLHttpRequest():A.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):null;br.open("POST",S,true);br.onreadystatechange=function(){if(this.readyState===4&&this.status!==200){bo(bp)}};br.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");br.send(bp)}catch(bq){bo(bp)}}function az(br,bq){var bp=new Date();if(!bf){if(aS==="POST"){a3(br)}else{bo(br)}h=bp.getTime()+bq}}function a1(bp){return bk+bp+"."+bc+"."+aW}function V(){if(ac){return"0"}if(!s(d.cookieEnabled)){var bp=a1("testcookie");a2(bp,"1");return ah(bp)==="1"?"1":"0"}return d.cookieEnabled?"1":"0"}function aL(){aW=ax((ae||a7)+(bl||"/")).slice(0,4)}function ag(){var bq=a1("cvar"),bp=ah(bq);if(bp.length){bp=JSON2.parse(bp);if(C(bp)){return bp}}return{}}function R(){if(W===false){W=ag()}}function bb(){var bp=new Date();aT=bp.getTime()}function ad(bt,bq,bp,bs,br,bu){a2(a1("id"),bt+"."+bq+"."+bp+"."+bs+"."+br+"."+bu,ai,bl,ae)}function Q(){var bq=new Date(),bp=Math.round(bq.getTime()/1000),bs=ah(a1("id")),br; if(bs){br=bs.split(".");br.unshift("0")}else{if(!aC){aC=ax((d.userAgent||"")+(d.platform||"")+JSON2.stringify(bd)+bq.getTime()+Math.random()).slice(0,16)}br=["1",aC,bp,0,bp,"",""]}return br}function O(){var bp=ah(a1("ref"));if(bp.length){try{bp=JSON2.parse(bp);if(C(bp)){return bp}}catch(bq){}}return["","",0,""]}function P(){var bp=ac;ac=false;a2(a1("id"),"",-86400,bl,ae);a2(a1("ses"),"",-86400,bl,ae);a2(a1("cvar"),"",-86400,bl,ae);a2(a1("ref"),"",-86400,bl,ae);ac=bp}function ba(bt){if(!bt||!C(bt)){return}var bs=[];var br;for(br in bt){if(Object.prototype.hasOwnProperty.call(bt,br)){bs.push(br)}}var bu={};bs.sort();var bp=bs.length;var bq;for(bq=0;bq<bp;bq++){bu[bs[bq]]=bt[bs[bq]]}return bu}function av(br,bP,bQ,bs){var bN,bq=new Date(),bz=Math.round(bq.getTime()/1000),bT,bO,bu,bF,bK,by,bI,bv,bM,bt=1024,bV,bC,bJ=W,bA=a1("ses"),bB=a1("ref"),bW=a1("cvar"),bG=Q(),bE=ah(bA),bL=O(),bS=aE||bm,bw,bp;if(ac){P()}if(bf){return""}bT=bG[0];bO=bG[1];bF=bG[2];bu=bG[3];bK=bG[4];by=bG[5];if(!s(bG[6])){bG[6]="" diff --git a/plugins/Actions/javascripts/actionsDataTable.js b/plugins/Actions/javascripts/actionsDataTable.js index d48b8dc8e9..e41e42f473 100644 --- a/plugins/Actions/javascripts/actionsDataTable.js +++ b/plugins/Actions/javascripts/actionsDataTable.js @@ -242,7 +242,7 @@ } } }); - + var table = $(domElem); if (!table.hasClass('dataTable')) { table = table.closest('.dataTable'); @@ -250,6 +250,8 @@ if (stripingNeeded) { self.addOddAndEvenClasses(table); } + + self.$element.trigger('piwik:actionsSubTableToggled'); } // toggle the +/- image @@ -278,6 +280,9 @@ $('.datatableRelatedReports', content).replaceWith(oldReportsElem); dataTableSel.replaceWith(content); + + content.trigger('piwik:dataTableLoaded'); + piwikHelper.lazyScrollTo(content[0], 400); return content; @@ -311,6 +316,8 @@ // we execute the bindDataTableEvent function for the new DIV self.bindEventsAndApplyStyle($('#' + self.workingDivId), response); + self.$element.trigger('piwik:actionsSubDataTableLoaded'); + //bind back the click event (disabled to avoid double-click problem) self.disabledRowDom.click( function () { diff --git a/plugins/CoreHome/javascripts/dataTable.js b/plugins/CoreHome/javascripts/dataTable.js index 6d80487d32..1148ecadd2 100644 --- a/plugins/CoreHome/javascripts/dataTable.js +++ b/plugins/CoreHome/javascripts/dataTable.js @@ -252,6 +252,8 @@ $.extend(DataTable.prototype, UIControl.prototype, { dataTableSel.replaceWith(content); } + content.trigger('piwik:dataTableLoaded'); + piwikHelper.lazyScrollTo(content[0], 400); return content; diff --git a/plugins/CoreUpdater/Controller.php b/plugins/CoreUpdater/Controller.php index f9369896fb..3e8981d07a 100644 --- a/plugins/CoreUpdater/Controller.php +++ b/plugins/CoreUpdater/Controller.php @@ -332,7 +332,7 @@ class Controller extends \Piwik\Plugin\Controller private function doWelcomeUpdates($view, $componentsWithUpdateFile) { $view->new_piwik_version = Version::VERSION; - $view->commandUpgradePiwik = "<br /><code>php " . Filesystem::getPathToPiwikRoot() . "/index.php -- \"module=CoreUpdater\" </code>"; + $view->commandUpgradePiwik = "<br /><code>php " . Filesystem::getPathToPiwikRoot() . "/console core:update </code>"; $pluginNamesToUpdate = array(); $coreToUpdate = false; diff --git a/plugins/Dashboard/Dashboard.php b/plugins/Dashboard/Dashboard.php index 94fbbf6b86..4fe9d81f2b 100644 --- a/plugins/Dashboard/Dashboard.php +++ b/plugins/Dashboard/Dashboard.php @@ -204,12 +204,11 @@ class Dashboard extends \Piwik\Plugin $login = Piwik::getCurrentUserLogin(); $dashboards = $this->getAllDashboards($login); - if (count($dashboards) > 1) { - $pos = 0; - foreach ($dashboards AS $dashboard) { - MenuMain::getInstance()->add('Dashboard_Dashboard', $dashboard['name'], array('module' => 'Dashboard', 'action' => 'embeddedIndex', 'idDashboard' => $dashboard['iddashboard']), true, $pos); - $pos++; - } + + $pos = 0; + foreach ($dashboards as $dashboard) { + MenuMain::getInstance()->add('Dashboard_Dashboard', $dashboard['name'], array('module' => 'Dashboard', 'action' => 'embeddedIndex', 'idDashboard' => $dashboard['iddashboard']), true, $pos); + $pos++; } } } diff --git a/plugins/Dashboard/javascripts/dashboard.js b/plugins/Dashboard/javascripts/dashboard.js index 3a2bddf258..85e8d37cf0 100644 --- a/plugins/Dashboard/javascripts/dashboard.js +++ b/plugins/Dashboard/javascripts/dashboard.js @@ -196,7 +196,7 @@ function copyDashboardToUser() { } }; - $('body')[0].addEventListener('mouseup', this.onBodyMouseUp); + $('body').on('mouseup', this.onBodyMouseUp); // setup widgetPreview this.$element.widgetPreview({ @@ -224,7 +224,7 @@ function copyDashboardToUser() { _destroy: function () { UIControl.prototype._destroy.call(this); - $('body')[0].removeEventListener('mouseup', this.onBodyMouseUp); + $('body').off('mouseup', null, this.onBodyMouseUp); } }); diff --git a/plugins/Dashboard/javascripts/dashboardObject.js b/plugins/Dashboard/javascripts/dashboardObject.js index fec02213d5..86af47f54f 100644 --- a/plugins/Dashboard/javascripts/dashboardObject.js +++ b/plugins/Dashboard/javascripts/dashboardObject.js @@ -490,7 +490,6 @@ * @param {string} [action] action to perform (defaults to saveLayout) */ function saveLayout(action) { - var columns = []; var columnNumber = 0; diff --git a/plugins/Dashboard/javascripts/dashboardWidget.js b/plugins/Dashboard/javascripts/dashboardWidget.js index 33d073d95c..ba06765026 100755 --- a/plugins/Dashboard/javascripts/dashboardWidget.js +++ b/plugins/Dashboard/javascripts/dashboardWidget.js @@ -36,7 +36,8 @@ onRemove: null, onRefresh: null, onMaximise: null, - onMinimise: null + onMinimise: null, + autoMaximiseVisualizations: ['tableAllColumns', 'tableGoals'] }, /** @@ -144,7 +145,9 @@ * @param {object} parameters */ setParameters: function (parameters) { - if (!this.isMaximised && (parameters.viewDataTable == 'tableAllColumns' || parameters.viewDataTable == 'tableGoals')) { + if (!this.isMaximised + && this.options.autoMaximiseVisualizations.indexOf(parameters.viewDataTable) !== -1 + ) { this.maximise(); } for (var name in parameters) { diff --git a/plugins/Insights/API.php b/plugins/Insights/API.php index f29d301c7a..0305caaf8a 100644 --- a/plugins/Insights/API.php +++ b/plugins/Insights/API.php @@ -27,43 +27,70 @@ class API extends \Piwik\Plugin\API const FILTER_BY_NEW = 'new'; const FILTER_BY_MOVERS = 'movers'; const FILTER_BY_DISAPPEARED = 'disappeared'; - const ORDER_BY_RELATIVE = 'relative'; - const ORDER_BY_ABSOLUTE = 'absolute'; - const ORDER_BY_IMPORTANCE = 'importance'; - public function getInsightsOverview($idSite, $period, $date) + /** + * @var Model + */ + private $model; + + private $reportIds = array( + 'Actions_getPageUrls', + 'Actions_getPageTitles', + 'Actions_getDownloads', + 'Referrers_getAll', + 'Referrers_getKeywords', + 'Referrers_getCampaigns', + 'Referrers_getSocials', + 'Referrers_getSearchEngines', + 'UserCountry_getCountry', + ); + + protected function __construct() + { + parent::__construct(); + + $this->model = new Model(); + } + + public function getInsightsOverview($idSite, $period, $date, $segment = false) { Piwik::checkUserHasViewAccess(array($idSite)); - /** @var DataTable[] $tables */ - $reports = array( - 'Actions_getPageUrls', - 'Actions_getPageTitles', - 'Actions_getDownloads', - 'Referrers_getAll', - 'Referrers_getKeywords', - 'Referrers_getCampaigns', - 'Referrers_getSocials', - 'Referrers_getSearchEngines', - 'UserCountry_getCountry', - ); - // post event to add other reports? - - $reportTableIds = array(); - $dataTableManager = DataTable\Manager::getInstance(); + $reportTableIds = array(); + /** @var DataTable[] $tables */ $tables = array(); - foreach ($reports as $report) { - $firstTableId = $dataTableManager->getMostRecentTableId(); - $table = $this->getInsightOverview($idSite, $period, $date, $report); + foreach ($this->reportIds as $reportId) { + $firstTableId = DataTable\Manager::getInstance()->getMostRecentTableId(); + $table = $this->getInsights($idSite, $period, $date, $reportId, $segment, 3, 3, '', 2, 25); $reportTableIds[] = $table->getId(); - $lastTableId = $dataTableManager->getMostRecentTableId(); + DataTable\Manager::getInstance()->deleteTablesExceptIgnored($reportTableIds, $firstTableId); + + $tables[] = $table; + } + + $map = new DataTable\Map(); + + foreach ($tables as $table) { + $map->addTable($table, $table->getMetadata('reportName')); + } + + return $map; + } - for ($index = $firstTableId; $index <= $lastTableId; $index++) { - if (!in_array($index, $reportTableIds)) { - $dataTableManager->deleteTable($index); - } - } + public function getOverallMoversAndShakers($idSite, $period, $date, $segment = false) + { + Piwik::checkUserHasViewAccess(array($idSite)); + + $reportTableIds = array(); + + /** @var DataTable[] $tables */ + $tables = array(); + foreach ($this->reportIds as $reportId) { + $firstTableId = DataTable\Manager::getInstance()->getMostRecentTableId(); + $table = $this->getMoversAndShakers($idSite, $period, $date, $reportId, $segment, 4, 4); + $reportTableIds[] = $table->getId(); + DataTable\Manager::getInstance()->deleteTablesExceptIgnored($reportTableIds, $firstTableId); $tables[] = $table; } @@ -77,230 +104,76 @@ class API extends \Piwik\Plugin\API return $map; } - public function getInsightOverview($idSite, $period, $date, $reportUniqueId, $segment = false, $limitIncreaser = 4, - $limitDecreaser = 4, $minVisitsPercent = 3, $minGrowthPercent = 25, $orderBy = 'absolute', - $considerMovers = true, $considerNew = true, $considerDisappeared = false) + public function getMoversAndShakers($idSite, $period, $date, $reportUniqueId, $segment = false, + $limitIncreaser = 4, $limitDecreaser = 4) { + $orderBy = 'absolute'; + $minGrowthPercent = 30; + $minMoversPercent = 2; + $minNewPercent = 2; + $minDisappearedPercent = 2; + Piwik::checkUserHasViewAccess(array($idSite)); $metric = 'nb_visits'; - // consider disappeared if impact > 10%? - - $totalValue = $this->getTotalValue($idSite, $period, $date, $metric); - $minVisits = $this->getMinVisits($totalValue, $minVisitsPercent); - $report = $this->getReportByUniqueId($idSite, $reportUniqueId); - $currentReport = $this->requestReport($idSite, $period, $date, $report, $metric, $segment); + $reportMetadata = $this->model->getReportByUniqueId($idSite, $reportUniqueId); + $totalValue = $this->model->getTotalValue($idSite, $period, $date, $metric); + $currentReport = $this->model->requestReport($idSite, $period, $date, $reportUniqueId, $metric, $segment); if ($period === 'day') { // if website is too young, than use website creation date // for faster performance just compare against last week? - $pastDate = Date::factory($date); - $pastDate = $pastDate->subDay(7); - $lastDate = $pastDate->toString(); - $lastReport = $this->requestReport($idSite, 'week', $lastDate, $report, $metric, $segment); + $pastDate = $this->model->getLastDate($date, $period, 7); + $lastReport = $this->model->requestReport($idSite, 'week', $pastDate, $reportUniqueId, $metric, $segment); $lastReport->filter('Piwik\Plugins\Insights\DataTable\Filter\Average', array($metric, 7)); + $lastDate = Range::factory('week', $pastDate); + $lastDate = $lastDate->getRangeString(); } else { - $pastDate = Range::getLastDate($date, $period); - - if (empty($pastDate[0])) { - return new DataTable(); - } - - $lastDate = $pastDate[0]; - $lastReport = $this->requestReport($idSite, $period, $lastDate, $report, $metric, $segment); + $lastDate = $this->model->getLastDate($date, $period, 1); + $lastReport = $this->model->requestReport($idSite, $period, $lastDate, $reportUniqueId, $metric, $segment); } - return $this->buildInsightsReport($period, $date, $limitIncreaser, $limitDecreaser, $minGrowthPercent, $orderBy, $currentReport, $lastReport, $metric, $considerMovers, $considerNew, $considerDisappeared, $minVisits, $report, $lastDate, $totalValue); + $insight = new InsightReport(); + return $insight->generateInsight($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $minMoversPercent, $minNewPercent, $minDisappearedPercent, $minGrowthPercent, $orderBy, $limitIncreaser, $limitDecreaser); } - // force $limitX and ignore minVisitsPercent, minGrowthPercent public function getInsights( - $idSite, $period, $date, $reportUniqueId, $limitIncreaser = 5, $limitDecreaser = 5, - $filterBy = '', $minVisitsPercent = 2, $minGrowthPercent = 20, - $comparedToXPeriods = 1, $orderBy = 'absolute', $segment = false) + $idSite, $period, $date, $reportUniqueId, $segment = false, $limitIncreaser = 5, $limitDecreaser = 5, + $filterBy = '', $minImpactPercent = 2, $minGrowthPercent = 20, + $comparedToXPeriods = 1, $orderBy = 'absolute') { Piwik::checkUserHasViewAccess(array($idSite)); $metric = 'nb_visits'; - $report = $this->getReportByUniqueId($idSite, $reportUniqueId); - - $lastDate = Range::getDateXPeriodsAgo(abs($comparedToXPeriods), $date, $period); - $currentReport = $this->requestReport($idSite, $period, $date, $report, $metric, $segment); - $lastReport = $this->requestReport($idSite, $period, $lastDate[0], $report, $metric, $segment); + $reportMetadata = $this->model->getReportByUniqueId($idSite, $reportUniqueId); + $lastDate = $this->model->getLastDate($date, $period, $comparedToXPeriods); + $currentReport = $this->model->requestReport($idSite, $period, $date, $reportUniqueId, $metric, $segment); + $lastReport = $this->model->requestReport($idSite, $period, $lastDate, $reportUniqueId, $metric, $segment); + $totalValue = $this->model->getRelevantTotalValue($currentReport, $idSite, $period, $date, $metric); - $totalValue = $this->getRelevantTotalValue($idSite, $period, $date, $currentReport, $metric); - $minVisits = $this->getMinVisits($totalValue, $minVisitsPercent); - - $considerMovers = false; - $considerNew = false; - $considerDisappeared = false; + $minMoversPercent = -1; + $minNewPercent = -1; + $minDisappearedPercent = -1; switch ($filterBy) { case self::FILTER_BY_MOVERS: - $considerMovers = true; + $minMoversPercent = $minImpactPercent; break; case self::FILTER_BY_NEW: - $considerNew = true; + $minNewPercent = $minImpactPercent; break; case self::FILTER_BY_DISAPPEARED: - $considerDisappeared = true; + $minDisappearedPercent = $minImpactPercent; break; default: - $considerMovers = true; - $considerNew = true; - $considerDisappeared = true; - } - - return $this->buildInsightsReport($period, $date, $limitIncreaser, $limitDecreaser, $minGrowthPercent, $orderBy, $currentReport, $lastReport, $metric, $considerMovers, $considerNew, $considerDisappeared, $minVisits, $report, $lastDate[0], $totalValue); - } - - private function requestReport($idSite, $period, $date, $report, $metric, $segment) - { - $params = array( - 'method' => $report['module'] . '.' . $report['action'], - 'format' => 'original', - 'idSite' => $idSite, - 'period' => $period, - 'date' => $date, - 'filter_limit' => 1000, - 'showColumns' => $metric - ); - - if (!empty($segment)) { - $params['segment'] = $segment; + $minMoversPercent = $minImpactPercent; + $minNewPercent = $minImpactPercent; + $minDisappearedPercent = $minImpactPercent; } - if (!empty($report['parameters']) && is_array($report['parameters'])) { - $params = array_merge($params, $report['parameters']); - } - - $request = new ApiRequest($params); - $table = $request->process(); - - return $table; - } - - private function getOrderByColumn($orderBy) - { - if (self::ORDER_BY_RELATIVE == $orderBy) { - $orderByColumn = 'growth_percent_numeric'; - } elseif (self::ORDER_BY_ABSOLUTE == $orderBy) { - $orderByColumn = 'difference'; - } elseif (self::ORDER_BY_IMPORTANCE == $orderBy) { - $orderByColumn = 'importance'; - } else { - throw new \Exception('Unsupported orderBy'); - } - - return $orderByColumn; - } - - private function getMinVisits($totalValue, $minVisitsPercent) - { - $minVisits = ceil(($totalValue / 100) * $minVisitsPercent); - - return (int) $minVisits; - } - - private function getRelevantTotalValue($idSite, $period, $date, DataTable $currentReport, $metric) - { - $totalMetric = $this->getMetricTotalValue($currentReport, $metric); - $totalValue = $this->getTotalValue($idSite, $period, $date, $metric); - - if (($totalMetric * 2) < $totalValue) { - return $totalMetric; - } - - return $totalValue; - } - - private function getTotalValue($idSite, $period, $date, $metric) - { - $visits = VisitsSummaryAPI::getInstance()->get($idSite, $period, $date, false, array($metric)); - $totalValue = $visits->getFirstRow()->getColumn($metric); - return $totalValue; - } - - private function getMetricTotalValue(DataTable $currentReport, $metric) - { - $totals = $currentReport->getMetadata('totals'); - - if (!empty($totals[$metric])) { - $totalValue = (int) $totals[$metric]; - } else { - $totalValue = 0; - } - - return $totalValue; - } - - private function buildInsightsReport($period, $date, $limitIncreaser, $limitDecreaser, $minGrowthPercent, $orderBy, $currentReport, $lastReport, $metric, $considerMovers, $considerNew, $considerDisappeared, $minVisits, $report, $lastDate, $totalValue) - { - $dataTable = new DataTable(); - $dataTable->filter( - 'Piwik\Plugins\Insights\DataTable\Filter\Insight', - array( - $currentReport, - $lastReport, - $metric, - $considerMovers, - $considerNew, - $considerDisappeared - ) - ); - - $dataTable->filter( - 'Piwik\Plugins\Insights\DataTable\Filter\MinGrowth', - array( - 'growth_percent_numeric', - $minGrowthPercent - ) - ); - - $dataTable->filter( - 'Piwik\Plugins\Insights\DataTable\Filter\ExcludeLowValue', - array( - $metric, - $minVisits - ) - ); - - $dataTable->filter( - 'Piwik\Plugins\Insights\DataTable\Filter\OrderBy', - array( - $this->getOrderByColumn($orderBy) - ) - ); - - $dataTable->filter( - 'Piwik\Plugins\Insights\DataTable\Filter\Limit', - array( - 'growth_percent_numeric', - $limitIncreaser, - $limitDecreaser - ) - ); - - $dataTable->setMetadataValues(array( - 'reportName' => $report['name'], - 'metricName' => $report['metrics'][$metric], - 'date' => $date, - 'lastDate' => $lastDate, - 'period' => $period, - 'report' => $report, - 'totalValue' => $totalValue, - 'minVisits' => $minVisits - )); - - return $dataTable; - } - - private function getReportByUniqueId($idSite, $reportUniqueId) - { - $processedReport = new ProcessedReport(); - $report = $processedReport->getReportMetadataByUniqueId($idSite, $reportUniqueId); - return $report; + $insight = new InsightReport(); + return $insight->generateInsight($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $minMoversPercent, $minNewPercent, $minDisappearedPercent, $minGrowthPercent, $orderBy, $limitIncreaser, $limitDecreaser); } } diff --git a/plugins/Insights/Controller.php b/plugins/Insights/Controller.php index 8526052215..b9431f5a3c 100644 --- a/plugins/Insights/Controller.php +++ b/plugins/Insights/Controller.php @@ -18,7 +18,21 @@ use Piwik\View; class Controller extends \Piwik\Plugin\Controller { - public function getInsightOverview() + public function getInsightsOverview() + { + $view = $this->prepareWidget($apiReport = 'getInsightsOverview'); + + return $view->render(); + } + + public function getOverallMoversAndShakers() + { + $view = $this->prepareWidget($apiReport = 'getOverallMoversAndShakers'); + + return $view->render(); + } + + private function prepareWidget($apiReport) { $idSite = Common::getRequestVar('idSite', null, 'int'); $period = Common::getRequestVar('period', null, 'string'); @@ -26,18 +40,14 @@ class Controller extends \Piwik\Plugin\Controller Piwik::checkUserHasViewAccess(array($idSite)); - $view = new View('@Insights/index.twig'); + $view = new View('@Insights/overviewWidget.twig'); $this->setBasicVariablesView($view); - $view->moversAndShakers = API::getInstance()->getInsightsOverview($idSite, $period, $date); - $view->showNoDataMessage = false; - $view->showInsightsControls = false; + $view->reports = API::getInstance()->$apiReport($idSite, $period, $date); $view->properties = array( - 'show_increase' => true, - 'show_decrease' => true, 'order_by' => 'absolute' ); - return $view->render(); + return $view; } } diff --git a/plugins/Insights/DataTable/Filter/ExcludeLowValue.php b/plugins/Insights/DataTable/Filter/ExcludeLowValue.php index aea5d1d9ea..cd1ec1c1b7 100644 --- a/plugins/Insights/DataTable/Filter/ExcludeLowValue.php +++ b/plugins/Insights/DataTable/Filter/ExcludeLowValue.php @@ -14,11 +14,21 @@ class ExcludeLowValue extends DataTable\BaseFilter { private $minimumValue; private $columnToRead; + private $columnToCheckToBeTrue; - public function __construct($table, $columnToRead, $minimumValue) + /** + * @param DataTable $table + * @param string $columnToRead + * @param int $minimumValue + * @param string $columnToCheckToBeTrue if set, we will delete a row only if this column evaluates to true. If + * column does not evaluate to true we will not delete the row even if + * the value is lower than the minimumValue. + */ + public function __construct($table, $columnToRead, $minimumValue, $columnToCheckToBeTrue = '') { $this->columnToRead = $columnToRead; $this->minimumValue = $minimumValue; + $this->columnToCheckToBeTrue = $columnToCheckToBeTrue; } public function filter($table) @@ -27,11 +37,17 @@ class ExcludeLowValue extends DataTable\BaseFilter return; } - $minimumValue = $this->minimumValue; - $isValueLowPopulation = function ($value) use ($minimumValue) { - return $value < $minimumValue; - }; + foreach ($table->getRows() as $key => $row) { - $table->filter('ColumnCallbackDeleteRow', array($this->columnToRead, $isValueLowPopulation)); + if ($this->columnToCheckToBeTrue && !$row->getColumn($this->columnToCheckToBeTrue)) { + continue; + } + + $value = $row->getColumn($this->columnToRead); + + if ($this->minimumValue > abs($value)) { + $table->deleteRow($key); + } + } } }
\ No newline at end of file diff --git a/plugins/Insights/DataTable/Filter/Insight.php b/plugins/Insights/DataTable/Filter/Insight.php index 44d767cccf..699d9a6614 100644 --- a/plugins/Insights/DataTable/Filter/Insight.php +++ b/plugins/Insights/DataTable/Filter/Insight.php @@ -30,53 +30,69 @@ class Insight extends DataTable\Filter\CalculateEvolutionFilter public function filter($table) { - foreach ($this->currentDataTable->getRows() as $key => $row) { - $pastRow = $this->getPastRowFromCurrent($row); - $oldValue = 0; + foreach ($this->currentDataTable->getRows() as $row) { + $this->addRowIfNewOrMover($table, $row); + } - if (!$pastRow && !$this->considerNew) { - continue; + if ($this->considerDisappeared) { + foreach ($this->pastDataTable->getRows() as $row) { + $this->addRowIfDisappeared($table, $row); } + } + } - if ($pastRow && $this->considerMovers) { - $oldValue = $pastRow->getColumn($this->columnValueToRead); - } elseif ($pastRow) { - continue; - } + private function addRowIfDisappeared(DataTable $table, DataTable\Row $row) + { + if ($this->getRowFromTable($this->currentDataTable, $row)) { + return; + } - $difference = $this->getDividend($row); - if ($difference === false) { - continue; - } + $newValue = 0; + $oldValue = $row->getColumn($this->columnValueToRead); + $difference = $newValue - $oldValue; + + if ($oldValue == 0 && $newValue == 0) { + $growthPercentage = '0%'; + } else { + $growthPercentage = '-100%'; + } - $newValue = $row->getColumn($this->columnValueToRead); - $divisor = $this->getDivisor($row); + $this->addRow($table, $row, $growthPercentage, $newValue, $oldValue, $difference, $isDisappeared = true); + } - $growthPercentage = $this->formatValue($difference, $divisor); + private function addRowIfNewOrMover(DataTable $table, DataTable\Row $row) + { + $pastRow = $this->getPastRowFromCurrent($row); - $this->addRow($table, $row, $growthPercentage, $newValue, $oldValue, $difference); + if (!$pastRow && !$this->considerNew) { + return; + } elseif ($pastRow && !$this->considerMovers) { + return; } - if ($this->considerDisappeared) { - foreach ($this->pastDataTable->getRows() as $key => $row) { + $isNew = false; + $isMover = false; + $isDisappeared = false; + + if (!$pastRow) { + $isNew = true; + $oldValue = 0; + } else { + $isMover = true; + $oldValue = $pastRow->getColumn($this->columnValueToRead); + } - if ($this->getRowFromTable($this->currentDataTable, $row)) { - continue; - } + $difference = $this->getDividend($row); + if ($difference === false) { + return; + } - $newValue = 0; - $oldValue = $row->getColumn($this->columnValueToRead); - $difference = $newValue - $oldValue; + $newValue = $row->getColumn($this->columnValueToRead); + $divisor = $this->getDivisor($row); - if ($oldValue == 0 && $newValue == 0) { - $growthPercentage = '0%'; - } else { - $growthPercentage = '-100%'; - } + $growthPercentage = $this->formatValue($difference, $divisor); - $this->addRow($table, $row, $growthPercentage, $newValue, $oldValue, $difference); - } - } + $this->addRow($table, $row, $growthPercentage, $newValue, $oldValue, $difference, $isDisappeared, $isNew, $isMover); } private function getRowFromTable(DataTable $table, DataTable\Row $row) @@ -84,7 +100,7 @@ class Insight extends DataTable\Filter\CalculateEvolutionFilter return $table->getRowFromLabel($row->getColumn('label')); } - private function addRow(DataTable $table, DataTable\Row $row, $growthPercentage, $newValue, $oldValue, $difference) + private function addRow(DataTable $table, DataTable\Row $row, $growthPercentage, $newValue, $oldValue, $difference, $disappeared = false, $isNew = false, $isMover = false) { $columns = $row->getColumns(); $columns['growth_percent'] = $growthPercentage; @@ -94,6 +110,9 @@ class Insight extends DataTable\Filter\CalculateEvolutionFilter $columns['value_new'] = $newValue; $columns['difference'] = $difference; $columns['importance'] = abs($difference); + $columns['isDisappeared'] = $disappeared; + $columns['isNew'] = $isNew; + $columns['isMover'] = $isMover; $table->addRowFromArray(array(DataTable\Row::COLUMNS => $columns)); } diff --git a/plugins/Insights/DataTable/Filter/OrderBy.php b/plugins/Insights/DataTable/Filter/OrderBy.php index 27d74d7db9..7217c77260 100644 --- a/plugins/Insights/DataTable/Filter/OrderBy.php +++ b/plugins/Insights/DataTable/Filter/OrderBy.php @@ -13,11 +13,11 @@ use Piwik\DataTable\Row; class OrderBy extends BaseFilter { - private $columnToRead; + private $columnsToCheck; - public function __construct($table, $columnToRead) + public function __construct($table, $columnToRead, $columnSecondOrder, $columnThirdOrder = '') { - $this->columnToRead = $columnToRead; + $this->columnsToCheck = array($columnToRead, $columnSecondOrder, $columnThirdOrder); } public function filter($table) @@ -26,27 +26,46 @@ class OrderBy extends BaseFilter return; } - $table->sort(array($this, 'sort'), $this->columnToRead); + $table->sort(array($this, 'sort'), $this->columnsToCheck[0]); } public function sort(Row $a, Row $b) { - $valA = $a->getColumn($this->columnToRead); - $valB = $b->getColumn($this->columnToRead); + foreach ($this->columnsToCheck as $column) { + if ($column) { - if (!isset($valA) && !isset($valB)) { + $valA = $a->getColumn($column); + $valB = $b->getColumn($column); + $sort = $this->sortVal($valA, $valB); + + if (isset($sort)) { + return $sort; + } + } + } + + return 0; + } + + private function sortVal($valA, $valB) + { + if ((!isset($valA) || $valA === false) && (!isset($valB) || $valB === false)) { return 0; } - if (!isset($valA)) { + if (!isset($valA) || $valA === false) { return 1; } - if (!isset($valB)) { + if (!isset($valB) || $valB === false) { return -1; } - if ($valA > 0 && $valB < 0) { + if ($valA === $valB) { + return null; + } + + if ($valA >= 0 && $valB < 0) { return -1; } @@ -58,18 +77,7 @@ class OrderBy extends BaseFilter return $valA < $valB ? 1 : -1; } - $aVisits = $a->getColumn('nb_visits'); - $bVisits = $b->getColumn('nb_visits'); - - if ($aVisits == $bVisits) { - return 0; - } - - if ($aVisits > $bVisits) { - return -1; - } - - return 1; + return null; } }
\ No newline at end of file diff --git a/plugins/Insights/InsightReport.php b/plugins/Insights/InsightReport.php new file mode 100644 index 0000000000..72d4dc6fe0 --- /dev/null +++ b/plugins/Insights/InsightReport.php @@ -0,0 +1,169 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ +namespace Piwik\Plugins\Insights; + +use Piwik\DataTable; + +/** + * API for plugin Insights + * + * @method static \Piwik\Plugins\Insights\API getInstance() + */ +class InsightReport +{ + const ORDER_BY_RELATIVE = 'relative'; + const ORDER_BY_ABSOLUTE = 'absolute'; + const ORDER_BY_IMPORTANCE = 'importance'; + + /** + * @param array $reportMetadata + * @param string $period + * @param string $date + * @param string $lastDate + * @param string $metric + * @param DataTable $currentReport + * @param DataTable $lastReport + * @param int $totalValue + * @param int $minVisitsMoversPercent Exclude rows who moved and the difference is not at least min percent + * visits of totalVisits. -1 excludes movers. + * @param int $minVisitsNewPercent Exclude rows who are new and the difference is not at least min percent + * visits of totalVisits. -1 excludes all new. + * @param int $minVisitsDisappearedPercent Exclude rows who are disappeared and the difference is not at least min + * percent visits of totalVisits. -1 excludes all disappeared. + * @param int $minGrowthPercent The actual growth of a row must be at least percent compared to the + * previous value (not total value) + * @param string $orderBy Order by absolute, relative, importance + * @param int $limitIncreaser + * @param int $limitDecreaser + * @return DataTable + */ + public function generateInsight($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $minVisitsMoversPercent, $minVisitsNewPercent, $minVisitsDisappearedPercent, $minGrowthPercent, $orderBy, $limitIncreaser, $limitDecreaser) + { + $minChangeMovers = $this->getMinVisits($totalValue, $minVisitsMoversPercent); + $minIncreaseNew = $this->getMinVisits($totalValue, $minVisitsNewPercent); + $minDecreaseDisappeared = $this->getMinVisits($totalValue, $minVisitsDisappearedPercent); + + $dataTable = new DataTable(); + $dataTable->filter( + 'Piwik\Plugins\Insights\DataTable\Filter\Insight', + array( + $currentReport, + $lastReport, + $metric, + $considerMovers = (-1 !== $minVisitsMoversPercent), + $considerNew = (-1 !== $minVisitsNewPercent), + $considerDisappeared = (-1 !== $minVisitsDisappearedPercent) + ) + ); + + $dataTable->filter( + 'Piwik\Plugins\Insights\DataTable\Filter\MinGrowth', + array( + 'growth_percent_numeric', + $minGrowthPercent, + ) + ); + + if ($minIncreaseNew) { + $dataTable->filter( + 'Piwik\Plugins\Insights\DataTable\Filter\ExcludeLowValue', + array( + 'difference', + $minIncreaseNew, + 'isNew' + ) + ); + } + + if ($minChangeMovers) { + $dataTable->filter( + 'Piwik\Plugins\Insights\DataTable\Filter\ExcludeLowValue', + array( + 'difference', + $minChangeMovers, + 'isMover' + ) + ); + } + + if ($minDecreaseDisappeared) { + $dataTable->filter( + 'Piwik\Plugins\Insights\DataTable\Filter\ExcludeLowValue', + array( + 'difference', + $minDecreaseDisappeared, + 'isDisappeared' + ) + ); + } + + $dataTable->filter( + 'Piwik\Plugins\Insights\DataTable\Filter\OrderBy', + array( + $this->getOrderByColumn($orderBy), + $orderBy === self::ORDER_BY_RELATIVE ? $this->getOrderByColumn(self::ORDER_BY_ABSOLUTE) : $this->getOrderByColumn(self::ORDER_BY_RELATIVE), + $metric + ) + ); + + $dataTable->filter( + 'Piwik\Plugins\Insights\DataTable\Filter\Limit', + array( + 'growth_percent_numeric', + $limitIncreaser, + $limitDecreaser + ) + ); + + $dataTable->setMetadataValues(array( + 'reportName' => $reportMetadata['name'], + 'metricName' => $reportMetadata['metrics'][$metric], + 'date' => $date, + 'lastDate' => $lastDate, + 'period' => $period, + 'report' => $reportMetadata, + 'totalValue' => $totalValue, + 'minChangeMovers' => $minChangeMovers, + 'minIncreaseNew' => $minIncreaseNew, + 'minDecreaseDisappeared' => $minDecreaseDisappeared, + 'minGrowthPercent' => $minGrowthPercent, + 'minVisitsMoversPercent' => $minVisitsMoversPercent, + 'minVisitsNewPercent' => $minVisitsNewPercent, + 'minVisitsDisappearedPercent' => $minVisitsDisappearedPercent + )); + + return $dataTable; + } + + private function getOrderByColumn($orderBy) + { + if (self::ORDER_BY_RELATIVE == $orderBy) { + $orderByColumn = 'growth_percent_numeric'; + } elseif (self::ORDER_BY_ABSOLUTE == $orderBy) { + $orderByColumn = 'difference'; + } elseif (self::ORDER_BY_IMPORTANCE == $orderBy) { + $orderByColumn = 'importance'; + } else { + throw new \Exception('Unsupported orderBy'); + } + + return $orderByColumn; + } + + private function getMinVisits($totalValue, $percent) + { + if ($percent <= 0) { + return 0; + } + + $minVisits = ceil(($totalValue / 100) * $percent); + + return (int) $minVisits; + } +} diff --git a/plugins/Insights/Insights.php b/plugins/Insights/Insights.php index 1753b32aa8..9c915ce99d 100644 --- a/plugins/Insights/Insights.php +++ b/plugins/Insights/Insights.php @@ -34,7 +34,8 @@ class Insights extends \Piwik\Plugin public function addWidgets() { - WidgetsList::add('Insights_Category', 'Insights_OverviewWidgetTitle', 'Insights', 'getInsightOverview'); + WidgetsList::add('Insights_WidgetCategory', 'Insights_OverviewWidgetTitle', 'Insights', 'getInsightsOverview'); + WidgetsList::add('Insights_WidgetCategory', 'Insights_MoversAndShakersWidgetTitle', 'Insights', 'getOverallMoversAndShakers'); } public function getStylesheetFiles(&$stylesheets) diff --git a/plugins/Insights/Model.php b/plugins/Insights/Model.php new file mode 100644 index 0000000000..380f80b224 --- /dev/null +++ b/plugins/Insights/Model.php @@ -0,0 +1,117 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ +namespace Piwik\Plugins\Insights; + +use Piwik\DataTable; +use Piwik\Date; +use Piwik\Log; +use Piwik\Period\Range; +use Piwik\Piwik; +use Piwik\Plugins\API\ProcessedReport; +use Piwik\API\Request as ApiRequest; +use Piwik\Plugins\VisitsSummary\API as VisitsSummaryAPI; + +/** + * API for plugin Insights + * + * @method static \Piwik\Plugins\Insights\API getInstance() + */ +class Model +{ + + public function requestReport($idSite, $period, $date, $reportUniqueId, $metric, $segment) + { + $report = $this->getReportByUniqueId($idSite, $reportUniqueId); + + $params = array( + 'method' => $report['module'] . '.' . $report['action'], + 'format' => 'original', + 'idSite' => $idSite, + 'period' => $period, + 'date' => $date, + 'filter_limit' => 1000, + 'showColumns' => $metric + ); + + if (!empty($segment)) { + $params['segment'] = $segment; + } + + if (!empty($report['parameters']) && is_array($report['parameters'])) { + $params = array_merge($params, $report['parameters']); + } + + $request = new ApiRequest($params); + $table = $request->process(); + + return $table; + } + + public function getLastDate($date, $period, $comparedToXPeriods) + { + $pastDate = Range::getDateXPeriodsAgo(abs($comparedToXPeriods), $date, $period); + + if (empty($pastDate[0])) { + throw new \Exception('Not possible to compare this date/period combination'); + } + + return $pastDate[0]; + } + + public function getRelevantTotalValue(DataTable $currentReport, $idSite, $period, $date, $metric) + { + $totalMetric = $this->getMetricTotalValue($currentReport, $metric); + $totalValue = $this->getTotalValue($idSite, $period, $date, $metric); + + if ($totalMetric > $totalValue) { + return $totalMetric; + } + + if (($totalMetric * 2) < $totalValue) { + return $totalMetric; + } + + return $totalValue; + } + + public function getTotalValue($idSite, $period, $date, $metric) + { + $visits = VisitsSummaryAPI::getInstance()->get($idSite, $period, $date, false, array($metric)); + $firstRow = $visits->getFirstRow(); + + if (empty($firstRow)) { + return 0; + } + + $totalValue = $firstRow->getColumn($metric); + + return (int) $totalValue; + } + + public function getMetricTotalValue(DataTable $currentReport, $metric) + { + $totals = $currentReport->getMetadata('totals'); + + if (!empty($totals[$metric])) { + $totalValue = (int) $totals[$metric]; + } else { + $totalValue = 0; + } + + return $totalValue; + } + + public function getReportByUniqueId($idSite, $reportUniqueId) + { + $processedReport = new ProcessedReport(); + $report = $processedReport->getReportMetadataByUniqueId($idSite, $reportUniqueId); + + return $report; + } +} diff --git a/plugins/Insights/Visualizations/Insight.php b/plugins/Insights/Visualizations/Insight.php index f16c913b0f..3f67f51a57 100644 --- a/plugins/Insights/Visualizations/Insight.php +++ b/plugins/Insights/Visualizations/Insight.php @@ -14,6 +14,7 @@ use Piwik\DataTable; use Piwik\Period\Range; use Piwik\Plugin\ViewDataTable; use Piwik\Plugin\Visualization; +use Piwik\Plugins\Insights\Model; /** * InsightsVisualization Visualization. @@ -25,7 +26,7 @@ class Insight extends Visualization { const ID = 'insightsVisualization'; const TEMPLATE_FILE = '@Insights/insightVisualization.twig'; - const FOOTER_ICON_TITLE = 'InsightsVisualization'; + const FOOTER_ICON_TITLE = 'Insights'; const FOOTER_ICON = 'plugins/Insights/images/idea.png'; public function beforeLoadDataTable() @@ -34,7 +35,7 @@ class Insight extends Visualization $report = str_replace('.', '_', $report); if (!$this->requestConfig->filter_limit) { - $this->requestConfig->filter_limit = 25; + $this->requestConfig->filter_limit = 10; } $limit = $this->requestConfig->filter_limit; @@ -53,7 +54,7 @@ class Insight extends Visualization $this->requestConfig->apiMethodToRequestDataTable = 'Insights.getInsights'; $this->requestConfig->request_parameters_to_modify = array( 'reportUniqueId' => $report, - 'minVisitsPercent' => $this->requestConfig->min_visits_percent, + 'minImpactPercent' => $this->requestConfig->min_impact_percent, 'minGrowthPercent' => $this->requestConfig->min_growth_percent, 'comparedToXPeriods' => $this->requestConfig->compared_to_x_periods_ago, 'orderBy' => $this->requestConfig->order_by, @@ -80,8 +81,6 @@ class Insight extends Visualization public function afterAllFiltersAreApplied() { - $this->assignTemplateVar('showNoDataMessage', true); - $this->assignTemplateVar('showInsightsControls', true); $this->assignTemplateVar('period', Common::getRequestVar('period', null, 'string')); } @@ -100,9 +99,14 @@ class Insight extends Visualization $period = Common::getRequestVar('period', null, 'string'); $date = Common::getRequestVar('date', null, 'string'); - $lastDate = Range::getDateXPeriodsAgo(1, $date, $period); + try { + $model = new Model(); + $lastDate = $model->getLastDate($date, $period, 1); + } catch (\Exception $e) { + return false; + } - if (empty($lastDate[0])) { + if (empty($lastDate)) { return false; } diff --git a/plugins/Insights/Visualizations/Insight/RequestConfig.php b/plugins/Insights/Visualizations/Insight/RequestConfig.php index 93f52a9687..3edfecb7a5 100644 --- a/plugins/Insights/Visualizations/Insight/RequestConfig.php +++ b/plugins/Insights/Visualizations/Insight/RequestConfig.php @@ -13,7 +13,7 @@ use Piwik\ViewDataTable\RequestConfig as VisualizationRequestConfig; class RequestConfig extends VisualizationRequestConfig { - public $min_visits_percent = 2; + public $min_impact_percent = 1; public $min_growth_percent = 20; public $compared_to_x_periods_ago = 1; public $order_by = 'absolute'; @@ -28,7 +28,7 @@ class RequestConfig extends VisualizationRequestConfig $properties = array( 'min_growth_percent', - 'min_visits_percent', + 'min_impact_percent', 'order_by', 'compared_to_x_periods_ago', 'filter_by', diff --git a/plugins/Insights/javascripts/insightsDataTable.js b/plugins/Insights/javascripts/insightsDataTable.js index 18780b4d7a..3947c76c31 100644 --- a/plugins/Insights/javascripts/insightsDataTable.js +++ b/plugins/Insights/javascripts/insightsDataTable.js @@ -35,7 +35,7 @@ _init: function (domElem) { this.initMinGrowthPercentage(domElem); - this.initMinVisitsPercent(domElem); + this.initMinImpactPercent(domElem); this.initShowIncreaseOrDecrease(domElem); this.initOrderBy(domElem); this.initComparedToXPeriodsAgo(domElem); @@ -98,10 +98,10 @@ }); }, - initMinVisitsPercent: function (domElem) { + initMinImpactPercent: function (domElem) { var self = this; - $('[name=minVisitsPercent]', domElem).bind('change', function (event) { - self._changeParameterAndReload({min_visits_percent: getValueFromEvent(event)}); + $('[name=minImpactPercent]', domElem).bind('change', function (event) { + self._changeParameterAndReload({min_impact_percent: getValueFromEvent(event)}); }); }, diff --git a/plugins/Insights/lang/en.json b/plugins/Insights/lang/en.json index acc356241a..81630a7f83 100644 --- a/plugins/Insights/lang/en.json +++ b/plugins/Insights/lang/en.json @@ -1,7 +1,12 @@ { "Insights": { "OverviewWidgetTitle": "Insights Overview", - "Category": "Insights", - "NoResultMatchesCriteria": "No rows match the criteria" + "WidgetCategory": "Insights", + "NoResultMatchesCriteria": "No rows match the criteria", + "MoversAndShakersWidgetTitle": "Movers and Shakers", + "TitleConsideredVisits": "Considered rows having at least a growth of at least %s%% compared to %s.", + "TitleConsideredChanges": "Considered movers only if they increased or decreased by more than %s visits, new entries only if they increase by more than %s visits, and disappeared rows if they decreased by more than %s visits based on %s total visits.", + "TitleReportBasedOn": "Based on %s %s, rows less than %s %s were ignored", + "TitleRowChangeDetails": "'%s' changed from %s (%s) to %s (%s) %s" } }
\ No newline at end of file diff --git a/plugins/Insights/stylesheets/insightVisualization.less b/plugins/Insights/stylesheets/insightVisualization.less index b559c9e36a..a5ed362414 100644 --- a/plugins/Insights/stylesheets/insightVisualization.less +++ b/plugins/Insights/stylesheets/insightVisualization.less @@ -25,4 +25,11 @@ .notGrown { color:red; } + + table td { + &.labelodd, &.labeleven { + + background-image: none; + } + } }
\ No newline at end of file diff --git a/plugins/Insights/templates/index.twig b/plugins/Insights/templates/index.twig deleted file mode 100644 index fc91a81330..0000000000 --- a/plugins/Insights/templates/index.twig +++ /dev/null @@ -1,5 +0,0 @@ -{% for dataTable in moversAndShakers.getDataTables() %} - - {% include "@Insights/insightVisualization.twig" %} - -{% endfor %}
\ No newline at end of file diff --git a/plugins/Insights/templates/insightControls.twig b/plugins/Insights/templates/insightControls.twig index d976ecccf8..46d186dff3 100644 --- a/plugins/Insights/templates/insightControls.twig +++ b/plugins/Insights/templates/insightControls.twig @@ -1,14 +1,17 @@ <div style="padding: 10px;padding-bottom: 0px;"> Minimum impact of - <select name="minVisitsPercent" title="Based on a total of {{ dataTable.getMetadata('totalValue') }} visitors or metricname"> + <select name="minImpactPercent" title="Based on a total of {{ dataTable.getMetadata('totalValue') }} visitors or metricname"> {% for i in range(0, 10) %} - <option {% if i == properties.min_visits_percent %}selected{% endif %} value="{{ i }}">{{ i }}%</option> + <option {% if i == properties.min_impact_percent %}selected{% endif %} value="{{ i }}">{{ i }}%</option> {% endfor %} {% for i in range(12, 30, 2) %} - <option {% if i == properties.min_visits_percent %}selected{% endif %} value="{{ i }}">{{ i }}%</option> + <option {% if i == properties.min_impact_percent %}selected{% endif %} value="{{ i }}">{{ i }}%</option> {% endfor %} - {% for i in range(35, 100, 5) %} - <option {% if i == properties.min_visits_percent %}selected{% endif %} value="{{ i }}">{{ i }}%</option> + {% for i in range(40, 100, 10) %} + <option {% if i == properties.min_impact_percent %}selected{% endif %} value="{{ i }}">{{ i }}%</option> + {% endfor %} + {% for i in range(200, 1000, 100) %} + <option {% if i == properties.min_impact_percent %}selected{% endif %} value="{{ i }}">{{ i }}%</option> {% endfor %} </select> @@ -25,28 +28,30 @@ {% endfor %} </select> - compared to - {% if period == 'day' %} - <select size="1" name="comparedToXPeriodsAgo"> - <option value="1" {% if properties.compared_to_x_periods_ago == 1 %}selected{% endif %}> - previous day - </option> - <option value="7" {% if properties.compared_to_x_periods_ago == 7 %}selected{% endif %}> - same day in previous week - </option> - <option value="365" {% if properties.compared_to_x_periods_ago == 365 %}selected{% endif %}> - same day in previous year - </option> - </select> - {% elseif period == 'month' %} - <select size="1" name="comparedToXPeriodsAgo"> - <option value="1" {% if properties.compared_to_x_periods_ago == 1 %}selected{% endif %}> - previous month - </option> - <option value="12" {% if properties.compared_to_x_periods_ago == 12 %}selected{% endif %}> - same month in previous year - </option> - </select> + {% if period == 'day' or period == 'month' %} + compared to + {% if period == 'day' %} + <select size="1" name="comparedToXPeriodsAgo"> + <option value="1" {% if properties.compared_to_x_periods_ago == 1 %}selected{% endif %}> + previous day + </option> + <option value="7" {% if properties.compared_to_x_periods_ago == 7 %}selected{% endif %}> + same day in previous week + </option> + <option value="365" {% if properties.compared_to_x_periods_ago == 365 %}selected{% endif %}> + same day in previous year + </option> + </select> + {% elseif period == 'month' %} + <select size="1" name="comparedToXPeriodsAgo"> + <option value="1" {% if properties.compared_to_x_periods_ago == 1 %}selected{% endif %}> + previous month + </option> + <option value="12" {% if properties.compared_to_x_periods_ago == 12 %}selected{% endif %}> + same month in previous year + </option> + </select> + {% endif %} {% endif %} <hr style="height: 1px;border: 0px;background-color: #cccccc;" /> diff --git a/plugins/Insights/templates/insightVisualization.twig b/plugins/Insights/templates/insightVisualization.twig index 9c9f72c479..50d1b3ecef 100644 --- a/plugins/Insights/templates/insightVisualization.twig +++ b/plugins/Insights/templates/insightVisualization.twig @@ -1,54 +1,24 @@ -<div class="insightsDataTable"> +{% set metadata = dataTable.getAllTableMetadata%} +{% set consideredVisits = 'Insights_TitleConsideredVisits'|translate(metadata.minGrowthPercent, metadata.lastDate|prettyDate(metadata.period)) %} + +<div class="insightsDataTable" title="{{ consideredVisits|e('html_attr') }}"> {% if dataTable.getRowsCount > 0 %} <table class="dataTable"> <thead> - <tr title="Based on {{ dataTable.getMetadata('totalValue') }} {{ dataTable.getMetadata('metricName') }}, rows less than {{ dataTable.getMetadata('minVisits') }} {{ dataTable.getMetadata('metricName') }} were ignored"> - <th class="label"> - {{ dataTable.getMetadata('reportName') }} - </th> - <th class="label orderBy" name="orderBy" value="absolute" - style="{% if 'absolute' == properties.order_by %}font-weight:bold;{% endif %}"> - {{ dataTable.getMetadata('metricName') }} - </th> - <th class="label orderBy" name="orderBy" value="relative" - style="{% if 'relative' == properties.order_by %}font-weight:bold;{% endif %}"> - {{ 'MultiSites_Evolution'|translate }} - </th> - </tr> + {% include "@Insights/table_header.twig" %} </thead> - <tbody> - - {% for row in dataTable.getRows %} - <tr title="{{ dataTable.getMetadata('metricName') }} changed from {{ row.getColumn('value_old') }} ({{ dataTable.getMetadata('lastDate') }}) to {{ row.getColumn('value_new') }} ({{ dataTable.getMetadata('date') }})"> - <td> - <span class="title" - title="{{ row.getColumn('label') }}"> - {{ row.getColumn('label') }} - </span> - </td> - {% if row.getColumn('grown') %} - <td>+{{ row.getColumn('difference') }}</td> - <td class="grown"> - +{{ row.getColumn('growth_percent') }} - </td> - {% else %} - <td>{{ row.getColumn('difference') }}</td> - <td class="notGrown"> - {{ row.getColumn('growth_percent') }} - </td> - {% endif %} - </tr> - {% endfor %} + <tbody> + {% for row in dataTable.getRows %} + {% include "@Insights/table_row.twig" %} + {% endfor %} </tbody> </table> - {% elseif showNoDataMessage %} + {% else %} <div class="pk-emptyDataTable"> {{ 'Insights_NoResultMatchesCriteria'|translate }} </div> {% endif %} - {% if showInsightsControls %} - {% include "@Insights/insightControls.twig" %} - {% endif %} + {% include "@Insights/insightControls.twig" %} </div>
\ No newline at end of file diff --git a/plugins/Insights/templates/overviewWidget.twig b/plugins/Insights/templates/overviewWidget.twig new file mode 100644 index 0000000000..2a672af69b --- /dev/null +++ b/plugins/Insights/templates/overviewWidget.twig @@ -0,0 +1,37 @@ +{% set allMetadata = reports.getFirstRow.getAllTableMetadata %} + +{% set consideredVisits = 'Insights_TitleConsideredVisits'|translate(allMetadata.minGrowthPercent, allMetadata.lastDate|prettyDate(allMetadata.period)) %} +{% set consideredChanges = '' %} + +{% if allMetadata.minChangeMovers or allMetadata.minIncreaseNew or allMetadata.minDecreaseDisappeared %} + {% set consideredChanges = 'Insights_TitleConsideredChanges'|translate(allMetadata.minChangeMovers, allMetadata.minIncreaseNew, allMetadata.minDecreaseDisappeared, allMetadata.totalValue) %} +{% endif %} + +<div class="insightsDataTable" title="{{ consideredVisits|e('html_attr') }} {{ consideredChanges|e('html_attr') }}"> + {% if reports.getColumns|length > 0 %} + + <table class="dataTable"> + {% for dataTable in reports.getDataTables() if dataTable.getRowsCount > 0 %} + {% set metadata = dataTable.getAllTableMetadata %} + + <thead> + {% include "@Insights/table_header.twig" %} + </thead> + + <tbody> + {% for row in dataTable.getRows %} + {% include "@Insights/table_row.twig" %} + {% endfor %} + </tbody> + + {% endfor %} + </table> + + {% else %} + + <div class="pk-emptyDataTable"> + {{ 'Insights_NoResultMatchesCriteria'|translate }} + </div> + + {% endif %} +</div>
\ No newline at end of file diff --git a/plugins/Insights/templates/table_header.twig b/plugins/Insights/templates/table_header.twig new file mode 100644 index 0000000000..7226f88450 --- /dev/null +++ b/plugins/Insights/templates/table_header.twig @@ -0,0 +1,13 @@ +<tr> + <th class="label"> + {{ metadata.reportName }} + </th> + <th class="label orderBy" name="orderBy" value="absolute" + style="{% if 'absolute' == properties.order_by %}font-weight:bold;{% endif %}"> + {{ metadata.metricName }} + </th> + <th class="label orderBy" name="orderBy" value="relative" + style="{% if 'relative' == properties.order_by %}font-weight:bold;{% endif %}"> + {{ 'MultiSites_Evolution'|translate }} + </th> +</tr>
\ No newline at end of file diff --git a/plugins/Insights/templates/table_row.twig b/plugins/Insights/templates/table_row.twig new file mode 100644 index 0000000000..bd3b04a2e7 --- /dev/null +++ b/plugins/Insights/templates/table_row.twig @@ -0,0 +1,15 @@ +<tr title="{{ 'Insights_TitleRowChangeDetails'|translate(row.getColumn('label'), row.getColumn('value_old'), metadata.lastDate|prettyDate(metadata.period), row.getColumn('value_new'), metadata.date|prettyDate(metadata.period), metadata.metricName)|e('html_attr') }}"> + <td> + <span class="title"> + {{ row.getColumn('label') }} + </span> + </td> + + {% if row.getColumn('grown') %} + <td>+{{ row.getColumn('difference') }}</td> + <td class="grown">+{{ row.getColumn('growth_percent') }}</td> + {% else %} + <td>{{ row.getColumn('difference') }}</td> + <td class="notGrown">{{ row.getColumn('growth_percent') }}</td> + {% endif %} +</tr>
\ No newline at end of file diff --git a/plugins/Insights/tests/ApiTest.php b/plugins/Insights/tests/ApiTest.php index 1e0818d8c7..b7e85f4142 100644 --- a/plugins/Insights/tests/ApiTest.php +++ b/plugins/Insights/tests/ApiTest.php @@ -40,13 +40,13 @@ class ApiTest extends \IntegrationTestCase } /** - '//Mover1' => 2, +8 // 400% - '//Old1' => 9, -9 // -100% - '/Mover2' => 24, -11 // -50% - '//Mover3' => 21, -1 // -5% - '/Old2' => 3 -3 // -100% - New1, +5 // 100% - New2 +2 // 100% + '/Mover1' => 2, +8 // 400% + '/Old1' => 9, -9 // -100% + '/Mover2' => 24, -11 // -50% + '/Mover3' => 21, -1 // -5% + '/Old2' => 3 -3 // -100% + '/New1', +5 // 100% + '/New2' +2 // 100% */ public function test_getInsights_ShouldReturnCorrectMetadata() { @@ -60,7 +60,13 @@ class ApiTest extends \IntegrationTestCase 'lastDate' => self::$fixture->date2, 'period' => 'day', 'totalValue' => 50, - 'minVisits' => 1 + 'minChangeMovers' => 1, + 'minIncreaseNew' => 1, + 'minDecreaseDisappeared' => 1, + 'minGrowthPercent' => 20, + 'minVisitsMoversPercent' => 2, + 'minVisitsNewPercent' => 2, + 'minVisitsDisappearedPercent' => 2, ); $this->assertInternalType('array', $metadata['report']); @@ -92,7 +98,7 @@ class ApiTest extends \IntegrationTestCase public function test_getInsights_ShouldReturnAllRowsIfMinValuesArelow() { - $insights = $this->requestInsights(array('minVisitsPercent' => 0, 'minGrowthPercent' => 1)); + $insights = $this->requestInsights(array('minImpactPercent' => 0, 'minGrowthPercent' => 1)); $expectedLabels = array( '/Mover1', @@ -106,23 +112,23 @@ class ApiTest extends \IntegrationTestCase $this->assertRows($expectedLabels, $insights); } - public function test_getInsights_ShouldReturnReturnNothingIfMinVisitsPercentIsTooHigh() + public function test_getInsights_ShouldReturnReturnNothingIfminImpactPercentIsTooHigh() { - $insights = $this->requestInsights(array('minVisitsPercent' => 10000, 'minGrowthPercent' => 0)); + $insights = $this->requestInsights(array('minImpactPercent' => 10000, 'minGrowthPercent' => 0)); $this->assertRows(array(), $insights); } public function test_getInsights_ShouldReturnReturnNothingIfMinGrowthIsHigh() { - $insights = $this->requestInsights(array('minVisitsPercent' => 0, 'minGrowthPercent' => 10000)); + $insights = $this->requestInsights(array('minImpactPercent' => 0, 'minGrowthPercent' => 10000)); $this->assertRows(array(), $insights); } public function test_getInsights_ShouldOrderAbsoluteByDefault() { - $insights = $this->requestInsights(array('minVisitsPercent' => 0, 'minGrowthPercent' => 0)); + $insights = $this->requestInsights(array('minImpactPercent' => 0, 'minGrowthPercent' => 0)); $expectedLabels = array( '/Mover1', @@ -138,7 +144,7 @@ class ApiTest extends \IntegrationTestCase public function test_getInsights_ShouldBeAbleToOrderRelative() { - $insights = $this->requestInsights(array('minVisitsPercent' => 0, 'minGrowthPercent' => 0, 'orderBy' => 'relative')); + $insights = $this->requestInsights(array('minImpactPercent' => 0, 'minGrowthPercent' => 0, 'orderBy' => 'relative')); $expectedLabels = array( '/Mover1', @@ -154,7 +160,7 @@ class ApiTest extends \IntegrationTestCase public function test_getInsights_ShouldBeAbleToOrderByImportance() { - $insights = $this->requestInsights(array('minVisitsPercent' => 0, 'minGrowthPercent' => 0, 'orderBy' => 'importance')); + $insights = $this->requestInsights(array('minImpactPercent' => 0, 'minGrowthPercent' => 0, 'orderBy' => 'importance')); $expectedLabels = array( '/Mover2', @@ -181,7 +187,7 @@ class ApiTest extends \IntegrationTestCase public function test_getInsights_ShouldBeAbleToShowOnlyMovers() { - $insights = $this->requestInsights(array('minVisitsPercent' => 0, 'minGrowthPercent' => 0, 'filterBy' => 'movers')); + $insights = $this->requestInsights(array('minImpactPercent' => 0, 'minGrowthPercent' => 0, 'filterBy' => 'movers')); $expectedLabels = array( '/Mover1', @@ -193,7 +199,7 @@ class ApiTest extends \IntegrationTestCase public function test_getInsights_ShouldBeAbleToShowOnlyNew() { - $insights = $this->requestInsights(array('minVisitsPercent' => 0, 'minGrowthPercent' => 0, 'filterBy' => 'new')); + $insights = $this->requestInsights(array('minImpactPercent' => 0, 'minGrowthPercent' => 0, 'filterBy' => 'new')); $expectedLabels = array( '/New1', @@ -204,7 +210,7 @@ class ApiTest extends \IntegrationTestCase public function test_getInsights_ShouldBeAbleToShowOnlyDisappeared() { - $insights = $this->requestInsights(array('minVisitsPercent' => 0, 'minGrowthPercent' => 0, 'filterBy' => 'disappeared')); + $insights = $this->requestInsights(array('minImpactPercent' => 0, 'minGrowthPercent' => 0, 'filterBy' => 'disappeared')); $expectedLabels = array( '/Old1', diff --git a/plugins/Insights/tests/FilterExcludeLowValueTest.php b/plugins/Insights/tests/FilterExcludeLowValueTest.php index e9080c85da..45ddf8075e 100644 --- a/plugins/Insights/tests/FilterExcludeLowValueTest.php +++ b/plugins/Insights/tests/FilterExcludeLowValueTest.php @@ -29,17 +29,17 @@ class FilterExcludeLowValueTest extends \PHPUnit_Framework_TestCase { $this->table = new DataTable(); $this->table->addRowsFromArray(array( - array(Row::COLUMNS => array('label' => 'val1', 'growth' => 22)), - array(Row::COLUMNS => array('label' => 'val2', 'growth' => 14)), - array(Row::COLUMNS => array('label' => 'val3', 'growth' => 18)), - array(Row::COLUMNS => array('label' => 'val4', 'growth' => 20)), - array(Row::COLUMNS => array('label' => 'val5', 'growth' => 22)), - array(Row::COLUMNS => array('label' => 'val6', 'growth' => 25)), - array(Row::COLUMNS => array('label' => 'val7', 'growth' => 17)), - array(Row::COLUMNS => array('label' => 'val8', 'growth' => 20)), - array(Row::COLUMNS => array('label' => 'val9', 'growth' => 0)), - array(Row::COLUMNS => array('label' => 'val10', 'growth' => 15)), - array(Row::COLUMNS => array('label' => 'val11', 'growth' => 16)) + array(Row::COLUMNS => array('label' => 'val1', 'growth' => 22, 'isFooBar' => false)), + array(Row::COLUMNS => array('label' => 'val2', 'growth' => 14, 'isFooBar' => true)), + array(Row::COLUMNS => array('label' => 'val3', 'growth' => 18, 'isFooBar' => false)), + array(Row::COLUMNS => array('label' => 'val4', 'growth' => 20, 'isFooBar' => true)), + array(Row::COLUMNS => array('label' => 'val5', 'growth' => 22, 'isFooBar' => true)), + array(Row::COLUMNS => array('label' => 'val6', 'growth' => 25, 'isFooBar' => true)), + array(Row::COLUMNS => array('label' => 'val7', 'growth' => 17, 'isFooBar' => false)), + array(Row::COLUMNS => array('label' => 'val8', 'growth' => 20, 'isFooBar' => false)), + array(Row::COLUMNS => array('label' => 'val9', 'growth' => 0, 'isFooBar' => false)), + array(Row::COLUMNS => array('label' => 'val10', 'growth' => 15, 'isFooBar' => false)), + array(Row::COLUMNS => array('label' => 'val11', 'growth' => 16, 'isFooBar' => true)) )); } @@ -74,15 +74,22 @@ class FilterExcludeLowValueTest extends \PHPUnit_Framework_TestCase $this->assertOrder(array()); } + public function testShouldRemoveValuesOnlyIfColumnToCheckIsTrue() + { + $this->excludeLowValues(21, 'isFooBar'); + + $this->assertOrder(array('val1', 'val3', 'val5', 'val6', 'val7', 'val8', 'val9', 'val10')); + } + private function assertOrder($expectedOrder) { $this->assertEquals($expectedOrder, $this->table->getColumn('label')); $this->assertEquals(count($expectedOrder), $this->table->getRowsCount()); } - private function excludeLowValues($minimumValue) + private function excludeLowValues($minimumValue, $columnToCheck = null) { - $filter = new ExcludeLowValue($this->table, 'growth', $minimumValue); + $filter = new ExcludeLowValue($this->table, 'growth', $minimumValue, $columnToCheck); $filter->filter($this->table); } diff --git a/plugins/Insights/tests/FilterInsightTest.php b/plugins/Insights/tests/FilterInsightTest.php index 4a6431ce8a..f122f93aa7 100644 --- a/plugins/Insights/tests/FilterInsightTest.php +++ b/plugins/Insights/tests/FilterInsightTest.php @@ -148,6 +148,29 @@ class FilterInsightTest extends \PHPUnit_Framework_TestCase $this->assertColumnValues($values); } + public function testShouldDetectWhetherRowIsNewMoverOrDisappeared() + { + $this->applyInsightConsiderAll(); + + $values = array( + array('label' => 'val1', 'isNew' => false, 'isMover' => true, 'isDisappeared' => false), + array('label' => 'val2', 'isNew' => true, 'isMover' => false, 'isDisappeared' => false), + array('label' => 'val3', 'isNew' => true, 'isMover' => false, 'isDisappeared' => false), + array('label' => 'val4', 'isNew' => false, 'isMover' => true, 'isDisappeared' => false), + array('label' => 'val5', 'isNew' => true, 'isMover' => false, 'isDisappeared' => false), + array('label' => 'val6', 'isNew' => false, 'isMover' => true, 'isDisappeared' => false), + array('label' => 'val7', 'isNew' => true, 'isMover' => false, 'isDisappeared' => false), + array('label' => 'val8', 'isNew' => false, 'isMover' => true, 'isDisappeared' => false), + array('label' => 'val9', 'isNew' => false, 'isMover' => true, 'isDisappeared' => false), + array('label' => 'val10', 'isNew' => false, 'isMover' => true, 'isDisappeared' => false), + array('label' => 'val102', 'isNew' => false, 'isMover' => false, 'isDisappeared' => true), + array('label' => 'val109', 'isNew' => false, 'isMover' => false, 'isDisappeared' => true), + array('label' => 'val107', 'isNew' => false, 'isMover' => false, 'isDisappeared' => true) + ); + + $this->assertColumnValues($values); + } + public function testShouldCalculateDifferenceAndGrowthPercentage() { $this->applyInsightConsiderAll(); diff --git a/plugins/Insights/tests/FilterOrderByTest.php b/plugins/Insights/tests/FilterOrderByTest.php index 0203bf58fb..fd613f2e73 100644 --- a/plugins/Insights/tests/FilterOrderByTest.php +++ b/plugins/Insights/tests/FilterOrderByTest.php @@ -68,7 +68,27 @@ class FilterOrderByTest extends \PHPUnit_Framework_TestCase $this->applyOrderByFilter(); - $this->assertOrder(array('pos4', 'pos2', 'pos1', 'pos3', 'pos6', 'pos5', 'neg3', 'neg1', 'neg2', 'neg4')); + $this->assertOrder(array('pos4', 'pos2', 'pos1', 'pos3', 'pos6', 'pos5', 'neg3', 'neg2', 'neg1', 'neg4')); + } + + public function testOrderByShouldSortDependingOnNbVisitsIfColumnsHaveSameValueAndNbVisitsIsNegative() + { + $this->table->addRowsFromArray(array( + array(Row::COLUMNS => array('label' => 'pos1', 'nb_visits' => -40, 'growth' => 7)), + array(Row::COLUMNS => array('label' => 'pos2', 'nb_visits' => -55, 'growth' => 7)), + array(Row::COLUMNS => array('label' => 'pos3', 'nb_visits' => -35, 'growth' => 7)), + array(Row::COLUMNS => array('label' => 'pos4', 'nb_visits' => -60, 'growth' => 7)), + array(Row::COLUMNS => array('label' => 'pos5', 'nb_visits' => -7, 'growth' => 7)), + array(Row::COLUMNS => array('label' => 'pos6', 'nb_visits' => -35, 'growth' => 7)), + array(Row::COLUMNS => array('label' => 'neg1', 'nb_visits' => -33, 'growth' => -5)), + array(Row::COLUMNS => array('label' => 'neg2', 'nb_visits' => -34, 'growth' => -5)), + array(Row::COLUMNS => array('label' => 'neg3', 'nb_visits' => -99, 'growth' => -5)), + array(Row::COLUMNS => array('label' => 'neg4', 'nb_visits' => -20, 'growth' => -5)) + )); + + $this->applyOrderByFilter(); + + $this->assertOrder(array('pos4', 'pos2', 'pos1', 'pos3', 'pos6', 'pos5', 'neg3', 'neg2', 'neg1', 'neg4')); } private function assertOrder($expectedOrder) @@ -79,7 +99,7 @@ class FilterOrderByTest extends \PHPUnit_Framework_TestCase private function applyOrderByFilter() { - $filter = new OrderBy($this->table, 'growth'); + $filter = new OrderBy($this->table, 'growth', 'nb_visits'); $filter->filter($this->table); } diff --git a/plugins/Insights/tests/Fixtures/SomeVisitsDifferentPathsOnTwoDays.php b/plugins/Insights/tests/Fixtures/SomeVisitsDifferentPathsOnTwoDays.php index 6fc2861b92..76320ca83c 100644 --- a/plugins/Insights/tests/Fixtures/SomeVisitsDifferentPathsOnTwoDays.php +++ b/plugins/Insights/tests/Fixtures/SomeVisitsDifferentPathsOnTwoDays.php @@ -33,7 +33,7 @@ class SomeVisitsDifferentPathsOnTwoDays extends \Test_Piwik_BaseFixture private function setUpWebsitesAndGoals() { if (!self::siteCreated($idSite = 1)) { - self::createWebsite('2008-12-12 00:00:00', $ecommerce = 0, $siteName = 'Site AAAAAA'); + $this->idSite = self::createWebsite('2008-12-12 00:00:00', $ecommerce = 0, $siteName = 'Site AAAAAA'); } } diff --git a/plugins/Insights/tests/InsightReportTest.php b/plugins/Insights/tests/InsightReportTest.php new file mode 100644 index 0000000000..6c8cd7d85a --- /dev/null +++ b/plugins/Insights/tests/InsightReportTest.php @@ -0,0 +1,242 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +namespace Piwik\Plugins\Insights\tests; + +use Piwik\DataTable; +use Piwik\DataTable\Row; +use Piwik\Plugins\Insights\InsightReport; + +/** + * @group Insights + * @group InsightReportTest + * @group Unit + * @group Core + */ +class InsightReportTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var InsightReport + */ + private $insightReport; + + /** + * @var DataTable + */ + private $currentTable; + + /** + * @var DataTable + */ + private $pastTable; + + /** + * val11 mov 5 170 +165 +3400% + * val7 new 0 134 +134 +100% + * val3 new 0 90 +90 +100% + * val10 mov 0 89 +89 +100% + * val2 new 0 70 +70 +100% + * val1 mov 102 120 +18 +18% + * val12 mov 5 14 +9 +180% + * val5 new 0 0 0 0% + * val109 dis 0 0 0 0% + * val6 mov 180 0 -180 -100% + * val107 dis 150 0 -150 -100% + * val9 mov 72 7 -65 -90% + * val8 mov 140 100 -40 -40% + * val102 dis 29 0 -29 -100% + * val4 mov 120 99 -21 -19% + */ + + // TODO use data providers + public function setUp() + { + $this->currentTable = new DataTable(); + $this->currentTable->addRowsFromArray(array( + array(Row::COLUMNS => array('label' => 'val1', 'nb_visits' => 120)), + array(Row::COLUMNS => array('label' => 'val2', 'nb_visits' => 70)), + array(Row::COLUMNS => array('label' => 'val3', 'nb_visits' => 90)), + array(Row::COLUMNS => array('label' => 'val4', 'nb_visits' => 99)), + array(Row::COLUMNS => array('label' => 'val5', 'nb_visits' => 0)), + array(Row::COLUMNS => array('label' => 'val6', 'nb_visits' => 0)), + array(Row::COLUMNS => array('label' => 'val7', 'nb_visits' => 134)), + array(Row::COLUMNS => array('label' => 'val8', 'nb_visits' => 100)), + array(Row::COLUMNS => array('label' => 'val9', 'nb_visits' => 7)), + array(Row::COLUMNS => array('label' => 'val10', 'nb_visits' => 89)), + array(Row::COLUMNS => array('label' => 'val11', 'nb_visits' => 170)), + array(Row::COLUMNS => array('label' => 'val12', 'nb_visits' => 14)) + )); + + $this->pastTable = new DataTable(); + $this->pastTable->addRowsFromArray(array( + array(Row::COLUMNS => array('label' => 'val1', 'nb_visits' => 102)), + array(Row::COLUMNS => array('label' => 'val102', 'nb_visits' => 29)), + array(Row::COLUMNS => array('label' => 'val4', 'nb_visits' => 120)), + array(Row::COLUMNS => array('label' => 'val6', 'nb_visits' => 180)), + array(Row::COLUMNS => array('label' => 'val109', 'nb_visits' => 0)), + array(Row::COLUMNS => array('label' => 'val8', 'nb_visits' => 140)), + array(Row::COLUMNS => array('label' => 'val9', 'nb_visits' => 72)), + array(Row::COLUMNS => array('label' => 'val107', 'nb_visits' => 150)), + array(Row::COLUMNS => array('label' => 'val10', 'nb_visits' => 0)), + array(Row::COLUMNS => array('label' => 'val11', 'nb_visits' => 5)), + array(Row::COLUMNS => array('label' => 'val12', 'nb_visits' => 5)) + )); + + $this->insightReport = new InsightReport(); + } + + public function testImportanceOrder() + { + $report = $this->generateInsight(2, 2, 2, 17, InsightReport::ORDER_BY_IMPORTANCE, 99, 99); + $this->assertOrder($report, array('val6', 'val11', 'val107', 'val7', 'val3', 'val10', 'val2', 'val9', 'val8', 'val102', 'val4', 'val1', 'val12')); + } + + public function testRelativeOrder() + { + $report = $this->generateInsight(2, 2, 2, 17, InsightReport::ORDER_BY_RELATIVE, 99, 99); + $this->assertOrder($report, array('val11', 'val12', 'val7', 'val3', 'val10', 'val2', 'val1', 'val6', 'val107', 'val102', 'val9', 'val8', 'val4')); + } + + public function testMinGrowth() + { + $report = $this->generateInsight(2, 2, 2, 4000, 'absolute', 99, 99); + $this->assertOrder($report, array()); + + $report = $this->generateInsight(2, 2, 2, 1000, 'absolute', 99, 99); + $this->assertOrder($report, array('val11')); + + $report = $this->generateInsight(2, 2, 2, 120, 'absolute', 99, 99); + $this->assertOrder($report, array('val11', 'val12')); + + $report = $this->generateInsight(2, 2, 2, 80, 'absolute', 99, 99); + $this->assertOrder($report, array('val11', 'val7', 'val3', 'val10', 'val2', 'val12', 'val6', 'val107', 'val9', 'val102')); + + $report = $this->generateInsight(2, 2, 2, 19, 'absolute', 99, 99); + $this->assertOrder($report, array('val11', 'val7', 'val3', 'val10', 'val2', 'val12', 'val6', 'val107', 'val9', 'val8', 'val102')); + + $report = $this->generateInsight(2, 2, 2, 17, 'absolute', 99, 99); + $this->assertOrder($report, array('val11', 'val7', 'val3', 'val10', 'val2', 'val1', 'val12', 'val6', 'val107', 'val9', 'val8', 'val102', 'val4')); + } + + public function testLimit() + { + $report = $this->generateInsight(2, 2, 2, 20, 'absolute', 1, 1); + + $this->assertOrder($report, array('val11', 'val6')); + } + + public function testLimitOnlyIncrease() + { + $report = $this->generateInsight(2, 2, 2, 20, 'absolute', 1, 0); + + $this->assertOrder($report, array('val11')); + } + + public function testLimitOnlyDecrease() + { + $report = $this->generateInsight(2, 2, 2, 20, 'absolute', 0, 1); + + $this->assertOrder($report, array('val6')); + } + + public function testLimitOnlyNone() + { + $report = $this->generateInsight(2, 2, 2, 20, 'absolute', 0, 0); + + $this->assertOrder($report, array()); + } + + public function testNoMovers() + { + $report = $this->generateInsight(-1, 2, 2, 20, 'absolute', 99, 99); + + $this->assertOrder($report, array('val7', 'val3', 'val2', 'val107', 'val102')); + } + + public function testMinImpactMovers() + { + $report = $this->generateInsight(2, -1, -1, 17, 'absolute', 99, 99); + $this->assertOrder($report, array('val11', 'val10', 'val1', 'val12', 'val6', 'val9', 'val8', 'val4')); + + $report = $this->generateInsight(20, -1, -1, 17, 'absolute', 99, 99); + $this->assertOrder($report, array('val11', 'val10', 'val6', 'val9', 'val8')); + + $report = $this->generateInsight(80, -1, -1, 17, 'absolute', 99, 99); + $this->assertOrder($report, array('val11', 'val6')); + + $report = $this->generateInsight(10000, -1, -1, 17, 'absolute', 99, 99); + $this->assertOrder($report, array()); + } + + public function testNoNew() + { + $report = $this->generateInsight(2, -1, 2, 17, 'absolute', 99, 99); + $this->assertOrder($report, array('val11', 'val10', 'val1', 'val12', 'val6', 'val107', 'val9', 'val8', 'val102', 'val4')); + } + + public function testMinImpactNew() + { + $report = $this->generateInsight(-1, 2, -1, 17, 'absolute', 99, 99); + $this->assertOrder($report, array('val7', 'val3', 'val2')); + + $report = $this->generateInsight(-1, 22, -1, 17, 'absolute', 99, 99); + $this->assertOrder($report, array('val7', 'val3', 'val2')); + + $report = $this->generateInsight(-1, 36, -1, 17, 'absolute', 99, 99); + $this->assertOrder($report, array('val7', 'val3')); + + $report = $this->generateInsight(-1, 66, -1, 17, 'absolute', 99, 99); + $this->assertOrder($report, array('val7')); + + $report = $this->generateInsight(-1, 10000, -1, 17, 'absolute', 99, 99); + $this->assertOrder($report, array()); + } + + public function testNoDisappeared() + { + $report = $this->generateInsight(2, 2, -1, 17, 'absolute', 99, 99); + $this->assertOrder($report, array('val11', 'val7', 'val3', 'val10', 'val2', 'val1', 'val12', 'val6', 'val9', 'val8', 'val4')); + } + + public function testMinDisappeared() + { + $report = $this->generateInsight(-1, -1, 2, 17, 'absolute', 99, 99); + $this->assertOrder($report, array('val107', 'val102')); + + $report = $this->generateInsight(-1, -1, 14, 17, 'absolute', 99, 99); + $this->assertOrder($report, array('val107', 'val102')); + + $report = $this->generateInsight(-1, -1, 15, 17, 'absolute', 99, 99); + $this->assertOrder($report, array('val107')); + + $report = $this->generateInsight(-1, -1, 75, 17, 'absolute', 99, 99); + $this->assertOrder($report, array('val107')); + + $report = $this->generateInsight(-1, -1, 76, 17, 'absolute', 99, 99); + $this->assertOrder($report, array()); + + $report = $this->generateInsight(-1, -1, 10000, 17, 'absolute', 99, 99); + $this->assertOrder($report, array()); + } + + private function generateInsight($minVisitsMoversPercent, $minVisitsNewPercent, $minVisitsDisappearedPercent, $minGrowthPercent, $orderBy, $limitIncreaser, $limitDecreaser) + { + $reportMetadata = array('name' => 'TestReport', 'metrics' => array('nb_visits' => 'Visits')); + $report = $this->insightReport->generateInsight( + $reportMetadata, 'day', 'today', 'yesterday', 'nb_visits', $this->currentTable, $this->pastTable, $totalValue = 200, + $minVisitsMoversPercent, $minVisitsNewPercent, $minVisitsDisappearedPercent, $minGrowthPercent, $orderBy, $limitIncreaser, $limitDecreaser); + + return $report; + } + + private function assertOrder(DataTable $table, $expectedOrder) + { + $this->assertEquals($expectedOrder, $table->getColumn('label')); + $this->assertEquals(count($expectedOrder), $table->getRowsCount()); + } +} diff --git a/plugins/Insights/tests/ModelTest.php b/plugins/Insights/tests/ModelTest.php new file mode 100644 index 0000000000..36bbe18012 --- /dev/null +++ b/plugins/Insights/tests/ModelTest.php @@ -0,0 +1,174 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +namespace Piwik\Plugins\Insights\tests; + +use Piwik\DataTable; +use Piwik\Plugins\Insights\Model; +use Piwik\Plugins\Insights\tests\Fixtures\SomeVisitsDifferentPathsOnTwoDays; + +/** + * @group Insights + * @group ModelTest + * @group Database + * @group Plugins + */ +class ModelTest extends \IntegrationTestCase +{ + /** + * @var SomeVisitsDifferentPathsOnTwoDays + */ + public static $fixture = null; + + /** + * @var Model + */ + private $model; + + public function setUp() + { + parent::setUp(); + + $this->model = new Model(); + } + + public function test_requestReport_shouldReturnTheDataTableOfTheReport_AndContainReportTotals() + { + $idSite = self::$fixture->idSite; + $date = self::$fixture->date1; + $metric = 'nb_visits'; + + $table = $this->model->requestReport($idSite, 'day', $date, 'Actions_getPageUrls', $metric, false); + + $this->assertEquals(5, $table->getRowsCount()); + + $totals = $table->getMetadata('totals'); + $this->assertEquals(50, $totals[$metric]); + } + + public function test_getReportByUniqueId_shouldReturnReport() + { + $report = $this->model->getReportByUniqueId(self::$fixture->idSite, 'Actions_getPageUrls'); + + $this->assertEquals('Actions', $report['module']); + $this->assertEquals('getPageUrls', $report['action']); + } + + public function test_getLastDate_shouldReturnTheLastDateDependingOnPeriod() + { + $date = $this->model->getLastDate('2012-12-12', 'day', 1); + $this->assertEquals('2012-12-11', $date); + + $date = $this->model->getLastDate('2012-12-12', 'week', 1); + $this->assertEquals('2012-12-05', $date); + + $date = $this->model->getLastDate('2012-12-03', 'week', 1); + $this->assertEquals('2012-11-26', $date); + + $date = $this->model->getLastDate('2012-12-02', 'week', 1); + $this->assertEquals('2012-11-25', $date); + + $date = $this->model->getLastDate('2012-12-12', 'month', 1); + $this->assertEquals('2012-11-12', $date); + + $date = $this->model->getLastDate('2012-12-01', 'month', 1); + $this->assertEquals('2012-11-01', $date); + } + + public function test_getLastDate_shouldReturnTheLastDateDependingOnComparedTo() + { + $date = $this->model->getLastDate('2012-12-12', 'day', 1); + $this->assertEquals('2012-12-11', $date); + + $date = $this->model->getLastDate('2012-12-12', 'day', 2); + $this->assertEquals('2012-12-10', $date); + + $date = $this->model->getLastDate('2012-12-12', 'day', 7); + $this->assertEquals('2012-12-05', $date); + } + + public function test_getMetricTotalValue_shouldReturnTheTotalValueFromMetadata() + { + $table = $this->getTableWithTotal('17'); + + $total = $this->model->getMetricTotalValue($table, 'nb_visits'); + + $this->assertEquals(17, $total); + $this->assertInternalType('integer', $total); + } + + public function test_getMetricTotalValue_shouldReturnZeroIfMetricHasNoTotal() + { + $table = new DataTable(); + $table->setMetadata('totals', array('nb_visits' => '17')); + + $total = $this->model->getMetricTotalValue($table, 'unknown_metric'); + + $this->assertEquals(0, $total); + } + + /** + * @expectedException \Exception + */ + public function test_getLastDate_shouldThrowExceptionIfNotPossibleToGetLastDate() + { + $this->model->getLastDate('last10', 'day', 1); + } + + public function test_getTotalValue_shouldCalculateTotals() + { + $total = $this->model->getTotalValue(self::$fixture->idSite, 'day', self::$fixture->date1, 'nb_visits'); + $this->assertEquals(50, $total); + + $total = $this->model->getTotalValue(self::$fixture->idSite, 'day', self::$fixture->date2, 'nb_visits'); + $this->assertEquals(59, $total); + } + + /** + * @expectedException \Exception + */ + public function test_getTotalValue_shouldReturnZero_IfColumnDoesNotExist() + { + $this->model->getTotalValue(self::$fixture->idSite, 'day', self::$fixture->date1, 'unknown_ColUmn'); + } + + public function test_getRelevantTotalValue_shouldReturnTotalValue_IfMetricTotalIsHighEnough() + { + $table = $this->getTableWithTotal(25); + $total = $this->model->getRelevantTotalValue($table, self::$fixture->idSite, 'day', self::$fixture->date1, 'nb_visits'); + $this->assertEquals(50, $total); + } + + public function test_getRelevantTotalValue_shouldReturnMetricTotal_IfMetricTotalIsHigherThanTotalValue() + { + $table = $this->getTableWithTotal(80); + $total = $this->model->getRelevantTotalValue($table, self::$fixture->idSite, 'day', self::$fixture->date1, 'nb_visits'); + $this->assertEquals(80, $total); + } + + public function test_getRelevantTotalValue_shouldReturnMetricTotal_IfMetricTotalIsTooLow() + { + $table = $this->getTableWithTotal(24); + $total = $this->model->getRelevantTotalValue($table, self::$fixture->idSite, 'day', self::$fixture->date1, 'nb_visits'); + $this->assertEquals(24, $total); + + $table = $this->getTableWithTotal(0); + $total = $this->model->getRelevantTotalValue($table, self::$fixture->idSite, 'day', self::$fixture->date1, 'nb_visits'); + $this->assertEquals(0, $total); + } + + private function getTableWithTotal($total) + { + $table = new DataTable(); + $table->setMetadata('totals', array('nb_visits' => $total)); + return $table; + } + +} + +ModelTest::$fixture = new SomeVisitsDifferentPathsOnTwoDays();
\ No newline at end of file diff --git a/plugins/Installation/Controller.php b/plugins/Installation/Controller.php index 85dc80d3f7..fd4e91642e 100644 --- a/plugins/Installation/Controller.php +++ b/plugins/Installation/Controller.php @@ -871,7 +871,6 @@ class Controller extends \Piwik\Plugin\ControllerAdmin $infos['serverOs'] = @php_uname(); $infos['serverTime'] = date('H:i:s'); - $infos['registerGlobals_ok'] = ini_get('register_globals') == 0; $infos['memoryMinimum'] = $minimumMemoryLimit; $infos['memory_ok'] = true; @@ -940,7 +939,6 @@ class Controller extends \Piwik\Plugin\ControllerAdmin if ( !empty($infos['missing_desired_extensions']) || !$infos['gd_ok'] || !$infos['multibyte_ok'] - || !$infos['registerGlobals_ok'] || !$infos['memory_ok'] || !empty($infos['integrityErrorMessages']) || !$infos['timezone'] // if timezone support isn't available diff --git a/plugins/SegmentEditor/javascripts/Segmentation.js b/plugins/SegmentEditor/javascripts/Segmentation.js index abf8852a0e..c9b197c2a7 100644 --- a/plugins/SegmentEditor/javascripts/Segmentation.js +++ b/plugins/SegmentEditor/javascripts/Segmentation.js @@ -1072,7 +1072,7 @@ $(document).ready(function() { var idx = null; for (idx in self.props.availableSegments) { - if (self.props.availableSegments[idx].definition == params.definition) { + if (self.props.availableSegments[idx].idsegment == params.idSegment) { break; } } @@ -1170,7 +1170,7 @@ $(document).ready(function() { } }; - $('body')[0].addEventListener('mouseup', this.onMouseUp); + $('body').on('mouseup', this.onMouseUp); // re-initialize top controls since the size of the control is not the same after it's // initialized. @@ -1198,7 +1198,7 @@ $(document).ready(function() { _destroy: function () { UIControl.prototype._destroy.call(this); - $('body')[0].removeEventListener('mouseup', this.onMouseUp); + $('body').off('mouseup', null, this.onMouseUp); } }); diff --git a/plugins/Widgetize/templates/index.twig b/plugins/Widgetize/templates/index.twig index ba462bd7ab..bbf6896214 100644 --- a/plugins/Widgetize/templates/index.twig +++ b/plugins/Widgetize/templates/index.twig @@ -63,4 +63,7 @@ <div id='iframeDivToExport' style='display:none;'></div> </div> </div> + +{% include "@Dashboard/_widgetFactoryTemplate.twig" %} + {% endblock %}
\ No newline at end of file diff --git a/tests/webtest/config/webtest.example.properties b/tests/webtest/config/webtest.example.properties deleted file mode 100644 index 86ed420d43..0000000000 --- a/tests/webtest/config/webtest.example.properties +++ /dev/null @@ -1,47 +0,0 @@ -################################################ -# Test suite configuration file -################################################ - -### WebTests config -wt.home=/usr/local/canoo -wt.config.host=127.0.0.1 -wt.config.port=80 -wt.config.protocol=http -wt.config.basepath=/piwik - -wt.config.failOnError=true -wt.config.haltOnError=true -wt.config.haltOnFailure=true -wt.config.enableJS=true -wt.config.throwExceptionOnScriptError=true -wt.config.browser=Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12 -wt.config.verifyLinks=true -wt.config.verifyImages=true -wt.config.headless=false -#wt.openResultFile.skip=true - -## General settings -testcase.dir=./testcases - -# patterns for each level -testcase.level0.pattern=*.xml -testcase.level1.pattern=*.xml -testcase.level2.pattern=*.xml -testcase.level3.pattern=*.xml -screens=manual_results - -## To turn on/off specific level of tests just uncomment/comment appropriate line below -test.level0=true -test.level1=true -#test.level2=true -#test.level3=true - -## db settings -db.username=username -db.password=password -db.port=3306 -db.name=piwik -db.host=127.0.0.1 - -## Google API key -google.apikey= diff --git a/tests/webtest/test_suite.xml b/tests/webtest/test_suite.xml deleted file mode 100644 index 7efe10ed71..0000000000 --- a/tests/webtest/test_suite.xml +++ /dev/null @@ -1,50 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project name="Piwik" default="Level3" basedir="."> - - <target name="setup"> - <mkdir dir="${screens}" /> - </target> - - <target name="Level0" if="test.level0" depends="setup"> - <echo>Starting smoke tests...</echo> - <subant failonerror="${wt.config.failOnError}" inheritall="true"> - <fileset dir="${testcase.dir}/level0" includes="${testcase.level0.pattern}"/> - </subant> - <echo>##################################</echo> - <echo># 0 level smoke tests - FINISHED!#</echo> - <echo>##################################</echo> - </target> - - <target name="Level1" if="test.level1" depends="Level0"> - <echo>Starting setup tests...</echo> - <subant failonerror="${wt.config.failOnError}" inheritall="true"> - <fileset dir="${testcase.dir}/level1" includes="${testcase.level1.pattern}"/> - </subant> - <echo>#################################</echo> - <echo># 1st level tests - FINISHED! #</echo> - <echo>#################################</echo> - </target> - - <target name="Level2" if="test.level2" depends="Level1"> - <echo>Starting setup tests...</echo> - <subant failonerror="${wt.config.failOnError}" inheritall="true"> - <fileset dir="${testcase.dir}/level2" includes="${testcase.level2.pattern}"/> - </subant> - <echo>###################################</echo> - <echo># 2nd level test - FINISHED! #</echo> - <echo>###################################</echo> - </target> - - <target name="Level3" if="test.level3" depends="Level2"> - <echo>Starting UI tests - 3rd level...</echo> - <echo>+-----------------------------------------+</echo> - <echo>| WARNING! 3rd Level tests are optional |</echo> - <echo>| and could fail without BUILD FAILED! |</echo> - <echo>+-----------------------------------------+</echo> - <subant failonerror="${wt.config.failOnError}" inheritall="true"> - <fileset dir="${testcase.dir}/level3" includes="${testcase.level3.pattern}"/> - </subant> - <echo>3rd level smoke tests finished - check for potential errors!</echo> - </target> - -</project> diff --git a/tests/webtest/testcases/level0/1.1-install.disabled b/tests/webtest/testcases/level0/1.1-install.disabled deleted file mode 100644 index b75a929b40..0000000000 --- a/tests/webtest/testcases/level0/1.1-install.disabled +++ /dev/null @@ -1,229 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!DOCTYPE project [ - <!ENTITY time SYSTEM "../modules/time.xml"> - <!ENTITY checkForErrors SYSTEM "../modules/errors.xml"> - <!ENTITY verifyLinksAndImages SYSTEM "../modules/common_pages.xml"> - <!ENTITY loadMacros SYSTEM "../modules/macros.xml"> - <!ENTITY raquo "»"> - <!ENTITY rsaquo "›" > -]> - -<project name="Smoke test level0 - deploy test" basedir="." default="webtest"> - &time; - <target name="webtest"> - <webtest name="install index"> - <steps> - <echo>Installation</echo> - - &loadMacros; - - <echo>Piwik install - dbsetup: db.name: ${db.name}</echo> - <sql - driver="com.mysql.jdbc.Driver" - url="jdbc:mysql://${db.host}:${db.port}/" - userid="${db.username}" - password="${db.password}" - > - <classpath> - <pathelement location="${basedir}/../lib/java/mysql-connector-java-5.1.7.jar" /> - </classpath> - <transaction> - DROP DATABASE IF EXISTS ${db.name}; - </transaction> - <transaction> - CREATE DATABASE IF NOT EXISTS ${db.name}; - </transaction> - </sql> - - <invoke description="get index" url="/" /> - - <!-- 1. welcome --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Welcome!" /> - <verifyText description="check page text" text="This process is split up into 9 easy steps and will take around 5 minutes" /> - -<!-- - &checkForErrors; ---> - &verifyLinksAndImages; - - <retryClickLink description="wait for piwik.php tracking test" label="Next »" maxcount="10" seconds="1" /> - - <!-- 2. systemCheck --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="System Check" /> - <verifyText description="check page text" text="Optional" /> - - &checkForErrors; - &verifyLinksAndImages; - - <not description="check if system check passed"> - <verifyXPath description="looking for error image" xpath="//img[@src='plugins/Zeitgeist/images/error.png']" /> - </not> - - <verifyXPath description="looking for ok image" xpath="//img[@src='plugins/Zeitgeist/images/ok.png']" /> - - <clickLink description="click 'Next'" label="Next »" /> - - <!-- 3. databaseSetup --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Database Setup" /> - - &checkForErrors; - &verifyLinksAndImages; - - <setInputField description="set database host (and port)" name="host" value="${db.host}:${db.port}" /> - <setInputField description="set database username" name="username" value="${db.username}" /> - <setInputField description="set database password" name="password" value="${db.password}" /> - <setInputField description="set database name" name="dbname" value="${db.name}" /> - <setInputField description="set database port" name="tables_prefix" value="canoo_" /> - - <clickButton description="click 'Next »' button" label="Next »" /> - - <!-- 4. databaseCheck --> -<!-- - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Database Check" /> - - &checkForErrors; - &verifyLinksAndImages; - - <clickLink description="click 'Next'" label="Next »" /> ---> - - <!-- 5. tablesCreation --> - - <not description="check if no error"> - <verifyXPath description="looking for error image" xpath="//img[@src='plugins/Zeitgeist/images/error_medium.png']" /> - </not> - - <not description="check if no warning"> - <verifyXPath description="looking for warning image" xpath="//img[@src='plugins/Zeitgeist/images/warning_medium.png']" /> - </not> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Tables created with success!" /> - <verifyXPath description="looking for success image" xpath="//img[@src='plugins/Zeitgeist/images/success_medium.png']" /> - - &checkForErrors; - &verifyLinksAndImages; - - <clickLink description="click 'Next'" label="Next »" /> - - <!-- 6. generalSetup --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Super User" /> - - &checkForErrors; - &verifyLinksAndImages; - - <setInputField description="set Piwik login" name="login" value="piwik_login" /> - <setInputField description="set Piwik password" name="password" value="piwik_password" /> - <setInputField description="set repeated Piwik password" name="password_bis" value="piwik_password" /> - <setInputField description="set Piwik email" name="email" value="nobody@piwik.org" /> - - <clickButton description="click 'Next »' button" label="Next »" /> - - <!-- 7. firstWebsiteSetup --> - - <not description="check if no error"> - <verifyXPath description="looking for error image" xpath="//img[@src='plugins/Zeitgeist/images/error_medium.png']" /> - </not> - - <not description="check if no warning"> - <verifyXPath description="looking for warning image" xpath="//img[@src='plugins/Zeitgeist/images/warning_medium.png']" /> - </not> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Setup a Website" /> - - &checkForErrors; - &verifyLinksAndImages; - - <setInputField description="set Piwik site name" name="siteName" value="Dummy Site Name" /> - <setInputField description="set Piwik URL" name="url" value="${wt.config.protocol}://${wt.config.host}:${wt.config.port}${wt.config.basepath}" /> - <setSelectField description="set Piwik timezone" name="timezone" value="UTC" /> - - <clickButton description="click 'Next »' button" label="Next »" /> - - <!-- 8. displayJavascriptCode --> - - <not description="check if no error"> - <verifyXPath description="looking for error image" xpath="//img[@src='plugins/Zeitgeist/images/error_medium.png']" /> - </not> - - <not description="check if no warning"> - <verifyXPath description="looking for warning image" xpath="//img[@src='plugins/Zeitgeist/images/warning_medium.png']" /> - </not> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="JavaScript Tracking code" /> - - &checkForErrors; - &verifyLinksAndImages; - - <clickLink description="click 'Next'" label="Next »" /> - - <!-- 9. finished --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Congratulations" /> - - &checkForErrors; - &verifyLinksAndImages; - - <clickLink description="click 'Continue to Piwik'" label="Continue to Piwik »" /> - - <!-- logging in --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Lost your password?" /> - - &checkForErrors; - &verifyLinksAndImages; - - <setInputField description="set Piwik login" htmlId="form_login" value="piwik_login" /> - <setInputField description="set Piwik password" htmlId="form_password" value="piwik_password" /> - - <clickButton description="click 'Sign in' button" label="Sign in" /> - - <!-- logged in --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Web Analytics Reports - Dummy Site Name" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Dashboard" /> - <verifyText description="check page text" text="Hello" /> - - <!-- change language --> -<!-- - <clickElement description="click 'Deutsch'" xpath="//select[@id='language']/option[@value='de']" /> - - <verifyText description="check page text" text="Hallo" /> - - <clickElement description="click 'Français'" xpath="//select[@id='language']/option[@value='fr']" /> - - <verifyText description="check page text" text="Bonjour" /> - - <clickElement description="click 'English'" xpath="//select[@id='language']/option[@value='en']" /> - - <verifyText description="check page text" text="Hello" /> ---> - </steps> - </webtest> - </target> -</project> diff --git a/tests/webtest/testcases/level0/1.2-loginforms.disabled b/tests/webtest/testcases/level0/1.2-loginforms.disabled deleted file mode 100644 index 3917bedf4e..0000000000 --- a/tests/webtest/testcases/level0/1.2-loginforms.disabled +++ /dev/null @@ -1,297 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!DOCTYPE project [ - <!ENTITY time SYSTEM "../modules/time.xml"> - <!ENTITY checkForErrors SYSTEM "../modules/errors.xml"> - <!ENTITY verifyLinksAndImages SYSTEM "../modules/common_pages.xml"> - <!ENTITY loadMacros SYSTEM "../modules/macros.xml"> - <!ENTITY raquo "»"> - <!ENTITY rsaquo "›" > -]> - -<project name="Smoke test level0 - deploy test" basedir="." default="webtest"> - &time; - <target name="webtest"> - <webtest name="login forms"> - <config> - <header name="piwik_auth" value="" /> - </config> - <steps> - <echo>Login Forms</echo> - - &loadMacros; - - <invoke description="get login form" url="/" /> - - <!-- login (blank) --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Lost your password?" /> - - &checkForErrors; - &verifyLinksAndImages; - - <clickButton description="click 'Sign in' button" label="Sign in" /> - - <!-- login (invalid) --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Lost your password?" /> - - <verifyText description="check page text" text="<strong>Error</strong>: Username required" /> - <verifyText description="check page text" text="<strong>Error</strong>: Password required" /> - - &checkForErrors; - &verifyLinksAndImages; - - <setInputField description="set Piwik login" htmlId="form_login" value="piwik_login" /> - <setInputField description="set Piwik password" htmlId="form_password" value="invalid_password" /> - - <clickButton description="click 'Sign in' button" label="Sign in" /> - - <!-- lost password --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Lost your password?" /> - - <verifyText description="check page text" text="<strong>Error</strong>: Username & Password not correct" /> - - &checkForErrors; - &verifyLinksAndImages; - - <clickLink description="click 'Lost your password?'" label="Lost your password?" /> - - <!-- send password reset (blank) --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Sign in" /> - - &checkForErrors; - &verifyLinksAndImages; - - <clickButton description="click 'Send password reset' button" label="Send password reset" /> - - <!-- send password reset (invalid) --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Sign in" /> - - <verifyText description="check page text" text="<strong>Error</strong>: Username or E-mail required" /> - - &checkForErrors; - &verifyLinksAndImages; - - <setInputField description="set Piwik login" htmlId="form_login" value="invalid" /> - - <clickButton description="click 'Send password reset' button" label="Send password reset" /> - - <!-- send password reset (ok) --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Sign in" /> - - <verifyText description="check page text" text="<strong>Error</strong>: Invalid username and/or e-mail address" /> - - &checkForErrors; - &verifyLinksAndImages; - - <setInputField description="set Piwik login" htmlId="form_login" value="piwik_login" /> - - <clickButton description="click 'Send password reset' button" label="Send password reset" /> - - <!-- sent --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Sign in" /> - - <ifStep description="check email was sent"> - <condition> - <not> - <verifyText description="check page text" text="Information to reset your password has been sent. Check your e-mail." /> - </not> - </condition> - <then> - <verifyText description="check page text" text="<strong>Error</strong>: Unable to send mail." /> - </then> - </ifStep> - - &checkForErrors; - &verifyLinksAndImages; - - <clickLink description="click 'Sign in'" label="Sign in" /> - - <!-- login --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Lost your password?" /> - - &checkForErrors; - &verifyLinksAndImages; - - <setInputField description="set Piwik login" htmlId="form_login" value="piwik_login" /> - <setInputField description="set Piwik password" htmlId="form_password" value="piwik_password" /> - - <clickButton description="click 'Sign in' button" label="Sign in" /> - - <!-- logged in; now, logout --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Web Analytics Reports - Dummy Site Name" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Dashboard" /> - <verifyText description="check page text" text="Hello" /> - <verifyText description="check page text" text="Sign out" /> - - <retryClickLink description="click 'Sign out'" label="Sign out" seconds="5" /> - - <!-- logged out --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Sign in" /> - - &checkForErrors; - &verifyLinksAndImages; - - <not description="no auth cookie"> - <verifyCookie name="piwik_auth" regex="login"/> - <verifyCookie name="piwik_auth" regex="token_auth"/> - </not> - - <invoke description="get reset password form" url="/index.php?module=Login&action=resetPassword" /> - - <!-- reset password (blank) --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Lost your password?" /> - <verifyText description="check page text" text="Password reset token:" /> - - &checkForErrors; - &verifyLinksAndImages; - - <clickButton description="click 'Change password' button" label="Change password" /> - - <!-- reset password (password mismatch) --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Lost your password?" /> - <verifyText description="check page text" text="Password reset token:" /> - - <verifyText description="check page text" text="<strong>Error</strong>: Username required" /> - <verifyText description="check page text" text="<strong>Error</strong>: Password required" /> - <verifyText description="check page text" text="<strong>Error</strong>: Password (repeat) required" /> - <verifyText description="check page text" text="<strong>Error</strong>: Password reset token required" /> - - &checkForErrors; - &verifyLinksAndImages; - - <setInputField description="set Piwik login" htmlId="form_login" value="piwik_login" /> - <setInputField description="set Piwik password" htmlId="form_password" value="invalid1" /> - <setInputField description="set Piwik password bis" htmlId="form_password_bis" value="invalid2" /> - <setInputField description="set Piwik reset token" htmlId="form_token" value="invalid" /> - - <clickButton description="click 'Change password' button" label="Change password" /> - - <!-- reset password (invalid user) --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Lost your password?" /> - <verifyText description="check page text" text="Password reset token:" /> - - <verifyText description="check page text" text="<strong>Error</strong>: Passwords do not match." /> - - &checkForErrors; - &verifyLinksAndImages; - - <setInputField description="set Piwik login" htmlId="form_login" value="invalid" /> - <setInputField description="set Piwik password" htmlId="form_password" value="invalid" /> - <setInputField description="set Piwik password bis" htmlId="form_password_bis" value="invalid" /> - <setInputField description="set Piwik reset token" htmlId="form_token" value="invalid" /> - - <clickButton description="click 'Change password' button" label="Change password" /> - - <!-- reset password (invalid token) --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Lost your password?" /> - <verifyText description="check page text" text="Password reset token:" /> - - <verifyText description="check page text" text="<strong>Error</strong>: Invalid username and/or e-mail address" /> - - &checkForErrors; - &verifyLinksAndImages; - - <setInputField description="set Piwik login" htmlId="form_login" value="piwik_login" /> - <setInputField description="set Piwik password" htmlId="form_password" value="piwik_password" /> - <setInputField description="set Piwik password bis" htmlId="form_password_bis" value="piwik_password" /> - <setInputField description="set Piwik reset token" htmlId="form_token" value="invalid" /> - - <clickButton description="click 'Change password' button" label="Change password" /> - - <!-- reset password (ok) --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Lost your password?" /> - <verifyText description="check page text" text="Password reset token:" /> - - <verifyText description="check page text" text="<strong>Error</strong>: Token is invalid or has expired." /> - - &checkForErrors; - &verifyLinksAndImages; - - <generateResetToken output="piwik_reset_token" /> - - <setInputField description="set Piwik login" htmlId="form_login" value="piwik_login" /> - <setInputField description="set Piwik password" htmlId="form_password" value="new_password" /> - <setInputField description="set Piwik password bis" htmlId="form_password_bis" value="new_password" /> - <setInputField description="set Piwik reset token" htmlId="form_token" value="${piwik_reset_token}" /> - - <clickButton description="click 'Change password' button" label="Change password" /> - - <!-- reset; now sign-in --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Sign in" /> - - <verifyText description="check page text" text="Password successfully changed!" /> - - <clickLink description="click 'Sign in'" label="Sign in" /> - - <!-- login with new password --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Lost your password?" /> - - &checkForErrors; - &verifyLinksAndImages; - - <setInputField description="set Piwik login" htmlId="form_login" value="piwik_login" /> - <setInputField description="set Piwik password" htmlId="form_password" value="new_password" /> - - <clickButton description="click 'Sign in' button" label="Sign in" /> - - <!-- logged in --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Web Analytics Reports - Dummy Site Name" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Dashboard" /> - <verifyText description="check page text" text="Hello" /> - - </steps> - </webtest> - </target> -</project> diff --git a/tests/webtest/testcases/level0/1.3-unit-tests.disabled b/tests/webtest/testcases/level0/1.3-unit-tests.disabled deleted file mode 100644 index 530871d78a..0000000000 --- a/tests/webtest/testcases/level0/1.3-unit-tests.disabled +++ /dev/null @@ -1,63 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!DOCTYPE project [ - <!ENTITY time SYSTEM "../modules/time.xml"> - <!ENTITY checkForErrors SYSTEM "../modules/errors.xml"> - <!ENTITY verifyLinksAndImages SYSTEM "../modules/common_pages.xml"> - <!ENTITY loadMacros SYSTEM "../modules/macros.xml"> - <!ENTITY raquo "»"> - <!ENTITY rsaquo "›" > - -]> - -<project name="Smoke test level0 - deploy test" basedir="." default="webtest"> - &time; - <target name="webtest"> - <webtest name="unit tests"> - <config timeout="600" /> - <steps> - <echo>Unit Tests</echo> - - &loadMacros; - - <echo>Piwik install - dbsetup: db.name: ${db.name}</echo> - <sql - driver="com.mysql.jdbc.Driver" - url="jdbc:mysql://${db.host}:${db.port}/" - userid="${db.username}" - password="${db.password}" - > - <classpath> - <pathelement location="${basedir}/../lib/java/mysql-connector-java-5.1.7.jar" /> - </classpath> - <transaction> - DROP DATABASE IF EXISTS ${db.name}; - </transaction> - <transaction> - CREATE DATABASE IF NOT EXISTS ${db.name}; - </transaction> - </sql> - - <concat destfile="${basedir}/../../config/config.ini.php" append="true" fixlastline="true"> - <fileset file="${basedir}/../config/wt.template.ini" /> - <filterchain> - <expandproperties /> - </filterchain> - </concat> - - <invoke description="get all_tests" url="/tests/all_tests.php" /> - - <verifyTitle description="check the title is parsed correctly" text="Piwik - running all tests" /> - <verifyText description="check page text" text="Piwik unit tests" /> - - <not description="total failure"> - <verifyText description="check for 0 passes" text="<strong>0</strong> passes" /> - </not> - - <verifyText description="no failures" text="<strong>0</strong> fails" /> - - <verifyText description="no exceptions" text="<strong>0</strong> exceptions" /> - </steps> - </webtest> - </target> -</project> diff --git a/tests/webtest/testcases/level0/1.4-javascript.xml b/tests/webtest/testcases/level0/1.4-javascript.xml deleted file mode 100644 index 8b0378d135..0000000000 --- a/tests/webtest/testcases/level0/1.4-javascript.xml +++ /dev/null @@ -1,195 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!DOCTYPE project [ - <!ENTITY time SYSTEM "../modules/time.xml"> - <!ENTITY checkForErrors SYSTEM "../modules/errors.xml"> - <!ENTITY verifyLinksAndImages SYSTEM "../modules/common_pages.xml"> - <!ENTITY loadMacros SYSTEM "../modules/macros.xml"> - <!ENTITY raquo "»"> - <!ENTITY rsaquo "›" > -]> - -<project name="Smoke test level0 - deploy test" basedir="." default="webtest"> - &time; - <target name="webtest"> - <webtest name="piwik.js"> - <steps> - <echo>Piwik JavaScript Test</echo> - - &loadMacros; - - <macrodef name="qunit" description="run qunit tests"> - <attribute name="expectedFail" default="0" /> - <sequential> - <groovy> - step.context.webClient.cache.clear() - </groovy> - - <invoke description="get unit test" url="/tests/javascript/" /> - <verifyTitle description="check the title is parsed correctly" text="piwik.js: Unit Tests" /> - - <retry description="wait for test to complete" maxcount="30"> - <sleep description="pause" seconds="1" /> - <verifyXPath description="check for result" xpath="//span[@class='failed']" /> - </retry> - - <verifyXPath description="check for not failed" xpath="//span[@class='failed']" text="@{expectedFail}" /> - <not description="check for at least 1 pass"> - <verifyXPath description="check for success" xpath="//span[@class='passed']" text="0" /> - </not> - </sequential> - </macrodef> - - <macrodef name="genstub" description="generate stub.tpl"> - <attribute name="path" /> - <sequential> - <echo file="../javascript/stub.tpl"> -<script src="frameworks/@{path}" type="text/javascript"></script> - </echo> - </sequential> - </macrodef> - - <macrodef name="genstub2" description="generate stub.tpl"> - <attribute name="path" /> - <attribute name="path2" /> - <sequential> - <echo file="../javascript/stub.tpl"> -<script src="frameworks/@{path}" type="text/javascript"></script> -<script src="frameworks/@{path2}" type="text/javascript"></script> - </echo> - </sequential> - </macrodef> - - <macrodef name="googlestub" description="generate stub.tpl"> - <attribute name="lib" /> - <attribute name="version" default="1" /> - <sequential> - <ifStep description="is google api key defined?"> - <condition> - <not> - <verifyProperty name="${google.apikey}" value="" propertyType="ant" /> - </not> - </condition> - <then> - <echo file="../javascript/stub.tpl"> -<script src="https://www.google.com/jsapi?key=${google.apikey}" type="text/javascript"></script> -<script type="text/javascript"> - google.load("@{lib}", "@{version}"); -</script> - </echo> - </then> - <else> - <echo>Google API key not defined; unable to load @{lib}, version @{version}</echo> - <delete file="../javascript/stub.tpl" quiet="true" /> - </else> - </ifStep> - - </sequential> - </macrodef> - - <!-- - tracking tests are disabled in WebTest - - 1) when loading the iframe (click handler), it changes - the "current" response to the iframe - - @see http://webtest-community.canoo.com/jira/browse/WT-428 - - 2) GET requests for the web bug/beacon/pixel are ignored - --> - <!-- touch file="../javascript/enable_sqlite" / --> - - <delete file="../javascript/stub.tpl" quiet="true" /> - <qunit description="piwik.js standalone" /> - - <genstub path="dojo/dojo-1.0.3.js" /> - <qunit description="piwik.js + dojo 1.0.3" /> - - <genstub path="dojo/dojo-1.1.2.js" /> - <qunit description="piwik.js + dojo 1.1.2" /> - - <genstub path="dojo/dojo-1.2.4.js" /> - <qunit description="piwik.js + dojo 1.2.4" /> - - <genstub path="dojo/dojo-1.3.3.js" /> - <qunit description="piwik.js + dojo 1.3.3" /> - - <genstub path="dojo/dojo-1.4.3.js" /> - <qunit description="piwik.js + dojo 1.4.3" /> - - <genstub path="dojo/dojo-1.5.0.js" /> - <qunit description="piwik.js + dojo 1.5.0" /> - - <genstub path="dojo/dojo-1.6.0.js" /> - <qunit description="piwik.js + dojo 1.6.0" /> - - <googlestub lib="dojo" version="1" /> - <qunit description="piwik.js + dojo 1.x" /> - - <!-- - <genstub2 path="ext/ext-base-2.3.0.js" path2="ext/extjs-2.3.0.js" /> - <qunit description="piwik.js + extjs 2.3.0" /> - - <genstub2 path="ext/ext-base-3.3.1.js" path2="ext/extjs-3.3.1.js" /> - <qunit description="piwik.js + extjs 3.3.1" /> - --> - - <!-- - <genstub path="ext/ext-core-3.0.0.js" /> - <qunit description="piwik.js + ext-core 3.0.0" /> - - <genstub path="ext/ext-core-3.1.0.js" /> - <qunit description="piwik.js + ext-core 3.1.0" /> - - <googlestub lib="ext-core" version="3" /> - <qunit description="piwik.js + ext-core 3.x" /> - --> - - <genstub2 path="jquery/jquery-1.0.4.js" path2="jquery/jquery.json-2.2.js" /> - <qunit description="piwik.js + jquery 1.0.4" /> - - <genstub2 path="jquery/jquery-1.1.4.js" path2="jquery/jquery.json-2.2.js" /> - <qunit description="piwik.js + jquery 1.1.4" /> - - <genstub2 path="jquery/jquery-1.2.6.js" path2="jquery/jquery.json-2.2.js" /> - <qunit description="piwik.js + jquery 1.2.6" /> - - <genstub2 path="jquery/jquery-1.3.2.js" path2="jquery/jquery.json-2.2.js" /> - <qunit description="piwik.js + jquery 1.3.2" /> - - <genstub2 path="jquery/jquery-1.4.4.js" path2="jquery/jquery.json-2.2.js" /> - <qunit description="piwik.js + jquery 1.4.4" /> - - <genstub2 path="jquery/jquery-1.5.1.js" path2="jquery/jquery.json-2.2.js" /> - <qunit description="piwik.js + jquery 1.5.1" /> - - <genstub path="mootools/mootools-1.1.2.js" /> - <qunit description="piwik.js + mootools 1.1.2" /> - - <genstub path="mootools/mootools-1.2.5.js" /> - <qunit description="piwik.js + mootools 1.2.5" /> - - <genstub path="mootools/mootools-1.3.1.js" /> - <qunit description="piwik.js + mootools 1.3.1" /> - - <googlestub lib="mootools" version="1.3" /> - <qunit description="piwik.js + mootools 1.3.x" /> - - <genstub path="prototype/prototype-1.5.0.js" /> - <qunit description="piwik.js + prototype 1.5.0" /> - - <genstub path="prototype/prototype-1.6.0.js" /> - <qunit description="piwik.js + prototype 1.6.0" /> - - <genstub path="prototype/prototype-1.7.0.js" /> - <qunit description="piwik.js + prototype 1.7.0" /> - - <googlestub lib="prototype" version="1" /> - <qunit description="piwik.js + prototype 1.x" /> - - <genstub path="yui/yui-3.3.0.js" /> - <qunit description="piwik.js + yui 3.x" /> - </steps> - </webtest> - </target> -</project> diff --git a/tests/webtest/testcases/level0/1.5-jslint.xml b/tests/webtest/testcases/level0/1.5-jslint.xml deleted file mode 100644 index 8e06c32393..0000000000 --- a/tests/webtest/testcases/level0/1.5-jslint.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!DOCTYPE project [ - <!ENTITY time SYSTEM "../modules/time.xml"> - <!ENTITY checkForErrors SYSTEM "../modules/errors.xml"> - <!ENTITY verifyLinksAndImages SYSTEM "../modules/common_pages.xml"> - <!ENTITY loadMacros SYSTEM "../modules/macros.xml"> - <!ENTITY raquo "»"> - <!ENTITY rsaquo "›" > -]> - -<project name="Smoke test level0 - deploy test" basedir="." default="webtest"> - &time; - <target name="webtest"> - <webtest name="jslint"> - <steps> - <echo>JSLint</echo> - - <invoke description="get form" url="http://jslint.com/" /> - <loadfile description="load javascript" srcFile="../../js/piwik.js" property="js" encoding="UTF-8" /> - <setInputField description="paste javascript" xpath="//fieldset[@id='JSLINT_SOURCE']/textarea" value="${js}" /> - <clickButton description="click button" label="JSLint" /> - <sleep description="pause" seconds="1" /> - <verifyXPath description="check for errors" xpath="//fieldset[@id='JSLINT_ERRORS' and @style='display: none;']" /> - </steps> - </webtest> - </target> -</project> diff --git a/tests/webtest/testcases/level1/1.4-preinstall.xml b/tests/webtest/testcases/level1/1.4-preinstall.xml deleted file mode 100644 index 0e1e2b48f2..0000000000 --- a/tests/webtest/testcases/level1/1.4-preinstall.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!DOCTYPE project [ - <!ENTITY time SYSTEM "../modules/time.xml"> - <!ENTITY checkForErrors SYSTEM "../modules/errors.xml"> - <!ENTITY verifyLinksAndImages SYSTEM "../modules/common_pages.xml"> - <!ENTITY loadMacros SYSTEM "../modules/macros.xml"> - <!ENTITY raquo "»"> - <!ENTITY rsaquo "›" > -]> - -<project name="Level 1 - pre-install 1.1.1" basedir="." default="webtest"> - &time; - <target name="webtest"> - <webtest name="pre-install"> - <config> - <option name="ThrowExceptionOnScriptError" value="false" /> - </config> - <steps> - <echo>Pre-install 1.1.1</echo> - - &loadMacros; - - <piwikPreInstall version="1.1.1" /> - </steps> - </webtest> - </target> -</project> diff --git a/tests/webtest/testcases/level1/1.5-install.xml b/tests/webtest/testcases/level1/1.5-install.xml deleted file mode 100644 index affa55960b..0000000000 --- a/tests/webtest/testcases/level1/1.5-install.xml +++ /dev/null @@ -1,227 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!DOCTYPE project [ - <!ENTITY time SYSTEM "../modules/time.xml"> - <!ENTITY checkForErrors SYSTEM "../modules/errors.xml"> - <!ENTITY verifyLinksAndImages SYSTEM "../modules/common_pages.xml"> - <!ENTITY loadMacros SYSTEM "../modules/macros.xml"> - <!ENTITY raquo "»"> - <!ENTITY rsaquo "›" > -]> - -<project name="Level 1 - install" basedir="." default="webtest"> - &time; - <target name="webtest"> - <webtest name="install index"> - <steps> - <echo>Installation</echo> - - &loadMacros; - - <echo>Piwik install - dbsetup: db.name: ${db.name}</echo> - <sql - driver="com.mysql.jdbc.Driver" - url="jdbc:mysql://${db.host}:${db.port}/" - userid="${db.username}" - password="${db.password}" - > - <classpath> - <pathelement location="${basedir}/../lib/java/mysql-connector-java-5.1.7.jar" /> - </classpath> - <transaction> - DROP DATABASE IF EXISTS ${db.name}; - </transaction> - <transaction> - CREATE DATABASE IF NOT EXISTS ${db.name}; - </transaction> - </sql> - - <invoke description="get index" url="/" /> - - <!-- 1. welcome --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Welcome!" /> - <verifyText description="check page text" text="This process is split up into 9 easy steps and will take around 5 minutes" /> - -<!-- - &checkForErrors; ---> - &verifyLinksAndImages; - - <retryClickLink description="wait for piwik.php tracking test" label="Next »" maxcount="10" seconds="1" /> - - <!-- 2. systemCheck --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="System Check" /> - <verifyText description="check page text" text="Optional" /> - - &checkForErrors; - &verifyLinksAndImages; - - <not description="check if system check passed"> - <verifyXPath description="looking for error image" xpath="//img[@src='plugins/Zeitgeist/images/error.png']" /> - </not> - - <verifyXPath description="looking for ok image" xpath="//img[@src='plugins/Zeitgeist/images/ok.png']" /> - - <clickLink description="click 'Next'" label="Next »" /> - - <!-- 3. databaseSetup --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Database Setup" /> - - &checkForErrors; - &verifyLinksAndImages; - - <setInputField description="set database host (and port)" name="host" value="${db.host}:${db.port}" /> - <setInputField description="set database username" name="username" value="${db.username}" /> - <setInputField description="set database password" name="password" value="${db.password}" /> - <setInputField description="set database name" name="dbname" value="${db.name}" /> - <setInputField description="set database port" name="tables_prefix" value="canoo_" /> - - <clickButton description="click 'Go!' button" label="Go!" /> - - <!-- 4. databaseCheck --> -<!-- - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Database Check" /> - - &checkForErrors; - &verifyLinksAndImages; - - <clickLink description="click 'Next'" label="Next »" /> ---> - - <!-- 5. tablesCreation --> - - <not description="check if no error"> - <verifyXPath description="looking for error image" xpath="//img[@src='plugins/Zeitgeist/images/error_medium.png']" /> - </not> - - <not description="check if no warning"> - <verifyXPath description="looking for warning image" xpath="//img[@src='plugins/Zeitgeist/images/warning_medium.png']" /> - </not> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Tables created with success!" /> - <verifyXPath description="looking for success image" xpath="//img[@src='plugins/Zeitgeist/images/success_medium.png']" /> - - &checkForErrors; - &verifyLinksAndImages; - - <clickLink description="click 'Next'" label="Next »" /> - - <!-- 6. generalSetup --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="General Setup" /> - - &checkForErrors; - &verifyLinksAndImages; - - <setInputField description="set Piwik login" name="login" value="piwik_login" /> - <setInputField description="set Piwik password" name="password" value="piwik_password" /> - <setInputField description="set repeated Piwik password" name="password_bis" value="piwik_password" /> - <setInputField description="set Piwik email" name="email" value="nobody@piwik.org" /> - - <clickButton description="click 'Go!' button" label="Go!" /> - - <!-- 7. firstWebsiteSetup --> - - <not description="check if no error"> - <verifyXPath description="looking for error image" xpath="//img[@src='plugins/Zeitgeist/images/error_medium.png']" /> - </not> - - <not description="check if no warning"> - <verifyXPath description="looking for warning image" xpath="//img[@src='plugins/Zeitgeist/images/warning_medium.png']" /> - </not> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Setup a Website" /> - - &checkForErrors; - &verifyLinksAndImages; - - <setInputField description="set Piwik site name" name="siteName" value="Dummy Site Name" /> - <setInputField description="set Piwik URL" name="url" value="${wt.config.protocol}://${wt.config.host}:${wt.config.port}${wt.config.basepath}" /> - <setSelectField description="set Piwik timezone" name="timezone" value="UTC" /> - - <clickButton description="click 'Go!' button" label="Go!" /> - - <!-- 8. displayJavascriptCode --> - - <not description="check if no error"> - <verifyXPath description="looking for error image" xpath="//img[@src='plugins/Zeitgeist/images/error_medium.png']" /> - </not> - - <not description="check if no warning"> - <verifyXPath description="looking for warning image" xpath="//img[@src='plugins/Zeitgeist/images/warning_medium.png']" /> - </not> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="JavaScript Tracking tag" /> - - &checkForErrors; - &verifyLinksAndImages; - - <clickLink description="click 'Next'" label="Next »" /> - - <!-- 9. finished --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Installation" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Congratulations" /> - - &checkForErrors; - &verifyLinksAndImages; - - <clickLink description="click 'Continue to Piwik'" label="Continue to Piwik »" /> - - <!-- logging in --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Lost your password?" /> - - &checkForErrors; - &verifyLinksAndImages; - - <setInputField description="set Piwik login" htmlId="form_login" value="piwik_login" /> - <setInputField description="set Piwik password" htmlId="form_password" value="piwik_password" /> - - <clickButton description="click 'Sign in' button" label="Sign in" /> - - <!-- logged in --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Web Analytics Reports" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Dashboard" /> - <verifyText description="check page text" text="Hello" /> - - <!-- change language --> - <retryClickLink description="click 'Deutsch'" href="index.php?module=LanguagesManager&action=saveLanguage&language=de" seconds="5" /> - - <verifyText description="check page text" text="Hallo" /> - - <retryClickLink description="click 'Français'" href="index.php?module=LanguagesManager&action=saveLanguage&language=fr" seconds="5" /> - - <verifyText description="check page text" text="Bonjour" /> - - <retryClickLink description="click 'English'" href="index.php?module=LanguagesManager&action=saveLanguage&language=en" seconds="5" /> - - <verifyText description="check page text" text="Hello" /> - </steps> - </webtest> - </target> -</project> diff --git a/tests/webtest/testcases/level1/1.6-update.xml b/tests/webtest/testcases/level1/1.6-update.xml deleted file mode 100644 index 37ee23453f..0000000000 --- a/tests/webtest/testcases/level1/1.6-update.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!DOCTYPE project [ - <!ENTITY time SYSTEM "../modules/time.xml"> - <!ENTITY checkForErrors SYSTEM "../modules/errors.xml"> - <!ENTITY verifyLinksAndImages SYSTEM "../modules/common_pages.xml"> - <!ENTITY loadMacros SYSTEM "../modules/macros.xml"> - <!ENTITY raquo "»"> - <!ENTITY rsaquo "›" > -]> - -<project name="Level 1 - auto update" basedir="." default="webtest"> - &time; - <target name="webtest"> - <webtest name="auto update"> - <steps> - <echo>Auto-Update</echo> - - &loadMacros; - - <piwikAutoUpdate /> - </steps> - </webtest> - </target> -</project> diff --git a/tests/webtest/testcases/modules/common_pages.xml b/tests/webtest/testcases/modules/common_pages.xml deleted file mode 100644 index bf888b61d8..0000000000 --- a/tests/webtest/testcases/modules/common_pages.xml +++ /dev/null @@ -1,8 +0,0 @@ - <enableJavaScript description="Disable JS verification for external resources" enable="false" /> - <ifStep description="production tests" test="${wt.config.verifyLinks}"> - <verifyLinks /> - </ifStep> - <ifStep description="production tests" test="${wt.config.verifyImages}"> - <verifyImages /> - </ifStep> - <enableJavaScript description="Turn back JS verification for further testing" enable="true" /> diff --git a/tests/webtest/testcases/modules/errors.xml b/tests/webtest/testcases/modules/errors.xml deleted file mode 100644 index 16ef77e1e2..0000000000 --- a/tests/webtest/testcases/modules/errors.xml +++ /dev/null @@ -1,6 +0,0 @@ -<not description="There should be no errors and no notices on output page"> - <verifyText description="Check errors" text="error:" /> - <verifyText description="Check errors" text="Fatal error" /> - <verifyText description="Check notices" text="Notice" /> - <verifyText description="Check warnings" text="Warning" /> -</not> diff --git a/tests/webtest/testcases/modules/macros.xml b/tests/webtest/testcases/modules/macros.xml deleted file mode 100644 index ceeef91101..0000000000 --- a/tests/webtest/testcases/modules/macros.xml +++ /dev/null @@ -1,205 +0,0 @@ -<macrodef name="generateResetToken" description="generate reset token"> - <attribute name="output" default="piwik_reset_token" /> - <sequential> - <exec executable="${php.executable}" dir="${basedir}" outputproperty="@{output}"> - <arg value="-r" /> - <arg value="@date_default_timezone_set('UTC'); $ini = parse_ini_file('${basedir}/../../config/config.ini.php', true); $passwd = md5('piwik_password'); echo hash('whirlpool', strftime('%Y%m%d%H', time()+24*60*60) . 'piwik_login' . 'nobody@piwik.org' . substr($passwd, 0, 16) . $ini['superuser']['salt'] . substr($passwd, -16));" /> - </exec> - </sequential> -</macrodef> - -<macrodef name="retryClickLink" description="clickLink with retry and timeout"> - <attribute name="maxcount" default="1" /> - <attribute name="seconds" default="1" /> - <attribute name="description" default="" /> - <attribute name="label" default="" /> - <attribute name="href" default="" /> - <sequential> - <retry description="@{description}" maxcount="@{maxcount}"> - <sleep description="pause" seconds="@{seconds}" /> - <clickLink description="click link" label="@{label}" href="@{href}" /> - </retry> - </sequential> -</macrodef> - -<macrodef name="piwikGetVersion" description="get Piwik version"> - <attribute name="propertyName" default="latestVersion" /> - <sequential> - <get src="http://api.piwik.org/1.0/getLatestVersion/" dest="latestVersion.txt" /> - <loadfile srcFile="latestVersion.txt" property="@{propertyName}"> - <filterchain> - <striplinebreaks /> - </filterchain> - </loadfile> - </sequential> -</macrodef> - -<macrodef name="piwikPreInstall" description="pre-install Piwik"> - <attribute name="version" default="1.0" /> - <sequential> - <!-- download Piwik and unzip --> - - <property environment="env" /> - - <get src="http://builds.piwik.org/piwik-@{version}.zip" dest="piwik-@{version}.zip" /> - - <unzip src="piwik-@{version}.zip" dest="${env.WORKSPACE}" /> - - <delete includeemptydirs="true"> - <fileset dir="${basedir}/../.." includes="config/**" /> - <fileset dir="${basedir}/../.." includes="core/**" /> - <fileset dir="${basedir}/../.." includes="js/**" /> - <fileset dir="${basedir}/../.." includes="lang/**" /> - <fileset dir="${basedir}/../.." includes="libs/**" /> - <fileset dir="${basedir}/../.." includes="misc/**" /> - <fileset dir="${basedir}/../.." includes="plugins/**" /> - <fileset dir="${basedir}/../.." includes="tmp/**" /> - <fileset dir="${basedir}/../.."> - <include name="*" /> - <exclude name="tests" /> - </fileset> - </delete> - - <move todir="${env.WORKSPACE}/build/"> - <fileset dir="${env.WORKSPACE}/piwik/" /> - </move> - - <replace file="${env.WORKSPACE}/build/config/global.ini.php"> - <replacefilter - token="latest_version_url = http://builds.piwik.org/latest.zip" - value="latest_version_url = http://${env.HTTP_HOST}/jenkins.private/jobs/Piwik/workspace/latest.zip" /> - <replacefilter - token="api_service_url = http://api.piwik.org" - value="api_service_url = http://${env.HTTP_HOST}/jenkins.private/jobs/Piwik/workspace" /> - </replace> - <length file="${env.WORKSPACE}/build/config/global.ini.php" property="configLEN" /> - <checksum file="${env.WORKSPACE}/build/config/global.ini.php" property="configMD5" /> - <replaceregexp - file="${env.WORKSPACE}/build/config/manifest.inc.php" - match='"(config/global.ini.php)".*' - replace='"\1" => array("${configLEN}", "${configMD5}"),' - byline="true" /> - </sequential> -</macrodef> - -<macrodef name="piwikAutoUpdate" description="auto-update Piwik"> - <sequential> - <!-- logging in --> - - <invoke description="get index" url="/" /> - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Lost your password?" /> - - &checkForErrors; - &verifyLinksAndImages; - - <setInputField description="set Piwik login" htmlId="form_login" value="piwik_login" /> - <setInputField description="set Piwik password" htmlId="form_password" value="piwik_password" /> - - <clickButton description="click 'Sign in' button" label="Sign in" /> - - <!-- logged in --> - - <ifStep description="check if this version changed the page title"> - <condition> - <not> - <verifyProperty name="latestVersion" value="1.6" propertyType="ant" /> - </not> - </condition> - <then> - <verifyTitle description="check the title is parsed correctly" text="Piwik › Web Analytics Reports" /> - </then> - <else> - <verifyTitle description="check the title is parsed correctly" text="Piwik › Web Analytics Reports - Dummy Site Name" /> - </else> - </ifStep> - - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Dashboard" /> - <verifyText description="check page text" text="Hello" /> - - <!-- update notice --> - - <verifyText description="check page text" text="New Update:" /> - <mouseOver description="expand header message" htmlId="header_message" /> - <verifyText description="check page text" text="Please update now!" /> - - <enableJavaScript enable="false" /> - <clickLink description="click 'Please update now'" href="action=newVersionAvailable" /> - - <!-- one click update --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Update" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Update Automatically" /> - <verifyText description="check page text" text="Download" /> - - <clickButton description="click 'Update Automatically' Button" label="Update Automatically" /> - - <!-- download, unzip --> - - <!-- invoke description="one click update" url="/index.php?module=CoreUpdater&action=oneClickUpdate" /--> - - <!-- javascript needed for form to auto-post --> - - <clickButton description="simulate auto-post form" label="Continue" /> - - <not description="check for errors"> - <verifyXPath description="looking for error image" xpath="//img[@src='plugins/Zeitgeist/images/error_medium.png']" /> - </not> - - <not description="check if zip archive passed"> - <verifyText description="check page text" text="Incompatible archive" /> - </not> - - <verifyText description="check page text" text="Piwik updated successfully!" /> - <clickButton description="click 'Continue to Piwik' button" label="Continue to Piwik" /> - - <!-- db update? --> - - <ifStep description="check if db update required"> - <condition> - <verifyText description="check page text" text="Database Upgrade Required" /> - </condition> - <then> - <clickButton description="click 'Upgrade Piwik' button" label="Upgrade Piwik" /> - - <!-- db update done --> - - <not description="check for errors"> - <verifyXPath description="looking for error image" xpath="//img[@src='plugins/Zeitgeist/images/error_medium.png']" /> - </not> - - <verifyText description="check page text" text="Piwik has been successfully updated!" /> - <clickButton description="click 'Continue to Piwik' button" label="Continue to Piwik" /> - </then> - </ifStep> - - <!-- logged out? --> - <ifStep description="check if re-login required"> - <condition> - <verifyTitle description="check the title is parsed correctly" text="Piwik › Sign in" /> - </condition> - <then> - <setInputField description="set Piwik login" htmlId="form_login" value="piwik_login" /> - <setInputField description="set Piwik password" htmlId="form_password" value="piwik_password" /> - - <!-- sign in --> - - <clickButton description="click 'Sign in' button" label="Sign in" /> - </then> - </ifStep> - - <!-- logged in --> - - <verifyTitle description="check the title is parsed correctly" text="Piwik › Web Analytics Reports - Dummy Site Name" /> - <verifyText description="check page text" text="Piwik" /> - <verifyText description="check page text" text="Dashboard" /> - <verifyText description="check page text" text="Hello" /> - - <not description="up to date"> - <verifyText description="check page text" text="New Update:" /> - </not> - </sequential> -</macrodef> diff --git a/tests/webtest/testcases/modules/time.xml b/tests/webtest/testcases/modules/time.xml deleted file mode 100644 index d910a565d2..0000000000 --- a/tests/webtest/testcases/modules/time.xml +++ /dev/null @@ -1,15 +0,0 @@ - <tstamp> - <format property="today.plus.one" pattern="yyyy-MM-dd" - offset="1" unit="day" /> - </tstamp> - <tstamp> - <format property="today.plus.three" pattern="yyyy-MM-dd" - offset="3" unit="day" /> - </tstamp> - <tstamp> - <format property="unique" pattern="yyMMddHHmmssS" /> - </tstamp> - <tstamp> - <format property="today.minus.two" pattern="yyyy-MM-dd" - offset="-2" unit="day" /> - </tstamp> |