diff options
Diffstat (limited to 'plugins/SegmentEditor')
-rw-r--r-- | plugins/SegmentEditor/SegmentEditor.php | 6 | ||||
-rw-r--r-- | plugins/SegmentEditor/SegmentFormatter.php | 147 | ||||
-rw-r--r-- | plugins/SegmentEditor/SegmentList.php | 32 | ||||
-rw-r--r-- | plugins/SegmentEditor/SegmentSelectorControl.php | 20 | ||||
-rw-r--r-- | plugins/SegmentEditor/javascripts/Segmentation.js | 6 | ||||
-rw-r--r-- | plugins/SegmentEditor/lang/cs.json | 9 | ||||
-rw-r--r-- | plugins/SegmentEditor/lang/el.json | 7 | ||||
-rw-r--r-- | plugins/SegmentEditor/lang/en.json | 7 | ||||
-rw-r--r-- | plugins/SegmentEditor/lang/it.json | 7 | ||||
-rw-r--r-- | plugins/SegmentEditor/lang/ja.json | 4 | ||||
-rw-r--r-- | plugins/SegmentEditor/lang/pt-br.json | 8 | ||||
-rw-r--r-- | plugins/SegmentEditor/lang/tr.json | 8 | ||||
-rw-r--r-- | plugins/SegmentEditor/templates/_segmentSelector.twig | 16 | ||||
-rw-r--r-- | plugins/SegmentEditor/tests/Integration/SegmentFormatterTest.php | 116 | ||||
-rw-r--r-- | plugins/SegmentEditor/tests/Integration/SegmentListTest.php | 74 |
15 files changed, 445 insertions, 22 deletions
diff --git a/plugins/SegmentEditor/SegmentEditor.php b/plugins/SegmentEditor/SegmentEditor.php index 9107935e73..a46be068bc 100644 --- a/plugins/SegmentEditor/SegmentEditor.php +++ b/plugins/SegmentEditor/SegmentEditor.php @@ -28,6 +28,7 @@ class SegmentEditor extends \Piwik\Plugin 'AssetManager.getJavaScriptFiles' => 'getJsFiles', 'AssetManager.getStylesheetFiles' => 'getStylesheetFiles', 'Template.nextToCalendar' => 'getSegmentEditorHtml', + 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys', ); } @@ -85,4 +86,9 @@ class SegmentEditor extends \Piwik\Plugin { return Config::getInstance()->General['allow_adding_segments_for_all_websites'] == 1; } + + public function getClientSideTranslationKeys(&$translationKeys) + { + $translationKeys[] = 'SegmentEditor_CustomSegment'; + } } diff --git a/plugins/SegmentEditor/SegmentFormatter.php b/plugins/SegmentEditor/SegmentFormatter.php new file mode 100644 index 0000000000..19838d46d5 --- /dev/null +++ b/plugins/SegmentEditor/SegmentFormatter.php @@ -0,0 +1,147 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ +namespace Piwik\Plugins\SegmentEditor; + +use Exception; +use Piwik\Config; +use Piwik\Db; +use Piwik\Piwik; +use Piwik\Segment; +use Piwik\Segment\SegmentExpression; + +/** + */ +class SegmentFormatter +{ + /** + * @var SegmentList + */ + private $segmentList; + + private $matchesMetric = array( + SegmentExpression::MATCH_EQUAL => 'General_OperationEquals', + SegmentExpression::MATCH_NOT_EQUAL => 'General_OperationNotEquals', + SegmentExpression::MATCH_LESS_OR_EQUAL => 'General_OperationAtMost', + SegmentExpression::MATCH_GREATER_OR_EQUAL => 'General_OperationAtLeast', + SegmentExpression::MATCH_LESS => 'General_OperationLessThan', + SegmentExpression::MATCH_GREATER => 'General_OperationGreaterThan', + ); + + private $matchesDimension = array( + SegmentExpression::MATCH_EQUAL => 'General_OperationIs', + SegmentExpression::MATCH_NOT_EQUAL => 'General_OperationIsNot', + SegmentExpression::MATCH_CONTAINS => 'General_OperationContains', + SegmentExpression::MATCH_DOES_NOT_CONTAIN => 'General_OperationDoesNotContain', + SegmentExpression::MATCH_STARTS_WITH => 'General_OperationStartsWith', + SegmentExpression::MATCH_ENDS_WITH => 'General_OperationEndsWith' + ); + + private $operators = array( + SegmentExpression::BOOL_OPERATOR_AND => 'General_And', + SegmentExpression::BOOL_OPERATOR_OR => 'General_Or', + SegmentExpression::BOOL_OPERATOR_END => '', + ); + + public function __construct(SegmentList $segmentList) + { + $this->segmentList = $segmentList; + } + + public function getHumanReadable($segmentString, $idSite) + { + if (empty($segmentString)) { + return Piwik::translate('SegmentEditor_DefaultAllVisits'); + } + + try { + $segment = new SegmentExpression(urldecode($segmentString)); + $expressions = $segment->parseSubExpressions(); + } catch (Exception $e) { + $segment = new SegmentExpression($segmentString); + $expressions = $segment->parseSubExpressions(); + } + + $readable = ''; + foreach ($expressions as $expression) { + $operator = $expression[SegmentExpression::INDEX_BOOL_OPERATOR]; + $operand = $expression[SegmentExpression::INDEX_OPERAND]; + $name = $operand[SegmentExpression::INDEX_OPERAND_NAME]; + + $segment = $this->segmentList->findSegment($name, $idSite); + + if (empty($segment)) { + throw new Exception(sprintf("The segment '%s' does not exist.", $name)); + } + + $readable .= $segment['name'] . ' '; + $readable .= $this->getTranslationForComparison($operand, $segment['type']) . ' '; + $readable .= $this->getFormattedValue($operand); + $readable .= $this->getTranslationForBoolOperator($operator) . ' '; + } + + $readable = trim($readable); + + return $readable; + } + + private function getTranslationForComparison($operand, $segmentType) + { + $operator = $operand[SegmentExpression::INDEX_OPERAND_OPERATOR]; + + $translation = $operator; + + if ($operator === SegmentExpression::MATCH_IS_NULL_OR_EMPTY) { + return Piwik::translate('SegmentEditor_SegmentOperatorIsNullOrEmpty'); + } + + if ($operator === SegmentExpression::MATCH_IS_NOT_NULL_NOR_EMPTY) { + return Piwik::translate('SegmentEditor_SegmentOperatorIsNotNullNorEmpty'); + } + + if ($segmentType === 'dimension' && !empty($this->matchesDimension[$operator])) { + $translation = Piwik::translate($this->matchesDimension[$operator]); + } + if ($segmentType === 'metric' && !empty($this->matchesMetric[$operator])) { + $translation = Piwik::translate($this->matchesMetric[$operator]); + } + + return strtolower($translation); + } + + private function getFormattedValue($operand) + { + $operator = $operand[SegmentExpression::INDEX_OPERAND_OPERATOR]; + + if ($operator === SegmentExpression::MATCH_IS_NULL_OR_EMPTY + || $operator === SegmentExpression::MATCH_IS_NOT_NULL_NOR_EMPTY) { + return ''; + } + + $value = $operand[SegmentExpression::INDEX_OPERAND_VALUE]; + + if (empty($value)) { + $value = ''; + } + + return '"' . $value . '" '; + } + + private function getTranslationForBoolOperator($operator) + { + $translation = ''; + + if (!empty($this->operators[$operator])) { + $translation = Piwik::translate($this->operators[$operator]); + } elseif (!empty($operator)) { + $translation = $operator; + } + + return $translation; + } +} diff --git a/plugins/SegmentEditor/SegmentList.php b/plugins/SegmentEditor/SegmentList.php new file mode 100644 index 0000000000..e7094d4793 --- /dev/null +++ b/plugins/SegmentEditor/SegmentList.php @@ -0,0 +1,32 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ +namespace Piwik\Plugins\SegmentEditor; + +use Piwik\API\Request; +use Piwik\Config; +use Piwik\Db; + +/** + */ +class SegmentList +{ + public function findSegment($segmentName, $idSite) + { + $segments = Request::processRequest('API.getSegmentsMetadata', array( + 'idSites' => array($idSite), + )); + + foreach ($segments as $segment) { + if ($segment['segment'] == $segmentName && !empty($segmentName)) { + return $segment; + } + } + } + +} diff --git a/plugins/SegmentEditor/SegmentSelectorControl.php b/plugins/SegmentEditor/SegmentSelectorControl.php index e37354e1cd..72be071e5e 100644 --- a/plugins/SegmentEditor/SegmentSelectorControl.php +++ b/plugins/SegmentEditor/SegmentSelectorControl.php @@ -8,8 +8,10 @@ */ namespace Piwik\Plugins\SegmentEditor; +use Piwik\API\Request; use Piwik\Common; use Piwik\Config; +use Piwik\Container\StaticContainer; use Piwik\Piwik; use Piwik\Plugins\API\API as APIMetadata; use Piwik\View\UIControl; @@ -37,13 +39,17 @@ class SegmentSelectorControl extends UIControl $this->selectedSegment = Common::getRequestVar('segment', false, 'string'); + $formatter = StaticContainer::get('Piwik\Plugins\SegmentEditor\SegmentFormatter'); + $this->segmentDescription = $formatter->getHumanReadable(Request::getRawSegmentFromRequest(), $this->idSite); + $this->isAddingSegmentsForAllWebsitesEnabled = SegmentEditor::isAddingSegmentsForAllWebsitesEnabled(); $segments = APIMetadata::getInstance()->getSegmentsMetadata($this->idSite); + $visitTitle = Piwik::translate('General_Visit'); $segmentsByCategory = array(); foreach ($segments as $segment) { - if ($segment['category'] == Piwik::translate('General_Visit') + if ($segment['category'] == $visitTitle && ($segment['type'] == 'metric' && $segment['segment'] != 'visitIp') ) { $metricsLabel = Piwik::translate('General_Metrics'); @@ -52,7 +58,6 @@ class SegmentSelectorControl extends UIControl } $segmentsByCategory[$segment['category']][] = $segment; } - uksort($segmentsByCategory, array($this, 'sortSegmentCategories')); $this->createRealTimeSegmentsIsEnabled = Config::getInstance()->General['enable_create_realtime_segments']; $this->segmentsByCategory = $segmentsByCategory; @@ -95,15 +100,6 @@ class SegmentSelectorControl extends UIControl return (bool) $savedSegment['auto_archive']; } - public function sortSegmentCategories($a, $b) - { - // Custom Variables last - if ($a == Piwik::translate('CustomVariables_CustomVariables')) { - return 1; - } - return 0; - } - private function getTranslations() { $translationKeys = array( @@ -115,6 +111,8 @@ class SegmentSelectorControl extends UIControl 'General_OperationGreaterThan', 'General_OperationContains', 'General_OperationDoesNotContain', + 'General_OperationStartsWith', + 'General_OperationEndsWith', 'General_OperationIs', 'General_OperationIsNot', 'General_OperationContains', diff --git a/plugins/SegmentEditor/javascripts/Segmentation.js b/plugins/SegmentEditor/javascripts/Segmentation.js index 0e47bd7d19..2ffd7dac57 100644 --- a/plugins/SegmentEditor/javascripts/Segmentation.js +++ b/plugins/SegmentEditor/javascripts/Segmentation.js @@ -49,6 +49,8 @@ Segmentation = (function($) { self.availableMatches["dimension"]["!="] = self.translations['General_OperationIsNot']; self.availableMatches["dimension"]["=@"] = self.translations['General_OperationContains']; self.availableMatches["dimension"]["!@"] = self.translations['General_OperationDoesNotContain']; + self.availableMatches["dimension"]["=^"] = self.translations['General_OperationStartsWith']; + self.availableMatches["dimension"]["=$"] = self.translations['General_OperationEndsWith']; segmentation.prototype.setAvailableSegments = function (segments) { this.availableSegments = segments; @@ -83,7 +85,7 @@ Segmentation = (function($) { var name = $(foundItems).first().find("span.segname").text(); title.text(name); } else { - title.text("Custom Segment"); + title.text(_pk_translate('SegmentEditor_CustomSegment')); } segmentationTitle.html(title); } @@ -264,7 +266,7 @@ Segmentation = (function($) { }; var findAndExplodeByMatch = function(metric){ - var matches = ["==" , "!=" , "<=", ">=", "=@" , "!@","<",">"]; + var matches = ["==" , "!=" , "<=", ">=", "=@" , "!@","<",">", "=^", "=$"]; var newMetric = {}; var minPos = metric.length; var match, index; diff --git a/plugins/SegmentEditor/lang/cs.json b/plugins/SegmentEditor/lang/cs.json index 36dd2084b3..c5752de9e2 100644 --- a/plugins/SegmentEditor/lang/cs.json +++ b/plugins/SegmentEditor/lang/cs.json @@ -7,13 +7,14 @@ "AutoArchivePreProcessed": "Segmentovaná hlášení jsou předzpracována rychleji (vyžadují cron)", "AutoArchiveRealTime": "Segmentovaná hlášení jsou zpracována v reálném čase", "ChooseASegment": "Zvolte segment", + "CurrentlySelectedSegment": "Aktuálně vybraný segment: %s", "DataAvailableAtLaterDate": "Vaše segmentovaná analytická hlášení budou dostupná později. Omlouváme se za tuto nepříjemnost.", "DefaultAllVisits": "Všechny návštěvy", "DragDropCondition": "Přetáhněte podmínku", "LoadingSegmentedDataMayTakeSomeTime": "Zpracování segmentovaných dat návštěvníků může pár minut trvat...", "OperatorAND": "AND", "OperatorOR": "OR", - "SaveAndApply": "Uložit & použít", + "SaveAndApply": "Uložit a použít", "SegmentDisplayedAllWebsites": "Všechny webové stránky", "SegmentDisplayedThisWebsiteOnly": "Pouze tyto webové stránky", "SegmentIsDisplayedForWebsite": "A zobrazený po", @@ -26,6 +27,10 @@ "YouMayChangeSetting": "Jinak můžete nastavení změnit v souboru %s, nebo můžete upravit tento segment a zvolit %s.", "YouMustBeLoggedInToCreateSegments": "Pro vytváření a úpravu vlastních segmentů návštěvníků musíte být přihlášen.", "YouDontHaveAccessToCreateSegments": "Pro vytváření a úpravu segmentů nemáte požadovanou přístupovou úroveň.", - "AddingSegmentForAllWebsitesDisabled": "Přidávání segmentů pro všechny stránky bylo zakázáno." + "AddingSegmentForAllWebsitesDisabled": "Přidávání segmentů pro všechny stránky bylo zakázáno.", + "SegmentXIsAUnionOf": "%s je propojení těchto segmentů:", + "CustomSegment": "Vlastní segment", + "SegmentOperatorIsNullOrEmpty": "je nulový nebo prázdný", + "SegmentOperatorIsNotNullNorEmpty": "není nulový nebo prázdný" } }
\ No newline at end of file diff --git a/plugins/SegmentEditor/lang/el.json b/plugins/SegmentEditor/lang/el.json index e0a9f14a6a..72d3659543 100644 --- a/plugins/SegmentEditor/lang/el.json +++ b/plugins/SegmentEditor/lang/el.json @@ -7,6 +7,7 @@ "AutoArchivePreProcessed": "οι αναφορές τμημάτων προεπεξεργάζονται (γρηγορότερα, απαιτείται το archive.php με cron)", "AutoArchiveRealTime": "οι αναφορές τμημάτων επεξεργάζονται σε πραγματικό χρόνο", "ChooseASegment": "Επιλέξτε ένα τμήμα", + "CurrentlySelectedSegment": "Επιλεγμένο τμήμα αυτή τη στιγμή: %s", "DataAvailableAtLaterDate": "Οι τμηματικές αναφορές αναλυτικών θα είναι αργότερα διαθέσιμες. Ζητούμε συγγνώμη για την ταλαιπωρία.", "DefaultAllVisits": "Όλες οι επισκέψεις", "DragDropCondition": "Συνθήκη με Σύρε & Άσε", @@ -26,6 +27,10 @@ "YouMayChangeSetting": "Εναλλακτικά, μπορείτε να αλλάξετε τη ρύθμιση στο αρχείο ρυθμίσεων (%s), ή να τροποποιήσετε το Τμήμα αυτό και να επιλέξετε '%s'.", "YouMustBeLoggedInToCreateSegments": "Θα πρέπει να έχετε κάνει είσοδο για να δημιουργήσετε και να επεξεργαστείτε προσαρμοσμένα τμήματα επισκεπτών.", "YouDontHaveAccessToCreateSegments": "Δεν διαθέτετε την απαιτούμενη πρόσβαση ασφαλείας για να δημιουργείτε και να τροποποιείτε τμήματα.", - "AddingSegmentForAllWebsitesDisabled": "Η προσθήκη τμημάτων έχει απενεργοποιηθεί για όλους τους ιστοτόπους." + "AddingSegmentForAllWebsitesDisabled": "Η προσθήκη τμημάτων έχει απενεργοποιηθεί για όλους τους ιστοτόπους.", + "SegmentXIsAUnionOf": "Το %s είναι η ένωση αυτών των τμημάτων:", + "CustomSegment": "Προσαρμοσμένο τμήμα", + "SegmentOperatorIsNullOrEmpty": "είναι άκυρο (null) ή κενό", + "SegmentOperatorIsNotNullNorEmpty": "δεν είναι άκυρο (null) ή άδειο" } }
\ No newline at end of file diff --git a/plugins/SegmentEditor/lang/en.json b/plugins/SegmentEditor/lang/en.json index 46bdf5fef2..8651afeecd 100644 --- a/plugins/SegmentEditor/lang/en.json +++ b/plugins/SegmentEditor/lang/en.json @@ -7,6 +7,7 @@ "AutoArchivePreProcessed": "segmented reports are pre-processed (faster, requires cron)", "AutoArchiveRealTime": "segmented reports are processed in real time", "ChooseASegment": "Choose a segment", + "CurrentlySelectedSegment": "Currently selected segment: %s", "DataAvailableAtLaterDate": "Your segmented analytics reports will be available later. We apologize for the inconvenience.", "DefaultAllVisits": "All visits", "DragDropCondition": "Drag & Drop condition", @@ -26,6 +27,10 @@ "YouMayChangeSetting": "Alternatively you may change the setting in the config file (%s), or edit this Segment and choose '%s'.", "YouMustBeLoggedInToCreateSegments": "You must be logged in to create and edit custom visitor segments.", "YouDontHaveAccessToCreateSegments": "You don't have the required access level to create and edit segments.", - "AddingSegmentForAllWebsitesDisabled": "Adding segments for all websites has been disabled." + "AddingSegmentForAllWebsitesDisabled": "Adding segments for all websites has been disabled.", + "SegmentXIsAUnionOf": "%s is a union of these segments:", + "CustomSegment": "Custom Segment", + "SegmentOperatorIsNullOrEmpty": "is null or empty", + "SegmentOperatorIsNotNullNorEmpty": "is not null nor empty" } }
\ No newline at end of file diff --git a/plugins/SegmentEditor/lang/it.json b/plugins/SegmentEditor/lang/it.json index 63b0ec0ce2..28b4b9f3ed 100644 --- a/plugins/SegmentEditor/lang/it.json +++ b/plugins/SegmentEditor/lang/it.json @@ -7,6 +7,7 @@ "AutoArchivePreProcessed": "i reports segmentati sono pre-elaborati (più veloce, richiede un cron-job)", "AutoArchiveRealTime": "i reports segmentati sono elaborati in tempo reale", "ChooseASegment": "Scegli un segmento", + "CurrentlySelectedSegment": "Segmento attualmente selezionato: %s", "DataAvailableAtLaterDate": "I report segmentati delle statistiche saranno disponibili più tardi. Ci scusiamo per l'inconveniente.", "DefaultAllVisits": "Tutte le visite", "DragDropCondition": "Copia & Incolla condizione", @@ -26,6 +27,10 @@ "YouMayChangeSetting": "In alternativa, puoi cambiare le impostazioni nel file di configurazione (%s) o modificare questo Segmento e scegliere '%s'.", "YouMustBeLoggedInToCreateSegments": "Devi avere effettuato l'accesso per creare e modificare i segmenti personalizzati dei visitatori.", "YouDontHaveAccessToCreateSegments": "Non hai un livello d'accesso adeguato per creare e modificare i segmenti.", - "AddingSegmentForAllWebsitesDisabled": "L'aggiunta di segmenti per tutti i siti è stata disabilitata." + "AddingSegmentForAllWebsitesDisabled": "L'aggiunta di segmenti per tutti i siti è stata disabilitata.", + "SegmentXIsAUnionOf": "%s è un'unione di questi segmenti:", + "CustomSegment": "Segmento Speciale", + "SegmentOperatorIsNullOrEmpty": "è nullo o vuoto", + "SegmentOperatorIsNotNullNorEmpty": "non è nullo nè vuoto" } }
\ No newline at end of file diff --git a/plugins/SegmentEditor/lang/ja.json b/plugins/SegmentEditor/lang/ja.json index 8c65a9c7cf..0156de56ab 100644 --- a/plugins/SegmentEditor/lang/ja.json +++ b/plugins/SegmentEditor/lang/ja.json @@ -1,5 +1,6 @@ { "SegmentEditor": { + "PluginDescription": "セグメントエディターでカスタム ユーザー セグメントを作成、編集できます。", "AddANDorORCondition": "%s の条件を追加", "AddNewSegment": "新しいセグメントを追加", "AreYouSureDeleteSegment": "このセグメントを削除してもよろしいですか?", @@ -25,6 +26,7 @@ "YouMayChangeSetting": "別の方法としては設定ファイル (%s) で設定を変更するか、このセグメント '%s' を選択し編集することができます。", "YouMustBeLoggedInToCreateSegments": "ビジターのカスタムセグメントの作成と編集にはログインが必要です。", "YouDontHaveAccessToCreateSegments": "セグメントの作成および編集に必要なレベルのアクセス権限を持っていません。", - "AddingSegmentForAllWebsitesDisabled": "全ウェブサイトに対するセグメントは追加できませんでした。" + "AddingSegmentForAllWebsitesDisabled": "全ウェブサイトに対するセグメントは追加できませんでした。", + "CustomSegment": "カスタムセグメント" } }
\ No newline at end of file diff --git a/plugins/SegmentEditor/lang/pt-br.json b/plugins/SegmentEditor/lang/pt-br.json index a5f8df59f2..eb7a8919d2 100644 --- a/plugins/SegmentEditor/lang/pt-br.json +++ b/plugins/SegmentEditor/lang/pt-br.json @@ -7,6 +7,7 @@ "AutoArchivePreProcessed": "Relatórios segmentados são pré-processados (Para agilizar, é necessário usar o cron em: archive.php)", "AutoArchiveRealTime": "Relatórios segmentados são processados em tempo real", "ChooseASegment": "Escolha um segmento", + "CurrentlySelectedSegment": "Segmento atualmente selecionado: %s", "DataAvailableAtLaterDate": "Os seus relatórios de análise segmentados estarão disponíveis mais tarde. Pedimos desculpas pela inconveniência.", "DefaultAllVisits": "Todas as visitas", "DragDropCondition": "Condição Drag & Drop", @@ -23,8 +24,13 @@ "ThisSegmentIsVisibleTo": "Este segmento é visível para:", "VisibleToAllUsers": "Todos os Usuários", "VisibleToMe": "mim", + "YouMayChangeSetting": "Alternativamente, você pode alterar a configuração no arquivo de configuração (%s), ou editar este Segmento e escolher %s.", "YouMustBeLoggedInToCreateSegments": "Você precisa estar logado para criar e editar segmentos personalizados de visitantes.", "YouDontHaveAccessToCreateSegments": "Você não tem o nível de acesso necessário para criar e editar segmentos.", - "AddingSegmentForAllWebsitesDisabled": "Adicionar segmentos para todos os sites foi desativado." + "AddingSegmentForAllWebsitesDisabled": "Adicionar segmentos para todos os sites foi desativado.", + "SegmentXIsAUnionOf": "%s é uma união destes segmentos:", + "CustomSegment": "Segmento Personalizado", + "SegmentOperatorIsNullOrEmpty": "está nulo ou vazio", + "SegmentOperatorIsNotNullNorEmpty": "não está nulo nem vazio" } }
\ No newline at end of file diff --git a/plugins/SegmentEditor/lang/tr.json b/plugins/SegmentEditor/lang/tr.json new file mode 100644 index 0000000000..3541941a61 --- /dev/null +++ b/plugins/SegmentEditor/lang/tr.json @@ -0,0 +1,8 @@ +{ + "SegmentEditor": { + "OperatorAND": "VE", + "OperatorOR": "VEYA", + "SaveAndApply": "Kaydet & Uygula", + "VisibleToAllUsers": "tüm kullanıcılar" + } +}
\ No newline at end of file diff --git a/plugins/SegmentEditor/templates/_segmentSelector.twig b/plugins/SegmentEditor/templates/_segmentSelector.twig index 7a8019d37e..dc269dc8b9 100644 --- a/plugins/SegmentEditor/templates/_segmentSelector.twig +++ b/plugins/SegmentEditor/templates/_segmentSelector.twig @@ -1,5 +1,5 @@ <div class="SegmentEditor" style="display:none;"> - <div class="segmentationContainer listHtml" title="{{ 'SegmentEditor_ChooseASegment'|translate|e('html_attr') }}"> + <div class="segmentationContainer listHtml" title="{{ 'SegmentEditor_ChooseASegment'|translate|e('html_attr') }}. {{ 'SegmentEditor_CurrentlySelectedSegment'|translate(segmentDescription)|e('html_attr') }}"> <a class="title"><span class="icon icon-segment"></span><span class="segmentationTitle"></span></a> <div class="dropdown dropdown-body"> <div class="segmentFilterContainer"> @@ -61,6 +61,8 @@ <option value=">">{{ 'General_OperationGreaterThan'|translate }}</option> <option value="=@">{{ 'General_OperationContains'|translate }}</option> <option value="!@">{{ 'General_OperationDoesNotContain'|translate }}</option> + <option value="=^">{{ 'General_OperationStartsWith'|translate }}</option> + <option value="=$">{{ 'General_OperationEndsWith'|translate }}</option> </select> </div> <div class="segment-input metricValueBlock"> @@ -99,7 +101,17 @@ <a class="metric_category" href="#">{{ category }}</a> <ul style="display:none;"> {% for segmentInCategory in segmentsInCategory %} - <li data-metric="{{ segmentInCategory.segment }}"><a class="ddmetric" href="#">{{ segmentInCategory.name }}</a></li> + {% set title = segmentInCategory.name %} + {% if segmentInCategory.unionOfSegments is defined and segmentInCategory.unionOfSegments %} + {% set title = 'SegmentEditor_SegmentXIsAUnionOf'|translate(title) %} + {% for unionSegment in segmentInCategory.unionOfSegments %} + {% set title = title ~ ' ' ~ unionSegment %} + {% if not loop.last %} + {% set title = title ~ ',' %} + {% endif %} + {% endfor %} + {% endif %} + <li data-metric="{{ segmentInCategory.segment }}" title="{{ title|e('html_attr') }}"><a class="ddmetric" href="#">{{ segmentInCategory.name }}</a></li> {% endfor %} </ul> </li> diff --git a/plugins/SegmentEditor/tests/Integration/SegmentFormatterTest.php b/plugins/SegmentEditor/tests/Integration/SegmentFormatterTest.php new file mode 100644 index 0000000000..ca37e0775b --- /dev/null +++ b/plugins/SegmentEditor/tests/Integration/SegmentFormatterTest.php @@ -0,0 +1,116 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +namespace Piwik\Plugins\SegmentEditor\tests\Integration; + +use Piwik\Plugins\SegmentEditor\SegmentFormatter; +use Piwik\Plugins\SegmentEditor\SegmentList; +use Piwik\Tests\Framework\Fixture; +use Piwik\Tests\Framework\Mock\FakeAccess; +use Piwik\Tests\Framework\TestCase\IntegrationTestCase; +use Piwik\Translate; +use Exception; + +/** + * @group SegmentFormatterTest + * @group SegmentFormatter + * @group SegmentEditor + * @group Plugins + */ +class SegmentFormatterTest extends IntegrationTestCase +{ + /** + * @var SegmentFormatter + */ + private $formatter; + + private $idSite; + + public function setUp() + { + parent::setUp(); + + $this->idSite = Fixture::createWebsite('2012-01-01 00:00:00'); + $this->formatter = new SegmentFormatter(new SegmentList()); + + Translate::loadAllTranslations(); + } + + public function tearDown() + { + Translate::reset(); + } + + public function test_getHumanReadable_noSegmentGiven_ShouldReturnDefaultSegment() + { + $readable = $this->formatter->getHumanReadable($segment = '', $this->idSite); + $this->assertSame('All visits', $readable); + } + + public function test_getHumanReadable_ShouldTranslateAMetric() + { + $readable = $this->formatter->getHumanReadable($segment = 'visitCount>5', $this->idSite); + $this->assertSame('Number of visits greater than "5"', $readable); + + $readable = $this->formatter->getHumanReadable($segment = 'visitCount==5', $this->idSite); + $this->assertSame('Number of visits equals "5"', $readable); + } + + public function test_getHumanReadable_ShouldTranslateADimension() + { + $readable = $this->formatter->getHumanReadable($segment = 'resolution=@1024', $this->idSite); + $this->assertSame('Resolution contains "1024"', $readable); + + $readable = $this->formatter->getHumanReadable($segment = 'resolution==1024x768', $this->idSite); + $this->assertSame('Resolution is "1024x768"', $readable); + } + + public function test_getHumanReadable_ShouldCombineMultipleSegmentDefinitionsWithBooleanOperator() + { + $readable = $this->formatter->getHumanReadable($segment = 'browserVersion!=1.0;browserEngine=$Trident', $this->idSite); + $this->assertSame('Browser version is not "1.0" and Browser engine ends with "Trident"', $readable); + + $readable = $this->formatter->getHumanReadable($segment = 'browserVersion!=1.0,browserEngine=$Trident', $this->idSite); + $this->assertSame('Browser version is not "1.0" or Browser engine ends with "Trident"', $readable); + } + + public function test_getHumanReadable_ShouldHandleAMissingValue() + { + $readable = $this->formatter->getHumanReadable($segment = 'browserVersion==', $this->idSite); + $this->assertSame('Browser version is null or empty', $readable); + + $readable = $this->formatter->getHumanReadable($segment = 'browserVersion!=', $this->idSite); + $this->assertSame('Browser version is not null nor empty', $readable); + } + + public function test_getHumanReadable_ShouldHandleAUrlDecodedSegment() + { + $readable = $this->formatter->getHumanReadable($segment = 'pageUrl%3D%40piwik%2CvisitId!%3D1', $this->idSite); + $this->assertSame('Page URL contains "piwik" or Visit ID is not "1"', $readable); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage The segment 'noTexisTinG' does not exist + */ + public function test_getHumanReadable_ShouldThrowAnException_IfTheGivenSegmentNameDoesNotExist() + { + $this->formatter->getHumanReadable($segment = 'noTexisTinG==1.0', $this->idSite); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage The segment 'pageUrl=!1.0' is not valid. + */ + public function test_getHumanReadable_ShouldThrowAnException_IfSegmentCannotBeParsedBecauseOfInvalidFormat() + { + $invalidOperator = '=!'; + $this->formatter->getHumanReadable($segment = 'pageUrl' . $invalidOperator . '1.0', $this->idSite); + } + +} diff --git a/plugins/SegmentEditor/tests/Integration/SegmentListTest.php b/plugins/SegmentEditor/tests/Integration/SegmentListTest.php new file mode 100644 index 0000000000..3a90bb95ee --- /dev/null +++ b/plugins/SegmentEditor/tests/Integration/SegmentListTest.php @@ -0,0 +1,74 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +namespace Piwik\Plugins\SegmentEditor\tests\Integration; + +use Piwik\Plugins\SegmentEditor\SegmentList; +use Piwik\Tests\Framework\Fixture; +use Piwik\Tests\Framework\Mock\FakeAccess; +use Piwik\Tests\Framework\TestCase\IntegrationTestCase; +use Exception; + +/** + * @group SegmentListTest + * @group SegmentList + * @group SegmentEditor + * @group Plugins + */ +class SegmentListTest extends IntegrationTestCase +{ + /** + * @var SegmentList + */ + private $list; + + private $idSite; + + public function setUp() + { + parent::setUp(); + + $this->idSite = Fixture::createWebsite('2012-01-01 00:00:00'); + $this->list = new SegmentList(); + } + + public function test_findSegment_shouldFindSegmentByName_IfNameExists() + { + $segmentName = 'pageUrl'; + + $segment = $this->list->findSegment($segmentName, $this->idSite); + $this->assertInternalType('array', $segment); + $this->assertSame($segmentName, $segment['segment']); + } + + public function test_findSegment_shouldNotFindSegmentByName_IfNameDoesNotExist() + { + $segment = $this->list->findSegment('aNyNotExisTinGSegmEnt', $this->idSite); + $this->assertNull($segment); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage checkUserHasViewAccess + */ + public function test_findSegment_ShouldThrowException_IfNotEnoughPermission() + { + FakeAccess::clearAccess($superUser = false, array(1)); + + $segment = $this->list->findSegment('pageUrl', 999); + $this->assertNull($segment); + } + + public function provideContainerConfig() + { + return array( + 'Piwik\Access' => new FakeAccess() + ); + } + +} |