All Downloads are FREE. Search and download functionalities are using the official Maven repository.

SLING-INF.content.dev.lib.sakai.sakai.api.groups.js Maven / Gradle / Ivy

/*
 * Licensed to the Sakai Foundation (SF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The SF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
/**
 * @class Groups
 *
 * @description
 * Group related convenience functions. This should only hold functions
 * which are used across multiple pages, and does not constitute functionality
 * related to a single area/page
 *
 * @namespace
 * Group related convenience functions
 */
define(
    [
        "jquery",
        "config/config_custom",
        "sakai/sakai.api.server",
        "sakai/sakai.api.util",
        "sakai/sakai.api.i18n",
        "sakai/sakai.api.user",
        "sakai/sakai.api.communication",
        "underscore"
    ],
    function($, sakai_conf, sakai_serv, sakai_util, sakai_i18n, sakai_user, sakai_comm, _){

    var sakaiGroupsAPI = {
        /**
         * Get the data for the specified group
         *
         * @param {String} groupid The ID of the group
         * @param {Function} callback Callback function, passes (success, (data|xhr))
         * @param {Boolean} async If this call should be ascynronous, defaults to true
         */
        getGroupData : function(groupid, callback, async, cache) {
            if (async === null || async === undefined) {
                async = true;
            }
            if (cache !== false) {
                cache = true;
            }
            $.ajax({
                url: "/~" + groupid + "/public.infinity.json",
                async: async,
                cache: cache,
                success: function(data) {
                    if ($.isFunction(callback)) {
                        callback(true, data);
                    }
                },
                error: function(xhr, textStatus, thrownError) {
                    debug.error("Could not get data for group " + groupid);
                    if ($.isFunction(callback)) {
                        callback(false, xhr);
                    }
                }
            });
        },

        groupData : {},

        /**
         * Get the data for the specified group
         *
         * @param {Object} groupids The ID of the group or an array of group IDs
         * @param {Function} callback Callback function, passes (success, (data|xhr))
         * @param {Boolean} async If this call should be ascynronous, defaults to true
         */
        getGroupAuthorizableData : function(groupids, callback) {
            var toReturn = {};
            var batchRequest = [];
            if (_.isString(groupids)){
                groupids = [groupids];
            }
            $.each(groupids, function(index, groupid){
                if ($.isPlainObject(sakaiGroupsAPI.groupData[groupid])) {
                    toReturn[groupid] = sakaiGroupsAPI.groupData[groupid];
                } else {
                    batchRequest.push({
                        url: "/system/userManager/group/" + groupid + ".json",
                        method: "GET"
                    });
                }
            });
            sakai_serv.batch(batchRequest, function(success, response){
                $.each(response.results, function(index, item){
                    var group = $.parseJSON(item.body);
                    sakaiGroupsAPI.groupData[group.properties["sakai:group-id"]] = group;
                    toReturn[group.properties["sakai:group-id"]] = group;
                });
                if ($.isFunction(callback)){
                    callback(true, toReturn);
                }
            });
        },

        checkIfGroupExists : function(groupid) {
            // Check if the group exists.
            var groupExists = false;
            $.ajax({
                url: "/~" + groupid + ".json",
                type: "GET",
                async: false,
                success: function(data, textStatus) {
                    groupExists = true;
                }
            });
            return groupExists;
        },

        /**
         * Create a group
         * @param {String} id the id of the group that's being created
         * @param {String} title the title of the group that's being created
         * @param {String} description the description of the group that's being created
         * @param {Array} tags The tags to tag the group with on creation
         * @param {Array} users An array of users of the format:
         *  "name": user name
         *  "firstName": user's first name
         *  "userid": user's userid
         *  "role": the permission to give the user (manager, member, ta)
         *  "roleString": The translated role string to give the user ("Member", "Manager", "Teaching Assistant")
         *  "creator": true | false (if this user is the creator of the group)
         * @param {String} joinability The joinability of the group (yes, no, withauth)
         * @param {String} visibility The visibility of the group (members-only, logged-in-only, public)
         * @param {String} templatePath The path in the /var/templates/worlds space for this template, without .json (/var/templates/worlds/group/basic-group)
         * @param {String} subject The tokenized subject of the message (translated) to send to the users joined to this group
         * @param {String} body The body of the aforementioned message in the same format
         * @param {Object} meData The sakai.data.me object
         * @param {Function} callback the callback function for when the group save is complete. It will pass
         *                            two params, success {Boolean} and nameTaken {Boolean}
        */
        createGroup : function(id, title, description, tags, users, joinability, visibility, templatePath, subject, body, meData, callback) {
            var data = {
                "id" : id,
                "title" : title,
                "tags" : tags,
                "description" : description,
                "visibility" : visibility,
                "joinability" : joinability,
                "worldTemplate" : templatePath,
                'schemaVersion': sakai_conf.schemaVersion,
                "message" : {
                    "body" : body,
                    "subject" : subject,
                    "creatorName" : sakai_user.getDisplayName(meData.profile),
                    "groupName" : title,
                    "system" : sakai_i18n.getValueForKey("SAKAI"),
                    "link" : sakai_conf.SakaiDomain + "/~" + id,
                    "toSend" : []
                },
                "usersToAdd" : []
            };
            $.each(users, function(i,user) {
                data.usersToAdd.push({
                    "userid": user.userid,
                    "role": user.role
                });
                if (!user.creator) {
                    data.message.toSend.push({
                        "userid": user.userid,
                        "firstName": user.firstName,
                        "role": user.roleString,
                        "messageMode": "both"
                    });
                }
            });

            $.ajax({
                url: sakai_conf.URL.WORLD_CREATION_SERVICE,
                data: {data: $.toJSON(data)},
                type: "POST",
                success: function(_data, textStatus){
                    callback(true, data);
                },
                error: function(){
                    callback(false, data);
                }
            });
        },

        /**
         * Delete a group
         * @param {String} id the id of the group that's being deleted
         * @param {Function} callback the callback function for when the group delete is complete.
        */
        deleteGroup : function(groupID, meData, callback) {
            sakaiGroupsAPI.getGroupAuthorizableData(groupID, function(success, groupAuthData){
                if (success && groupAuthData) {
                    groupAuthData = groupAuthData[groupID];
                    var groupArray = [groupID];

                    // delete any pseudo groups
                    if (groupAuthData.properties["sakai:roles"]) {
                        var roles = $.parseJSON(groupAuthData.properties["sakai:roles"]);
                        if (roles && roles.length > 0) {
                            for (var r = 0; r < roles.length; r++) {
                                groupArray.push(groupID + "-" + roles[r].id);
                            }
                        }
                    }

                    // delete the group
                    $.ajax({
                        url: "/system/userManager.delete.json",
                        type: "POST",
                        traditional: true,
                        data: {
                            ":applyTo": groupArray
                        },
                        success: function(data){
                            if ($.isFunction(callback)) {
                                callback(true);
                            }
                        },
                        error: function(){
                            if ($.isFunction(callback)) {
                                callback(false);
                            }
                        }
                    });
                } else if ($.isFunction(callback)) {
                    callback(false);
                }
            });
        },

        /**
         * Update group basic information
         *
         * @param {String} id The id of the group to update
         * @param {String} title The new title of the group
         * @param {String} description The new description of the group
         * @param {String} kind The kind of group, defined in (TODO define this somewhere, currently only in groupbasicinfo.html)
         * @param {Function} callback Callback function, passes (success)
         */
        updateGroupInfo : function(id, title, description, kind, callback) {
            var groupProfileURL = "/~" + id + "/public/authprofile.profile.json";

            $.ajax({
                url: groupProfileURL,
                data: {
                    "_charset_":"utf-8",
                    "sakai:group-title" : title,
                    "sakai:group-description" : description,
                    "sakai:group-kind" : kind
                },
                type: "POST",
                error: function(xhr, textStatus, thrownError){
                    debug.error("Unable to update group information.");
                },
                complete: function(xhr, textStatus) {
                    if ($.isFunction(callback)) {
                        callback(textStatus === "success");
                    }
                }
            });
        },

        /**
         * Update group profile
         *
         * @param {String} id The id of the group to update
         * @param {Object} profile The group's profile
         * @param {Array} tags The group's tags
         * @param {Object} groupData The group's authprofile data - need this for role extraction
         * @param {Function} callback Callback function, passes (success, updated)
         */
        updateGroupProfile : function(id, profile, tags, groupData, callback) {
            var groupProfileURL = "/~" + id + "/public/authprofile";
            var groupProfileSaveURL = groupProfileURL + ".profile.json";
            var batch = [];
            var doProfilePost = false,
                doTagsPost = false,
                doPermissionPost = false;

            var updatePermissions = function(_callback) {
                var roles = $.parseJSON(groupData["sakai:roles"]);
                sakaiGroupsAPI.setPermissions(id, profile[ "sakai:group-joinable" ], profile[ "sakai:group-visible" ], roles, function( success, data ) {
                    if ( $.isFunction( _callback ) ) {
                        _callback( success );
                    }
                });
            };

            var updateProfile = function(_callback) {
                sakai_serv.batch( batch, function( success, data ) {
                    if ( $.isFunction( _callback ) ) {
                        _callback( success );
                    }
                });
            };

            // Get the difference of the tags arrays. If there is one, then we should update it
            groupData[ "sakai:tags" ] = groupData[ "sakai:tags" ] || [];
            var merged = _.uniq( $.merge( $.merge( [], tags ), groupData[ "sakai:tags" ] ) );
            if ( merged.length !== tags.length || merged.length !== groupData[ "sakai:tags" ].length ) {
                doTagsPost = true;
            }

            if ( groupData[ "sakai:group-joinable" ] !== profile[ "sakai:group-joinable" ] || groupData[ "sakai:group-visible" ] !== profile[ "sakai:group-visible" ] ) {
                doPermissionPost = true;
            }

            $.each( profile, function(i, data) {
                if ( groupData[i] !== data ) {
                    doProfilePost = true;
                    // Update the group data immediately
                    groupData[i] = data;
                }
            });

            if ( doProfilePost || doTagsPost || doPermissionPost ) {
                if ( doProfilePost ) {
                    batch.push({
                        "url": groupProfileSaveURL,
                        "method": "POST",
                        "parameters": profile
                    });
                    // Also update the pseudo-groups sakai:parent-group-title property
                    var roles = $.parseJSON(groupData["sakai:roles"]);
                    $.each(roles, function(i, role) {
                        batch.push({
                            "url": "/system/userManager/group/" + id + "-" + role.id + ".update.json",
                            "method": "POST",
                            "parameters": {
                                "sakai:parent-group-title": profile["sakai:group-title"]
                            }
                        });
                    });
                }

                // Always call tagEntity, it has it's own internal 'no POSTing if no changes' mechanism
                sakai_util.tagEntity( groupProfileURL, tags, groupData[ "sakai:tags" ], function( success, newTags ) {
                    groupData[ "sakai:tags" ] = newTags;

                    if ( doProfilePost ) {
                        updateProfile(function(success, data) {
                            if ( doPermissionPost ) {
                                updatePermissions(function(success, data) {
                                    if ( $.isFunction( callback ) ) {
                                        callback( success );
                                    }
                                });
                            } else {
                                if ( $.isFunction( callback ) ) {
                                    callback( success );
                                }
                            }
                        });
                    } else if ( doPermissionPost ) {
                        updatePermissions(function(success, data) {
                            if ( $.isFunction( callback ) ) {
                                callback( success );
                            }
                        });
                    } else {
                        if ( $.isFunction( callback ) ) {
                            callback( success );
                        }
                    }
                });
            } else {
                callback( true );
            }
        },

        /**
         * Checks whether the given value is valid as defined by the given
         * permissionsProperty.
         *
         * @param {Object} permissionsProperty Permissions property object
         *   (i.e. sakai.config.Permissions.Groups.joinable) with valid values to check
         *   against
         * @param {Object} value Value to investigate
         * @return true if the value has a valid property value, false otherwise
         */
        isValidPermissionsProperty : function(permissionsProperty, value) {
            if(!value || value === "") {
                // value is empty - not valid
                return false;
            }
            for(var index in permissionsProperty) {
                if(permissionsProperty.hasOwnProperty(index)) {
                    if(value === permissionsProperty[index]) {
                        // value is valid
                        return true;
                    }
                }
            }
            // value is not valid
            return false;
        },

        /**
         * Public function used to set joinability and visibility permissions for a
         * group with groupid.
         *
         * @param {String} groupid The id of the group that needs permissions set
         * @param {String} joinable The joinable state for the group (from sakai.config.Permissions.Groups)
         * @param {String} visible The visibile state for the group (from sakai.config.Permissions.Groups)
         * @param {Array} roles The roles for this group, from the "sakai:roles" property of the group
         * @param {Function} callback Function to be called on complete - callback
         *   args: (success)
         * @return None
         */
        setPermissions : function(groupid, joinable, visible, roles, callback) {
            if ( groupid && _.isString(groupid) &&
               this.isValidPermissionsProperty(sakai_conf.Permissions.Groups.joinable, joinable) &&
               this.isValidPermissionsProperty(sakai_conf.Permissions.Groups.visible, visible)) {

                // issue a BATCH POST to update Jackrabbit group & Home Folder group
                var batchRequests = [];
                // add in the main group, we need to modify their permissions too
                roles.push({id:groupid});
                $.each(roles, function(i, role) {
                    var groupURL = groupid;
                    if (role.id !== groupid) {
                        groupURL += "-" + role.id;
                    }
                    var groupUpdateURL = "/system/userManager/group/" + groupURL + ".update.html";

                    // determine visibility state
                    if (visible === sakai_conf.Permissions.Groups.visible.members) {
                        // visible to members only, so remove everyone & anonymous, as they're not a member
                        batchRequests.push({
                            "url": groupUpdateURL,
                            "method": "POST",
                            "parameters": {
                                ":viewer@Delete":
                                [
                                    "everyone",
                                    "anonymous"
                                ],
                                "sakai:group-visible": visible,
                                "sakai:group-joinable": joinable
                            }
                        });
                    } else if (visible === sakai_conf.Permissions.Groups.visible.allusers) {
                        // visible to all logged in users
                        // remove anonymous, as this is only for logged in users
                        batchRequests.push({
                            "url": groupUpdateURL,
                            "method": "POST",
                            "parameters": {
                                ":viewer": "everyone",
                                ":viewer@Delete": "anonymous",
                                "sakai:group-visible": visible,
                                "sakai:group-joinable": joinable
                            }
                        });
                    } else {
                        // visible to the public
                        // all logged in users 'everyone'
                        // all non-logged in users 'anonymous'
                        batchRequests.push({
                            "url": groupUpdateURL,
                            "method": "POST",
                            "parameters": {
                                ":viewer":
                                [
                                    "everyone",
                                    "anonymous"
                                ],
                                "sakai:group-visible": visible,
                                "sakai:group-joinable": joinable
                            }
                        });
                    }
                });


                // issue the BATCH POST
                sakai_serv.batch(batchRequests, function(success, data) {
                    if (success) {
                        // update group context and call callback
                        if(sakai_global.currentgroup && sakai_global.currentgroup.data && sakai_global.currentgroup.data.authprofile) {
                            sakai_global.currentgroup.data.authprofile["sakai:group-joinable"] = joinable;
                            sakai_global.currentgroup.data.authprofile["sakai:group-visible"] = visible;
                        }
                        if ($.isFunction(callback)) {
                            callback(true);
                        }
                    } else {
                        // Log an error message
                        debug.error("Setting permissions on the group failed");
                        if ($.isFunction(callback)) {
                            callback(false);
                        }
                    }
                });
            } else {
                debug.warn("Invalid arguments sent to sakai.api.Groups.setPermissions");
                if ($.isFunction(callback)) {
                    callback(false);
                }
            }
        },


        /**
         * Determines whether the current user is a manager of the given group.
         *
         * @param groupid {String} id of the group to check
         * @param {Object} meData the data from sakai.api.User.data.me
         * @return true if the current user is a manager, false otherwise
         */
        isCurrentUserAManager : function(groupid, meData, groupinfo) {
            if (groupinfo) {
                var managementRoles = [];
                var roles = $.parseJSON(groupinfo["sakai:roles"]);
                for (var r = 0; r < roles.length; r++) {
                    if (roles[r].isManagerRole) {
                        managementRoles.push(roles[r].id);
                    }
                }
                var canManage = false;
                for (var i = 0; i < meData.groups.length; i++) {
                    for (var mr = 0; mr < managementRoles.length; mr++) {
                        if (meData.groups[i]["sakai:group-id"] === groupinfo["sakai:group-id"] + "-" + managementRoles[mr]) {
                            canManage = true;
                        }
                    }
                }
                return canManage;
            } else {
                if (!groupid || typeof(groupid) !== "string") {
                    return false;
                }
                var managersGroupId = groupid + "-manager";
                return $.inArray(managersGroupId, meData.user.subjects) !== -1;
            }
        },


        /**
         * Determines whether the current user is a member of the given group.
         * Managers are considered members of a group. If the current user is a manager
         * of the group, this function will return true.
         *
         * @param groupid {String} id of the group to check
         * @param {Object} meData the data from sakai.api.User.data.me
         * @return true if the current user is a member or manager, false otherwise
         */
        isCurrentUserAMember : function(groupid, meData) {
            if(!groupid || typeof(groupid) !== "string") {
                return false;
            }
            return $.inArray(groupid, meData.user.subjects) !== -1;
        },


        /**
         * Determines whether the current user is allowed to leave the group
         *
         * @param groupid {String} id of the group to check
         * @param {Object} meData the data from sakai.api.User.data.me
         * @param {Function} callback Function to be called on complete - callback
         */
        isAllowedToLeave : function(groupids, meData, callback) {
            sakaiGroupsAPI.getGroupAuthorizableData(groupids, function(groupSuccess, groupData){
                var toReturn = {};
                var groupDataCache = {};
                var toCheck = [];
                $.each(groupData, function(groupid, group){
                    if (sakaiGroupsAPI.isCurrentUserAManager(groupid, meData, group.properties)) {
                        // Check if there is more then one manager in the group
                        toCheck.push(groupid);
                        groupDataCache[groupid] = group.properties;
                    } else {
                        // Members are always allowed to leave the group, managers should always be present and cannot leave when they are the last one in the group
                        toReturn[groupid] = true;
                    }
                });
                sakaiGroupsAPI.getMembers(toCheck, function(membersSuccess, memberData){
                    $.each(memberData, function(groupid, members){
                        var numManagers = sakaiGroupsAPI.getManagerCount(groupDataCache[groupid], members);
                        toReturn[groupid] = numManagers > 1;
                    });
                    if ($.isFunction(callback)) {
                        callback(toReturn);
                    }
                });
            });
        },

        /**
         * Get the number of managers in the group
         *
         * @param {Object} groupdata The data from the group's authprofile
         * @param {Object} members The result of sakai.api.Groups.getMembers()
         */
        getManagerCount : function(groupdata, members) {
            var managers = 0;
            if (groupdata["sakai:roles"]) {
                var roles = [],
                    managerRoles = [];
                if (_.isString(groupdata["sakai:roles"])) {
                    roles = $.parseJSON(groupdata["sakai:roles"]);
                }
                $.each(roles, function(i, role) {
                    if (role.isManagerRole) {
                        managerRoles.push(role.id);
                    }
                });
                $.each(members, function(i, member) {
                    member = member.results ? member.results : member;
                    if ($.inArray(i, managerRoles) > -1 && member.length) {
                        managers += member.length;
                    }
                });
            }
            return managers;
        },

        /**
         * Creates a join request for the current user for a given group
         * @param {String} groupID     ID of the group to the user wants to join
         * @param {Function} callback  Callback function executed at the end of the
         *                             operation - callback args:
         *  -- {Boolean} success       True if operation succeeded, false otherwise
         */
        addJoinRequest : function(groupID, callback) {
            sakaiGroupsAPI.getGroupAuthorizableData(groupID, function(success, groupData){
                groupData = groupData[groupID];
                sakaiGroupsAPI.getMembers(groupID, function(success, groupMembers){
                    groupMembers = groupMembers[groupID];

                    // Function used to send the join request message to the managers of the
                    // group that's being joined
                    var sendJoinRequestMessage = function(managerArray) {
                        var userString = sakai_user.getDisplayName(sakai_user.data.me.profile);
                        var groupString = groupData.properties["sakai:group-title"];
                        var systemString = sakai_i18n.getValueForKey("SAKAI");
                        var profileLink = sakai_conf.SakaiDomain + "/~" + sakai_util.safeURL(sakai_user.data.me.user.userid);
                        var acceptLink = sakai_conf.SakaiDomain + "/~" + groupData.properties["sakai:group-id"] + "#e=joinrequests";
                        var subject = "",
                            body = "";
                        if (groupData.properties["sakai:group-joinable"] === "withauth") {
                            subject = sakai_i18n.getValueForKey("GROUP_JOIN_REQUEST_TITLE")
                                      .replace(/\$\{sender\}/g, userString)
                                      .replace(/\$\{group\}/g, groupString);
                            body = sakai_i18n.getValueForKey("GROUP_JOIN_REQUEST_BODY")
                                   .replace(/\$\{sender\}/g, userString)
                                   .replace(/\$\{group\}/g, groupString)
                                   .replace(/\$\{system\}/g, systemString)
                                   .replace(/\$\{profilelink\}/g, profileLink)
                                   .replace(/\$\{acceptlink\}/g, acceptLink)
                                   .replace(/\$\{br\}/g,"\n");
                        } else {
                            subject = sakai_i18n.getValueForKey("GROUP_JOINED_TITLE")
                                     .replace(/\$\{sender\}/g, userString)
                                     .replace(/\$\{group\}/g, groupString);
                            body = sakai_i18n.getValueForKey("GROUP_JOINED_BODY")
                                   .replace(/\$\{sender\}/g, userString)
                                   .replace(/\$\{group\}/g, groupString)
                                   .replace(/\$\{system\}/g, systemString)
                                   .replace(/\$\{profilelink\}/g, profileLink)
                                   .replace(/\$\{br\}/g,"\n");
                        }
                        sakai_comm.sendMessage(managerArray, sakai_user.data.me, subject, body, false, false, false, true, "join_request");
                    };

                    // User id to send the join request for
                    var userID = sakai_user.data.me.user.userid;
                    // Retrieve the join role for the current group
                    var roles = $.parseJSON(groupData.properties["sakai:roles"]);
                    var joinRole = groupData.properties["sakai:joinRole"];
                    var pseudoGroupID = groupID + "-" + joinRole;
                    // Send the join request
                    $.ajax({
                        url: "/~" + pseudoGroupID + "/joinrequests.create.html",
                        type: "POST",
                        data: {
                            userid: userID
                        },
                        success: function (data) {
                            // Adjust the cached me-object to reflect the pending request
                            sakai_user.data.me.user.subjects.push(groupID, pseudoGroupID);
                            // Send a message to the managers of the group
                            var managers = [];
                            for (var r = 0; r < roles.length; r++) {
                                if (roles[r].isManagerRole && groupMembers[roles[r].id] && groupMembers[roles[r].id].results) {
                                    for (var m = 0; m < groupMembers[roles[r].id].results.length; m++) {
                                        managers.push(groupMembers[roles[r].id].results[m].userid);
                                    }
                                }
                            }
                            sendJoinRequestMessage(managers);
                            if ($.isFunction(callback)) {
                                callback(true);
                            }
                        },
                        error: function(status) {
                            debug.error("Could not process join request");
                            if ($.isFunction(callback)) {
                                callback(false);
                            }
                        }
                    });
                });
            });
        },

        /**
         * Removes a join request for the given user for the specified group
         *
         * @param {String} userID ID of the user that wants to join the group
         * @param {String} groupID ID of the group to the user wants to join
         * @param {Function} callback Callback function executed at the end of the
         * operation - callback args:
         *  -- {Boolean} success True if operation succeeded, false otherwise
         */
        removeJoinRequest : function(userID, groupID, callback) {
            if (userID && typeof(userID) === "string" &&
                groupID && typeof(groupID) === "string") {
                $.ajax({
                    url: "/~" + groupID + "/joinrequests/" + sakai_util.safeURL(userID),
                    data: {
                        ":operation": "delete"
                    },
                    type: "POST",
                    success: function (data) {
                        if ($.isFunction(callback)) {
                            callback(true);
                        }
                    },
                    error: function (xhr, textStatus, thrownError) {
                        debug.error("Could not remove join request");
                        if ($.isFunction(callback)) {
                            callback(false);
                        }
                    }
                });
            } else {
                debug.warn("Invalid arguments sent to sakai.api.Groups.removeJoinRequest()");
                if ($.isFunction(callback)) {
                    callback(false);
                }
            }
        },

        /**
         * Returns all join requests for the specified group
         *
         * @param {String} groupID ID of the group to fetch join requests for
         * @param {Function} callback Callback function executed at the end of the
         * @param {Boolean} async Optional argument to set whether this operation is
         *   asynchronous or not. Default is true.
         * operation - callback args:
         *  -- {Boolean} success true if operation succeeded, false otherwise
         *  -- {Object} joinrequest data if successful
         */
        getJoinRequests : function(groupID, callback, async) {
            if (_.isString(groupID)) {
                if (async === null || async === undefined) {
                    async = true;
                }
                $.ajax({
                    url: "/var/joinrequests/list.json?groupId=" + groupID,
                    type: "GET",
                    async: async,
                    success: function (data) {
                        if ($.isFunction(callback)) {
                            callback(true, data);
                        }
                    },
                    error: function (xhr, textStatus, thrownError) {
                        debug.error("Request to get join requests failed");
                        if ($.isFunction(callback)) {
                            callback(false);
                        }
                    }
                });
            } else {
                debug.warn("Invalid arguments sent to sakai.api.Groups.getJoinRequests()");
                if ($.isFunction(callback)) {
                    callback(false);
                }
            }
        },

        /**
         * Searches through managers and members of a group and returns the results
         * @param {String} groupId Id of the group to search in
         * @param {String} query Query put in by the user, if empty a search for all participants is executed
         * @param {Number} num The number of items to search for (page size)
         * @param {Number} page The current page (0-indexed)
         * @param {String} sort The parameter to sort on (firstName or lastName)
         * @param {String} sortOrder The direction of the sort (desc or asc)
         * @param {Function} callback Function executed on success or error
         * @param {Boolean} roleCache Flag to get group role data from cache if available 
         */
        searchMembers: function(groupId, query, num, page, sort, sortOrder, callback, roleCache) {
            if (groupId) {
                var url = "";
                if (query && query !== "*") {
                    url = sakai_conf.URL.SEARCH_GROUP_MEMBERS + "?group=" + groupId + "&q=" + query;
                } else {
                    url = sakai_conf.URL.SEARCH_GROUP_MEMBERS_ALL + "?group=" + groupId;
                }
                if (num !== undefined) {
                    url += "&items=" + num;
                }
                if (page !== undefined) {
                    url += "&page=" + page;
                }
                if (sort) {
                    url += "&sortOn=" + sort;
                }
                if (sortOrder) {
                    url += "&sortOrder=" + sortOrder;
                }
                $.ajax({
                    url: url,
                    type: "GET",
                    success: function(data){
                        var participantCount = 0;
                        if (data.results.length) {
                            // Do a couple requests first so the group data is cached
                            sakaiGroupsAPI.getGroupAuthorizableData(groupId, function() {
                                sakaiGroupsAPI.getRole(data.results[0].userid, groupId, function(success, role) {
                                    $.each(data.results, function(index, user){
                                        sakaiGroupsAPI.getRole(user.userid, groupId, function(success, role){
                                            user.role = role;
                                            participantCount++;
                                            if (participantCount === data.results.length) {
                                                if ($.isFunction(callback)) {
                                                    callback(true, data);
                                                }
                                            }
                                        });
                                    });
                                }, roleCache);
                            });
                        } else {
                            if ($.isFunction(callback)) {
                                callback(true, {});
                            }
                        }
                    },
                    error: function(err){
                        debug.error(err);
                        if ($.isFunction(callback)) {
                            callback(false, err);
                        }
                    }
                });
            } else {
                if ($.isFunction(callback)) {
                    callback(false, false);
                }
            }
        },
        /**
         * Returns all the users who are member of a certain group
         *
         * @param {String} groupids The ID of the group we would like to get the members of or an array of group IDs
         * @param {Function} callback Callback function, passes (success, (data|xhr))
         * @param {Boolean} everyone If we should return managers + members (useful for pseudoGroups)
         * @param {Boolean} noCache Whether or not to refresh the cache
         */
        getMembers : function(groupids, callback, everyone, noCache) {
            var dataToReturn = {};
            var toCheck = [];
            if (_.isString(groupids)){
                groupids = [groupids];
            }
            $.each(groupids, function(index, groupid){
                if (sakaiGroupsAPI.groupData[groupid] && sakaiGroupsAPI.groupData[groupid].membersPerRole && !noCache){
                    dataToReturn[groupid] = sakaiGroupsAPI.groupData[groupid].membersPerRole;
                } else {
                    toCheck.push(groupid);
                }
            });
            sakaiGroupsAPI.getGroupAuthorizableData(toCheck, function(success, groupData){
                if (success){
                    var batchRequests = [];
                    var urlToGroupMapping = {};
                    $.each(groupData, function(groupid, group){
                        var roles = $.parseJSON(group.properties["sakai:roles"]);
                        for (var i = 0; i < roles.length; i++) {
                            var selector = "members";
                            if (everyone) {
                                selector = "everyone";
                            }
                            var url = "/system/userManager/group/" + groupid + "-" + roles[i].id + "." + selector + ".json";
                            urlToGroupMapping[url] = {
                                "groupid": groupid,
                                "role": roles[i].id
                            };
                            batchRequests.push({
                                "url": url,
                                "method": "GET",
                                "parameters": {
                                    items: 1000
                                }
                            });
                        }
                    });
                    sakai_serv.batch(batchRequests, function(success, data){
                        if (success) {
                            $.each(data.results, function(m, membershiplist){
                                // Retrieve the group and role id from the URL
                                var groupid = urlToGroupMapping[membershiplist.url].groupid;
                                var roleid = urlToGroupMapping[membershiplist.url].role;
                                // Add the members to the response
                                var members = $.parseJSON(membershiplist.body);
                                dataToReturn[groupid] = dataToReturn[groupid] || {};
                                dataToReturn[groupid][roleid] = {"results": members};
                                if (sakaiGroupsAPI.groupData[groupid]){
                                    sakaiGroupsAPI.groupData[groupid].membersPerRole = sakaiGroupsAPI.groupData[groupid].membersPerRole || {};
                                    sakaiGroupsAPI.groupData[groupid].membersPerRole[roleid] = {"results": members};
                                }
                            });
                            if ($.isFunction(callback)) {
                                callback(true, dataToReturn);
                            }
                        }
                    }, false, true);
                } else {
                    debug.error("Could not get members group info for " + groupids);
                    if ($.isFunction(callback)) {
                        callback(false, xhr);
                    }
                }
            });
        },

        groupRoleData : {},

        getRoles : function(groupData, translate) {
            var roles = [];
            groupData.roles = groupData.roles || groupData["sakai:roles"];
            if ( _.isString( groupData.roles ) ) {
                groupData.roles = $.parseJSON( groupData.roles );
            }
            $.each(groupData.roles, function(i,role) {
                if (_.isString(role)){
                    role = $.parseJSON(role);
                }
                if (translate) {
                    role.title = sakai_i18n.getValueForKey(role.title);
                    role.titlePlural = sakai_i18n.getValueForKey(role.titlePlural);
                }
                roles.push(role);
            });
            return roles;
        },

        getRole : function(userId, groupID, callback, roleCache){
            var cache = roleCache === false ? false : true;
            var groupInfo = sakaiGroupsAPI.getGroupAuthorizableData(groupID, function(success, data){
                if (success){
                    data = data[groupID];
                    var roles = $.parseJSON(data.properties["sakai:roles"]);
                    var batchRequests = [];
                    var role;
                    for (var i = 0; i < roles.length; i++) {
                        var url = "/system/userManager/group/" + groupID + "-" + roles[i].id + ".everyone.json";
                        batchRequests.push({
                            "url": url,
                            "method": "GET",
                            "parameters": {
                                items: 10000
                            }
                        });
                    }
                    var parseRoles = function(data) {
                        var isMatch = function(user, index){
                            return user.userid === userId;
                        };

                        for (var i = 0; i < roles.length; i++) {
                            if (data.results.hasOwnProperty(i)) {
                                var members = $.parseJSON(data.results[i].body);
                                if (members === null) {
                                  continue;
                                }
                                if ($.grep(members, isMatch).length > 0){
                                    role = roles[i];
                                    break;
                                }
                            }
                        }
                        if ($.isFunction(callback)) {
                            callback(true, role);
                        }
                    };

                    if (cache && $.isPlainObject(sakaiGroupsAPI.groupRoleData[groupID])) {
                        parseRoles(sakaiGroupsAPI.groupRoleData[groupID]);
                    } else {
                        sakai_serv.batch(batchRequests, function(success, data){
                            if (success) {
                                sakaiGroupsAPI.groupRoleData[groupID] = data;
                                parseRoles(data);
                            }
                        }, false, true);
                    }

                } else {
                    debug.error("Could not get members group info for " + groupID);
                    if ($.isFunction(callback)) {
                        callback(false, xhr);
                    }
                }
            });
        },

        /**
         * Checks if one role managers the other, returns true if the role has management rights
         *
         * @param {Object} parentRoleObject The role we want to check if it has management rights on the other
         * @param {String} roleIdToCheck The role to check if it can be managed by
         */
        hasManagementRights : function(parentRoleObject, roleIdToCheck) {
            var manages = false;
            if (parentRoleObject.manages) {
                $.each(parentRoleObject.manages, function(i, childRole) {
                    if (childRole === roleIdToCheck) {
                        manages = true;
                        return false;
                    }
                });
            }
            return manages;
        },

        leave : function(groupId, role, meData, callback){
            var reqs = [
                {
                    url: "/system/userManager/group/"+ groupId + "-" + role.id + ".leave.json",
                    method: "POST"
                },
                {
                    url: "/system/userManager/group/"+ groupId + ".leave.json",
                    method: "POST"
                }
            ];
            sakai_serv.batch(reqs, function(success){
                var pseudoGroupID = groupId + "-" + role;
                var index = meData.user.subjects.indexOf(groupId);
                meData.user.subjects.splice(index, 1);
                index = meData.user.subjects.indexOf(pseudoGroupID);
                meData.user.subjects.splice(index, 1);
                if ($.isFunction(callback)){
                    callback(success);
                }
            });
        },

        /**
         * Retrieves the profile picture for the group
         *
         * @param {Object} profile the groups profile
         * @return {String} the url for the profile picture
         */
        getProfilePicture : function(profile) {
            return sakai_util.constructProfilePicture(profile, "group");
        },

        /**
         * Function to process search results for groups
         *
         * @param {Object} results Search results to process
         * @param {Object} meData User object for the user
         * @returns {Object} results Processed results
         */
        prepareGroupsForRender: function(results, meData) {
            $.each(results, function(i, group){
                if (group["sakai:group-id"]) {
                    group.id = group["sakai:group-id"];
                    if (group["sakai:group-title"]) {
                        group["sakai:group-title-short"] = sakai_util.applyThreeDots(group["sakai:group-title"], 550, {max_rows: 1,whole_word: false}, "s3d-bold");
                        group["sakai:group-title-shorter"] = sakai_util.applyThreeDots(group["sakai:group-title"], 130, {max_rows: 1,whole_word: false}, "s3d-bold");
                    }

                    if (group["sakai:group-description"]) {
                        group["sakai:group-description-short"] = sakai_util.applyThreeDots(group["sakai:group-description"], 580, {max_rows: 2,whole_word: false});
                        group["sakai:group-description-shorter"] = sakai_util.applyThreeDots(group["sakai:group-description"], 150, {max_rows: 2,whole_word: false});
                    }

                    var groupType = sakai_i18n.getValueForKey("OTHER");
                    if (group["sakai:category"]){
                        for (var c = 0; c < sakai_conf.worldTemplates.length; c++) {
                            if (sakai_conf.worldTemplates[c].id === group["sakai:category"]){
                                groupType = sakai_i18n.getValueForKey(sakai_conf.worldTemplates[c].title);
                            }
                        }
                    }
                    // Modify the tags if there are any
                    if (group["sakai:tags"]) {
                        group.tagsProcessed = sakai_util.formatTags(group["sakai:tags"]);
                    } else if (group.basic && group.basic.elements && group.basic.elements["sakai:tags"]) {
                        group.tagsProcessed = sakai_util.formatTags(group.basic.elements["sakai:tags"].value);
                    }
                    group.groupType = groupType;
                    group.lastModified = group.lastModified;
                    group.picPath = sakaiGroupsAPI.getProfilePicture(group);
                    group.userMember = false;
                    if (sakaiGroupsAPI.isCurrentUserAManager(group["sakai:group-id"], meData) || sakaiGroupsAPI.isCurrentUserAMember(group["sakai:group-id"], meData)){
                        group.userMember = true;
                    }
                    // use large default group icon on search page
                    if (group.picPath === sakai_conf.URL.GROUP_DEFAULT_ICON_URL){
                        group.picPathLarge = sakai_conf.URL.GROUP_DEFAULT_ICON_URL_LARGE;
                    }
                }
            });
            return results;
        },

        /**
         * Change the permission of some users on a group
         *
         * @param {String} groupID the ID of the group to add members to
         * @param {Array} rolesToAdd Array of user/group IDs to add to the group
         * @param {Array} rolesToDelete Array of user/group IDs to remove from the group
         * @param {Object} meData the data from sakai.api.User.data.me
         * @param {Boolean} managerShip if the user should be added as a manager of the group (almost never is the case)
         * @param {Function} callback Callback function
         */
        changeUsersPermission : function(groupID, rolesToAdd, rolesToDelete, medata, managerShip, callback) {
            var addUserReqs = sakaiGroupsAPI.addUsersToGroup(groupID, rolesToAdd, medata, managerShip, false, true);
            var removeUserReqs = sakaiGroupsAPI.removeUsersFromGroup(groupID, rolesToDelete, medata, false, true);
            $.merge(addUserReqs, removeUserReqs);
            sakai_serv.batch(addUserReqs, function(success, data) {
                if ($.isFunction(callback)) {
                    callback(success, data);
                }
            });
        },

        /**
         * Add users to the specified group
         *
         * @param {String} groupID the ID of the group to add members to
         * @param {Array} users Array of user/group IDs to add to the group
         * @param {Object} meData the data from sakai.api.User.data.me
         * @param {Boolean} managerShip if the user should be added as a manager
         * @param {Function} callback Callback function
         * @param {Boolean} onlyReturnRequests only return the requests, don't make them
         */
        addUsersToGroup : function(groupID, users, medata, managerShip, callback, onlyReturnRequests) {
            var reqData = [];
            var currentUserIncluded = false;

            // Construct the batch requests
            $.each(users, function(index, user) {
                var url = "/system/userManager/group/" + groupID + ".update.json";
                if (user.permission){
                    url = "/system/userManager/group/" + groupID + "-" + user.permission.toLowerCase() + ".update.json";
                }
                var data = {};
                if (managerShip){
                    data[":manager"] = user.user;
                } else if (user.viewer === true) { // user is only a viewer, not a member
                    data[":viewer"] = user.user;
                } else {
                    data[":member"] = user.user;
                    data[":viewer"] = user.user;
                }
                reqData.push({
                    "url": url,
                    "method": "POST",
                    "parameters": data
                });
                if (user.user === medata.user.userid){
                    currentUserIncluded = true;
                }
            });
            if (reqData.length > 0) {
                // batch request to add users to group
                if (onlyReturnRequests) {
                    return reqData;
                } else {
                    sakai_serv.batch(reqData, function(success, data) {
                        if (!success) {
                            debug.error("Could not add users to group");
                        } else if (currentUserIncluded) {
                            medata.user.subjects.push(groupID);
                        }
                        // Add this to the members of the groups in the cache
                        if (sakaiGroupsAPI.groupData[groupID] && sakaiGroupsAPI.groupData[groupID].membersPerRole){
                            $.each(users, function(index, user) {
                                sakaiGroupsAPI.groupData[groupID].membersPerRole[user.permission] = sakaiGroupsAPI.groupData[groupID].membersPerRole[user.permission] || {"results": []};
                                sakaiGroupsAPI.groupData[groupID].membersPerRole[user.permission].results.push({
                                    "rep:userId": user.user
                                });
                            });
                        }
                        if ($.isFunction(callback)) {
                            callback(success);
                        }
                    });
                }
            } else {
                if ($.isFunction(callback)) {
                    callback(true);
                }
            }
            return true;
        },

        /**
         * Add content items to the specified group
         *
         * @param {String} groupID the ID of the group to add members to
         * @param {Array} contentList Array of content IDs to add to the group
         * @param {Function} callback Callback function
         */
        addContentToGroup : function(groupID, contentIDs, callback) {
            var reqData = [];

            $(contentIDs).each(function(i, contentID) {
                reqData.push({
                    "url": "/p/" + contentID + ".members.json",
                    "method": "POST",
                    "parameters": {
                        ":viewer": groupID
                    }
                });
            });

            if (reqData.length > 0) {
                // batch request to add content to group
                sakai_serv.batch(reqData, function(success, data) {
                    if (!success) {
                        debug.error("Error adding content to the group");
                    }
                    if ($.isFunction(callback)) {
                        callback(success);
                    }
                });
            }
        },

        /**
         * Remove users from the specified group
         *
         * @param {String} groupID the ID of the group to remove members from
         * @param {Array} users Array of user/group IDs to remove from the group
         * @param {Object} meData the data from sakai.api.User.data.me
         * @param {Function} callback Callback function
         * @param {Boolean} onlyReturnRequests only return the requests, don't make them
         */
        removeUsersFromGroup : function(groupID, users, medata, callback, onlyReturnRequests) {
            var reqData = [];
            var currentUserIncluded = false;

            $.each(users, function(index, user) {
                var params = {
                    "_charset_":"utf-8",
                    ":manager@Delete": user.userid
                };
                if ((user.hasOwnProperty("removeManagerOnly") && user.removeManagerOnly === false) || !user.hasOwnProperty("removeManagerOnly")) {
                    params[":member@Delete"] = user.userid;
                    params[":viewer@Delete"] = user.userid;
                }
                if (user.permission) {
                    reqData.push({
                        "url": "/system/userManager/group/" + groupID + "-" + user.permission + ".update.json",
                        "method": "POST",
                        "parameters": params
                    });
                } else {
                    reqData.push({
                        "url": "/system/userManager/group/" + groupID + ".update.json",
                        "method": "POST",
                        "parameters": params
                    });
                }
                if (user.userid === medata.user.userid) {
                    currentUserIncluded = true;
                }
            });

            if (reqData.length > 0) {
                if (onlyReturnRequests) {
                    return reqData;
                } else {
                    // batch request to remove users from group
                    sakai_serv.batch(reqData, function(success, data) {
                        if (!success) {
                            debug.error("Error removing users from the group");
                        } else if (currentUserIncluded){
                            // remove the group from medata.subjects
                            var index = medata.user.subjects.indexOf(groupID);
                            medata.user.subjects.splice(index, 1);
                        }
                        if ($.isFunction(callback)) {
                            callback(success);
                        }
                    });
                }
            }
            return true;
        },

        /**
         * Add users to the specified group
         *
         * @param {String} groupID the ID of the group to add members to
         * @param {Array} content Array of content IDs to remove from the group
         * @param {Function} callback Callback function
         */
        removeContentFromGroup : function(groupID, contentIDs, callback) {
            var reqData = [];

            $.each(contentIDs, function(index, contentID) {
                if (contentID) {
                    reqData.push({
                        "url": "/p/" + contentID + ".members.json",
                        "method": "POST",
                        "parameters": {
                            ":viewer@Delete": groupID
                        }
                    });
                }
            });

            if (reqData.length > 0) {
                // batch request to remove content from group
                sakai_serv.batch(reqData, function(success, data) {
                    if (!success) {
                        debug.error("Error removing content from the group");
                    }
                    if ($.isFunction(callback)) {
                        callback(success);
                    }
                });
            }
        },

        filterGroup: function(group, includeCollections){
            if (includeCollections && group["sakai:category"] && group["sakai:category"] === "collection" && group["sakai:group-title"]){
                return true;
            } else if (!group["sakai:group-title"] || group["sakai:excludeSearch"]) {
                return false;
            } else {
                if (group.groupid === "everyone") {
                    return false;
                } else {
                    return true;
                }
            }
        },

        getMemberships : function(groups, includeCollections){
            var newjson = {entry: []};
            for (var i = 0, il = groups.length; i < il; i++) {
                if (sakaiGroupsAPI.filterGroup(groups[i], includeCollections)) {
                    newjson.entry.push(groups[i]);
                }
            }
            newjson.entry.sort(function(a, b){
                if (a["sakai:category"] === "collection" && b["sakai:category"] === "collection"){
                    return sakai_util.Sorting.naturalSort(a["sakai:group-title"], b["sakai:group-title"]);
                } else if (a["sakai:category"] === "collection"){
                    return 1;
                } else if (b["sakai:category"] === "collection"){
                    return -1;
                } else {
                    return sakai_util.Sorting.naturalSort(a["sakai:group-title"], b["sakai:group-title"]);
                }
            });
            return newjson;
        },

        getTemplate: function(cat, id){
            var category = false;
            for (var i = 0; i < sakai_conf.worldTemplates.length; i++){
                if (sakai_conf.worldTemplates[i].id === cat){
                    category = sakai_conf.worldTemplates[i];
                    break;
                }
            }
            var template = false;
            if (category && category.templates && category.templates.length) {
                for (var w = 0; w < category.templates.length; w++){
                    if (category.templates[w].id === id){
                        template = category.templates[w];
                        break;
                    }
                }
            }
            return template;
        }

    };
    return sakaiGroupsAPI;
});




© 2015 - 2025 Weber Informatics LLC | Privacy Policy