From d89a08b8b27ef9a7293e9f8cf351bedbd838e2cb Mon Sep 17 00:00:00 2001 From: mattab <matthieu.aubry@gmail.com> Date: Sun, 12 May 2013 18:09:22 +1200 Subject: [PATCH] Fixes #3932 * you can now write browserCode==ff;referrerKeyword!= to select all visitors using firefox and that have a keyword set * or you can write referrerKeyword==;browserCode==ff to select all visitors using firefox and that did not have any keyword set Also fixes #3933 Refs #2135 * fixing last bugs with segment selector encoding (working on chrome + FF + opera) - I 'hope' it will work on iE... --- core/API/Proxy.php | 2 + core/API/Request.php | 12 ++++- core/Segment.php | 8 ++-- core/SegmentExpression.php | 44 ++++++++++++++++--- core/ViewDataTable.php | 24 ++++++++-- .../GenerateGraphData/ChartEvolution.php | 2 +- plugins/API/API.php | 2 +- .../DataTableRowAction/RowEvolution.php | 2 +- plugins/CoreHome/templates/broadcast.js | 5 ++- plugins/CoreHome/templates/datatable.js | 2 +- .../templates/datatable_rowactions.js | 1 + plugins/CoreHome/templates/menu.js | 4 +- plugins/CoreHome/templates/menu.tpl | 2 +- plugins/Live/Controller.php | 2 +- .../SegmentEditor/templates/Segmentation.js | 7 +-- plugins/UserCountryMap/Controller.php | 6 +-- plugins/VisitsSummary/Controller.php | 2 +- tests/PHPUnit/Core/SegmentExpressionTest.php | 13 +++--- tests/PHPUnit/Core/SegmentTest.php | 25 ++++++++++- themes/default/ajaxHelper.js | 13 +++++- 20 files changed, 132 insertions(+), 46 deletions(-) diff --git a/core/API/Proxy.php b/core/API/Proxy.php index 2a024afbf5..e7ed698f6e 100644 --- a/core/API/Proxy.php +++ b/core/API/Proxy.php @@ -161,6 +161,7 @@ class Piwik_API_Proxy // Temporarily sets the Request array to this API call context $saveGET = $_GET; + $saveQUERY_STRING = @$_SERVER['QUERY_STRING']; foreach ($parametersRequest as $param => $value) { $_GET[$param] = $value; } @@ -199,6 +200,7 @@ class Piwik_API_Proxy // Restore the request $_GET = $saveGET; + $_SERVER['QUERY_STRING'] = $saveQUERY_STRING; // log the API Call try { diff --git a/core/API/Request.php b/core/API/Request.php index 22d0436b3c..d9ec3f7cff 100644 --- a/core/API/Request.php +++ b/core/API/Request.php @@ -48,6 +48,12 @@ class Piwik_API_Request static public function getRequestArrayFromString($request) { $defaultRequest = $_GET + $_POST; + + $requestRaw = self::getRequestParametersGET(); + if(!empty($requestRaw['segment'])) { + $defaultRequest['segment'] = $requestRaw['segment']; + } + $requestArray = $defaultRequest; if (!is_null($request)) { @@ -63,9 +69,8 @@ class Piwik_API_Request $request = str_replace(array("\n", "\t"), '', $request); $requestParsed = Piwik_Common::getArrayFromQueryString($request); - -// parse_str($request, $requestArray); $requestArray = $requestParsed + $defaultRequest; + } foreach ($requestArray as &$element) { @@ -209,6 +214,9 @@ class Piwik_API_Request */ public static function getRequestParametersGET() { + if(empty($_SERVER['QUERY_STRING'])) { + return array(); + } $GET = Piwik_Common::getArrayFromQueryString($_SERVER['QUERY_STRING']); return $GET; } diff --git a/core/Segment.php b/core/Segment.php index a02581e829..af57fe59a9 100644 --- a/core/Segment.php +++ b/core/Segment.php @@ -37,9 +37,9 @@ class Piwik_Segment // First try with url decoded value. If that fails, try with raw value. // If that also fails, it will throw the exception try { - $this->initializeSegment($string, $idSites); - } catch(Exception $e) { $this->initializeSegment( urldecode($string), $idSites); + } catch(Exception $e) { + $this->initializeSegment($string, $idSites); } } @@ -50,7 +50,6 @@ class Piwik_Segment */ protected function initializeSegment($string, $idSites) { - $string = Piwik_Common::unsanitizeInputValue($string); // As a preventive measure, we restrict the filter size to a safe limit $string = substr($string, 0, self::SEGMENT_TRUNCATE_LIMIT); @@ -111,7 +110,8 @@ class Piwik_Segment // apply presentation filter if (isset($segment['sqlFilter']) && !empty($segment['sqlFilter']) - && $matchType != Piwik_SegmentExpression::MATCH_IS_NOT_NULL + && $matchType != Piwik_SegmentExpression::MATCH_IS_NOT_NULL_NOR_EMPTY + && $matchType != Piwik_SegmentExpression::MATCH_IS_NULL_OR_EMPTY ) { $value = call_user_func($segment['sqlFilter'], $value, $segment['sqlSegment'], $matchType, $name); diff --git a/core/SegmentExpression.php b/core/SegmentExpression.php index fe178abccf..43aa1294a1 100644 --- a/core/SegmentExpression.php +++ b/core/SegmentExpression.php @@ -27,8 +27,11 @@ class Piwik_SegmentExpression const MATCH_CONTAINS = '=@'; const MATCH_DOES_NOT_CONTAIN = '!@'; - // Note: undocumented for now, only used in API.getSuggestedValuesForSegment - const MATCH_IS_NOT_NULL = '::'; + // Note: you can't write this in the API, but access this feature + // via field!= <- IS NOT NULL + // or via field== <- IS NULL / empty + const MATCH_IS_NOT_NULL_NOR_EMPTY = '::NOT_NULL'; + const MATCH_IS_NULL_OR_EMPTY = '::NULL'; // Special case, since we look up Page URLs/Page titles in a sub SQL query const MATCH_ACTIONS_CONTAINS = 'IN'; @@ -72,9 +75,8 @@ class Piwik_SegmentExpression . self::MATCH_LESS_OR_EQUAL . '|' . self::MATCH_LESS . '|' . self::MATCH_CONTAINS . '|' - . self::MATCH_IS_NOT_NULL . '|' . self::MATCH_DOES_NOT_CONTAIN - . '){1}(.+)/'; + . '){1}(.*)/'; $match = preg_match($pattern, $operand, $matches); if ($match == 0) { throw new Exception('The segment \'' . $operand . '\' is not valid.'); @@ -83,6 +85,19 @@ class Piwik_SegmentExpression $leftMember = $matches[1]; $operation = $matches[2]; $valueRightMember = urldecode($matches[3]); + + // is null / is not null + if ($valueRightMember === '') { + if($operation == self::MATCH_NOT_EQUAL) { + $operation = self::MATCH_IS_NOT_NULL_NOR_EMPTY; + } elseif($operation == self::MATCH_EQUAL) { + $operation = self::MATCH_IS_NULL_OR_EMPTY; + } else { + throw new Exception('The segment \'' . $operand . '\' has no value specified. You can leave this value empty ' . + 'only when you use the operators: ' . self::MATCH_NOT_EQUAL . ' (is not) or ' . self::MATCH_EQUAL . ' (is)'); + } + } + $parsedSubExpressions[] = array( self::INDEX_BOOL_OPERATOR => $operator, self::INDEX_OPERAND => array( @@ -158,12 +173,14 @@ class Piwik_SegmentExpression $matchType = $def[1]; $value = $def[2]; + $alsoMatchNULLValues = false; switch ($matchType) { case self::MATCH_EQUAL: $sqlMatch = '='; break; case self::MATCH_NOT_EQUAL: $sqlMatch = '<>'; + $alsoMatchNULLValues = true; break; case self::MATCH_GREATER: $sqlMatch = '>'; @@ -184,13 +201,19 @@ class Piwik_SegmentExpression case self::MATCH_DOES_NOT_CONTAIN: $sqlMatch = 'NOT LIKE'; $value = '%' . $this->escapeLikeString($value) . '%'; + $alsoMatchNULLValues = true; break; - case self::MATCH_IS_NOT_NULL: + case self::MATCH_IS_NOT_NULL_NOR_EMPTY: $sqlMatch = 'IS NOT NULL AND ('.$field.' <> \'\' OR '.$field.' = 0)'; $value = null; break; + case self::MATCH_IS_NULL_OR_EMPTY: + $sqlMatch = 'IS NULL OR '.$field.' = \'\' '; + $value = null; + break; + case self::MATCH_ACTIONS_CONTAINS: // this match type is not accessible from the outside // (it won't be matched in self::parseSubExpressions()) @@ -204,11 +227,18 @@ class Piwik_SegmentExpression break; } + // We match NULL values when rows are excluded only when we are not doing a + $alsoMatchNULLValues = $alsoMatchNULLValues && !empty($value); + if ($matchType === self::MATCH_ACTIONS_CONTAINS || is_null($value)) { - $sqlExpression = "$field $sqlMatch"; + $sqlExpression = "( $field $sqlMatch )"; } else { - $sqlExpression = "$field $sqlMatch ?"; + if($alsoMatchNULLValues) { + $sqlExpression = "( $field IS NULL OR $field $sqlMatch ? )"; + } else { + $sqlExpression = "$field $sqlMatch ?"; + } } $this->checkFieldIsAvailable($field, $availableTables); diff --git a/core/ViewDataTable.php b/core/ViewDataTable.php index 28dc4b23bf..89cc36ff3d 100644 --- a/core/ViewDataTable.php +++ b/core/ViewDataTable.php @@ -583,13 +583,26 @@ abstract class Piwik_ViewDataTable } } + $segment = $this->getRawSegmentFromRequest(); + if(!empty($segment)) { + $requestString .= '&segment=' . $segment; + } + return $requestString; + } + + /** + * @return array|bool + */ + static public function getRawSegmentFromRequest() + { // we need the URL encoded segment parameter, we fetch it from _SERVER['QUERY_STRING'] instead of default URL decoded _GET + $segmentRaw = false; $segment = Piwik_Common::getRequestVar('segment', '', 'string'); if (!empty($segment)) { - $requestRaw = Piwik_API_Request::getRequestParametersGET(); - $requestString .= '&segment=' . $requestRaw['segment']; + $request = Piwik_API_Request::getRequestParametersGET(); + $segmentRaw = $request['segment']; } - return $requestString; + return $segmentRaw; } /** @@ -768,6 +781,11 @@ abstract class Piwik_ViewDataTable unset($javascriptVariablesToSet[$name]); } } + + $rawSegment = $this->getRawSegmentFromRequest(); + $javascriptVariablesToSet['segment'] = $rawSegment; + + return $javascriptVariablesToSet; } diff --git a/core/ViewDataTable/GenerateGraphData/ChartEvolution.php b/core/ViewDataTable/GenerateGraphData/ChartEvolution.php index 65d7988216..cbcf93d7be 100644 --- a/core/ViewDataTable/GenerateGraphData/ChartEvolution.php +++ b/core/ViewDataTable/GenerateGraphData/ChartEvolution.php @@ -191,7 +191,7 @@ class Piwik_ViewDataTable_GenerateGraphData_ChartEvolution extends Piwik_ViewDat 'idSite' => $idSite, 'period' => $period->getLabel(), 'date' => $dateInUrl->toString(), - 'segment' => Piwik_Common::unsanitizeInputValue(Piwik_Common::getRequestVar('segment', false)) + 'segment' => Piwik_ViewDataTable::getRawSegmentFromRequest() ); $hash = ''; if (!empty($queryStringAsHash)) { diff --git a/plugins/API/API.php b/plugins/API/API.php index e9d3511f19..2402b515fd 100644 --- a/plugins/API/API.php +++ b/plugins/API/API.php @@ -1659,7 +1659,7 @@ class Piwik_API_API // Select non empty fields only // Note: this optimization has only a very minor impact - $requestLastVisits.= "&segment=$segmentName" . Piwik_SegmentExpression::MATCH_IS_NOT_NULL . "null"; + $requestLastVisits.= "&segment=$segmentName".urlencode('!='); // By default Live fetches all actions for all visitors, but we'd rather do this only when required if($this->doesSegmentNeedActionsData($segmentName)) { diff --git a/plugins/CoreHome/DataTableRowAction/RowEvolution.php b/plugins/CoreHome/DataTableRowAction/RowEvolution.php index 5df1ce3e16..ab42ea3452 100644 --- a/plugins/CoreHome/DataTableRowAction/RowEvolution.php +++ b/plugins/CoreHome/DataTableRowAction/RowEvolution.php @@ -91,7 +91,7 @@ class Piwik_CoreHome_DataTableRowAction_RowEvolution list($this->date, $lastN) = Piwik_ViewDataTable_GenerateGraphHTML_ChartEvolution::getDateRangeAndLastN($this->period, $end); } - $this->segment = Piwik_Common::getRequestVar('segment', '', 'string'); + $this->segment = Piwik_ViewDataTable::getRawSegmentFromRequest(); $this->loadEvolutionReport(); } diff --git a/plugins/CoreHome/templates/broadcast.js b/plugins/CoreHome/templates/broadcast.js index 31c3fb6c29..508777c174 100644 --- a/plugins/CoreHome/templates/broadcast.js +++ b/plugins/CoreHome/templates/broadcast.js @@ -462,7 +462,10 @@ var broadcast = { hashStr = url.substring(url.indexOf("#"), url.length); } else { - hashStr = (location.hash); + locationSplit = location.href.split('#'); + if(typeof locationSplit[1] != 'undefined') { + hashStr = '#' + locationSplit[1]; + } } return hashStr; diff --git a/plugins/CoreHome/templates/datatable.js b/plugins/CoreHome/templates/datatable.js index 1369b11786..a0a9b4afd4 100644 --- a/plugins/CoreHome/templates/datatable.js +++ b/plugins/CoreHome/templates/datatable.js @@ -1367,7 +1367,7 @@ dataTable.prototype = // doing AJAX request var menuItem = null; $("#root").find(">ul.nav a").each(function () { - if ($(this).attr('name') == url) { + if ($(this).attr('href') == url) { menuItem = this; return false } diff --git a/plugins/CoreHome/templates/datatable_rowactions.js b/plugins/CoreHome/templates/datatable_rowactions.js index afe31cc61b..238c4e7309 100644 --- a/plugins/CoreHome/templates/datatable_rowactions.js +++ b/plugins/CoreHome/templates/datatable_rowactions.js @@ -213,6 +213,7 @@ DataTable_RowAction.prototype.getLabelFromTr = function (tr) { if (!value) { value = label.text(); } + value = value.trim(); return encodeURIComponent(value); }; diff --git a/plugins/CoreHome/templates/menu.js b/plugins/CoreHome/templates/menu.js index 3be160b1ca..b2010152be 100644 --- a/plugins/CoreHome/templates/menu.js +++ b/plugins/CoreHome/templates/menu.js @@ -29,7 +29,7 @@ menu.prototype = onItemClick: function (item) { $('ul.nav').trigger('piwikSwitchPage', item); - broadcast.propagateAjax($(item).attr('name')); + broadcast.propagateAjax( $(item).attr('href').substr(1) ); return false; }, @@ -45,7 +45,7 @@ menu.prototype = // for all sub menu we want to have a unique id based on their module and action // for main menu we want to add just the module as its id. this.menuNode.find('li').each(function () { - var url = $(this).find('a').attr('name'); + var url = $(this).find('a').attr('href').substr(1); var module = broadcast.getValueFromUrl("module", url); var action = broadcast.getValueFromUrl("action", url); var moduleId = broadcast.getValueFromUrl("idGoal", url) || broadcast.getValueFromUrl("idDashboard", url); diff --git a/plugins/CoreHome/templates/menu.tpl b/plugins/CoreHome/templates/menu.tpl index e9e2fcd853..476483f745 100644 --- a/plugins/CoreHome/templates/menu.tpl +++ b/plugins/CoreHome/templates/menu.tpl @@ -6,7 +6,7 @@ <ul> {foreach from=$level2 key=name item=urlParameters name=level2} {if strpos($name, '_') !== 0} - <li><a name='{$urlParameters._url|@urlRewriteWithParameters}' href='#{$urlParameters._url|@urlRewriteWithParameters|substr:1}' + <li><a href='#{$urlParameters._url|@urlRewriteWithParameters|substr:1}' onclick='return piwikMenu.onItemClick(this);'>{$name|translate|escape:'html'}</a></li> {/if} {/foreach} diff --git a/plugins/Live/Controller.php b/plugins/Live/Controller.php index 40f2300678..ef703aa743 100644 --- a/plugins/Live/Controller.php +++ b/plugins/Live/Controller.php @@ -130,7 +130,7 @@ class Piwik_Live_Controller extends Piwik_Controller private function setCounters($view) { - $segment = Piwik_Common::getRequestVar('segment', false, 'string'); + $segment = Piwik_ViewDataTable::getRawSegmentFromRequest(); $last30min = Piwik_Live_API::getInstance()->getCounters($this->idSite, $lastMinutes = 30, $segment); $last30min = $last30min[0]; $today = Piwik_Live_API::getInstance()->getCounters($this->idSite, $lastMinutes = 24 * 60, $segment); diff --git a/plugins/SegmentEditor/templates/Segmentation.js b/plugins/SegmentEditor/templates/Segmentation.js index eb8379efe9..0b5ab93147 100644 --- a/plugins/SegmentEditor/templates/Segmentation.js +++ b/plugins/SegmentEditor/templates/Segmentation.js @@ -948,12 +948,7 @@ $(document).ready( function(){ var changeSegment = function(segmentDefinition){ $('#segmentEditorPanel a.close').click(); segmentDefinition = cleanupSegmentDefinition(segmentDefinition); - -// if($.browser.mozilla ) { - segmentDefinition = encodeURIComponent(segmentDefinition); -// } -// alert('new segment to reload='+segmentDefinition); - + segmentDefinition = encodeURIComponent(segmentDefinition); return broadcast.propagateNewPage('segment=' + segmentDefinition, true); }; diff --git a/plugins/UserCountryMap/Controller.php b/plugins/UserCountryMap/Controller.php index b0ca11de21..5195ec7421 100644 --- a/plugins/UserCountryMap/Controller.php +++ b/plugins/UserCountryMap/Controller.php @@ -73,7 +73,7 @@ class Piwik_UserCountryMap_Controller extends Piwik_Controller 'date' => $date, 'token_auth' => $token_auth, 'format' => 'json', - 'segment' => Piwik_Common::unsanitizeInputValue(Piwik_Common::getRequestVar('segment', '')), + 'segment' => Piwik_ViewDataTable::getRawSegmentFromRequest(), 'showRawMetrics' => 1, 'enable_filter_excludelowpop' => 1, 'filter_excludelowpop_value' => -1 @@ -144,7 +144,7 @@ class Piwik_UserCountryMap_Controller extends Piwik_Controller 'date' => self::REAL_TIME_WINDOW, 'token_auth' => $token_auth, 'format' => 'json', - 'segment' => Piwik_Common::unsanitizeInputValue(Piwik_Common::getRequestVar('segment', '')), + 'segment' => Piwik_ViewDataTable::getRawSegmentFromRequest(), 'showRawMetrics' => 1 )); @@ -192,7 +192,7 @@ class Piwik_UserCountryMap_Controller extends Piwik_Controller . "&period=" . $period . "&date=" . $date . "&token_auth=" . $token_auth - . "&segment=" . Piwik_Common::unsanitizeInputValue(Piwik_Common::getRequestVar('segment', '')) + . "&segment=" . Piwik_ViewDataTable::getRawSegmentFromRequest() . "&enable_filter_excludelowpop=1" . "&showRawMetrics=1"; diff --git a/plugins/VisitsSummary/Controller.php b/plugins/VisitsSummary/Controller.php index c93cf11679..fd62d14e38 100644 --- a/plugins/VisitsSummary/Controller.php +++ b/plugins/VisitsSummary/Controller.php @@ -129,7 +129,7 @@ class Piwik_VisitsSummary_Controller extends Piwik_Controller $dataTableVisit = self::getVisitsSummary(); $dataRow = $dataTableVisit->getRowsCount() == 0 ? new Piwik_DataTable_Row() : $dataTableVisit->getFirstRow(); - $dataTableActions = Piwik_Actions_API::getInstance()->get($idSite, Piwik_Common::getRequestVar('period'), Piwik_Common::getRequestVar('date'), Piwik_Common::getRequestVar('segment', false)); + $dataTableActions = Piwik_Actions_API::getInstance()->get($idSite, Piwik_Common::getRequestVar('period'), Piwik_Common::getRequestVar('date'), Piwik_ViewDataTable::getRawSegmentFromRequest()); $dataActionsRow = $dataTableActions->getRowsCount() == 0 ? new Piwik_DataTable_Row() : $dataTableActions->getFirstRow(); diff --git a/tests/PHPUnit/Core/SegmentExpressionTest.php b/tests/PHPUnit/Core/SegmentExpressionTest.php index ea53e5d049..afbfa23854 100644 --- a/tests/PHPUnit/Core/SegmentExpressionTest.php +++ b/tests/PHPUnit/Core/SegmentExpressionTest.php @@ -60,10 +60,10 @@ class SegmentExpressionTest extends PHPUnit_Framework_TestCase return array( array('A==B%', array('where' => " A = ? ", 'bind' => array('B%'))), array('ABCDEF====B===', array('where' => " ABCDEF = ? ", 'bind' => array('==B==='))), - array('A===B;CDEF!=C!=', array('where' => " A = ? AND CDEF <> ? ", 'bind' => array('=B', 'C!='))), + array('A===B;CDEF!=C!=', array('where' => " A = ? AND ( CDEF IS NULL OR CDEF <> ? ) ", 'bind' => array('=B', 'C!='))), array('A==B,C==D', array('where' => " (A = ? OR C = ? )", 'bind' => array('B', 'D'))), - array('A!=B;C==D', array('where' => " A <> ? AND C = ? ", 'bind' => array('B', 'D'))), - array('A!=B;C==D,E!=Hello World!=', array('where' => " A <> ? AND (C = ? OR E <> ? )", 'bind' => array('B', 'D', 'Hello World!='))), + array('A!=B;C==D', array('where' => " ( A IS NULL OR A <> ? ) AND C = ? ", 'bind' => array('B', 'D'))), + array('A!=B;C==D,E!=Hello World!=', array('where' => " ( A IS NULL OR A <> ? ) AND (C = ? OR ( E IS NULL OR E <> ? ) )", 'bind' => array('B', 'D', 'Hello World!='))), array('A>B', array('where' => " A > ? ", 'bind' => array('B'))), array('A<B', array('where' => " A < ? ", 'bind' => array('B'))), @@ -74,7 +74,7 @@ class SegmentExpressionTest extends PHPUnit_Framework_TestCase array('A>=B;C>=D,E<w_ow great!', array('where' => " A >= ? AND (C >= ? OR E < ? )", 'bind' => array('B', 'D', 'w_ow great!'))), array('A=@B_', array('where' => " A LIKE ? ", 'bind' => array('%B\_%'))), - array('A!@B%', array('where' => " A NOT LIKE ? ", 'bind' => array('%B\%%'))), + array('A!@B%', array('where' => " ( A IS NULL OR A NOT LIKE ? ) ", 'bind' => array('%B\%%'))), ); } @@ -107,8 +107,7 @@ class SegmentExpressionTest extends PHPUnit_Framework_TestCase array(',;,'), array(','), array(',,'), - array('==='), - array('!=') + array('!='), ); } @@ -126,6 +125,6 @@ class SegmentExpressionTest extends PHPUnit_Framework_TestCase } catch (Exception $e) { return; } - $this->fail('Expected exception not raised'); + $this->fail('Expected exception not raised for:' . var_export($segment->getSql(), true)); } } diff --git a/tests/PHPUnit/Core/SegmentTest.php b/tests/PHPUnit/Core/SegmentTest.php index 35da2a58a3..c007cc9d20 100644 --- a/tests/PHPUnit/Core/SegmentTest.php +++ b/tests/PHPUnit/Core/SegmentTest.php @@ -55,7 +55,7 @@ class SegmentTest extends PHPUnit_Framework_TestCase // AND, with 2 values rewrites array('countryCode==a;visitorType!=returning;visitorType==new', array( - 'where' => ' log_visit.location_country = ? AND log_visit.visitor_returning <> ? AND log_visit.visitor_returning = ? ', + 'where' => ' log_visit.location_country = ? AND ( log_visit.visitor_returning IS NULL OR log_visit.visitor_returning <> ? ) AND log_visit.visitor_returning = ? ', 'bind' => array('a', '1', '0'))), // OR, with 2 value rewrites @@ -63,6 +63,27 @@ class SegmentTest extends PHPUnit_Framework_TestCase 'where' => ' (log_visit.referer_type = ? OR log_visit.referer_type = ? )', 'bind' => array(Piwik_Common::REFERER_TYPE_SEARCH_ENGINE, Piwik_Common::REFERER_TYPE_DIRECT_ENTRY))), + + // IS NOT NULL + array('browserCode==ff;referrerKeyword!=', array( + 'where' => ' log_visit.config_browser_name = ? AND ( log_visit.referer_keyword IS NOT NULL AND (log_visit.referer_keyword <> \'\' OR log_visit.referer_keyword = 0) ) ', + 'bind' => array('ff') + )), + array('referrerKeyword!=,browserCode==ff', array( + 'where' => ' (( log_visit.referer_keyword IS NOT NULL AND (log_visit.referer_keyword <> \'\' OR log_visit.referer_keyword = 0) ) OR log_visit.config_browser_name = ? )', + 'bind' => array('ff') + )), + + // IS NULL + array('browserCode==ff;referrerKeyword==', array( + 'where' => ' log_visit.config_browser_name = ? AND ( log_visit.referer_keyword IS NULL OR log_visit.referer_keyword = \'\' ) ', + 'bind' => array('ff') + )), + array('referrerKeyword==,browserCode==ff', array( + 'where' => ' (( log_visit.referer_keyword IS NULL OR log_visit.referer_keyword = \'\' ) OR log_visit.config_browser_name = ? )', + 'bind' => array('ff') + )), + ); } @@ -259,7 +280,7 @@ class SegmentTest extends PHPUnit_Framework_TestCase WHERE ( log_conversion.idvisit = ? ) AND - ( log_conversion.idgoal <> ? AND log_link_visit_action.custom_var_k1 = ? AND log_conversion.idgoal = ? )", + ( ( log_conversion.idgoal IS NULL OR log_conversion.idgoal <> ? ) AND log_link_visit_action.custom_var_k1 = ? AND log_conversion.idgoal = ? )", "bind" => array(1, 2, 'Test', 1)); $this->assertEquals($this->_filterWhitsSpaces($expected), $this->_filterWhitsSpaces($query)); diff --git a/themes/default/ajaxHelper.js b/themes/default/ajaxHelper.js index f2e7e12a71..10b9459216 100644 --- a/themes/default/ajaxHelper.js +++ b/themes/default/ajaxHelper.js @@ -300,10 +300,19 @@ function ajaxHelper() { this._buildAjaxCall = function () { var that = this; + var parameters = this._mixinDefaultGetParams(this.getParams); + + var url = 'index.php?'; + // we took care of encoding &segment properly already, so we don't use $.param for it ($.param URL encodes the values) + if(parameters['segment']) { + url += 'segment=' + parameters['segment'] + '&'; + delete parameters['segment']; + } + url += $.param(parameters); var ajaxCall = { type: 'POST', async: this.async !== false, - url: 'index.php?' + $.param(this._mixinDefaultGetParams(this.getParams)), + url: url, dataType: this.format || 'json', error: this.errorCallback, success: function (response) { @@ -363,7 +372,7 @@ function ajaxHelper() { var defaultParams = { idSite: piwik.idSite || broadcast.getValueFromUrl('idSite'), period: piwik.period || broadcast.getValueFromUrl('period'), - segment: broadcast.getValueFromHash('segment', window.location.href) + segment: broadcast.getValueFromHash('segment', window.location.href.split('#')[1]) }; // never append token_auth to url -- GitLab