Skip to content

Commit

Permalink
Fixes #6766 Let Super User view and edit segments created by other users
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mattab committed Nov 30, 2015
1 parent 5ce9ba9 commit 3ac3f88
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 34 deletions.
1 change: 1 addition & 0 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
"ConfigFileIsNotWritable": "The Piwik configuration file %s is not writable, some of your changes might not be saved. %s Please change permissions of the config file to make it writable.",
"Continue": "Continue",
"ContinueToPiwik": "Continue to Piwik",
"CreatedByUser": "created by %s",
"CurrentMonth": "Current Month",
"CurrentWeek": "Current Week",
"CurrentYear": "Current Year",
Expand Down
1 change: 1 addition & 0 deletions plugins/CoreHome/CoreHome.php
Original file line number Diff line number Diff line change
Expand Up @@ -278,5 +278,6 @@ public function getClientSideTranslationKeys(&$translationKeys)
$translationKeys[] = 'CoreHome_MenuEntries';
$translationKeys[] = 'SitesManager_Sites';
$translationKeys[] = 'CoreHome_ChangeCurrentWebsite';
$translationKeys[] = 'General_CreatedByUser';
}
}
4 changes: 2 additions & 2 deletions plugins/Dashboard/stylesheets/dashboard.less
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
43 changes: 40 additions & 3 deletions plugins/SegmentEditor/API.php
Original file line number Diff line number Diff line change
Expand Up @@ -352,15 +352,52 @@ public function getAll($idSite = false)
$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
*/
Expand Down
21 changes: 21 additions & 0 deletions plugins/SegmentEditor/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,27 @@ public function getAllSegmentsForSite($idSite, $userLogin)
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();
Expand Down
2 changes: 2 additions & 0 deletions plugins/SegmentEditor/SegmentEditor.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,7 @@ public static function isAddingSegmentsForAllWebsitesEnabled()
public function getClientSideTranslationKeys(&$translationKeys)
{
$translationKeys[] = 'SegmentEditor_CustomSegment';
$translationKeys[] = 'SegmentEditor_VisibleToSuperUser';
$translationKeys[] = 'SegmentEditor_SharedWithYou';
}
}
129 changes: 104 additions & 25 deletions plugins/SegmentEditor/javascripts/Segmentation.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ Segmentation = (function($) {
var foundItems = $(selector, this.target);
var title = $('<strong></strong>');
if( foundItems.length > 0) {
var name = $(foundItems).first().find("span.segname").text();
var idSegment = $(foundItems).first().attr('data-idsegment');
var name = getSegmentNameEnrichedWithUsername( getSegmentFromId(idSegment));
title.text(name);
} else {
title.text(_pk_translate('SegmentEditor_CustomSegment'));
Expand Down Expand Up @@ -203,10 +204,38 @@ Segmentation = (function($) {
+ ' 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) {
Expand All @@ -217,12 +246,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">'+getSegmentNameEnrichedWithUsername(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']);
Expand All @@ -238,6 +276,43 @@ 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 segmentName;
};

var getSegmentNameEnrichedWithUsername = function(segment) {
var segmentName = segment.name;
if(hasSuperUserAccessAndSegmentCreatedByAnotherUser(segment)) {
segmentName += ' (' + _pk_translate('General_CreatedByUser', [segment.login]) + ')';
}
return segmentName;
};

var getFormHtml = function() {
var html = self.editorTemplate.find("> .segment-element").clone();
// set left margin to center form
Expand All @@ -251,7 +326,7 @@ Segmentation = (function($) {
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)+'">'+getSegmentNameEnrichedWithUsername(segment)+'</option>';
segmentsDropdown.append(newOption);
}
$(html).find(".segment-content > h3").after(getInitialStateRowsHtml()).show();
Expand Down Expand Up @@ -327,7 +402,7 @@ Segmentation = (function($) {
$(self.form).find(".segment-content > h3 > span").text(segment.name);
$(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').text(getSegmentNameEnrichedWithUsername(segment));

if(segment.definition != ""){
revokeInitialStateRows();
Expand Down Expand Up @@ -360,13 +435,22 @@ 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 () {
$(self.target).find(" .filterNoResults").remove();
$(self.target).find(".segmentList li").each(function () {
$(this).show();
});
$(self.target).find(".segmentList .segmentsVisibleToSuperUser").show();
$(self.target).find(".segmentList .segmentsSharedWithMeBySuperUser").show();
}

var bindEvents = function () {
Expand Down Expand Up @@ -407,15 +491,14 @@ 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");
var segmentExtra = getSegmentFromId(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);
}
});

Expand Down Expand Up @@ -748,20 +831,11 @@ 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];
}

segment.name = option.attr("title");
var idsegment = option.attr("data-idsegment");

segment.definition = option.data("definition");
var segmentExtra = getSegmentFromId(idsegment);

openEditForm(segment);
openEditForm(segmentExtra);
}

var doDragDropBindings = function(){
Expand Down Expand Up @@ -900,7 +974,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);

Expand Down Expand Up @@ -1166,7 +1245,7 @@ $(document).ready(function() {
}
}

self.props.availableSegments[idx] = params;
$.extend( self.props.availableSegments[idx], params);
self.rebuild();

self.impl.setSegment(params.definition);
Expand Down
4 changes: 3 additions & 1 deletion plugins/SegmentEditor/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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:",
"SelectSegmentOfVisitors": "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.",
Expand Down
Loading

0 comments on commit 3ac3f88

Please sign in to comment.