diff --git a/admin/themes/default/js/group_list.js b/admin/themes/default/js/group_list.js
index c1ed58a40..d455c42c4 100644
--- a/admin/themes/default/js/group_list.js
+++ b/admin/themes/default/js/group_list.js
@@ -1,7 +1,7 @@
const DELAY_FEEDBACK = 3000;
/*-------
-Group Popup
+Group Popin
-------*/
$(".group_details_popup_trigger").click(function () {
@@ -84,31 +84,8 @@ jQuery(document).ready(function () {
data = jQuery.parseJSON(raw_data);
if (data.stat === "ok") {
$(".addGroupFormLabelAndInput input").val('');
- id = data.result.groups[0].id;
- //Setup the group
- newgroup = $("#group-template").clone().attr("id", "group-" + id);
- newgroup.css("order", -id);
- newgroup.attr("data-id", id);
- newgroup.find("#group_name").html(name);
- newgroup.find(".group_name-editable").val(name);
- newgroup.find(".Group-checkbox label").attr("for", "Group-Checkbox-selection-" + id);
- newgroup.find(".Group-checkbox input").attr("id", "Group-Checkbox-selection-" + id);
- newgroup.find(".input-edit-group-name").attr("placeholder", name);
- newgroup.find(".group_number_users").html("0 " + str_member_default);
- newgroup.find(".group_name-editable").html(name);
- hideAddGroupForm();
- //Setup the icon color
- var colors = [["#ffa744", "#ffe9cf"],["#896af3", "#e0daf4"], ["#6ece5e","#d6ffcf"],["#2883c3","#cfebff"]];
- var colorId = Number(id)%4;
- newgroup.find(".icon-users-1").attr("style", "color:"+colors[colorId][0]+"; background-color:"+colors[colorId][1]);
-
- setupGroupBox(newgroup);
-
- //Place group in first Place
- newgroup.appendTo(".groups");
- newgroup.find(".groupMessage").html(str_group_created);
- newgroup.find(".groupMessage").fadeIn();
- newgroup.find(".groupMessage").delay(DELAY_FEEDBACK).fadeOut();
+ group = data.result.groups[0];
+ createGroup(group)
} else {
$("#addGroupForm .groupError").html(str_name_taken);
$("#addGroupForm .groupError").fadeIn();
@@ -122,6 +99,33 @@ jQuery(document).ready(function () {
});
});
+var createGroup = function(group) {
+ //Setup the group
+ newgroup = $("#group-template").clone().attr("id", "group-" + group.id);
+ newgroup.css("order", -group.id);
+ newgroup.attr("data-id", group.id);
+ newgroup.find("#group_name").html(group.name);
+ newgroup.find(".group_name-editable").val(group.name);
+ newgroup.find(".Group-checkbox label").attr("for", "Group-Checkbox-selection-" + group.id);
+ newgroup.find(".Group-checkbox input").attr("id", "Group-Checkbox-selection-" + group.id);
+ newgroup.find(".input-edit-group-name").attr("placeholder", group.name);
+ newgroup.find(".group_number_users").html(group.nb_users+" " + ((group.nb_users > 1)? str_members_default:str_member_default));
+ newgroup.find(".group_name-editable").html(group.name);
+ hideAddGroupForm();
+ //Setup the icon color
+ var colors = [["#ffa744", "#ffe9cf"],["#896af3", "#e0daf4"], ["#6ece5e","#d6ffcf"],["#2883c3","#cfebff"]];
+ var colorId = Number(group.id)%4;
+ newgroup.find(".icon-users-1").attr("style", "color:"+colors[colorId][0]+"; background-color:"+colors[colorId][1]);
+
+ setupGroupBox(newgroup);
+
+ //Place group in first Place
+ newgroup.appendTo(".groups");
+ newgroup.find(".groupMessage").html(str_group_created);
+ newgroup.find(".groupMessage").fadeIn();
+ newgroup.find(".groupMessage").delay(DELAY_FEEDBACK).fadeOut();
+}
+
/*-------
SETUP JS ON GROUP BOX
-------*/
@@ -215,8 +219,15 @@ var setupGroupBox = function (groupBox) {
/* Hide group options and rename field on click on the screen */
$(document).mouseup(function (e) {
- if ($(e.target).closest("#group-"+id+" #GroupOptions").length === 0) {
- groupBox.find(".group-dropdown-options #GroupOptions").hide();
+ e.stopPropagation();
+ let option_is_clicked = false
+ $("#GroupOptions div").each(function () {
+ if (!($(this).has(e.target).length === 0)) {
+ option_is_clicked = true;
+ }
+ })
+ if (!option_is_clicked) {
+ groupBox.find("#GroupOptions").hide();
}
});
@@ -229,6 +240,7 @@ var setupGroupBox = function (groupBox) {
groupBox.find(".manage-users").on("click", function(){openUserManager(id)});
+ groupBox.find("#GroupDuplicate").on("click", function(){duplicateAction(id)})
};
@@ -289,6 +301,7 @@ var deleteGroup = function (id) {
if (data.stat === "ok") {
$("#group-" + id).remove();
$(".DeleteGroupList div[data-id="+id+"]").remove()
+ $("#MergeOptionsChoices option[value="+ id +"]").remove()
resolve();
}
},
@@ -393,6 +406,47 @@ var setupDefaultActions = function(id, is_default) {
}
}
+var duplicateAction = function(id) {
+ let loadState = new TemporaryState();
+ loadState.changeHTML($("#group-" + id + " #GroupDuplicate"), " ")
+ loadState.removeClass($("#group-" + id + " #GroupDuplicate"), "icon-docs");
+ loadState.changeAttribute($("#group-" + id + " #GroupDuplicate"), "style", "pointer-events: none; text-align: center;")
+ copy_name = $("#group-" + id + " #group_name").html() + str_copy;
+
+ let name_exist = function(name) {
+ exist = false;
+ $(".Group-name-container p").each(function () {
+ if ($(this).html() === name)
+ exist = true
+ })
+ return exist;
+ }
+
+ let i = 1;
+ while (name_exist(copy_name))
+ {
+ copy_name = $("#group-" + id + " #group_name").html() + str_other_copy.replace("%s", i++)
+ }
+
+ jQuery.ajax({
+ url: "ws.php?format=json&method=pwg.groups.duplicate",
+ type: "POST",
+ data: "group_id=" + id + "&pwg_token=" + pwg_token + "©_name=" + copy_name,
+ success: function (raw_data) {
+ data = jQuery.parseJSON(raw_data);
+ console.log(data);
+ loadState.reverse();
+ if (data.stat === "ok") {
+ group = data.result.groups[0];
+ createGroup(group);
+ }
+ },
+ error: function (err) {
+ console.log(err);
+ },
+ });
+}
+
/*-------
Selection mode toggle actions,
@@ -512,12 +566,18 @@ $('.ConfirmMergeButton').on("click", function() {
loadState.removeClass($('.ConfirmMergeButton'), "icon-ok");
merge_group = [];
str_merge_group = "";
+ name_merge = [];
+ name_dest = [];
dest_grp = $("#MergeOptionsChoices").val();
$(".DeleteGroupList div").each(function () {
- if (dest_grp != $(this).attr("data-id")) {
+ if (dest_grp != $(this).attr("data-id"))
+ {
str_merge_group += "&merge_group_id[]="+$(this).attr("data-id");
merge_group.push($(this).attr("data-id"));
+ name_merge.push($(this).find("p").html())
+ } else {
+ name_dest = $(this).find("p").html();
}
})
@@ -540,6 +600,23 @@ $('.ConfirmMergeButton').on("click", function() {
$(".DeleteGroupList").html("");
$("#MergeOptionsChoices").html("");
+ $.alert({
+ title: str_merged_into
+ .replace("%s1",name_merge.toString())
+ .replace("%s2",name_dest),
+ icon: 'icon-ok',
+ titleClass: "groupDeleteAlert",
+ theme:"modern",
+ closeIcon: true,
+ content: "",
+ animation: "zoom",
+ boxWidth: '20%',
+ useBootstrap: false,
+ backgroundDismiss: true,
+ animateFromElement: false,
+ typeAnimated: false,
+ });
+
$("#group-"+dest_grp + " .group_number_users").html(" ");
jQuery.ajax({
url: "ws.php?format=json&method=pwg.users.getList",
@@ -564,11 +641,11 @@ $('.ConfirmMergeButton').on("click", function() {
$('.ConfirmDeleteButton').on("click", function() {
let names = [];
- let promises = [];
+ let ids = [];
$('.DeleteGroupList div').each(function () {
let id = $(this).data('id');
names.push($("#group-"+id+" #group_name").html());
- promises.push(deleteGroup(id));
+ ids.push(id);
});
let loadState = new TemporaryState;
@@ -576,25 +653,47 @@ $('.ConfirmDeleteButton').on("click", function() {
loadState.changeHTML($('.ConfirmDeleteButton'), " ");
loadState.removeClass($('.ConfirmDeleteButton'),"icon-ok");
- Promise.all(promises).then(() => {
- loadState.reverse();
- updateSelectionPanel("NoSelection");
- $.alert({
- title: str_groups_deleted.replace("%s",names.toString()),
- titleClass: "groupDeleteAlert",
- theme: "modern",
- icon: 'icon-ok',
- closeIcon: true,
- content: "",
- animation: "zoom",
- boxWidth: '20%',
- useBootstrap: false,
- backgroundDismiss: true,
- animateFromElement: false,
- typeAnimated: false,
- backgroundDismiss: true,
- });
+ str_id = ""
+ ids.forEach(function(id) {
+ str_id += "group_id[]=" + id + "&"
})
+
+ jQuery.ajax({
+ url: "ws.php?format=json&method=pwg.groups.delete",
+ type: "POST",
+ data: str_id + "pwg_token=" + pwg_token,
+ success: function (raw_data) {
+ data = jQuery.parseJSON(raw_data);
+ if (data.stat === "ok") {
+ $(".DeleteGroupList div").each(function() {
+ $(this).remove();
+ $("#group-" + $(this).attr("data-id")).remove();
+ $("#MergeOptionsChoices option[value="+ $(this).attr("data-id") +"]").remove()
+ })
+
+ loadState.reverse();
+ updateSelectionPanel("NoSelection");
+ $.alert({
+ title: str_groups_deleted.replace("%s",names.toString()),
+ titleClass: "groupDeleteAlert",
+ theme: "modern",
+ icon: 'icon-ok',
+ closeIcon: true,
+ content: "",
+ animation: "zoom",
+ boxWidth: '20%',
+ useBootstrap: false,
+ backgroundDismiss: true,
+ animateFromElement: false,
+ typeAnimated: false,
+ backgroundDismiss: true,
+ });
+ }
+ },
+ error: function (err) {
+ console.log(err);
+ },
+ });
});
/*-------
@@ -671,6 +770,7 @@ var openUserManager = function(grp_id) {
loadState.reverse();
data = jQuery.parseJSON(raw_data);
if (data.stat === "ok") {
+ //Set the popin name
$(".group-name-block p").html(
$("#group-" + grp_id + " #group_name").html() + " / " + str_user_list
)
@@ -684,12 +784,12 @@ var openUserManager = function(grp_id) {
// Sort in alphabetic order
usersInGroup.sort(function( a, b ) {
if ( a.username.toLowerCase() < b.username.toLowerCase() ){
- return 1;
- } else return -1
+ return -1;
+ } else return 1
});
let i = 0;
while ($(".UsersInGroupList").outerHeight() <= maxOffsetUserCont && usersInGroup[i] != undefined){
- getUserDisplay(usersInGroup[i].username, usersInGroup[i].id, grp_id).prependTo(".UsersInGroupList");
+ getUserDisplay(usersInGroup[i].username, usersInGroup[i].id, grp_id).appendTo(".UsersInGroupList");
i++;
};
while ($(".UsersInGroupList").height() > maxOffsetUserCont) {
@@ -806,7 +906,6 @@ $(".AddUserBlock button").on("click", function () {
associateUserInfo.insertAfter(userBlock);
associateUserInfo.find("p").html(str_user_associated);
associateUserInfo.fadeIn()
- associateUserInfo.delay(DELAY_FEEDBACK).fadeOut()
updateUserSearch();
@@ -846,7 +945,7 @@ $(".input-user-name").on("input", function() {
let i = 0;
while ($(".UsersInGroupList").outerHeight() <= maxOffsetUserCont && usersInGroup[i] != undefined){
getUserDisplay(usersInGroup[i].username, usersInGroup[i].id, grp_id)
- .prependTo(".UsersInGroupList");
+ .appendTo(".UsersInGroupList");
i++;
}
}
diff --git a/admin/themes/default/template/group_list.tpl b/admin/themes/default/template/group_list.tpl
index 7e69cfc18..197ac8334 100644
--- a/admin/themes/default/template/group_list.tpl
+++ b/admin/themes/default/template/group_list.tpl
@@ -13,8 +13,11 @@ var str_delete = '{'Delete group "%s"?'|@translate}'
var str_yes_delete_confirmation = "{'Yes, delete'|@translate}"
var str_no_delete_confirmation = "{"No, I have changed my mind"|@translate}"
var str_user_associated = "{"User associated"|@translate}"
-var str_user_dissociated = '{'User "%s" Dissociated from this group'|@translate}'
+var str_user_dissociated = '{'User "%s" dissociated from this group'|@translate}'
var str_user_list = "{"User List"|@translate}"
+var str_merged_into = '{'Group(s) \{%s1\} succesfully merged into "%s2"'|@translate}'
+var str_copy = '{' (copy)'|@translate}'
+var str_other_copy = '{' (copy %s)'|@translate}'
var serverKey = '{$CACHE_KEYS.users}'
var serverId = '{$CACHE_KEYS._hash}'
diff --git a/admin/themes/default/theme.css b/admin/themes/default/theme.css
index 48d269f3f..e014321d7 100644
--- a/admin/themes/default/theme.css
+++ b/admin/themes/default/theme.css
@@ -2050,6 +2050,10 @@ input:checked + .slider:before {
line-height: 28px !important;
}
+.groupDeleteAlert {
+ margin-bottom: -2px !important;
+}
+
.groupDeleteConfirm ~ .jconfirm-content-pane, .groupDeleteAlert ~ .jconfirm-content-pane {
height: 0px !important;
margin: 0px !important;
@@ -2070,7 +2074,7 @@ input:checked + .slider:before {
}
.groupDeleteAlert .jconfirm-icon-c {
- margin-bottom: 20px !important;
+ margin-bottom: 25px !important;
}
/*Group checkbox*/
diff --git a/include/ws_functions/pwg.groups.php b/include/ws_functions/pwg.groups.php
index 5d6c7fabb..668385acc 100644
--- a/include/ws_functions/pwg.groups.php
+++ b/include/ws_functions/pwg.groups.php
@@ -316,6 +316,97 @@ SELECT user_id
);
}
+/**
+ * API method
+ * Create a copy of a group
+ * @param mixed[] $params
+ * @option int group_id
+ * @option string copy_name
+ */
+function ws_groups_duplicate($params, &$service) {
+
+ if (get_pwg_token() != $params['pwg_token'])
+ {
+ return new PwgError(403, 'Invalid security token');
+ }
+
+ $query = '
+SELECT COUNT(*)
+ FROM `'.GROUPS_TABLE.'`
+ WHERE name = \''.$params['copy_name'].'\'
+;';
+ list($count) = pwg_db_fetch_row(pwg_query($query));
+ if ($count != 0)
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, 'This name is already used by another group.');
+ }
+
+ $query = '
+SELECT COUNT(*)
+ FROM `'. GROUPS_TABLE .'`
+ WHERE id = '.$params["group_id"].'
+;';
+ list($count) = pwg_db_fetch_row(pwg_query($query));
+ if ($count == 0)
+ {
+ return new PwgError(WS_ERR_INVALID_PARAM, 'This group does not exist.');
+ }
+
+ $query = '
+SELECT is_default
+ FROM `'. GROUPS_TABLE .'`
+ WHERE id = '.$params['group_id'].'
+;';
+
+ $is_default = pwg_db_fetch_row(pwg_query($query))[0];
+
+ // creating the group
+ single_insert(
+ GROUPS_TABLE,
+ array(
+ 'name' => $params['copy_name'],
+ 'is_default' => boolean_to_string($is_default),
+ )
+ );
+ $inserted_id = pwg_db_insert_id();
+
+ pwg_activity('group', $inserted_id, 'add');
+
+ $query = '
+ SELECT user_id
+ FROM `'. USER_GROUP_TABLE .'`
+ WHERE group_id = '.$params['group_id'].'
+ ;';
+
+ $users = query2array($query, null, 'user_id');
+
+ $inserts = array();
+ foreach ($users as $user)
+ {
+ $inserts[] = array(
+ 'group_id' => $inserted_id,
+ 'user_id' => $user,
+ );
+ }
+
+ mass_inserts(
+ USER_GROUP_TABLE,
+ array('group_id', 'user_id'),
+ $inserts,
+ array('ignore'=>true)
+ );
+
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+ invalidate_user_cache();
+
+ foreach ($users as $user_id)
+ {
+ pwg_activity('user', $user_id, 'edit', array("associated" => $params['group_id']));
+ }
+
+ return $service->invoke('pwg.groups.getList', array('group_id' => $inserted_id));
+}
+
/**
* API method
* Removes user(s) from a group
diff --git a/ws.php b/ws.php
index f85469fcc..c3c9dddd7 100644
--- a/ws.php
+++ b/ws.php
@@ -915,7 +915,7 @@ function ws_addDefaultMethods( $arr )
'ws_groups_merge',
array(
'destination_group_id' => array('type'=>WS_TYPE_ID,
- 'info'=>'Destination group (is not necessarily part of groups to merge)'),
+ 'info'=>'Is not necessarily part of groups to merge'),
'merge_group_id' => array('flags'=>WS_PARAM_FORCE_ARRAY,
'type'=>WS_TYPE_ID),
'pwg_token' => array(),
@@ -925,6 +925,19 @@ function ws_addDefaultMethods( $arr )
array('admin_only'=>true, 'post_only'=>true)
);
+ $service->addMethod(
+ 'pwg.groups.duplicate',
+ 'ws_groups_duplicate',
+ array(
+ 'group_id' => array('type'=>WS_TYPE_ID),
+ 'copy_name' => array(),
+ 'pwg_token' => array(),
+ ),
+ 'Create a copy of a group',
+ $ws_functions_root . 'pwg.groups.php',
+ array('admin_only'=>true, 'post_only'=>true)
+ );
+
$service->addMethod(
'pwg.users.getList',
'ws_users_getList',