1 /** 2 * Copyright (C) 2005-2010 Alfresco Software Limited. 3 * 4 * This file is part of Alfresco 5 * 6 * Alfresco is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU Lesser General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * Alfresco is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public License 17 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 /** 21 * ConsoleUsers tool component. 22 * 23 * @namespace Alfresco 24 * @class Alfresco.ConsoleUsers 25 */ 26 (function() 27 { 28 /** 29 * YUI Library aliases 30 */ 31 var Dom = YAHOO.util.Dom, 32 Event = YAHOO.util.Event, 33 Element = YAHOO.util.Element; 34 35 /** 36 * Alfresco Slingshot aliases 37 */ 38 var $html = Alfresco.util.encodeHTML; 39 40 /** 41 * ConsoleUsers constructor. 42 * 43 * @param {String} htmlId The HTML id �of the parent element 44 * @return {Alfresco.ConsoleUsers} The new ConsoleUsers instance 45 * @constructor 46 */ 47 Alfresco.ConsoleUsers = function(htmlId) 48 { 49 this.name = "Alfresco.ConsoleUsers"; 50 Alfresco.ConsoleUsers.superclass.constructor.call(this, htmlId); 51 52 /* Register this component */ 53 Alfresco.util.ComponentManager.register(this); 54 55 /* Load YUI Components */ 56 Alfresco.util.YUILoaderHelper.require(["button", "container", "datasource", "datatable", "json", "history"], this.onComponentsLoaded, this); 57 58 /* Decoupled event listeners */ 59 YAHOO.Bubbling.on("viewUserClick", this.onViewUserClick, this); 60 61 /* Define panel handlers */ 62 var parent = this; 63 64 // NOTE: the panel registered first is considered the "default" view and is displayed first 65 66 /* Search Panel Handler */ 67 SearchPanelHandler = function SearchPanelHandler_constructor() 68 { 69 SearchPanelHandler.superclass.constructor.call(this, "search"); 70 }; 71 72 YAHOO.extend(SearchPanelHandler, Alfresco.ConsolePanelHandler, 73 { 74 75 /** 76 * INSTANCE VARIABLES 77 */ 78 79 /** 80 * Keeps track if this panel is searching or not 81 * 82 * @property isSearching 83 * @type Boolean 84 */ 85 isSearching: false, 86 87 88 /** 89 * PANEL LIFECYCLE CALLBACKS 90 */ 91 92 /** 93 * Called by the ConsolePanelHandler when this panel shall be loaded 94 * 95 * @method onLoad 96 */ 97 onLoad: function onLoad() 98 { 99 // Buttons 100 parent.widgets.searchButton = Alfresco.util.createYUIButton(parent, "search-button", parent.onSearchClick); 101 parent.widgets.newuserButton = Alfresco.util.createYUIButton(parent, "newuser-button", parent.onNewUserClick); 102 parent.widgets.uploadUsersButton = Alfresco.util.createYUIButton(parent, "uploadusers-button", parent.onUploadUsersClick); 103 104 var newuserSuccess = function(res) 105 { 106 if (!res.json.data.creationAllowed) 107 { 108 parent.widgets.newuserButton.set("disabled", true); 109 } 110 }; 111 112 // make an ajax call to get authentication mutability - "creationAllowed" will be returned as true 113 // in the response if the administrator is able to create new users on the alfresco server 114 Alfresco.util.Ajax.jsonGet( 115 { 116 url: Alfresco.constants.PROXY_URI + "api/authentication", 117 successCallback: 118 { 119 fn: newuserSuccess, 120 scope: this 121 }, 122 failureMessage: parent._msg("message.authenticationdetails-failure", $html(parent.group)) 123 }); 124 125 // DataTable and DataSource setup 126 parent.widgets.dataSource = new YAHOO.util.DataSource(Alfresco.constants.PROXY_URI + "api/people", 127 { 128 responseType: YAHOO.util.DataSource.TYPE_JSON, 129 responseSchema: 130 { 131 resultsList: "people", 132 metaFields: 133 { 134 recordOffset: "startIndex", 135 totalRecords: "totalRecords" 136 } 137 } 138 }); 139 140 var me = this; 141 142 // Work to be performed after data has been queried but before display by the DataTable 143 parent.widgets.dataSource.doBeforeParseData = function PeopleFinder_doBeforeParseData(oRequest, oFullResponse) 144 { 145 var updatedResponse = oFullResponse; 146 147 if (oFullResponse) 148 { 149 var items = oFullResponse.people; 150 151 // remove GUEST(s) 152 for (var i = 0; i < items.length; i++) 153 { 154 if (items[i].userName == "guest" || items[i].userName.indexOf("guest&") == 0) 155 { 156 items.splice(i, 1); 157 } 158 } 159 160 // initial sort by username field 161 items.sort(function(a, b) 162 { 163 return (a.userName > b.userName); 164 }); 165 166 // we need to wrap the array inside a JSON object so the DataTable gets the object it expects 167 updatedResponse = 168 { 169 "people": items 170 }; 171 } 172 173 // update Results Bar message with number of results found 174 if (items.length < parent.options.maxSearchResults) 175 { 176 me._setResultsMessage("message.results", $html(parent.searchTerm), items.length); 177 } 178 else 179 { 180 me._setResultsMessage("message.maxresults", parent.options.maxSearchResults); 181 } 182 183 return updatedResponse; 184 }; 185 186 // Setup the main datatable 187 this._setupDataTable(); 188 189 // register the "enter" event on the search text field 190 var searchText = Dom.get(parent.id + "-search-text"); 191 192 new YAHOO.util.KeyListener(searchText, 193 { 194 keys: YAHOO.util.KeyListener.KEY.ENTER 195 }, 196 { 197 fn: function() 198 { 199 parent.onSearchClick(); 200 }, 201 scope: parent, 202 correctScope: true 203 }, "keydown").enable(); 204 }, 205 206 onShow: function onShow() 207 { 208 Dom.get(parent.id + "-search-text").focus(); 209 }, 210 211 onUpdate: function onUpdate() 212 { 213 // update the text field - as this event could come from bookmark, navigation or a search button click 214 var searchTermElem = Dom.get(parent.id + "-search-text"); 215 searchTermElem.value = parent.searchTerm; 216 217 // check search length again as we may have got here via history navigation 218 if (!this.isSearching && parent.searchTerm !== undefined && parent.searchTerm.length >= parent.options.minSearchTermLength) 219 { 220 this.isSearching = true; 221 222 var me = this; 223 224 // Reset the custom error messages 225 me._setDefaultDataTableErrors(parent.widgets.dataTable); 226 227 // Don't display any message 228 parent.widgets.dataTable.set("MSG_EMPTY", parent._msg("message.searching")); 229 230 // Empty results table 231 parent.widgets.dataTable.deleteRows(0, parent.widgets.dataTable.getRecordSet().getLength()); 232 233 var successHandler = function ConsoleUsers__ps_successHandler(sRequest, oResponse, oPayload) 234 { 235 me._enableSearchUI(); 236 me._setDefaultDataTableErrors(parent.widgets.dataTable); 237 parent.widgets.dataTable.onDataReturnInitializeTable.call(parent.widgets.dataTable, sRequest, oResponse, oPayload); 238 }; 239 240 var failureHandler = function ConsoleUsers__ps_failureHandler(sRequest, oResponse) 241 { 242 me._enableSearchUI(); 243 if (oResponse.status == 401) 244 { 245 // Our session has likely timed-out, so refresh to offer the login page 246 window.location.reload(); 247 } 248 else 249 { 250 try 251 { 252 var response = YAHOO.lang.JSON.parse(oResponse.responseText); 253 parent.widgets.dataTable.set("MSG_ERROR", response.message); 254 parent.widgets.dataTable.showTableMessage(response.message, YAHOO.widget.DataTable.CLASS_ERROR); 255 me._setResultsMessage("message.noresults"); 256 } 257 catch(e) 258 { 259 me._setDefaultDataTableErrors(parent.widgets.dataTable); 260 } 261 } 262 }; 263 264 // Send the query to the server 265 parent.widgets.dataSource.sendRequest(me._buildSearchParams(parent.searchTerm), 266 { 267 success: successHandler, 268 failure: failureHandler, 269 scope: parent 270 }); 271 me._setResultsMessage("message.searchingFor", $html(parent.searchTerm)); 272 273 // Disable search button and display a wait feedback message if the users hasn't been found yet 274 parent.widgets.searchButton.set("disabled", true); 275 YAHOO.lang.later(2000, me, function(){ 276 if (me.isSearching) 277 { 278 if (!me.widgets.feedbackMessage) 279 { 280 me.widgets.feedbackMessage = Alfresco.util.PopupManager.displayMessage( 281 { 282 text: Alfresco.util.message("message.searching", parent.name), 283 spanClass: "wait", 284 displayTime: 0 285 }); 286 } 287 else if (!me.widgets.feedbackMessage.cfg.getProperty("visible")) 288 { 289 me.widgets.feedbackMessage.show(); 290 } 291 } 292 }, []); 293 } 294 }, 295 296 /** 297 * Enable search button, hide the pending wait message and set the panel as not searching. 298 * 299 * @method _enableSearchUI 300 * @private 301 */ 302 _enableSearchUI: function _enableSearchUI() 303 { 304 // Enable search button and close the wait feedback message if present 305 if (this.widgets.feedbackMessage && this.widgets.feedbackMessage.cfg.getProperty("visible")) 306 { 307 this.widgets.feedbackMessage.hide(); 308 } 309 parent.widgets.searchButton.set("disabled", false); 310 this.isSearching = false; 311 }, 312 313 /** 314 * Setup the YUI DataTable with custom renderers. 315 * 316 * @method _setupDataTable 317 * @private 318 */ 319 _setupDataTable: function _setupDataTable() 320 { 321 /** 322 * DataTable Cell Renderers 323 * 324 * Each cell has a custom renderer defined as a custom function. See YUI documentation for details. 325 * These MUST be inline in order to have access to the parent instance (via the "parent" variable). 326 */ 327 328 /** 329 * User avatar custom datacell formatter 330 * 331 * @method renderCellAvatar 332 */ 333 var renderCellAvatar = function renderCellAvatar(elCell, oRecord, oColumn, oData) 334 { 335 Dom.setStyle(elCell, "min-height", "64px"); 336 Dom.setStyle(elCell.parentNode, "width", oColumn.width + "px"); 337 Dom.setStyle(elCell.parentNode, "border-right", "1px solid #D7D7D7"); 338 339 // apply the avatar image as a background 340 var avatarUrl = Alfresco.constants.URL_RESCONTEXT + "components/images/no-user-photo-64.png"; 341 if (oRecord.getData("avatar") !== undefined) 342 { 343 avatarUrl = Alfresco.constants.PROXY_URI + oRecord.getData("avatar") + "?c=queue&ph=true"; 344 } 345 Dom.setStyle(elCell, "background-image", "url('" + avatarUrl + "')"); 346 Dom.setStyle(elCell, "background-repeat", "no-repeat"); 347 Dom.setStyle(elCell, "background-position", "22px 50%"); 348 349 // overlay the account enabled/disabled indicator image 350 var enabled = (oRecord.getData("enabled") ? 'enabled' : 'disabled'); 351 elCell.innerHTML = '<img class="indicator" alt="' + parent._msg("label." + enabled) + '" src="' + Alfresco.constants.URL_RESCONTEXT + 'components/images/account_' + enabled + '.gif" alt="" />'; 352 }; 353 354 /** 355 * User full name custom datacell formatter 356 * 357 * @method renderCellFullName 358 */ 359 var renderCellFullName = function renderCellFullName(elCell, oRecord, oColumn, oData) 360 { 361 // Create view userlink 362 var firstName = oRecord.getData("firstName"), 363 lastName = oRecord.getData("lastName"), 364 name = firstName + ' ' + (lastName ? lastName : ""), 365 viewUserLink = document.createElement("a"); 366 viewUserLink.innerHTML = $html(name); 367 368 // fire the 'viewUserClick' event when the selected user in the list has changed 369 YAHOO.util.Event.addListener(viewUserLink, "click", function(e) 370 { 371 YAHOO.Bubbling.fire('viewUserClick', 372 { 373 username: oRecord.getData("userName") 374 }); 375 }, null, parent); 376 elCell.appendChild(viewUserLink); 377 }; 378 379 /** 380 * Quota custom datacell formatter 381 * 382 * @method renderCellQuota 383 */ 384 var renderCellQuota = function renderCellQuota(elCell, oRecord, oColumn, oData) 385 { 386 var quota = oRecord.getData("quota"); 387 var display = (quota !== -1 ? Alfresco.util.formatFileSize(quota) : ""); 388 elCell.innerHTML = display; 389 }; 390 391 /** 392 * Usage custom datacell formatter 393 * 394 * @method renderCellUsage 395 */ 396 var renderCellUsage = function renderCellQuota(elCell, oRecord, oColumn, oData) 397 { 398 elCell.innerHTML = Alfresco.util.formatFileSize(oRecord.getData("sizeCurrent")); 399 }; 400 401 /** 402 * Generic HTML-safe custom datacell formatter 403 */ 404 var renderCellSafeHTML = function renderCellSafeHTML(elCell, oRecord, oColumn, oData) 405 { 406 elCell.innerHTML = $html(oData); 407 }; 408 409 /** 410 * Usage custom datacell sorter 411 */ 412 var sortCellUsage = function sortCellUsage(a, b, desc) 413 { 414 var numA = a.getData("sizeCurrent"), 415 numB = b.getData("sizeCurrent"); 416 417 if (desc) 418 { 419 return (numA < numB ? 1 : (numA > numB ? -1 : 0)); 420 } 421 return (numA < numB ? -1 : (numA > numB ? 1 : 0)); 422 }; 423 424 /** 425 * Quota custom datacell sorter 426 */ 427 var sortCellQuota = function sortCellQuota(a, b, desc) 428 { 429 var numA = a.getData("quota"), 430 numB = b.getData("quota"); 431 432 if (desc) 433 { 434 return (numA < numB ? 1 : (numA > numB ? -1 : 0)); 435 } 436 return (numA < numB ? -1 : (numA > numB ? 1 : 0)); 437 }; 438 439 // DataTable column defintions 440 var columnDefinitions = 441 [ 442 { key: "avatar", label: "", sortable: false, formatter: renderCellAvatar, width: 70 }, 443 { key: "fullName", label: parent._msg("label.name"), sortable: true, formatter: renderCellFullName }, 444 { key: "userName", label: parent._msg("label.username"), sortable: true, formatter: renderCellSafeHTML }, 445 { key: "jobtitle", label: parent._msg("label.jobtitle"), sortable: true, formatter: renderCellSafeHTML }, 446 { key: "email", label: parent._msg("label.email"), sortable: true, formatter: renderCellSafeHTML }, 447 { key: "usage", label: parent._msg("label.usage"), sortable: true, sortOptions: {sortFunction: sortCellUsage}, formatter: renderCellUsage }, 448 { key: "quota", label: parent._msg("label.quota"), sortable: true, sortOptions: {sortFunction: sortCellQuota}, formatter: renderCellQuota } 449 ]; 450 451 // DataTable definition 452 parent.widgets.dataTable = new YAHOO.widget.DataTable(parent.id + "-datatable", columnDefinitions, parent.widgets.dataSource, 453 { 454 initialLoad: false, 455 renderLoopSize: 32, 456 sortedBy: 457 { 458 key: "userName", 459 dir: "asc" 460 }, 461 MSG_EMPTY: parent._msg("message.empty") 462 }); 463 }, 464 465 /** 466 * Resets the YUI DataTable errors to our custom messages 467 * NOTE: Scope could be YAHOO.widget.DataTable, so can't use "this" 468 * 469 * @method _setDefaultDataTableErrors 470 * @param dataTable {object} Instance of the DataTable 471 * @private 472 */ 473 _setDefaultDataTableErrors: function _setDefaultDataTableErrors(dataTable) 474 { 475 var msg = Alfresco.util.message; 476 dataTable.set("MSG_EMPTY", parent._msg("message.empty", "Alfresco.ConsoleUsers")); 477 dataTable.set("MSG_ERROR", parent._msg("message.error", "Alfresco.ConsoleUsers")); 478 }, 479 480 /** 481 * Build URI parameters for People List JSON data webscript 482 * 483 * @method _buildSearchParams 484 * @param searchTerm {string} User search term 485 * @private 486 */ 487 _buildSearchParams: function _buildSearchParams(searchTerm) 488 { 489 return "?filter=" + encodeURIComponent(searchTerm) + "&maxResults=" + parent.options.maxSearchResults; 490 }, 491 492 /** 493 * Set the message in the Results Bar area 494 * 495 * @method _setResultsMessage 496 * @param messageId {string} The messageId to display 497 * @private 498 */ 499 _setResultsMessage: function _setResultsMessage(messageId, arg1, arg2) 500 { 501 var resultsDiv = Dom.get(parent.id + "-search-bar"); 502 resultsDiv.innerHTML = parent._msg(messageId, arg1, arg2); 503 } 504 }); 505 new SearchPanelHandler(); 506 507 /* View Panel Handler */ 508 ViewPanelHandler = function ViewPanelHandler_constructor() 509 { 510 ViewPanelHandler.superclass.constructor.call(this, "view"); 511 }; 512 513 YAHOO.extend(ViewPanelHandler, Alfresco.ConsolePanelHandler, 514 { 515 onLoad: function onLoad() 516 { 517 // Buttons 518 parent.widgets.gobackButton = Alfresco.util.createYUIButton(parent, "goback-button", parent.onGoBackClick); 519 parent.widgets.deleteuserButton = Alfresco.util.createYUIButton(parent, "deleteuser-button", parent.onDeleteUserClick); 520 parent.widgets.edituserButton = Alfresco.util.createYUIButton(parent, "edituser-button", parent.onEditUserClick); 521 }, 522 523 onBeforeShow: function onBeforeShow() 524 { 525 // Hide the main panel area before it is displayed - so we don't show 526 // old data to the user before the Update() method paints the results 527 Dom.get(parent.id + "-view-title").innerHTML = ""; 528 Dom.setStyle(parent.id + "-view-main", "visibility", "hidden"); 529 }, 530 531 onShow: function onShow() 532 { 533 window.scrollTo(0, 0); 534 }, 535 536 onUpdate: function onUpdate() 537 { 538 var success = function(res) 539 { 540 var fnSetter = function(id, val) 541 { 542 Dom.get(parent.id + id).innerHTML = val ? $html(val) : ""; 543 }; 544 545 var person = YAHOO.lang.JSON.parse(res.serverResponse.responseText); 546 547 // apply avatar image URL 548 var photos = Dom.getElementsByClassName("view-photoimg", "img"); 549 for (var i in photos) 550 { 551 photos[i].src = person.avatar ? 552 Alfresco.constants.PROXY_URI + person.avatar + "?c=force" : 553 Alfresco.constants.URL_RESCONTEXT + "components/images/no-user-photo-64.png"; 554 } 555 556 // About section fields 557 var firstName = person.firstName, 558 lastName = person.lastName, 559 fullName = firstName + ' ' + (lastName ? lastName : ""); 560 fnSetter("-view-title", fullName); 561 fnSetter("-view-name", fullName); 562 fnSetter("-view-jobtitle", person.jobtitle); 563 fnSetter("-view-organization", person.organization); 564 // biography is a special html field 565 var bio = person.persondescription ? person.persondescription : ""; 566 Dom.get(parent.id + "-view-bio").innerHTML = bio.replace(/\n/g, "<br/>"); 567 568 // Contact section fields 569 fnSetter("-view-location", person.location); 570 fnSetter("-view-email", person.email); 571 fnSetter("-view-telephone", person.telephone); 572 fnSetter("-view-mobile", person.mobile); 573 fnSetter("-view-skype", person.skype); 574 fnSetter("-view-instantmsg", person.instantmsg); 575 fnSetter("-view-googleusername", person.googleusername); 576 577 // Company section fields 578 fnSetter("-view-companyname", person.organization); 579 // build the company address up and set manually - encoding each value 580 var addr = ""; 581 addr += person.companyaddress1 ? ($html(person.companyaddress1) + "<br/>") : ""; 582 addr += person.companyaddress2 ? ($html(person.companyaddress2) + "<br/>") : ""; 583 addr += person.companyaddress3 ? ($html(person.companyaddress3) + "<br/>") : ""; 584 addr += person.companypostcode ? ($html(person.companypostcode) + "<br/>") : ""; 585 Dom.get(parent.id + "-view-companyaddress").innerHTML = addr; 586 fnSetter("-view-companytelephone", person.companytelephone); 587 fnSetter("-view-companyfax", person.companyfax); 588 fnSetter("-view-companyemail", person.companyemail); 589 590 // More section fields 591 fnSetter("-view-username", parent.currentUserId); 592 fnSetter("-view-enabled", person.enabled ? parent._msg("label.enabled") : parent._msg("label.disabled")); 593 fnSetter("-view-quota", (person.quota !== -1 ? Alfresco.util.formatFileSize(person.quota) : "")); 594 fnSetter("-view-usage", Alfresco.util.formatFileSize(person.sizeCurrent)); 595 var fnGroupToString = function() 596 { 597 return this.displayName; 598 } 599 for (var i = 0, j = person.groups.length; i < j; person.groups[i++].toString = fnGroupToString) {} 600 fnSetter("-view-groups", person.groups.join(", ")); 601 602 // Make main panel area visible 603 Dom.setStyle(parent.id + "-view-main", "visibility", "visible"); 604 }; 605 606 // make an ajax call to get user details 607 Alfresco.util.Ajax.request( 608 { 609 url: Alfresco.constants.PROXY_URI + "api/people/" + encodeURIComponent(parent.currentUserId) + "?groups=true", 610 method: Alfresco.util.Ajax.GET, 611 successCallback: 612 { 613 fn: success, 614 scope: parent 615 }, 616 failureMessage: parent._msg("message.getuser-failure", $html(parent.currentUserId)) 617 }); 618 } 619 }); 620 new ViewPanelHandler(); 621 622 /* Create User Panel Handler */ 623 CreatePanelHandler = function CreatePanelHandler_constructor() 624 { 625 CreatePanelHandler.superclass.constructor.call(this, "create"); 626 }; 627 628 YAHOO.extend(CreatePanelHandler, Alfresco.ConsolePanelHandler, 629 { 630 _visible: false, 631 632 _groups: [], 633 634 _form: null, 635 636 onLoad: function onLoad() 637 { 638 // events we are interested in 639 YAHOO.Bubbling.on("itemSelected", this.onGroupSelected, this); 640 YAHOO.Bubbling.on("removeGroupCreate", this.onRemoveGroupCreate, this); 641 642 // Buttons 643 parent.widgets.createuserOkButton = Alfresco.util.createYUIButton(parent, "createuser-ok-button", parent.onCreateUserOKClick); 644 parent.widgets.createuserAnotherButton = Alfresco.util.createYUIButton(parent, "createuser-another-button", parent.onCreateUserAnotherClick); 645 parent.widgets.createuserCancelButton = Alfresco.util.createYUIButton(parent, "createuser-cancel-button", parent.onCreateUserCancelClick); 646 647 // Form definition 648 var form = new Alfresco.forms.Form(parent.id + "-create-form"); 649 form.setSubmitElements([parent.widgets.createuserOkButton, parent.widgets.createuserAnotherButton]); 650 form.setShowSubmitStateDynamically(true); 651 652 // Form field validation 653 form.addValidation(parent.id + "-create-firstname", Alfresco.forms.validation.mandatory, null, "keyup"); 654 form.addValidation(parent.id + "-create-email", Alfresco.forms.validation.mandatory, null, "keyup"); 655 form.addValidation(parent.id + "-create-email", Alfresco.forms.validation.email, null, "keyup"); 656 form.addValidation(parent.id + "-create-username", Alfresco.forms.validation.nodeName, null, "keyup"); 657 form.addValidation(parent.id + "-create-username", Alfresco.forms.validation.length, 658 { 659 min: parent.options.minUsernameLength, 660 max: 100, 661 crop: true, 662 includeWhitespace: false 663 }, "keyup"); 664 form.addValidation(parent.id + "-create-password", Alfresco.forms.validation.length, 665 { 666 min: parent.options.minPasswordLength, 667 max: 100, 668 crop: true 669 }, "keyup"); 670 form.addValidation(parent.id + "-create-verifypassword", Alfresco.forms.validation.length, 671 { 672 min: parent.options.minPasswordLength, 673 max: 100, 674 crop: true 675 }, "keyup"); 676 677 // Initialise the form 678 form.init(); 679 this._form = form; 680 681 // Load in the Groups Finder component from the server 682 Alfresco.util.Ajax.request( 683 { 684 url: Alfresco.constants.URL_SERVICECONTEXT + "components/people-finder/group-finder", 685 dataObj: 686 { 687 htmlid: parent.id + "-create-groupfinder" 688 }, 689 successCallback: 690 { 691 fn: this.onGroupFinderLoaded, 692 scope: this 693 }, 694 failureMessage: "Could not load Group Finder component", 695 execScripts: true 696 }); 697 }, 698 699 onGroupFinderLoaded: function onGroupFinderLoaded(res) 700 { 701 // Inject the component from the XHR request into it's placeholder DIV element 702 var finderDiv = Dom.get(parent.id + "-create-groupfinder"); 703 finderDiv.innerHTML = res.serverResponse.responseText; 704 705 // Find the Group Finder by container ID 706 parent.modules.createGroupFinder = Alfresco.util.ComponentManager.get(parent.id + "-create-groupfinder"); 707 708 // Set the correct options for our use 709 parent.modules.createGroupFinder.setOptions( 710 { 711 viewMode: Alfresco.GroupFinder.VIEW_MODE_COMPACT, 712 singleSelectMode: false, 713 wildcardPrefix: false 714 }); 715 }, 716 717 /** 718 * Group selected event handler. 719 * This event can be fired from either Groups picker - so we much ensure 720 * the event is for the current panel by checking panel visibility. 721 * 722 * @method onGroupSelected 723 * @param e {object} DomEvent 724 * @param args {array} Event parameters (depends on event type) 725 */ 726 onGroupSelected: function onGroupSelected(e, args) 727 { 728 if (this._visible) 729 { 730 this.addGroup(args[1]); 731 } 732 }, 733 734 /** 735 * Add a group to the list of selected groups 736 * 737 * @method addGroup 738 * @param group {object} Group object 739 */ 740 addGroup: function addGroup(group) 741 { 742 var found = false; 743 for (var i=0, j=this._groups.length; i<j; i++) 744 { 745 if (this._groups[i] != null && this._groups[i].itemName === group.itemName) 746 { 747 found = true; 748 break; 749 } 750 } 751 752 if (!found) 753 { 754 this._groups.push(group); 755 756 var groupDiv = Dom.get(parent.id + "-create-groups"); 757 var idx = (this._groups.length - 1); 758 var groupEl = document.createElement("span"); 759 groupEl.setAttribute("id", parent.id + "_group" + idx); 760 groupEl.setAttribute("title", parent._msg("label.removegroup")); 761 Dom.addClass(groupEl, "group-item"); 762 groupEl.innerHTML = $html(group.displayName); 763 groupDiv.appendChild(groupEl); 764 765 Alfresco.util.useAsButton(groupEl, function(e, obj) 766 { 767 // Remove group from ui 768 YAHOO.Bubbling.fire('removeGroupCreate', { id: obj.idx }); 769 770 // Tell group finder to deselect the group 771 YAHOO.Bubbling.fire('itemDeselected', { eventGroup: parent.modules.createGroupFinder, itemName: obj.group.itemName }); 772 }, { idx: idx, group: group }); 773 } 774 }, 775 776 getGroups: function getGroups() 777 { 778 var groups = []; 779 for (var i=0, j=this._groups.length; i<j; i++) 780 { 781 if (this._groups[i] != null) 782 { 783 groups.push(this._groups[i].itemName); 784 } 785 } 786 return groups; 787 }, 788 789 /** 790 * Group removed event handler 791 * 792 * @method onRemoveGroupCreate 793 * @param e {object} DomEvent 794 * @param args {array} Event parameters (depends on event type) 795 */ 796 onRemoveGroupCreate: function onRemoveGroupCreate(e, args) 797 { 798 var i = args[1].id; 799 var el = Dom.get(parent.id + "_group" + i); 800 el.parentNode.removeChild(el); 801 this._groups[i] = null; 802 }, 803 804 onBeforeShow: function onBeforeShow() 805 { 806 // Hide the main panel area before it is displayed - so we don't show 807 // old data to the user before the onShow() method paints the results 808 Dom.setStyle(parent.id + "-create-main", "visibility", "hidden"); 809 810 this.clear(); 811 }, 812 813 clear: function clear() 814 { 815 var fnClearEl = function(id) 816 { 817 Dom.get(parent.id + id).value = ""; 818 }; 819 820 // clear data fields 821 fnClearEl("-create-firstname"); 822 fnClearEl("-create-lastname"); 823 fnClearEl("-create-email"); 824 fnClearEl("-create-username"); 825 fnClearEl("-create-password"); 826 fnClearEl("-create-verifypassword"); 827 fnClearEl("-create-quota"); 828 Dom.get(parent.id + "-create-disableaccount").checked = false; 829 830 // reset quota selection drop-down 831 Dom.get(parent.id + "-create-quotatype").value = "gb"; 832 833 // clear selected groups 834 this._groups = []; 835 Dom.get(parent.id + "-create-groups").innerHTML = ""; 836 if (parent.modules.createGroupFinder) 837 { 838 parent.modules.createGroupFinder.clearResults(); 839 } 840 if (this._form !== null) 841 { 842 this._form.init(); 843 } 844 845 // Notify group finder that no groups are selected 846 YAHOO.Bubbling.fire("allItemsDeselected", 847 { 848 eventGroup: parent.modules.createGroupFinder 849 }); 850 851 }, 852 853 onShow: function onShow() 854 { 855 this._visible = true; 856 window.scrollTo(0, 0); 857 858 // Make main panel area visible 859 Dom.setStyle(parent.id + "-create-main", "visibility", "visible"); 860 861 Dom.get(parent.id + "-create-firstname").focus(); 862 }, 863 864 onHide: function onHide() 865 { 866 this._visible = false; 867 } 868 }); 869 new CreatePanelHandler(); 870 871 /* Update User Panel Handler */ 872 UpdatePanelHandler = function UpdatePanelHandler_constructor() 873 { 874 UpdatePanelHandler.superclass.constructor.call(this, "update"); 875 }; 876 877 YAHOO.extend(UpdatePanelHandler, Alfresco.ConsolePanelHandler, 878 { 879 _visible: false, 880 881 _removedGroups: [], 882 _addedGroups: [], 883 _originalGroups: [], 884 _groups: [], 885 _photoReset: false, 886 _form: null, 887 888 onLoad: function onLoad() 889 { 890 // events we are interested in 891 YAHOO.Bubbling.on("itemSelected", this.onGroupSelected, this); 892 YAHOO.Bubbling.on("removeGroupUpdate", this.onRemoveGroupUpdate, this); 893 894 // Buttons 895 parent.widgets.updateuserSaveButton = Alfresco.util.createYUIButton(parent, "updateuser-save-button", parent.onUpdateUserOKClick); 896 parent.widgets.updateuserCancelButton = Alfresco.util.createYUIButton(parent, "updateuser-cancel-button", parent.onUpdateUserCancelClick); 897 parent.widgets.updateuserClearPhotoButton = Alfresco.util.createYUIButton(parent, "updateuser-clearphoto-button", parent.onUpdateUserClearPhotoClick); 898 899 // Form definition 900 var form = new Alfresco.forms.Form(parent.id + "-update-form"); 901 form.setSubmitElements(parent.widgets.updateuserSaveButton); 902 form.setShowSubmitStateDynamically(true); 903 904 // Form field validation 905 form.addValidation(parent.id + "-update-firstname", Alfresco.forms.validation.mandatory, null, "keyup"); 906 form.addValidation(parent.id + "-update-email", Alfresco.forms.validation.mandatory, null, "keyup"); 907 form.addValidation(parent.id + "-update-email", Alfresco.forms.validation.email, null, "keyup"); 908 909 // Initialise the form 910 form.init(); 911 this._form = form; 912 913 // Load in the Groups Finder component from the server 914 Alfresco.util.Ajax.request( 915 { 916 url: Alfresco.constants.URL_SERVICECONTEXT + "components/people-finder/group-finder", 917 dataObj: 918 { 919 htmlid: parent.id + "-update-groupfinder" 920 }, 921 successCallback: 922 { 923 fn: this.onGroupFinderLoaded, 924 scope: this 925 }, 926 failureMessage: "Could not load Group Finder component", 927 execScripts: true 928 }); 929 }, 930 931 onGroupFinderLoaded: function onGroupFinderLoaded(res) 932 { 933 // Inject the component from the XHR request into it's placeholder DIV element 934 var finderDiv = Dom.get(parent.id + "-update-groupfinder"); 935 finderDiv.innerHTML = res.serverResponse.responseText; 936 937 // Find the Group Finder by container ID 938 parent.modules.updateGroupFinder = Alfresco.util.ComponentManager.get(parent.id + "-update-groupfinder"); 939 940 // Set the correct options for our use 941 parent.modules.updateGroupFinder.setOptions( 942 { 943 viewMode: Alfresco.GroupFinder.VIEW_MODE_COMPACT, 944 singleSelectMode: false, 945 wildcardPrefix: false 946 }); 947 }, 948 949 /** 950 * Group selected event handler. 951 * This event can be fired from either Groups picker - so we much ensure 952 * the event is for the current panel by checking panel visibility. 953 * 954 * @method onGroupSelected 955 * @param e {object} DomEvent 956 * @param args {array} Event parameters (depends on event type) 957 */ 958 onGroupSelected: function onGroupSelected(e, args) 959 { 960 if (this._visible) 961 { 962 this.addGroup(args[1]); 963 } 964 }, 965 966 /** 967 * Add a group to the list of selected groups 968 * 969 * @method addGroup 970 * @param group {object} Group object 971 */ 972 addGroup: function addGroup(group) 973 { 974 var found = false, 975 i, j; 976 for (i = 0, j = this._groups.length; i < j; i++) 977 { 978 if (this._groups[i] !== null && this._groups[i].itemName === group.itemName) 979 { 980 found = true; 981 break; 982 } 983 } 984 985 if (!found) 986 { 987 this._groups.push(group); 988 989 var groupDiv = Dom.get(parent.id + "-update-groups"), 990 idx = (this._groups.length-1), 991 groupEl = document.createElement("span"); 992 groupEl.setAttribute("id", parent.id + "_group" + idx); 993 groupEl.setAttribute("title", parent._msg("label.removegroup")); 994 Dom.addClass(groupEl, "group-item"); 995 groupEl.innerHTML = $html(group.displayName); 996 groupDiv.appendChild(groupEl); 997 998 Alfresco.util.useAsButton(groupEl, function(e, obj) 999 { 1000 // Remove group from ui 1001 YAHOO.Bubbling.fire('removeGroupUpdate', { id: obj.idx }); 1002 1003 // Tell group finder to deselect the group 1004 YAHOO.Bubbling.fire('itemDeselected', { eventGroup: parent.modules.updateGroupFinder, itemName: obj.group.itemName }); 1005 }, { idx: idx, group: group }); 1006 1007 1008 1009 // if this group wasn't one of the original list, then add it to the addition list 1010 found = false; 1011 for (i = 0, j = this._originalGroups.length; i < j; i++) 1012 { 1013 if (this._originalGroups[i].itemName === group.itemName) 1014 { 1015 found = true; 1016 break; 1017 } 1018 } 1019 if (!found) 1020 { 1021 this._addedGroups.push(group.itemName); 1022 } 1023 } 1024 }, 1025 1026 /** 1027 * Group removed event handler 1028 * 1029 * @method onRemoveGroupUpdate 1030 * @param e {object} DomEvent 1031 * @param args {array} Event parameters (depends on event type) 1032 */ 1033 onRemoveGroupUpdate: function onRemoveGroupUpdate(e, args) 1034 { 1035 var i = args[1].id; 1036 var el = Dom.get(parent.id + "_group" + i); 1037 el.parentNode.removeChild(el); 1038 var group = this._groups[i]; 1039 this._groups[i] = null; 1040 1041 // if this group was one of the original list, then add it to the removed list 1042 for (var i=0, j=this._originalGroups.length; i<j; i++) 1043 { 1044 if (this._originalGroups[i].itemName === group.itemName) 1045 { 1046 this._removedGroups.push(group.itemName); 1047 break; 1048 } 1049 } 1050 // also remove from the added groups list 1051 for (var i=0, j=this._addedGroups.length; i<j; i++) 1052 { 1053 if (this._addedGroups[i] === group.itemName) 1054 { 1055 this._addedGroups.splice(i, 1); 1056 break; 1057 } 1058 } 1059 }, 1060 1061 getAddedGroups: function getAddedGroups() 1062 { 1063 return this._addedGroups; 1064 }, 1065 1066 getRemovedGroups: function getRemovedGroups() 1067 { 1068 return this._removedGroups; 1069 }, 1070 1071 resetGroups: function resetGroups() 1072 { 1073 this._groups = []; 1074 this._addedGroups = []; 1075 this._removedGroups = []; 1076 Dom.get(parent.id + "-update-groups").innerHTML = ""; 1077 }, 1078 1079 setPhotoReset: function setPhotoReset() 1080 { 1081 this._photoReset = true; 1082 }, 1083 1084 getPhotoReset: function getPhotoReset() 1085 { 1086 return this._photoReset; 1087 }, 1088 1089 onBeforeShow: function onBeforeShow() 1090 { 1091 // Hide the main panel area before it is displayed - so we don't show 1092 // old data to the user before the Update() method paints the results 1093 Dom.get(parent.id + "-update-title").innerHTML = ""; 1094 Dom.setStyle(parent.id + "-update-main", "visibility", "hidden"); 1095 }, 1096 1097 onShow: function onShow() 1098 { 1099 this._visible = true; 1100 window.scrollTo(0, 0); 1101 }, 1102 1103 onHide: function onHide() 1104 { 1105 this._visible = false; 1106 }, 1107 1108 onUpdate: function onUpdate() 1109 { 1110 var me = this; 1111 var success = function(res) 1112 { 1113 var fnSetter = function(id, val) 1114 { 1115 Dom.get(parent.id + id).value = val; 1116 }; 1117 var fnDisabler = function(id, propId, map) 1118 { 1119 if (map["{http://www.alfresco.org/model/content/1.0}" + propId]) 1120 { 1121 Dom.get(parent.id + id).setAttribute("disabled", true); 1122 } 1123 }; 1124 1125 var person = YAHOO.lang.JSON.parse(res.serverResponse.responseText); 1126 1127 // apply avatar image URL 1128 var photos = Dom.getElementsByClassName("update-photoimg", "img"); 1129 for (var i in photos) 1130 { 1131 photos[i].src = person.avatar ? 1132 Alfresco.constants.PROXY_URI + person.avatar + "?c=force" : 1133 Alfresco.constants.URL_RESCONTEXT + "components/images/no-user-photo-64.png"; 1134 } 1135 1136 // About section fields 1137 var firstName = person.firstName, 1138 lastName = person.lastName, 1139 fullName = firstName + ' ' + (lastName ? lastName : ""); 1140 Dom.get(parent.id + "-update-title").innerHTML = $html(fullName); 1141 fnSetter("-update-firstname", firstName); 1142 fnDisabler("-update-firstname", "firstName", person.immutability); 1143 fnSetter("-update-lastname", lastName); 1144 fnDisabler("-update-lastname", "lastName", person.immutability); 1145 fnSetter("-update-email", person.email); 1146 fnDisabler("-update-email", "email", person.immutability); 1147 if (!person.capabilities.isMutable) 1148 { 1149 Dom.get(parent.id + "-update-old-password").setAttribute("disabled", true); 1150 Dom.get(parent.id + "-update-password").setAttribute("disabled", true); 1151 Dom.get(parent.id + "-update-verifypassword").setAttribute("disabled", true); 1152 } 1153 fnSetter("-update-old-password", ""); 1154 fnSetter("-update-password", ""); 1155 fnSetter("-update-verifypassword", ""); 1156 1157 // convert quota to closest value type 1158 var quota = person.quota; 1159 if (quota !== -1) 1160 { 1161 if (quota < Alfresco.util.BYTES_MB) 1162 { 1163 // show in kilobytes 1164 quota = Math.round(quota / Alfresco.util.BYTES_KB); 1165 Dom.get(parent.id + "-update-quotatype").value = "kb"; 1166 } 1167 else if (quota < Alfresco.util.BYTES_GB) 1168 { 1169 // show in metabytes 1170 quota = Math.round(quota / Alfresco.util.BYTES_MB); 1171 Dom.get(parent.id + "-update-quotatype").value = "mb"; 1172 } 1173 else 1174 { 1175 // show in gigabytes 1176 quota = Math.round(quota / Alfresco.util.BYTES_GB); 1177 Dom.get(parent.id + "-update-quotatype").value = "gb"; 1178 } 1179 fnSetter("-update-quota", quota.toString()); 1180 } 1181 else 1182 { 1183 fnSetter("-update-quota", ""); 1184 } 1185 1186 // account enabled/disabled 1187 Dom.get(parent.id + "-update-disableaccount").checked = (person.enabled == false); 1188 1189 // add groups the user is already assigned to and maintain a copy of the original group list 1190 me.resetGroups(); 1191 YAHOO.Bubbling.fire("allItemsDeselected", 1192 { 1193 eventGroup: parent.modules.updateGroupFinder 1194 }); 1195 me._originalGroups = person.groups; 1196 for (var i=0, j=person.groups.length; i<j; i++) 1197 { 1198 me.addGroup( 1199 { 1200 "itemName": person.groups[i].itemName, 1201 "displayName": person.groups[i].displayName 1202 }); 1203 1204 // Make the group finder aware of which groups the user already has 1205 YAHOO.Bubbling.fire("itemSelected", 1206 { 1207 eventGroup: parent.modules.updateGroupFinder, 1208 "itemName": person.groups[i].itemName, 1209 "displayName": person.groups[i].displayName 1210 }); 1211 } 1212 1213 // Hide or show the old password field - only required if user changing own password 1214 if (parent.currentUserId.toLowerCase() === Alfresco.constants.USERNAME.toLowerCase()) 1215 { 1216 Dom.setStyle(parent.id + "-oldpassword-wrapper", "display", "block"); 1217 } 1218 else 1219 { 1220 Dom.setStyle(parent.id + "-oldpassword-wrapper", "display", "none"); 1221 } 1222 1223 // Make main panel area visible 1224 Dom.setStyle(parent.id + "-update-main", "visibility", "visible"); 1225 1226 1227 1228 1229 me._form.updateSubmitElements(); 1230 }; 1231 1232 // make an ajax call to get user details 1233 Alfresco.util.Ajax.request( 1234 { 1235 url: Alfresco.constants.PROXY_URI + "api/people/" + encodeURIComponent(parent.currentUserId) + "?groups=true", 1236 method: Alfresco.util.Ajax.GET, 1237 successCallback: 1238 { 1239 fn: success, 1240 scope: parent 1241 }, 1242 failureMessage: parent._msg("message.getuser-failure", $html(parent.currentUserId)) 1243 }); 1244 } 1245 }); 1246 new UpdatePanelHandler(); 1247 1248 CSVResultsPanelHandler = function CSVResultsPanelHandler_constructor() 1249 { 1250 CSVResultsPanelHandler.superclass.constructor.call(this, "csvresults"); 1251 }; 1252 1253 YAHOO.extend(CSVResultsPanelHandler, Alfresco.ConsolePanelHandler, 1254 { 1255 /** 1256 * PANEL LIFECYCLE CALLBACKS 1257 */ 1258 /** 1259 * Called by the ConsolePanelHandler when this panel shall be loaded 1260 * 1261 * @method onLoad 1262 */ 1263 onLoad: function onLoad() 1264 { 1265 parent.widgets.csvGobackButton = Alfresco.util.createYUIButton(parent, "csv-goback-button", parent.onGoBackClick); 1266 }, 1267 1268 onShow: function onShow() 1269 { 1270 if (parent.csvResults) 1271 { 1272 var dataSource; 1273 var successful = parent.csvResults.successful; 1274 if (successful && successful.length > 0 && parent.csvResults.successful[0].response) 1275 { 1276 successful = successful[0].response; 1277 1278 // If the response contains the "successful" array containing an element then it does not necessarily 1279 // mean that the CSV upload succeeded. This simply means that the upload request was successfully processed 1280 // (i.e. the file was received) 1281 if (successful.data && successful.data.users) 1282 { 1283 parent.fileUpload.hide(); 1284 1285 // If the successful response contains a data object with a "users" attribute then we at least know that 1286 // some users have been processed so can construct a result table using that data... 1287 dataSource = new YAHOO.util.DataSource(successful.data.users); 1288 dataSource.responseType = YAHOO.util.DataSource.TYPE_JSARRAY; 1289 dataSource.responseSchema = { fields: [ "username", "uploadStatus" ]}; 1290 1291 // Show a pop-up with the summary data... 1292 if (successful.data.addedUsers == 0) 1293 { 1294 // No new users were added... 1295 Alfresco.util.PopupManager.displayMessage( 1296 { 1297 text: parent._msg("message.csvupload.failure") 1298 }); 1299 } 1300 else if (successful.data.addedUsers == successful.data.totalUsers) 1301 { 1302 // All the users found in the CSV file were added 1303 Alfresco.util.PopupManager.displayMessage( 1304 { 1305 text: parent._msg("message.csvupload.success", successful.data.addedUsers) 1306 }); 1307 } 1308 else 1309 { 1310 // Some of the users could not be added. 1311 var failedUsers = successful.data.totalUsers - successful.data.addedUsers; 1312 Alfresco.util.PopupManager.displayMessage( 1313 { 1314 text: parent._msg("message.csvupload.partialSuccess", successful.data.addedUsers, failedUsers) 1315 }); 1316 } 1317 1318 var columnDefs = [{key:"username", label: parent._msg("label.username"), sortable: true, resizeable: true}, 1319 {key:"uploadStatus", label: parent._msg("label.uploadStatus"), sortable: true, resizeable: true}]; 1320 1321 var resultsTable = new YAHOO.widget.DataTable(parent.id + "-csvresults-datatable", 1322 columnDefs, 1323 dataSource); 1324 1325 Dom.removeClass(parent.id + "-csvresults-success", "hidden"); 1326 Dom.addClass(parent.id + "-csvresults-failure", "hidden"); 1327 } 1328 else 1329 { 1330 parent.fileUpload.hide(); 1331 1332 // The CSV upload failed 1333 Alfresco.util.PopupManager.displayMessage( 1334 { 1335 text: parent._msg("message.csvupload.error") 1336 }); 1337 1338 Dom.get(parent.id + "-csvresults-error").innerHTML = successful.message; 1339 1340 Dom.addClass(parent.id + "-csvresults-success", "hidden"); 1341 Dom.removeClass(parent.id + "-csvresults-failure", "hidden"); 1342 } 1343 1344 1345 } 1346 else 1347 { 1348 // The upload did not work. 1349 } 1350 } 1351 } 1352 }); 1353 new CSVResultsPanelHandler(); 1354 1355 return this; 1356 }; 1357 1358 YAHOO.extend(Alfresco.ConsoleUsers, Alfresco.ConsoleTool, 1359 { 1360 /** 1361 * Object container for initialization options 1362 * 1363 * @property options 1364 * @type object 1365 */ 1366 options: 1367 { 1368 /** 1369 * Number of characters required for a search. 1370 * 1371 * @property minSearchTermLength 1372 * @type int 1373 * @default 1 1374 */ 1375 minSearchTermLength: 1, 1376 1377 /** 1378 * Maximum number of items to display in the results list 1379 * 1380 * @property maxSearchResults 1381 * @type int 1382 * @default 100 1383 */ 1384 maxSearchResults: 100, 1385 1386 /** 1387 * Minimum length of a username 1388 * 1389 * @property minUsernameLength 1390 * @type int 1391 * @default 2 1392 */ 1393 minUsernameLength: 2, 1394 1395 /** 1396 * Minimum length of a password 1397 * 1398 * @property minPasswordLength 1399 * @type int 1400 * @default 3 1401 */ 1402 minPasswordLength: 3 1403 }, 1404 1405 /** 1406 * Current user id for an action. 1407 * 1408 * @property currentUserId 1409 * @type string 1410 */ 1411 currentUserId: "", 1412 1413 /** 1414 * Current search term, obtained from form input field. 1415 * 1416 * @property searchTerm 1417 * @type string 1418 */ 1419 searchTerm: undefined, 1420 1421 /** 1422 * The result of the last CSV upload. 1423 * 1424 * @property csvResults 1425 * @type object 1426 */ 1427 csvResults: undefined, 1428 1429 1430 /** 1431 * Fired by YUI when parent element is available for scripting. 1432 * Component initialisation, including instantiation of YUI widgets and event listener binding. 1433 * 1434 * @method onReady 1435 */ 1436 onReady: function ConsoleUsers_onReady() 1437 { 1438 // Generate the popup dialog for confirmation of deleting a user 1439 this.popups.deleteDialog = Alfresco.util.createYUIPanel("deleteDialog", 1440 { 1441 width: "36em", 1442 text: '<div class="yui-u" style="text-align:center"><br/>' + this._msg("panel.delete.msg") + '<br/><br/></div>', 1443 buttons: [ 1444 { 1445 text: this._msg("button.delete"), 1446 handler: 1447 { 1448 fn: this.onDeleteUserOK, 1449 scope: this 1450 } 1451 }, 1452 { 1453 text: this._msg("button.cancel"), 1454 handler: 1455 { 1456 fn: this.onDeleteUserCancel, 1457 scope: this 1458 }, 1459 isDefault: true 1460 }] 1461 }, 1462 { 1463 type: YAHOO.widget.SimpleDialog 1464 }); 1465 1466 this.popups.deleteDialog.setHeader(this._msg("panel.delete.header")); 1467 1468 // Call super-class onReady() method 1469 Alfresco.ConsoleUsers.superclass.onReady.call(this); 1470 }, 1471 1472 /** 1473 * YUI WIDGET EVENT HANDLERS 1474 * Handlers for standard events fired from YUI widgets, e.g. "click" 1475 */ 1476 1477 /** 1478 * History manager state change event handler (override base class) 1479 * 1480 * @method onStateChanged 1481 * @param e {object} DomEvent 1482 * @param args {array} Event parameters (depends on event type) 1483 */ 1484 onStateChanged: function ConsoleUsers_onStateChanged(e, args) 1485 { 1486 var state = this.decodeHistoryState(args[1].state); 1487 1488 // test if panel has actually changed? 1489 if (state.panel) 1490 { 1491 this.showPanel(state.panel); 1492 } 1493 1494 if (state.search !== undefined && this.currentPanelId === "search") 1495 { 1496 // keep track of the last search performed 1497 var searchTerm = state.search; 1498 this.searchTerm = searchTerm; 1499 1500 this.updateCurrentPanel(); 1501 } 1502 1503 if (state.userid && 1504 (this.currentPanelId === "view" || 1505 this.currentPanelId === "create" || 1506 this.currentPanelId === "update")) 1507 { 1508 this.currentUserId = state.userid; 1509 1510 this.updateCurrentPanel(); 1511 } 1512 }, 1513 1514 /** 1515 * Search button click event handler 1516 * 1517 * @method onSearchClick 1518 * @param e {object} DomEvent 1519 * @param args {array} Event parameters (depends on event type) 1520 */ 1521 onSearchClick: function ConsoleUsers_onSearchClick(e, args) 1522 { 1523 var searchTermElem = Dom.get(this.id + "-search-text"); 1524 var searchTerm = YAHOO.lang.trim(searchTermElem.value); 1525 1526 // inform the user if the search term entered is too small 1527 if (searchTerm.length < this.options.minSearchTermLength) 1528 { 1529 Alfresco.util.PopupManager.displayMessage( 1530 { 1531 text: this._msg("message.minimum-length", this.options.minSearchTermLength) 1532 }); 1533 return; 1534 } 1535 1536 this.refreshUIState({"search": searchTerm}); 1537 }, 1538 1539 /** 1540 * Upload Users button click event handler 1541 * 1542 * @method onUploadUsersClick 1543 * @param e {object} DomEvent 1544 * @param args {array} Event parameters (depends on event type) 1545 */ 1546 onUploadUsersClick: function ConsoleUsers_onUploadUsersClick(e, args) 1547 { 1548 // Force the use of the HTML (rather than Flash) uploader because there are issues with the 1549 // Flash uploader in these circumstances when Sharepoint is being used. The Flash uploader 1550 // picks up the wrong JSESSIONID cookie which causes the upload to fail. 1551 if (!this.fileUpload) 1552 { 1553 this.fileUpload = Alfresco.util.ComponentManager.findFirst("Alfresco.HtmlUpload") 1554 } 1555 1556 // Show uploader for single file select - override the upload URL to use appropriate upload service 1557 var uploadConfig = 1558 { 1559 uploadURL: "api/people/upload.html", 1560 mode: this.fileUpload.MODE_SINGLE_UPLOAD, 1561 onFileUploadComplete: 1562 { 1563 fn: this.onUsersUploadComplete, 1564 scope: this 1565 } 1566 }; 1567 1568 this.fileUpload.show(uploadConfig); 1569 1570 // Make sure the "use Flash" tip is hidden just in case Flash is enabled... 1571 var singleUploadTip = Dom.get(this.fileUpload.id + "-singleUploadTip-span"); 1572 Dom.addClass(singleUploadTip, "hidden"); 1573 Event.preventDefault(e); 1574 }, 1575 1576 /** 1577 * Users Upload complete event handler 1578 * 1579 * @method onUsersUploadComplete 1580 * @param complete {object} Object literal containing details of successful upload 1581 */ 1582 onUsersUploadComplete: function ConsoleUsers_onUsersUploadComplete(complete) 1583 { 1584 this.csvResults = complete; 1585 this.refreshUIState({"panel": "csvresults"}); 1586 }, 1587 1588 /** 1589 * New User button click event handler 1590 * 1591 * @method onNewUserClick 1592 * @param e {object} DomEvent 1593 * @param args {array} Event parameters (depends on event type) 1594 */ 1595 onNewUserClick: function ConsoleUsers_onNewUserClick(e, args) 1596 { 1597 this.refreshUIState({"panel": "create"}); 1598 }, 1599 1600 /** 1601 * Edit User button click event handler 1602 * 1603 * @method onEditUserClick 1604 * @param e {object} DomEvent 1605 * @param args {array} Event parameters (depends on event type) 1606 */ 1607 onEditUserClick: function ConsoleUsers_onEditUserClick(e, args) 1608 { 1609 this.refreshUIState({"panel": "update"}); 1610 }, 1611 1612 /** 1613 * View User event handler 1614 * 1615 * @method onViewUserClick 1616 * @param e {object} DomEvent 1617 * @param args {array} Event parameters (depends on event type) 1618 */ 1619 onViewUserClick: function ConsoleUsers_onViewUserClick(e, args) 1620 { 1621 var userid = args[1].username; 1622 this.refreshUIState({"panel": "view", "userid": userid}); 1623 }, 1624 1625 /** 1626 * Go back button click event handler 1627 * 1628 * @method onGoBackClick 1629 * @param e {object} DomEvent 1630 * @param args {array} Event parameters (depends on event type) 1631 */ 1632 onGoBackClick: function ConsoleUsers_onGoBackClick(e, args) 1633 { 1634 this.refreshUIState({"panel": "search"}); 1635 }, 1636 1637 /** 1638 * Delete User button click event handler 1639 * 1640 * @method onDeleteUserClick 1641 * @param e {object} DomEvent 1642 * @param args {array} Event parameters (depends on event type) 1643 */ 1644 onDeleteUserClick: function ConsoleUsers_onDeleteUserClick(e, args) 1645 { 1646 this.popups.deleteDialog.show(); 1647 }, 1648 1649 /** 1650 * Fired when the admin confirms that they want to delete a User. 1651 * 1652 * @method onDeleteUserOK 1653 * @param e {object} DomEvent 1654 */ 1655 onDeleteUserOK: function ConsoleUsers_onDeleteUserOK(e) 1656 { 1657 Alfresco.util.Ajax.request( 1658 { 1659 method: Alfresco.util.Ajax.DELETE, 1660 url: Alfresco.constants.PROXY_URI + "api/people/" + encodeURIComponent(this.currentUserId), 1661 successCallback: 1662 { 1663 fn: this.onDeletedUser, 1664 scope: this 1665 }, 1666 failureMessage: this._msg("panel.delete.fail") 1667 }); 1668 }, 1669 1670 /** 1671 * Fired on successful deletion of a user. 1672 * 1673 * @method onDeletedUser 1674 * @param e {object} DomEvent 1675 */ 1676 onDeletedUser: function ConsoleUsers_onDeletedUser(e) 1677 { 1678 // return to the search screen - we can no longer view the user details 1679 this.popups.deleteDialog.hide(); 1680 Alfresco.util.PopupManager.displayMessage( 1681 { 1682 text: this._msg("message.delete-success") 1683 }); 1684 this.refreshUIState({"panel": "search"}); 1685 }, 1686 1687 /** 1688 * Fired when the admin cancels the operation to delete a User. 1689 * 1690 * @method onDeleteUserCancel 1691 * @param e {object} DomEvent 1692 */ 1693 onDeleteUserCancel: function ConsoleUsers_onDeleteUserCancel(e) 1694 { 1695 this.popups.deleteDialog.hide(); 1696 }, 1697 1698 /** 1699 * Fired when the Create User OK button is clicked. 1700 * 1701 * @method onCreateUserOKClick 1702 * @param e {object} DomEvent 1703 * @param args {array} Event parameters (depends on event type) 1704 */ 1705 onCreateUserOKClick: function ConsoleUsers_onCreateUserOKClick(e, args) 1706 { 1707 var handler = function(res) 1708 { 1709 window.scrollTo(0, 0); 1710 Alfresco.util.PopupManager.displayMessage( 1711 { 1712 text: this._msg("message.create-success") 1713 }); 1714 this.refreshUIState({"panel": "search"}); 1715 }; 1716 this._createUser(handler); 1717 }, 1718 1719 /** 1720 * Fired when the Create User and Create Another button is clicked. 1721 * 1722 * @method onCreateUserAnotherClick 1723 * @param e {object} DomEvent 1724 * @param args {array} Event parameters (depends on event type) 1725 */ 1726 onCreateUserAnotherClick: function ConsoleUsers_onCreateUserAnotherClick(e, args) 1727 { 1728 var me = this; 1729 var handler = function(res) 1730 { 1731 window.scrollTo(0, 0); 1732 Alfresco.util.PopupManager.displayMessage( 1733 { 1734 text: me._msg("message.create-success") 1735 }); 1736 1737 // clear fields 1738 this._getCurrentPanel().clear(); 1739 Dom.get(me.id + "-create-firstname").focus(); 1740 }; 1741 this._createUser(handler); 1742 }, 1743 1744 /** 1745 * Fired when the Create User Cancel button is clicked. 1746 * 1747 * @method onCreateUserCancelClick 1748 * @param e {object} DomEvent 1749 * @param args {array} Event parameters (depends on event type) 1750 */ 1751 onCreateUserCancelClick: function ConsoleUsers_onCreateUserCancelClick(e, args) 1752 { 1753 this.refreshUIState({"panel": "search"}); 1754 }, 1755 1756 /** 1757 * Fired when the Update User OK button is clicked. 1758 * 1759 * @method onUpdateUserOKClick 1760 * @param e {object} DomEvent 1761 * @param args {array} Event parameters (depends on event type) 1762 */ 1763 onUpdateUserOKClick: function ConsoleUsers_onUpdateUserOKClick(e, args) 1764 { 1765 var me = this; 1766 var handler = function(res) 1767 { 1768 window.scrollTo(0, 0); 1769 Alfresco.util.PopupManager.displayMessage( 1770 { 1771 text: me._msg("message.update-success") 1772 }); 1773 me.refreshUIState({"panel": "view"}); 1774 }; 1775 this._updateUser(handler); 1776 }, 1777 1778 /** 1779 * Fired when the Update User Cancel button is clicked. 1780 * 1781 * @method onUpdateUserCancelClick 1782 * @param e {object} DomEvent 1783 * @param args {array} Event parameters (depends on event type) 1784 */ 1785 onUpdateUserCancelClick: function ConsoleUsers_onUpdateUserCancelClick(e, args) 1786 { 1787 this.refreshUIState({"panel": "view"}); 1788 }, 1789 1790 /** 1791 * Fired when the Use Default button is clicked to clear user photo. 1792 * 1793 * @method onUpdateUserClearPhotoClick 1794 * @param e {object} DomEvent 1795 * @param args {array} Event parameters (depends on event type) 1796 */ 1797 onUpdateUserClearPhotoClick: function ConsoleUsers_onUpdateUserClearPhotoClick(e, args) 1798 { 1799 Dom.get(this.id + "-update-photoimg").src = Alfresco.constants.URL_RESCONTEXT + "components/images/no-user-photo-64.png"; 1800 this._getCurrentPanel().setPhotoReset(); 1801 }, 1802 1803 /** 1804 * Encode state object into a packed string for use as url history value. 1805 * Override base class. 1806 * 1807 * @method encodeHistoryState 1808 * @param obj {object} state object 1809 * @private 1810 */ 1811 encodeHistoryState: function ConsoleUsers_encodeHistoryState(obj) 1812 { 1813 // wrap up current state values 1814 var stateObj = {}; 1815 if (this.currentPanelId !== "") 1816 { 1817 stateObj.panel = this.currentPanelId; 1818 } 1819 if (this.currentUserId !== "") 1820 { 1821 stateObj.userid = this.currentUserId; 1822 } 1823 if (this.searchTerm !== undefined) 1824 { 1825 stateObj.search = this.searchTerm; 1826 } 1827 1828 // convert to encoded url history state - overwriting with any supplied values 1829 var state = ""; 1830 if (obj.panel || stateObj.panel) 1831 { 1832 state += "panel=" + encodeURIComponent(obj.panel ? obj.panel : stateObj.panel); 1833 } 1834 if (obj.userid || stateObj.userid) 1835 { 1836 if (state.length !== 0) 1837 { 1838 state += "&"; 1839 } 1840 state += "userid=" + encodeURIComponent(obj.userid ? obj.userid : stateObj.userid); 1841 } 1842 if (obj.search !== undefined || stateObj.search !== undefined) 1843 { 1844 if (state.length !== 0) 1845 { 1846 state += "&"; 1847 } 1848 state += "search=" + encodeURIComponent(obj.search !== undefined ? obj.search : stateObj.search); 1849 } 1850 return state; 1851 }, 1852 1853 /** 1854 * PRIVATE FUNCTIONS 1855 */ 1856 1857 /** 1858 * Create a user - returning true on success, false on any error. 1859 * 1860 * @method _createUser 1861 * @param handler {function} Handler function to be called on successful creation 1862 * @private 1863 */ 1864 _createUser: function ConsoleUsers__createUser(handler) 1865 { 1866 // TODO: respect minimum field length for username/password 1867 1868 var me = this; 1869 var fnGetter = function(id) 1870 { 1871 return YAHOO.lang.trim(Dom.get(me.id + id).value); 1872 }; 1873 1874 // verify password against second field 1875 var password = fnGetter("-create-password"); 1876 var verifypw = fnGetter("-create-verifypassword"); 1877 if (password !== verifypw) 1878 { 1879 Alfresco.util.PopupManager.displayMessage( 1880 { 1881 text: this._msg("message.password-validate-failure") 1882 }); 1883 return; 1884 } 1885 1886 // gather up the data for our JSON PUT request 1887 var username = fnGetter("-create-username"); 1888 var quota = this._calculateQuota(me.id + "-create"); 1889 1890 // gather the selected groups from the panel 1891 var groups = this._getCurrentPanel().getGroups(); 1892 1893 var personObj = 1894 { 1895 userName: username, 1896 password: password, 1897 firstName: fnGetter("-create-firstname"), 1898 lastName: fnGetter("-create-lastname"), 1899 email: fnGetter("-create-email"), 1900 disableAccount: Dom.get(me.id + "-create-disableaccount").checked, 1901 quota: quota, 1902 groups: groups 1903 }; 1904 1905 Alfresco.util.Ajax.request( 1906 { 1907 url: Alfresco.constants.PROXY_URI + "api/people", 1908 method: Alfresco.util.Ajax.POST, 1909 dataObj: personObj, 1910 requestContentType: Alfresco.util.Ajax.JSON, 1911 successCallback: 1912 { 1913 fn: handler, 1914 scope: this 1915 }, 1916 failureCallback: 1917 { 1918 fn: function(res) 1919 { 1920 var json = Alfresco.util.parseJSON(res.serverResponse.responseText); 1921 if (json.status.code === 409) 1922 { 1923 // username already exists 1924 Alfresco.util.PopupManager.displayPrompt( 1925 { 1926 title: this._msg("message.failure"), 1927 text: this._msg("message.create-user-exists") 1928 }); 1929 } 1930 else 1931 { 1932 // generic error 1933 Alfresco.util.PopupManager.displayPrompt( 1934 { 1935 title: this._msg("message.failure"), 1936 text: this._msg("message.create-failure", json.message) 1937 }); 1938 } 1939 }, 1940 scope: this 1941 } 1942 }); 1943 }, 1944 1945 /** 1946 * Update a user - returning true on success, false on any error. 1947 * 1948 * @method _updateUser 1949 * @param handler {function} Handler function to be called on successful update 1950 * @private 1951 */ 1952 _updateUser: function ConsoleUsers__updateUser(handler) 1953 { 1954 var me = this; 1955 1956 var isCurrentUser = (this.currentUserId.toLowerCase() === Alfresco.constants.USERNAME.toLowerCase()); 1957 1958 var fnGetter = function(id) 1959 { 1960 return Dom.get(me.id + id).value; 1961 }; 1962 1963 var updateSuccess = function(res) 1964 { 1965 var completed = function(res) 1966 { 1967 if (YAHOO.lang.trim(fnGetter("-update-password")).length !== 0) 1968 { 1969 var passwordObj = 1970 { 1971 newpw: YAHOO.lang.trim(fnGetter("-update-password")) 1972 }; 1973 if (isCurrentUser == true) 1974 { 1975 passwordObj.oldpw = YAHOO.lang.trim(fnGetter("-update-old-password")); 1976 } 1977 1978 // update the password for the user 1979 Alfresco.util.Ajax.request( 1980 { 1981 url: Alfresco.constants.PROXY_URI + "api/person/changepassword/" + encodeURIComponent(me.currentUserId), 1982 method: Alfresco.util.Ajax.POST, 1983 dataObj: passwordObj, 1984 requestContentType: Alfresco.util.Ajax.JSON, 1985 successCallback: 1986 { 1987 fn: handler, 1988 scope: me 1989 }, 1990 failureMessage: me._msg("message.password-failure") 1991 }); 1992 } 1993 else 1994 { 1995 handler.call(); 1996 } 1997 }; 1998 1999 if (this._getCurrentPanel().getPhotoReset()) 2000 { 2001 Alfresco.util.Ajax.request( 2002 { 2003 url: Alfresco.constants.PROXY_URI + "slingshot/profile/resetavatar/" + encodeURIComponent(this.currentUserId), 2004 method: Alfresco.util.Ajax.PUT, 2005 requestContentType: Alfresco.util.Ajax.JSON, 2006 successCallback: 2007 { 2008 fn: completed, 2009 scope: this 2010 }, 2011 failureCallback: 2012 { 2013 fn: function(res) 2014 { 2015 // generic error 2016 Alfresco.util.PopupManager.displayPrompt( 2017 { 2018 title: this._msg("message.failure"), 2019 text: this._msg("message.clear-photo-failure") 2020 }); 2021 completed.call(); 2022 }, 2023 scope: this 2024 } 2025 }); 2026 } 2027 else 2028 { 2029 completed.call(); 2030 } 2031 }; 2032 2033 // verify password against second field 2034 var oldPw = fnGetter("-update-old-password"); 2035 var password = fnGetter("-update-password"); 2036 var verifypw = fnGetter("-update-verifypassword"); 2037 if (YAHOO.lang.trim(password).length !== 0) 2038 { 2039 if (isCurrentUser == true && (YAHOO.lang.trim(oldPw).length === 0)) 2040 { 2041 Alfresco.util.PopupManager.displayMessage( 2042 { 2043 text: this._msg("message.password-validate-oldpw") 2044 }); 2045 return; 2046 } 2047 if (YAHOO.lang.trim(password).length < this.options.minPasswordLength) 2048 { 2049 Alfresco.util.PopupManager.displayMessage( 2050 { 2051 text: this._msg("message.password-validate-length", this.options.minPasswordLength) 2052 }); 2053 return; 2054 } 2055 if (password !== verifypw) 2056 { 2057 Alfresco.util.PopupManager.displayMessage( 2058 { 2059 text: this._msg("message.password-validate-failure") 2060 }); 2061 return; 2062 } 2063 } 2064 2065 // gather up the data for our JSON PUT request 2066 var quota = this._calculateQuota(me.id + "-update"); 2067 2068 // gather the groups for addition and groups for removal from the panel 2069 var addGroups = this._getCurrentPanel().getAddedGroups(); 2070 var removeGroups = this._getCurrentPanel().getRemovedGroups(); 2071 2072 var personObj = 2073 { 2074 firstName: fnGetter("-update-firstname"), 2075 lastName: fnGetter("-update-lastname"), 2076 email: fnGetter("-update-email"), 2077 disableAccount: Dom.get(me.id + "-update-disableaccount").checked, 2078 quota: quota, 2079 addGroups: addGroups, 2080 removeGroups: removeGroups 2081 }; 2082 2083 Alfresco.util.Ajax.request( 2084 { 2085 url: Alfresco.constants.PROXY_URI + "api/people/" + encodeURIComponent(this.currentUserId), 2086 method: Alfresco.util.Ajax.PUT, 2087 dataObj: personObj, 2088 requestContentType: Alfresco.util.Ajax.JSON, 2089 successCallback: 2090 { 2091 fn: updateSuccess, 2092 scope: this 2093 }, 2094 failureCallback: 2095 { 2096 fn: function(res) 2097 { 2098 var json = Alfresco.util.parseJSON(res.serverResponse.responseText); 2099 Alfresco.util.PopupManager.displayPrompt( 2100 { 2101 title: this._msg("message.failure"), 2102 text: this._msg("message.update-failure", json.message) 2103 }); 2104 }, 2105 scope: this 2106 } 2107 }); 2108 }, 2109 2110 /** 2111 * Return the quota value as input by the user - converted to bytes. 2112 * 2113 * @method _calculateQuota 2114 * @param idPrefix {string} ID prefix of the quota UI elements 2115 * @return the quota value as input by the user - converted to bytes 2116 * @private 2117 */ 2118 _calculateQuota: function ConsoleUsers__calculateQuota(idPrefix) 2119 { 2120 var quota = -1; 2121 var quotaValue = Dom.get(idPrefix + "-quota").value; 2122 if (quotaValue.length !== 0) 2123 { 2124 // convert from giga/mega/kilo bytes 2125 try 2126 { 2127 quota = parseInt(quotaValue); 2128 if (quota >= 0) 2129 { 2130 var quotaType = Dom.get(idPrefix + "-quotatype").value; 2131 if (quotaType === "gb") 2132 { 2133 quota *= Alfresco.util.BYTES_GB; 2134 } 2135 else if (quotaType === "mb") 2136 { 2137 quota *= Alfresco.util.BYTES_MB; 2138 } 2139 else if (quotaType === "kb") 2140 { 2141 quota *= Alfresco.util.BYTES_KB; 2142 } 2143 } 2144 else 2145 { 2146 quota = -1; 2147 } 2148 } 2149 catch (e) 2150 { 2151 // ignore if we cannot parse quota field 2152 } 2153 } 2154 return quota; 2155 }, 2156 2157 /** 2158 * Gets a custom message 2159 * 2160 * @method _msg 2161 * @param messageId {string} The messageId to retrieve 2162 * @return {string} The custom message 2163 * @private 2164 */ 2165 _msg: function ConsoleUsers__msg(messageId) 2166 { 2167 return Alfresco.util.message.call(this, messageId, "Alfresco.ConsoleUsers", Array.prototype.slice.call(arguments).slice(1)); 2168 } 2169 }); 2170 })();