1 /**
  2  * @fileOverview
  3  * @author <a href="https://www.labkey.org">LabKey</a> (<a href="mailto:info@labkey.com">info@labkey.com</a>)
  4  * @license Copyright (c) 2012-2019 LabKey Corporation
  5  * <p/>
  6  * Licensed under the Apache License, Version 2.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at
  9  * <p/>
 10  * http://www.apache.org/licenses/LICENSE-2.0
 11  * <p/>
 12  * Unless required by applicable law or agreed to in writing, software
 13  * distributed under the License is distributed on an "AS IS" BASIS,
 14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  * See the License for the specific language governing permissions and
 16  * limitations under the License.
 17  * <p/>
 18  */
 19 
 20 /**
 21  * @namespace LabKey Security Reporting and Helper class.
 22  * This class provides several static methods and data members for
 23  * calling the security-related APIs, and interpreting the results.
 24  *            <p>Additional Documentation:
 25  *              <ul>
 26  *                  <li><a href="https://www.labkey.org/Documentation/wiki-page.view?name=security">LabKey Security and Accounts</a></li>
 27  *              </ul>
 28  *           </p>
 29  */
 30 LABKEY.Security = new function()
 31 {
 32     /*-- public methods --*/
 33     /** @scope LABKEY.Security */
 34     return {
 35 
 36         /**
 37          * A map of the various permission bits supported in the LabKey Server.
 38          * You can use these values with the hasPermission() method to test if
 39          * a user or group has a particular permission. The values in this map
 40          * are as follows:
 41          * <ul>
 42          * <li>read</li>
 43          * <li>insert</li>
 44          * <li>update</li>
 45          * <li>del</li>
 46          * <li>readOwn</li>
 47          * <li>updateOwn</li>
 48          * <li>deleteOwn</li>
 49          * <li>all</li>
 50          * </ul>
 51          * For example, to refer to the update permission, the syntax would be:<br/>
 52          * <pre><code>LABKEY.Security.permissions.update</code></pre>
 53          */
 54         permissions : {
 55             read: 1,
 56             insert: 2,
 57             update: 4,
 58             del: 8,
 59             readOwn: 16,
 60             updateOwn: 64,
 61             deleteOwn: 128,
 62             admin: 32768,
 63             all: 65535
 64         },
 65 
 66         /**
 67          * A map of commonly used effective permissions supported in the LabKey Server.
 68          * You can use these values with the hasEffectivePermission() method to test if
 69          * a user or group has a particular permission. The values in this map
 70          * are as follows:
 71          * <ul>
 72          * <li>read</li>
 73          * <li>insert</li>
 74          * <li>update</li>
 75          * <li>del</li>
 76          * <li>readOwn</li>
 77          * </ul>
 78          * For example, to refer to the update permission, the syntax would be:<br/>
 79          * <pre><code>LABKEY.Security.effectivePermissions.update</code></pre>
 80          */
 81         effectivePermissions : {
 82             insert: "org.labkey.api.security.permissions.InsertPermission",
 83             read: "org.labkey.api.security.permissions.ReadPermission",
 84             admin: "org.labkey.api.security.permissions.AdminPermission",
 85             del: "org.labkey.api.security.permissions.DeletePermission",
 86             readOwn: "org.labkey.api.security.permissions.ReadSomePermission",
 87             update: "org.labkey.api.security.permissions.UpdatePermission"
 88         },
 89 
 90         /**
 91          * A map of the various permission roles exposed in the user interface.
 92          * The members are as follows:
 93          * <ul>
 94          * <li>admin</li>
 95          * <li>editor</li>
 96          * <li>author</li>
 97          * <li>reader</li>
 98          * <li>restrictedReader</li>
 99          * <li>noPerms</li>
100          * </ul>
101          * For example, to refer to the author role, the syntax would be:<br/>
102          * <pre><code>LABKEY.Security.roles.author</code></pre>
103          */
104         roles : {
105             admin: 65535,
106             editor: 15,
107             author: 195,
108             reader: 1,
109             restrictedReader: 16,
110             submitter: 2,
111             noPerms: 0
112         },
113 
114         /**
115          * A map of the special system group ids. These ids are assigned by the system
116          * at initial startup and are constant across installations. The values in
117          * this map are as follows:
118          * <ul>
119          * <li>administrators</li>
120          * <li>users</li>
121          * <li>guests</li>
122          * <li>developers</li>
123          * </ul>
124          * For example, to refer to the administrators group, the syntax would be:<br/>
125          * <pre><code>LABKEY.Security.systemGroups.administrators</code></pre>
126          */
127         systemGroups : {
128             administrators: -1,
129             users: -2,
130             guests: -3,
131             developers: -4
132         },
133 
134         /**
135          * Get the effective permissions for all groups within the container, optionally
136          * recursing down the container hierarchy.
137          * @param config A configuration object with the following properties:
138          * @param {function} config.success A reference to a function to call with the API results. This
139          * function will be passed the following parameters:
140          * <ul>
141          * <li><b>groupPermsInfo:</b> an object containing properties about the container and group permissions.
142          * This object will have the following shape:
143          *  <ul>
144          *  <li>container
145          *      <ul>
146          *          <li>id: the container id</li>
147          *          <li>name: the container name</li>
148          *          <li>path: the container path</li>
149          *          <li>isInheritingPerms: true if the container is inheriting permissions from its parent</li>
150          *          <li>groups: an array of group objects, each of which will have the following properties:
151          *              <ul>
152          *                  <li>id: the group id</li>
153          *                  <li>name: the group's name</li>
154          *                  <li>type: the group's type ('g' for group, 'r' for role, 'm' for module-specific)</li>
155          *                  <li>roleLabel: (DEPRECATED) a description of the group's permission role. This will correspond
156          *                      to the visible labels shown on the permissions page (e.g., 'Admin (all permissions)'.</li>
157          *                  <li>role: (DEPRECATED) the group's role value (e.g., 'ADMIN'). Use this property for programmatic checks.</li>
158          *                  <li>permissions: (DEPRECATED) The group's effective permissions as a bit mask.
159          *                          Use this with the hasPermission() method to test for specific permissions.</li>
160          *                  <li>roles: An array of role unique names that this group is playing in the container. This replaces the
161          *                              existing roleLabel, role and permissions properties. Groups may now play multiple roles in a container
162          *                              and each role grants the user a set of permissions. Use the getRoles() method to retrieve information
163          *                              about the roles, including which permissions are granted by each role.
164          *                  </li>
165          *                  <li>effectivePermissions: An array of effective permission unique names the group has.</li>
166          *              </ul>
167          *          </li>
168          *          <li>children: if includeSubfolders was true, this will contain an array of objects, each of
169          *              which will have the same shape as the parent container object.</li>
170          *      </ul>
171          *  </li>
172          * </ul>
173          * </li>
174          * <li><b>response:</b> The XMLHttpResponse object</li>
175          * </ul>
176          * @param {function} [config.failure] A reference to a function to call when an error occurs. This
177          * function will be passed the following parameters:
178          * <ul>
179          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
180          * <li><b>response:</b> The XMLHttpResponse object</li>
181          * </ul>
182          * @param {boolean} [config.includeSubfolders] Set to true to recurse down the subfolders (defaults to false)
183          * @param {string} [config.containerPath] An alternate container path to get permissions from. If not specified,
184          * the current container path will be used.
185          * @param {object} [config.scope] A scoping object for the success and error callback functions (default to this).
186          * @returns {Mixed} In client-side scripts, this method will return a transaction id
187          * for the async request that can be used to cancel the request
188          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
189          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
190          */
191         getGroupPermissions : function(config)
192         {
193             var params = {};
194             if (config.includeSubfolders != undefined)
195                 params.includeSubfolders = config.includeSubfolders;
196 
197             return LABKEY.Ajax.request({
198                 url: LABKEY.ActionURL.buildURL("security", "getGroupPerms", config.containerPath),
199                 method : 'GET',
200                 params: params,
201                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
202                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true)
203             });
204         },
205 
206         /**
207          * Returns true if the permission passed in 'perm' is on in the permissions
208          * set passed as 'perms'. This is a local function and does not make a call to the server.
209          * @param {int} perms The permission set, typically retrieved for a given user or group.
210          * @param {int} perm A specific permission bit to check for.
211          */
212         hasPermission : function(perms, perm)
213         {
214             return perms & perm;
215         },
216 
217         /**
218          * Returns true if the permission passed in 'desiredPermission' is in the permissions
219          * array passed as 'effectivePermissions'. This is a local function and does not make a call to the server.
220          * @param {Array} effectivePermissions The permission set, typically retrieved for a given user or group.
221          * @param {String} desiredPermission A specific permission bit to check for.
222          * @returns {boolean}
223          */
224         hasEffectivePermission : function(effectivePermissions, desiredPermission)
225         {
226             for (var i = 0; i < effectivePermissions.length; i++)
227             {
228                 if (effectivePermissions[i] == desiredPermission)
229                 {
230                     return true;
231                 }
232             }
233             return false;
234         },
235 
236         /**
237          * Returns the name of the security role represented by the permissions passed as 'perms'.
238          * The return value will be the name of a property in the LABKEY.Security.roles map.
239          * This is a local function, and does not make a call to the server.
240          * @param {int} perms The permissions set
241          * @deprecated Do not use this anymore. Use the roles array in the various responses and the
242          * getRoles() method to obtain extra information about each role.
243          */
244         getRole : function(perms)
245         {
246             for (var role in LABKEY.Security.roles)
247             {
248                 if (LABKEY.Security.roles.hasOwnProperty(role))
249                 {
250                     if (perms == LABKEY.Security.roles[role])
251                     {
252                         return role;
253                     }
254                 }
255             }
256         },
257 
258         /**
259          * Returns information about the container paths visible to the current user
260          * @param config A configuration object containing the following properties
261          * @param {boolean} [config.includeSubfolders] If set to true, the entire branch of containers will be returned.
262          * If false, only the immediate children of the starting container will be returned (defaults to false).
263          * @param {int} [config.depth] May be used to control the depth of recursion if includeSubfolders is set to true.
264          * @param {Mixed} [config.container] A container id or full-path String or an Array of container id/full-path
265          * Strings (only the first will be used). If not present, the current container is used.
266          * @param {Function} config.success A reference to a function to call with the API results. This
267          * function will be passed an array of container paths as strings
268          */
269         getReadableContainers : function(config)
270         {
271             var params = {};
272             config = config || {};
273             if (undefined !== config.container)
274             {
275                 if (LABKEY.Utils.isArray(config.container))
276                 {
277                     if (config.container.length > 0)
278                     {
279                         config.container = [config.container[0]];
280                     }
281                     else
282                     {
283                         delete config.container;
284                     }
285                 }
286                 else
287                 {
288                     config.container = [ config.container ];
289                 }
290                 params.container = config.container;
291             }
292             if (undefined !== config.includeSubfolders)
293                 params.includeSubfolders = config.includeSubfolders;
294             if (undefined !== config.depth)
295                 params.depth = config.depth;
296 
297             return LABKEY.Ajax.request({
298                 url: LABKEY.ActionURL.buildURL("project", "getReadableContainers", config.containerPath),
299                 method : 'GET',
300                 params: params,
301                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope, false, function(o) { return o.containers; }),
302                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true)
303             });
304         },
305 
306         /**
307          * Returns information about a user's permissions within a container. If you don't specify a user id, this
308          * will return information about the current user.
309          * @param config A configuration object containing the following properties
310          * @param {int} config.userId The id of the user. Omit to get the current user's information
311          * @param {string} config.userEmail The email address (user name) of the user (specify only userId or userEmail, not both)
312          * @param {Function} config.success A reference to a function to call with the API results. This
313          * function will be passed the following parameters:
314          * <ul>
315          * <li><b>userPermsInfo:</b> an object containing properties about the user's permissions.
316          * This object will have the following shape:
317          *  <ul>
318          *  <li>container: information about the container and the groups the user belongs to in that container
319          *      <ul>
320          *          <li>id: the container id</li>
321          *          <li>name: the container name</li>
322          *          <li>path: the container path</li>
323          *          <li>roleLabel: (DEPRECATED) a description of the user's permission role in this container. This will correspond
324          *               to the visible labels shown on the permissions page (e.g., 'Admin (all permissions)'.</li>
325          *          <li>role: (DEPRECATED) the user's role value (e.g., 'ADMIN'). Use this property for programmatic checks.</li>
326          *          <li>permissions: (DEPRECATED) The user's effective permissions in this container as a bit mask.
327          *               Use this with the hasPermission() method to test for specific permissions.</li>
328          *          <li>roles: An array of role unique names that this user is playing in the container. This replaces the
329          *               existing roleLabel, role and permissions properties. Users may now play multiple roles in a container
330          *               and each role grants the user a set of permissions. Use the getRoles() method to retrieve information
331          *               about the roles, including which permissions are granted by each role.
332          *          </li>
333          *          <li>effectivePermissions: An array of effective permission unique names the user has.</li>
334          *          <li>groups: an array of group objects to which the user belongs, each of which will have the following properties:
335          *              <ul>
336          *                  <li>id: the group id</li>
337          *                  <li>name: the group's name</li>
338          *                  <li>roleLabel: (DEPRECATED) a description of the group's permission role. This will correspond
339          *                      to the visible labels shown on the permissions page (e.g., 'Admin (all permissions)'.</li>
340          *                  <li>role: (DEPRECATED) the group's role value (e.g., 'ADMIN'). Use this property for programmatic checks.</li>
341          *                  <li>permissions: (DEPRECATED) The group's effective permissions as a bit mask.
342          *                          Use this with the hasPermission() method to test for specific permissions.</li>
343          *                  <li>roles: An array of role unique names that this group is playing in the container. This replaces the
344          *                              existing roleLabel, role and permissions properties. Groups may now play multiple roles in a container
345          *                              and each role grants the user a set of permissions. Use the getRoles() method to retrieve information
346          *                              about the roles, including which permissions are granted by each role.
347          *                  </li>
348          *                  <li>effectivePermissions: An array of effective permission unique names the group has.</li>
349          *              </ul>
350          *          </li>
351          *          <li>children: if includeSubfolders was true, this will contain an array of objects, each of
352          *              which will have the same shape as the parent container object.</li>
353          *      </ul>
354          *  </li>
355          *  <li>user: information about the requested user
356          *      <ul>
357          *          <li>userId: the user's id</li>
358          *          <li>displayName: the user's display name</li>
359          *      </ul>
360          *  </li>
361          * </ul>
362          * </li>
363          * <li><b>response:</b> The XMLHttpResponse object</li>
364          * </ul>
365          * @param {function} [config.failure] A reference to a function to call when an error occurs. This
366          * function will be passed the following parameters:
367          * <ul>
368          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
369          * <li><b>response:</b> The XMLHttpResponse object</li>
370          * </ul>
371          * @param {boolean} [config.includeSubfolders] Set to true to recurse down the subfolders (defaults to false)
372          * @param {string} [config.containerPath] An alternate container path to get permissions from. If not specified,
373          * the current container path will be used.
374          * @param {Object} [config.scope] A scoping object for the success and error callback functions (default to this).
375          * @returns {Mixed} In client-side scripts, this method will return a transaction id
376          * for the async request that can be used to cancel the request
377          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
378          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
379          */
380         getUserPermissions : function(config)
381         {
382             var params = {};
383 
384             if(config.userId != undefined)
385                 params.userId = config.userId;
386             else if(config.userEmail != undefined)
387                 params.userEmail = config.userEmail;
388 
389             if(config.includeSubfolders != undefined)
390                 params.includeSubfolders = config.includeSubfolders;
391 
392             return LABKEY.Ajax.request({
393                 url: LABKEY.ActionURL.buildURL("security", "getUserPerms", config.containerPath),
394                 method : 'GET',
395                 params: params,
396                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
397                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true)
398             });
399         },
400 
401         /**
402          * Returns a list of users given selection criteria. This may be called by any logged-in user.
403          * @param config A configuration object containing the following properties
404          * @param {int} [config.groupId] The id of a project group for which you want the members.
405          * @param {string} [config.group] The name of a project group for which you want the members (specify groupId or group, not both).
406          * @param {string} [config.name] The first part of the user name, useful for user name completion. If specified,
407          * only users whose email address or display name starts with the value supplied will be returned.
408          * @param {boolean} [config.allMembers] This value is used to fetch all members in subgroups.
409          * @param {boolean} [config.active] This value is used to filter members based on activity (defaults to false).
410          * @param {Mixed} [config.permissions] A permissions string or an Array of permissions strings.
411          * If not present, no permission filtering occurs. If multiple permissions, all permissions are required.
412          * @param {function} config.success A reference to a function to call with the API results. This
413          * function will be passed the following parameters:
414          * <ul>
415          * <li><b>usersInfo:</b> an object with the following shape:
416          *  <ul>
417          *      <li>users: an array of user objects in the following form:
418          *          <ul>
419          *              <li>userId: the user's id</li>
420          *              <li>displayName: the user's display name</li>
421          *              <li>email: the user's email address</li>
422          *          </ul>
423          *      </li>
424          *      <li>container: the path of the requested container</li>
425          *  </ul>
426          * </li>
427          * <li><b>response:</b> The XMLHttpResponse object</li>
428          * </ul>
429          * @param {function} [config.failure] A reference to a function to call when an error occurs. This
430          * function will be passed the following parameters:
431          * <ul>
432          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
433          * <li><b>response:</b> The XMLHttpResponse object</li>
434          * </ul>
435          * @param {string} [config.containerPath] An alternate container path to get permissions from. If not specified,
436          * the current container path will be used.
437          * @param {object} [config.scope] A scoping object for the success and error callback functions (default to this).
438          * @returns {Mixed} In client-side scripts, this method will return a transaction id
439          * for the async request that can be used to cancel the request
440          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
441          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
442          */
443         getUsers : function(config)
444         {
445             var params = {};
446             if(undefined != config.groupId)
447                 params.groupId = config.groupId;
448             else if(undefined != config.group)
449                 params.group = config.group;
450 
451             if(undefined != config.name)
452                 params.name = config.name;
453 
454             if(undefined != config.allMembers)
455                 params.allMembers = config.allMembers;
456 
457             if (undefined != config.active)
458                 params.active = config.active;
459 
460             if (undefined != config.permissions)
461             {
462                 if (!LABKEY.Utils.isArray(config.permissions))
463                 {
464                     config.permissions = [ config.permissions ];
465                 }
466                 params.permissions = config.permissions;
467             }
468 
469             return LABKEY.Ajax.request({
470                 url: LABKEY.ActionURL.buildURL("user", "getUsers.api", config.containerPath),
471                 method : 'GET',
472                 params: params,
473                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
474                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true)
475             });
476         },
477 
478         /**
479          * Creates a new container, which may be a project, folder, or workbook.
480          * @param config A configuration object with the following properties
481          * @param {String} [config.name] Required for projects or folders. The name of the container.
482          * @param {String} [config.title] The title of the container, used primarily for workbooks.
483          * @param {String} [config.description] The description of the container, used primarily for workbooks.
484          * @param {boolean} [config.isWorkbook] Whether this a workbook should be created. Defaults to false.
485          * @param {String} [config.folderType] The name of the folder type to be applied.
486          * @param {function} [config.success] A reference to a function to call with the API results. This
487          * function will be passed the following parameters:
488          * <ul>
489          * <li><b>containersInfo:</b> an object with the following properties:
490          *  <ul>
491          *      <li>id: the id of the requested container</li>
492          *      <li>name: the name of the requested container</li>
493          *      <li>path: the path of the requested container</li>
494          *      <li>sortOrder: the relative sort order of the requested container</li>
495          *      <li>description: an optional description for the container (may be null or missing)</li>
496          *      <li>title: an optional non-unique title for the container (may be null or missing)</li>
497          *      <li>isWorkbook: true if this container is a workbook. Workbooks do not appear in the left-hand project tree.</li>
498          *      <li>effectivePermissions: An array of effective permission unique names the group has.</li>
499          *  </ul>
500          * </li>
501          * <li><b>response:</b> The XMLHttpResponse object</li>
502          * </ul>
503          * @param {function} [config.failure] A reference to a function to call when an error occurs. This
504          * function will be passed the following parameters:
505          * <ul>
506          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
507          * <li><b>response:</b> The XMLHttpResponse object</li>
508          * </ul>
509          * @param {string} [config.containerPath] An alternate container in which to create a new container. If not specified,
510          * the current container path will be used.
511          * @param {object} [config.scope] A scoping object for the success and error callback functions (default to this).
512          * @returns {Mixed} In client-side scripts, this method will return a transaction id
513          * for the async request that can be used to cancel the request
514          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
515          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
516          */
517         createContainer : function(config)
518         {
519             var params = {};
520             params.name = config.name;
521             params.title = config.title;
522             params.description = config.description;
523             params.isWorkbook = config.isWorkbook;
524             params.folderType = config.folderType;
525 
526             return LABKEY.Ajax.request({
527                 url: LABKEY.ActionURL.buildURL("core", "createContainer", config.containerPath),
528                 method : 'POST',
529                 jsonData : params,
530                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
531                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true)
532             });
533         },
534         
535         /**
536          * Deletes an existing container, which may be a project, folder, or workbook.
537          * @param config A configuration object with the following properties
538          * @param {function} [config.success] A reference to a function to call with the API results. This
539          * function will be passed the following parameter:
540          * <ul>
541          * <li><b>object:</b> Empty JavaScript object</li>
542          * <li><b>response:</b> The XMLHttpResponse object</li>
543          * </ul>
544          * @param {function} [config.failure] A reference to a function to call when an error occurs. This
545          * function will be passed the following parameters:
546          * <ul>
547          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
548          * <li><b>response:</b> The XMLHttpResponse object</li>
549          * </ul>
550          * @param {string} [config.containerPath] The container which should be deleted. If not specified,
551          * the current container path will be deleted.
552          * @param {object} [config.scope] A scoping object for the success and error callback functions (default to this).
553          * @returns {Mixed} In client-side scripts, this method will return a transaction id
554          * for the async request that can be used to cancel the request
555          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
556          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
557          */
558         deleteContainer : function(config)
559         {
560             return LABKEY.Ajax.request({
561                 url: LABKEY.ActionURL.buildURL("core", "deleteContainer", config.containerPath),
562                 method : 'POST',
563                 jsonData : {},
564                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
565                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true)
566             });
567         },
568 
569         /**
570          * Moves an existing container, which may be a folder or workbook to be the subfolder of another folder and/or project.
571          * @param config A configuration object with the following properties
572          * @param {string} config.containerPath The current container path of the container that is going to be moved. Additionally, the container
573          * entity id is also valid.
574          * @param {string} config.destinationParent The container path of destination parent. Additionally, the destination parent entity id
575          * is also valid.
576          * @param {boolean} [config.addAlias] Add alias of current container path to container that is being moved (defaults to True).
577          * @param {function} [config.success] A reference to a function to call with the API results. This function will
578          * be passed the following parameters:
579          * <ul>
580          * <li><b>object:</b> Empty JavaScript object</li>
581          * <li><b>response:</b> The XMLHttpResponse object</li>
582          * </ul>
583          * @param {function} [config.failure] A reference to a function to call when an error occurs. This
584          * function will be passed the following parameters:
585          * <ul>
586          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
587          * <li><b>response:</b> The XMLHttpResponse object</li>
588          * </ul>
589          * @param {object} [config.scope] A scoping object for the success and error callback functions (default to this).
590          */
591         moveContainer : function(config) {
592 
593             var params = {};
594             params.container = config.container || config.containerPath;
595             params.parent = config.destinationParent || config.parent || config.parentPath;
596             params.addAlias = true;
597 
598             if (!params.container) {
599                 console.error("'containerPath' must be specified for LABKEY.Security.moveContainer invocation.");
600                 return;
601             }
602 
603             if (!params.parent) {
604                 console.error("'parent' must be specified for LABKEY.Security.moveContainer invocation.");
605                 return;
606             }
607             
608             if (config.addAlias === false) {
609                 params.addAlias = false;
610             }
611             
612             return LABKEY.Ajax.request({
613                 url : LABKEY.ActionURL.buildURL("core", "moveContainer", params.container),
614                 method : 'POST',
615                 jsonData : params,
616                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
617                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true)
618             });
619         },
620 
621         /**
622          * Retrieves the full set of folder types that are available on the server.
623          * @param config A configuration object with the following properties
624          * @param {function} config.success A reference to a function to call with the API results. This
625          * function will be passed the following parameter:
626          * <ul>
627          * <li><b>folderTypes:</b> Map from folder type name to folder type object, which consists of the following properties:
628          *  <ul>
629          *      <li><b>name:</b> the cross-version stable name of the folder type</li>
630          *      <li><b>description:</b> a short description of the folder type</li>
631          *      <li><b>label:</b> the name that's shown to the user for this folder type</li>
632          *      <li><b>defaultModule:</b> name of the module that provides the home screen for this folder type</li>
633          *      <li><b>activeModules:</b> an array of module names that are automatically active for this folder type</li>
634          *      <li><b>workbookType:</b> boolean that indicates if this is specifically intended to use as a workbook type
635          *      <li><b>requiredWebParts:</b> an array of web parts that are part of this folder type and cannot be removed
636          *          <ul>
637          *              <li><b>name:</b> the name of the web part</li>
638          *              <li><b>properties:</b> a map of properties that are automatically set</li>
639          *          </ul>
640          *      </li>
641          *      <li><b>preferredWebParts:</b> an array of web parts that are part of this folder type but may be removed. Same structure as requiredWebParts</li>
642          *  </ul>
643          * </li>
644          * <li><b>response:</b> The XMLHttpResponse object</li>
645          * </ul>
646          * @param {function} [config.failure] A reference to a function to call when an error occurs. This
647          * function will be passed the following parameters:
648          * <ul>
649          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
650          * <li><b>response:</b> The XMLHttpResponse object</li>
651          * </ul>
652          * @param {object} [config.scope] A scoping object for the success and error callback functions (default to this).
653          * @returns {Mixed} In client-side scripts, this method will return a transaction id
654          * for the async request that can be used to cancel the request
655          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
656          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
657          */
658         getFolderTypes : function(config)
659         {
660             return LABKEY.Ajax.request({
661                 url: LABKEY.ActionURL.buildURL("core", "getFolderTypes", config.containerPath),
662                 method : 'POST',
663                 jsonData : {},
664                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
665                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true)
666             });
667         },
668 
669 
670         /**
671          * Retrieves the full set of modules that are installed on the server.
672          * @param config A configuration object with the following properties
673          * @param {function} config.success A reference to a function to call with the API results. This
674          * function will be passed the following parameter:
675          * <ul>
676          * <li><b>folderType:</b> the folderType, based on the container used when calling this API</li>
677          * <li><b>modules:</b> Array of all modules present on this site, each of which consists of the following properties:
678          *  <ul>
679          *      <li><b>name:</b> the name of the module</li>
680          *      <li><b>required:</b> whether this module is required in the folder type specified above</li>
681          *      <li><b>tabName:</b> name of the tab associated with this module</li>
682          *      <li><b>active:</b> whether this module should be active for this container</li>
683          *      <li><b>enabled:</b> whether this module should be enabled by default for this container</li>
684          *  </ul>
685          * </li>
686          * <li><b>response:</b> The XMLHttpResponse object</li>
687          * </ul>
688          * @param {function} [config.failure] A reference to a function to call when an error occurs. This
689          * function will be passed the following parameters:
690          * <ul>
691          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
692          * <li><b>response:</b> The XMLHttpResponse object</li>
693          * </ul>
694          * @param {object} [config.scope] A scoping object for the success and error callback functions (default to this).
695          * @returns {Mixed} In client-side scripts, this method will return a transaction id
696          * for the async request that can be used to cancel the request
697          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
698          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
699          */
700         getModules : function(config)
701         {
702             return LABKEY.Ajax.request({
703                 url: LABKEY.ActionURL.buildURL("admin", "getModules", config.containerPath),
704                 method : 'POST',
705                 jsonData : {},
706                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
707                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true)
708             });
709         },
710 
711 
712         /**
713          * Returns information about the specified container, including the user's current permissions within
714          * that container. If the includeSubfolders config option is set to true, it will also return information
715          * about all descendants the user is allowed to see.
716          * @param config A configuration object with the following properties
717          * @param {Mixed} [config.container] A container id or full-path String or an Array of container id/full-path Strings.  If not present, the current container is used.
718          * @param {boolean} [config.includeSubfolders] If set to true, the entire branch of containers will be returned.
719          * If false, only the immediate children of the starting container will be returned (defaults to false).
720          * @param {boolean} [config.includeEffectivePermissions] If set to false, the effective permissions for this container resource
721          * will not be included. (defaults to true)
722          * @param {int} [config.depth] May be used to control the depth of recursion if includeSubfolders is set to true.
723          * @param {Array} [config.moduleProperties] The names (Strings) of modules whose Module Property values should be included for each container.
724          * Use "*" to get the value of all Module Properties for all modules.
725          * @param {function} config.success A reference to a function to call with the API results. This
726          * function will be passed the following parameters:
727          * <ul>
728          * <li><b>containersInfo:</b>
729          * If <code>config.container</code> is an Array, an object with property
730          * <code>containers</code> and value Array of 'container info' is returned.
731          * If <code>config.container</code> is a String, a object of 'container info' is returned.
732          * <br>
733          * The 'container info' properties are as follows:
734          *  <ul>
735          *      <li>id: the id of the requested container</li>
736          *      <li>name: the name of the requested container</li>
737          *      <li>path: the path of the requested container</li>
738          *      <li>sortOrder: the relative sort order of the requested container</li>
739          *      <li>activeModules: an assay of the names (strings) of active modules in the container</li>
740          *      <li>folderType: the name (string) of the folder type, matched with getFolderTypes()</li>
741          *      <li>description: an optional description for the container (may be null or missing)</li>
742          *      <li>title: an optional non-unique title for the container (may be null or missing)</li>
743          *      <li>isWorkbook: true if this container is a workbook. Workbooks do not appear in the left-hand project tree.</li>
744          *      <li>isContainerTab: true if this container is a Container Tab. Container Tabs do not appear in the left-hand project tree.</li>
745          *      <li>userPermissions: (DEPRECATED) the permissions the current user has in the requested container.
746          *          Use this value with the hasPermission() method to test for specific permissions.</li>
747          *      <li>effectivePermissions: An array of effective permission unique names the group has.</li>
748          *      <li>children: if the includeSubfolders parameter was true, this will contain
749          *          an array of child container objects with the same shape as the parent object.</li>
750          *      <li>moduleProperties: if requested in the config object, an array of module properties for each included module:
751          *          <ul>
752          *              <li>name: the name of the Module Property.</li>
753          *              <li>moduleName: the name of the module specifying this property.</li>
754          *              <li>effectiveValue: the value of the property, including a value potentially inherited from parent containers.</li>
755          *              <li>value: the value of the property as set for this specific container</li>
756          *          </ul>
757          *      </li>
758          *  </ul>
759          * </li>
760          * <li><b>response:</b> The XMLHttpResponse object</li>
761          * </ul>
762          * @param {function} [config.failure] A reference to a function to call when an error occurs. This
763          * function will be passed the following parameters:
764          * <ul>
765          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
766          * <li><b>response:</b> The XMLHttpResponse object</li>
767          * </ul>
768          * @param {string} [config.containerPath] An alternate container path to get permissions from. If not specified,
769          * the current container path will be used.
770          * @param {object} [config.scope] A scoping object for the success and error callback functions (default to this).
771          * @returns {Mixed} In client-side scripts, this method will return a transaction id
772          * for the async request that can be used to cancel the request
773          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
774          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
775          */
776         getContainers : function(config)
777         {
778             var params = {};
779             config = config || {};
780             if (undefined != config.container)
781             {
782                 if (LABKEY.Utils.isArray(config.container))
783                 {
784                     params.multipleContainers = true;
785                 }
786                 else
787                 {
788                     config.container = [ config.container ];
789                 }
790                 params.container = config.container;
791             }
792             if (undefined != config.includeSubfolders)
793                 params.includeSubfolders = config.includeSubfolders;
794             if (undefined != config.depth)
795                 params.depth = config.depth;
796             if (undefined != config.moduleProperties)
797                 params.moduleProperties = config.moduleProperties;
798             if (undefined != config.includeEffectivePermissions)
799                 params.includeEffectivePermissions = config.includeEffectivePermissions;
800 
801             return LABKEY.Ajax.request({
802                 url: LABKEY.ActionURL.buildURL("project", "getContainers", config.containerPath),
803                 method : 'GET',
804                 params: params,
805                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
806                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true)
807             });
808         },
809 
810         /**
811          * Exposes limited information about the current user. This property returns a JavaScript object
812          * with the following properties:
813          * <ul>
814          * <li>id: the user's unique id number</li>
815          * <li>displayName: the user's display name</li>
816          * <li>email: the user's email address</li>
817          * <li>canInsert: set to true if this user can insert data in the current folder</li>
818          * <li>canUpdate: set to true if this user can update data in the current folder</li>
819          * <li>canUpdateOwn: set to true if this user can update data this user created in the current folder</li>
820          * <li>canDelete: set to true if this user can delete data in the current folder</li>
821          * <li>canDeleteOwn: set to true if this user can delete data this user created in the current folder</li>
822          * <li>isAdmin: set to true if this user has admin permissions in the current folder</li>
823          * <li>isGuest: set to true if this user is the guest (anonymous) user</li>
824          * <li>isSystemAdmin: set to true if this user is a system administrator</li>
825          * <li>isDeveloper: set to true if this user is a developer</li>
826          * <li>isSignedIn: set to true if this user is signed in</li>
827          * </ul>
828          */
829         currentUser : LABKEY.user,
830 
831         /**
832          * Exposes limited information about the current container. This property returns a JavaScript object
833          * with the following properties:
834          * <ul>
835          * <li>id: the container's unique id (entityid)</li>
836          * <li>name: the name of the container</li>
837          * <li>path: the path of the current container</li>
838          * <li>type: the type of container, either project, folder or workbook</li>
839          * </ul>
840          */
841         currentContainer : LABKEY.container,
842 
843         /**
844          * Returns the set of groups the current user belongs to in the current container or specified containerPath.
845          * This may be called by any user.
846          * @param {object} config A configuration object with the following properties:
847          * @param {function} config.success A reference to a function that will be called with the results.
848          * This function will receive the follwing parameters:
849          * <ul>
850          * <li>results: an object with the following properties:
851          *  <ul>
852          *      <li>groups: An array of group information objects, each of which has the following properties:
853          *          <ul>
854          *              <li>id: The unique id of the group.</li>
855          *              <li>name: The name of the group.</li>
856          *              <li>isProjectGroup: true if this group is defined at the project level.</li>
857          *              <li>isSystemGroup: true if this group is defined at the system level.</li>
858          *          </ul>
859          *      </li>
860          *  </ul>
861          * </li>
862          * </ul>
863          * @param {function} [config.failure] A reference to a function to call when an error occurs. This
864          * function will be passed the following parameters:
865          * <ul>
866          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
867          * <li><b>response:</b> The XMLHttpResponse object</li>
868          * </ul>
869          * @param {string} [config.containerPath] An alternate container path to get permissions from. If not specified,
870          * the current container path will be used.
871          * @param {object} [config.scope] A scoping object for the success and error callback functions (default to this).
872          * @returns {Mixed} In client-side scripts, this method will return a transaction id
873          * for the async request that can be used to cancel the request
874          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
875          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
876          */
877         getGroupsForCurrentUser : function(config)
878         {
879             return LABKEY.Ajax.request({
880                 url: LABKEY.ActionURL.buildURL("security", "getGroupsForCurrentUser", config.containerPath),
881                 method: 'GET',
882                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
883                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true)
884             });
885         },
886 
887         /**
888          * Ensures that the current user is logged in.
889          * @param {object} config A configuration object with the following properties:
890          * @param {boolean} [config.useSiteLoginPage] Set to true to redirect the browser to the normal site login page.
891          * After the user logs in, the browser will be redirected back to the current page, and the current user information
892          * will be available via {@link LABKEY.Security.currentUser}. If omitted or set to false, this function
893          * will attempt to login via an AJAX request, which will cause the browser to display the basic authentication
894          * dialog. After the user logs in successfully, the config.success function will be called.
895          * @param {function} config.success A reference to a function that will be called after a successful login.
896          * It is passed the following parameters:
897          * <ul>
898          *  <li>results: an object with the following properties:
899          *      <ul>
900          *          <li>currentUser: a reference to the current user. See {@link LABKEY.Security.currentUser} for more details.</li>
901          *      </ul>
902          *  </li>
903          * </ul>
904          * Note that if the current user is already logged in, the successCallback function will be called immediately,
905          * passing the current user information from {@link LABKEY.Security.currentUser}.
906          * @param {function} [config.failure] A reference to a function to call when an error occurs. This
907          * function will be passed the following parameters:
908          * <ul>
909          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
910          * <li><b>response:</b> The XMLHttpResponse object</li>
911          * </ul>
912          * @param {object} [config.scope] A scoping object for the success and error callback functions (default to this).
913          * @param {boolean} [config.force] Set to true to force a login even if the user is already logged in.
914          * This is useful for keeping a session alive during a long-lived page. To do so, call this function
915          * with config.force set to true, and config.useSiteLoginPage to false (or omit).
916          * @returns {Mixed} In client-side scripts, this method will return a transaction id
917          * for the async request that can be used to cancel the request
918          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
919          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
920          */
921         ensureLogin : function(config)
922         {
923             if (LABKEY.Security.currentUser.isGuest || config.force)
924             {
925                 if (config.useSiteLoginPage)
926                 {
927                     window.location = LABKEY.ActionURL.buildURL("login", "login") + "?returnUrl=" + window.location;
928                 }
929                 else
930                 {
931                     return LABKEY.Ajax.request({
932                         url: LABKEY.ActionURL.buildURL("security", "ensureLogin"),
933                         method: 'GET',
934                         success: LABKEY.Utils.getCallbackWrapper(function(data, req){
935                             if(data.currentUser)
936                                 LABKEY.Security.currentUser = data.currentUser;
937 
938                             if(LABKEY.Utils.getOnSuccess(config))
939                                 LABKEY.Utils.getOnSuccess(config).call(config.scope || this, data, req);
940 
941                         }, this),
942                         failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true)
943                     });
944                 }
945             }
946             else
947             {
948                 LABKEY.Utils.getOnSuccess(config).call(config.scope || this, {currentUser: LABKEY.Security.currentUser});
949             }
950         },
951 
952         /**
953          * Returns the tree of securable resources from the current container downward
954          * @param config A configuration object with the following properties:
955          * @param {Boolean} config.includeSubfolders If set to true, the response will include subfolders
956          * and their contained securable resources (defaults to false).
957          * @param {Boolean} config.includeEffectivePermissions If set to true, the response will include the
958          * list of effective permissions (unique names) the current user has to each resource (defaults to false).
959          * These permissions are calcualted based on the current user's group memberships and role assignments, and
960          * represent the actual permissions the user has to these resources at the time of the API call.
961          * @param {Function} config.success A reference to a function to call with the API results. This
962          * function will be passed the following parameters:
963          * <ul>
964          * <li><b>data:</b> an object with a property named "resources" which contains the root resource.
965          * Each resource has the following properties:
966          *  <ul>
967          *      <li>id: The unique id of the resource (String, typically a GUID).</li>
968          *      <li>name: The name of the resource suitable for showing to a user.</li>
969          *      <li>description: The description of the reosurce.</li>
970          *      <li>resourceClass: The fully-qualified Java class name of the resource.</li>
971          *      <li>sourceModule: The name of the module in which the resource is defined and managed</li>
972          *      <li>parentId: The parent resource's id (may be omitted if no parent)</li>
973          *      <li>parentContainerPath: The parent resource's container path (may be omitted if no parent)</li>
974          *      <li>children: An array of child resource objects.</li>
975          *      <li>effectivePermissions: An array of permission unique names the current user has on the resource. This will be
976          *          present only if the includeEffectivePermissions property was set to true on the config object.</li>
977          *  </ul>
978          * </li>
979          * <li><b>response:</b> The XMLHttpResponse object</li>
980          * </ul>
981          * @param {Function} [config.failure] A reference to a function to call when an error occurs. This
982          * function will be passed the following parameters:
983          * <ul>
984          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
985          * <li><b>response:</b> The XMLHttpResponse object</li>
986          * </ul>
987          * @param {object} [config.scope] A scoping object for the success and error callback functions (default to this).
988          * @param {string} [config.containerPath] An alternate container path to get permissions from. If not specified,
989          * the current container path will be used.
990          * @returns {Mixed} In client-side scripts, this method will return a transaction id
991          * for the async request that can be used to cancel the request
992          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
993          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
994          */
995         getSecurableResources : function(config)
996         {
997             var params = {};
998             if(undefined != config.includeSubfolders)
999                 params.includeSubfolders = config.includeSubfolders;
1000             if(undefined != config.includeEffectivePermissions)
1001                 params.includeEffectivePermissions = config.includeEffectivePermissions;
1002 
1003             return LABKEY.Ajax.request({
1004                 url: LABKEY.ActionURL.buildURL("security", "getSecurableResources", config.containerPath),
1005                 method: "GET",
1006                 params: params,
1007                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
1008                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true)
1009             });
1010         },
1011 
1012         /*
1013          * EXPERIMENTAL! gets permissions for a set of tables within a schema.
1014          * Currently only study tables have individual permissions so only works on the study schema
1015          * @param config A configuration object with the following properties:
1016          * @param {object} [config.scope] A scoping object for the success and error callback functions (default to this).
1017          * @param {object} [config.schemaName] Name of the schema to retrieve information on.
1018          * @param {string} [config.containerPath] An alternate container path to get permissions from. If not specified,
1019          * the current container path will be used.
1020          * @param {Function} config.success A reference to a function to call with the API results. This
1021          * function will be passed the following parameters:
1022          * <ul>
1023          * <li><b>data:</b> an object with a property named "schemas" which contains a queries object.
1024          * The queries object property with the name of each table/queries. So
1025          * schemas.study.queries.Demographics would yield the following results
1026          *  <ul>
1027          *      <li>id: The unique id of the resource (String, typically a GUID).</li>
1028          *      <li>name: The name of the resource suitable for showing to a user.</li>
1029          *      <li>description: The description of the reosurce.</li>
1030          *      <li>resourceClass: The fully-qualified Java class name of the resource.</li>
1031          *      <li>sourceModule: The name of the module in which the resource is defined and managed</li>
1032          *      <li>parentId: The parent resource's id (may be omitted if no parent)</li>
1033          *      <li>parentContainerPath: The parent resource's container path (may be omitted if no parent)</li>
1034          *      <li>children: An array of child resource objects.</li>
1035          *      <li>effectivePermissions: An array of permission unique names the current user has on the resource. This will be
1036          *          present only if the includeEffectivePermissions property was set to true on the config object.</li>
1037          *      <li>permissionMap: An object with one property per effectivePermission allowed the user. This restates
1038          *          effectivePermissions in a slightly more convenient way
1039          *  </ul>
1040          * </li>
1041          * <li><b>response:</b> The XMLHttpResponse object</li>
1042          * </ul>
1043          * @param {Function} [config.failure] A reference to a function to call when an error occurs. This
1044          * function will be passed the following parameters:
1045          * <ul>
1046          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
1047          * <li><b>response:</b> The XMLHttpResponse object</li>
1048          * </ul>
1049          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1050          * for the async request that can be used to cancel the request
1051          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1052          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1053          */
1054         getSchemaPermissions: function(config) {
1055             if (config.schemaName && config.schemaName != "study")
1056                 throw "Method only works for the study schema";
1057 
1058             var successCallback = function(json, response) {
1059 
1060                 //First lets make sure there is a study in here.
1061                 var studyResource = null;
1062                 for (var i = 0; i < json.resources.children.length; i++)
1063                 {
1064                     var resource = json.resources.children[i];
1065                     if (resource.resourceClass == "org.labkey.study.model.StudyImpl"){
1066                         studyResource = resource;
1067                         break;
1068                     }
1069                 }
1070 
1071                 if (null == studyResource)
1072                 {
1073                     config.failure.apply(config.scope || this, [{description:"No study found in container."}, response]);
1074                     return;
1075                 }
1076 
1077                 var result = {queries:{}}, dataset;
1078 
1079                 for (i=0; i < studyResource.children.length; i++) {
1080                     dataset = studyResource.children[i];
1081                     result.queries[dataset.name] = dataset;
1082                     dataset.permissionMap = {};
1083                     for (var j=0; j < dataset.effectivePermissions.length; j++) {
1084                         dataset.permissionMap[dataset.effectivePermissions[j]] = true;
1085                     }
1086                 }
1087 
1088                 config.success.apply(config.scope || this, [{schemas:{study:result}}, response]);
1089             };
1090 
1091             var myConfig = {};
1092             if (config) {
1093                 for (var c in config) {
1094                     if (config.hasOwnProperty(c)) {
1095                         myConfig[c] = config[c];
1096                     }
1097                 }
1098             }
1099             myConfig.includeEffectivePermissions = true;
1100             myConfig.success = successCallback;
1101             return LABKEY.Security.getSecurableResources(myConfig);
1102         },
1103 
1104         /**
1105          * Returns the complete set of roles defined on the server, along with the permissions each role grants.
1106          * @param config A configuration object with the following properties:
1107          * @param {Function} config.success A reference to a function to call with the API results. This
1108          * function will be passed the following parameters:
1109          * <ul>
1110          * <li><b>roles:</b> An array of role objects, each of which has the following properties:
1111          *  <ul>
1112          *      <li>uniqueName: The unique name of the resource (String, typically a fully-qualified class name).</li>
1113          *      <li>name: The name of the role suitable for showing to a user.</li>
1114          *      <li>description: The description of the role.</li>
1115          *      <li>sourceModule: The name of the module in which the role is defined.</li>
1116          *      <li>permissions: An array of permissions the role grants. Each permission has the following properties:
1117          *          <ul>
1118          *              <li>uniqueName: The unique name of the permission (String, typically a fully-qualified class name).</li>
1119          *              <li>name: The name of the permission.</li>
1120          *              <li>description: A description of the permission.</li>
1121          *              <li>sourceModule: The module in which the permission is defined.</li>
1122          *          </ul>
1123          *      </li>
1124          *  </ul>
1125          * </li>
1126          * <li><b>response:</b> The XMLHttpResponse object</li>
1127          * </ul>
1128          * @param {Function} [config.failure] A reference to a function to call when an error occurs. This
1129          * function will be passed the following parameters:
1130          * <ul>
1131          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
1132          * <li><b>response:</b> The XMLHttpResponse object</li>
1133          * </ul>
1134          * @param {object} [config.scope] A scoping object for the success and error callback functions (default to this).
1135          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1136          * for the async request that can be used to cancel the request
1137          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1138          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1139          */
1140         getRoles : function(config)
1141         {
1142             return LABKEY.Ajax.request({
1143                 url: LABKEY.ActionURL.buildURL("security", "getRoles"),
1144                 method: "GET",
1145                 success: LABKEY.Utils.getCallbackWrapper(function(data, req){
1146 
1147                     //roles and perms are returned in two separate blocks for efficiency
1148                     var idx;
1149                     var permMap = {};
1150                     var perm;
1151                     for(idx = 0; idx < data.permissions.length; ++idx)
1152                     {
1153                         perm = data.permissions[idx];
1154                         permMap[perm.uniqueName] = perm;
1155                     }
1156 
1157                     var idxPerm;
1158                     var role;
1159                     for(idx = 0; idx < data.roles.length; ++idx)
1160                     {
1161                         role = data.roles[idx];
1162                         for(idxPerm = 0; idxPerm < role.permissions.length; ++idxPerm)
1163                         {
1164                             role.permissions[idxPerm] = permMap[role.permissions[idxPerm]];
1165                         }
1166                     }
1167 
1168                     var fn = LABKEY.Utils.getOnSuccess(config);
1169                     if (fn)
1170                         fn.call(config.scope || this, data.roles, req);
1171 
1172                 }, this),
1173                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true)
1174             });
1175         },
1176 
1177         /**
1178          * Retrieves the security policy for the requested resource id. Note that this will return the
1179          * policy in effect for this resource, which might be the policy from a parent resource if there
1180          * is no explicit policy set on the requested resource. Use the isInherited method on the returned
1181          * LABKEY.SecurityPolicy object to determine if the policy is inherited or not.
1182          * Note that the securable resource must be within the current container, or one of its descendants.
1183          * @param config A configuration object with the following properties
1184          * @param {String} config.resourceId The unique id of the securable resource.
1185          * @param {Function} config.success A reference to a function to call with the API results. This
1186          * function will be passed the following parameters:
1187          * <ul>
1188          * <li><b>policy:</b> an instance of a LABKEY.SecurityPolicy object.</li>
1189          * <li><b>relevantRoles:</b> an array of role ids that are relevant for the given resource.</li>
1190          * <li><b>response:</b> The XMLHttpResponse object</li>
1191          * </ul>
1192          * @param {Function} [config.failure] A reference to a function to call when an error occurs. This
1193          * function will be passed the following parameters:
1194          * <ul>
1195          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
1196          * <li><b>response:</b> The XMLHttpResponse object</li>
1197          * </ul>
1198          * @param {object} [config.scope] A scoping object for the success and error callback functions (default to this).
1199          * @param {string} [config.containerPath] An alternate container path to get permissions from. If not specified,
1200          * the current container path will be used.
1201          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1202          * for the async request that can be used to cancel the request
1203          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1204          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1205          */
1206         getPolicy : function(config)
1207         {
1208             return LABKEY.Ajax.request({
1209                 url: LABKEY.ActionURL.buildURL("security", "getPolicy", config.containerPath),
1210                 method: "GET",
1211                 params: { resourceId: config.resourceId },
1212                 success: LABKEY.Utils.getCallbackWrapper(function(data, req){
1213                     data.policy.requestedResourceId = config.resourceId;
1214                     LABKEY.Utils.getOnSuccess(config).call(config.scope || this, data.policy, data.relevantRoles, req);
1215                 }, this),
1216                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true)
1217             });
1218         },
1219 
1220         /**
1221          * Deletes the security policy for the requested resource id. This will cause resource to inherit its
1222          * security policy from its parent resource.
1223          * @param config A configuration object with the following properties
1224          * @param {String} config.resourceId The unique id of the securable resource.
1225          * @param {Function} config.success A reference to a function to call with the API results. This
1226          * function will be passed the following parameters:
1227          * <ul>
1228          * <li><b>data:</b> a simple object with one property called 'success' which will be set to true.</li>
1229          * <li><b>response:</b> The XMLHttpResponse object</li>
1230          * </ul>
1231          * @param {Function} [config.failure] A reference to a function to call when an error occurs. This
1232          * function will be passed the following parameters:
1233          * <ul>
1234          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
1235          * <li><b>response:</b> The XMLHttpResponse object</li>
1236          * </ul>
1237          * @param {Object} [config.scope] A scoping object for the success and error callback functions (default to this).
1238          * @param {string} [config.containerPath] An alternate container path to get permissions from. If not specified,
1239          * the current container path will be used.
1240          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1241          * for the async request that can be used to cancel the request
1242          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1243          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1244          */
1245         deletePolicy : function(config)
1246         {
1247             return LABKEY.Ajax.request({
1248                 url: LABKEY.ActionURL.buildURL("security", "deletePolicy", config.containerPath),
1249                 method: "POST",
1250                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
1251                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
1252                 jsonData: { resourceId: config.resourceId },
1253                 headers : {
1254                     'Content-Type' : 'application/json'
1255                 }
1256             });
1257         },
1258 
1259         /**
1260          * Saves the supplied security policy. This object should be a LABKEY.SecurityPolicy object. This
1261          * method will completely overwrite the existing policy for the resource. If another user has changed
1262          * the policy in between the time it was selected and this method is called, the save will fail with
1263          * an optimistic concurrency exception. To force your policy over the other, call the setModified()
1264          * method on the policy passing null.
1265          * @param config A configuration object with the following properties
1266          * @param {String} config.policy The LABKEY.SecurityPolicy object
1267          * @param {Function} config.success A reference to a function to call with the API results. This
1268          * function will be passed the following parameters:
1269          * <ul>
1270          * <li><b>data:</b> a simple object with one property called 'success' which will be set to true.</li>
1271          * <li><b>response:</b> The XMLHttpResponse object</li>
1272          * </ul>
1273          * @param {Function} [config.failure] A reference to a function to call when an error occurs. This
1274          * function will be passed the following parameters:
1275          * <ul>
1276          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
1277          * <li><b>response:</b> The XMLHttpResponse object</li>
1278          * </ul>
1279          * @param {Object} [config.scope] A scoping object for the success and error callback functions (default to this).
1280          * @param {string} [config.containerPath] An alternate container path to get permissions from. If not specified,
1281          * the current container path will be used.
1282          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1283          * for the async request that can be used to cancel the request
1284          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1285          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1286          */
1287         savePolicy : function(config)
1288         {
1289             return LABKEY.Ajax.request({
1290                 url: LABKEY.ActionURL.buildURL("security", "savePolicy", config.containerPath),
1291                 method : 'POST',
1292                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
1293                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
1294                 jsonData : config.policy.policy,
1295                 headers : {
1296                     'Content-Type' : 'application/json'
1297                 }
1298             });
1299         },
1300 
1301         /**
1302          * Creates a new group. The new group will be created at the project level when the current
1303          * container is a folder or project, or will be created at the system level if the current
1304          * container is the root.
1305          * @param config A configuration object with the following properties:
1306          * @param {String} config.groupName The name of the group to create
1307          * @param {Function} config.success A reference to a function to call with the API results. This
1308          * function will be passed the following parameters:
1309          * <ul>
1310          * <li><b>data:</b> a simple object with two properties: id and name (the new group id and name respectively)</li>
1311          * <li><b>response:</b> The XMLHttpResponse object</li>
1312          * </ul>
1313          * @param {Function} [config.failure] A reference to a function to call when an error occurs. This
1314          * function will be passed the following parameters:
1315          * <ul>
1316          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
1317          * <li><b>response:</b> The XMLHttpResponse object</li>
1318          * </ul>
1319          * @param {Object} [config.scope] A scoping object for the success and error callback functions (default to this).
1320          * @param {string} [config.containerPath] An alternate container path to get permissions from. If not specified,
1321          * the current container path will be used.
1322          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1323          * for the async request that can be used to cancel the request
1324          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1325          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1326          */
1327         createGroup : function(config)
1328         {
1329             var params = {name: config.groupName};
1330             return LABKEY.Ajax.request({
1331                 url: LABKEY.ActionURL.buildURL("security", "createGroup", config.containerPath),
1332                 method: "POST",
1333                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
1334                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
1335                 jsonData: params,
1336                 headers : {
1337                     'Content-Type' : 'application/json'
1338                 }
1339             });
1340         },
1341 
1342         /**
1343          * Deletes a group.
1344          * @param config A configuration object with the following properties:
1345          * @param {int} config.groupId The id of the group to delete
1346          * @param {Function} config.success A reference to a function to call with the API results. This
1347          * function will be passed the following parameters:
1348          * <ul>
1349          * <li><b>data:</b> a simple object with a property named "deleted" that contains the deleted group id.</li>
1350          * <li><b>response:</b> The XMLHttpResponse object</li>
1351          * </ul>
1352          * @param {Function} [config.failure] A reference to a function to call when an error occurs. This
1353          * function will be passed the following parameters:
1354          * <ul>
1355          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
1356          * <li><b>response:</b> The XMLHttpResponse object</li>
1357          * </ul>
1358          * @param {Object} [config.scope] A scoping object for the success and error callback functions (default to this).
1359          * @param {string} [config.containerPath] An alternate container path to get permissions from. If not specified,
1360          * the current container path will be used.
1361          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1362          * for the async request that can be used to cancel the request
1363          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1364          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1365          */
1366         deleteGroup : function(config)
1367         {
1368             var params = {id: config.groupId};
1369             return LABKEY.Ajax.request({
1370                 url: LABKEY.ActionURL.buildURL("security", "deleteGroup", config.containerPath),
1371                 method: "POST",
1372                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
1373                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
1374                 jsonData: params,
1375                 headers : {
1376                     'Content-Type' : 'application/json'
1377                 }
1378             });
1379         },
1380 
1381         /**
1382          * Renames a group.
1383          * @param config A configuration object with the following properties:
1384          * @param {int} config.groupId The id of the group to delete
1385          * @param {String} config.newName The new name for the group
1386          * @param {Function} config.success A reference to a function to call with the API results. This
1387          * function will be passed the following parameters:
1388          * <ul>
1389          * <li><b>data:</b> a simple object with the following properties: 'renamed'=the group id; 'oldName'=the old name; 'newName'=the new name.</li>
1390          * <li><b>response:</b> The XMLHttpResponse object</li>
1391          * </ul>
1392          * @param {Function} [config.failure] A reference to a function to call when an error occurs. This
1393          * function will be passed the following parameters:
1394          * <ul>
1395          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
1396          * <li><b>response:</b> The XMLHttpResponse object</li>
1397          * </ul>
1398          * @param {Object} [config.scope] A scoping object for the success and error callback functions (default to this).
1399          * @param {string} [config.containerPath] An alternate container path to get permissions from. If not specified,
1400          * the current container path will be used.
1401          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1402          * for the async request that can be used to cancel the request
1403          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1404          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1405          */
1406         renameGroup : function(config) {
1407             return LABKEY.Ajax.request({
1408                 url: LABKEY.ActionURL.buildURL("security", "renameGroup", config.containerPath),
1409                 method: "POST",
1410                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
1411                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
1412                 jsonData: { id: config.groupId, newName: config.newName },
1413                 headers : {
1414                     'Content-Type' : 'application/json'
1415                 }
1416             });
1417 
1418         },
1419 
1420         /**
1421          * Adds a new member to an existing group.
1422          * @param config A configuration object with the following properties:
1423          * @param {int} config.groupId The id of the group to which you want to add the member.
1424          * @param {int|int[]} config.principalIds An integer id or array of ids of the users or groups you want to add as members.
1425          * @param {Function} config.success A reference to a function to call with the API results. This
1426          * function will be passed the following parameters:
1427          * <ul>
1428          * <li><b>data:</b> a simple object with a property named "added" that contains the added principal id.</li>
1429          * <li><b>response:</b> The XMLHttpResponse object</li>
1430          * </ul>
1431          * @param {Function} [config.failure] A reference to a function to call when an error occurs. This
1432          * function will be passed the following parameters:
1433          * <ul>
1434          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
1435          * <li><b>response:</b> The XMLHttpResponse object</li>
1436          * </ul>
1437          * @param {Object} [config.scope] A scoping object for the success and error callback functions (default to this).
1438          * @param {string} [config.containerPath] An alternate container path to get permissions from. If not specified,
1439          * the current container path will be used.
1440          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1441          * for the async request that can be used to cancel the request
1442          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1443          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1444          */
1445         addGroupMembers : function(config)
1446         {
1447             var params = {
1448                 groupId: config.groupId,
1449                 principalIds: (LABKEY.Utils.isArray(config.principalIds) ? config.principalIds : [config.principalIds])
1450             };
1451             return LABKEY.Ajax.request({
1452                 url: LABKEY.ActionURL.buildURL("security", "addGroupMember", config.containerPath),
1453                 method: "POST",
1454                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
1455                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
1456                 jsonData: params,
1457                 headers : {
1458                     'Content-Type' : 'application/json'
1459                 }
1460             });
1461 
1462         },
1463 
1464         /**
1465          * Removes a member from an existing group.
1466          * @param config A configuration object with the following properties:
1467          * @param {int} config.groupId The id of the group from which you want to remove the member.
1468          * @param {int|int[]} config.principalIds An integer id or array of ids of the users or groups you want to remove.
1469          * @param {Function} config.success A reference to a function to call with the API results. This
1470          * function will be passed the following parameters:
1471          * <ul>
1472          * <li><b>data:</b> a simple object with a property named "removed" that contains the removed principal id.</li>
1473          * <li><b>response:</b> The XMLHttpResponse object</li>
1474          * </ul>
1475          * @param {Function} [config.failure] A reference to a function to call when an error occurs. This
1476          * function will be passed the following parameters:
1477          * <ul>
1478          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
1479          * <li><b>response:</b> The XMLHttpResponse object</li>
1480          * </ul>
1481          * @param {Object} [config.scope] A scoping object for the success and error callback functions (default to this).
1482          * @param {string} [config.containerPath] An alternate container path to get permissions from. If not specified,
1483          * the current container path will be used.
1484          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1485          * for the async request that can be used to cancel the request
1486          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1487          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1488          */
1489         removeGroupMembers : function(config)
1490         {
1491             var params = {
1492                 groupId: config.groupId,
1493                 principalIds: (LABKEY.Utils.isArray(config.principalIds) ? config.principalIds : [config.principalIds])
1494             };
1495             return LABKEY.Ajax.request({
1496                 url: LABKEY.ActionURL.buildURL("security", "removeGroupMember", config.containerPath),
1497                 method: "POST",
1498                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
1499                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
1500                 jsonData: params,
1501                 headers : {
1502                     'Content-Type' : 'application/json'
1503                 }
1504             });
1505         },
1506 
1507         /**
1508          * Creates a new user account
1509          * @param config A configuration object with the following properties:
1510          * @param {String} config.email The new user's email address, or a semicolon separated list of email addresses.
1511          * @param {Boolean} config.sendEmail Set to false to stop the server from sending a welcome email to the user.
1512          * @param {String} config.optionalMessage An optional message to include in the new user registration email.
1513          * @param {Function} config.success A reference to a function to call with the API results. This
1514          * function will be passed the following parameters:
1515          * <ul>
1516          * <li><b>data:</b> a simple object, or array of objects, with three properties: userId, email, and message.</li>
1517          * <li><b>response:</b> The XMLHttpResponse object</li>
1518          * </ul>
1519          * @param {Function} [config.failure] A reference to a function to call when an error occurs. This
1520          * function will be passed the following parameters:
1521          * <ul>
1522          * <li><b>errorInfo:</b> an object containing detailed error information (may be null)</li>
1523          * <li><b>response:</b> The XMLHttpResponse object</li>
1524          * </ul>
1525          * @param {Object} [config.scope] A scoping object for the success and error callback functions (default to this).
1526          * @param {string} [config.containerPath] An alternate container path to get permissions from. If not specified,
1527          * the current container path will be used.
1528          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1529          * for the async request that can be used to cancel the request
1530          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1531          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1532          */
1533         createNewUser : function(config)
1534         {
1535             var params = {
1536                 email: config.email,
1537                 sendEmail: config.sendEmail,
1538                 optionalMessage: config.optionalMessage
1539             };
1540             return LABKEY.Ajax.request({
1541                 url: LABKEY.ActionURL.buildURL("security", "createNewUser", config.containerPath),
1542                 method: "POST",
1543                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
1544                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
1545                 jsonData: params,
1546                 headers : {
1547                     'Content-Type' : 'application/json'
1548                 }
1549             });
1550         },
1551 
1552         /**
1553          * Returns the name of the home container, which is automatically created when your server is set up.  It is usually 'home'
1554          * @returns {string} The name of the home container automatically created on this server.
1555          */
1556         getHomeContainer: function(){
1557             return LABKEY.homeContainer;
1558         },
1559 
1560         /**
1561          * Returns the name of the shared container, which is automatically created when your server is setup. It is usually 'Shared'
1562          * @returns {string} The name of the shared container automatically created on this server.
1563          */
1564         getSharedContainer: function(){
1565             return LABKEY.sharedContainer;
1566         }
1567     };
1568 };
1569