Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormattab <matthieu.aubry@gmail.com>2015-11-30 06:00:02 +0300
committermattab <matthieu.aubry@gmail.com>2016-01-22 11:12:59 +0300
commita38c0c3012af0259a3a0036f17a821b693d12886 (patch)
treec4ef7483e2c9bc9a1b4e58fd69cfb9b82f612417
parentd7211cd8c622257f7acaefd7d56367325e6c480e (diff)
Fixes #6766 Let Super User view and edit segments created by other users
As a Super User: * I can now see all segments that were created for this website by any other user * When a segment was created by another user who is not Super User, the segment appears below a new section "Visible to you because you have Super User access:" * Such segments are editable by the Super User * The only difference when editing someone else's segment, as a Super User, is that "This segment is visible to [ME]" now says "This segment is visible to [SEGMENT_AUTHOR_USERNAME]" * One can now search in the search bar for a username and see all segments created by this user For all users: * New section "Shared with you:" now lists segments created by a Super User, and marked as "Visible to [All Users]" * Before segments shared with me, looked the same as segments I created, which was confusing
-rw-r--r--lang/en.json1
-rw-r--r--plugins/CoreHome/CoreHome.php1
-rw-r--r--plugins/Dashboard/stylesheets/dashboard.less4
-rw-r--r--plugins/SegmentEditor/API.php43
-rw-r--r--plugins/SegmentEditor/Model.php21
-rw-r--r--plugins/SegmentEditor/SegmentEditor.php2
-rw-r--r--plugins/SegmentEditor/javascripts/Segmentation.js237
-rw-r--r--plugins/SegmentEditor/lang/en.json4
-rw-r--r--plugins/SegmentEditor/stylesheets/segmentation.less14
-rw-r--r--plugins/SegmentEditor/templates/_segmentSelector.twig2
-rw-r--r--plugins/SegmentEditor/tests/Integration/ApiTest.php221
-rw-r--r--tests/PHPUnit/Framework/Fixture.php1
12 files changed, 465 insertions, 86 deletions
diff --git a/lang/en.json b/lang/en.json
index 95556d3c8d..131b224b40 100644
--- a/lang/en.json
+++ b/lang/en.json
@@ -87,6 +87,7 @@
"Continue": "Continue",
"ContinueToPiwik": "Continue to Piwik",
"CurrentlyUsingUnsecureHttp": "You are currently using Piwik over unsecure HTTP, which can be risky. We recommend you set up Piwik to use SSL (HTTPS) for improved security.",
+ "CreatedByUser": "created by %s",
"CurrentMonth": "Current Month",
"CurrentWeek": "Current Week",
"CurrentYear": "Current Year",
diff --git a/plugins/CoreHome/CoreHome.php b/plugins/CoreHome/CoreHome.php
index ba0f3edd82..52cfa2de5d 100644
--- a/plugins/CoreHome/CoreHome.php
+++ b/plugins/CoreHome/CoreHome.php
@@ -278,5 +278,6 @@ class CoreHome extends \Piwik\Plugin
$translationKeys[] = 'CoreHome_MenuEntries';
$translationKeys[] = 'SitesManager_Sites';
$translationKeys[] = 'CoreHome_ChangeCurrentWebsite';
+ $translationKeys[] = 'General_CreatedByUser';
}
}
diff --git a/plugins/Dashboard/stylesheets/dashboard.less b/plugins/Dashboard/stylesheets/dashboard.less
index b45398379c..26120e1abb 100644
--- a/plugins/Dashboard/stylesheets/dashboard.less
+++ b/plugins/Dashboard/stylesheets/dashboard.less
@@ -257,7 +257,7 @@
ul.widgetpreview-widgetlist,
ul.widgetpreview-categorylist {
- color: #5d5342;
+ color: @theme-color-text-light;
list-style: none;
font-size: 11px;
line-height: 20px;
@@ -318,7 +318,7 @@ div.widgetpreview-preview {
font-weight: normal;
padding-top: 10px;
margin-left: 10px;
- color: #5D5342;
+ color: @theme-color-text-light;
list-style: none;
font-size: 11px;
line-height: 20px;
diff --git a/plugins/SegmentEditor/API.php b/plugins/SegmentEditor/API.php
index 358f0d2b3e..ad4098775c 100644
--- a/plugins/SegmentEditor/API.php
+++ b/plugins/SegmentEditor/API.php
@@ -351,16 +351,53 @@ class API extends \Piwik\Plugin\API
$userLogin = Piwik::getCurrentUserLogin();
$model = $this->getModel();
- if (empty($idSite)) {
- $segments = $model->getAllSegments($userLogin);
+ if(Piwik::hasUserSuperUserAccess()) {
+ $segments = $model->getAllSegmentsForAllUsers($idSite);
} else {
- $segments = $model->getAllSegmentsForSite($idSite, $userLogin);
+ if (empty($idSite)) {
+ $segments = $model->getAllSegments($userLogin);
+ } else {
+ $segments = $model->getAllSegmentsForSite($idSite, $userLogin);
+ }
}
+ $segments = $this->sortSegmentsCreatedByUserFirst($segments);
+
return $segments;
}
/**
+ * Sorts segment in a particular order:
+ *
+ * 1) my segments
+ * 2) segments created by the super user that were shared with all users
+ * 3) segments created by other users (which are visible to all super users)
+ *
+ * @param $segments
+ * @return array
+ */
+ private function sortSegmentsCreatedByUserFirst($segments)
+ {
+ $orderedSegments = array();
+ foreach($segments as $id => &$segment) {
+ if($segment['login'] == Piwik::getCurrentUserLogin()) {
+ $orderedSegments[] = $segment;
+ unset($segments[$id]);
+ }
+ }
+ foreach($segments as $id => &$segment) {
+ if($segment['enable_all_users'] == 1) {
+ $orderedSegments[] = $segment;
+ unset($segments[$id]);
+ }
+ }
+ foreach($segments as $id => &$segment) {
+ $orderedSegments[] = $segment;
+ }
+ return $orderedSegments;
+ }
+
+ /**
* @return string
*/
private function getMessageCannotEditSegmentCreatedBySuperUser()
diff --git a/plugins/SegmentEditor/Model.php b/plugins/SegmentEditor/Model.php
index 7f312557f9..7e73b6a1ab 100644
--- a/plugins/SegmentEditor/Model.php
+++ b/plugins/SegmentEditor/Model.php
@@ -98,6 +98,27 @@ class Model
return $segments;
}
+ /**
+ * This should be used _only_ by Super Users
+ * @param $idSite
+ * @return array
+ */
+ public function getAllSegmentsForAllUsers($idSite = false)
+ {
+ $bind = array();
+ $sqlWhereCondition = '';
+
+ if(!empty($idSite)) {
+ $bind = array($idSite);
+ $sqlWhereCondition = '(enable_only_idsite = ? OR enable_only_idsite = 0) AND';
+ }
+
+ $sqlWhereCondition = $this->buildQuerySortedByName($sqlWhereCondition . ' deleted = 0');
+ $segments = $this->getDb()->fetchAll($sqlWhereCondition, $bind);
+
+ return $segments;
+ }
+
public function deleteSegment($idSegment)
{
$db = $this->getDb();
diff --git a/plugins/SegmentEditor/SegmentEditor.php b/plugins/SegmentEditor/SegmentEditor.php
index 0d7c84ed7a..1e6e4d3ec7 100644
--- a/plugins/SegmentEditor/SegmentEditor.php
+++ b/plugins/SegmentEditor/SegmentEditor.php
@@ -88,5 +88,7 @@ class SegmentEditor extends \Piwik\Plugin
public function getClientSideTranslationKeys(&$translationKeys)
{
$translationKeys[] = 'SegmentEditor_CustomSegment';
+ $translationKeys[] = 'SegmentEditor_VisibleToSuperUser';
+ $translationKeys[] = 'SegmentEditor_SharedWithYou';
}
}
diff --git a/plugins/SegmentEditor/javascripts/Segmentation.js b/plugins/SegmentEditor/javascripts/Segmentation.js
index 2ffd7dac57..d47a83b4a1 100644
--- a/plugins/SegmentEditor/javascripts/Segmentation.js
+++ b/plugins/SegmentEditor/javascripts/Segmentation.js
@@ -80,14 +80,14 @@ Segmentation = (function($) {
var currentDecoded = piwikHelper.htmlDecode(current);
var selector = 'div.segmentList ul li[data-definition="'+currentDecoded+'"]';
var foundItems = $(selector, this.target);
- var title = $('<strong></strong>');
+
if( foundItems.length > 0) {
- var name = $(foundItems).first().find("span.segname").text();
- title.text(name);
+ var idSegment = $(foundItems).first().attr('data-idsegment');
+ var title = getSegmentName( getSegmentFromId(idSegment));
} else {
- title.text(_pk_translate('SegmentEditor_CustomSegment'));
+ title = _pk_translate('SegmentEditor_CustomSegment');
}
- segmentationTitle.html(title);
+ segmentationTitle.html( "<strong>" + title + "</strong>");
}
else {
$(this.content).find(".segmentationTitle").text(this.translations['SegmentEditor_DefaultAllVisits']);
@@ -199,14 +199,42 @@ Segmentation = (function($) {
var html = self.editorTemplate.find("> .listHtml").clone();
var segment, injClass;
var listHtml = '<li data-idsegment="" ' +
- (self.currentSegmentStr == "" ? " class='segmentSelected' " : "")
- + ' data-definition=""><span class="segname">' + self.translations['SegmentEditor_DefaultAllVisits']
- + ' ' + self.translations['General_DefaultAppended']
- + '</span></li> ';
+ (self.currentSegmentStr == "" ? " class='segmentSelected' " : "")
+ + ' data-definition=""><span class="segname">' + self.translations['SegmentEditor_DefaultAllVisits']
+ + ' ' + self.translations['General_DefaultAppended']
+ + '</span></li> ';
+
+ var isVisibleToSuperUserNoticeAlreadyDisplayedOnce = false;
+ var isVisibleToSuperUserNoticeShouldBeClosed = false;
+
+ var isSharedWithMeBySuperUserNoticeAlreadyDisplayedOnce = false;
+ var isSharedWithMeBySuperUserNoticeShouldBeClosed = false;
+
if(self.availableSegments.length > 0) {
+
for(var i = 0; i < self.availableSegments.length; i++)
{
segment = self.availableSegments[i];
+
+ if(isSegmentSharedWithMeBySuperUser(segment) && !isSharedWithMeBySuperUserNoticeAlreadyDisplayedOnce) {
+ isSharedWithMeBySuperUserNoticeAlreadyDisplayedOnce = true;
+ isSharedWithMeBySuperUserNoticeShouldBeClosed = true;
+ listHtml += '<span class="segmentsSharedWithMeBySuperUser"><hr> ' + _pk_translate('SegmentEditor_SharedWithYou') + ':<br/><br/>';
+ }
+
+ if(isSegmentVisibleToSuperUserOnly(segment) && !isVisibleToSuperUserNoticeAlreadyDisplayedOnce) {
+ // close <span class="segmentsSharedWithMeBySuperUser">
+ if(isSharedWithMeBySuperUserNoticeShouldBeClosed) {
+ isSharedWithMeBySuperUserNoticeShouldBeClosed = false;
+ listHtml += '</span>';
+ }
+
+ isVisibleToSuperUserNoticeAlreadyDisplayedOnce = true;
+ isVisibleToSuperUserNoticeShouldBeClosed = true;
+ listHtml += '<span class="segmentsVisibleToSuperUser"><hr> ' + _pk_translate('SegmentEditor_VisibleToSuperUser') + ':<br/><br/>';
+ }
+
+
injClass = "";
var checkSelected = segment.definition;
if(!$.browser.mozilla) {
@@ -217,12 +245,21 @@ Segmentation = (function($) {
injClass = 'class="segmentSelected"';
}
listHtml += '<li data-idsegment="'+segment.idsegment+'" data-definition="'+ (segment.definition).replace(/"/g, '&quot;') +'" '
- +injClass+' title="'+segment.name+'"><span class="segname">'+segment.name+'</span>';
+ +injClass+' title="'+ getSegmentTooltipEnrichedWithUsername(segment) +'"><span class="segname">'+getSegmentName(segment)+'</span>';
if(self.segmentAccess == "write") {
listHtml += '<span class="editSegment" title="'+ self.translations['General_Edit'].toLocaleLowerCase() +'"></span>';
}
listHtml += '</li>';
}
+
+ if(isVisibleToSuperUserNoticeShouldBeClosed) {
+ listHtml += '</span>';
+ }
+
+ if(isSharedWithMeBySuperUserNoticeShouldBeClosed) {
+ listHtml += '</span>';
+ }
+
$(html).find(".segmentList > ul").append(listHtml);
if(self.segmentAccess === "write"){
$(html).find(".add_new_segment").html(self.translations['SegmentEditor_AddNewSegment']);
@@ -238,20 +275,58 @@ Segmentation = (function($) {
return html;
};
+ var isSegmentVisibleToSuperUserOnly = function(segment) {
+ return hasSuperUserAccessAndSegmentCreatedByAnotherUser(segment)
+ && segment.enable_all_users == 0;
+ };
+
+ var isSegmentSharedWithMeBySuperUser = function(segment) {
+ return segment.login != piwik.userLogin
+ && segment.enable_all_users == 1;
+ };
+
+ var hasSuperUserAccessAndSegmentCreatedByAnotherUser = function(segment) {
+ return piwik.hasSuperUserAccess && segment.login != piwik.userLogin;
+ };
+
+ var getSegmentTooltipEnrichedWithUsername = function(segment) {
+ var segmentName = segment.name;
+ if(hasSuperUserAccessAndSegmentCreatedByAnotherUser(segment)) {
+ segmentName += ' (';
+ segmentName += _pk_translate('General_CreatedByUser', [segment.login]);
+
+ if(segment.enable_all_users == 0) {
+ segmentName += ', ' + _pk_translate('SegmentEditor_VisibleToSuperUser');
+ }
+
+ segmentName += ')';
+ }
+ return sanitiseSegmentName(segmentName);
+ };
+
+ var getSegmentName = function(segment) {
+ return sanitiseSegmentName(segment.name);
+ };
+
+ var sanitiseSegmentName = function(segment) {
+ segment = piwikHelper.escape(segment);
+ return segment;
+ }
+
var getFormHtml = function() {
var html = self.editorTemplate.find("> .segment-element").clone();
// set left margin to center form
var segmentsDropdown = $(html).find(".available_segments_select");
var segment, newOption;
newOption = '<option data-idsegment="" data-definition="" title="'
- + self.translations['SegmentEditor_AddNewSegment']
- + '">' + self.translations['SegmentEditor_AddNewSegment']
- + '</option>';
+ + self.translations['SegmentEditor_AddNewSegment']
+ + '">' + self.translations['SegmentEditor_AddNewSegment']
+ + '</option>';
segmentsDropdown.append(newOption);
for(var i = 0; i < self.availableSegments.length; i++)
{
segment = self.availableSegments[i];
- newOption = '<option data-idsegment="'+segment.idsegment+'" data-definition="'+(segment.definition).replace(/"/g, '&quot;')+'" title="'+segment.name+'">'+segment.name+'</option>';
+ newOption = '<option data-idsegment="'+segment.idsegment+'" data-definition="'+(segment.definition).replace(/"/g, '&quot;')+'" title="'+getSegmentTooltipEnrichedWithUsername(segment)+'">'+getSegmentName(segment)+'</option>';
segmentsDropdown.append(newOption);
}
$(html).find(".segment-content > h3").after(getInitialStateRowsHtml()).show();
@@ -324,10 +399,15 @@ Segmentation = (function($) {
var openEditForm = function(segment){
addForm("edit", segment);
- $(self.form).find(".segment-content > h3 > span").text(segment.name);
+ $(self.form).find(".segment-content > h3 > span")
+ .html( getSegmentName(segment) )
+ .prop('title', getSegmentTooltipEnrichedWithUsername(segment));
+
$(self.form).find('.available_segments_select > option[data-idsegment="'+segment.idsegment+'"]').prop("selected",true);
- $(self.form).find('.available_segments a.dropList').text(segment.name);
+ $(self.form).find('.available_segments a.dropList')
+ .html( getSegmentName(segment) )
+ .prop( 'title', getSegmentTooltipEnrichedWithUsername(segment));
if(segment.definition != ""){
revokeInitialStateRows();
@@ -360,6 +440,13 @@ Segmentation = (function($) {
$(self.target).find(".segmentList li:first")
.before("<li class=\"filterNoResults grayed\">" + self.translations['General_SearchNoResults'] + "</li>");
}
+
+ if ($(self.target).find(".segmentList .segmentsVisibleToSuperUser li:visible").length == 0) {
+ $(self.target).find(".segmentList .segmentsVisibleToSuperUser").hide();
+ }
+ if ($(self.target).find(".segmentList .segmentsSharedWithMeBySuperUser li:visible").length == 0) {
+ $(self.target).find(".segmentList .segmentsSharedWithMeBySuperUser").hide();
+ }
}
var clearFilterSegmentList = function () {
@@ -367,6 +454,8 @@ Segmentation = (function($) {
$(self.target).find(".segmentList li").each(function () {
$(this).show();
});
+ $(self.target).find(".segmentList .segmentsVisibleToSuperUser").show();
+ $(self.target).find(".segmentList .segmentsSharedWithMeBySuperUser").show();
}
var bindEvents = function () {
@@ -407,15 +496,13 @@ Segmentation = (function($) {
self.target.on("click", ".segmentList li", function (e) {
if ($(e.currentTarget).hasClass("grayed") !== true) {
- var segment = {};
- segment.idsegment = $(this).attr("data-idsegment");
- segment.definition = $(this).data("definition");
- segment.name = $(this).attr("title");
+ var idsegment = $(this).attr("data-idsegment");
+ segmentDefinition = $(this).data("definition");
- self.setSegment(segment.definition);
+ self.setSegment(segmentDefinition);
self.markCurrentSegment();
- self.segmentSelectMethod( segment.definition );
- toggleLoadingMessage(segment.definition.length);
+ self.segmentSelectMethod( segmentDefinition );
+ toggleLoadingMessage(segmentDefinition.length);
}
});
@@ -748,16 +835,9 @@ Segmentation = (function($) {
};
function openEditFormGivenSegment(option) {
- var segment = {};
- segment.idsegment = option.attr("data-idsegment");
-
- var segmentExtra = getSegmentFromId(segment.idsegment);
- for(var item in segmentExtra)
- {
- segment[item] = segmentExtra[item];
- }
+ var idsegment = option.attr("data-idsegment");
- segment.name = option.attr("title");
+ var segment = getSegmentFromId(idsegment);
segment.definition = option.data("definition");
@@ -815,7 +895,7 @@ Segmentation = (function($) {
// 1 - do most obvious selection -> mark whole categories matching search string
// also expand whole category
$(self.form).find('.segment-nav div > ul > li').each( function(){
- curStr = normalizeSearchString($(this).find("a.metric_category").text());
+ curStr = normalizeSearchString($(this).find("a.metric_category").text());
if(curStr.indexOf(search) > -1) {
$(this).addClass("searchFound");
$(this).find("ul").show();
@@ -823,7 +903,7 @@ Segmentation = (function($) {
$(this).show();
}
}
- );
+ );
// 2 - among all unselected categories find metrics which match and mark parent as search result
$(self.form).find(".segment-nav div > ul > li:not(.searchFound)").each(function(){
@@ -872,8 +952,8 @@ Segmentation = (function($) {
}
search = search.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
- .replace(/\s+/g, '_') // collapse whitespace and replace by underscore
- .replace(/-+/g, '-'); // collapse dashes
+ .replace(/\s+/g, '_') // collapse whitespace and replace by underscore
+ .replace(/-+/g, '-'); // collapse dashes
return search;
};
@@ -900,7 +980,12 @@ Segmentation = (function($) {
placeSegmentationFormControls();
if(mode == "edit") {
- $(self.form).find('.enable_all_users_select > option[value="'+segment.enable_all_users+'"]').prop("selected",true);
+ var userSelector = $(self.form).find('.enable_all_users_select > option[value="' + segment.enable_all_users + '"]').prop("selected",true);
+
+ // Replace "Visible to me" by "Visible to $login" when user is super user
+ if(hasSuperUserAccessAndSegmentCreatedByAnotherUser(segment)) {
+ $(self.form).find('.enable_all_users_select > option[value="' + 0 + '"]').text(segment.login);
+ }
$(self.form).find('.visible_to_website_select > option[value="'+segment.enable_only_idsite+'"]').prop("selected",true);
$(self.form).find('.auto_archive_select > option[value="'+segment.auto_archive+'"]').prop("selected",true);
@@ -991,43 +1076,43 @@ Segmentation = (function($) {
var makeDropList = function(spanId, selectId){
var select = $(self.form).find(selectId).hide();
var dropList = $( '<a class="dropList dropdown">' )
- .insertAfter( select )
- .text( select.children(':selected').text() )
- .autocomplete({
- delay: 0,
- minLength: 0,
- appendTo: "body",
- source: function( request, response ) {
- response( select.children( "option" ).map(function() {
- var text = $( this ).text();
- return {
- label: text,
- value: this.value,
- option: this
- };
- }) );
- },
- select: function( event, ui ) {
- event.preventDefault();
- ui.item.option.selected = true;
- // Mark original select>option
- $(spanId + ' option[value="' + ui.item.value + '"]', self.editorTemplate).prop('selected', true);
- dropList.text(ui.item.label);
- $(self.form).find(selectId).trigger("change");
- }
- })
- .click(function() {
- // close all other droplists made by this form
- $("a.dropList").autocomplete("close");
- // close if already visible
- if ( $(this).autocomplete( "widget" ).is(":visible") ) {
- $(this).autocomplete("close");
- return;
- }
- // pass empty string as value to search for, displaying all results
- $(this).autocomplete( "search", "" );
+ .insertAfter( select )
+ .text( select.children(':selected').text() )
+ .autocomplete({
+ delay: 0,
+ minLength: 0,
+ appendTo: "body",
+ source: function( request, response ) {
+ response( select.children( "option" ).map(function() {
+ var text = $( this ).text();
+ return {
+ label: text,
+ value: this.value,
+ option: this
+ };
+ }) );
+ },
+ select: function( event, ui ) {
+ event.preventDefault();
+ ui.item.option.selected = true;
+ // Mark original select>option
+ $(spanId + ' option[value="' + ui.item.value + '"]', self.editorTemplate).prop('selected', true);
+ dropList.text(ui.item.label);
+ $(self.form).find(selectId).trigger("change");
+ }
+ })
+ .click(function() {
+ // close all other droplists made by this form
+ $("a.dropList").autocomplete("close");
+ // close if already visible
+ if ( $(this).autocomplete( "widget" ).is(":visible") ) {
+ $(this).autocomplete("close");
+ return;
+ }
+ // pass empty string as value to search for, displaying all results
+ $(this).autocomplete( "search", "" );
- });
+ });
$('body').on('mouseup',function (e) {
if (!$(e.target).parents(spanId).length
&& !$(e.target).is(spanId)
@@ -1166,7 +1251,7 @@ $(document).ready(function() {
}
}
- self.props.availableSegments[idx] = params;
+ $.extend( self.props.availableSegments[idx], params);
self.rebuild();
self.impl.setSegment(params.definition);
@@ -1222,8 +1307,8 @@ $(document).ready(function() {
};
var segmentFromRequest = encodeURIComponent(self.props.selectedSegment)
- || broadcast.getValueFromHash('segment')
- || broadcast.getValueFromUrl('segment');
+ || broadcast.getValueFromHash('segment')
+ || broadcast.getValueFromUrl('segment');
if($.browser.mozilla) {
segmentFromRequest = decodeURIComponent(segmentFromRequest);
}
diff --git a/plugins/SegmentEditor/lang/en.json b/plugins/SegmentEditor/lang/en.json
index 8651afeecd..6e7861e0c0 100644
--- a/plugins/SegmentEditor/lang/en.json
+++ b/plugins/SegmentEditor/lang/en.json
@@ -20,10 +20,12 @@
"SegmentIsDisplayedForWebsite": "and displayed for",
"SegmentNotApplied": "Segment '%s' not applied",
"SegmentNotAppliedMessage": "You are requesting data for the Custom Segment '%s', this Piwik configuration currently prevents real time processing of reports for performance reasons.",
- "SelectSegmentOfVisitors": "Select a segment of visitors:",
+ "SelectSegmentOfVisits": "Select a segment of visits:",
"ThisSegmentIsVisibleTo": "This segment is visible to:",
"VisibleToAllUsers": "all users",
"VisibleToMe": "me",
+ "VisibleToSuperUser": "Visible to you because you have Super User access",
+ "SharedWithYou": "Shared with you",
"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.",
diff --git a/plugins/SegmentEditor/stylesheets/segmentation.less b/plugins/SegmentEditor/stylesheets/segmentation.less
index 125a0c9f56..705c4ec2f9 100644
--- a/plugins/SegmentEditor/stylesheets/segmentation.less
+++ b/plugins/SegmentEditor/stylesheets/segmentation.less
@@ -174,7 +174,7 @@ div.scrollable {
}
.segment-element .segment-nav div > ul > li a {
- color: #5d5342;
+ color: @theme-color-text-light;
font-size: 11px;
font-weight: bold;
text-decoration: none;
@@ -454,7 +454,7 @@ div.scrollable {
}
.segmentationContainer .submenu ul {
- color: #5D5342;
+ color: @theme-color-text-light;
float: none;
font-size: 11px;
font-weight: normal;
@@ -572,7 +572,7 @@ body > a.ddmetric {
cursor: move;
padding: 1px 0 2px 18px;
background: #eae8e3 url(plugins/SegmentEditor/images/segment-move.png) 100% 50% no-repeat;
- color: #5d5342;
+ color: @theme-color-text-light;
font-weight: normal;
font-size: 11px;
text-decoration: none;
@@ -759,3 +759,11 @@ a.metric_category {
display: inline-block;
vertical-align: sub;
}
+
+.segmentsVisibleToSuperUser, .segmentsSharedWithMeBySuperUser {
+ font-style: italic;
+
+ li {
+ font-style: normal;
+ }
+}
diff --git a/plugins/SegmentEditor/templates/_segmentSelector.twig b/plugins/SegmentEditor/templates/_segmentSelector.twig
index 18c885919a..c853f5211a 100644
--- a/plugins/SegmentEditor/templates/_segmentSelector.twig
+++ b/plugins/SegmentEditor/templates/_segmentSelector.twig
@@ -7,7 +7,7 @@
<span/>
</div>
<ul class="submenu">
- <li>{{ 'SegmentEditor_SelectSegmentOfVisitors'|translate }}
+ <li>{{ 'SegmentEditor_SelectSegmentOfVisits'|translate }}
<div class="segmentList">
<ul>
</ul>
diff --git a/plugins/SegmentEditor/tests/Integration/ApiTest.php b/plugins/SegmentEditor/tests/Integration/ApiTest.php
new file mode 100644
index 0000000000..c58ec7a8cd
--- /dev/null
+++ b/plugins/SegmentEditor/tests/Integration/ApiTest.php
@@ -0,0 +1,221 @@
+<?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\API;
+use Piwik\Tests\Framework\Fixture;
+use Piwik\Tests\Framework\Mock\FakeAccess;
+use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+
+/**
+ * @group SegmentEditor
+ * @group ApiTest
+ * @group Plugins
+ */
+class ApiTest extends IntegrationTestCase
+{
+ /**
+ * @var API
+ */
+ private $api;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $this->api = API::getInstance();
+
+ Fixture::createSuperUser();
+ if (!Fixture::siteCreated(1)) {
+ Fixture::createWebsite('2012-01-01 00:00:00');
+ }
+ if (!Fixture::siteCreated(2)) {
+ Fixture::createWebsite('2012-01-01 00:00:00');
+ }
+
+ }
+
+ public function test_getAll_forOneWebsite_returnsSortedSegments()
+ {
+ $this->createAdminUser();
+ $this->createSegments();
+ $this->setAdminUser();
+
+ $expectedOrder = array(
+ // 1) my segments
+ 'segment 1',
+ 'segment 3',
+ 'segment 7',
+
+ // 2) segments created by a super user that were shared with all users
+ 'segment 5',
+ 'segment 9',
+
+ // 3) segments created by other users (which are visible to all super users)
+ // not a super user, so can't see those
+ );
+
+ $segments = $this->api->getAll($idSite = 1);
+ $segmentNames = $this->getNamesFromSegments($segments);
+ $this->assertSame($expectedOrder, $segmentNames);
+ }
+
+ public function test_getAll_forAllWebsites_returnsSortedSegments()
+ {
+ $this->createAdminUser();
+ $this->createSegments();
+ $this->setAdminUser();
+
+ $expectedOrder = array(
+ // 1) my segments
+ 'segment 1',
+ 'segment 2',
+ 'segment 3',
+ 'segment 7',
+
+ // 2) segments created by a super user that were shared with all users
+ 'segment 5',
+ 'segment 6',
+ 'segment 9',
+
+ // 3) segments created by other users (which are visible to all super users)
+ // not a super user, so can't see those
+ );
+
+ $segments = $this->api->getAll();
+ $segmentNames = $this->getNamesFromSegments($segments);
+ $this->assertSame($expectedOrder, $segmentNames);
+ }
+
+ public function test_getAll_forAllWebsites_returnsSortedSegments_asSuperUser()
+ {
+ $this->createAdminUser();
+ $this->createSegments();
+ $this->setAnotherSuperUser();
+
+ $expectedOrder = array(
+ // 1) my segments
+ 'segment 9',
+
+ // 2) segments created by a super user that were shared with all users
+ 'segment 5',
+ 'segment 6',
+
+ // 3) segments created by other users (which are visible to all super users)
+ 'segment 1',
+ 'segment 2',
+ 'segment 3',
+ 'segment 4',
+ 'segment 7',
+ 'segment 8',
+ );
+
+ $segments = $this->api->getAll();
+ $segmentNames = $this->getNamesFromSegments($segments);
+ $this->assertSame($expectedOrder, $segmentNames);
+ }
+
+ public function test_getAll_forOneWebsite_returnsSortedSegments_asSuperUser()
+ {
+ $this->createAdminUser();
+ $this->createSegments();
+ $this->setAnotherSuperUser();
+
+ $expectedOrder = array(
+ // 1) my segments
+ 'segment 9',
+
+ // 2) segments created by a super user that were shared with all users
+ 'segment 5',
+
+ // 3) segments created by other users (which are visible to all super users)
+ 'segment 1',
+ 'segment 3',
+ 'segment 4',
+ 'segment 7',
+ 'segment 8',
+ );
+
+ $segments = $this->api->getAll($idSite = 1);
+ $segmentNames = $this->getNamesFromSegments($segments);
+ $this->assertSame($expectedOrder, $segmentNames);
+ }
+
+ /**
+ * @return bool|int
+ */
+ protected function createSegments()
+ {
+ $this->setAdminUser();
+ $this->api->add('segment 1', 'visitCount<2', $idSite = 1, $autoArchive = true, $enableAllUsers = false);
+ $this->api->add('segment 2', 'countryCode==fr', $idSite = 2, $autoArchive = false, $enableAllUsers = false);
+ $this->api->add('segment 3', 'visitCount<2', $idSite = 1, $autoArchive = true, $enableAllUsers = false);
+
+ $this->setSuperUser();
+ $this->api->add('segment 4', 'countryCode!=fr', $idSite = false, $autoArchive = false, $enableAllUsers = false);
+ $this->api->add('segment 5', 'countryCode!=fr', $idSite = 1, $autoArchive = false, $enableAllUsers = true);
+ $this->api->add('segment 6', 'visitCount<2', $idSite = 2, $autoArchive = true, $enableAllUsers = true);
+
+ $this->setAdminUser();
+ $this->api->add('segment 7', 'visitCount<2', $idSite = 1, $autoArchive = true, $enableAllUsers = false);
+
+ $this->setAnotherAdminUser();
+ $this->api->add('segment 8', 'visitCount<2', $idSite = 1, $autoArchive = true, $enableAllUsers = false);
+
+ $this->setAnotherSuperUser();
+ $this->api->add('segment 9', 'countryCode!=fr', $idSite = false, $autoArchive = false, $enableAllUsers = true);
+
+ }
+
+ protected function setSuperUser($userName = 'superUserLogin')
+ {
+ FakeAccess::clearAccess($superUser = true, $idSitesAdmin = array(), $idSitesView = array(), $userName);
+ }
+
+ protected function setAnotherSuperUser()
+ {
+ $this->setSuperUser('anotherSuperUser');
+ }
+
+ protected function setAdminUser($userName = 'myUserLogin')
+ {
+ FakeAccess::clearAccess($superUser = false, $idSitesAdmin = array(1,2), $idSitesView = array(1,2), $userName);
+ }
+
+ protected function setAnotherAdminUser()
+ {
+ $this->setAdminUser('anotherUserWithAdmin');
+ }
+
+ public function provideContainerConfig()
+ {
+ return array(
+ 'Piwik\Access' => new FakeAccess()
+ );
+ }
+
+ protected function createAdminUser()
+ {
+ \Piwik\Plugins\UsersManager\API::getInstance()->addUser('myUserLogin', 'password', 'test@test.com');
+ }
+
+ /**
+ * @param $segments
+ * @return array
+ */
+ protected function getNamesFromSegments($segments)
+ {
+ $segmentNames = array();
+ foreach ($segments as $segment) {
+ $segmentNames[] = $segment['name'];
+ }
+ return $segmentNames;
+ }
+
+}
diff --git a/tests/PHPUnit/Framework/Fixture.php b/tests/PHPUnit/Framework/Fixture.php
index 3f66bd3a76..9ef26bbb67 100644
--- a/tests/PHPUnit/Framework/Fixture.php
+++ b/tests/PHPUnit/Framework/Fixture.php
@@ -612,6 +612,7 @@ class Fixture extends \PHPUnit_Framework_Assert
self::assertEquals($expectedResponse, $response, "Expected GIF beacon, got: <br/>\n"
. var_export($response, true)
. "\n If you are stuck, you can enable [Tracker] debug=1; in config.ini.php to get more debug info."
+ . "\n\n Also, please try to restart your webserver, and run the test again, this may help!"
. base64_encode($response)
. $url
);