Rushabh Mehta | aaf86ba | 2012-02-28 17:40:13 +0530 | [diff] [blame] | 1 | // ERPNext - web based ERP (http://erpnext.com) |
| 2 | // Copyright (C) 2012 Web Notes Technologies Pvt Ltd |
| 3 | // |
| 4 | // This program is free software: you can redistribute it and/or modify |
| 5 | // it under the terms of the GNU General Public License as published by |
| 6 | // the Free Software Foundation, either version 3 of the License, or |
| 7 | // (at your option) any later version. |
| 8 | // |
| 9 | // This program is distributed in the hope that it will be useful, |
| 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | // GNU General Public License for more details. |
| 13 | // |
| 14 | // You should have received a copy of the GNU General Public License |
| 15 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 16 | |
| 17 | $.extend(wn.pages.users, { |
| 18 | onload: function(wrapper) { |
| 19 | wn.pages.users.profiles = {}; |
| 20 | wn.pages.users.refresh(); |
| 21 | wn.pages.users.setup(); |
| 22 | wn.pages.users.role_editor = new erpnext.RoleEditor(); |
| 23 | }, |
| 24 | setup: function() { |
| 25 | // set roles |
| 26 | $('.users-area').on('click', '.btn.user-roles', function() { |
| 27 | var uid = $(this).parent().parent().attr('data-name'); |
| 28 | wn.pages.users.role_editor.show(uid); |
| 29 | }); |
| 30 | |
| 31 | // settings |
| 32 | $('.users-area').on('click', '.btn.user-settings', function() { |
| 33 | var uid = $(this).parent().parent().attr('data-name'); |
| 34 | wn.pages.users.show_settings(uid); |
| 35 | }); |
| 36 | |
| 37 | // delete |
| 38 | $('.users-area').on('click', 'a.close', function() { |
| 39 | $card = $(this).parent(); |
| 40 | var uid = $card.attr('data-name'); |
| 41 | $card.css('opacity', 0.6); |
| 42 | wn.call({ |
| 43 | method: 'utilities.page.users.users.delete', |
| 44 | args: {'uid': uid}, |
| 45 | callback: function(r,rt) { |
| 46 | if(!r.exc) |
| 47 | $card.fadeOut() |
| 48 | } |
| 49 | }); |
| 50 | }) |
| 51 | |
| 52 | }, |
| 53 | refresh: function() { |
| 54 | // make the list |
| 55 | wn.call({ |
| 56 | method:'utilities.page.users.users.get', |
| 57 | callback: function(r, rt) { |
| 58 | $('.users-area').empty(); |
| 59 | for(var i in r.message) { |
| 60 | var p = r.message[i]; |
| 61 | wn.pages.users.profiles[p.name] = p; |
| 62 | wn.pages.users.render(p); |
| 63 | } |
| 64 | } |
| 65 | }); |
Anand Doshi | 1ed4ef1 | 2012-04-27 15:30:23 +0530 | [diff] [blame] | 66 | if(!$('.subscription-info').length && (wn.boot.max_users || wn.boot.expires_on)) { |
Anand Doshi | 3f6eed2 | 2012-05-01 12:23:28 +0530 | [diff] [blame] | 67 | var $sub_info = $('<div class="subscription-info-box"><div>') |
| 68 | .insertAfter($(wn.pages.users).find('.help')); |
Anand Doshi | 1ed4ef1 | 2012-04-27 15:30:23 +0530 | [diff] [blame] | 69 | if(wn.boot.max_users) { |
| 70 | $sub_info.append(repl('\ |
| 71 | <span class="subscription-info"> \ |
| 72 | Max Users: <b>%(max_users)s</b> \ |
| 73 | </span>', { max_users: wn.boot.max_users })); |
| 74 | } |
| 75 | if(wn.boot.expires_on) { |
| 76 | $sub_info.append(repl('\ |
| 77 | <span class="subscription-info"> \ |
| 78 | Expires On: <b>%(expires_on)s</b> \ |
| 79 | </span>', { expires_on: dateutil.str_to_user(wn.boot.expires_on) })); |
| 80 | } |
| 81 | } |
Rushabh Mehta | aaf86ba | 2012-02-28 17:40:13 +0530 | [diff] [blame] | 82 | }, |
| 83 | render: function(data) { |
| 84 | if(data.file_list) { |
Rushabh Mehta | 1572adf | 2012-02-29 15:19:20 +0530 | [diff] [blame] | 85 | data.imgsrc = 'files/' + data.file_list.split('\n')[0].split(',')[1]; |
Rushabh Mehta | aaf86ba | 2012-02-28 17:40:13 +0530 | [diff] [blame] | 86 | } else { |
Rushabh Mehta | 79ae165 | 2012-02-29 15:23:25 +0530 | [diff] [blame] | 87 | data.imgsrc = 'lib/images/ui/no_img_' + (data.gender=='Female' ? 'f' : 'm') + '.gif'; |
Rushabh Mehta | aaf86ba | 2012-02-28 17:40:13 +0530 | [diff] [blame] | 88 | } |
Rushabh Mehta | 204e77d | 2012-02-29 19:09:20 +0530 | [diff] [blame] | 89 | data.fullname = wn.user_info(data.name).fullname; |
Rushabh Mehta | aaf86ba | 2012-02-28 17:40:13 +0530 | [diff] [blame] | 90 | data.delete_html = ''; |
| 91 | if(!data.enabled) |
| 92 | data.delete_html = '<a class="close" title="delete">×</a>'; |
| 93 | |
| 94 | $('.users-area').append(repl('<div class="user-card" data-name="%(name)s">\ |
| 95 | %(delete_html)s\ |
| 96 | <img src="%(imgsrc)s">\ |
| 97 | <div class="user-info">\ |
| 98 | <b class="user-fullname">%(fullname)s</b><br>\ |
| 99 | %(name)s<br>\ |
| 100 | <button class="btn btn-small user-roles"><i class="icon-user"></i> Roles</button>\ |
| 101 | <button class="btn btn-small user-settings"><i class="icon-cog"></i> Settings</button>\ |
| 102 | </div>\ |
| 103 | </div>', data)); |
| 104 | |
| 105 | if(!data.enabled) { |
| 106 | $('.users-area .user-card:last') |
| 107 | .addClass('disabled') |
| 108 | .find('.user-fullname').html('Disabled'); |
| 109 | } |
| 110 | }, |
| 111 | show_settings: function(uid) { |
| 112 | var me = wn.pages.users; |
| 113 | if(!me.settings_dialog) |
| 114 | me.make_settings_dialog(); |
| 115 | |
| 116 | var p = me.profiles[uid]; |
| 117 | me.uid = uid; |
| 118 | |
| 119 | me.settings_dialog.set_values({ |
| 120 | restrict_ip: p.restrict_ip || '', |
| 121 | login_before: p.login_before || '', |
| 122 | login_after: p.login_after || '', |
| 123 | enabled: p.enabled || 0, |
| 124 | new_password: '' |
| 125 | }); |
| 126 | |
| 127 | me.settings_dialog.show(); |
| 128 | |
| 129 | }, |
| 130 | make_settings_dialog: function() { |
| 131 | var me = wn.pages.users; |
| 132 | me.settings_dialog = new wn.widgets.Dialog({ |
| 133 | title: 'Set User Security', |
| 134 | width: 500, |
| 135 | fields: [ |
| 136 | { |
| 137 | label:'Enabled', |
| 138 | description: 'Uncheck to disable', |
| 139 | fieldtype: 'Check', fieldname: 'enabled' |
| 140 | }, |
| 141 | { |
| 142 | label:'IP Address', |
| 143 | description: 'Restrict user login by IP address, partial ips (111.111.111), \ |
| 144 | multiple addresses (separated by commas) allowed', |
| 145 | fieldname:'restrict_ip', fieldtype:'Data' |
| 146 | }, |
| 147 | { |
| 148 | label:'Login After', |
| 149 | description: 'User can only login after this hour (0-24)', |
| 150 | fieldtype: 'Int', fieldname: 'login_after' |
| 151 | }, |
| 152 | { |
| 153 | label:'Login Before', |
| 154 | description: 'User can only login before this hour (0-24)', |
| 155 | fieldtype: 'Int', fieldname: 'login_before' |
| 156 | }, |
| 157 | { |
| 158 | label:'New Password', |
| 159 | description: 'Update the current user password', |
| 160 | fieldtype: 'Data', fieldname: 'new_password' |
| 161 | }, |
| 162 | { |
| 163 | label:'Update', fieldtype:'Button', fieldname:'update' |
| 164 | } |
| 165 | ] |
| 166 | }); |
| 167 | |
| 168 | this.settings_dialog.fields_dict.update.input.onclick = function() { |
| 169 | var btn = this; |
Rushabh Mehta | aaf86ba | 2012-02-28 17:40:13 +0530 | [diff] [blame] | 170 | var args = me.settings_dialog.get_values(); |
| 171 | args.user = me.uid; |
| 172 | |
| 173 | if (args.new_password) { |
| 174 | me.get_password(btn, args); |
| 175 | } else { |
Rushabh Mehta | ffb25fc | 2012-03-01 11:29:22 +0530 | [diff] [blame] | 176 | me.update_security(btn, args); |
Rushabh Mehta | aaf86ba | 2012-02-28 17:40:13 +0530 | [diff] [blame] | 177 | } |
| 178 | }; |
| 179 | |
| 180 | }, |
Rushabh Mehta | ffb25fc | 2012-03-01 11:29:22 +0530 | [diff] [blame] | 181 | update_security: function(btn, args) { |
Rushabh Mehta | aaf86ba | 2012-02-28 17:40:13 +0530 | [diff] [blame] | 182 | var me = wn.pages.users; |
Rushabh Mehta | ffb25fc | 2012-03-01 11:29:22 +0530 | [diff] [blame] | 183 | $(btn).set_working(); |
Rushabh Mehta | aaf86ba | 2012-02-28 17:40:13 +0530 | [diff] [blame] | 184 | $c_page('utilities', 'users', 'update_security', JSON.stringify(args), function(r,rt) { |
Rushabh Mehta | ffb25fc | 2012-03-01 11:29:22 +0530 | [diff] [blame] | 185 | $(btn).done_working(); |
Rushabh Mehta | aaf86ba | 2012-02-28 17:40:13 +0530 | [diff] [blame] | 186 | if(r.exc) { |
| 187 | msgprint(r.exc); |
| 188 | return; |
| 189 | } |
| 190 | me.settings_dialog.hide(); |
| 191 | $.extend(me.profiles[me.uid], me.settings_dialog.get_values()); |
| 192 | me.refresh(); |
| 193 | }); |
| 194 | }, |
| 195 | get_password: function(btn, args) { |
| 196 | var me = wn.pages.users; |
| 197 | var pass_d = new wn.widgets.Dialog({ |
| 198 | title: 'Your Password', |
| 199 | width: 300, |
| 200 | fields: [ |
| 201 | { |
| 202 | label: 'Please Enter <b style="color: black">Your Password</b>', |
| 203 | description: "Your password is required to update the user's password", |
| 204 | fieldtype: 'Password', fieldname: 'sys_admin_pwd', reqd: 1 |
| 205 | }, |
| 206 | { |
| 207 | label: 'Continue', fieldtype: 'Button', fieldname: 'continue' |
| 208 | } |
| 209 | ] |
| 210 | }); |
| 211 | |
| 212 | pass_d.fields_dict.continue.input.onclick = function() { |
| 213 | btn.pwd_dialog.hide(); |
| 214 | args.sys_admin_pwd = btn.pwd_dialog.get_values().sys_admin_pwd; |
| 215 | btn.set_working(); |
Anand Doshi | ecd8df8 | 2012-03-02 12:18:47 +0530 | [diff] [blame] | 216 | me.update_security(btn, args); |
Rushabh Mehta | aaf86ba | 2012-02-28 17:40:13 +0530 | [diff] [blame] | 217 | btn.done_working(); |
| 218 | } |
| 219 | |
| 220 | pass_d.show(); |
| 221 | btn.pwd_dialog = pass_d; |
| 222 | btn.done_working(); |
| 223 | }, |
| 224 | add_user: function() { |
| 225 | var me = wn.pages.users; |
Anand Doshi | 1ed4ef1 | 2012-04-27 15:30:23 +0530 | [diff] [blame] | 226 | var active_users = $('.user-card:not(.disabled)'); |
Anand Doshi | 5c2a792 | 2012-04-30 20:03:23 +0530 | [diff] [blame] | 227 | if(wn.boot.max_users && (active_users.length >= wn.boot.max_users)) { |
Anand Doshi | 1ed4ef1 | 2012-04-27 15:30:23 +0530 | [diff] [blame] | 228 | msgprint(repl("Alas! <br />\ |
| 229 | You already have <b>%(active_users)s</b> active users, \ |
| 230 | which is the maximum number that you are currently allowed to add. <br /><br /> \ |
| 231 | So, to add more users, you can:<br /> \ |
| 232 | 1. <b>Upgrade to the unlimited users plan</b>, or<br /> \ |
| 233 | 2. <b>Disable one or more of your existing users and try again</b>", |
| 234 | {active_users: active_users.length})); |
| 235 | return; |
| 236 | } |
Rushabh Mehta | aaf86ba | 2012-02-28 17:40:13 +0530 | [diff] [blame] | 237 | var d = new wn.widgets.Dialog({ |
| 238 | title: 'Add User', |
| 239 | width: 400, |
| 240 | fields: [{ |
| 241 | fieldtype: 'Data', fieldname: 'user', reqd: 1, |
| 242 | label: 'Email Id of the user to add' |
| 243 | }, { |
| 244 | fieldtype: 'Data', fieldname: 'first_name', reqd: 1, label: 'First Name' |
| 245 | }, { |
| 246 | fieldtype: 'Data', fieldname: 'last_name', label: 'Last Name' |
| 247 | }, { |
| 248 | fieldtype: 'Data', fieldname: 'password', reqd: 1, label: 'Password' |
| 249 | }, { |
| 250 | fieldtype: 'Button', label: 'Add', fieldname: 'add' |
| 251 | }] |
| 252 | }); |
| 253 | |
| 254 | d.make(); |
| 255 | d.fields_dict.add.input.onclick = function() { |
| 256 | v = d.get_values(); |
| 257 | if(v) { |
| 258 | d.fields_dict.add.input.set_working(); |
| 259 | $c_page('utilities', 'users', 'add_user', v, function(r,rt) { |
| 260 | if(r.exc) { msgprint(r.exc); return; } |
| 261 | else { |
Anand Doshi | a6952c9 | 2012-03-07 19:37:23 +0530 | [diff] [blame] | 262 | wn.boot.user_info[v.user] = {fullname:v.first_name + ' ' + (v.last_name || '')}; |
Rushabh Mehta | aaf86ba | 2012-02-28 17:40:13 +0530 | [diff] [blame] | 263 | d.hide(); |
| 264 | me.refresh(); |
| 265 | } |
| 266 | }) |
| 267 | } |
| 268 | } |
| 269 | d.show(); |
| 270 | } |
| 271 | }); |
| 272 | |
| 273 | erpnext.RoleEditor = Class.extend({ |
| 274 | init: function() { |
| 275 | this.dialog = new wn.widgets.Dialog({ |
| 276 | title: 'Set Roles' |
| 277 | }); |
| 278 | var me = this; |
| 279 | $(this.dialog.body).html('<div class="help">Loading...</div>') |
| 280 | wn.call({ |
| 281 | method:'utilities.page.users.users.get_roles', |
| 282 | callback: function(r) { |
| 283 | me.roles = r.message; |
| 284 | me.show_roles(); |
| 285 | } |
| 286 | }); |
| 287 | }, |
| 288 | show_roles: function() { |
| 289 | var me = this; |
| 290 | $(this.dialog.body).empty(); |
| 291 | for(var i in this.roles) { |
| 292 | $(this.dialog.body).append(repl('<div class="user-role" \ |
| 293 | data-user-role="%(role)s">\ |
| 294 | <input type="checkbox"> \ |
| 295 | <a href="#"><i class="icon-question-sign"></i></a> %(role)s\ |
| 296 | </div>', {role: this.roles[i]})); |
| 297 | } |
| 298 | $(this.dialog.body).append('<div style="clear: both">\ |
Rushabh Mehta | b9004bd | 2012-03-05 18:28:33 +0530 | [diff] [blame] | 299 | <button class="btn btn-small btn-info">Save</button></div>'); |
| 300 | $(this.dialog.body).find('button.btn-info').click(function() { |
Rushabh Mehta | aaf86ba | 2012-02-28 17:40:13 +0530 | [diff] [blame] | 301 | me.save(); |
| 302 | }); |
| 303 | $(this.dialog.body).find('.user-role a').click(function() { |
| 304 | me.show_permissions($(this).parent().attr('data-user-role')) |
| 305 | return false; |
| 306 | }) |
| 307 | }, |
| 308 | show: function(uid) { |
| 309 | var me = this; |
| 310 | this.uid = uid; |
| 311 | this.dialog.show(); |
| 312 | // set user roles |
| 313 | wn.call({ |
| 314 | method:'utilities.page.users.users.get_user_roles', |
| 315 | args: {uid:uid}, |
| 316 | callback: function(r, rt) { |
| 317 | $(me.dialog.body).find('input[type="checkbox"]').attr('checked', false); |
| 318 | for(var i in r.message) { |
| 319 | $(me.dialog.body) |
| 320 | .find('[data-user-role="'+r.message[i] |
| 321 | +'"] input[type="checkbox"]').attr('checked',true); |
| 322 | } |
| 323 | } |
| 324 | }) |
| 325 | }, |
| 326 | save: function() { |
| 327 | var set_roles = []; |
| 328 | var unset_roles = []; |
| 329 | $(this.dialog.body).find('[data-user-role]').each(function() { |
| 330 | var $check = $(this).find('input[type="checkbox"]'); |
| 331 | if($check.attr('checked')) { |
| 332 | set_roles.push($(this).attr('data-user-role')); |
| 333 | } else { |
| 334 | unset_roles.push($(this).attr('data-user-role')); |
| 335 | } |
| 336 | }) |
| 337 | wn.call({ |
| 338 | method:'utilities.page.users.users.update_roles', |
| 339 | args: { |
| 340 | set_roles: JSON.stringify(set_roles), |
| 341 | unset_roles: JSON.stringify(unset_roles), |
| 342 | uid: this.uid |
| 343 | }, |
Rushabh Mehta | b9004bd | 2012-03-05 18:28:33 +0530 | [diff] [blame] | 344 | btn: $(this.dialog.body).find('.btn-info').get(0), |
Rushabh Mehta | aaf86ba | 2012-02-28 17:40:13 +0530 | [diff] [blame] | 345 | callback: function() { |
| 346 | |
| 347 | } |
| 348 | }) |
| 349 | }, |
| 350 | show_permissions: function(role) { |
| 351 | // show permissions for a role |
| 352 | var me = this; |
| 353 | if(!this.perm_dialog) |
| 354 | this.make_perm_dialog() |
| 355 | $(this.perm_dialog.body).empty(); |
| 356 | wn.call({ |
| 357 | method:'utilities.page.users.users.get_perm_info', |
| 358 | args: {role: role}, |
| 359 | callback: function(r) { |
| 360 | var $body = $(me.perm_dialog.body); |
| 361 | $body.append('<table class="user-perm"><tbody><tr>\ |
| 362 | <th style="text-align: left">Document Type</th>\ |
| 363 | <th>Level</th>\ |
| 364 | <th>Read</th>\ |
| 365 | <th>Write</th>\ |
| 366 | <th>Submit</th>\ |
| 367 | <th>Cancel</th>\ |
| 368 | <th>Amend</th></tr></tbody></table>'); |
| 369 | for(var i in r.message) { |
| 370 | var perm = r.message[i]; |
| 371 | |
| 372 | // if permission -> icon |
| 373 | for(key in perm) { |
| 374 | if(key!='parent' && key!='permlevel') { |
| 375 | if(perm[key]) { |
| 376 | perm[key] = '<i class="icon-ok"></i>'; |
| 377 | } else { |
| 378 | perm[key] = ''; |
| 379 | } |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | $body.find('tbody').append(repl('<tr>\ |
| 384 | <td style="text-align: left">%(parent)s</td>\ |
| 385 | <td>%(permlevel)s</td>\ |
| 386 | <td>%(read)s</td>\ |
| 387 | <td>%(write)s</td>\ |
| 388 | <td>%(submit)s</td>\ |
| 389 | <td>%(cancel)s</td>\ |
| 390 | <td>%(amend)s</td>\ |
| 391 | </tr>', perm)) |
| 392 | } |
| 393 | |
| 394 | me.perm_dialog.show(); |
| 395 | } |
| 396 | }); |
| 397 | |
| 398 | }, |
| 399 | make_perm_dialog: function() { |
| 400 | this.perm_dialog = new wn.widgets.Dialog({ |
| 401 | title:'Role Permissions', |
| 402 | width: 500 |
| 403 | }); |
| 404 | } |
| 405 | }) |