From 5164862249eaf7af69f0ca6470d4f5e42784725b Mon Sep 17 00:00:00 2001 From: mattab Date: Sat, 13 Feb 2016 11:02:21 +0100 Subject: Apply offset and limit correctly to the Visitor Log SQL queries --- core/DataAccess/LogQueryBuilder.php | 35 +++++---- core/Segment.php | 7 +- tests/PHPUnit/Integration/SegmentTest.php | 126 +++++++++++++++++++++++++++++- 3 files changed, 148 insertions(+), 20 deletions(-) diff --git a/core/DataAccess/LogQueryBuilder.php b/core/DataAccess/LogQueryBuilder.php index b0f2b73ad0..c65f36bf10 100644 --- a/core/DataAccess/LogQueryBuilder.php +++ b/core/DataAccess/LogQueryBuilder.php @@ -16,7 +16,7 @@ use Piwik\Segment\SegmentExpression; class LogQueryBuilder { public function getSelectQueryString(SegmentExpression $segmentExpression, $select, $from, $where, $bind, $groupBy, - $orderBy, $limit) + $orderBy, $limitAndOffset) { if (!is_array($from)) { $from = array($from); @@ -43,11 +43,11 @@ class LogQueryBuilder if ($useSpecialConversionGroupBy) { $innerGroupBy = "CONCAT(log_conversion.idvisit, '_' , log_conversion.idgoal, '_', log_conversion.buster)"; - $sql = $this->buildWrappedSelectQuery($select, $from, $where, $groupBy, $orderBy, $limit, $innerGroupBy); + $sql = $this->buildWrappedSelectQuery($select, $from, $where, $groupBy, $orderBy, $limitAndOffset, $innerGroupBy); } elseif ($joinWithSubSelect) { - $sql = $this->buildWrappedSelectQuery($select, $from, $where, $groupBy, $orderBy, $limit); + $sql = $this->buildWrappedSelectQuery($select, $from, $where, $groupBy, $orderBy, $limitAndOffset); } else { - $sql = $this->buildSelectQuery($select, $from, $where, $groupBy, $orderBy, $limit); + $sql = $this->buildSelectQuery($select, $from, $where, $groupBy, $orderBy, $limitAndOffset); } return array( 'sql' => $sql, @@ -249,12 +249,12 @@ class LogQueryBuilder * @param string $where * @param string $groupBy * @param string $orderBy - * @param string $limit + * @param string $limitAndOffset * @param null|string $innerGroupBy If given, this inner group by will be used. If not, we try to detect one * @throws Exception * @return string */ - private function buildWrappedSelectQuery($select, $from, $where, $groupBy, $orderBy, $limit, $innerGroupBy = null) + private function buildWrappedSelectQuery($select, $from, $where, $groupBy, $orderBy, $limitAndOffset, $innerGroupBy = null) { $matchTables = "(log_visit|log_conversion_item|log_conversion|log_action)"; preg_match_all("/". $matchTables ."\.[a-z0-9_\*]+/", $select, $matches); @@ -271,7 +271,7 @@ class LogQueryBuilder $innerFrom = $from; $innerWhere = $where; - $innerLimit = $limit; + $innerLimitAndOffset = $limitAndOffset; if (!isset($innerGroupBy) && in_array('log_visit', $matchesFrom[1])) { $innerGroupBy = "log_visit.idvisit"; @@ -280,16 +280,16 @@ class LogQueryBuilder } $innerOrderBy = "NULL"; - if ($innerLimit && $orderBy) { + if ($innerLimitAndOffset && $orderBy) { // only When LIMITing we can apply to the inner query the same ORDER BY as the parent query $innerOrderBy = $orderBy; } - if ($innerLimit) { + if ($innerLimitAndOffset) { // When LIMITing, no need to GROUP BY (GROUPing by is done before the LIMIT which is super slow when large amount of rows is matched) $innerGroupBy = false; } - $innerQuery = $this->buildSelectQuery($innerSelect, $innerFrom, $innerWhere, $innerGroupBy, $innerOrderBy, $innerLimit); + $innerQuery = $this->buildSelectQuery($innerSelect, $innerFrom, $innerWhere, $innerGroupBy, $innerOrderBy, $innerLimitAndOffset); $select = preg_replace('/'.$matchTables.'\./', 'log_inner.', $select); $from = " @@ -299,7 +299,9 @@ class LogQueryBuilder $where = false; $orderBy = preg_replace('/'.$matchTables.'\./', 'log_inner.', $orderBy); $groupBy = preg_replace('/'.$matchTables.'\./', 'log_inner.', $groupBy); - $query = $this->buildSelectQuery($select, $from, $where, $groupBy, $orderBy, $limit); + + $outerLimitAndOffset = null; + $query = $this->buildSelectQuery($select, $from, $where, $groupBy, $orderBy, $outerLimitAndOffset); return $query; } @@ -312,10 +314,10 @@ class LogQueryBuilder * @param string $where where clause * @param string $groupBy group by clause * @param string $orderBy order by clause - * @param string|int $limit limit by clause eg '5' for Limit 5 Offset 0 or '10, 5' for Limit 5 Offset 10 + * @param string|int $limitAndOffset limit by clause eg '5' for Limit 5 Offset 0 or '10, 5' for Limit 5 Offset 10 * @return string */ - private function buildSelectQuery($select, $from, $where, $groupBy, $orderBy, $limit) + private function buildSelectQuery($select, $from, $where, $groupBy, $orderBy, $limitAndOffset) { $sql = " SELECT @@ -341,11 +343,16 @@ class LogQueryBuilder $orderBy"; } - $sql = $this->appendLimitClauseToQuery($sql, $limit); + $sql = $this->appendLimitClauseToQuery($sql, $limitAndOffset); return $sql; } + /** + * @param $sql + * @param $limit LIMIT clause eg. "10, 50" (offset 10, limit 50) + * @return string + */ private function appendLimitClauseToQuery($sql, $limit) { $limitParts = explode(',', (string) $limit); diff --git a/core/Segment.php b/core/Segment.php index d9f8d163c6..0ba687740e 100644 --- a/core/Segment.php +++ b/core/Segment.php @@ -299,12 +299,13 @@ class Segment { $segmentExpression = $this->segmentExpression; - if ($offset > 0) { - $limit = (int) $offset . ', ' . (int) $limit; + $limitAndOffset = null; + if($limit > 0) { + $limitAndOffset = (int) $offset . ', ' . (int) $limit; } return $this->segmentQueryBuilder->getSelectQueryString($segmentExpression, $select, $from, $where, $bind, - $groupBy, $orderBy, $limit); + $groupBy, $orderBy, $limitAndOffset); } /** diff --git a/tests/PHPUnit/Integration/SegmentTest.php b/tests/PHPUnit/Integration/SegmentTest.php index 7041c89202..2cd93d9d87 100644 --- a/tests/PHPUnit/Integration/SegmentTest.php +++ b/tests/PHPUnit/Integration/SegmentTest.php @@ -829,9 +829,129 @@ class SegmentTest extends IntegrationTestCase AND ( log_link_visit_action.custom_var_k1 = ? ) ORDER BY NULL - LIMIT 33 - ) AS log_inner - LIMIT 33", + LIMIT 0, 33 + ) AS log_inner", + "bind" => array(1, 'Test')); + + $this->assertEquals($this->removeExtraWhiteSpaces($expected), $this->removeExtraWhiteSpaces($query)); + } + + + public function test_getSelectQuery_whenLimitAndOffset_outerQueryShouldNotHaveOffset() + { + $select = 'sum(log_visit.visit_total_time) as sum_visit_length'; + $from = 'log_visit'; + $where = 'log_visit.idvisit = ?'; + $bind = array(1); + + $segment = 'customVariablePageName1==Test'; + $segment = new Segment($segment, $idSites = array()); + + $orderBy = false; + $groupBy = false; + $limit = 33; + $offset = 10; + + $query = $segment->getSelectQuery($select, $from, $where, $bind, $orderBy, $groupBy, $limit, $offset); + + $expected = array( + "sql" => " + SELECT + sum(log_inner.visit_total_time) as sum_visit_length + FROM + ( + SELECT + log_visit.visit_total_time + FROM + " . Common::prefixTable('log_visit') . " AS log_visit + LEFT JOIN " . Common::prefixTable('log_link_visit_action') . " AS log_link_visit_action ON log_link_visit_action.idvisit = log_visit.idvisit + WHERE + ( log_visit.idvisit = ? ) + AND + ( log_link_visit_action.custom_var_k1 = ? ) + ORDER BY NULL + LIMIT 10, 33 + ) AS log_inner", + "bind" => array(1, 'Test')); + + $this->assertEquals($this->removeExtraWhiteSpaces($expected), $this->removeExtraWhiteSpaces($query)); + } + + public function test_getSelectQuery_whenOffsetIsZero() + { + $select = 'sum(log_visit.visit_total_time) as sum_visit_length'; + $from = 'log_visit'; + $where = 'log_visit.idvisit = ?'; + $bind = array(1); + + $segment = 'customVariablePageName1==Test'; + $segment = new Segment($segment, $idSites = array()); + + $orderBy = false; + $groupBy = false; + $limit = 33; + $offset = 0; + + $query = $segment->getSelectQuery($select, $from, $where, $bind, $orderBy, $groupBy, $limit, $offset); + + $expected = array( + "sql" => " + SELECT + sum(log_inner.visit_total_time) as sum_visit_length + FROM + ( + SELECT + log_visit.visit_total_time + FROM + " . Common::prefixTable('log_visit') . " AS log_visit + LEFT JOIN " . Common::prefixTable('log_link_visit_action') . " AS log_link_visit_action ON log_link_visit_action.idvisit = log_visit.idvisit + WHERE + ( log_visit.idvisit = ? ) + AND + ( log_link_visit_action.custom_var_k1 = ? ) + ORDER BY NULL + LIMIT 0, 33 + ) AS log_inner", + "bind" => array(1, 'Test')); + + $this->assertEquals($this->removeExtraWhiteSpaces($expected), $this->removeExtraWhiteSpaces($query)); + } + + public function test_getSelectQuery_whenLimitIsZero() + { + $select = 'sum(log_visit.visit_total_time) as sum_visit_length'; + $from = 'log_visit'; + $where = 'log_visit.idvisit = ?'; + $bind = array(1); + + $segment = 'customVariablePageName1==Test'; + $segment = new Segment($segment, $idSites = array()); + + $orderBy = false; + $groupBy = false; + $limit = 0; + $offset = 10; + + $query = $segment->getSelectQuery($select, $from, $where, $bind, $orderBy, $groupBy, $limit, $offset); + + $expected = array( + "sql" => " + SELECT + sum(log_inner.visit_total_time) as sum_visit_length + FROM + ( + SELECT + log_visit.visit_total_time + FROM + " . Common::prefixTable('log_visit') . " AS log_visit + LEFT JOIN " . Common::prefixTable('log_link_visit_action') . " AS log_link_visit_action ON log_link_visit_action.idvisit = log_visit.idvisit + WHERE + ( log_visit.idvisit = ? ) + AND + ( log_link_visit_action.custom_var_k1 = ? ) + GROUP BY log_visit.idvisit + ORDER BY NULL + ) AS log_inner", "bind" => array(1, 'Test')); $this->assertEquals($this->removeExtraWhiteSpaces($expected), $this->removeExtraWhiteSpaces($query)); -- cgit v1.2.3 From 055839d047c1d0b3ba36a5447e40ebee507a0b74 Mon Sep 17 00:00:00 2001 From: mattab Date: Sat, 13 Feb 2016 11:58:44 +0100 Subject: Apply offset and limit correctly to the Visitor Log SQL queries --- plugins/Live/tests/Integration/ModelTest.php | 9 ++++----- tests/PHPUnit/Integration/SegmentTest.php | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/plugins/Live/tests/Integration/ModelTest.php b/plugins/Live/tests/Integration/ModelTest.php index 355f1fb777..828d3865f0 100644 --- a/plugins/Live/tests/Integration/ModelTest.php +++ b/plugins/Live/tests/Integration/ModelTest.php @@ -53,7 +53,7 @@ class ModelTest extends IntegrationTestCase AND log_visit.visit_last_action_time >= ? AND log_visit.visit_last_action_time <= ? ORDER BY idsite, visit_last_action_time DESC - LIMIT 100 + LIMIT 0, 100 ) AS sub GROUP BY sub.idvisit ORDER BY sub.visit_last_action_time DESC @@ -93,7 +93,7 @@ class ModelTest extends IntegrationTestCase AND log_visit.visit_last_action_time >= ? AND log_visit.visit_last_action_time <= ? ORDER BY visit_last_action_time DESC - LIMIT 100 + LIMIT 0, 100 ) AS sub GROUP BY sub.idvisit ORDER BY sub.visit_last_action_time DESC @@ -154,7 +154,7 @@ class ModelTest extends IntegrationTestCase $period = 'month', $date = '2010-01-01', $segment = 'customVariablePageName1==Test', - $offset = 0, + $offset = 10, $limit = 100, $visitorId = 'abc', $minTimestamp = false, @@ -175,10 +175,9 @@ class ModelTest extends IntegrationTestCase AND log_visit.visit_last_action_time <= ? ) AND ( log_link_visit_action.custom_var_k1 = ? ) ORDER BY idsite, visit_last_action_time DESC - LIMIT 100 + LIMIT 10, 100 ) AS log_inner ORDER BY idsite, visit_last_action_time DESC - LIMIT 100 ) AS sub GROUP BY sub.idvisit ORDER BY sub.visit_last_action_time DESC diff --git a/tests/PHPUnit/Integration/SegmentTest.php b/tests/PHPUnit/Integration/SegmentTest.php index 2cd93d9d87..9f626e7969 100644 --- a/tests/PHPUnit/Integration/SegmentTest.php +++ b/tests/PHPUnit/Integration/SegmentTest.php @@ -1353,7 +1353,7 @@ class SegmentTest extends IntegrationTestCase $this->assertEquals($this->removeExtraWhiteSpaces($expected), $this->removeExtraWhiteSpaces($query)); } - // se https://github.com/piwik/piwik/issues/9194 + // see https://github.com/piwik/piwik/issues/9194 public function test_getSelectQuery_whenQueryingLogConversionWithSegmentThatUsesLogLinkVisitActionAndLogVisit_shouldUseSubselectGroupedByIdVisitAndBuster() { $select = 'log_conversion.idgoal AS `idgoal`, -- cgit v1.2.3 From 002bb10d6c1e949ddb7ff8d9c7629f8f728e9edc Mon Sep 17 00:00:00 2001 From: Matthieu Aubry Date: Sat, 20 Feb 2016 23:31:05 +0100 Subject: We're hiring engineers! --- HIRING.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 HIRING.md diff --git a/HIRING.md b/HIRING.md new file mode 100644 index 0000000000..4eaefa80fd --- /dev/null +++ b/HIRING.md @@ -0,0 +1,18 @@ +# We are hiring engineers to build an awesome product and platform used by millions of people + +Are you ready for a new challenge? Or maybe you know someone who is looking for a change? We have some exciting problems to solve and are looking for senior developers to work with us and our community on our open source Piwik Analytics platform. Piwik is used by more than one million websites all over the world. It is deployed on more than 300.000 servers and some users track more than 1 billion actions per month. + +## What is it like to work on Piwik? + +We develop this software using modern PHP, MySQL, Redis, AngularJS and more. We provide several kind of APIs and a plugin architecture to allow developers to extend and change Piwik to their needs. However, we would not be Piwik if we stopped at this point! We want to turn Piwik into an even more awesome product and platform. +You can imagine there is a lot to do and many challenges to face! + +While one part is to always make Piwik scale better and to improve UI and UX, we also want to provide simple APIs to make the life of developers as pleasant as possible. We aim to solve things the right way and our thousands of unit, integration, system, JavaScript and screenshot tests help us to innovate and to not be afraid of change. We like clean code and constant improvements. + +The Piwik team lives in New Zealand, Europe (Poland, Germany) and in the U.S. We do the vast majority of our collaboration online. Our values include being open, transparent and sharing knowledge. For this we use tools like GitHub and Slack to communicate and Quake servers to take our minds off complex challenges. We are a small, flexible team, so when you come aboard, you will play an integral part in engineering and have a big impact on the product loved by so many people. You’ll help to create a welcoming environment for new contributors and set an example with your development practices and communications skills. + +## Apply now, or spread the word! + +If you have strong skills in PHP send us an email with your CV and tell us a little about yourself and your experience in engineering complex applications. + +[Apply for a job here http://piwik.org/jobs/](http://piwik.org/jobs/) and if you’re maybe not the right candidate, contribute to the project by sharing this blog post and by sending it to your friends! -- cgit v1.2.3 From 6f3faf8c9dea2772ab74891a4c3c7216e231b84c Mon Sep 17 00:00:00 2001 From: mattab Date: Thu, 3 Mar 2016 15:27:20 +0100 Subject: Adding failing test case which reproduces SQL error #9822 --- tests/PHPUnit/System/TransitionsTest.php | 12 ++++++++++++ ...withSegment__Transitions.getTransitionsForPageUrl_day.xml | 6 ++++++ 2 files changed, 18 insertions(+) create mode 100644 tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageUrl_day.xml diff --git a/tests/PHPUnit/System/TransitionsTest.php b/tests/PHPUnit/System/TransitionsTest.php index 3049d0f823..44d38dc9db 100644 --- a/tests/PHPUnit/System/TransitionsTest.php +++ b/tests/PHPUnit/System/TransitionsTest.php @@ -79,6 +79,18 @@ class TransitionsTest extends SystemTestCase 'limitBeforeGrouping' => 2 ) )); + + $return[] = array('Transitions.getTransitionsForPageUrl', array( // test w/ segment + 'idSite' => self::$fixture->idSite, + 'date' => self::$fixture->dateTime, + 'periods' => array('day'), + 'testSuffix' => '_withSegment', + 'segment' => 'visitConvertedGoalId!%3D2', + 'otherRequestParameters' => array( + 'pageUrl' => 'http://example.org/page/one.html', + 'limitBeforeGrouping' => 2 + ) + )); return $return; } diff --git a/tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageUrl_day.xml b/tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageUrl_day.xml new file mode 100644 index 0000000000..3f6cf26e87 --- /dev/null +++ b/tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageUrl_day.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file -- cgit v1.2.3 From 94f3a97f5688054f2e305d44ad51681152aeee7d Mon Sep 17 00:00:00 2001 From: mattab Date: Thu, 3 Mar 2016 16:32:12 +0100 Subject: Prefix DB field by the table alias, to prevent error when a segment joins another table that has some field names in common #9822 --- plugins/Transitions/API.php | 6 +- tests/PHPUnit/System/TransitionsTest.php | 9 ++ ..._Transitions.getTransitionsForPageTitle_day.xml | 117 +++++++++++++++++++++ ...t__Transitions.getTransitionsForPageUrl_day.xml | 112 +++++++++++++++++++- 4 files changed, 239 insertions(+), 5 deletions(-) create mode 100644 tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageTitle_day.xml diff --git a/plugins/Transitions/API.php b/plugins/Transitions/API.php index 1ab38f89ae..89823d89c9 100644 --- a/plugins/Transitions/API.php +++ b/plugins/Transitions/API.php @@ -222,7 +222,8 @@ class API extends \Piwik\Plugin\API if ($actionType != 'title') { // specific setup for page urls $types[Action::TYPE_PAGE_URL] = 'followingPages'; - $dimension = 'if ( idaction_url IS NULL, idaction_name, idaction_url )'; + $dimension = 'if ( %s.idaction_url IS NULL, %s.idaction_name, %s.idaction_url )'; + $dimension = str_replace('%s', 'log_link_visit_action', $dimension ); // site search referrers are logged with url=NULL // when we find one, we have to join on name $joinLogActionColumn = $dimension; @@ -405,7 +406,8 @@ class API extends \Piwik\Plugin\API if ($dimension == 'idaction_url_ref') { // site search referrers are logged with url_ref=NULL // when we find one, we have to join on name_ref - $dimension = 'if ( idaction_url_ref IS NULL, idaction_name_ref, idaction_url_ref )'; + $dimension = 'if ( %s.idaction_url_ref IS NULL, %s.idaction_name_ref, %s.idaction_url_ref )'; + $dimension = str_replace('%s', 'log_link_visit_action', $dimension ); $joinLogActionOn = $dimension; } else { $joinLogActionOn = $dimension; diff --git a/tests/PHPUnit/System/TransitionsTest.php b/tests/PHPUnit/System/TransitionsTest.php index 44d38dc9db..b319558c90 100644 --- a/tests/PHPUnit/System/TransitionsTest.php +++ b/tests/PHPUnit/System/TransitionsTest.php @@ -91,6 +91,15 @@ class TransitionsTest extends SystemTestCase 'limitBeforeGrouping' => 2 ) )); + $return[] = array('Transitions.getTransitionsForPageTitle', array( + 'idSite' => self::$fixture->idSite, + 'date' => self::$fixture->dateTime, + 'periods' => array('day'), + 'testSuffix' => '_withSegment', + 'otherRequestParameters' => array( + 'pageTitle' => 'page title - page/one.html', + ) + )); return $return; } diff --git a/tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageTitle_day.xml b/tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageTitle_day.xml new file mode 100644 index 0000000000..26c278c975 --- /dev/null +++ b/tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageTitle_day.xml @@ -0,0 +1,117 @@ + + + Sat, Mar 6 + + + + 3 + + + + 2 + + + + 1 + + + + 1 + + + + + + 1 + + + + 1 + + + + 5 + 17 + 3 + 3 + + + + + 2 + + + + 2 + + + + 2 + + + + 1 + + + + 1 + + + + + + 1 + + + + + + 1 + + + + 1 + + + + + + 1 + + + + 1 + + + + + + direct + 1 +
+
+
+ + + search + 1 +
+ + + 1 + +
+
+ + + website + 1 +
+ + + 1 + +
+
+
+
\ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageUrl_day.xml b/tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageUrl_day.xml index 3f6cf26e87..865d25db4e 100644 --- a/tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageUrl_day.xml +++ b/tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageUrl_day.xml @@ -1,6 +1,112 @@ - + Sat, Mar 6 + + + + 3 + + + + 2 + + + + 2 + + + + + + 1 + + + + 2 + 18 + 4 + 7 + + + + + 3 + + + + 2 + + + + 3 + + + + + + 1 + + + + + + 1 + + + + 1 + + + + + + 1 + + + + 1 + + + + + + direct + 1 +
+
+
+ + + search + 1 +
+ + + 1 + +
+
+ + + website + 1 +
+ + + 1 + +
+
+ + + campaign + 1 +
+ + + 1 + +
+
+
\ No newline at end of file -- cgit v1.2.3 From 687e459a25f49ff92c7fbb5caa70e04681d1dd8c Mon Sep 17 00:00:00 2001 From: Thomas Steur Date: Thu, 10 Mar 2016 11:20:48 +1300 Subject: added example re how to specify multiple URLs via HTTP API fixes #9901 --- plugins/SitesManager/API.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/SitesManager/API.php b/plugins/SitesManager/API.php index 739af7d5e9..d6b969f9ad 100644 --- a/plugins/SitesManager/API.php +++ b/plugins/SitesManager/API.php @@ -491,6 +491,7 @@ class API extends \Piwik\Plugin\API * @param array|string $urls The URLs array must contain at least one URL called the 'main_url' ; * if several URLs are provided in the array, they will be recorded * as Alias URLs for this website. + * When calling API via HTTP specify multiple URLs via `&urls[]=http...&urls[]=http...`. * @param int $ecommerce Is Ecommerce Reporting enabled for this website? * @param null $siteSearch * @param string $searchKeywordParameters Comma separated list of search keyword parameter names @@ -767,7 +768,7 @@ class API extends \Piwik\Plugin\API * they won't be duplicated. The 'main_url' of the website won't be affected by this method. * * @param int $idSite - * @param array|string $urls + * @param array|string $urls When calling API via HTTP specify multiple URLs via `&urls[]=http...&urls[]=http...`. * @return int the number of inserted URLs */ public function addSiteAliasUrls($idSite, $urls) @@ -1077,6 +1078,7 @@ class API extends \Piwik\Plugin\API * @param int $idSite website ID defining the website to edit * @param string $siteName website name * @param string|array $urls the website URLs + * When calling API via HTTP specify multiple URLs via `&urls[]=http...&urls[]=http...`. * @param int $ecommerce Whether Ecommerce is enabled, 0 or 1 * @param null|int $siteSearch Whether site search is enabled, 0 or 1 * @param string $searchKeywordParameters Comma separated list of search keyword parameter names -- cgit v1.2.3 From 9d9e30b413633c2e55f1570fb9037154cd60688e Mon Sep 17 00:00:00 2001 From: mattab Date: Thu, 10 Mar 2016 16:02:17 +0100 Subject: Adding LoginHttpAuth submodule using ` git submodule add --force https://github.com/piwik/plugin-LoginHttpAuth.git plugins/LoginHttpAuth` refs #9908 --- plugins/LoginHttpAuth | 1 + 1 file changed, 1 insertion(+) create mode 160000 plugins/LoginHttpAuth diff --git a/plugins/LoginHttpAuth b/plugins/LoginHttpAuth new file mode 160000 index 0000000000..92978e17ac --- /dev/null +++ b/plugins/LoginHttpAuth @@ -0,0 +1 @@ +Subproject commit 92978e17acd032cfcdfc1f4be4c40947b54b91e7 -- cgit v1.2.3 From 379dbcea60a373fc955beac8e87ce9cba29f4ad9 Mon Sep 17 00:00:00 2001 From: mattab Date: Thu, 10 Mar 2016 16:59:43 +0100 Subject: Use sprintf instead of str_replace for consistency --- plugins/Transitions/API.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/Transitions/API.php b/plugins/Transitions/API.php index 89823d89c9..4304e2a281 100644 --- a/plugins/Transitions/API.php +++ b/plugins/Transitions/API.php @@ -222,8 +222,8 @@ class API extends \Piwik\Plugin\API if ($actionType != 'title') { // specific setup for page urls $types[Action::TYPE_PAGE_URL] = 'followingPages'; - $dimension = 'if ( %s.idaction_url IS NULL, %s.idaction_name, %s.idaction_url )'; - $dimension = str_replace('%s', 'log_link_visit_action', $dimension ); + $dimension = 'if ( %1$s.idaction_url IS NULL, %1$s.idaction_name, %1$s.idaction_url )'; + $dimension = sprintf($dimension, 'log_link_visit_action' ); // site search referrers are logged with url=NULL // when we find one, we have to join on name $joinLogActionColumn = $dimension; @@ -406,8 +406,8 @@ class API extends \Piwik\Plugin\API if ($dimension == 'idaction_url_ref') { // site search referrers are logged with url_ref=NULL // when we find one, we have to join on name_ref - $dimension = 'if ( %s.idaction_url_ref IS NULL, %s.idaction_name_ref, %s.idaction_url_ref )'; - $dimension = str_replace('%s', 'log_link_visit_action', $dimension ); + $dimension = 'if ( %1$s.idaction_url_ref IS NULL, %1$s.idaction_name_ref, %1$s.idaction_url_ref )'; + $dimension = sprintf($dimension, 'log_link_visit_action'); $joinLogActionOn = $dimension; } else { $joinLogActionOn = $dimension; -- cgit v1.2.3 From 071c86833c753d5352d25b41ceee535f8db1de84 Mon Sep 17 00:00:00 2001 From: mattab Date: Thu, 10 Mar 2016 17:20:20 +0100 Subject: UI tests: Added LoginHttpAuth as submodule https://github.com/piwik/piwik/issues/9908 --- tests/UI/expected-ui-screenshots | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/UI/expected-ui-screenshots b/tests/UI/expected-ui-screenshots index c8da554243..6e33543e76 160000 --- a/tests/UI/expected-ui-screenshots +++ b/tests/UI/expected-ui-screenshots @@ -1 +1 @@ -Subproject commit c8da5542432c1e1410f0330fcd612e93b1414a16 +Subproject commit 6e33543e76d17fc8d7f12769d267145552a8296e -- cgit v1.2.3 From 863ccf903704ed71182be4a0b2a3ddf745760cf6 Mon Sep 17 00:00:00 2001 From: Matthieu Aubry Date: Thu, 10 Mar 2016 17:58:50 +0100 Subject: 2.16.1-b2 --- core/Version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/Version.php b/core/Version.php index 9e9036a0ac..c85b9d829f 100644 --- a/core/Version.php +++ b/core/Version.php @@ -20,7 +20,7 @@ final class Version * The current Piwik version. * @var string */ - const VERSION = '2.16.1-b1'; + const VERSION = '2.16.1-b2'; public function isStableVersion($version) { -- cgit v1.2.3 From 03db4798885cf07a9de3400a41be0253fecb2a28 Mon Sep 17 00:00:00 2001 From: Thomas Steur Date: Fri, 11 Mar 2016 08:58:29 +1300 Subject: fix fatal error Call to protected method fixes #9912 --- plugins/UserCountry/Commands/AttributeHistoricalDataWithLocations.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/UserCountry/Commands/AttributeHistoricalDataWithLocations.php b/plugins/UserCountry/Commands/AttributeHistoricalDataWithLocations.php index 5e617f53e6..c5eaf833da 100644 --- a/plugins/UserCountry/Commands/AttributeHistoricalDataWithLocations.php +++ b/plugins/UserCountry/Commands/AttributeHistoricalDataWithLocations.php @@ -145,7 +145,7 @@ class AttributeHistoricalDataWithLocations extends ConsoleCommand * Print information about progress. * @param OutputInterface $output */ - protected function onVisitProcessed(OutputInterface $output) + public function onVisitProcessed(OutputInterface $output) { ++$this->processed; @@ -199,4 +199,4 @@ class AttributeHistoricalDataWithLocations extends ConsoleCommand return $geolocator; } -} \ No newline at end of file +} -- cgit v1.2.3 From 179f588a196575e0afbb99aa4f600cb689db7c57 Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 13 Mar 2016 14:01:36 +0200 Subject: Fix broken link Was pointing to [this instead](https://piwik.org/blog/2015/01/piwik-expanding-seeking-talented-software-engineer-new-zealand-poland/) (404) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aec6448c3d..11eefb1630 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Piwik is released under the GPL v3 (or later) license, see [misc/gpl-3.0.txt](mi Are you looking for a new challenge? We are currently seeking a software engineer or software developer who is passionate about data processing, security, privacy, the open source and free/libre philosophy and usable interface design. -[View Job Description](https://piwik.org/blog/2015/01/piwik-expanding-seeking-talented-software-engineer-new-zealand-poland/) - [Apply online](http://piwik.org/jobs/) +[View Job Description](https://piwik.org/blog/2016/01/piwik-expanding-seeking-talented-software-engineer-new-zealand-poland/) - [Apply online](http://piwik.org/jobs/) This is for a full time position to work on the open source Piwik platform, either remotely or we can help the right candidate relocate to beautiful New Zealand (Wellington) or Poland (Wroclaw). -- cgit v1.2.3 From 1cee0266607552cad3c6b243c05c775d8860cf80 Mon Sep 17 00:00:00 2001 From: sgiehl Date: Sun, 13 Mar 2016 20:08:21 +0100 Subject: Adds icons for some newly detected browsers --- plugins/DevicesDetection/images/browsers/AT.gif | Bin 0 -> 1087 bytes plugins/DevicesDetection/images/browsers/KY.gif | Bin 0 -> 614 bytes plugins/DevicesDetection/images/browsers/OT.gif | Bin 0 -> 1025 bytes plugins/DevicesDetection/images/browsers/SP.gif | Bin 0 -> 990 bytes plugins/DevicesDetection/images/browsers/SS.gif | Bin 0 -> 595 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 plugins/DevicesDetection/images/browsers/AT.gif create mode 100644 plugins/DevicesDetection/images/browsers/KY.gif create mode 100644 plugins/DevicesDetection/images/browsers/OT.gif create mode 100644 plugins/DevicesDetection/images/browsers/SP.gif create mode 100644 plugins/DevicesDetection/images/browsers/SS.gif diff --git a/plugins/DevicesDetection/images/browsers/AT.gif b/plugins/DevicesDetection/images/browsers/AT.gif new file mode 100644 index 0000000000..f1d9824afd Binary files /dev/null and b/plugins/DevicesDetection/images/browsers/AT.gif differ diff --git a/plugins/DevicesDetection/images/browsers/KY.gif b/plugins/DevicesDetection/images/browsers/KY.gif new file mode 100644 index 0000000000..9d14605aca Binary files /dev/null and b/plugins/DevicesDetection/images/browsers/KY.gif differ diff --git a/plugins/DevicesDetection/images/browsers/OT.gif b/plugins/DevicesDetection/images/browsers/OT.gif new file mode 100644 index 0000000000..068d88fa29 Binary files /dev/null and b/plugins/DevicesDetection/images/browsers/OT.gif differ diff --git a/plugins/DevicesDetection/images/browsers/SP.gif b/plugins/DevicesDetection/images/browsers/SP.gif new file mode 100644 index 0000000000..f404825e95 Binary files /dev/null and b/plugins/DevicesDetection/images/browsers/SP.gif differ diff --git a/plugins/DevicesDetection/images/browsers/SS.gif b/plugins/DevicesDetection/images/browsers/SS.gif new file mode 100644 index 0000000000..5ea7e91ba4 Binary files /dev/null and b/plugins/DevicesDetection/images/browsers/SS.gif differ -- cgit v1.2.3 From 2ed6ba170115bd1b159b834cc7ea6586f82dc144 Mon Sep 17 00:00:00 2001 From: mattab Date: Mon, 14 Mar 2016 14:39:44 +1300 Subject: Refs #9842 Add Unit test showcasing the issue --- tests/PHPUnit/Unit/UrlHelperTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/PHPUnit/Unit/UrlHelperTest.php b/tests/PHPUnit/Unit/UrlHelperTest.php index cc15d6eeb1..4a009d90d1 100644 --- a/tests/PHPUnit/Unit/UrlHelperTest.php +++ b/tests/PHPUnit/Unit/UrlHelperTest.php @@ -224,6 +224,15 @@ class UrlHelperTest extends \PHPUnit_Framework_TestCase $this->assertEquals('segment=pageTitle!@%40Hello%20World;pageTitle!@Peace%20Love%20', UrlHelper::getQueryFromUrl('/?segment=pageTitle!@%40Hello%20World;pageTitle!@Peace%20Love%20', array())); } + public function test_getQueryFromUrl_whenUrlParameterIsDuplicatedInQueryString_returnsLastFoundValue() + { + // Currently when the same parameter is used several times in the query string, + // only the last set value is returned by UrlHelper::getParameterFromQueryString + // refs https://github.com/piwik/piwik/issues/9842#issue-136043409 + $this->assertEquals('blue', UrlHelper::getParameterFromQueryString('selected_colors=red&selected_colors=blue&par3=1', 'selected_colors')); + $this->assertEquals('selected_colors=red&selected_colors=blue&par3=1', UrlHelper::getQueryFromUrl('http:/mydomain.com?selected_colors=red&selected_colors=blue&par3=1', array())); + } + /** * @group Core */ -- cgit v1.2.3 From 77ceacbcf3ec05491523c59151da27c7b88bb9bc Mon Sep 17 00:00:00 2001 From: Matthieu Aubry Date: Tue, 15 Mar 2016 11:24:25 +1300 Subject: Added tooltip to code coverage badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 11eefb1630..6ef7604077 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![Build Status](https://travis-ci.org/piwik/piwik.svg?branch=master)](https://travis-ci.org/piwik/piwik) [![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/piwik/piwik.svg)](https://scrutinizer-ci.com/g/piwik/piwik?branch=master) -[![Code Coverage](https://scrutinizer-ci.com/g/piwik/piwik/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/piwik/piwik/?branch=master) +[![Code Coverage](https://scrutinizer-ci.com/g/piwik/piwik/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/piwik/piwik/?branch=master "Unit tests code coverage. Does not include coverage of integration tests, system tests or UI screenshot tests.") [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/piwik/piwik.svg)](http://isitmaintained.com/project/piwik/piwik "Average time to resolve an issue") [![Percentage of issues still open](http://isitmaintained.com/badge/open/piwik/piwik.svg)](http://isitmaintained.com/project/piwik/piwik "Percentage of issues still open") [![Dependency Status](https://gemnasium.com/piwik/piwik.svg)](https://gemnasium.com/piwik/piwik) -- cgit v1.2.3 From 218e9ee7946295d0f54ac21e7890eb0406580f94 Mon Sep 17 00:00:00 2001 From: sgiehl Date: Fri, 11 Mar 2016 04:23:00 +0100 Subject: reduce z-index of siteselector within content... so it won't be displayed before popover background layer --- plugins/CoreHome/angularjs/siteselector/siteselector.directive.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CoreHome/angularjs/siteselector/siteselector.directive.less b/plugins/CoreHome/angularjs/siteselector/siteselector.directive.less index b6e4c3d676..78dd32a862 100644 --- a/plugins/CoreHome/angularjs/siteselector/siteselector.directive.less +++ b/plugins/CoreHome/angularjs/siteselector/siteselector.directive.less @@ -22,7 +22,7 @@ > .siteSelector { position: absolute; - z-index: 9999; + z-index: 999; } a.title { -- cgit v1.2.3 From 780feedd07d3cbd749108ed1f49fd23542b6cc0f Mon Sep 17 00:00:00 2001 From: sgiehl Date: Sat, 12 Mar 2016 23:38:26 +0100 Subject: metric tooltip should be above site selector --- plugins/CoreHome/stylesheets/dataTable/_reportDocumentation.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CoreHome/stylesheets/dataTable/_reportDocumentation.less b/plugins/CoreHome/stylesheets/dataTable/_reportDocumentation.less index 117fcf8716..6d071025f9 100644 --- a/plugins/CoreHome/stylesheets/dataTable/_reportDocumentation.less +++ b/plugins/CoreHome/stylesheets/dataTable/_reportDocumentation.less @@ -10,7 +10,7 @@ table.dataTable th .columnDocumentation { border: 1px solid #e4e5e4; padding: 5px 10px 6px 10px; border-radius: 4px; - z-index: 125; + z-index: 150; position: absolute; box-shadow: 0 0 4px #e4e5e4; cursor: default; -- cgit v1.2.3 From 34278b00c7fcb5b1fb19cdca783ce39efb6ac02d Mon Sep 17 00:00:00 2001 From: sgiehl Date: Sun, 13 Mar 2016 11:22:25 +0100 Subject: Adds UI test for metric tooltip --- tests/UI/specs/UIIntegration_spec.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/UI/specs/UIIntegration_spec.js b/tests/UI/specs/UIIntegration_spec.js index 9703f28814..fd91c3711d 100644 --- a/tests/UI/specs/UIIntegration_spec.js +++ b/tests/UI/specs/UIIntegration_spec.js @@ -244,6 +244,12 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik? }, done); }); + it('should display metric tooltip correctly', function (done) { + expect.screenshot("metric_tooltip").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { + page.mouseMove('[data-report="Referrers.getReferrerType"] #nb_visits .thDIV', 500); + }, done); + }); + it('should load the referrers > search engines & keywords page correctly', function (done) { expect.screenshot('referrers_search_engines_keywords').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { page.load("?" + urlBase + "#" + generalParams + "&module=Referrers&action=getSearchEnginesAndKeywords"); @@ -687,4 +693,4 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik? page.click('a.actionSegmentVisitorLog:visible'); }, done); }); -}); \ No newline at end of file +}); -- cgit v1.2.3 From 00a81e1d395c91c0a8f22b3ccfcd36b1c8665c6a Mon Sep 17 00:00:00 2001 From: mattab Date: Tue, 15 Mar 2016 13:14:06 +1300 Subject: New QueuedTracking release --- plugins/QueuedTracking | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/QueuedTracking b/plugins/QueuedTracking index 39b9498062..78f677f041 160000 --- a/plugins/QueuedTracking +++ b/plugins/QueuedTracking @@ -1 +1 @@ -Subproject commit 39b949806240c93beef5d0308988f608b6437886 +Subproject commit 78f677f041f637f7a6faf81a09b5aeb06e71e347 -- cgit v1.2.3 From 409fb2d22670105cfd2652a4987625fc6f19cece Mon Sep 17 00:00:00 2001 From: mattab Date: Tue, 15 Mar 2016 14:53:37 +1300 Subject: Use consistent token_auth naming, and remove "token" to minimise confusion with token_auth --- plugins/Login/lang/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Login/lang/en.json b/plugins/Login/lang/en.json index 185de64c25..89a06ab7e0 100644 --- a/plugins/Login/lang/en.json +++ b/plugins/Login/lang/en.json @@ -12,7 +12,7 @@ "LoginOrEmail": "Username or E-mail", "LoginPasswordNotCorrect": "Wrong Username and password combination.", "LostYourPassword": "Lost your password?", - "MailPasswordChangeBody": "Hi %1$s,\n\nA password reset request was received from %2$s. To confirm this password change so you can login with your new credentials, visit the following link:\n\n%3$s\n\nAttention: Changing the password will also change your token_auth. You can look up your new token_auth on your settings page.\n\nIf you are using your API token in any external applications or for archiving, make sure to update the token as requests to the API will fail otherwise.\n\nNote: this token will expire in 24 hours.\n\nAnd thank you for using Piwik!", + "MailPasswordChangeBody": "Hi %1$s,\n\nA password reset request was received from %2$s. To confirm this password change so you can login with your new credentials, visit the following link:\n\n%3$s\n\nAttention: Changing the password will also change your token_auth. You can look up your new token_auth on your settings page.\n\nIf you are using your API token_auth in any external applications or for archiving, make sure to update the token_auth as requests to the API will fail otherwise.\n\nNote: this link will expire in 24 hours.\n\nAnd thank you for using Piwik!", "MailTopicPasswordChange": "Confirm Password Change", "PasswordChanged": "Your password has been changed.", "PasswordRepeat": "Password (repeat)", -- cgit v1.2.3 From e9cf5bec7d0e29238ddf2dbf985ed65a106fa2e9 Mon Sep 17 00:00:00 2001 From: mattab Date: Tue, 15 Mar 2016 15:11:55 +1300 Subject: UI tests: Fixed z-index issues + new UI test for metric tooltip https://github.com/piwik/piwik/issues/9868 --- tests/UI/expected-ui-screenshots | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/UI/expected-ui-screenshots b/tests/UI/expected-ui-screenshots index 6e33543e76..3ad4542963 160000 --- a/tests/UI/expected-ui-screenshots +++ b/tests/UI/expected-ui-screenshots @@ -1 +1 @@ -Subproject commit 6e33543e76d17fc8d7f12769d267145552a8296e +Subproject commit 3ad45429636e8c7375e81ce69cddec04074e939d -- cgit v1.2.3 From 4c334be38b8426f54a7e6ab314a82ec25ce49c81 Mon Sep 17 00:00:00 2001 From: mattab Date: Tue, 15 Mar 2016 16:09:59 +1300 Subject: Generate .htaccess files even on non apache servers Fixes #9810 --- core/SettingsServer.php | 1 + plugins/Installation/ServerFilesGenerator.php | 14 ++++++-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/core/SettingsServer.php b/core/SettingsServer.php index d84e3ff483..06432a5dfb 100644 --- a/core/SettingsServer.php +++ b/core/SettingsServer.php @@ -76,6 +76,7 @@ class SettingsServer * * @return bool * @api + * @deprecated */ public static function isApache() { diff --git a/plugins/Installation/ServerFilesGenerator.php b/plugins/Installation/ServerFilesGenerator.php index fcd780523d..6009854544 100644 --- a/plugins/Installation/ServerFilesGenerator.php +++ b/plugins/Installation/ServerFilesGenerator.php @@ -15,12 +15,10 @@ class ServerFilesGenerator { /** * Generate Apache .htaccess files to restrict access + * .htaccess files are created on all webservers even Nginx, as sometimes Nginx knows how to handle .htaccess files */ public static function createHtAccessFiles() { - if (!SettingsServer::isApache()) { - return; - } $denyAll = self::getDenyAllHtaccessContent(); $allow = self::getAllowHtaccessContent(); @@ -76,17 +74,17 @@ class ServerFilesGenerator * * Apache-specific; for IIS @see web.config * + * .htaccess files are created on all webservers even Nginx, as sometimes Nginx knows how to handle .htaccess files + * * @param string $path without trailing slash * @param bool $overwrite whether to overwrite an existing file or not * @param string $content */ protected static function createHtAccess($path, $overwrite = true, $content) { - if (SettingsServer::isApache()) { - $file = $path . '/.htaccess'; - if ($overwrite || !file_exists($file)) { - @file_put_contents($file, $content); - } + $file = $path . '/.htaccess'; + if ($overwrite || !file_exists($file)) { + @file_put_contents($file, $content); } } -- cgit v1.2.3 From 5306046526f091ebc7c099704ce3938f47cd51a8 Mon Sep 17 00:00:00 2001 From: mattab Date: Tue, 15 Mar 2016 17:14:35 +1300 Subject: Use latest travis scripts --- plugins/CustomDimensions | 2 +- tests/travis | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/CustomDimensions b/plugins/CustomDimensions index aab8e5a724..c63fda6d26 160000 --- a/plugins/CustomDimensions +++ b/plugins/CustomDimensions @@ -1 +1 @@ -Subproject commit aab8e5a7246135a1d6b3ca00e665aea4adf8035b +Subproject commit c63fda6d26a5d767078d7961d329f449e4cecac0 diff --git a/tests/travis b/tests/travis index 3e80077f81..f6b1d610c0 160000 --- a/tests/travis +++ b/tests/travis @@ -1 +1 @@ -Subproject commit 3e80077f810f8ab963be85fb5be032138328201e +Subproject commit f6b1d610c0d137db79c4d4f0af4cea4cd675173c -- cgit v1.2.3 From cace70b364cdd8fc6154768e07740e2210f57f77 Mon Sep 17 00:00:00 2001 From: mattab Date: Tue, 15 Mar 2016 17:59:35 +1300 Subject: Plugin submodules update --- plugins/QueuedTracking | 2 +- plugins/SecurityInfo | 2 +- plugins/TasksTimetable | 2 +- plugins/TreemapVisualization | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/QueuedTracking b/plugins/QueuedTracking index 78f677f041..a7137646fa 160000 --- a/plugins/QueuedTracking +++ b/plugins/QueuedTracking @@ -1 +1 @@ -Subproject commit 78f677f041f637f7a6faf81a09b5aeb06e71e347 +Subproject commit a7137646fa4d738c6378686df6cd222fd291217f diff --git a/plugins/SecurityInfo b/plugins/SecurityInfo index 8647523ae5..85790278f1 160000 --- a/plugins/SecurityInfo +++ b/plugins/SecurityInfo @@ -1 +1 @@ -Subproject commit 8647523ae5de07f5dbfc9f50476c9bb661a51b33 +Subproject commit 85790278f1c34d2b12c9a4d846df81daee905bb4 diff --git a/plugins/TasksTimetable b/plugins/TasksTimetable index 53ab383e4d..8212ef0033 160000 --- a/plugins/TasksTimetable +++ b/plugins/TasksTimetable @@ -1 +1 @@ -Subproject commit 53ab383e4d19963441b2e8c8211fac3ac9426cb6 +Subproject commit 8212ef0033dd2b3731fccd39c498f61d6ca81470 diff --git a/plugins/TreemapVisualization b/plugins/TreemapVisualization index e487d14390..7b7e5ac94e 160000 --- a/plugins/TreemapVisualization +++ b/plugins/TreemapVisualization @@ -1 +1 @@ -Subproject commit e487d14390a4b99504a38ba6237705c10317b127 +Subproject commit 7b7e5ac94e4f3bdbd8f501b3c885fc5b28092802 -- cgit v1.2.3 From 25b2da923b2dbe999e4b716a37cfa4f804fa1770 Mon Sep 17 00:00:00 2001 From: mattab Date: Tue, 15 Mar 2016 18:57:15 +1300 Subject: CustomDimensions was updated --- plugins/CustomDimensions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CustomDimensions b/plugins/CustomDimensions index c63fda6d26..b950e3223f 160000 --- a/plugins/CustomDimensions +++ b/plugins/CustomDimensions @@ -1 +1 @@ -Subproject commit c63fda6d26a5d767078d7961d329f449e4cecac0 +Subproject commit b950e3223f9ffc37e7c950cfd785664ffdce2f9f -- cgit v1.2.3 From 40848302dcef96d240cb0a3b2f378aa1286ba146 Mon Sep 17 00:00:00 2001 From: mattab Date: Wed, 16 Mar 2016 22:44:23 +1300 Subject: Minor comment --- core/Tracker/Visit.php | 2 +- tests/travis | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/Tracker/Visit.php b/core/Tracker/Visit.php index 80d8d13613..f4485f52fb 100644 --- a/core/Tracker/Visit.php +++ b/core/Tracker/Visit.php @@ -365,7 +365,7 @@ class Visit implements VisitInterface return $this->userSettings; } - // is the referrer host any of the registered URLs for this website? + // is the host any of the registered URLs for this website? public static function isHostKnownAliasHost($urlHost, $idSite) { $websiteData = Cache::getCacheWebsiteAttributes($idSite); diff --git a/tests/travis b/tests/travis index f6b1d610c0..2551892dc2 160000 --- a/tests/travis +++ b/tests/travis @@ -1 +1 @@ -Subproject commit f6b1d610c0d137db79c4d4f0af4cea4cd675173c +Subproject commit 2551892dc296f1abc500acf7b04380689a64588b -- cgit v1.2.3 From e4e7d8000f96e9d7b593a9350c38376e29b27309 Mon Sep 17 00:00:00 2001 From: Joost van Rijn Date: Wed, 16 Mar 2016 21:31:34 +0100 Subject: Fix typo --- config/global.ini.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/global.ini.php b/config/global.ini.php index fd9ef2d649..431e9a21bc 100644 --- a/config/global.ini.php +++ b/config/global.ini.php @@ -345,7 +345,7 @@ login_password_recovery_email_address = "password-recovery@{DOMAIN}" ; name that appears as a Sender in the password recovery email login_password_recovery_email_name = Piwik -; email address that appears as a Repy-to in the password recovery email +; email address that appears as a Reply-to in the password recovery email ; if specified, {DOMAIN} will be replaced by the current Piwik domain login_password_recovery_replyto_email_address = "no-reply@{DOMAIN}" ; name that appears as a Reply-to in the password recovery email -- cgit v1.2.3 From 5ec18493cf6b262d33c4a93452b7624ca586f1ec Mon Sep 17 00:00:00 2001 From: mattab Date: Fri, 18 Mar 2016 01:04:15 +1300 Subject: Set returning visitor flag when user first visited the website at least 1 day ago --- plugins/CoreHome/Columns/VisitorReturning.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/CoreHome/Columns/VisitorReturning.php b/plugins/CoreHome/Columns/VisitorReturning.php index fc0ca345a7..5f3ba2584a 100644 --- a/plugins/CoreHome/Columns/VisitorReturning.php +++ b/plugins/CoreHome/Columns/VisitorReturning.php @@ -50,7 +50,7 @@ class VisitorReturning extends VisitDimension public function onNewVisit(Request $request, Visitor $visitor, $action) { $visitCount = $request->getVisitCount(); - $daysSinceLastVisit = $request->getDaysSinceLastVisit(); + $daysSinceFirstVisit = $request->getDaysSinceFirstVisit(); $daysSinceLastOrder = $request->getDaysSinceLastOrder(); $isReturningCustomer = ($daysSinceLastOrder !== false); @@ -59,7 +59,7 @@ class VisitorReturning extends VisitDimension return self::IS_RETURNING_CUSTOMER; } - if ($visitCount > 1 || $visitor->isVisitorKnown() || $daysSinceLastVisit > 0) { + if ($visitCount > 1 || $visitor->isVisitorKnown() || $daysSinceFirstVisit > 0) { return self::IS_RETURNING; } -- cgit v1.2.3 From 464be65c8e43f70c643cd589ac54da28d12780c2 Mon Sep 17 00:00:00 2001 From: sgiehl Date: Sun, 20 Mar 2016 12:57:41 +0100 Subject: handle PivotBy within HtmlTable visualization to fix side effects --- plugins/CoreVisualizations/CoreVisualizations.php | 20 +----------- .../Visualizations/HtmlTable.php | 19 ++++++++++++ .../Visualizations/HtmlTable/PivotBy.php | 36 ---------------------- 3 files changed, 20 insertions(+), 55 deletions(-) delete mode 100644 plugins/CoreVisualizations/Visualizations/HtmlTable/PivotBy.php diff --git a/plugins/CoreVisualizations/CoreVisualizations.php b/plugins/CoreVisualizations/CoreVisualizations.php index 9a5f88e7ec..0aec35fb3e 100644 --- a/plugins/CoreVisualizations/CoreVisualizations.php +++ b/plugins/CoreVisualizations/CoreVisualizations.php @@ -29,8 +29,7 @@ class CoreVisualizations extends \Piwik\Plugin 'AssetManager.getStylesheetFiles' => 'getStylesheetFiles', 'AssetManager.getJavaScriptFiles' => 'getJsFiles', 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys', - 'UsersManager.deleteUser' => 'deleteUser', - 'ViewDataTable.addViewDataTable' => 'addViewDataTable' + 'UsersManager.deleteUser' => 'deleteUser' ); } @@ -39,23 +38,6 @@ class CoreVisualizations extends \Piwik\Plugin ViewDataTableManager::clearUserViewDataTableParameters($userLogin); } - public function addViewDataTable(&$viewDataTable) - { - // Both are the same HtmlTable, just the Pivot one has some extra logic in case Pivot is used. - // We don't want to use the same HtmlTable twice in the UI. Therefore we always need to remove one. - if (Common::getRequestVar('pivotBy', '')) { - $tableToRemove = 'Visualizations\HtmlTable'; - } else { - $tableToRemove = 'HtmlTable\PivotBy'; - } - - foreach ($viewDataTable as $index => $table) { - if (Common::stringEndsWith($table, $tableToRemove)) { - unset($viewDataTable[$index]); - } - } - } - public function getStylesheetFiles(&$stylesheets) { $stylesheets[] = "plugins/CoreVisualizations/stylesheets/dataTableVisualizations.less"; diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable.php b/plugins/CoreVisualizations/Visualizations/HtmlTable.php index 66cb4c26e9..dff8aa3e7a 100644 --- a/plugins/CoreVisualizations/Visualizations/HtmlTable.php +++ b/plugins/CoreVisualizations/Visualizations/HtmlTable.php @@ -70,6 +70,25 @@ class HtmlTable extends Visualization $dataTable = $request->process(); $this->assignTemplateVar('siteSummary', $dataTable); } + + if ($this->isPivoted()) { + $this->config->columns_to_display = $this->dataTable->getColumns(); + } + } + + public function beforeGenericFiltersAreAppliedToLoadedDataTable() + { + if ($this->isPivoted()) { + $this->config->columns_to_display = $this->dataTable->getColumns(); + + $this->dataTable->applyQueuedFilters(); + } + + parent::beforeGenericFiltersAreAppliedToLoadedDataTable(); } + protected function isPivoted() + { + return $this->requestConfig->pivotBy || Common::getRequestVar('pivotBy', ''); + } } diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable/PivotBy.php b/plugins/CoreVisualizations/Visualizations/HtmlTable/PivotBy.php deleted file mode 100644 index 1703988599..0000000000 --- a/plugins/CoreVisualizations/Visualizations/HtmlTable/PivotBy.php +++ /dev/null @@ -1,36 +0,0 @@ -config->columns_to_display = $this->dataTable->getColumns(); - - $this->dataTable->applyQueuedFilters(); - - parent::beforeGenericFiltersAreAppliedToLoadedDataTable(); - } - - public function beforeRender() - { - parent::beforeRender(); - - $this->config->columns_to_display = $this->dataTable->getColumns(); - } -} -- cgit v1.2.3 From 8d665858021c853bd00fd14572a9b8ee83b89e45 Mon Sep 17 00:00:00 2001 From: sgiehl Date: Sun, 20 Mar 2016 19:08:40 +0100 Subject: displayed columns might not be correct when empty pivotBy is given --- plugins/Events/Events.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/Events/Events.php b/plugins/Events/Events.php index e178dc197b..84576c2832 100644 --- a/plugins/Events/Events.php +++ b/plugins/Events/Events.php @@ -143,7 +143,8 @@ class Events extends \Piwik\Plugin $secondaryDimension = $this->getSecondaryDimensionFromRequest(); $view->config->subtable_controller_action = API::getInstance()->getActionToLoadSubtables($apiMethod, $secondaryDimension); - if (Common::getRequestVar('pivotBy', false) === false) { + $pivotBy = Common::getRequestVar('pivotBy', false); + if (empty($pivotBy)) { $view->config->columns_to_display = array('label', 'nb_events', 'sum_event_value'); } -- cgit v1.2.3 From 5b10dcd6a7f40cb3f579f1ded6b931aefe64113c Mon Sep 17 00:00:00 2001 From: sgiehl Date: Mon, 21 Mar 2016 10:44:40 +0100 Subject: Always disable pivot for all columns table as it unsupported --- .../CoreVisualizations/Visualizations/HtmlTable/AllColumns.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php b/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php index 5acf9b50be..959aa0d57b 100644 --- a/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php +++ b/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php @@ -64,4 +64,14 @@ class AllColumns extends HtmlTable $properties->columns_to_display = $columnsToDisplay; }); } + + public function beforeLoadDataTable() + { + $this->requestConfig->request_parameters_to_modify['pivotBy'] = null; // always unset pivotBy + } + + protected function isPivoted() + { + return false; // Pivot not supported + } } -- cgit v1.2.3 From 7eb9b661dbe5436c234d5104e84e454e69ced73f Mon Sep 17 00:00:00 2001 From: sgiehl Date: Mon, 21 Mar 2016 14:36:16 +0100 Subject: fixes #9930 prevent linebreak in visitor log keyword position --- plugins/Live/stylesheets/live.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/Live/stylesheets/live.less b/plugins/Live/stylesheets/live.less index 7bbdde4044..bf71c90c2c 100644 --- a/plugins/Live/stylesheets/live.less +++ b/plugins/Live/stylesheets/live.less @@ -119,6 +119,10 @@ ol.visitorLog li { margin-right: 4px; } +.visitorReferrer .visitorRank { + display: inline-block; +} + .visitorRank { border: 1px solid #D8D8D8; color: #474747; -- cgit v1.2.3 From fb6a6bdadc05bbce85a0b197979cf657b83cf183 Mon Sep 17 00:00:00 2001 From: sgiehl Date: Tue, 22 Mar 2016 21:45:47 +0100 Subject: goals fitting exact page title don't need to start with http --- plugins/Goals/API.php | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/Goals/API.php b/plugins/Goals/API.php index 113bea5ec9..9b24a59c76 100644 --- a/plugins/Goals/API.php +++ b/plugins/Goals/API.php @@ -183,6 +183,7 @@ class API extends \Piwik\Plugin\API if ($patternType == 'exact' && substr($pattern, 0, 4) != 'http' && substr($matchAttribute, 0, 6) != 'event_' + && $matchAttribute != 'title' ) { throw new Exception(Piwik::translate('Goals_ExceptionInvalidMatchingString', array("http:// or https://", "http://www.yourwebsite.com/newsletter/subscribed.html"))); } -- cgit v1.2.3 From 6ead0d23d4e77048ce45aae5fcb2519c5544856b Mon Sep 17 00:00:00 2001 From: sgiehl Date: Tue, 22 Mar 2016 22:01:12 +0100 Subject: adds test --- plugins/Goals/tests/Integration/APITest.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/Goals/tests/Integration/APITest.php b/plugins/Goals/tests/Integration/APITest.php index 913bebf0a6..7dcb79eef5 100644 --- a/plugins/Goals/tests/Integration/APITest.php +++ b/plugins/Goals/tests/Integration/APITest.php @@ -62,6 +62,13 @@ class APITest extends IntegrationTestCase $this->assertGoal($idGoal, 'MyName', 'url', 'http://www.test.de', 'exact', 1, 50, 1); } + public function test_addGoal_ShouldSucceed_IfExactPageTitle() + { + $idGoal = $this->api->addGoal($this->idSite, 'MyName', 'title', 'normal title', 'exact', true, 50, true); + + $this->assertGoal($idGoal, 'MyName', 'title', 'normal title', 'exact', 1, 50, 1); + } + /** * @expectedException \Exception * @expectedExceptionMessage Goals_ExceptionInvalidMatchingString -- cgit v1.2.3 From 88ad8c95aaac3bf6ebc17c4ebc6db40b534c9267 Mon Sep 17 00:00:00 2001 From: sebastianpiskorski Date: Mon, 1 Feb 2016 21:18:04 +0100 Subject: Test for PR #9486, Validate allowed TLDs with current IANA list --- libs/Zend/Validate/Hostname.php | 140 +++++++++++++++++++++-- tests/PHPUnit/Integration/EmailValidatorTest.php | 57 +++++++++ 2 files changed, 185 insertions(+), 12 deletions(-) diff --git a/libs/Zend/Validate/Hostname.php b/libs/Zend/Validate/Hostname.php index cd5db5abcb..5dc6e818d7 100644 --- a/libs/Zend/Validate/Hostname.php +++ b/libs/Zend/Validate/Hostname.php @@ -201,16 +201,7 @@ class Zend_Validate_Hostname extends Zend_Validate_Abstract 'villas', 'vin', 'vip', 'virgin', 'vision', 'vista', 'vistaprint', 'viva', 'vlaanderen', 'vn', 'vodka', 'vote', 'voting', 'voto', 'voyage', 'vu', 'wales', 'walter', 'wang', 'wanggou', 'watch', 'watches', 'webcam', 'weber', 'website', 'wed', 'wedding', 'weir', 'wf', 'whoswho', 'wien', 'wiki', 'williamhill', 'win', 'windows', 'wine', - 'wme', 'work', 'works', 'world', 'ws', 'wtc', 'wtf', 'xbox', 'xerox', 'xin', 'कॉम', '佛山', '慈善', '集团', - '在线', '한국', '点看', 'คอม', 'ভারত', '八卦', 'موقع', '公益', '公司', '移动', '我爱你', 'москва', 'қаз', 'онлайн', - 'сайт', 'срб', 'бел', 'קום', '时尚', '淡马锡', 'орг', 'नेट', '삼성', 'சிங்கப்பூர்', '商标', '商店', '商城', 'дети', - 'мкд', 'ポイント', '新闻', '工行', 'كوم', '中文网', '中信', '中国', '中國', '娱乐', '谷歌', 'భారత్', 'ලංකා', 'ભારત', - 'भारत', '网店', 'संगठन', '餐厅', '网络', 'ком', 'укр', '香港', '诺基亚', '飞利浦', '台湾', '台灣', '手表', '手机', - 'мон', 'الجزائر', 'عمان', 'ارامكو', 'ایران', 'امارات', 'بازار', 'الاردن', 'موبايلي', 'بھارت', 'المغرب', - 'السعودية', 'سودان', 'همراه', 'عراق', 'مليسيا', '닷컴', '政府', 'شبكة', 'بيتك', 'გე', '机构', '组织机构', - '健康', 'ไทย', 'سورية', 'рус', 'рф', '珠宝', 'تونس', '大拿', 'みんな', 'グーグル', 'ελ', '世界', 'ਭਾਰਤ', '网址', - '닷넷', 'コム', '游戏', 'vermögensberater', 'vermögensberatung', '企业', '信息', 'مصر', 'قطر', '广东', 'இலங்கை', - 'இந்தியா', 'հայ', '新加坡', 'فلسطين', '政务', 'xperia', 'xxx', 'xyz', 'yachts', 'yamaxun', 'yandex', 'ye', + 'wme', 'work', 'works', 'world', 'ws', 'wtc', 'wtf', 'xbox', 'xerox', 'xin', 'xperia', 'xxx', 'xyz', 'yachts', 'yamaxun', 'yandex', 'ye', 'yodobashi', 'yoga', 'yokohama', 'youtube', 'yt', 'za', 'zara', 'zero', 'zip', 'zm', 'zone', 'zuerich', 'zw' ); @@ -371,9 +362,134 @@ class Zend_Validate_Hostname extends Zend_Validate_Abstract 'ایران' => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'), '中国' => 'Hostname/Cn.php', '公司' => 'Hostname/Cn.php', - '网络' => 'Hostname/Cn.php' + '网络' => 'Hostname/Cn.php', + 'कॉम' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'セール' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '佛山' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '慈善' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '集团' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '在线' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '한국' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '点看' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'คอม' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'ভারত' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '八卦' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'موقع' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '公益' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '公司' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '移动' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '我爱你' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'москва' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'қаз' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'онлайн' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'сайт' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '联通' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'срб' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'бел' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'קום' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '时尚' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '淡马锡' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'ファッション' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'орг' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'नेट' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'ストア' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '삼성' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'சிங்கப்பூர்' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '商标' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '商店' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '商城' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'дети' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'мкд' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'ею' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'ポイント' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '新闻' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '工行' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'كوم' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '中文网' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '中信' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '中国' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '中國' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '娱乐' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '谷歌' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'భారత్' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'ලංකා' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '购物' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'クラウド' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'ભારત' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'भारत' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '网店' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'संगठन' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '餐厅' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '网络' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'ком' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'укр' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '香港' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '诺基亚' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '食品' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '飞利浦' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '台湾' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '台灣' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '手表' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '手机' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'мон' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'الجزائر' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'عمان' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'ارامكو' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'ایران' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'امارات' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'بازار' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'الاردن' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'موبايلي' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'بھارت' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'المغرب' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'السعودية' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'سودان' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'همراه' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'عراق' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'مليسيا' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '澳門' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '닷컴' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '政府' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'شبكة' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'بيتك' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'გე' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '机构' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '组织机构' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '健康' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'ไทย' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'سورية' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'рус' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'рф' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '珠宝' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'تونس' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '大拿' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'みんな' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'グーグル' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'ελ' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '世界' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '書籍' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'ਭਾਰਤ' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '网址' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '닷넷' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'コム' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '游戏' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'VERMöGENSBERATER' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'VERMöGENSBERATUNG' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '企业' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '信息' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '嘉里大酒店' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'مصر' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'قطر' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '广东' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'இலங்கை' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'இந்தியா' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'հայ' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '新加坡' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + 'فلسطين' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), + '政务' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu') ); + protected $_idnLength = array( 'BIZ' => array(5 => 17, 11 => 15, 12 => 20), 'CN' => array(1 => 20), @@ -744,7 +860,7 @@ class Zend_Validate_Hostname extends Zend_Validate_Abstract // Check for URI Syntax (RFC3986) if ($this->_options['allow'] & self::ALLOW_URI) { - if (preg_match("/^([a-zA-Z0-9-._~!$&\'()*+,;=]|%[[:xdigit:]]{2}){1,254}$/i", $value)) { + if (preg_match("/^([a-zA-Z0-9-._~!$&'()*+,;=]|%[[:xdigit:]]{2}){1,254}$/i", $value)) { return true; } else { $this->_error(self::INVALID_URI); diff --git a/tests/PHPUnit/Integration/EmailValidatorTest.php b/tests/PHPUnit/Integration/EmailValidatorTest.php index 4b2e215506..262baab9e0 100644 --- a/tests/PHPUnit/Integration/EmailValidatorTest.php +++ b/tests/PHPUnit/Integration/EmailValidatorTest.php @@ -8,6 +8,7 @@ namespace Piwik\Tests\Integration; +use Piwik\Http; use Piwik\Piwik; /** @@ -20,6 +21,62 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase return Piwik::isValidEmailString($email); } + private function getAllTlds() + { + /** @var array $response */ + $response = \Piwik\Http::sendHttpRequest("http://data.iana.org/TLD/tlds-alpha-by-domain.txt", 30, null, null, null, null, null, true); + + $this->assertEquals("200", $response['status']); + + $tlds = explode("\n", $response['data']); + foreach ($tlds as $key => $tld) { + if (strpos($tld, '#') !== false || $tld == "") { + unset($tlds[$key]); + } + } + return $tlds; + } + + public function test_allCurrentTlds(){ + $tlds = $this->getAllTlds(); + if (count($tlds) === 0) { + $this->markTestSkipped("Couldn't get TLD list"); + } + + foreach ($tlds as $key => $tld) { + if (strpos(mb_strtolower($tld), 'xn--') !== 0) { + $tld = mb_strtolower($tld); + } + $this->assertTrue( + $this->isValid('test@example.' . idn_to_utf8($tld)) + ); + } + } + + public function test_invalidTld(){ + $tlds = [ + strval(bin2hex(openssl_random_pseudo_bytes(64))), //generates 128 bit length string + '-tld-cannot-start-from-hypen', + 'ąęśćżźł-there-is-no-such-idn', + 'xn--fd67as67fdsa', //no such idn punycode + '!@#-inavlid-chars-in-tld', + 'no spaces in tld allowed', + 'no--double--hypens--allowed' + ]; + if (count($tlds) === 0) { + $this->markTestSkipped("Couldn't get TLD list"); + } + + foreach ($tlds as $key => $tld) { + if (strpos(mb_strtolower($tld), 'xn--') !== 0) { + $tld = mb_strtolower($tld); + } + $this->assertFalse( + $this->isValid('test@example.' . idn_to_utf8($tld)) + ); + } + } + public function test_isValid_validStandard() { $this->assertTrue($this->isValid('test@example.com')); -- cgit v1.2.3 From d862f469085440eff5e5c89852fac80c6698ad3c Mon Sep 17 00:00:00 2001 From: sgiehl Date: Fri, 25 Mar 2016 23:31:16 +0100 Subject: language update --- lang/el.json | 6 +++--- lang/fi.json | 20 ++++++++++++++++++++ lang/ko.json | 4 ++++ lang/nb.json | 1 + lang/ru.json | 15 +++++++++++++++ lang/sq.json | 2 ++ lang/sv.json | 2 +- lang/tr.json | 2 +- plugins/API/lang/fi.json | 6 +++++- plugins/API/lang/ru.json | 5 ++++- plugins/Actions/lang/fi.json | 5 ++++- plugins/Actions/lang/ru.json | 4 +++- plugins/Contents/lang/ru.json | 6 +++++- plugins/CoreAdminHome/lang/ru.json | 12 +++++++++++- plugins/CoreHome/lang/fi.json | 11 ++++++++++- plugins/CoreHome/lang/ko.json | 1 + plugins/CoreUpdater/lang/fi.json | 10 +++++++++- plugins/CustomVariables/lang/fi.json | 6 +++++- plugins/DBStats/lang/fi.json | 1 + plugins/Dashboard/lang/fi.json | 2 ++ plugins/Dashboard/lang/lt.json | 2 ++ plugins/DevicePlugins/lang/fi.json | 2 ++ plugins/Diagnostics/lang/fi.json | 6 ++++++ plugins/Ecommerce/lang/fi.json | 8 ++++++++ plugins/Feedback/lang/fi.json | 8 +++++++- plugins/Goals/lang/el.json | 2 +- plugins/Goals/lang/lt.json | 2 +- plugins/Goals/lang/nb.json | 1 + plugins/ImageGraph/lang/fi.json | 3 ++- plugins/Installation/lang/fi.json | 14 ++++++++++++++ plugins/Live/lang/fi.json | 4 +++- plugins/Live/lang/nb.json | 1 + plugins/MobileAppMeasurable/lang/fi.json | 7 +++++++ plugins/PrivacyManager/lang/fi.json | 7 +++++++ plugins/PrivacyManager/lang/nb.json | 2 ++ plugins/Provider/lang/fi.json | 4 +++- plugins/Referrers/lang/fi.json | 2 ++ plugins/SEO/lang/fi.json | 1 + plugins/SegmentEditor/lang/fi.json | 9 ++++++++- plugins/SitesManager/lang/el.json | 2 +- plugins/Transitions/lang/fi.json | 1 + plugins/UserCountry/lang/fi.json | 1 + plugins/UserCountry/lang/nb.json | 1 + plugins/UserCountryMap/lang/fi.json | 5 ++++- plugins/UserLanguage/lang/fi.json | 3 ++- plugins/UsersManager/lang/fi.json | 12 ++++++++++++ plugins/VisitFrequency/lang/fi.json | 2 ++ plugins/VisitTime/lang/fi.json | 1 + plugins/VisitorInterest/lang/fi.json | 1 + plugins/VisitsSummary/lang/fi.json | 1 + plugins/WebsiteMeasurable/lang/fi.json | 7 +++++++ 51 files changed, 219 insertions(+), 24 deletions(-) create mode 100644 plugins/Diagnostics/lang/fi.json create mode 100644 plugins/Ecommerce/lang/fi.json create mode 100644 plugins/MobileAppMeasurable/lang/fi.json create mode 100644 plugins/WebsiteMeasurable/lang/fi.json diff --git a/lang/el.json b/lang/el.json index fcceae2a81..c141191e32 100644 --- a/lang/el.json +++ b/lang/el.json @@ -62,11 +62,11 @@ "ColumnNbActions": "Δραστηριότητες", "ColumnNbActionsDocumentation": "Ο αριθμός των δραστηριοτήτων που έγιναν από τους επισκέπτες σας. Οι δραστηριότητες μπορεί να είναι προβολές σελίδων, λήψεις ή εξωτερικοί σύνδεσμοι.", "ColumnNbUniqVisitors": "Μοναδικοί επισκέπτες", - "ColumnNbUniqVisitorsDocumentation": "Ο αριθμός των μη διπλών επισκεπτών που έρχονται στην ιστοσελίδα. Κάθε χρήστης καταγράφετε μόνο μια φορά, ακόμα και αν επισκέπτεται την ιστοσελίδα περισσότερες φορές τη μέρα.", + "ColumnNbUniqVisitorsDocumentation": "Ο αριθμός των μη διπλών επισκεπτών που έρχονται στην ιστοσελίδα. Κάθε χρήστης καταγράφεται μόνο μια φορά, ακόμα και αν επισκέπτεται την ιστοσελίδα περισσότερες φορές τη μέρα.", "ColumnNbUsers": "Χρήστες", "ColumnNbUsersDocumentation": "Ο αριθμός χρηστών που έχουν κάνει είσοδο στον ιστοτόπο σας. Είναι ο αριθμός των μοναδικών ενεργών χρηστών που έχουν καθορισμένο αναγνωριστικό χρήστη (μέσω της συνάρτησης παρακολούθησης 'setUserId').", "ColumnNbVisits": "Επισκέψεις", - "ColumnNbVisitsDocumentation": "Αν ένας επισκέπτης έρθει στην ιστοσελίδα για πρώτη φορά ή αν επισκέπτεται μια σελίδα για περισσότερο από 30 λεπτά μετά την τελευταία προβολή σελίδας, αυτό θα καταγράφετε ως νέα επίσκεψη.", + "ColumnNbVisitsDocumentation": "Αν ένας επισκέπτης έρθει στην ιστοσελίδα για πρώτη φορά ή αν επισκέπτεται μια σελίδα για περισσότερο από 30 λεπτά μετά την τελευταία προβολή σελίδας, αυτό θα καταγράφεται ως νέα επίσκεψη.", "ColumnPageBounceRateDocumentation": "Το ποσοστό των επισκέψεων που ξεκίνησαν σε αυτή τη σελίδα και άφησαν την ιστοσελίδα αμέσως.", "ColumnPageviews": "Προβολές σελίδων", "ColumnPageviewsDocumentation": "Οι επισκέψεις αυτής της σελίδας.", @@ -77,7 +77,7 @@ "ColumnUniqueEntrances": "Μοναδικές είσοδοι", "ColumnUniqueExits": "Μοναδικές έξοδοι", "ColumnUniquePageviews": "Μοναδικές προβολές σελίδων", - "ColumnUniquePageviewsDocumentation": "Ο αριθμός των επισκέψεων που περιελάμβαναν αυτή τη σελίδα. Αν μια σελίδα προβλήθηκε πολλές φορές σε μια επίσκεψη, καταγράφετε μόνο μια φορά..", + "ColumnUniquePageviewsDocumentation": "Ο αριθμός των επισκέψεων που περιελάμβαναν αυτή την σελίδα. Αν μια σελίδα προβλήθηκε πολλές φορές σε μια επίσκεψη, καταγράφεται μόνο μια φορά.", "ColumnValuePerVisit": "Τιμή ανά Επίσκεψη", "ColumnViewedAfterSearch": "Πατημένο στα αποτελέσματα αναζήτησης", "ColumnViewedAfterSearchDocumentation": "Ο αριθμός των επισκέψεων σε αυτή τη σελίδα, έπειτα από αναζήτηση ενός επισκέπτη στην ιστοσελίδα σας και αφού στη συνέχεια έκανε κλικ σε αυτή τη σελίδα από τα αποτελέσματα αναζήτησης.", diff --git a/lang/fi.json b/lang/fi.json index 715c3afc41..a864ac39be 100644 --- a/lang/fi.json +++ b/lang/fi.json @@ -1,5 +1,7 @@ { "General": { + "12HourClock": "12-tuntinen kello", + "24HourClock": "24-tuntinen kello", "AbandonedCarts": "Hylätyt ostoskorit", "AboutPiwikX": "Tietoja Piwikistä %s", "Action": "Toiminto", @@ -10,6 +12,7 @@ "AllWebsitesDashboard": "Kaikkien verkkosivujen työpöytä", "And": "ja", "API": "API", + "Apply": "Käytä", "ArchivingInlineHelp": "Keskikokoisilla ja vilkkailla sivulla on suositeltavaa kieltää arkistointi selaimesta. Parempi vaihtoehto on käyttää cron-työtä arkistointiin joka tunti.", "ArchivingTriggerDescription": "Suositeltavaa suuremmissa Piwik-asennuksissa. Sinun täytyy %1$sasentaa cron-työ%2$s, jotta raportit käsitellään oikein.", "AuthenticationMethodSmtp": "SMTP:n autentikointimenetelmä", @@ -23,6 +26,7 @@ "CannotUnzipFile": "Ei voi purkaa tiedostoa %1$s: %2$s", "ChangePassword": "Vaihda salasana", "ChangeTagCloudView": "Voit katsoa raporttia myös muissa muodoissa. Käytä nappuloita raportin alareunassa.", + "ChooseDate": "Valitse päivä, nyt valittu päivä: %s", "ChooseLanguage": "Valitse kieli", "ChoosePeriod": "Valitse aikaväli", "ClickHere": "Klikkaa tästä lisätietoja.", @@ -81,6 +85,8 @@ "ConfigFileIsNotWritable": "Piwikin asetustiedostoon %1$s ei voi kirjoittaa. Kaikkia muutoksia ei voi tallentaa. %2$s Muuta tiedoston oikeuksia niin, että kirjoittaminen on sallittua.", "Continue": "Jatka", "ContinueToPiwik": "Jatka Piwikiin", + "CurrentlyUsingUnsecureHttp": "Käytät Piwikiä epäturvallisen HTTP:n yli. Suosittelemme säätämään Piwikin käyttämään SSL:ää (HTTPS).", + "CreatedByUser": "luoja %s", "CurrentMonth": "Tämä kuukausi", "CurrentWeek": "Tämä viikko", "CurrentYear": "Tämä vuosi", @@ -94,6 +100,7 @@ "Date": "Päiväys", "DateRange": "Aikaväli:", "DateRangeFrom": "Alkaen", + "DateRangeInPeriodList": "päiväysalue", "DateRangeTo": "Mihin", "DaysHours": "%1$s päivää %2$s tuntia", "DaysSinceFirstVisit": "Päiviä ensimmäisestä käynnistä", @@ -221,6 +228,7 @@ "Name": "Nimi", "NbActions": "Toimintojen määrä", "NbSearches": "Sisäisten hakujen määrä", + "NeedMoreHelp": "Tarvitsetko lisää apua?", "Never": "Ei koskaan", "NewReportsWillBeProcessedByCron": "Kun Piwikin arkistointia ei käynnistetä selaimesta, uudet raportit luodaan cronilla.", "NewUpdatePiwikX": "Uusi päivitys: Piwik %s", @@ -233,6 +241,7 @@ "NotDefined": "%s ei ole määritetty.", "Note": "Huomio", "NotInstalled": "Ei asennettu", + "NotRecommended": "ei suositella", "NotValid": "%s on virheellinen", "NumberOfVisits": "Käyntien lukumäärä", "NUsers": "%s käyttäjää", @@ -256,6 +265,7 @@ "OperationNotEquals": "Ei täsmää", "OptionalSmtpPort": "Valinnainen. Oletus 25 salaamattomalle ja TLS:lle ja 465 SSL:lle.", "Options": "Asetukset", + "Or": "tai", "OrCancel": "tai %1$s peruuta %2$s", "Others": "Muut", "Outlink": "Lähtevä linkki", @@ -283,10 +293,13 @@ "Price": "Hinta", "ProductConversionRate": "Tuotteen konversiot", "ProductRevenue": "Tuotteiden tulot", + "Measurable": "Mitattava", + "Measurables": "Mitattavat", "PurchasedProducts": "Ostetut tuotteet", "Quantity": "Määrä", "RangeReports": "Oma aikaväli", "ReadThisToLearnMore": "%1$sLue täältä lisätietoa.%2$s", + "Recommended": "Suositeltu", "RecordsToPlot": "Piirrettävät tietueet", "Refresh": "Päivitä", "RefreshPage": "Päivitä sivu", @@ -297,6 +310,7 @@ "ReportGeneratedFrom": "Tämä raportti on luotu %s:n tiedoista.", "ReportRatioTooltip": "'%1$s' kuvaa %2$s :ta %3$s %4$s :ssa %5$s:n kanssa.", "Reports": "Raportit", + "ReportsContainingTodayWillBeProcessedAtMostEvery": "Arkistoi enintään joka X sekunti", "ReportsWillBeProcessedAtMostEveryHour": "Raportit päivitetään enintään kerran tunnissa.", "RequestTimedOut": "Pyyntö osoitteeseen %s aikakatkaistiin. Ole hyvä ja yritä uudelleen.", "Required": "%s vaaditaan", @@ -334,10 +348,14 @@ "TagCloud": "Avainsanapilvi", "Tax": "Verot", "TimeAgo": "%s sitten", + "TimeFormat": "Aikamuoto", "TimeOnPage": "Aika sivulla", "Total": "Yhteensä", "TotalRatioTooltip": "Tämä on %1$s kaikista %2$s %3$s.", "TotalRevenue": "Tulot yhteensä", + "TrackingScopeAction": "Toiminto", + "TrackingScopePage": "Sivu", + "TrackingScopeVisit": "Käynti", "TransitionsRowActionTooltip": "Näe mitä kävijät tekivät ennen ja jälkeen tällä sivulla käymistä", "TransitionsRowActionTooltipTitle": "Avaa muutokset", "TranslatorName": "Olli Jarva<\/a>", @@ -363,6 +381,7 @@ "Visitors": "Kävijät", "VisitsWith": "Käynnit %s:n kanssa", "VisitorSettings": "Kävijöiden asetukset", + "VisitType": "Käyntityyppi", "VisitTypeExample": "Voit esimerkiksi valita kaikki kävijät jotka palasivat sivulle ja ostivat edellisellä käynnillä. Esimerkki pyynnöstä on %s", "Warning": "Varoitus", "WarningPhpVersionXIsTooOld": "Käyttämäsi PHP versio %s on ohittanut EOL (End of Life) ajankohdan. Suosittelemme vakavasti ohjelmiston päivittämistä uudempaan versioon, sillä käyttämäsi versio voi altistaa sivuston tietoturva-aukoille ja virheille, jotka ovat korjattu PHP:n uudemmissa versioissa.", @@ -384,6 +403,7 @@ "YearsDays": "%1$s vuotta %2$s päivää", "Yes": "Kyllä", "YouAreCurrentlyUsing": "Käytät Piwik %s:ää", + "YouAreViewingDemoShortMessage": "Katsot Piwikin demoversiota", "YouMustBeLoggedIn": "Sinun täytyy kirjautua sisään ennen tämän toiminnallisuuden käyttämistä.", "YourChangesHaveBeenSaved": "Muutokset on tallennettu" }, diff --git a/lang/ko.json b/lang/ko.json index 615e8bf383..761a278d51 100644 --- a/lang/ko.json +++ b/lang/ko.json @@ -27,6 +27,7 @@ "CannotUnzipFile": "%1$s 파일의 압축을 풀 수 없습니다: %2$s", "ChangePassword": "비밀번호 변경", "ChangeTagCloudView": "태그 클라우드가 아닌 다른 방법으로 보고서를 볼 수 있습니다. 보고서의 아래쪽에있는 컨트롤을 사용하세요.", + "ChooseDate": "날짜를 선택하세요, 현재 선택된 날짜는 %s", "ChooseLanguage": "언어 선택", "ChoosePeriod": "기간 선택", "ClickHere": "자세한 내용은 이곳을 클릭하세요.", @@ -84,6 +85,7 @@ "Continue": "계속", "ContinueToPiwik": "Piwik 계속 하기", "CurrentlyUsingUnsecureHttp": "현재 위험할 수 있는 불안전한 HTTP를 통해 Piwik를 이용하고 있습니다. 우리는 SSL (HTTPS)를 설치하여 보안을 향상시킬 것을 추천합니다.", + "CreatedByUser": "%s가 만듬", "CurrentMonth": "이번달", "CurrentWeek": "이번주", "CurrentYear": "올해", @@ -242,6 +244,7 @@ "OperationDoesNotContain": "포함하지 않기", "OptionalSmtpPort": "옵션입니다. 비 암호화 및 TLS SMTP는 25가 SSL SMTP는 465이 기본입니다.", "Options": "설정", + "Or": "혹은", "OrCancel": "또는 %1$s 취소 %2$s", "Others": "기타", "Outlink": "외부링크", @@ -298,6 +301,7 @@ "Save": "저장", "SaveImageOnYourComputer": "이미지를 저장하려면 이미지를 오른쪽으로 클릭하여 \"다른 이름으로 그림 저장...\"을 선택합니다", "Search": "검색", + "SearchNoResults": "결과 없음", "SeeAll": "다 보기", "SeeTheOfficialDocumentationForMoreInformation": "자세한 내용은 %1$s 공식 문서 %2$s를 참조하세요.", "SelectYesIfYouWantToSendEmailsViaServer": "로컬 mail() 함수 대신 메일서버를 통해 이메일을 보낼 경우, \"예\"를 선택합니다", diff --git a/lang/nb.json b/lang/nb.json index c20d68cb56..c307c41792 100644 --- a/lang/nb.json +++ b/lang/nb.json @@ -231,6 +231,7 @@ "Name": "Navn", "NbActions": "Antall handlinger", "NbSearches": "Antall interne søk", + "NeedMoreHelp": "Trenger du mer hjelp?", "Never": "Aldri", "NewReportsWillBeProcessedByCron": "Hvis Piwik-arkivering ikke blir utløst av nettleseren, så vil nye rapporter bli prosessert ved hjelp av crontab.", "NewUpdatePiwikX": "Ny utgave: Piwik %s", diff --git a/lang/ru.json b/lang/ru.json index 79d4aed2c4..9ec7aa55b0 100644 --- a/lang/ru.json +++ b/lang/ru.json @@ -1,5 +1,7 @@ { "General": { + "12HourClock": "12-часовой формат времени", + "24HourClock": "24-часовой формат времени", "AbandonedCarts": "Нереализованные покупки", "AboutPiwikX": "О Piwik %s", "Action": "Действие", @@ -25,6 +27,7 @@ "CannotUnzipFile": "Не могу распаковать файл %1$s: %2$s", "ChangePassword": "Изменить пароль", "ChangeTagCloudView": "Учтите, что Вы можете просматривать отчет не только через облако тегов. Используйте элементы управления внизу отчета для переключения вариантов просмотра.", + "ChooseDate": "Выбор даты, сейчас выбрана дата %s", "ChooseLanguage": "Выбрать язык", "ChoosePeriod": "Выбрать период", "ClickHere": "Нажмите здесь, чтобы узнать больше", @@ -83,6 +86,8 @@ "ConfigFileIsNotWritable": "Файл конфигурации Piwik %1$s закрыт для записи, ваши изменения не будут сохранены. %2$s Пожалуйста, измените разрешения конфигурационного файла и разрешите запись в него.", "Continue": "Продолжить", "ContinueToPiwik": "Перейти к Piwik", + "CurrentlyUsingUnsecureHttp": "В данный момент вы используете Piwik через небезопасное соединение HTTP, что может быть рискованно. Мы рекомендуем настроить Piwik на использование SSL (HTTPS) для повышения уровня безопасности.", + "CreatedByUser": "сделано %s", "CurrentMonth": "Текущий месяц", "CurrentWeek": "Текущая неделя", "CurrentYear": "Текущий год", @@ -225,6 +230,7 @@ "Name": "Имя", "NbActions": "Количество действий", "NbSearches": "Количество обращений к внутреннему поиску", + "NeedMoreHelp": "Нужна помощь?", "Never": "Никогда", "NewReportsWillBeProcessedByCron": "Если архивирование Piwik не провоцируется браузером, новые отчеты производятся с помощью crontab-задач.", "NewUpdatePiwikX": "Новое обновление: Piwik %s", @@ -259,8 +265,11 @@ "OperationIsNot": "Не", "OperationLessThan": "Меньше чем", "OperationNotEquals": "Не равно", + "OperationStartsWith": "Начинается с", + "OperationEndsWith": "Заканчивается с", "OptionalSmtpPort": "Необязательно. По умолчанию используется 25 для незашифрованного и TLS SMTP соединения, и 465 для SSL SMTP.", "Options": "Настройки", + "Or": "или", "OrCancel": "или %1$s отмените %2$s", "Others": "Другие", "Outlink": "Исходящая ссылка", @@ -289,6 +298,8 @@ "Price": "Цена", "ProductConversionRate": "Конверсия для товара", "ProductRevenue": "Прибыль с товара", + "Measurable": "Единица измерения", + "Measurables": "Единицы измерения", "PurchasedProducts": "Купленные товары", "Quantity": "Количество", "RangeReports": "Другие периоды", @@ -349,6 +360,9 @@ "TotalRatioTooltip": "Это %1$s из всех %2$s %3$s.", "TotalRevenue": "Общая прибыль", "TotalVisitsPageviewsActionsRevenue": "(Всего: %1$s визиты, %2$s просмотры страниц, %3$s действия, %4$s выручка)", + "TrackingScopeAction": "Действие", + "TrackingScopePage": "Страница", + "TrackingScopeVisit": "Посещение", "TransitionsRowActionTooltip": "Посмотрите, что посетители делали до и после просмотра этой страницы", "TransitionsRowActionTooltipTitle": "Открыть переходы", "TranslatorName": "Ademaro, Joker Interactive, Важенин Илья (компания Codax), Nelde Maxim, Andrey, Vadim Nekhai, UptimePal", @@ -383,6 +397,7 @@ "WarningFileIntegrityNoManifestDeployingFromGit": "Если вы делаете деплой Piwik из Git, это сообщение является нормальным.", "WarningFileIntegrityNoMd5file": "Проверка целостности не может быть проведена из-за отсутствия функции md5_file().", "WarningPasswordStored": "%1$sВнимание:%2$s Этот пароль будет сохранен в конфигурационном файле на сервере в незашифрованном виде, и будет виден любому, кто имеет доступ к файловой системе сервера.", + "WarningDebugOnDemandEnabled": "Режим слежения за %1$s включен. Из соображений безопасности он должен быть включен только в небольшой период времени. Чтобы отключить его, установите %2$s на %3$s в %4$s", "Website": "Сайт", "Weekly": "Еженедельно", "WeeklyReport": "еженедельно", diff --git a/lang/sq.json b/lang/sq.json index 175075db1d..c071259db9 100644 --- a/lang/sq.json +++ b/lang/sq.json @@ -208,6 +208,7 @@ "NoDataForGraph": "Pa të dhëna për këtë grafik", "NoDataForTagCloud": "Pa të dhëna për këtë re etiketash.", "NotDefined": "%s pa u përkufizuar", + "NotRecommended": "jo e këshillueshme", "NotValid": "%s nuk është e vlefshme", "NumberOfVisits": "Numër vizitash", "NVisits": "%s vizita", @@ -273,6 +274,7 @@ "Total": "Gjithsej", "TotalRevenue": "Të ardhura Gjithsej", "TotalVisitsPageviewsActionsRevenue": "(Gjithsej: %1$s vizita, %2$s parje faqesh, %3$s veprime, %4$s të ardhura)", + "TrackingScopePage": "Faqe", "TranslatorName": "Besnik Bleta", "UniquePurchases": "Blerje Unike", "Unknown": "I panjohur", diff --git a/lang/sv.json b/lang/sv.json index 9628ac2bf3..312eb24a1b 100644 --- a/lang/sv.json +++ b/lang/sv.json @@ -366,7 +366,7 @@ "TrackingScopeVisit": "Besök", "TransitionsRowActionTooltip": "Se vad besökarna gjorde före och efter att ha tittat på den här sidan", "TransitionsRowActionTooltipTitle": "Öppna övergångar", - "TranslatorName": "Sökmotoroptimering.se, Kampanjjakt.se, Fredrik Astrom, Tony", + "TranslatorName": "Sökmotoroptimering.se, Kampanjjakt.se, Fredrik Astrom, Tony, National Library of Sweden<\/a>, Yegane Shirazi<\/a>", "UniquePurchases": "Unika beställningar", "Unknown": "Okänt", "Upload": "Ladda upp", diff --git a/lang/tr.json b/lang/tr.json index 219a429305..faa035cf35 100644 --- a/lang/tr.json +++ b/lang/tr.json @@ -285,7 +285,7 @@ "TrackingScopePage": "Sayfa", "TrackingScopeVisit": "Ziyaret", "TransitionsRowActionTooltipTitle": "Açık Geçişler", - "TranslatorName": "Fabian Becker, Emre Yazici, Emre Saraçoğlu, Uğur Eskici, Umut ARICAN", + "TranslatorName": "Fabian Becker, Emre Yazici, Emre Saraçoğlu, Uğur Eskici, Umut ARICAN<\/a>", "UniquePurchases": "Tekil Satın Alımlar", "Unknown": "Bilinmeyen", "Upload": "Yükle", diff --git a/plugins/API/lang/fi.json b/plugins/API/lang/fi.json index 22e886ce2c..27db066e77 100644 --- a/plugins/API/lang/fi.json +++ b/plugins/API/lang/fi.json @@ -4,8 +4,12 @@ "KeepTokenSecret": "Tämä token_auth on yhtä salainen kuin salasanasi, %1$s älä jaa sitä%2$s!", "LoadedAPIs": "Ladattiin %s APIa", "MoreInformation": "Lisätietoa Piwikin APIsta löytyy sivulta %1$sJohdatus Piwikin APIin%2$s ja %3$sPiwikin API%4$s.", + "PluginDescription": "Kaikki Piwikissä olevat tiedot on saatavilla yksinkertaisten APIen kautta. Tämä lisäosa on API verkkosivuille. Tämän lisäosan kautta voit ladata tiedot xml:nä, json:na, php:nä, csv:nä jne.", + "ReportingApiReference": "Raportointi-API:n referenssi", "TopLinkTooltip": "Hae analytiikkatietoja automaattisesti yksinkertaisella API:lla JSON:lla, XML:llä jne.", "UserAuthentication": "Käyttäjän autentikointi", - "UsingTokenAuth": "Jos haluat %1$s hakea tietoja skriptillä, crontabista jne. %2$s sinun täytyy lisätä parametri %3$s API-kutsujen osoitteisiin, jos kutsu vaatii autentikoinnin." + "UsingTokenAuth": "Jos haluat %1$s hakea tietoja skriptillä, crontabista jne. %2$s sinun täytyy lisätä parametri %3$s API-kutsujen osoitteisiin, jos kutsu vaatii autentikoinnin.", + "Glossary": "Sanasto", + "LearnAboutCommonlyUsedTerms": "Opi lisää yleisistä termeistä Piwikissä: %1$s ja %2$s." } } \ No newline at end of file diff --git a/plugins/API/lang/ru.json b/plugins/API/lang/ru.json index fd5378fa78..b1f33d003e 100644 --- a/plugins/API/lang/ru.json +++ b/plugins/API/lang/ru.json @@ -5,8 +5,11 @@ "LoadedAPIs": "%s API успешно загружен", "MoreInformation": "Чтобы узнать больше информации о Piwik API, пожалуйста, посмотрите раздел %1$s Introduction to Piwik API %2$s в %3$s Piwik API Reference %4$s.", "PluginDescription": "Все данные из Piwik доступны через простые API. Этот плагин является входной точкой для веб сервиса, который можно вызвать чтобы получить данные веб аналитики в xml, json, php, csv и др.", + "ReportingApiReference": "Сообщение справочной информации по API", "TopLinkTooltip": "Получайте доступ к вашей веб-аналитике с помощью простого API и использования json, xml и др.", "UserAuthentication": "Аутентификация пользователя", - "UsingTokenAuth": "Если вам необходимо %1$s запрашивать данные в ваших скриптах, cron-задачах, или другого источника, то вам %2$s необходимо добавить следующий ключ %3$s к URL API-вызова, который требует аутентификации." + "UsingTokenAuth": "Если вам необходимо %1$s запрашивать данные в ваших скриптах, cron-задачах, или другого источника, то вам %2$s необходимо добавить следующий ключ %3$s к URL API-вызова, который требует аутентификации.", + "Glossary": "Глоссарий", + "LearnAboutCommonlyUsedTerms": "Изучите часто используемые термины, чтобы извлечь максимум пользы из Piwik Analytics: %1$s and %2$s." } } \ No newline at end of file diff --git a/plugins/Actions/lang/fi.json b/plugins/Actions/lang/fi.json index cb7a0a31ca..26f23e5629 100644 --- a/plugins/Actions/lang/fi.json +++ b/plugins/Actions/lang/fi.json @@ -2,6 +2,7 @@ "Actions": { "AvgGenerationTimeTooltip": "Keskiarvo %1$s osumasta %2$s %3$s - %4$s", "ColumnClickedURL": "Klikattu URL", + "ColumnActionURL": "Toiminnon osoite", "ColumnClicks": "Klikkaukset", "ColumnClicksDocumentation": "Tämän linkin klikkausten määrä.", "ColumnDownloadURL": "Ladattu URL", @@ -39,6 +40,7 @@ "PagesReportDocumentation": "Tämä raportti sisältää tietoa sivuista, joilla on käyty. %s Taulukko on organisoitu hierarkisesti, URL:t näytetään puurakenteena.", "PageTitlesReportDocumentation": "Tämä raportti sisältää tietoa käytyjen sivujen otsikoista. %1$s Sivun otsikko on HTML:n %2$s-tagi, jonka useimmat selaimet näyttävät ikkunan otsikossa.", "PageUrls": "Sivujen URL:t", + "PluginDescription": "Raportoi sivukatselut ja sivujen otsikot. Mahdollistaa sivun sisäisen hakukoneen mittaamisen. Seuraa automaattisesti ulospäin suuntautuvia linkkejä ja latauksia.", "SiteSearchCategories1": "Tämä raportti listaa kategoriat jotka kävijät valitsivat.", "SiteSearchCategories2": "Esimerkiksi e-kauppojen sivuilla on tyypillisesti \"Kategoria\"-valitsin, jolla käyttäjät voivat rajoittaa hakutuloksia.", "SiteSearchFollowingPagesDoc": "Kun kävijät hakevat sivuiltasi, he etsivät tiettyä sivua, sisältöä, tuotetta tai palvelua. Tämä raportti listaa sivut joita klikattiin useiten haun jälkeen.", @@ -59,6 +61,7 @@ "WidgetPageUrlsFollowingSearch": "Verkkosivuhaun tuloksena löytyneet sivut", "WidgetSearchCategories": "Haun kategoriat", "WidgetSearchKeywords": "Sivuhaun hakusanat", - "WidgetSearchNoResultKeywords": "Hakusanat ilman tuloksia" + "WidgetSearchNoResultKeywords": "Hakusanat ilman tuloksia", + "ActionType": "Toiminnon tyyppi" } } \ No newline at end of file diff --git a/plugins/Actions/lang/ru.json b/plugins/Actions/lang/ru.json index 04b3e49b5e..61d49c8364 100644 --- a/plugins/Actions/lang/ru.json +++ b/plugins/Actions/lang/ru.json @@ -2,6 +2,7 @@ "Actions": { "AvgGenerationTimeTooltip": "В среднем по %1$s хит(ов) %2$s между %3$s и %4$s", "ColumnClickedURL": "URL кликов", + "ColumnActionURL": "URL действия", "ColumnClicks": "Клики", "ColumnClicksDocumentation": "Количество кликов по этой ссылке.", "ColumnDownloadURL": "Ссылка для загрузки", @@ -60,6 +61,7 @@ "WidgetPageUrlsFollowingSearch": "Страницы, которые нашлись в поиске", "WidgetSearchCategories": "Категории поиска", "WidgetSearchKeywords": "Поисковые ключевые слова сайта", - "WidgetSearchNoResultKeywords": "Поисковые ключевые слова без результатов" + "WidgetSearchNoResultKeywords": "Поисковые ключевые слова без результатов", + "ActionType": "Тип действия" } } \ No newline at end of file diff --git a/plugins/Contents/lang/ru.json b/plugins/Contents/lang/ru.json index b4d5864720..bddfd2799c 100644 --- a/plugins/Contents/lang/ru.json +++ b/plugins/Contents/lang/ru.json @@ -1,5 +1,6 @@ { "Contents": { + "PluginDescription": "Отслеживание контента и баннеров позволяет вам измерять эффективность (просмотры, клики, CTR) любой части контента на ваших страницах (баннер-реклама, изображение, любой элемент).", "Impressions": "Показы", "Interactions": "Взаимодествия", "Interaction": "Взаимодествие", @@ -7,6 +8,9 @@ "ContentName": "Название публикации", "ContentPiece": "Часть публикации", "ContentTarget": "Цель публикации", - "Contents": "Публикации" + "Contents": "Публикации", + "InteractionsMetricDocumentation": "Сколько раз с блоком контента происходило взаимодействие (например, 'клик' по баннеру или рекламе).", + "ImpressionsMetricDocumentation": "Сколько раз блок контента, такой как баннер или реклама, был показан на странице.", + "InteractionRateMetricDocumentation": "Соотношение представления контента и взаимодействий." } } \ No newline at end of file diff --git a/plugins/CoreAdminHome/lang/ru.json b/plugins/CoreAdminHome/lang/ru.json index 92b61015dc..f1c55ce85b 100644 --- a/plugins/CoreAdminHome/lang/ru.json +++ b/plugins/CoreAdminHome/lang/ru.json @@ -1,8 +1,10 @@ { "CoreAdminHome": { + "AddNewTrustedHost": "Добавить новый доверенный хост", "Administration": "Администрирование", "ArchivingSettings": "Настройка архивации", "BrandingSettings": "Настройки логотипа", + "ReleaseChannel": "Канал выпуска", "ClickHereToOptIn": "Кликните, чтобы вы учитывались в аналитике.", "ClickHereToOptOut": "Кликните, чтобы отказаться от учета вас в аналитике.", "CustomLogoFeedbackInfo": "Если вы используйете свой логотип, вам, возможно, также понадобится скрыть ссылку %1$s в верхнем меню. Для этого просто отключите плагин Feedback (обратная связь) на странице %2$sУправление плагинами%3$s.", @@ -20,6 +22,9 @@ "InvalidPluginsWarning": "Следующие плагины не совместимы с %1$s и не могут быть загружены: %2$s.", "InvalidPluginsYouCanUninstall": "Вы можете обновить или удалить эти плагины на странице %1$sУправления плагинами%2$s.", "JavaScriptTracking": "JavaScript-отслеживание", + "JSTracking_CampaignKwdParam": "Параметр Ключевого слова кампании", + "JSTracking_CampaignNameParam": "Параметр Имени кампании", + "JSTracking_CodeNoteBeforeClosingHead": "Удостоверьтесь, что этот код находится на каждой странице вашего вебсайта. Мы рекомендуем вставлять его сразу перед закрытием тега %1$s.", "JSTracking_CustomCampaignQueryParam": "Использовать пользовательские имена параметров в запросе для названия кампании и ключевого слова", "JSTracking_CustomCampaignQueryParamDesc": "Примечание: %1$sPiwik автоматически определит параметры Google Analytics.%2$s", "JSTracking_DisableCookies": "Отключить все отслеживания cookies", @@ -44,6 +49,7 @@ "JSTrackingIntro5": "Если вы хотите больше, чем простое отслеживание страниц, пожалуйста, ознакомьтесь с %1$sPiwik Javascript Tracking documentation%2$s для просмотра всех функций. С помощью этих функций вы можете отслеживать цели, пользовательские переменные, заказы электронной коммерции, неоформленные заказы и многое другое.", "LogoNotWriteableInstruction": "Чтобы использовать собственное лого вместо стандартного Piwik, откройте для записи эту папку: %1$s Piwik нужен доступ на запись к вашим лого, храняшимся в файлах %2$s.", "FileUploadDisabled": "Загрузка файлов не включена в вашей конфигурации PHP. Для загрузки другого логотипа выставите %s в php.ini и перезапустите веб-сервер.", + "LogoUploadFailed": "Загруженный файл не может быть обработан. Пожалуйста, проверьте, что файл имеет нужный формат.", "LogoUpload": "Выберите лого для загрузки", "FaviconUpload": "Выбрать Favicon для загрузки", "LogoUploadHelp": "Пожалуйста, закачивайте файлы в %1$s форматах, минимальное ограничение по высоте – %2$s пикселей.", @@ -53,6 +59,7 @@ "MenuDevelopment": "Разработка", "OptOutComplete": "Исключение из политики конфиденциальности завершено; ваши посещения на данный сайт не будут учитываться системой веб аналитики. Мы уважаем ваш выбор.", "OptOutCompleteBis": "Заметьте, что если вы очистите cookies браузера, то, скорее всего, удалится и исключительный cookie, или если вы поменяете компьютер или браузер, то необходимо будет пройти процедуру исключения снова.", + "OptOutDntFound": "Ваши действия не отслеживались, так как ваш браузер сообщает, что вы не хотите этого. Это настройка вашего браузера, поэтому у вас не будет возможности включить ее до тех пор, пока вы не отключите опцию \"Не отслеживать\".", "OptOutExplanation": "Piwik – за сохранение личных данных в сети. Поэтому данная система может предложить вашим пользователям выбор исключения из политики конфиденциальности (отказ от дальнейшего сбора статистики о пользователе). Вы можете вставить следующий HTML-код на одну из ваших страниц сайта, например на страницу о гарантиях конфиденциальности.", "OptOutExplanationBis": "Тег покаже \"iframe\", в якому міститиметься посилання для ваших відвідувачів, клацнувши на яке, вони зможуть відмовитися від потрапляння в веб-аналітику через отримання відповідного файлу cookie. %1$s Клацніть тут%2$s, щоб переглянути вміст що буде показано в \"iframe\".", "OptOutForYourVisitors": "Исключение из политики конфиденциальности Piwik для посетителей", @@ -67,6 +74,7 @@ "SendPluginUpdateCommunication": "Отправить email с уведомлением, когда для плагина будет доступна новая версия", "SendPluginUpdateCommunicationHelp": "Письмо будет отправлено суперпользователю когда будет доступна новая версия плагина.", "StableReleases": "Если Piwik является важной частью вашего бизнеса, мы рекомендуем использовать последнюю стабильную версию. Если вы используете последнюю бета версию, и вы нашли ошибку или есть предложение, пожалуйста, %1$sперейдите по ссылке%2$s.", + "LtsReleases": "Версии LTS (Долгосрочная поддержка) получают только исправления, касающиеся безопасности и ошибок.", "SystemPluginSettings": "Системные настройки плагинов", "TrackAGoal": "Отслеживать цель", "TrackingCode": "Код отслеживания", @@ -79,6 +87,8 @@ "YouAreOptedIn": "Статистика о вас собирается.", "YouAreOptedOut": "Вы отказались от сбора статистических данных.", "YouMayOptOut": "Вы можете отказаться от уникального cookie, привязанному к вашему браузеру, и идентифицирующего вас в системе аналитики данного сайта, тем самым отказавшись от любого сбора сведений о вас и их анализа на данном сайте.", - "YouMayOptOutBis": "Снимите галочку и получите исключающий cookie для отказа сбора данных." + "YouMayOptOutBis": "Снимите галочку и получите исключающий cookie для отказа сбора данных.", + "ProtocolNotDetectedCorrectly": "В данный момент вы просматриваете Piwik через безопасное соединение SSL (используя https), но Piwic смог обнаружить только небезопасное соединение на сервере.", + "ProtocolNotDetectedCorrectlySolution": "Чтобы удостовериться, что Piwic безопасно запрашивает и обрабатывает ваш контент через HTTPS, вы можете отредактировать свой файл %1$s или настроить ваши настройки прокси, или вы можете добавить линию %2$s под разделом %3$s. %4$sУзнать больше%5$s" } } \ No newline at end of file diff --git a/plugins/CoreHome/lang/fi.json b/plugins/CoreHome/lang/fi.json index 382429907e..401eb9fdfc 100644 --- a/plugins/CoreHome/lang/fi.json +++ b/plugins/CoreHome/lang/fi.json @@ -3,6 +3,7 @@ "CategoryNoData": "Tässä kategoriassa ei ole tietoja. Kokeile linkkiä \"Kaikki esiintymät\".", "CheckForUpdates": "Tarkista päivitykset", "CheckPiwikOut": "Tutustu Piwikiin!", + "ClickToEditX": "Muokkaa %s klikkaamalla", "CloseWidgetDirections": "Voit sulkea tämän widget-käyttöliittymän klikkaamalla \"X\"-ikonia käyttöliittymän yläreunassa.", "DataForThisReportHasBeenPurged": "Tämän raportin data on yli %s kuukautta vanhaa ja on poistettu.", "DataTableExcludeAggregateRows": "Yhdistetyt rivit ovat näkyvillä %s Piilota", @@ -23,8 +24,10 @@ "InjectedHostSuperUserWarning": "Piwik saattaa olla väärin asennettu (esim. jos Piwik on hiljattain siirretty uuteen serveriin tai URL:ään). Voit joko %1$sklikata tästä ja lisätä %2$s ja lisätä päteväksi Piwik isäntänimeksi (jos luotat siihen)%3$s, tai %4$sklikata tästä ja %5$s siirtyäksesi Piwikiin turvallisesti%6$s.", "InjectedHostWarningIntro": "Käytät Piwikiä osoitteesta %1$s, mutta Piwik on konfiguroitu ajettavaksi tässä osoitteessa: %2$s.", "JavascriptDisabled": "JavaScriptin täytyy olla käytössä normaalinäkymässä.
JavaScript ei ole päällä tai ei ole tuettu selaimessasi.
Ota JavaScript käyttöön selaimesi asetuksista ja %1$syritä uudelleen%2$s.", + "MainNavigation": "Päänavigointi", "MakeADifference": "Ole mukana vaikuttamassa: %1$sTee lahjoitus%2$s Piwik 2.0 version rahoittamiseksi!", "MakeOneTimeDonation": "Lahjoita kertasumma.", + "Menu": "Valikko", "NoPrivilegesAskPiwikAdmin": "Olet kirjautuneena sisään käyttäjänä '%1$s', mutta sinulla ei ole mitään oikeuksia Piwikissä. %2$sPyydä Piwikin ylläpitäjää (klikkaa avataksesi sähköpostin)%3$s antamaan katseluoikeudet verkkosivuun.", "OnlyForSuperUserAccess": "Tämä widget näkyy ainoastaan käyttäjille, joilla on Superkäyttäjän oikeudet.", "PageOf": "%1$s of %2$s", @@ -35,6 +38,7 @@ "SharePiwikShort": "Piwik! Ilmainen ja avoimen lähdekoodin verkkoanalyysi. Hallitse omaa dataasi.", "ShareThis": "Jaa tämä", "ShowJSCode": "Näytä lisättävä Javascript-koodi", + "SkipToContent": "Siirry sisältöön", "SubscribeAndBecomePiwikSupporter": "Jatka turvalliselle luottokorttimaksusivulle (Paypal) ryhtyäksesi Piwikin tukijaksi!", "SupportPiwik": "Tue Piwikiä!", "TableNoData": "Ei tietoja tässä taulukossa", @@ -45,6 +49,11 @@ "YouAreUsingTheLatestVersion": "Käytössäsi on uusin versio Piwikistä!", "ClickRowToExpandOrContract": "Klikkaa tätä riviä avataksesi tai sulkeaksesi alataulukon.", "UndoPivotBySubtable": "Tämä raportti on käännetty %s:llä. Kumoa kääntö", - "PivotBySubtable": "Tämä raportti ei ole käännetty %1$s:n mukaan. Käännetty %2$s:llä." + "PivotBySubtable": "Tämä raportti ei ole käännetty %1$s:n mukaan. Käännetty %2$s:llä.", + "QuickAccessTitle": "Hae %s:llä. Käytä nuolia navigointiin. Oikotie: haku aukeaa painamalla f-näppäintä.", + "MenuEntries": "Valikon sisältö", + "Segments": "Segmentit", + "AdblockIsMaybeUsed": "Jos käytät mainostenestoa (ad blocker), poista se käytöstä tällä sivulla, jotta Piwik toimii ongelmitta.", + "ChangeCurrentWebsite": "Valitse verkkosivu, nyt valittuna %s" } } \ No newline at end of file diff --git a/plugins/CoreHome/lang/ko.json b/plugins/CoreHome/lang/ko.json index 53f815c4cc..1288435bf2 100644 --- a/plugins/CoreHome/lang/ko.json +++ b/plugins/CoreHome/lang/ko.json @@ -49,6 +49,7 @@ "ClickRowToExpandOrContract": "하위 테이블의 행을 확장하거나 축소하기 위해 클릭하세요.", "UndoPivotBySubtable": "이 보고서는 %s Undo pivot에 의해 결정되었습니다.", "PivotBySubtable": "이 보고서는 %1$s Pivot이 %2$s에 의해 결정되지 않았습니다.", + "QuickAccessTitle": "%s 검색. 검색 결과를 확인할 때 방향키를 사용하세요. 단축키: 'f'는 검색", "MenuEntries": "메뉴", "Segments": "세그멘트", "AdblockIsMaybeUsed": "Piwik가 문제 없이 동작하기 위해서 광고 차단기능이 있는 플러그인을 꺼주시길 바랍니다.", diff --git a/plugins/CoreUpdater/lang/fi.json b/plugins/CoreUpdater/lang/fi.json index 87b362e1e2..28915e6f2f 100644 --- a/plugins/CoreUpdater/lang/fi.json +++ b/plugins/CoreUpdater/lang/fi.json @@ -25,6 +25,11 @@ "HighTrafficPiwikServerEnableMaintenance": "Jos Piwik-palvelimellasi on suuria määriä liikennettä, suosittelemme %1$spoistamaan käyttäjäseurannan hetkellisesti käytöstä ja laittamaan Piwikin käyttäjäliittymän huoltotilaan%2$s.", "IncompatbilePluginsWillBeDisabledInfo": "Huom. Osa lisäosista ei ole yhteensopivia Piwikin kanssa: %s. Nämä poistetaan käytöstä kun päivität:", "InstallingTheLatestVersion": "Asennetaan uusinta versiota", + "LatestBetaRelease": "Viimeisin beta-julkaisu", + "LatestStableRelease": "Viimeisin vakaa julkaisu", + "Latest2XStableRelease": "Viimeisin vakaa 2.X", + "Latest2XBetaRelease": "Viimeisin beta 2.X", + "LtsSupportVersion": "Pitkään tuettu versio", "MajorUpdateWarning1": "Tämä on iso päivitys! Päivityksessä kestää kauemmin kuin normaalisti.", "MajorUpdateWarning2": "Seuraavat ohjeet ovat erityisen tärkeitä suurille asennuksille.", "NoteForLargePiwikInstances": "Tärkeä tiedotus suurille Piwikin asennuksille", @@ -48,6 +53,8 @@ "UpdateHasBeenCancelledExplanation": "Piwikin yhden klikkauksen päivitys on peruutettu. Jos et voi korjata alla olevaa virhettä, on suositeltavaa päivittää Piwik manuaalisesti. %1$s Ole hyvä ja tarkista %2$sPäivitysdokumentaatio%3$s", "UpdateTitle": "Piwik › Päivitys", "UpdateSuccessTitle": "Piwik on päivitetty onnistuneesti!", + "UpdateErrorTitle": "Päivitysvirhe", + "Updating": "Päivitetään", "UpgradeComplete": "Päivitys valmis!", "UpgradePiwik": "Päivitä Piwik", "VerifyingUnpackedFiles": "Tarkistetaan purettuja tiedostoja", @@ -56,6 +63,7 @@ "YouCanUpgradeAutomaticallyOrDownloadPackage": "Voit päivittää versioon %s automaattisesti tai ladata paketin ja asentaa sen manuaalisesti:", "YouCouldManuallyExecuteSqlQueries": "Jos et voi käyttää komentorivin päivitysohjelmaa ja Piwikin päivitys epäonnistuu (aikakatkaisu tai jokin muu virhe), voit ajaa SQL-kyselyt itse.", "YouMustDownloadPackageOrFixPermissions": "Piwik ei voi ylikirjoittaa nykyistä asennusta. Voit joko korjata hakemistojen\/tiedostojen oikeudet tai ladata paketin ja asentaa version %s itse:", - "YourDatabaseIsOutOfDate": "Piwikin tietokanta on vanhentunut ja se tulee päivittää ennen jatkamista." + "YourDatabaseIsOutOfDate": "Piwikin tietokanta on vanhentunut ja se tulee päivittää ennen jatkamista.", + "ViewVersionChangelog": "katso muutostiedot tälle versiolle:" } } \ No newline at end of file diff --git a/plugins/CustomVariables/lang/fi.json b/plugins/CustomVariables/lang/fi.json index 51c8ee0f1f..0dfd138a41 100644 --- a/plugins/CustomVariables/lang/fi.json +++ b/plugins/CustomVariables/lang/fi.json @@ -5,6 +5,10 @@ "CustomVariables": "Kustomoidut muuttujat", "CustomVariablesReportDocumentation": "Tämä raportti sisältää tietoa kustomoiduista muuttujastasi. Voit tarkastella eri arvojen määrää klikkaamalla muuttujan nimeä. %1$s Saat lisätietoa kustomoiduista muuttujista %2$sCustom Variables%3$s-sivulta piwik.orgista (englanninkielinen)", "ScopePage": "alueena sivu", - "ScopeVisit": "alueena käynti" + "ScopeVisit": "alueena käynti", + "ManageDescription": "Tämä on yleiskatsaus kaikista kustomoiduista muuttujista ja niiden käytöstä verkkosivulla '%s'. Nimet on järjestetty käyttömäärien mukaan.", + "Index": "Indeksi", + "Usages": "Käytöt", + "Unused": "Käyttämätön" } } \ No newline at end of file diff --git a/plugins/DBStats/lang/fi.json b/plugins/DBStats/lang/fi.json index edb42aeadd..9232287c22 100644 --- a/plugins/DBStats/lang/fi.json +++ b/plugins/DBStats/lang/fi.json @@ -10,6 +10,7 @@ "MetricDataByYear": "Metriikat vuosittain", "MetricTables": "Metriikkataulut", "OtherTables": "Muut taulut", + "PluginDescription": "Tarjoaa tietoa MySQL-tietokannan käytöstä. Saatavilla pääkäyttäjille Diagnostiikka-sivun alla.", "ReportDataByYear": "Raporttitaulut vuosittain", "ReportTables": "Raporttitaulut", "RowCount": "Rivien määrä", diff --git a/plugins/Dashboard/lang/fi.json b/plugins/Dashboard/lang/fi.json index c888edd724..14a6dd65b1 100644 --- a/plugins/Dashboard/lang/fi.json +++ b/plugins/Dashboard/lang/fi.json @@ -18,8 +18,10 @@ "Maximise": "Suurenna", "Minimise": "Pienennä", "NotUndo": "Et voi peruuttaa tätä operaatiota.", + "PluginDescription": "Web-analytiikkojen työpöytä. Muokkaa työpöytääsi lisäämällä uusia osia, siirtämällä osia eri kohtiin, ja vaihtamalla työpöydän sisältöä. Jokainen käyttäjä voi hallita omaa työpöytäänsä.", "RemoveDashboard": "Poista näkymä", "RemoveDashboardConfirm": "Haluatko varmasti poistaa työpöydän \"%s\"?", + "RemoveDefaultDashboardNotPossible": "Oletustyöpöytää ei voi poistaa", "RenameDashboard": "Uudelleenimeä näkymä", "ResetDashboard": "Nollaa työpöytä", "ResetDashboardConfirm": "Haluatko varmasti nollata työpöydän asettelun takaisin oletusasetuksiin?", diff --git a/plugins/Dashboard/lang/lt.json b/plugins/Dashboard/lang/lt.json index dc83d12c30..b7ac2a7f30 100644 --- a/plugins/Dashboard/lang/lt.json +++ b/plugins/Dashboard/lang/lt.json @@ -9,6 +9,7 @@ "DashboardCopied": "Esamas skydelis sėkmingai nukopijuotas pasirinktam naudotojui.", "DashboardEmptyNotification": "Jūsų Skydelyje nėra jokių valdiklių. Pradėkite, pridėdami kelis valdiklius arba, tiesiog, atstatykite skydelį į numatytąjį valdiklių pasirinkimą.", "DashboardName": "Skydelio pavadinimas:", + "DashboardOf": "%s skydelis", "DefaultDashboard": "Numatytasis skydelis - Naudojamas numatytųjų valdiklių pasirinkimo ir stulpelių išdėstymas", "DeleteWidgetConfirm": "Ar tikrai norite pašalinti šį valdiklį iš skydelio?", "EmptyDashboard": "Tuščias skydelis - Parinkite savo mėgiamus valdiklius", @@ -20,6 +21,7 @@ "PluginDescription": "Jūsų Saityno Analitikos Skydelis. Tinkinkite savo skydelį, pridėdami naujų valdiklių, vilkdami juos iš vienos vietos į kitą ir keisdami skydelio stulpelių išdėstymą. Kiekvienas naudotojas gali tvarkyti savo asmeninį pasirinktiną skydelį.", "RemoveDashboard": "Šalinti skydelį", "RemoveDashboardConfirm": "Ar tikrai norite pašalinti skydelį \"%s\"?", + "RemoveDefaultDashboardNotPossible": "Numatytasis skydelis negali būti pašalintas", "RenameDashboard": "Pervadinti skydelį", "ResetDashboard": "Atstatyti skydelį", "ResetDashboardConfirm": "Ar tikrai norite atstatyti savo skydelio išdėstymą į numatytąjį Valdiklių pasirinkimą?", diff --git a/plugins/DevicePlugins/lang/fi.json b/plugins/DevicePlugins/lang/fi.json index 8011625ef1..de4ac1ac6b 100644 --- a/plugins/DevicePlugins/lang/fi.json +++ b/plugins/DevicePlugins/lang/fi.json @@ -2,6 +2,8 @@ "DevicePlugins": { "BrowserWithNoPluginsEnabled": "%1$s ilman liitännäisiä aktivoitu", "BrowserWithPluginsEnabled": "%1$s liitännäisillä %2$s on aktivoitu", + "PluginDescription": "Lista lisäosista joita kävijöiden selaimet tukevat.", + "PluginDetectionDoesNotWorkInIE": "Huom. Lisäosien tunnistus ei toimi Internet Explorerissa ennen versiota 11. Tässä raportissa on mukana vain uudet IE:t ja muut selaimet.", "WidgetPlugins": "Lista lisäosista", "WidgetPluginsDocumentation": "Tämä raportti näyttää, mitä selainlisäosia vierailijoillasi oli käytössä. Tästä tiedosta voi olla hyötyä, kun joudut valitsemaan, miten tietoa esitetään ja välitetään vierailijoille." } diff --git a/plugins/Diagnostics/lang/fi.json b/plugins/Diagnostics/lang/fi.json new file mode 100644 index 0000000000..28051d0630 --- /dev/null +++ b/plugins/Diagnostics/lang/fi.json @@ -0,0 +1,6 @@ +{ + "Diagnostics": { + "ConfigFileTitle": "Asetustiedosto", + "Sections": "Osiot" + } +} \ No newline at end of file diff --git a/plugins/Ecommerce/lang/fi.json b/plugins/Ecommerce/lang/fi.json new file mode 100644 index 0000000000..6942b9eb21 --- /dev/null +++ b/plugins/Ecommerce/lang/fi.json @@ -0,0 +1,8 @@ +{ + "Ecommerce": { + "PluginDescription": "E-kauppa mahdollistaa myyntiin liittyvien toimintojen seuraamisen: tuotteiden lisäämisen ostoskoriin ja ostosten tekemisen. Myös tuotteiden ja tuotekategorioiden katselu, ja hylätyt ostoskorit seurataan.", + "Sales": "Myynnit", + "SalesBy": "Myynnit %s:n mukaan", + "SalesAdjective": "Myynnit %s" + } +} \ No newline at end of file diff --git a/plugins/Feedback/lang/fi.json b/plugins/Feedback/lang/fi.json index 6ab6ec2a91..f665cbf2da 100644 --- a/plugins/Feedback/lang/fi.json +++ b/plugins/Feedback/lang/fi.json @@ -10,6 +10,12 @@ "RateFeatureTitle": "Pidätkö ominaisuudesta '%s'? Jätä arvostelu ja kommentti", "SendFeedback": "Lähetä palaute", "ThankYou": "Kiitos että autat parantamaan Piwikiä!", - "TopLinkTooltip": "Kerro meille mitä ajattelet, tai osta tukipalveluita (englanniksi)." + "TopLinkTooltip": "Kerro meille mitä ajattelet, tai osta tukipalveluita (englanniksi).", + "CommunityHelp": "Yhteisön apu", + "ProfessionalHelp": "Ammattilaisapu", + "PiwikProReviewPiwikSetup": "Piwik-asennuksesi arviointi", + "PiwikProPhoneEmailSupport": "Puhelin- ja sähköpostituki", + "PiwikProPremiumFeatures": "Premium-ominaisuudet", + "ContactUs": "Ota yhteyttä" } } \ No newline at end of file diff --git a/plugins/Goals/lang/el.json b/plugins/Goals/lang/el.json index 612438258b..b2cce6c204 100644 --- a/plugins/Goals/lang/el.json +++ b/plugins/Goals/lang/el.json @@ -66,7 +66,7 @@ "GoalsOverview": "Επισκόπηση στόχων", "GoalsOverviewDocumentation": "Αυτό είναι μια επισκόπηση των μετατροπών των στόχων σας. Αρχικά, το διάγραμμα δείχνει το άθροισμα όλων των μετατροπών. %s Κάτω από το διάγραμμα, μπορείτε να αναφορές μετατροπής για κάθε έναν από τους στόχους. Τα μικροδιαγράμματα μπορούν να μεγεθυνθούν πατώντας επάνω τους.", "GoalX": "Στόχος %s", - "HelpOneConversionPerVisit": "Αν μια Σελίδα ταιριάζει, αυτός ο Στόχος ανανεώνεται ή προβάλεται περισσόερες φορές ανά Επίσκεψη και ο Στόχος θα καταγράφετε μόνο την πρώτη φορά που φορτώθηκε η σελίδα κατά την επίσκεψη.", + "HelpOneConversionPerVisit": "Αν μια Σελίδα ταιριάζει, αυτός ο Στόχος ανανεώνεται ή προβάλλεται περισσότερες φορές ανά Επίσκεψη και ο Στόχος θα καταγράφεται μόνο την πρώτη φορά που φορτώθηκε η σελίδα κατά την επίσκεψη.", "IsExactly": "είναι ακριβώς %s", "LearnMoreAboutGoalTrackingDocumentation": "Δείτε περισσότερα για την %1$sΠαρακολούθηση των Στόχων στο Piwik%2$s στην τεκμηρίωση για το χρήστη.", "LeftInCart": "%s απομένουν στο καλάθι", diff --git a/plugins/Goals/lang/lt.json b/plugins/Goals/lang/lt.json index 10bcee0e28..c32adb2a5b 100644 --- a/plugins/Goals/lang/lt.json +++ b/plugins/Goals/lang/lt.json @@ -6,7 +6,7 @@ "BestCountries": "Jūsų geriausios konversijos šalys:", "BestKeywords": "Jū9sų geriausi konversijos raktažodžiai:", "BestReferrers": "Jūsų geriausios konversijos svetainės:", - "CaseSensitive": "Linksnių atitikimas", + "CaseSensitive": "Raidžių dydžio sutapimas", "ClickOutlink": "Paspauskite ant nuorodos į išorinį puslapį", "ColumnConversions": "Konversijos", "Contains": "turi %s", diff --git a/plugins/Goals/lang/nb.json b/plugins/Goals/lang/nb.json index 415c58bff0..62627850be 100644 --- a/plugins/Goals/lang/nb.json +++ b/plugins/Goals/lang/nb.json @@ -16,6 +16,7 @@ "ColumnConversions": "Konvertering", "ColumnConversionsDocumentation": "Antall konverteringer for %s.", "Contains": "inneholder %s", + "ConversionRate": "%s konverteringsrate", "Conversions": "%s konverteringer", "DaysToConv": "Dager til konvertering", "Details": "Måldetaljer", diff --git a/plugins/ImageGraph/lang/fi.json b/plugins/ImageGraph/lang/fi.json index 5dac1b5f20..06af13adfe 100644 --- a/plugins/ImageGraph/lang/fi.json +++ b/plugins/ImageGraph/lang/fi.json @@ -1,5 +1,6 @@ { "ImageGraph": { - "ColumnOrdinateMissing": "Kolumnia '%1$s' ei löydetty tässä raportissa. Kokeile mitä tahansa %2$s" + "ColumnOrdinateMissing": "Kolumnia '%1$s' ei löydetty tässä raportissa. Kokeile mitä tahansa %2$s", + "PluginDescription": "Luo kauniita staattisia PNG-kuvaajia mistä tahansa raportista." } } \ No newline at end of file diff --git a/plugins/Installation/lang/fi.json b/plugins/Installation/lang/fi.json index 0a3a2579dd..25a3b390af 100644 --- a/plugins/Installation/lang/fi.json +++ b/plugins/Installation/lang/fi.json @@ -15,6 +15,7 @@ "DatabaseSetupLogin": "käyttäjätunnus", "DatabaseSetupServer": "tietokantapalvelin", "DatabaseSetupTablePrefix": "taulujen etuliite", + "Email": "Sähköposti", "Extension": "lisäosa", "Filesystem": "Tiedostojärjestelmä", "GetInvolved": "Jos pidät näkemästäsi, myös sinä voit %1$sosallistua%2$s.", @@ -24,6 +25,7 @@ "InstallationStatus": "Asennuksen tila", "InsufficientPrivilegesHelp": "Voit lisätä nämä oikeudet esim. phpMyAdminilla tai ajamalla oikeat SQL-kyselyt. Jos et tiedä miten tehdä nämä asiat, pyydä järjestelmän ylläpitäjää säätämään oikeudet oikein.", "InsufficientPrivilegesMain": "Joko tietokantaa ei ole olemassa (eikä sitä voitu luoda), tai tällä käyttäjällä ei ole tarvittavia oikeuksia. Tietokannan käyttäjällä täytyy olla seuraavat oikeudet: %s", + "InvalidStateError": "Virhe: Piwik on jo asennettu. %1$s Mene takaisin %2$s Piwikiin%3$s.", "JsTagArchivingHelp1": "Kohtalaisen ja korkean liikenteen verkkosivuille on tiettyjä optimointeja, jotka tulisi tehdä, jotta Piwik voi toimia nopeammin (kuten %1$sautomaattisen arkistoinnin asettaminen%2$s).", "JSTracking_EndNote": "Huom: Asennuksen jälkeen voit luoda omia seurantakoodeja ylläpitosivun osastolla %1$sSeurantakoodi%2$s", "JSTracking_Intro": "Voidaksesi seurata liikennettä Piwikin avulla, sinun tulee lisätä ekstrakoodi jokaiselle verkkosivullesi.", @@ -36,9 +38,14 @@ "NfsFilesystemWarningSuffixInstall": "Tiedostopohjaisten sessioiden käyttäminen NFS:ssä on todella hidasta, joten Piwik käyttää tietokantasessioita. Jos sinulla on monia samanaikaisia ohjauspaneelin käyttäjiä, sinun tarvitsee ehkä lisätä tietokantaserverin käyttäjäyhteyksien maksimimäärää.", "NoConfigFound": "Piwikin asetustiedostoa ei löydy ja yrität siirtyä Piwikin sivuille.
  » Voit
asentaa Piwikin nyt<\/a><\/b>
Jos asensit Piwikin aikaisemmin ja tietokannassa on jo tietoja, älä murehdi, tietoja ei hävitetä.<\/small>", "Optional": "Optionaalinen", + "Password": "Salasana", "PasswordDoNotMatch": "salasanat eivät täsmää", + "PasswordRepeat": "Salasana (uudelleen)", "PercentDone": "%s %% valmiina", + "PiwikProAdTitle": "Edistynyt analytiikka ja palvelut", "PleaseFixTheFollowingErrors": "Korjaa seuraavat virheet", + "DefaultSettings": "Oletusasetukset", + "DefaultSettingsHelp": "Piwikissä on oletusasetukset. Voit muuttaa asetuksia nyt tai myöhemmin hallintasivulta.", "Requirements": "Piwikin vaatimukset", "RestartWebServer": "Käynnistä web-palvelimesi uudelleen näiden muutosten jälkeen.", "ReusingTables": "Taulukoiden uudelleenkäyttö", @@ -46,15 +53,19 @@ "SeeBelowForMoreInfo": "Katso alempaa lisätietoja.", "SetupWebsite": "Lisää verkkosivu", "SetupWebsiteError": "Virhe verkkosivun lisäämisessä", + "SetupWebSiteName": "Verkkosivun nimi", "SetupWebsiteSetupSuccess": "Sivu %s luotiin onnistuneesti!", + "SetupWebSiteURL": "Verkkosivun osoite", "SiteSetup": "Luo ensimmäinen seurattava verkkosivu:", "SiteSetupFootnote": "Huom: kun asennus on valmis, voit lisätä lisää verkkosivuja!", "SuperUser": "Pääkäyttäjä", + "SuperUserLogin": "Pääkäyttäjän kirjautuminen", "SuperUserSetupError": "Superkäyttäjää lisätessä tapahtui virhe.", "SuperUserSetupSuccess": "Pääkäyttäjän luominen onnistui!", "SystemCheck": "Järjestelmän asetukset", "SystemCheckAutoUpdateHelp": "Huomioi: Piwikin yhden klikkauksen päivitys vaatii kirjoitusoikeudet Piwikin kansioon ja kansion kaikkeen sisältöön.", "SystemCheckCreateFunctionHelp": "Piwik käyttää anonyymejä funktioita takaisinkutsuihin.", + "SystemCheckDatabaseExtensions": "MySQL-lisäosat", "SystemCheckDatabaseHelp": "Piwik vaatii joko mysqli-lisäosan tai sekä PDO- että pdo_mysql-lisäosat..", "SystemCheckDebugBacktraceHelp": "View::factory ei voi luoda näkymää kutsuvalle moduulille.", "SystemCheckError": "Tapahtui virhe - täytyy korjata ennen jatkamista", @@ -62,6 +73,7 @@ "SystemCheckExtensions": "Muut vaaditut lisäosat", "SystemCheckFileIntegrity": "Tiedoston eheys", "SystemCheckFunctions": "Vaaditut funktiot", + "SystemCheckFunctionHelp": "Sinun täytyy ottaa käyttöön tämä sisäänrakennettu funktio.", "SystemCheckGDFreeType": "GD > 2.x + Freetype (grafiikka)", "SystemCheckGDHelp": "Pienet graafit eivät toimi.", "SystemCheckGlobHelp": "Tämä sisäänrakennettu toiminnallisuus on poistettu käytöstä palvelimellasi. Piwik yrittää emuloida toimintoa, mutta saattaa törmätä uusiin turvallisuusrajoituksiin. Suorituskyky heikkenee.", @@ -99,6 +111,7 @@ "SystemCheckZlibHelp": "PHP pitää olla asennettuna zlib-lisäosan kanssa, --with-zlib.", "SystemCheckCronArchiveProcess": "Arkistointityö", "SystemCheckCronArchiveProcessCLI": "Prosessien hallinta komentoriviltä", + "SystemCheckUpdateHttps": "Päivitä HTTPS:n yli", "NotSupported": "ei tuettu", "Tables": "Luodaan taulut", "TablesCreatedSuccess": "Taulut luotu onnistuneesti!", @@ -109,6 +122,7 @@ "TablesUpdatedSuccess": "Tietokanta on päivitetty onnistuneesti: %1$s > %2$s!", "TablesWarningHelp": "Valitse joko nykyisten taulujen käyttö tai luo taulut uudelleen (vanhat tiedot menetetään).", "TablesWithSameNamesFound": "Osalla %1$s tauluista tietokannassa %2$s on sama nimi kuin tauluilla, joita Piwik yrittää luoda.", + "Timezone": "Verkkosivun aikavyöhyke", "WeHopeYouWillEnjoyPiwik": "Toivomme että nautit Piwikin käytöstä yhtä paljon kuin me nautimme sen luomisesta!", "Welcome": "Tervetuloa!", "WelcomeHelp": "

Piwik on vapaan lähdekoodin verkkosivujen analysointityökalu, joka tekee kävijöiden tietojen keräämisen ja analysoinnin helpoksi.<\/p>

Tämä prosessi on jaettu %s helppoon osaan ja vie aikaa noin viisi minuuttia.<\/p>", diff --git a/plugins/Live/lang/fi.json b/plugins/Live/lang/fi.json index 505ef58e1b..a273a5d133 100644 --- a/plugins/Live/lang/fi.json +++ b/plugins/Live/lang/fi.json @@ -31,6 +31,8 @@ "VisitorProfile": "Kävijäprofiili", "VisitorsInRealTime": "Reaaliaikaiset kävijätiedot", "VisitorsLastVisit": "Tämän kävijän edellinen käynti oli %s päivää sitten.", - "VisitsFrom": "%1$s%2$s käyntiä%3$s lähteestä" + "VisitsFrom": "%1$s%2$s käyntiä%3$s lähteestä", + "OnClickPause": "%s on käynnissä. Pysäytä klikkaamalla.", + "OnClickStart": "%s on pysäytetty. Aloita klikkaamalla." } } \ No newline at end of file diff --git a/plugins/Live/lang/nb.json b/plugins/Live/lang/nb.json index f70474f6c6..5ac8a3275c 100644 --- a/plugins/Live/lang/nb.json +++ b/plugins/Live/lang/nb.json @@ -23,6 +23,7 @@ "VisitorProfile": "Besøksprofil", "VisitorsInRealTime": "Besøkende i sanntid", "VisitsFrom": "%1$s%2$s besøk%3$s fra", + "VisitSummaryWithActionDetails": "Brukte totalt %1$s%2$s på nettsiden%3$s og utførte %4$s handlinger%5$s (%6$s) over %7$s besøk%8$s.", "OnClickPause": "%s er startet. Klikk for å sette på pause.", "OnClickStart": "%s er stoppet. Klikk for å starte." } diff --git a/plugins/MobileAppMeasurable/lang/fi.json b/plugins/MobileAppMeasurable/lang/fi.json new file mode 100644 index 0000000000..8300bfb476 --- /dev/null +++ b/plugins/MobileAppMeasurable/lang/fi.json @@ -0,0 +1,7 @@ +{ + "MobileAppMeasurable": { + "MobileApp": "Mobiili-app", + "MobileApps": "Mobiili-appit", + "MobileAppDescription": "Natiiviohjelmat iOS:llä, Androidilla tai millä tahansa muulla mobiilikäyttöjärjestelmällä" + } +} \ No newline at end of file diff --git a/plugins/PrivacyManager/lang/fi.json b/plugins/PrivacyManager/lang/fi.json index bc8d0c0085..af20fe9d0c 100644 --- a/plugins/PrivacyManager/lang/fi.json +++ b/plugins/PrivacyManager/lang/fi.json @@ -2,6 +2,7 @@ "PrivacyManager": { "AnonymizeIpDescription": "Valitse \"Kyllä\", jos et halua, että Piwik seuraa kokonaisia IP-osoitteita.", "AnonymizeIpInlineHelp": "Poistaa viimeisen tavun vierailijoiden IP-osoitteista, mikäli paikalliset yksityiseensuojalait\/-ohjeistukset vaativat.", + "AnonymizeIpExtendedHelp": "Kun käyttäjät vierailevat sivullasi, Piwik ei tallenna täyttä IP-osoitetta (esim. %1$s), vaan sen sijaan osoite anonymisoidaan (esim. %2$s). IP-osoitteen anonymisointi on osa yksityisyydensuojasta määrääviä lakeja esimerkiksi Saksassa.", "AnonymizeIpMaskLengtDescription": "Valitse, montako tavua käyttäjien IP-osoitteista piilotetaan.", "AnonymizeIpMaskLength": "%1$s tavua - esim. %2$s", "CannotLockSoDeleteLogActions": "log_action-taulua ei ole tyhjätty. Lisää \"LOCK TABLES\"-oikeus käyttäjälle %s.", @@ -12,6 +13,8 @@ "DeleteDataDescription": "Voit säätää Piwikin poistamaan vanhat kävijätiedot ja\/tai luodut raportit, jotta tietokannan koko pysyy pienenä.", "DeleteDataDescription2": "Voit valita, että etukäteen luodut raportit säilytetäänja ainoastaan käynnit, avatut sivut ja seurantalogit poistetaan. Tai raportit voidaan poistaa ja logit säilyttää.", "DeleteDataInterval": "Poista vanhat tiedot joka", + "DeleteOldVisitorLogs": "Poista vanhat kävijälogit", + "DeleteOldArchivedReports": "Poista arkistoidut raportit", "DeleteLogDescription2": "Kun lokeja poistetaan automaattisesti, sinun täytyy tarkistaa, että kaikki aikaisemmat päivittäiset raportit on prosessoitu, jotta tietoja ei häviä.", "DeleteLogInfo": "Lokit seuraavista tauluista poistetaan: %s", "DeleteLogsConfirm": "Olet ottamassa käyttöön lokitietojen poistamisen. Jos vanhat tiedot poistetaan ja raportteja ei ole vielä luotu, et näe historiatietoja. Haluatko varmasti tehdä tämän?", @@ -24,6 +27,7 @@ "DeleteReportsInfo2": "Jos et ole ottanut käyttöön \"%s\":ää, vanhat raportit luodaan automaattisesti uudelleen tarvittaessa.", "DeleteReportsInfo3": "Jos olet ottanut käyttöön \"%s\":n, vanhat tiedot poistetaan lopullisesti.", "DeleteReportsOlderThan": "Poista raportit, jotka ovat vanhempia kuin", + "DeleteSchedulingSettings": "Ajoita vanhojen tietojen poisto", "DeleteDataSettings": "Poista vanhat lokit ja raportit", "DoNotTrack_Description": "\"Do not Track\" (älä seuraa) on teknologia, jolla käyttäjät voivat ilmoittaa etteivät halua tulla seuratuiksi.", "DoNotTrack_Disable": "Poista \"Älä seuraa minua\" (\"do not track\") -tuki käytöstä", @@ -38,15 +42,18 @@ "GeolocationAnonymizeIpNote": "Huom: Geopaikannuksella on suurin piirtein samat tulokset, kun 1 tavu on salattu. Jos 2 tavua tai enemmän on salattu, Geopaikannus on epätarkka.", "GetPurgeEstimate": "Kokoarviot tietojen poistamisesta", "KeepBasicMetrics": "Kerää yksinkertaiset metriikat (käynnit, sivujen katselut, kauppatiedot jne.)", + "KeepDataFor": "Säilytä kaikki tiedot", "KeepReportSegments": "Säilytä alla listattujen tietojen lisäksi segmentoidut raportit", "LastDelete": "Edellinen poistaminen oli", "LeastDaysInput": "Päiviä täytyy olla enemmän kuin %s.", "LeastMonthsInput": "Kuukausien lukumäärän täytyy olla suurempi kuin %s.", "MenuPrivacySettings": "Yksityisyys", "NextDelete": "Seuraava poistaminen on", + "PluginDescription": "Paranna kävijöiden yksityisyydensuojaa ja säädä Piwik-asennuksesi noudattamaan paikallista lainsäädäntöä", "PurgeNow": "Siivoa tietokanta nyt", "PurgeNowConfirm": "Olet poistamassa tietoja lopullisesti. Haluatko varmasti jatkaa?", "PurgingData": "Siivotaan tietoja...", + "RecommendedForPrivacy": "Suositellaan yksityisyydensuojaan", "ReportsDataSavedEstimate": "Tietokannan koko", "SaveSettingsBeforePurge": "Olet muuttanut tietojen poistamisen asetuksia. Tallenna muutokset ennen jatkamista.", "SeeAlsoOurOfficialGuidePrivacy": "Lue myös virallinen oppaamme: %1$sVerkkoanalyysi ja yksityisyys%2$s", diff --git a/plugins/PrivacyManager/lang/nb.json b/plugins/PrivacyManager/lang/nb.json index 87b96e9d56..8642afedbf 100644 --- a/plugins/PrivacyManager/lang/nb.json +++ b/plugins/PrivacyManager/lang/nb.json @@ -12,6 +12,8 @@ "DeleteMaxRowsNoLimit": "ingen grense", "DeleteReportsOlderThan": "Slett rapporter eldre enn", "DeleteDataSettings": "Slett gamle besøkslogger og -rapporter", + "DoNotTrack_Disable": "Deaktiver Do Not Track støtte", + "DoNotTrack_Enable": "Aktiver Do Not Track støtte", "EstimatedSpaceSaved": "Estimert plassbesparelse", "GeolocationAnonymizeIpNote": "Merk: Geoposisjonering vil ha omtrent de samme resultatene med en byte anonymisert. Med to byte eller mer, vil geoposisjonering være unøyaktig.", "KeepDataFor": "Behold all data for", diff --git a/plugins/Provider/lang/fi.json b/plugins/Provider/lang/fi.json index bf079428c4..cce8a9cac5 100644 --- a/plugins/Provider/lang/fi.json +++ b/plugins/Provider/lang/fi.json @@ -1,7 +1,9 @@ { "Provider": { "ColumnProvider": "Palveluntarjoajat", + "PluginDescription": "Raportoi kävijöiden internetoperaattorin", "ProviderReportDocumentation": "Tämä raportti näyttää, mitä internetin toimittajia kävijäsi käyttivät sivuillasi. Saat lisätietoja klikkaamalla toimittajan nimeä. %s Jos Piwik ei tunnista toimittajan nimeä, kävijästä näytetään IP.", - "WidgetProviders": "Palveluntarjoajat" + "WidgetProviders": "Palveluntarjoajat", + "ProviderReportFooter": "Tuntematon toimittaja ei selvitä IP-osoitteita" } } \ No newline at end of file diff --git a/plugins/Referrers/lang/fi.json b/plugins/Referrers/lang/fi.json index a4e985a12b..3f877a70ea 100644 --- a/plugins/Referrers/lang/fi.json +++ b/plugins/Referrers/lang/fi.json @@ -20,10 +20,12 @@ "EvolutionDocumentationMoreInfo": "Löydät lisätietoja erilaisista viittaustyypeistä taulun %s dokumentaatiosta.", "Keywords": "Avainsanat", "KeywordsReportDocumentation": "Tämä rapotti näyttää, millä hakusanoilla kävijät tulivat sivuillesi. %s Näet hakukoneiden määrän klikkaamalla hakusanaa.", + "PluginDescription": "Raportoi viittaajiin liittyvää tietoa: hakukoneet, hakusanat, verkkosivut, kampanjat, sosiaalisen median, suorat saapumiset.", "Referrer": "Viittaukset", "ReferrerName": "Viittauksen nimi", "Referrers": "Viittaajat", "ReferrersOverview": "Viittauksien yleiskatsaus", + "ReferrerTypes": "Viittaajatyypit", "SearchEngines": "Hakukoneet", "SearchEnginesDocumentation": "Kävijä tuli sivullesi hakukoneesta. %1$s Katso %2$s raportista lisätietoja.", "SearchEnginesReportDocumentation": "Tämä raportti näyttää, mitkä hakukoneet viittasivat kävijöitä sivuillesi. %s Näet hakusanat klikkaamalla hakukoneen nimeä.", diff --git a/plugins/SEO/lang/fi.json b/plugins/SEO/lang/fi.json index 354270e2d3..02accf4536 100644 --- a/plugins/SEO/lang/fi.json +++ b/plugins/SEO/lang/fi.json @@ -1,5 +1,6 @@ { "SEO": { + "PluginDescription": "Tämä lisäosa hakee ja näyttää SEO-tietoja: Alexan web ranking, Googlen Pagerank, indeksoitujen sivujen lukumäärän, ja takaisin osoittavien linkkien määrän valitulle sivulle.", "AlexaRank": "Alexa-tulos", "Bing_IndexedPages": "Bingin indeksoidut sivut", "Dmoz": "DMOZ tulossivut", diff --git a/plugins/SegmentEditor/lang/fi.json b/plugins/SegmentEditor/lang/fi.json index de72617253..7aab90628c 100644 --- a/plugins/SegmentEditor/lang/fi.json +++ b/plugins/SegmentEditor/lang/fi.json @@ -16,10 +16,17 @@ "SegmentDisplayedAllWebsites": "kaikki sivut", "SegmentDisplayedThisWebsiteOnly": "vain tällä verkkosivulla", "SegmentNotApplied": "Segmenttiä '%s' ei sovelleta", + "SelectSegmentOfVisits": "Valitse segmentit käynnille:", "ThisSegmentIsVisibleTo": "Tämä segmentti näytetään seuraaville:", "VisibleToAllUsers": "kaikki käyttäjät", "VisibleToMe": "minä", "YouMayChangeSetting": "Vaihtoehtoisesti voit vaihtaa asetuksen tiedostosta %1$s, tai muuttaa tätä segmenttiä ja valita '%2$s'.", - "YouMustBeLoggedInToCreateSegments": "Sinun täytyy olla sisäänkirjautuneena voidaksesi luoda tai muokata kävijäsegmenttejä." + "VisibleToSuperUser": "Näkyvissä sinulle, koska sinulla on pääkäyttäjän oikeudet", + "SharedWithYou": "Jaettu kanssasi", + "YouMustBeLoggedInToCreateSegments": "Sinun täytyy olla sisäänkirjautuneena voidaksesi luoda tai muokata kävijäsegmenttejä.", + "AddingSegmentForAllWebsitesDisabled": "Segmenttien lisääminen kaikille verkkosivuille on poistettu käytöstä.", + "CustomSegment": "Kustomoidut segmentit", + "SegmentOperatorIsNullOrEmpty": "on tyhjä", + "SegmentOperatorIsNotNullNorEmpty": "ei ole tyhjä" } } \ No newline at end of file diff --git a/plugins/SitesManager/lang/el.json b/plugins/SitesManager/lang/el.json index e8636db0ad..a6b2092a5a 100644 --- a/plugins/SitesManager/lang/el.json +++ b/plugins/SitesManager/lang/el.json @@ -11,7 +11,7 @@ "DefaultCurrencyForNewWebsites": "Προεπιλεγμένο Νόμισμα για νέες ιστοσελίδες", "DefaultTimezoneForNewWebsites": "Προεπιλεγμένη Ζώνη ώρας για νέες ιστοσελίδες", "DeleteConfirm": "Είστε σίγουρος ότι θέλετε να διαγράψετε την ιστοσελίδα %s?", - "DisableSiteSearch": "Να μην καταγράφετε η Αναζήτηση Σελίδας", + "DisableSiteSearch": "Να μην καταγράφεται η Αναζήτηση Σελίδας", "EcommerceHelp": "Όταν ενεργοποιηθεί, η αναφορά «Στόχοι» θα έχει ένα νέο τομέα «Ηλεκτρονικό Εμπόριο».", "EnableEcommerce": "Το Ηλεκτρονικό Εμπόριο ενεργοποιήθηκε", "EnableSiteSearch": "Η καταγραφή Αναζήτησης Ιστοσελίδας είναι ενεργοποιημένη", diff --git a/plugins/Transitions/lang/fi.json b/plugins/Transitions/lang/fi.json index 246303c4df..df5c6bc3a8 100644 --- a/plugins/Transitions/lang/fi.json +++ b/plugins/Transitions/lang/fi.json @@ -16,6 +16,7 @@ "NoDataForAction": "%s:lle ei ole tietoja", "NoDataForActionDetails": "Joko toiminnolle ei ole tietoja aikavälille %s tai toiminto on virheellinen.", "OutgoingTraffic": "Lähtevä liikenne", + "PluginDescription": "Raportoi edellisen ja seuraavat toiminnot jokaiselle sivulle. Saatavilla \"Toiminnot\"-raportissa uuden ikonin takaa.", "ShareOfAllPageviews": "Tällä sivulla on %1$s sivunavausta (%2$s kaikista)", "ToFollowingPages": "Sisäisille sivuille", "ToFollowingPagesInline": "%s sisäisille sivuille", diff --git a/plugins/UserCountry/lang/fi.json b/plugins/UserCountry/lang/fi.json index 98ea0c0518..1cb6e70cb2 100644 --- a/plugins/UserCountry/lang/fi.json +++ b/plugins/UserCountry/lang/fi.json @@ -16,6 +16,7 @@ "country_a2": "Satelliittiyhteys", "country_cat": "Katalaania puhuvat alueet", "country_o1": "Muu maa", + "country_ti": "Tiibet", "CurrentLocationIntro": "Tämän toteutuksen mukaan nykyinen sijaintisi on", "DefaultLocationProviderDesc1": "Oletustoteutus arvaa käyttäjien maan kielen perusteella.", "DefaultLocationProviderDesc2": "Tämä ei ole erityisen tarkkaa, joten %1$ssuosittelemme asentamaan ja käyttämään %2$sGeoIp:tä%3$s.%4$s", diff --git a/plugins/UserCountry/lang/nb.json b/plugins/UserCountry/lang/nb.json index 34b842e32d..a0c714d458 100644 --- a/plugins/UserCountry/lang/nb.json +++ b/plugins/UserCountry/lang/nb.json @@ -24,6 +24,7 @@ "HowToInstallGeoIpPecl": "Hvordan installerer jeg GeoIP PECL-utvidelsen?", "HowToInstallNginxModule": "Hvordan installerer jeg GeoIP-modulen for Nginx?", "HowToSetupGeoIP_Step1": "%1$sLast ned%2$s GeoLite City-databasen fra %3$sMaxMind%4$s.", + "HttpServerModule": "HTTP Server-modul", "ISPDatabase": "ISP-database", "IWantToDownloadFreeGeoIP": "Jeg vil laste ned gratis GeoIP-database...", "Latitude": "Breddegrad", diff --git a/plugins/UserCountryMap/lang/fi.json b/plugins/UserCountryMap/lang/fi.json index 9da534097e..ab377390bd 100644 --- a/plugins/UserCountryMap/lang/fi.json +++ b/plugins/UserCountryMap/lang/fi.json @@ -1,5 +1,6 @@ { "UserCountryMap": { + "PluginDescription": "Tämä lisäosa tarjoaa käyttäjäkartan ja reaaliaikakartan. Huom: \"UserCountry\"-lisäosan täytyy olla päällä.", "AndNOthers": "ja %s muuta", "Cities": "Kaupunkeja", "Countries": "Maita", @@ -17,6 +18,8 @@ "ShowingVisits": "Geopaikannetut käynnit viimeiset", "Unlocated": "%s<\/b> %p käynneistä %c:sta ei voitu geopaikantaa.", "VisitorMap": "Kartta kävijöistä", - "WorldWide": "Maailmanlaajuinen" + "WorldWide": "Maailmanlaajuinen", + "WithUnknownRegion": "%s tuntemattomalta alueelta", + "WithUnknownCity": "%s tuntemattomista kaupungeista" } } \ No newline at end of file diff --git a/plugins/UserLanguage/lang/fi.json b/plugins/UserLanguage/lang/fi.json index 57a7794cc9..140e43780b 100644 --- a/plugins/UserLanguage/lang/fi.json +++ b/plugins/UserLanguage/lang/fi.json @@ -1,6 +1,7 @@ { "UserLanguage": { "BrowserLanguage": "Selaimen kieli", - "LanguageCode": "Kielikoodi" + "LanguageCode": "Kielikoodi", + "PluginDescription": "Raportoi käyttäjän selaimen kieliasetukset." } } \ No newline at end of file diff --git a/plugins/UsersManager/lang/fi.json b/plugins/UsersManager/lang/fi.json index 8a39276cae..9fb8873852 100644 --- a/plugins/UsersManager/lang/fi.json +++ b/plugins/UsersManager/lang/fi.json @@ -3,9 +3,11 @@ "AddUser": "Lisää uusi käyttäjä", "Alias": "Alias", "AllWebsites": "Kaikki sivut", + "AnonymousUser": "Anonyymi käyttäjä", "AnonymousUserHasViewAccess": "Huom: käyttäjällä %1$s on %2$s pääsy tälle verkkosivulle.", "AnonymousUserHasViewAccess2": "Analyysiraporttisi ja kävijätietosi ovat julkisia.", "ApplyToAllWebsites": "Päivitä kaikille sivuille", + "ChangeAllConfirm": "Haluatko varmasti antaa käyttäjälle '%s' pääsyn kaikille verkkosivuille?", "ChangePasswordConfirm": "Salasanan vaihtaminen vaihtaa myös käyttäjän token_auth:n. Haluatko varmasti jatkaa?", "ClickHereToDeleteTheCookie": "Paina tästä poistaaksesi cookie", "ClickHereToSetTheCookieOnDomain": "Paina tästä luodaksesi cookie sivulle %s", @@ -14,6 +16,7 @@ "DeleteConfirm": "Haluatko varmasti poistaa käyttäjän %s?", "Email": "Sähköposti", "EmailYourAdministrator": "%1$sLähetä ylläpitäjällesi sähköpostia ongelmasta%2$s.", + "EnterUsernameOrEmail": "Kirjoita käyttäjätunnus tai sähköpostiosoite", "ExceptionAccessValues": "Oikeuksien täytyy olla yksi seuraavista arvoista: [ %s ]", "ExceptionAdminAnonymous": "Et voi sallia ylläpito-oikeuksia anonyymikäyttäjälle.", "ExceptionDeleteDoesNotExist": "Käyttäjää '%s' ei ole eikä sitä siksi voida poistaa.", @@ -21,14 +24,20 @@ "ExceptionEditAnonymous": "Anonyymikäyttäjää ei voi muokata tai poistaa. Se on Piwikin sisäinen tunnus käyttäjälle, joka ei ole kirjautunut sisään. Voit esimerkiksi julkaista tilastoja kaikille sallimalla anonyymikäyttäjälle katsomisoikeuden.", "ExceptionEmailExists": "Käyttäjä sähköpostilla '%s' on jo olemassa.", "ExceptionInvalidEmail": "Sähköposti ei ole kelvollinen.", + "ExceptionInvalidLoginFormat": "Käyttäjänimen pitää olla %1$s-%2$s merkkiä pitkä ja saa sisältää vain kirjaimia (ei ääkkösiä), numeroita tai '_' or '-' or '.' or '@' or '+'", "ExceptionInvalidPassword": "Salasanan pituuden täytyy olla %1$s ja %2$s välillä.", + "ExceptionLoginExists": "Käyttäjätunnus '%s' on jo olemassa.", "ExceptionPasswordMD5HashExpected": "UserManager.getTokenAuth haluaa MD5-tiivisteen salasanastasi (32 merkkiä pitkä merkkijono). Kutsu md5()-funktiota salasanallesi ennen kutsumista.", "ExceptionRemoveSuperUserAccessOnlySuperUser": "Superkäyttäjäoikeuksien poistaminen käyttäjältä '%s' ei ole mahdollista.", "ExceptionSuperUserAccess": "Tällä käyttäjällä on jo Superkäyttäjäoikeudet ja oikeudet muokata kaikkia verkkosivuja Piwikissä. Voit poistaa Superkäyttäjäoikeudet tältä käyttäjältä ja yrittää uudelleen.", "ExceptionUserDoesNotExist": "Käyttäjää '%s' ei ole olemassa.", "ExceptionYouMustGrantSuperUserAccessFirst": "Ainakin yhdellä käyttäjällä tulee olla Superkäyttäjäoikeudet. Ole hyvä ja anna toiselle käyttäjälle Superkäyttäjäoikeudet ensin.", + "ExceptionUserHasViewAccessAlready": "Käyttäjällä on jo pääsy sivulle.", + "ExceptionNoValueForUsernameOrEmail": "Kirjoita käyttäjätunnus tai sähköpostiosoite.", "ExcludeVisitsViaCookie": "Poista käyntiesi seuraaminen cookiella", "ForAnonymousUsersReportDateToLoadByDefault": "Lataa anonyymeille käyttäjille oletuksena", + "GiveViewAccess": "Anna katseluoikeus", + "GiveViewAccessTitle": "Anna olemassaolevalle käyttäjälle oikeus katsoa %s:n raportteja", "IfYouWouldLikeToChangeThePasswordTypeANewOne": "Jos haluat vaihtaa salasanan, kirjoita uusi. Muuten jätä tyhjäksi.", "InjectedHostCannotChangePwd": "Olet sivulla tällä hetkellä tuntemattoman isännän kautta (%1$s). Et voi vaihtaa salasanaasi ennen kuin tämä ongelma on korjattu.", "LastSeen": "Nähty viimeeksi", @@ -36,8 +45,11 @@ "MenuAnonymousUserSettings": "Anonyymin käyttäjän asetukset", "MenuUsers": "Käyttäjät", "MenuUserSettings": "Käyttäjäasetukset", + "MenuPersonal": "Henkilökohtainen", + "PersonalSettings": "Henkilökohtaiset asetukset", "NoteNoAnonymousUserAccessSettingsWontBeUsed2": "Huom. et voi vaihtaa tämän osion asetuksia, koska sinulla ei ole yhtäkään sivustoa, jonka tietoja anonyymit käyttäjät pääsevät katsomaan.", "NoUsersExist": "Yhtään käyttäjää ei ole vielä olemassa.", + "PluginDescription": "Käyttäjähallinta antaa sinun lisätä uusia käyttäjiä, muokata olemassaolevia käyttäjiä, antaa pääsyoikeuksia sivuille ja muokata sivuja.", "PrivAdmin": "Hallinnointioikeus", "PrivNone": "Ei käyttöoikeutta", "PrivView": "Näkymä", diff --git a/plugins/VisitFrequency/lang/fi.json b/plugins/VisitFrequency/lang/fi.json index b46c8115d6..4bee78edcc 100644 --- a/plugins/VisitFrequency/lang/fi.json +++ b/plugins/VisitFrequency/lang/fi.json @@ -10,6 +10,8 @@ "ColumnReturningVisits": "Palaavat käynnit", "ColumnSumVisitLengthReturning": "Palaavien käyttäjien aika yhteensä (sekunteja)", "ColumnUniqueReturningVisitors": "Yksilölliset palaavat kävijät", + "ColumnReturningUsers": "Palaavat käyttäjät", + "PluginDescription": "Raportoi metriikat ensimmäisen kerran kävijöistä ja palaavista vierailijoista", "ReturnActions": "%s toimintoa palaavilta käyttäjiltä", "ReturnAverageVisitDuration": "%s keskimääräinen käynnin pituus palaaville kävijöille", "ReturnAvgActions": "%s toimintoa \/ palaava käynti", diff --git a/plugins/VisitTime/lang/fi.json b/plugins/VisitTime/lang/fi.json index 14e8b8856b..1efd00df94 100644 --- a/plugins/VisitTime/lang/fi.json +++ b/plugins/VisitTime/lang/fi.json @@ -5,6 +5,7 @@ "DayOfWeek": "Viikonpäivä", "LocalTime": "Käyntejä (paikallinen aika)", "NHour": "%sh", + "PluginDescription": "Raportoi palvelimen ajan ja käyttäjän paikallisen ajan käynneille.", "ServerTime": "Käyntejä (palvelimen aika)", "SubmenuTimes": "Ajat", "VisitsByDayOfWeek": "Käynnit viikonpäivän mukaan", diff --git a/plugins/VisitorInterest/lang/fi.json b/plugins/VisitorInterest/lang/fi.json index e306a04236..e196332b95 100644 --- a/plugins/VisitorInterest/lang/fi.json +++ b/plugins/VisitorInterest/lang/fi.json @@ -7,6 +7,7 @@ "Engagement": "Sitoutuminen", "NPages": "%s sivua", "OnePage": "1 sivu", + "PluginDescription": "Raportoi kävijöiden kiinnostuksen: käytyjen sivujen määrän, sivuilla vietetyn ajan, ajan edellisestä käynnistä jne.", "VisitNum": "Käynnin numero", "VisitsByDaysSinceLast": "Käynnit lajiteltuna aikavälillä edelliseen käyntiin", "visitsByVisitCount": "Käynnit käyntinumeron mukaan", diff --git a/plugins/VisitsSummary/lang/fi.json b/plugins/VisitsSummary/lang/fi.json index 4df0a1d5db..0bc92bcf03 100644 --- a/plugins/VisitsSummary/lang/fi.json +++ b/plugins/VisitsSummary/lang/fi.json @@ -17,6 +17,7 @@ "NbUniquePageviewsDescription": "%s yksilöllistä sivunavausta", "NbUniqueVisitors": "%s uniikia kävijää", "NbVisitsBounced": "%s lyhyttä käyntiä (vain yksi ladattu sivu)", + "PluginDescription": "Raportoi yleiset analytiikkametriikat: käynnit, uniikit kävijät, toimintojen määrän jne.", "VisitsSummary": "Yhteenveto käynneistä", "VisitsSummaryDocumentation": "Tämä on käyntien muutoksen yleiskatsaus", "WidgetLastVisits": "Edelliset käynnit", diff --git a/plugins/WebsiteMeasurable/lang/fi.json b/plugins/WebsiteMeasurable/lang/fi.json new file mode 100644 index 0000000000..e3c519b052 --- /dev/null +++ b/plugins/WebsiteMeasurable/lang/fi.json @@ -0,0 +1,7 @@ +{ + "WebsiteMeasurable": { + "Website": "Verkkosivu", + "Websites": "Verkkosivut", + "WebsiteDescription": "Verkkosivusto on tyypillisesti kokoelma sivuja saman verkko-osoitteen alla." + } +} \ No newline at end of file -- cgit v1.2.3 From af7ef0a0c14d7c11f3fb483c3b930a02be933a2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Subileau?= Date: Sun, 27 Mar 2016 23:08:37 +0200 Subject: Whitelists EOT to be downloadable via apache webserver fixes #9967 --- plugins/Installation/ServerFilesGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Installation/ServerFilesGenerator.php b/plugins/Installation/ServerFilesGenerator.php index 6009854544..927f403ccb 100644 --- a/plugins/Installation/ServerFilesGenerator.php +++ b/plugins/Installation/ServerFilesGenerator.php @@ -37,7 +37,7 @@ class ServerFilesGenerator "\n\n" . "# Allow to serve static files which are safe\n" . - "\n" . + "\n" . $allow . "\n" . "\n"; -- cgit v1.2.3 From ec9b9072f2db7d659b553836be7f558deb716aaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Subileau?= Date: Sun, 27 Mar 2016 23:14:31 +0200 Subject: Updates .htaccess files to whitelist EOT files refs #9967 --- core/Updates/2.16.1-b3.php | 25 +++++++++++++++++++++++++ core/Version.php | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 core/Updates/2.16.1-b3.php diff --git a/core/Updates/2.16.1-b3.php b/core/Updates/2.16.1-b3.php new file mode 100644 index 0000000000..cb46053660 --- /dev/null +++ b/core/Updates/2.16.1-b3.php @@ -0,0 +1,25 @@ + Date: Thu, 17 Mar 2016 13:13:08 +1300 Subject: fix #9896 Keep Page URL fragments when tracking Page URLs" not persistent --- core/Access.php | 13 ++- core/AssetManager.php | 13 ++- core/BaseFactory.php | 7 +- core/Twig.php | 117 +++++++++++++++++---- core/Unzip.php | 4 + core/UpdateCheck.php | 3 +- core/WidgetsList.php | 8 +- plugins/CoreHome/templates/_dataTableCell.twig | 15 ++- plugins/Live/templates/getLastVisitsStart.twig | 35 ++++-- plugins/SitesManager/Controller.php | 1 - plugins/SitesManager/Menu.php | 1 + plugins/SitesManager/Model.php | 34 +++--- .../sites-manager/multiline-field.directive.html | 1 - .../sites-manager/sites-manager-site.controller.js | 9 +- .../sites-manager/sites-manager.controller.js | 19 ++-- .../SitesManager/templates/dialogs/dialogs.html | 1 - .../templates/dialogs/edit-dialog.html | 1 - .../templates/displayJavascriptCode.twig | 1 - .../SitesManager/templates/help/timezone-help.html | 3 - plugins/SitesManager/templates/index.html | 8 -- .../SitesManager/templates/siteWithoutData.twig | 4 +- .../templates/sites-list/site-fields.html | 2 +- plugins/UsersManager/Model.php | 105 +++++++++++------- plugins/UsersManager/tests/Integration/APITest.php | 11 ++ plugins/VisitFrequency/Controller.php | 1 + 25 files changed, 288 insertions(+), 129 deletions(-) diff --git a/core/Access.php b/core/Access.php index 881810bfca..c8b9bafea0 100644 --- a/core/Access.php +++ b/core/Access.php @@ -10,6 +10,7 @@ namespace Piwik; use Exception; use Piwik\Container\StaticContainer; +use Piwik\Plugins\SitesManager\API as SitesManagerApi; /** * Singleton that manages user access to Piwik resources. @@ -145,7 +146,7 @@ class Access $this->login = null; // if the Auth wasn't set, we may be in the special case of setSuperUser(), otherwise we fail TODO: docs + review - if ($this->auth === null) { + if (!isset($this->auth)) { return false; } @@ -207,7 +208,8 @@ class Access if ($this->hasSuperUserAccess) { if (empty($this->idsitesByAccess['superuser'])) { try { - $allSitesId = Plugins\SitesManager\API::getInstance()->getAllSitesId(); + $api = SitesManagerApi::getInstance(); + $allSitesId = $api->getAllSitesId(); } catch (\Exception $e) { $allSitesId = array(); } @@ -460,17 +462,18 @@ class Access { $isSuperUser = self::getInstance()->hasSuperUserAccess(); - self::getInstance()->setSuperUserAccess(true); + $access = self::getInstance(); + $access->setSuperUserAccess(true); try { $result = $function(); } catch (Exception $ex) { - self::getInstance()->setSuperUserAccess($isSuperUser); + $access->setSuperUserAccess($isSuperUser); throw $ex; } - self::getInstance()->setSuperUserAccess($isSuperUser); + $access->setSuperUserAccess($isSuperUser); return $result; } diff --git a/core/AssetManager.php b/core/AssetManager.php index 407a2058c0..54c09515f5 100644 --- a/core/AssetManager.php +++ b/core/AssetManager.php @@ -123,7 +123,7 @@ class AssetManager extends Singleton $this->getMergedCoreJSAsset()->delete(); $this->getMergedNonCoreJSAsset()->delete(); - $result .= $this->getIndividualJsIncludes(); + $result .= $this->getIndividualCoreAndNonCoreJsIncludes(); } else { $result .= sprintf(self::JS_IMPORT_DIRECTIVE, self::GET_CORE_JS_MODULE_ACTION); $result .= sprintf(self::JS_IMPORT_DIRECTIVE, self::GET_NON_CORE_JS_MODULE_ACTION); @@ -290,7 +290,7 @@ class AssetManager extends Singleton * * @return string */ - private function getIndividualJsIncludes() + private function getIndividualCoreAndNonCoreJsIncludes() { return $this->getIndividualJsIncludesFromAssetFetcher($this->getCoreJScriptFetcher()) . @@ -305,7 +305,9 @@ class AssetManager extends Singleton { $jsIncludeString = ''; - foreach ($assetFetcher->getCatalog()->getAssets() as $jsFile) { + $assets = $assetFetcher->getCatalog()->getAssets(); + + foreach ($assets as $jsFile) { $jsFile->validateFile(); $jsIncludeString = $jsIncludeString . sprintf(self::JS_IMPORT_DIRECTIVE, $jsFile->getRelativeLocation()); } @@ -339,10 +341,11 @@ class AssetManager extends Singleton return false; } - $plugin = Manager::getInstance()->getLoadedPlugin($pluginName); + $pluginManager = Manager::getInstance(); + $plugin = $pluginManager->getLoadedPlugin($pluginName); if ($plugin->isTheme()) { - $theme = Manager::getInstance()->getTheme($pluginName); + $theme = $pluginManager->getTheme($pluginName); $javaScriptFiles = $theme->getJavaScriptFiles(); diff --git a/core/BaseFactory.php b/core/BaseFactory.php index 24425c8fee..32b4090bc2 100644 --- a/core/BaseFactory.php +++ b/core/BaseFactory.php @@ -34,13 +34,18 @@ abstract class BaseFactory $className = static::getClassNameFromClassId($classId); if (!class_exists($className)) { - Common::sendHeader('Content-Type: text/plain; charset=utf-8'); + self::sendPlainHeader(); throw new Exception(static::getInvalidClassIdExceptionMessage($classId)); } return new $className; } + private static function sendPlainHeader() + { + Common::sendHeader('Content-Type: text/plain; charset=utf-8'); + } + /** * Should return a class name based on the class's associated string ID. */ diff --git a/core/Twig.php b/core/Twig.php index c3b6ba7414..9f17e0b218 100755 --- a/core/Twig.php +++ b/core/Twig.php @@ -23,6 +23,85 @@ use Twig_SimpleFilter; use Twig_SimpleFunction; use Twig_SimpleTest; +function piwik_filter_truncate($string, $size) +{ + if (strlen($string) < $size) { + return $string; + } else { + $array = str_split($string, $size); + return array_shift($array) . "..."; + } +} + +function piwik_format_number($string, $minFractionDigits, $maxFractionDigits) +{ + $formatter = NumberFormatter::getInstance(); + return $formatter->format($string, $minFractionDigits, $maxFractionDigits); +} + +function piwik_fix_lbrace($string) +{ + $chars = array('{', '{', '{', '{', '{', '{'); + + static $search; + static $replace; + + if (!isset($search)) { + $search = array_map(function ($val) { return $val . $val; }, $chars); + } + if (!isset($replace)) { + $replace = array_map(function ($val) { return $val . '⁣' . $val; }, $chars); + } + + return str_replace($search, $replace, $string); +} + +function piwik_escape_filter(Twig_Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false) { + + $string = twig_escape_filter($env, $string, $strategy, $charset, $autoescape); + + switch ($strategy) { + case 'html': + case 'html_attr': + return piwik_fix_lbrace($string); + case 'url': + $encoded = rawurlencode('{'); + return str_replace('{{', $encoded . $encoded, $string); + case 'css': + case 'js': + default: + return $string; + } +} + +function piwik_format_money($amount, $idSite) +{ + $currencySymbol = Site::getCurrencySymbolFor($idSite); + $numberFormatter = NumberFormatter::getInstance(); + return $numberFormatter->formatCurrency($amount, $currencySymbol, GoalManager::REVENUE_PRECISION); +} + +class PiwikTwigFilterExtension extends \Twig_Extension +{ + public function getFilters() + { + return array( + new Twig_SimpleFilter('e', '\Piwik\piwik_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')), + new Twig_SimpleFilter('escape', '\Piwik\piwik_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')) + ); + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return 'escaper2'; + } +} + /** * Twig class * @@ -84,8 +163,8 @@ class Twig $this->addFilter_money(); $this->addFilter_truncate(); $this->addFilter_notification(); - $this->addFilter_percentage(); $this->addFilter_percent(); + $this->addFilter_percentage(); $this->addFilter_percentEvolution(); $this->addFilter_piwikProAdLink(); $this->addFilter_piwikProOnPremisesAdLink(); @@ -109,6 +188,8 @@ class Twig $this->addTest_false(); $this->addTest_true(); $this->addTest_emptyString(); + + $this->twig->addExtension(new PiwikTwigFilterExtension()); } private function addTest_false() @@ -287,7 +368,9 @@ class Twig $string = str_replace('+', '%2B', $string); $string = str_replace(' ', html_entity_decode(' '), $string); - return SafeDecodeLabel::decodeLabelSafe($string); + $string = SafeDecodeLabel::decodeLabelSafe($string); + + return piwik_fix_lbrace($string); }, array('is_safe' => array('all'))); $this->twig->addFilter($rawSafeDecoded); @@ -304,7 +387,8 @@ class Twig protected function addFilter_percentage() { $percentage = new Twig_SimpleFilter('percentage', function ($string, $totalValue, $precision = 1) { - return NumberFormatter::getInstance()->formatPercent(Piwik::getPercentageSafe($string, $totalValue, $precision), $precision); + $formatter = NumberFormatter::getInstance(); + return $formatter->formatPercent(Piwik::getPercentageSafe($string, $totalValue, $precision), $precision); }); $this->twig->addFilter($percentage); } @@ -312,7 +396,8 @@ class Twig protected function addFilter_percent() { $percentage = new Twig_SimpleFilter('percent', function ($string, $precision = 1) { - return NumberFormatter::getInstance()->formatPercent($string, $precision); + $formatter = NumberFormatter::getInstance(); + return $formatter->formatPercent($string, $precision); }); $this->twig->addFilter($percentage); } @@ -320,7 +405,8 @@ class Twig protected function addFilter_percentEvolution() { $percentage = new Twig_SimpleFilter('percentEvolution', function ($string) { - return NumberFormatter::getInstance()->formatPercentEvolution($string); + $formatter = NumberFormatter::getInstance(); + return $formatter->formatPercentEvolution($string); }); $this->twig->addFilter($percentage); } @@ -371,7 +457,7 @@ class Twig protected function addFilter_number() { $formatter = new Twig_SimpleFilter('number', function ($string, $minFractionDigits = 0, $maxFractionDigits = 0) { - return NumberFormatter::getInstance()->format($string, $minFractionDigits, $maxFractionDigits); + return piwik_format_number($string, $minFractionDigits, $maxFractionDigits); }); $this->twig->addFilter($formatter); } @@ -379,27 +465,20 @@ class Twig protected function addFilter_truncate() { $truncateFilter = new Twig_SimpleFilter('truncate', function ($string, $size) { - if (strlen($string) < $size) { - return $string; - } else { - $array = str_split($string, $size); - return array_shift($array) . "..."; - } + return piwik_filter_truncate($string, $size); }); $this->twig->addFilter($truncateFilter); } protected function addFilter_money() { - $formatter = $this->formatter; - $moneyFilter = new Twig_SimpleFilter('money', function ($amount) use ($formatter) { + $moneyFilter = new Twig_SimpleFilter('money', function ($amount) { if (func_num_args() != 2) { throw new Exception('the money modifier expects one parameter: the idSite.'); } $idSite = func_get_args(); $idSite = $idSite[1]; - $currencySymbol = Site::getCurrencySymbolFor($idSite); - return NumberFormatter::getInstance()->formatCurrency($amount, $currencySymbol, GoalManager::REVENUE_PRECISION); + return piwik_format_money($amount, $idSite); }); $this->twig->addFilter($moneyFilter); } @@ -445,7 +524,8 @@ class Twig private function addPluginNamespaces(Twig_Loader_Filesystem $loader) { - $plugins = \Piwik\Plugin\Manager::getInstance()->getAllPluginsNames(); + $pluginManager = \Piwik\Plugin\Manager::getInstance(); + $plugins = $pluginManager->getAllPluginsNames(); foreach ($plugins as $name) { $path = sprintf("%s/plugins/%s/templates/", PIWIK_INCLUDE_PATH, $name); if (is_dir($path)) { @@ -461,7 +541,8 @@ class Twig */ private function addCustomPluginNamespaces(Twig_Loader_Filesystem $loader, $pluginName) { - $plugins = \Piwik\Plugin\Manager::getInstance()->getAllPluginsNames(); + $pluginManager = \Piwik\Plugin\Manager::getInstance(); + $plugins = $pluginManager->getAllPluginsNames(); foreach ($plugins as $name) { $path = sprintf("%s/plugins/%s/templates/plugins/%s/", PIWIK_INCLUDE_PATH, $pluginName, $name); if (is_dir($path)) { diff --git a/core/Unzip.php b/core/Unzip.php index ffef2add15..af1c14a815 100644 --- a/core/Unzip.php +++ b/core/Unzip.php @@ -33,15 +33,19 @@ class Unzip return new ZipArchive($filename); } break; + case 'tar.gz': return new Tar($filename, 'gz'); + case 'tar.bz2': return new Tar($filename, 'bz2'); + case 'gz': if (function_exists('gzopen')) { return new Gzip($filename); } break; + case 'PclZip': default: return new PclZip($filename); diff --git a/core/UpdateCheck.php b/core/UpdateCheck.php index b176ed87c3..e2ce130c4a 100644 --- a/core/UpdateCheck.php +++ b/core/UpdateCheck.php @@ -68,7 +68,8 @@ class UpdateCheck */ private static function getLatestAvailableVersionNumber() { - $channel = StaticContainer::get('\Piwik\Plugin\ReleaseChannels')->getActiveReleaseChannel(); + $releaseChannels = StaticContainer::get('\Piwik\Plugin\ReleaseChannels'); + $channel = $releaseChannels->getActiveReleaseChannel(); $url = $channel->getUrlToCheckForLatestAvailableVersion(); try { diff --git a/core/WidgetsList.php b/core/WidgetsList.php index 8380d7a1ee..bafc94323d 100644 --- a/core/WidgetsList.php +++ b/core/WidgetsList.php @@ -71,8 +71,7 @@ class WidgetsList extends Singleton } self::addWidgets(); - - uksort(self::$widgets, array('Piwik\WidgetsList', '_sortWidgetCategories')); + self::sortWidgets(); $widgets = array(); foreach (self::$widgets as $key => $v) { @@ -91,6 +90,11 @@ class WidgetsList extends Singleton return $widgets; } + private static function sortWidgets() + { + uksort(self::$widgets, array('Piwik\WidgetsList', '_sortWidgetCategories')); + } + private static function addWidgets() { if (!self::$hookCalled) { diff --git a/plugins/CoreHome/templates/_dataTableCell.twig b/plugins/CoreHome/templates/_dataTableCell.twig index 1bcd1bb0f2..ac6b935d7c 100644 --- a/plugins/CoreHome/templates/_dataTableCell.twig +++ b/plugins/CoreHome/templates/_dataTableCell.twig @@ -2,9 +2,12 @@ {% set tooltipIndex = column ~ '_tooltip' %} {% if row.getMetadata(tooltipIndex) %}{% endif %} {% if not row.getIdSubDataTable() and column=='label' and row.getMetadata('url') %} - + {% if not row.getMetadata('logo') %} - + {% endif %} {% endif %} @@ -19,7 +22,7 @@ {% endif %} {% set rowPercentage = row.getColumn(column)|percentage(reportTotal, 1) %} {% set metricTitle = translations[column]|default(column) %} - {% set reportLabel = row.getColumn(labelColumn)|truncate(40)|raw %} + {% set reportLabel = row.getColumn(labelColumn)|truncate(40)|rawSafeDecoded %} {% set reportRatioTooltip = 'General_ReportRatioTooltip'|translate(reportLabel, rowPercentage|e('html_attr'), reportTotal|e('html_attr'), metricTitle|e('html_attr'), translations[labelColumn]|default(labelColumn)|e('html_attr')) %} @@ -30,7 +33,9 @@ {% set totalRatioTooltip = '' %} {% endif %} -  {{ rowPercentage }} +  {{ rowPercentage }} {%- endif %} {% if column=='label' %} @@ -42,7 +47,7 @@ {% if row.getMetadata('html_label_prefix') %}{{ row.getMetadata('html_label_prefix') | raw }} {% endif -%} {%- if row.getMetadata('html_label_suffix') %}{{ row.getMetadata('html_label_suffix') | raw }}{% endif -%} {% endif %} - {%- if row.getColumn(column) %}{% if column=='label' %}{{- row.getColumn(column)|raw -}}{% else %}{{- row.getColumn(column)|number(2,0)|raw -}}{% endif %} + {%- if row.getColumn(column) %}{% if column=='label' %}{{- row.getColumn(column)|rawSafeDecoded -}}{% else %}{{- row.getColumn(column)|number(2,0)|raw -}}{% endif %} {%- else -%}- {%- endif -%} {% if column=='label' %}{% endif %} diff --git a/plugins/Live/templates/getLastVisitsStart.twig b/plugins/Live/templates/getLastVisitsStart.twig index 59a4a1fb9d..064a3545ae 100644 --- a/plugins/Live/templates/getLastVisitsStart.twig +++ b/plugins/Live/templates/getLastVisitsStart.twig @@ -19,23 +19,25 @@ {% endif %}
- {% if visitor.countryFlag is defined %} {% endif %} - {% if visitor.browserIcon is defined %} {% endif %} + {% if visitor.countryFlag is defined %} {% endif %} + {% if visitor.browserIcon is defined %} {% endif %} {% if visitor.operatingSystemIcon is defined %} {% endif %}   {% if visitor.visitConverted %} - + # {{ visitor.goalConversions }} {% if visitor.visitEcommerceStatusIcon %} - + {% endif %} {% endif %} {% if visitor.visitorTypeIcon %} - + {% endif %} {% if visitor.visitIp %} @@ -46,33 +48,45 @@ {% if visitor.referrerType is defined and visitor.referrerType != 'direct' %} {{ 'General_FromReferrer'|translate }} {% if visitor.referrerUrl is not empty %} -
+ {% endif %} + {% if visitor.searchEngineIcon is defined %} {% endif %} + {{ visitor.referrerName }} + {% if visitor.referrerUrl is not empty %} {% endif %} + {% if visitor.referrerKeyword is not empty %} - "{{ visitor.referrerKeyword }}"{% endif %} + {% set keyword %}{{ visitor.referrerKeyword }}{% endset %} {% set searchName %}{{ visitor.referrerName }}{% endset %} {% set position %}#{{ visitor.referrerKeywordPosition}}{% endset %} + {% if visitor.referrerKeywordPosition is not empty %} - + # {{ visitor.referrerKeywordPosition }} {% endif %} + {% elseif visitor.referrerType is defined %} {{ 'Referrers_DirectEntry'|translate }} {% endif %} -

- {{ 'General_Actions'|translate }}:  +
+ {{ 'General_Actions'|translate }}:  {% set col = 0 %} {% for action in visitor.actionDetails %} {% if loop.index <= maxPagesDisplayedByVisitor %} + {% if action.type == 'ecommerceOrder' or action.type == 'ecommerceAbandonedCart' %} {% set title %} {%- if action.type == 'ecommerceOrder' %} @@ -104,7 +118,9 @@ {{ 'General_ColumnRevenue'|translate }}: {{ action.revenue|money(idSite)|raw }} {% endif %} + {% else %} + {% set col = col + 1 %} {% if col >= 9 %} {% set col = 0 %} @@ -136,6 +152,7 @@ {% endif %} {% endif %} {% endfor %} + {% if visitor.actionDetails|length > maxPagesDisplayedByVisitor %} ({{ 'Live_MorePagesNotDisplayed'|translate }}) {% endif %} diff --git a/plugins/SitesManager/Controller.php b/plugins/SitesManager/Controller.php index fc7b7eb6e8..d64fb45fa9 100644 --- a/plugins/SitesManager/Controller.php +++ b/plugins/SitesManager/Controller.php @@ -63,7 +63,6 @@ class Controller extends \Piwik\Plugin\ControllerAdmin $response = new ResponseBuilder(Common::getRequestVar('format')); $globalSettings = array(); - $globalSettings['keepURLFragmentsGlobal'] = API::getInstance()->getKeepURLFragmentsGlobal(); $globalSettings['siteSpecificUserAgentExcludeEnabled'] = API::getInstance()->isSiteSpecificUserAgentExcludeEnabled(); $globalSettings['defaultCurrency'] = API::getInstance()->getDefaultCurrency(); diff --git a/plugins/SitesManager/Menu.php b/plugins/SitesManager/Menu.php index a9e82e6024..d242a25351 100644 --- a/plugins/SitesManager/Menu.php +++ b/plugins/SitesManager/Menu.php @@ -44,6 +44,7 @@ class Menu extends \Piwik\Plugin\Menu if (count($types) === 1) { // only one type is in use, use this one for the wording return reset($types); + } else { // multiple types are activated, check whether only one is actually in use $model = new Model(); diff --git a/plugins/SitesManager/Model.php b/plugins/SitesManager/Model.php index 96062b608a..5e69d308e7 100644 --- a/plugins/SitesManager/Model.php +++ b/plugins/SitesManager/Model.php @@ -41,8 +41,9 @@ class Model */ public function getSitesFromGroup($group) { - $sites = $this->getDb()->fetchAll("SELECT * FROM " . $this->table . " - WHERE `group` = ?", $group); + $db = $this->getDb(); + $sites = $db->fetchAll("SELECT * FROM " . $this->table . " + WHERE `group` = ?", $group); return $sites; } @@ -55,7 +56,8 @@ class Model */ public function getSitesGroups() { - $groups = $this->getDb()->fetchAll("SELECT DISTINCT `group` FROM " . $this->table); + $db = $this->getDb(); + $groups = $db->fetchAll("SELECT DISTINCT `group` FROM " . $this->table); $cleanedGroups = array(); foreach ($groups as $group) { @@ -72,7 +74,8 @@ class Model */ public function getAllSites() { - $sites = $this->getDb()->fetchAll("SELECT * FROM " . $this->table . " ORDER BY idsite ASC"); + $db = $this->getDb(); + $sites = $db->fetchAll("SELECT * FROM " . $this->table . " ORDER BY idsite ASC"); return $sites; } @@ -111,7 +114,8 @@ class Model { $siteUrlTable = Common::prefixTable('site_url'); - $ids = $this->getDb()->fetchAll( + $db = $this->getDb(); + $ids = $db->fetchAll( 'SELECT idsite FROM ' . $this->table . ' WHERE main_url IN ( ' . Common::getSqlStringFieldsArray($urls) . ') ' . 'UNION @@ -137,7 +141,8 @@ class Model $siteUrlTable = Common::prefixTable('site_url'); $sqlAccessSite = Access::getSqlAccessSite('idsite'); - $ids = $this->getDb()->fetchAll( + $db = $this->getDb(); + $ids = $db->fetchAll( 'SELECT idsite FROM ' . $this->table . ' WHERE main_url IN ( ' . Common::getSqlStringFieldsArray($urls) . ')' . @@ -171,7 +176,8 @@ class Model $query = 'SELECT idsite FROM ' . $this->table . ' WHERE timezone IN (' . Common::getSqlStringFieldsArray($timezones) . ') ORDER BY idsite ASC'; - $sites = $this->getDb()->fetchAll($query, $timezones); + $db = $this->getDb(); + $sites = $db->fetchAll($query, $timezones); return $sites; } @@ -223,8 +229,9 @@ class Model */ public function getSiteFromId($idSite) { - $site = $this->getDb()->fetchRow("SELECT * FROM " . $this->table . " - WHERE idsite = ?", $idSite); + $db = $this->getDb(); + $site = $db->fetchRow("SELECT * FROM " . $this->table . " + WHERE idsite = ?", $idSite); return $site; } @@ -237,7 +244,7 @@ class Model */ public function getSitesId() { - $result = Db::fetchAll("SELECT idsite FROM " . Common::prefixTable('site')); + $result = Db::fetchAll("SELECT idsite FROM " . Common::prefixTable('site')); $idSites = array(); foreach ($result as $idSite) { @@ -277,7 +284,8 @@ class Model { $db = $this->getDb(); $result = $db->fetchAll("SELECT url FROM " . Common::prefixTable("site_url") . " - WHERE idsite = ?", $idSite); + WHERE idsite = ?", $idSite); + $urls = array(); foreach ($result as $url) { $urls[] = $url['url']; @@ -354,7 +362,9 @@ class Model public function getUsedTypeIds() { $types = array(); - $rows = $this->getDb()->fetchAll("SELECT DISTINCT `type` as typeid FROM " . $this->table); + + $db = $this->getDb(); + $rows = $db->fetchAll("SELECT DISTINCT `type` as typeid FROM " . $this->table); foreach ($rows as $row) { $types[] = $row['typeid']; diff --git a/plugins/SitesManager/angularjs/sites-manager/multiline-field.directive.html b/plugins/SitesManager/angularjs/sites-manager/multiline-field.directive.html index fed8822dc1..2e1bf44bf7 100644 --- a/plugins/SitesManager/angularjs/sites-manager/multiline-field.directive.html +++ b/plugins/SitesManager/angularjs/sites-manager/multiline-field.directive.html @@ -3,5 +3,4 @@ rows="{{ rows }}" ng-model="field.value" ng-change="onChange()"> - diff --git a/plugins/SitesManager/angularjs/sites-manager/sites-manager-site.controller.js b/plugins/SitesManager/angularjs/sites-manager/sites-manager-site.controller.js index d759ec940f..0fac17cc22 100644 --- a/plugins/SitesManager/angularjs/sites-manager/sites-manager-site.controller.js +++ b/plugins/SitesManager/angularjs/sites-manager/sites-manager-site.controller.js @@ -135,22 +135,25 @@ "http://siteUrl2.com/" ]; $scope.site.exclude_unknown_urls = 0; - $scope.site.keep_url_fragment = "0"; + $scope.site.keep_url_fragment = 0; $scope.site.excluded_ips = []; $scope.site.excluded_parameters = []; $scope.site.excluded_user_agents = []; $scope.site.sitesearch_keyword_parameters = []; $scope.site.sitesearch_category_parameters = []; - $scope.site.sitesearch = $scope.globalSettings.searchKeywordParametersGlobal.length ? "1" : "0"; + $scope.site.sitesearch = $scope.globalSettings.searchKeywordParametersGlobal.length ? 1 : 0; $scope.site.timezone = $scope.globalSettings.defaultTimezone; $scope.site.currency = $scope.globalSettings.defaultCurrency; - $scope.site.ecommerce = "0"; + $scope.site.ecommerce = 0; updateSiteWithSiteSearchConfig(); }; var initExistingSite = function() { + $scope.site.keep_url_fragment = parseInt($scope.site.keep_url_fragment, 10); + $scope.site.ecommerce = parseInt($scope.site.ecommerce, 10); + $scope.site.sitesearch = parseInt($scope.site.sitesearch, 10); $scope.site.excluded_ips = sitesManagerApiHelper.commaDelimitedFieldToArray($scope.site.excluded_ips); $scope.site.excluded_parameters = sitesManagerApiHelper.commaDelimitedFieldToArray($scope.site.excluded_parameters); $scope.site.excluded_user_agents = sitesManagerApiHelper.commaDelimitedFieldToArray($scope.site.excluded_user_agents); diff --git a/plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js b/plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js index 100e75bbf7..9860667e71 100644 --- a/plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js +++ b/plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js @@ -118,8 +118,8 @@ var initEcommerceSelectOptions = function() { $scope.eCommerceptions = [ - {key: '0', value: translate('SitesManager_NotAnEcommerceSite')}, - {key: '1', value: translate('SitesManager_EnableEcommerce')} + {key: 0, value: translate('SitesManager_NotAnEcommerceSite')}, + {key: 1, value: translate('SitesManager_EnableEcommerce')} ]; }; @@ -189,18 +189,17 @@ var initSiteSearchSelectOptions = function() { $scope.siteSearchOptions = [ - {key: '1', value: translate('SitesManager_EnableSiteSearch')}, - {key: '0', value: translate('SitesManager_DisableSiteSearch')} + {key: 1, value: translate('SitesManager_EnableSiteSearch')}, + {key: 0, value: translate('SitesManager_DisableSiteSearch')} ]; }; var initKeepURLFragmentsList = function() { - - $scope.keepURLFragmentsOptions = { - 0: ($scope.globalSettings.keepURLFragmentsGlobal ? translate('General_Yes') : translate('General_No')) + ' (' + translate('General_Default') + ')', - 1: translate('General_Yes'), - 2: translate('General_No') - }; + $scope.keepURLFragmentsOptions = [ + {key: 0, value: ($scope.globalSettings.keepURLFragmentsGlobal ? translate('General_Yes') : translate('General_No')) + ' (' + translate('General_Default') + ')'}, + {key: 1, value: translate('General_Yes')}, + {key: 2, value: translate('General_No')} + ]; }; var addNewEntity = function () { diff --git a/plugins/SitesManager/templates/dialogs/dialogs.html b/plugins/SitesManager/templates/dialogs/dialogs.html index 476505e7bf..2f3d5d8072 100644 --- a/plugins/SitesManager/templates/dialogs/dialogs.html +++ b/plugins/SitesManager/templates/dialogs/dialogs.html @@ -1,3 +1,2 @@
-
diff --git a/plugins/SitesManager/templates/dialogs/edit-dialog.html b/plugins/SitesManager/templates/dialogs/edit-dialog.html index afb9910869..1bb6067f47 100644 --- a/plugins/SitesManager/templates/dialogs/edit-dialog.html +++ b/plugins/SitesManager/templates/dialogs/edit-dialog.html @@ -1,5 +1,4 @@
-

{{ site.editDialog.title }}

diff --git a/plugins/SitesManager/templates/displayJavascriptCode.twig b/plugins/SitesManager/templates/displayJavascriptCode.twig index 9b514b69c0..05d867030e 100644 --- a/plugins/SitesManager/templates/displayJavascriptCode.twig +++ b/plugins/SitesManager/templates/displayJavascriptCode.twig @@ -1,6 +1,5 @@ {% extends 'admin.twig' %} {% block content %} - {% include "@SitesManager/_displayJavascriptCode.twig" %} {% endblock %} \ No newline at end of file diff --git a/plugins/SitesManager/templates/help/timezone-help.html b/plugins/SitesManager/templates/help/timezone-help.html index 0308b783b5..f77ad7863e 100644 --- a/plugins/SitesManager/templates/help/timezone-help.html +++ b/plugins/SitesManager/templates/help/timezone-help.html @@ -9,10 +9,7 @@
- {{ 'SitesManager_UTCTimeIs'| translate : (utcTime | date : 'yyyy-MM-dd HH:mm:ss') }} -
- {{ 'SitesManager_ChangingYourTimezoneWillOnlyAffectDataForward'|translate }}
diff --git a/plugins/SitesManager/templates/index.html b/plugins/SitesManager/templates/index.html index cfdca4a970..adedf3e644 100644 --- a/plugins/SitesManager/templates/index.html +++ b/plugins/SitesManager/templates/index.html @@ -1,17 +1,9 @@
-
-
-
-
-
-
-
-
diff --git a/plugins/SitesManager/templates/siteWithoutData.twig b/plugins/SitesManager/templates/siteWithoutData.twig index 498d2ee765..b1a659f31a 100644 --- a/plugins/SitesManager/templates/siteWithoutData.twig +++ b/plugins/SitesManager/templates/siteWithoutData.twig @@ -33,7 +33,7 @@ {{ 'SitesManager_SiteWithoutDataSetupTracking'|translate('', '')|raw }} + }) ~ '">', "")|raw }}

@@ -41,7 +41,7 @@ {{ 'SitesManager_SiteWithoutDataSetupGoals'|translate('', '')|raw }} + }) ~ '">', "")|raw }}

{{ trackingHelp|raw }} diff --git a/plugins/SitesManager/templates/sites-list/site-fields.html b/plugins/SitesManager/templates/sites-list/site-fields.html index 200e935e27..2f0eaa7b76 100644 --- a/plugins/SitesManager/templates/sites-list/site-fields.html +++ b/plugins/SitesManager/templates/sites-list/site-fields.html @@ -94,7 +94,7 @@
-
diff --git a/plugins/UsersManager/Model.php b/plugins/UsersManager/Model.php index e6c0971867..db0285eab6 100644 --- a/plugins/UsersManager/Model.php +++ b/plugins/UsersManager/Model.php @@ -50,9 +50,10 @@ class Model $bind = $userLogins; } - $users = $this->getDb()->fetchAll("SELECT * FROM " . $this->table . " - $where - ORDER BY login ASC", $bind); + $db = $this->getDb(); + $users = $db->fetchAll("SELECT * FROM " . $this->table . " + $where + ORDER BY login ASC", $bind); return $users; } @@ -64,7 +65,8 @@ class Model */ public function getUsersLogin() { - $users = $this->getDb()->fetchAll("SELECT login FROM " . $this->table . " ORDER BY login ASC"); + $db = $this->getDb(); + $users = $db->fetchAll("SELECT login FROM " . $this->table . " ORDER BY login ASC"); $return = array(); foreach ($users as $login) { @@ -76,9 +78,10 @@ class Model public function getUsersSitesFromAccess($access) { - $users = $this->getDb()->fetchAll("SELECT login,idsite FROM " . Common::prefixTable("access") - . " WHERE access = ? - ORDER BY login, idsite", $access); + $db = $this->getDb(); + $users = $db->fetchAll("SELECT login,idsite FROM " . Common::prefixTable("access") + . " WHERE access = ? + ORDER BY login, idsite", $access); $return = array(); foreach ($users as $user) { @@ -90,8 +93,9 @@ class Model public function getUsersAccessFromSite($idSite) { - $users = $this->getDb()->fetchAll("SELECT login,access FROM " . Common::prefixTable("access") - . " WHERE idsite = ?", $idSite); + $db = $this->getDb(); + $users = $db->fetchAll("SELECT login,access FROM " . Common::prefixTable("access") + . " WHERE idsite = ?", $idSite); $return = array(); foreach ($users as $user) { @@ -103,7 +107,8 @@ class Model public function getUsersLoginWithSiteAccess($idSite, $access) { - $users = $this->getDb()->fetchAll("SELECT login + $db = $this->getDb(); + $users = $db->fetchAll("SELECT login FROM " . Common::prefixTable("access") . " WHERE idsite = ? AND access = ?", array($idSite, $access)); @@ -133,7 +138,8 @@ class Model */ public function getSitesAccessFromUser($userLogin) { - $users = $this->getDb()->fetchAll("SELECT idsite,access FROM " . Common::prefixTable("access") + $db = $this->getDb(); + $users = $db->fetchAll("SELECT idsite,access FROM " . Common::prefixTable("access") . " WHERE login = ?", $userLogin); $return = array(); @@ -167,12 +173,14 @@ class Model public function getUserByEmail($userEmail) { - return $this->getDb()->fetchRow("SELECT * FROM " . $this->table . " WHERE email = ?", $userEmail); + $db = $this->getDb(); + return $db->fetchRow("SELECT * FROM " . $this->table . " WHERE email = ?", $userEmail); } public function getUserByTokenAuth($tokenAuth) { - return $this->getDb()->fetchRow('SELECT * FROM ' . $this->table . ' WHERE token_auth = ?', $tokenAuth); + $db = $this->getDb(); + return $db->fetchRow('SELECT * FROM ' . $this->table . ' WHERE token_auth = ?', $tokenAuth); } public function addUser($userLogin, $passwordTransformed, $email, $alias, $tokenAuth, $dateRegistered) @@ -187,17 +195,31 @@ class Model 'superuser_access' => 0 ); - $this->getDb()->insert($this->table, $user); + $db = $this->getDb(); + $db->insert($this->table, $user); } public function setSuperUserAccess($userLogin, $hasSuperUserAccess) { - $this->getDb()->update($this->table, - array( - 'superuser_access' => $hasSuperUserAccess ? 1 : 0 - ), - "login = '$userLogin'" - ); + $this->updateUserFields($userLogin, array( + 'superuser_access' => $hasSuperUserAccess ? 1 : 0 + )); + } + + private function updateUserFields($userLogin, $fields) + { + $set = array(); + $bind = array(); + + foreach ($fields as $key => $val) { + $set[] = "`$key` = ?"; + $bind[] = $val; + } + + $bind[] = $userLogin; + + $db = $this->getDb(); + $db->query(sprintf('UPDATE `%s` SET %s WHERE `login` = ?', $this->table, implode(', ', $set)), $bind); } /** @@ -207,45 +229,47 @@ class Model */ public function getUsersHavingSuperUserAccess() { - $users = $this->getDb()->fetchAll("SELECT login, email, token_auth - FROM " . Common::prefixTable("user") . " - WHERE superuser_access = 1 - ORDER BY date_registered ASC"); + $db = $this->getDb(); + $users = $db->fetchAll("SELECT login, email, token_auth + FROM " . Common::prefixTable("user") . " + WHERE superuser_access = 1 + ORDER BY date_registered ASC"); return $users; } public function updateUser($userLogin, $password, $email, $alias, $tokenAuth) { - $this->getDb()->update($this->table, - array( - 'password' => $password, - 'alias' => $alias, - 'email' => $email, - 'token_auth' => $tokenAuth - ), - "login = '$userLogin'" - ); + $this->updateUserFields($userLogin, array( + 'password' => $password, + 'alias' => $alias, + 'email' => $email, + 'token_auth' => $tokenAuth + )); } public function userExists($userLogin) { - $count = $this->getDb()->fetchOne("SELECT count(*) FROM " . $this->table . " WHERE login = ?", $userLogin); + $db = $this->getDb(); + $count = $db->fetchOne("SELECT count(*) FROM " . $this->table . " WHERE login = ?", $userLogin); return $count != 0; } public function userEmailExists($userEmail) { - $count = $this->getDb()->fetchOne("SELECT count(*) FROM " . $this->table . " WHERE email = ?", $userEmail); + $db = $this->getDb(); + $count = $db->fetchOne("SELECT count(*) FROM " . $this->table . " WHERE email = ?", $userEmail); return $count != 0; } public function addUserAccess($userLogin, $access, $idSites) { + $db = $this->getDb(); + foreach ($idSites as $idsite) { - $this->getDb()->insert(Common::prefixTable("access"), + $db->insert(Common::prefixTable("access"), array("idsite" => $idsite, "login" => $userLogin, "access" => $access) @@ -255,7 +279,8 @@ class Model public function deleteUserOnly($userLogin) { - $this->getDb()->query("DELETE FROM " . $this->table . " WHERE login = ?", $userLogin); + $db = $this->getDb(); + $db->query("DELETE FROM " . $this->table . " WHERE login = ?", $userLogin); /** * Triggered after a user has been deleted. @@ -270,13 +295,15 @@ class Model public function deleteUserAccess($userLogin, $idSites = null) { + $db = $this->getDb(); + if (is_null($idSites)) { - $this->getDb()->query("DELETE FROM " . Common::prefixTable("access") . + $db->query("DELETE FROM " . Common::prefixTable("access") . " WHERE login = ?", array($userLogin)); } else { foreach ($idSites as $idsite) { - $this->getDb()->query("DELETE FROM " . Common::prefixTable("access") . + $db->query("DELETE FROM " . Common::prefixTable("access") . " WHERE idsite = ? AND login = ?", array($idsite, $userLogin) ); diff --git a/plugins/UsersManager/tests/Integration/APITest.php b/plugins/UsersManager/tests/Integration/APITest.php index f7ab746ce6..892deedc58 100644 --- a/plugins/UsersManager/tests/Integration/APITest.php +++ b/plugins/UsersManager/tests/Integration/APITest.php @@ -178,6 +178,17 @@ class APITest extends IntegrationTestCase $this->api->setUserPreference($user2, 'ohOH_myPreferenceName', 'valueForUser2'); } + public function test_updateUser() + { + $this->api->updateUser($this->login, 'newPassword', 'email@example.com', 'newAlias', false); + + $user = $this->api->getUser($this->login); + + $this->assertSame('14a88b9d2f52c55b5fbcf9c5d9c11875', $user['password']); + $this->assertSame('email@example.com', $user['email']); + $this->assertSame('newAlias', $user['alias']); + } + public function test_getSitesAccessFromUser_forSuperUser() { $user2 = 'userLogin2'; diff --git a/plugins/VisitFrequency/Controller.php b/plugins/VisitFrequency/Controller.php index e1279206fd..da3c9e461b 100644 --- a/plugins/VisitFrequency/Controller.php +++ b/plugins/VisitFrequency/Controller.php @@ -76,6 +76,7 @@ class Controller extends \Piwik\Plugin\Controller ); $period = Common::getRequestVar('period', false); + if ($period == 'day') { // add number of unique (returning) visitors for period=day $selectableColumns = array_merge( -- cgit v1.2.3 From 0ac1279792b10eafc50ef96b4474a86d1c840333 Mon Sep 17 00:00:00 2001 From: Thomas Steur Date: Tue, 29 Mar 2016 05:06:54 +0000 Subject: refs #9954 attach request only if a request url is actually set --- js/piwik.js | 4 +++- piwik.js | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/js/piwik.js b/js/piwik.js index cd00196bd2..c5597236c5 100644 --- a/js/piwik.js +++ b/js/piwik.js @@ -4497,7 +4497,9 @@ if (typeof window.Piwik !== 'object') { 'contentImpressions' ); - requests.push(request); + if (request) { + requests.push(request); + } } return requests; diff --git a/piwik.js b/piwik.js index 550e6053ab..ea1ba111d0 100644 --- a/piwik.js +++ b/piwik.js @@ -49,9 +49,9 @@ if(!B(cJ[6])){cJ[6]=""}var cI=cJ[6];return{newVisitor:cF,uuid:cG,createTs:cD,vis }function aB(cC){return(am&&cC&&0===String(cC).indexOf(am))}function bZ(cG,cC,cH,cD){if(aB(cC)){return 0}var cF=aG(bj,"download"),cE=aG(aN,"link"),cI=new RegExp("\\.("+cs.join("|")+")([?&#]|$)","i");if(cE.test(cG)){return"link"}if(cD||cF.test(cG)||cI.test(cC)){return"download"}if(cH){return 0}return"link"}function ag(cD){var cC;cC=cD.parentNode;while(cC!==null&&B(cC)){if(W.isLinkElement(cD)){break}cD=cC;cC=cD.parentNode}return cD}function cw(cH){cH=ag(cH);if(!W.hasNodeAttribute(cH,"href")){return}if(!B(cH.href)){return}var cG=W.getAttributeValueFromNode(cH,"href");if(aB(cG)){return}var cD=cH.pathname||bR(cH.href);var cI=cH.hostname||c(cH.href);var cJ=cI.toLowerCase();var cE=cH.href.replace(cI,cJ);var cF=new RegExp("^(javascript|vbscript|jscript|mocha|livescript|ecmascript|mailto|tel):","i");if(!cF.test(cE)){var cC=bZ(cH.className,cE,af(cJ,cD),W.hasNodeAttribute(cH,"download"));if(cC){return{type:cC,href:cE}}}}function aw(cC,cD,cE,cF){var cG=p.buildInteractionRequestParams(cC,cD,cE,cF);if(!cG){return }return bY(cG,null,"contentInteraction")}function cc(cE,cF,cJ,cC,cD){if(!B(cE)){return}if(aB(cE)){return cE}var cH=p.toAbsoluteUrl(cE);var cG="redirecturl="+n(cH)+"&";cG+=aw(cF,cJ,cC,(cD||cE));var cI="&";if(am.indexOf("?")<0){cI="?"}return am+cI+cG}function aR(cC,cD){if(!cC||!cD){return false}var cE=p.findTargetNode(cC);if(p.shouldIgnoreInteraction(cE)){return false}cE=p.findTargetNodeNoDefault(cC);if(cE&&!N(cE,cD)){return false}return true}function b0(cE,cD,cG){if(!cE){return}var cC=p.findParentContentNode(cE);if(!cC){return}if(!aR(cC,cE)){return}var cF=p.buildContentBlock(cC);if(!cF){return}if(!cF.target&&cG){cF.target=cG}return p.buildInteractionRequestParams(cD,cF.name,cF.piece,cF.target)}function aD(cD){if(!bH||!bH.length){return false}var cC,cE;for(cC=0;cC0){cG=parseInt(cG,10);cJ(cG)}})}function aO(cG,cI){var cH=bR(cG);var cF=bR(cI);if(!cH||cH==="/"||!cF||cF==="/"){return}var cE=D(cG);if(af(cE,"/")){return}if(J(cH,"/")){cH=e(cH,1)}var cJ=cH.split("/");var cD;for(cD=2;cD Date: Tue, 29 Mar 2016 07:14:17 +0000 Subject: fix missing whitespace between parameters in help text when using archive.php on cli --- misc/cron/archive.php | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/misc/cron/archive.php b/misc/cron/archive.php index f719a2d3d4..5410ed7a1f 100644 --- a/misc/cron/archive.php +++ b/misc/cron/archive.php @@ -22,18 +22,15 @@ define('PIWIK_ENABLE_SESSION_START', false); require_once PIWIK_INCLUDE_PATH . '/core/Common.php'; -if (!empty($_SERVER['argv'][0])) { - $callee = $_SERVER['argv'][0]; -} else { - $callee = ''; -} +if (Piwik\Common::isPhpCliMode()) { + $script = array_shift($_SERVER['argv']); + $args = implode(' ', $_SERVER['argv']); -if (false !== strpos($callee, 'archive.php')) { $piwikHome = PIWIK_INCLUDE_PATH; echo " ------------------------------------------------------- Using this 'archive.php' script is no longer recommended. -Please use '/path/to/php $piwikHome/console core:archive " . implode('', array_slice($_SERVER['argv'], 1)) . "' instead. +Please use '/path/to/php $piwikHome/console core:archive " . $args . "' instead. To get help use '/path/to/php $piwikHome/console core:archive --help' See also: http://piwik.org/docs/setup-auto-archiving/ @@ -41,16 +38,12 @@ If you cannot use the console because it requires CLI try 'php archive.php --url=http://your.piwik/path' ------------------------------------------------------- \n\n"; -} - -if (Piwik\Common::isPhpCliMode()) { require_once PIWIK_INCLUDE_PATH . "/core/bootstrap.php"; $console = new Piwik\Console(); // manipulate command line arguments so CoreArchiver command will be executed - $script = array_shift($_SERVER['argv']); array_unshift($_SERVER['argv'], 'core:archive'); array_unshift($_SERVER['argv'], $script); -- cgit v1.2.3 From 62bafef4f2ecef3b33b049531f68fa0a108d4cc2 Mon Sep 17 00:00:00 2001 From: Thomas Steur Date: Tue, 29 Mar 2016 07:39:28 +0000 Subject: fix tests by making sure it works with cgi --- misc/cron/archive.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/misc/cron/archive.php b/misc/cron/archive.php index 5410ed7a1f..0bc4daa1f1 100644 --- a/misc/cron/archive.php +++ b/misc/cron/archive.php @@ -23,14 +23,18 @@ define('PIWIK_ENABLE_SESSION_START', false); require_once PIWIK_INCLUDE_PATH . '/core/Common.php'; if (Piwik\Common::isPhpCliMode()) { - $script = array_shift($_SERVER['argv']); - $args = implode(' ', $_SERVER['argv']); + require_once PIWIK_INCLUDE_PATH . "/core/bootstrap.php"; + + $console = new Piwik\Console(); + // manipulate command line arguments so CoreArchiver command will be executed + $script = array_shift($_SERVER['argv']); $piwikHome = PIWIK_INCLUDE_PATH; + echo " ------------------------------------------------------- Using this 'archive.php' script is no longer recommended. -Please use '/path/to/php $piwikHome/console core:archive " . $args . "' instead. +Please use '/path/to/php $piwikHome/console core:archive " . implode(' ', $_SERVER['argv']) . "' instead. To get help use '/path/to/php $piwikHome/console core:archive --help' See also: http://piwik.org/docs/setup-auto-archiving/ @@ -39,11 +43,6 @@ try 'php archive.php --url=http://your.piwik/path' ------------------------------------------------------- \n\n"; - require_once PIWIK_INCLUDE_PATH . "/core/bootstrap.php"; - - $console = new Piwik\Console(); - - // manipulate command line arguments so CoreArchiver command will be executed array_unshift($_SERVER['argv'], 'core:archive'); array_unshift($_SERVER['argv'], $script); -- cgit v1.2.3 From 6a5d6728793b0d758d2ae2c1f6d5da690782c49f Mon Sep 17 00:00:00 2001 From: sgiehl Date: Tue, 22 Mar 2016 23:15:21 +0100 Subject: Display message why no reports are shown if there are no conversions --- plugins/Goals/lang/en.json | 1 + plugins/Goals/templates/getGoalReportView.twig | 16 +++++++++------- plugins/Goals/templates/getOverviewView.twig | 6 ++++-- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/plugins/Goals/lang/en.json b/plugins/Goals/lang/en.json index dc485c94d8..4aefc3e34b 100644 --- a/plugins/Goals/lang/en.json +++ b/plugins/Goals/lang/en.json @@ -77,6 +77,7 @@ "NewGoalIntro": "Goal Conversion tracking is one of the most efficient ways to measure and improve your business objectives.", "NewVisitorsConversionRateIs": "New visitors conversion rate is %s", "NoGoalsNeedAccess": "Only an Administrator or a user with Super User access can manage Goals for a given website. Please ask your Piwik administrator to set up a Goal for your website.
Tracking Goals is a great way to help understand and maximize your website performance!", + "NoConversionsNoReportsMessage": "Reports are not displayed because there is no conversion data for the selected goal and period.", "NeedAccess": "Only an Administrator or a user with Super User access can manage Goals for a given website.", "Optional": "(optional)", "OverallConversionRate": "%s overall conversion rate (visits with a completed goal)", diff --git a/plugins/Goals/templates/getGoalReportView.twig b/plugins/Goals/templates/getGoalReportView.twig index 3d69cb3f5b..411b7277b0 100644 --- a/plugins/Goals/templates/getGoalReportView.twig +++ b/plugins/Goals/templates/getGoalReportView.twig @@ -57,14 +57,16 @@ {% if displayFullReport %} +

+ {% if idGoal is defined %} + {{ 'Goals_GoalConversionsBy'|translate(goalName) }} + {% else %} + {{ 'Goals_ConversionsOverviewBy'|translate }} + {% endif %} +

{% if nb_conversions > 0 or cart_nb_conversions is defined %} -

- {% if idGoal is defined %} - {{ 'Goals_GoalConversionsBy'|translate(goalName) }} - {% else %} - {{ 'Goals_ConversionsOverviewBy'|translate }} - {% endif %} -

{{ goalReportsByDimension|raw }} + {% else %} +

{{ 'Goals_NoConversionsNoReportsMessage'|translate }}

{% endif %} {% endif %} diff --git a/plugins/Goals/templates/getOverviewView.twig b/plugins/Goals/templates/getOverviewView.twig index ce828a8b54..2581742441 100644 --- a/plugins/Goals/templates/getOverviewView.twig +++ b/plugins/Goals/templates/getOverviewView.twig @@ -45,7 +45,6 @@ {% endfor %} {% if displayFullReport %} - {% if sum_nb_conversions != 0 %}

{% if idGoal is defined %} {{ 'Goals_GoalConversionsBy'|translate(goalName) }} @@ -53,6 +52,9 @@ {{ 'Goals_ConversionsOverviewBy'|translate }} {% endif %}

- {{ goalReportsByDimension|raw }} + {% if sum_nb_conversions != 0 %} + {{ goalReportsByDimension|raw }} + {% else %} +

{{ 'Goals_NoConversionsNoReportsMessage'|translate }}

{% endif %} {% endif %} -- cgit v1.2.3 From 951dbcba07571b9864e34626f57729bc6b0af154 Mon Sep 17 00:00:00 2001 From: mattab Date: Wed, 30 Mar 2016 15:04:35 +1300 Subject: Fix the integration test, until next time - Refs #9977 --- libs/Zend/Validate/Hostname.php | 250 ++++++++++++----------- tests/PHPUnit/Integration/EmailValidatorTest.php | 4 +- 2 files changed, 129 insertions(+), 125 deletions(-) diff --git a/libs/Zend/Validate/Hostname.php b/libs/Zend/Validate/Hostname.php index 5dc6e818d7..49e72dd1aa 100644 --- a/libs/Zend/Validate/Hostname.php +++ b/libs/Zend/Validate/Hostname.php @@ -57,6 +57,7 @@ class Zend_Validate_Hostname extends Zend_Validate_Abstract const LOCAL_NAME_NOT_ALLOWED = 'hostnameLocalNameNotAllowed'; const UNDECIPHERABLE_TLD = 'hostnameUndecipherableTld'; const UNKNOWN_TLD = 'hostnameUnknownTld'; + const VALID_UNICODE_DOMAIN = '/^[\p{L}\p{M}]{1,63}$/iu'; /** * @var array @@ -363,130 +364,131 @@ class Zend_Validate_Hostname extends Zend_Validate_Abstract '中国' => 'Hostname/Cn.php', '公司' => 'Hostname/Cn.php', '网络' => 'Hostname/Cn.php', - 'कॉम' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'セール' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '佛山' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '慈善' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '集团' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '在线' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '한국' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '点看' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'คอม' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'ভারত' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '八卦' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'موقع' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '公益' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '公司' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '移动' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '我爱你' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'москва' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'қаз' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'онлайн' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'сайт' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '联通' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'срб' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'бел' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'קום' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '时尚' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '淡马锡' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'ファッション' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'орг' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'नेट' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'ストア' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '삼성' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'சிங்கப்பூர்' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '商标' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '商店' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '商城' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'дети' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'мкд' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'ею' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'ポイント' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '新闻' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '工行' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'كوم' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '中文网' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '中信' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '中国' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '中國' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '娱乐' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '谷歌' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'భారత్' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'ලංකා' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '购物' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'クラウド' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'ભારત' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'भारत' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '网店' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'संगठन' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '餐厅' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '网络' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'ком' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'укр' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '香港' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '诺基亚' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '食品' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '飞利浦' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '台湾' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '台灣' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '手表' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '手机' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'мон' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'الجزائر' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'عمان' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'ارامكو' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'ایران' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'امارات' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'بازار' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'الاردن' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'موبايلي' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'بھارت' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'المغرب' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'السعودية' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'سودان' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'همراه' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'عراق' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'مليسيا' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '澳門' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '닷컴' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '政府' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'شبكة' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'بيتك' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'გე' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '机构' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '组织机构' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '健康' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'ไทย' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'سورية' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'рус' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'рф' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '珠宝' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'تونس' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '大拿' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'みんな' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'グーグル' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'ελ' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '世界' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '書籍' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'ਭਾਰਤ' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '网址' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '닷넷' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'コム' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '游戏' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'VERMöGENSBERATER' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'VERMöGENSBERATUNG' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '企业' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '信息' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '嘉里大酒店' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'مصر' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'قطر' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '广东' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'இலங்கை' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'இந்தியா' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'հայ' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '新加坡' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - 'فلسطين' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu'), - '政务' => array(1 => '/^[\p{L}\p{M}]{1,63}$/iu') + 'कॉम' => array(1 => self::VALID_UNICODE_DOMAIN), + 'セール' => array(1 => self::VALID_UNICODE_DOMAIN), + '佛山' => array(1 => self::VALID_UNICODE_DOMAIN), + '慈善' => array(1 => self::VALID_UNICODE_DOMAIN), + '集团' => array(1 => self::VALID_UNICODE_DOMAIN), + '在线' => array(1 => self::VALID_UNICODE_DOMAIN), + '한국' => array(1 => self::VALID_UNICODE_DOMAIN), + '点看' => array(1 => self::VALID_UNICODE_DOMAIN), + 'คอม' => array(1 => self::VALID_UNICODE_DOMAIN), + 'ভারত' => array(1 => self::VALID_UNICODE_DOMAIN), + '八卦' => array(1 => self::VALID_UNICODE_DOMAIN), + 'موقع' => array(1 => self::VALID_UNICODE_DOMAIN), + '公益' => array(1 => self::VALID_UNICODE_DOMAIN), + '公司' => array(1 => self::VALID_UNICODE_DOMAIN), + '移动' => array(1 => self::VALID_UNICODE_DOMAIN), + '我爱你' => array(1 => self::VALID_UNICODE_DOMAIN), + 'москва' => array(1 => self::VALID_UNICODE_DOMAIN), + 'қаз' => array(1 => self::VALID_UNICODE_DOMAIN), + 'онлайн' => array(1 => self::VALID_UNICODE_DOMAIN), + 'сайт' => array(1 => self::VALID_UNICODE_DOMAIN), + '联通' => array(1 => self::VALID_UNICODE_DOMAIN), + 'срб' => array(1 => self::VALID_UNICODE_DOMAIN), + 'бел' => array(1 => self::VALID_UNICODE_DOMAIN), + 'קום' => array(1 => self::VALID_UNICODE_DOMAIN), + '时尚' => array(1 => self::VALID_UNICODE_DOMAIN), + '淡马锡' => array(1 => self::VALID_UNICODE_DOMAIN), + 'ファッション' => array(1 => self::VALID_UNICODE_DOMAIN), + 'орг' => array(1 => self::VALID_UNICODE_DOMAIN), + 'नेट' => array(1 => self::VALID_UNICODE_DOMAIN), + 'ストア' => array(1 => self::VALID_UNICODE_DOMAIN), + '삼성' => array(1 => self::VALID_UNICODE_DOMAIN), + 'சிங்கப்பூர்' => array(1 => self::VALID_UNICODE_DOMAIN), + '商标' => array(1 => self::VALID_UNICODE_DOMAIN), + '商店' => array(1 => self::VALID_UNICODE_DOMAIN), + '商城' => array(1 => self::VALID_UNICODE_DOMAIN), + 'дети' => array(1 => self::VALID_UNICODE_DOMAIN), + 'мкд' => array(1 => self::VALID_UNICODE_DOMAIN), + 'ею' => array(1 => self::VALID_UNICODE_DOMAIN), + 'ポイント' => array(1 => self::VALID_UNICODE_DOMAIN), + '新闻' => array(1 => self::VALID_UNICODE_DOMAIN), + '工行' => array(1 => self::VALID_UNICODE_DOMAIN), + 'كوم' => array(1 => self::VALID_UNICODE_DOMAIN), + '中文网' => array(1 => self::VALID_UNICODE_DOMAIN), + '中信' => array(1 => self::VALID_UNICODE_DOMAIN), + '中国' => array(1 => self::VALID_UNICODE_DOMAIN), + '中國' => array(1 => self::VALID_UNICODE_DOMAIN), + '娱乐' => array(1 => self::VALID_UNICODE_DOMAIN), + '谷歌' => array(1 => self::VALID_UNICODE_DOMAIN), + 'భారత్' => array(1 => self::VALID_UNICODE_DOMAIN), + 'ලංකා' => array(1 => self::VALID_UNICODE_DOMAIN), + '购物' => array(1 => self::VALID_UNICODE_DOMAIN), + 'クラウド' => array(1 => self::VALID_UNICODE_DOMAIN), + 'ભારત' => array(1 => self::VALID_UNICODE_DOMAIN), + 'भारत' => array(1 => self::VALID_UNICODE_DOMAIN), + '网店' => array(1 => self::VALID_UNICODE_DOMAIN), + 'संगठन' => array(1 => self::VALID_UNICODE_DOMAIN), + '餐厅' => array(1 => self::VALID_UNICODE_DOMAIN), + '网络' => array(1 => self::VALID_UNICODE_DOMAIN), + 'ком' => array(1 => self::VALID_UNICODE_DOMAIN), + 'укр' => array(1 => self::VALID_UNICODE_DOMAIN), + '香港' => array(1 => self::VALID_UNICODE_DOMAIN), + '诺基亚' => array(1 => self::VALID_UNICODE_DOMAIN), + '食品' => array(1 => self::VALID_UNICODE_DOMAIN), + '飞利浦' => array(1 => self::VALID_UNICODE_DOMAIN), + '台湾' => array(1 => self::VALID_UNICODE_DOMAIN), + '台灣' => array(1 => self::VALID_UNICODE_DOMAIN), + '手表' => array(1 => self::VALID_UNICODE_DOMAIN), + '手机' => array(1 => self::VALID_UNICODE_DOMAIN), + 'мон' => array(1 => self::VALID_UNICODE_DOMAIN), + 'الجزائر' => array(1 => self::VALID_UNICODE_DOMAIN), + 'عمان' => array(1 => self::VALID_UNICODE_DOMAIN), + 'ارامكو' => array(1 => self::VALID_UNICODE_DOMAIN), + 'ایران' => array(1 => self::VALID_UNICODE_DOMAIN), + 'امارات' => array(1 => self::VALID_UNICODE_DOMAIN), + 'بازار' => array(1 => self::VALID_UNICODE_DOMAIN), + 'الاردن' => array(1 => self::VALID_UNICODE_DOMAIN), + 'موبايلي' => array(1 => self::VALID_UNICODE_DOMAIN), + 'بھارت' => array(1 => self::VALID_UNICODE_DOMAIN), + 'المغرب' => array(1 => self::VALID_UNICODE_DOMAIN), + 'السعودية' => array(1 => self::VALID_UNICODE_DOMAIN), + 'سودان' => array(1 => self::VALID_UNICODE_DOMAIN), + 'همراه' => array(1 => self::VALID_UNICODE_DOMAIN), + 'عراق' => array(1 => self::VALID_UNICODE_DOMAIN), + 'مليسيا' => array(1 => self::VALID_UNICODE_DOMAIN), + '澳門' => array(1 => self::VALID_UNICODE_DOMAIN), + '닷컴' => array(1 => self::VALID_UNICODE_DOMAIN), + '政府' => array(1 => self::VALID_UNICODE_DOMAIN), + 'شبكة' => array(1 => self::VALID_UNICODE_DOMAIN), + 'بيتك' => array(1 => self::VALID_UNICODE_DOMAIN), + 'გე' => array(1 => self::VALID_UNICODE_DOMAIN), + '机构' => array(1 => self::VALID_UNICODE_DOMAIN), + '组织机构' => array(1 => self::VALID_UNICODE_DOMAIN), + '健康' => array(1 => self::VALID_UNICODE_DOMAIN), + 'ไทย' => array(1 => self::VALID_UNICODE_DOMAIN), + 'سورية' => array(1 => self::VALID_UNICODE_DOMAIN), + 'рус' => array(1 => self::VALID_UNICODE_DOMAIN), + 'рф' => array(1 => self::VALID_UNICODE_DOMAIN), + '珠宝' => array(1 => self::VALID_UNICODE_DOMAIN), + 'تونس' => array(1 => self::VALID_UNICODE_DOMAIN), + '大拿' => array(1 => self::VALID_UNICODE_DOMAIN), + 'みんな' => array(1 => self::VALID_UNICODE_DOMAIN), + 'グーグル' => array(1 => self::VALID_UNICODE_DOMAIN), + 'ελ' => array(1 => self::VALID_UNICODE_DOMAIN), + '世界' => array(1 => self::VALID_UNICODE_DOMAIN), + '書籍' => array(1 => self::VALID_UNICODE_DOMAIN), + 'ਭਾਰਤ' => array(1 => self::VALID_UNICODE_DOMAIN), + '网址' => array(1 => self::VALID_UNICODE_DOMAIN), + '닷넷' => array(1 => self::VALID_UNICODE_DOMAIN), + 'コム' => array(1 => self::VALID_UNICODE_DOMAIN), + '游戏' => array(1 => self::VALID_UNICODE_DOMAIN), + 'VERMöGENSBERATER' => array(1 => self::VALID_UNICODE_DOMAIN), + 'VERMöGENSBERATUNG' => array(1 => self::VALID_UNICODE_DOMAIN), + '企业' => array(1 => self::VALID_UNICODE_DOMAIN), + '信息' => array(1 => self::VALID_UNICODE_DOMAIN), + '嘉里大酒店' => array(1 => self::VALID_UNICODE_DOMAIN), + 'مصر' => array(1 => self::VALID_UNICODE_DOMAIN), + 'قطر' => array(1 => self::VALID_UNICODE_DOMAIN), + '广东' => array(1 => self::VALID_UNICODE_DOMAIN), + 'இலங்கை' => array(1 => self::VALID_UNICODE_DOMAIN), + 'இந்தியா' => array(1 => self::VALID_UNICODE_DOMAIN), + 'հայ' => array(1 => self::VALID_UNICODE_DOMAIN), + '新加坡' => array(1 => self::VALID_UNICODE_DOMAIN), + 'فلسطين' => array(1 => self::VALID_UNICODE_DOMAIN), + '政务' => array(1 => self::VALID_UNICODE_DOMAIN), + '家電' => array(1 => self::VALID_UNICODE_DOMAIN), ); diff --git a/tests/PHPUnit/Integration/EmailValidatorTest.php b/tests/PHPUnit/Integration/EmailValidatorTest.php index 262baab9e0..22c95f86ee 100644 --- a/tests/PHPUnit/Integration/EmailValidatorTest.php +++ b/tests/PHPUnit/Integration/EmailValidatorTest.php @@ -47,8 +47,10 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase if (strpos(mb_strtolower($tld), 'xn--') !== 0) { $tld = mb_strtolower($tld); } + $email = 'test@example.' . idn_to_utf8($tld); $this->assertTrue( - $this->isValid('test@example.' . idn_to_utf8($tld)) + $this->isValid($email), + "email $email is not valid, but expected to be valid. Add this domain extension to libs/Zend/Validate/Hostname.php" ); } } -- cgit v1.2.3 From 7ad2a7cc9f64f24f93e8c75736631fe20ef24f27 Mon Sep 17 00:00:00 2001 From: mattab Date: Wed, 30 Mar 2016 15:09:27 +1300 Subject: UI tests: Minor changes to Pivot view https://github.com/piwik/piwik/pull/9951 --- tests/UI/expected-ui-screenshots | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/UI/expected-ui-screenshots b/tests/UI/expected-ui-screenshots index 3ad4542963..debffa741c 160000 --- a/tests/UI/expected-ui-screenshots +++ b/tests/UI/expected-ui-screenshots @@ -1 +1 @@ -Subproject commit 3ad45429636e8c7375e81ce69cddec04074e939d +Subproject commit debffa741c32d40d39e98cdc31cea942c68a5797 -- cgit v1.2.3 From 027c4fa5b5c7d97c7818e3fb3c234d2c2a831dff Mon Sep 17 00:00:00 2001 From: mattab Date: Wed, 30 Mar 2016 15:21:31 +1300 Subject: Use both Days since First visit and Days since last visit to determine whether a user is returning --- plugins/CoreHome/Columns/VisitorReturning.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/CoreHome/Columns/VisitorReturning.php b/plugins/CoreHome/Columns/VisitorReturning.php index 5f3ba2584a..3a7268052e 100644 --- a/plugins/CoreHome/Columns/VisitorReturning.php +++ b/plugins/CoreHome/Columns/VisitorReturning.php @@ -49,8 +49,6 @@ class VisitorReturning extends VisitDimension */ public function onNewVisit(Request $request, Visitor $visitor, $action) { - $visitCount = $request->getVisitCount(); - $daysSinceFirstVisit = $request->getDaysSinceFirstVisit(); $daysSinceLastOrder = $request->getDaysSinceLastOrder(); $isReturningCustomer = ($daysSinceLastOrder !== false); @@ -59,7 +57,11 @@ class VisitorReturning extends VisitDimension return self::IS_RETURNING_CUSTOMER; } - if ($visitCount > 1 || $visitor->isVisitorKnown() || $daysSinceFirstVisit > 0) { + $visitCount = $request->getVisitCount(); + $daysSinceFirstVisit = $request->getDaysSinceFirstVisit(); + $daysSinceLastVisit = $request->getDaysSinceLastVisit(); + + if ($visitCount > 1 || $visitor->isVisitorKnown() || $daysSinceFirstVisit > 0 || $daysSinceLastVisit > 0) { return self::IS_RETURNING; } -- cgit v1.2.3 From 3ff659d4281637bb752800d32f18cdd0050590b2 Mon Sep 17 00:00:00 2001 From: mattab Date: Wed, 16 Mar 2016 15:10:11 +1300 Subject: piwik.js: remove the feature of `setDomains` magically setting the cookie path. Instead, we will better document how to correctly set the cookie configuration. https://github.com/piwik/piwik/issues/9932 --- js/piwik.js | 68 ------------------------------------------- piwik.js | 6 ++-- tests/javascript/index.php | 37 ++++------------------- tests/javascript/piwiktest.js | 1 - 4 files changed, 8 insertions(+), 104 deletions(-) diff --git a/js/piwik.js b/js/piwik.js index cd00196bd2..83fcc3d6de 100644 --- a/js/piwik.js +++ b/js/piwik.js @@ -4946,60 +4946,6 @@ if (typeof window.Piwik !== 'object') { }); } - /** - * Note: While we check whether the user is on a configHostAlias path we do not check whether the user is - * actually on the configHostAlias domain. This is already done where this method is called and for - * simplicity we do not check this again. - * - * Also we currently assume that all configHostAlias domains start with the same wild card of '*.', '.' or - * none. Eg either all like '*.piwik.org' or '.piwik.org' or 'piwik.org'. Piwik always adds '*.' so it - * should be fine. - */ - function findConfigCookiePathToUse(configHostAlias, currentUrl) - { - var aliasPath = getPathName(configHostAlias); - var currentPath = getPathName(currentUrl); - - if (!aliasPath || aliasPath === '/' || !currentPath || currentPath === '/') { - // no path set that would be useful for cookiePath - return; - } - - var aliasDomain = domainFixup(configHostAlias); - - if (isSiteHostPath(aliasDomain, '/')) { - // there is another configHostsAlias having same domain that allows all paths - // eg this alias is for piwik.org/support but there is another alias allowing - // piwik.org - return; - } - - if (stringEndsWith(aliasPath, '/')) { - aliasPath = removeCharactersFromEndOfString(aliasPath, 1); - } - - // eg if we're in the case of "apache.piwik/foo/bar" we check whether there is maybe - // also a config alias allowing "apache.piwik/foo". In this case we're not allowed to set - // the cookie for "/foo/bar" but "/foo" - var pathAliasParts = aliasPath.split('/'); - var i; - for (i = 2; i < pathAliasParts.length; i++) { - var lessRestrctivePath = pathAliasParts.slice(0, i).join('/'); - if (isSiteHostPath(aliasDomain, lessRestrctivePath)) { - aliasPath = lessRestrctivePath; - break; - } - } - - if (!isSitePath(currentPath, aliasPath)) { - // current path of current URL does not match the alias - // eg user is on piwik.org/demo but configHostAlias is for piwik.org/support - return; - } - - return aliasPath; - } - /* * Browser features (plugins, resolution, cookies) */ @@ -5578,11 +5524,6 @@ if (typeof window.Piwik !== 'object') { * case all links that don't go to '*.piwik.org/subsite1/ *' would be treated as outlinks. * For example a link to 'piwik.org/' or 'piwik.org/subsite2' both would be treated as outlinks. * - * We might automatically set a cookieConfigPath to avoid creating several cookies under one domain - * if there is a hostAlias defined with a path. Say a user is visiting 'http://piwik.org/subsite1' - * and '.piwik.org/subsite1' is set as a hostsAlias. Piwik will automatically use '/subsite1' as - * cookieConfigPath. - * * @param string|array hostsAlias */ setDomains: function (hostsAlias) { @@ -5593,15 +5534,6 @@ if (typeof window.Piwik !== 'object') { if (Object.prototype.hasOwnProperty.call(configHostsAlias, i) && isSameHost(domainAlias, domainFixup(String(configHostsAlias[i])))) { hasDomainAliasAlready = true; - - if (!configCookiePath) { - var path = findConfigCookiePathToUse(configHostsAlias[i], locationHrefAlias); - if (path) { - this.setCookiePath(path); - } - - break; - } } } diff --git a/piwik.js b/piwik.js index 550e6053ab..ea1ba111d0 100644 --- a/piwik.js +++ b/piwik.js @@ -49,9 +49,9 @@ if(!B(cJ[6])){cJ[6]=""}var cI=cJ[6];return{newVisitor:cF,uuid:cG,createTs:cD,vis }function aB(cC){return(am&&cC&&0===String(cC).indexOf(am))}function bZ(cG,cC,cH,cD){if(aB(cC)){return 0}var cF=aG(bj,"download"),cE=aG(aN,"link"),cI=new RegExp("\\.("+cs.join("|")+")([?&#]|$)","i");if(cE.test(cG)){return"link"}if(cD||cF.test(cG)||cI.test(cC)){return"download"}if(cH){return 0}return"link"}function ag(cD){var cC;cC=cD.parentNode;while(cC!==null&&B(cC)){if(W.isLinkElement(cD)){break}cD=cC;cC=cD.parentNode}return cD}function cw(cH){cH=ag(cH);if(!W.hasNodeAttribute(cH,"href")){return}if(!B(cH.href)){return}var cG=W.getAttributeValueFromNode(cH,"href");if(aB(cG)){return}var cD=cH.pathname||bR(cH.href);var cI=cH.hostname||c(cH.href);var cJ=cI.toLowerCase();var cE=cH.href.replace(cI,cJ);var cF=new RegExp("^(javascript|vbscript|jscript|mocha|livescript|ecmascript|mailto|tel):","i");if(!cF.test(cE)){var cC=bZ(cH.className,cE,af(cJ,cD),W.hasNodeAttribute(cH,"download"));if(cC){return{type:cC,href:cE}}}}function aw(cC,cD,cE,cF){var cG=p.buildInteractionRequestParams(cC,cD,cE,cF);if(!cG){return }return bY(cG,null,"contentInteraction")}function cc(cE,cF,cJ,cC,cD){if(!B(cE)){return}if(aB(cE)){return cE}var cH=p.toAbsoluteUrl(cE);var cG="redirecturl="+n(cH)+"&";cG+=aw(cF,cJ,cC,(cD||cE));var cI="&";if(am.indexOf("?")<0){cI="?"}return am+cI+cG}function aR(cC,cD){if(!cC||!cD){return false}var cE=p.findTargetNode(cC);if(p.shouldIgnoreInteraction(cE)){return false}cE=p.findTargetNodeNoDefault(cC);if(cE&&!N(cE,cD)){return false}return true}function b0(cE,cD,cG){if(!cE){return}var cC=p.findParentContentNode(cE);if(!cC){return}if(!aR(cC,cE)){return}var cF=p.buildContentBlock(cC);if(!cF){return}if(!cF.target&&cG){cF.target=cG}return p.buildInteractionRequestParams(cD,cF.name,cF.piece,cF.target)}function aD(cD){if(!bH||!bH.length){return false}var cC,cE;for(cC=0;cC0){cG=parseInt(cG,10);cJ(cG)}})}function aO(cG,cI){var cH=bR(cG);var cF=bR(cI);if(!cH||cH==="/"||!cF||cF==="/"){return}var cE=D(cG);if(af(cE,"/")){return}if(J(cH,"/")){cH=e(cH,1)}var cJ=cH.split("/");var cD;for(cD=2;cD Date: Wed, 30 Mar 2016 16:16:02 +1300 Subject: Documenting the setDomains change - refs https://github.com/piwik/piwik/pull/9933 https://github.com/piwik/piwik/issues/9932 --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bdf98fe7c..554aba5598 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,15 @@ This is a changelog for Piwik platform developers. All changes for our HTTP API' ### New features * New method `setIsWritableByCurrentUser` for `SystemSetting` to change the writable permission for certain system settings via DI. +### Breaking Changes +### Deprecations +### New APIs +### New commands +### New guides +### Library updates +### Internal change + * In the JavaScript tracker, the function `setDomains` will not anymore attempt to set a cookie path. Learn more about [configuring the tracker correctly](http://developer.piwik.org/guides/tracking-javascript-guide#tracking-one-domain) when tracking one or several domains and/or paths. + ## Piwik 2.16.0 ### New features -- cgit v1.2.3 From c9721dcce927b60e791e9af6c4de7774be473a7a Mon Sep 17 00:00:00 2001 From: mattab Date: Wed, 30 Mar 2016 16:30:01 +1300 Subject: Piwik.js 'setDomains' method supports page wildcards matching: example.com/index* `setDomains("example.com/index*")` will correctly not track an outlink request to for example.com/index.html or example.com/index_en.html refs #9932 --- js/piwik.js | 34 +++++++++++++++++++++++++- tests/javascript/index.php | 61 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 88 insertions(+), 7 deletions(-) diff --git a/js/piwik.js b/js/piwik.js index 3021ee0e40..b1efa6d53a 100644 --- a/js/piwik.js +++ b/js/piwik.js @@ -3112,7 +3112,7 @@ if (typeof window.Piwik !== 'object') { function isSitePath (path, pathAlias) { - var matchesAnyPath = (!pathAlias || pathAlias === '/'); + var matchesAnyPath = (!pathAlias || pathAlias === '/' || pathAlias === '/*'); if (matchesAnyPath) { return true; @@ -3129,6 +3129,26 @@ if (typeof window.Piwik !== 'object') { pathAlias = String(pathAlias).toLowerCase(); path = String(path).toLowerCase(); + // wildcard path support + if(stringEndsWith(pathAlias, '*')) { + // remove the final '*' before comparing + pathAlias = pathAlias.slice(0, -1); + + // Note: this is almost duplicated from just few lines above + matchesAnyPath = (!pathAlias || pathAlias === '/'); + + if (matchesAnyPath) { + return true; + } + + if (path === pathAlias) { + return true; + } + + // wildcard match + return path.indexOf(pathAlias) === 0; + } + // we need to append slashes so /foobarbaz won't match a site /foobar if (!stringEndsWith(path, '/')) { path += '/'; @@ -3141,6 +3161,15 @@ if (typeof window.Piwik !== 'object') { return path.indexOf(pathAlias) === 0; } + /** + * Whether the specified domain name and path belong to any of the alias domains (eg. set via setDomains). + * + * Note: this function is used to determine whether a click on a URL will be considered an "Outlink". + * + * @param host + * @param path + * @returns {boolean} + */ function isSiteHostPath(host, path) { var i, @@ -5526,6 +5555,9 @@ if (typeof window.Piwik !== 'object') { * case all links that don't go to '*.piwik.org/subsite1/ *' would be treated as outlinks. * For example a link to 'piwik.org/' or 'piwik.org/subsite2' both would be treated as outlinks. * + * Also supports page wildcard, eg 'piwik.org/index*'. In this case all links + * that don't go to piwik.org/index* would be treated as outlinks. + * * @param string|array hostsAlias */ setDomains: function (hostsAlias) { diff --git a/tests/javascript/index.php b/tests/javascript/index.php index fa8cfc4886..fa07f38500 100644 --- a/tests/javascript/index.php +++ b/tests/javascript/index.php @@ -2244,7 +2244,7 @@ function PiwikTest() { }); test("Tracker setDomains(), isSiteHostName(), isSiteHostPath(), and getLinkIfShouldBeProcessed()", function() { - expect(105); + expect(154); var tracker = Piwik.getTracker(); var initialDomains = tracker.getDomains(); @@ -2306,14 +2306,42 @@ function PiwikTest() { ok( isSiteHostName('dev.piwik.org'), 'isSiteHostName("dev.piwik.org")' ); ok( !isSiteHostName('piwik.org.com'), '!isSiteHostName("piwik.org.com")'); + // domain wildcard should not affect behavior + tracker.setDomains( '.piwik.net/*' ); + ok( isSiteHostName('piwik.net'), 'isSiteHostName("piwik.net")' ); + ok( isSiteHostName('dev.piwik.net'), 'isSiteHostName("dev.piwik.net")' ); + ok( !isSiteHostName('piwik.net.com'), '!isSiteHostName("piwik.net.com")'); + /** * isSiteHostPath () */ + // various edge cases with wildcards or 'empty' paths + var testCases = [ + ['piwik.org'], + ['piwik.org/'], + ['piwik.org/*'], + ['piwik.org/*', 'piwik.org/foo' ], + ['piwik.org/foo', 'piwik.org/*' ], + ['piwik.org/foo', 'piwik.org/*', 'piwik.org/*/bar' ], + ]; + for(var i in testCases) { + domainTestCase = testCases[i]; + tracker.setDomains( domainTestCase ); + + ok( isSiteHostPath('piwik.org', '/'), 'isSiteHostPath("piwik.org", "/") for ' + domainTestCase ); + ok( isSiteHostPath('piwik.org', ''), 'isSiteHostPath("piwik.org", "") for ' + domainTestCase ); + ok( isSiteHostPath('piwik.org', '*'), 'isSiteHostPath("piwik.org", "*") for ' + domainTestCase); + ok( isSiteHostPath('piwik.org', '/*'), 'isSiteHostPath("piwik.org", "/*") for ' + domainTestCase); + ok( isSiteHostPath('piwik.org', '/index'), 'isSiteHostPath("piwik.org", "/index") for ' + domainTestCase); + } + + // with path tracker.setDomains( '.piwik.org/path' ); ok( isSiteHostPath('piwik.org', '/path'), 'isSiteHostPath("piwik.org", "/path")' ); ok( isSiteHostPath('piwik.org', '/path/'), 'isSiteHostPath("piwik.org", "/path/")' ); + ok( !isSiteHostPath('piwik.org', '/path.htm'), 'isSiteHostPath("piwik.org", "/path.htm")' ); ok( isSiteHostPath('piwik.org', '/path/test'), 'isSiteHostPath("piwik.org", "/path/test)' ); ok( isSiteHostPath('dev.piwik.org', '/path'), 'isSiteHostPath("dev.piwik.org", "/path")' ); ok( !isSiteHostPath('piwik.org', '/pat'), '!isSiteHostPath("piwik.org", "/pat")'); @@ -2351,12 +2379,33 @@ function PiwikTest() { ok( isSiteHostPath('piwik.org', '/foo/bar'), 'isSiteHostPath("piwik.org", "/foo/bar")' ); ok( isSiteHostPath('piwik.org', '/bar/baz/foo'), 'isSiteHostPath("piwik.org", "/bar/baz/foo/")' ); ok( !isSiteHostPath('piwik.org', '/bar/ba'), 'isSiteHostPath("piwik.org", "/bar/ba")' ); - ok( isSiteHostPath('piwik.org', '/path/test'), 'isSiteHostPath("piwik.org", "/path/test)' ); + ok( isSiteHostPath('piwik.org', '/path/test'), 'isSiteHostPath("piwik.org", "/path/test")' ); + ok( isSiteHostPath('piwik.org', '/path/test.htm'), 'isSiteHostPath("piwik.org", "/path/test.htm")' ); ok( isSiteHostPath('dev.piwik.pro', '/test'), 'isSiteHostPath("dev.piwik.pro", "/test")' ); + ok( !isSiteHostPath('dev.piwik.pro', 'something/test.htm'), 'isSiteHostPath("dev.piwik.pro", "something/test")' ); ok( !isSiteHostPath('dev.piwik.pro', '/'), 'isSiteHostPath("dev.piwik.pro", "/")' ); - ok( !isSiteHostPath('piwik.pro', '/'), 'isSiteHostPath("piwik.pro", "/")' ); ok( !isSiteHostPath('piwik.org', '/'), 'isSiteHostPath("piwik.org", "/")' ); + ok( !isSiteHostPath('piwik.pro', '/'), 'isSiteHostPath("piwik.pro", "/")' ); + ok( !isSiteHostPath('piwik.org', '/index.htm'), 'isSiteHostPath("piwik.org", "/index.htm")' ); ok( !isSiteHostPath('piwik.org', '/anythingelse'), 'isSiteHostPath("piwik.org", "/anythingelse")' ); + ok( !isSiteHostPath('another.org', '/'), 'isSiteHostPath("another.org", "/")' ); + ok( !isSiteHostPath('another.org', '/anythingelse'), 'isSiteHostPath("another.org", "/anythingelse")' ); + + + // some subdirectories and some path wildcards + tracker.setDomains( ['piwik.org/path', 'piwik.org/path2', 'piwik.org/index*'] ); + ok( !isSiteHostPath('piwik.org', '/another'), "isSiteHostPath('piwik.org', '/another')" ); + ok( !isSiteHostPath('piwik.org', '/anotherindex'), "isSiteHostPath('piwik.org', '/anotherindex')" ); + ok( !isSiteHostPath('piwik.org', '/path.html'), "isSiteHostPath('piwik.org', '/path.html')" ); + ok( isSiteHostPath('piwik.org', '/index'), "isSiteHostPath('piwik.org', '/index')" ); + ok( isSiteHostPath('piwik.org', '/index.htm'), "isSiteHostPath('piwik.org', '/index.htm')" ); + ok( isSiteHostPath('piwik.org', '/index_en.htm'), "isSiteHostPath('piwik.org', '/index_en.htm')" ); + ok( isSiteHostPath('piwik.org', '/index*page'), "isSiteHostPath('piwik.org', '/index*page')" ); + + tracker.setDomains( ['piwik.org/index*', 'piwik.org'] ); + ok( isSiteHostPath('piwik.org', '/index*page'), "isSiteHostPath('piwik.org', '/index*page')" ); + ok( isSiteHostPath('piwik.org', ''), "isSiteHostPath('piwik.org', '')" ); + ok( isSiteHostPath('piwik.org', '/'), "isSiteHostPath('piwik.org', '/')" ); // all is compared lower case tracker.setDomains( '.piwik.oRg/PaTh' ); @@ -2415,7 +2464,7 @@ function PiwikTest() { }, getLinkIfShouldBeProcessed(createLink('http://www.piwik.org/footer')), 'getLinkIfShouldBeProcessed http://www.piwik.org/footer and there is domain piwik.org/foo but it should be outlink as path is different') /** - * Test sets a good cookie path automatically + * Test that we don't set a cookie path automatically */ tracker.setCookiePath(null); tracker.setDomains( ['.' + domainAlias + '/tests'] ); @@ -2425,9 +2474,9 @@ function PiwikTest() { tracker.setDomains( ['.' + domainAlias + '/tests/javascript'] ); equal(null, tracker.getConfigCookiePath(), 'should not set a cookie path automatically'); - tracker.setCookiePath(null); + tracker.setCookiePath('/path2'); tracker.setDomains( ['.' + domainAlias + '/tests/javascript', '.' + domainAlias + '/tests'] ); - equal(null, tracker.getConfigCookiePath(), 'should not set a cookie path automatically'); + equal('/path2', tracker.getConfigCookiePath(), 'should not set a cookie path automatically'); tracker.setCookiePath(null); }); -- cgit v1.2.3 From 81c48b897b4d465a90b0715a9f12daf0e2df7a3d Mon Sep 17 00:00:00 2001 From: mattab Date: Wed, 30 Mar 2016 16:48:08 +1300 Subject: New unit test ensuring that JS SDK getCookieName depends on website ID refs https://github.com/piwik/piwik/issues/9932 --- tests/javascript/index.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/javascript/index.php b/tests/javascript/index.php index fa07f38500..be9af836da 100644 --- a/tests/javascript/index.php +++ b/tests/javascript/index.php @@ -2537,6 +2537,24 @@ function PiwikTest() { equal( tracker.hook.test._getCookie( cookieName ), expectedValue, 'getCookie(), setCookie()' ); }); + test("Tracker getCookieName() contains website ID", function() { + expect(4); + + var tracker = Piwik.getTracker(); + tracker.setTrackerUrl("piwik.php"); + + tracker.setSiteId(1); + cookieName = tracker.hook.test._getCookieName('testing'); + ok( cookieName.indexOf('testing.1.') != -1); + ok( cookieName.indexOf('testing.2.') == -1); + + tracker.setSiteId(2); + cookieName = tracker.hook.test._getCookieName('testing-another'); + ok( cookieName.indexOf('testing-another.2.') != -1); + ok( cookieName.indexOf('testing-another.1.') == -1); + + }); + test("Tracker setDownloadExtensions(), addDownloadExtensions(), setDownloadClasses(), setLinkClasses(), and getLinkType()", function() { expect(72); -- cgit v1.2.3 From c9c0cad2708f463c31e004c29180dd8258bb13c0 Mon Sep 17 00:00:00 2001 From: mattab Date: Wed, 30 Mar 2016 18:02:25 +1300 Subject: JS Tracking code generator: new link to help page "Measuring domains and/or subdomains" https://github.com/piwik/piwik/issues/9932 --- plugins/CoreAdminHome/templates/trackingCodeGenerator.twig | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/CoreAdminHome/templates/trackingCodeGenerator.twig b/plugins/CoreAdminHome/templates/trackingCodeGenerator.twig index 787ff4aba7..1011afa8cb 100644 --- a/plugins/CoreAdminHome/templates/trackingCodeGenerator.twig +++ b/plugins/CoreAdminHome/templates/trackingCodeGenerator.twig @@ -50,6 +50,7 @@
{{ 'CoreAdminHome_JSTracking_MergeSubdomainsDesc'|translate("x."~defaultReportSiteDomain~"","y."~defaultReportSiteDomain~"")|raw }} + {{ 'General_LearnMore'|translate(' (', ')')|raw }}