blob: ee05001edf979b917a0dbc026bbc54ef04c6349d [file] [log] [blame]
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +05301// 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) {
Rushabh Mehtad47efd52012-07-13 11:15:25 +053019 var w = wn.pages.users;
20 wn.ui.make_app_page({
21 parent: w,
22 title: "Users",
23 single_column: true
24 });
25 w.profiles = {};
26 w.refresh();
27 w.setup();
28 w.role_editor = new erpnext.RoleEditor();
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +053029 },
30 setup: function() {
Rushabh Mehtad47efd52012-07-13 11:15:25 +053031 wn.pages.users.appframe.add_button('+ Add User', function() {
32 wn.pages.users.add_user();
33 });
34
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +053035 // set roles
Rushabh Mehtad47efd52012-07-13 11:15:25 +053036 var w = wn.pages.users;
37 $(w).on('click', '.btn.user-roles', function() {
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +053038 var uid = $(this).parent().parent().attr('data-name');
39 wn.pages.users.role_editor.show(uid);
40 });
41
42 // settings
Rushabh Mehtad47efd52012-07-13 11:15:25 +053043 $(w).on('click', '.btn.user-settings', function() {
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +053044 var uid = $(this).parent().parent().attr('data-name');
45 wn.pages.users.show_settings(uid);
46 });
47
48 // delete
Rushabh Mehtad47efd52012-07-13 11:15:25 +053049 $(w).on('click', 'a.close', function() {
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +053050 $card = $(this).parent();
51 var uid = $card.attr('data-name');
52 $card.css('opacity', 0.6);
53 wn.call({
54 method: 'utilities.page.users.users.delete',
55 args: {'uid': uid},
56 callback: function(r,rt) {
57 if(!r.exc)
58 $card.fadeOut()
59 }
60 });
61 })
62
63 },
64 refresh: function() {
65 // make the list
66 wn.call({
67 method:'utilities.page.users.users.get',
68 callback: function(r, rt) {
Rushabh Mehtad47efd52012-07-13 11:15:25 +053069 $(wn.pages.users).find('.layout-main').empty();
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +053070 for(var i in r.message) {
71 var p = r.message[i];
72 wn.pages.users.profiles[p.name] = p;
73 wn.pages.users.render(p);
74 }
75 }
76 });
Anand Doshi1ed4ef12012-04-27 15:30:23 +053077 if(!$('.subscription-info').length && (wn.boot.max_users || wn.boot.expires_on)) {
Anand Doshi3f6eed22012-05-01 12:23:28 +053078 var $sub_info = $('<div class="subscription-info-box"><div>')
79 .insertAfter($(wn.pages.users).find('.help'));
Anand Doshi1ed4ef12012-04-27 15:30:23 +053080 if(wn.boot.max_users) {
81 $sub_info.append(repl('\
82 <span class="subscription-info"> \
83 Max Users: <b>%(max_users)s</b> \
84 </span>', { max_users: wn.boot.max_users }));
85 }
86 if(wn.boot.expires_on) {
87 $sub_info.append(repl('\
88 <span class="subscription-info"> \
89 Expires On: <b>%(expires_on)s</b> \
90 </span>', { expires_on: dateutil.str_to_user(wn.boot.expires_on) }));
91 }
92 }
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +053093 },
94 render: function(data) {
95 if(data.file_list) {
Rushabh Mehta1572adf2012-02-29 15:19:20 +053096 data.imgsrc = 'files/' + data.file_list.split('\n')[0].split(',')[1];
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +053097 } else {
Rushabh Mehtaa9209432012-05-07 18:00:57 +053098 data.imgsrc = 'images/lib/ui/no_img_' + (data.gender=='Female' ? 'f' : 'm') + '.gif';
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +053099 }
Rushabh Mehta204e77d2012-02-29 19:09:20 +0530100 data.fullname = wn.user_info(data.name).fullname;
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +0530101 data.delete_html = '';
102 if(!data.enabled)
103 data.delete_html = '<a class="close" title="delete">&times;</a>';
104
Rushabh Mehtad47efd52012-07-13 11:15:25 +0530105 $(wn.pages.users).find('.layout-main').append(repl('<div class="user-card" data-name="%(name)s">\
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +0530106 %(delete_html)s\
107 <img src="%(imgsrc)s">\
108 <div class="user-info">\
109 <b class="user-fullname">%(fullname)s</b><br>\
110 %(name)s<br>\
111 <button class="btn btn-small user-roles"><i class="icon-user"></i> Roles</button>\
112 <button class="btn btn-small user-settings"><i class="icon-cog"></i> Settings</button>\
113 </div>\
114 </div>', data));
115
116 if(!data.enabled) {
Rushabh Mehtad47efd52012-07-13 11:15:25 +0530117 $(wn.pages.users).find('.layout-main .user-card:last')
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +0530118 .addClass('disabled')
119 .find('.user-fullname').html('Disabled');
120 }
121 },
122 show_settings: function(uid) {
123 var me = wn.pages.users;
124 if(!me.settings_dialog)
125 me.make_settings_dialog();
126
127 var p = me.profiles[uid];
128 me.uid = uid;
129
130 me.settings_dialog.set_values({
131 restrict_ip: p.restrict_ip || '',
132 login_before: p.login_before || '',
133 login_after: p.login_after || '',
134 enabled: p.enabled || 0,
135 new_password: ''
136 });
137
138 me.settings_dialog.show();
139
140 },
141 make_settings_dialog: function() {
142 var me = wn.pages.users;
143 me.settings_dialog = new wn.widgets.Dialog({
144 title: 'Set User Security',
145 width: 500,
146 fields: [
147 {
148 label:'Enabled',
149 description: 'Uncheck to disable',
150 fieldtype: 'Check', fieldname: 'enabled'
151 },
152 {
153 label:'IP Address',
154 description: 'Restrict user login by IP address, partial ips (111.111.111), \
155 multiple addresses (separated by commas) allowed',
156 fieldname:'restrict_ip', fieldtype:'Data'
157 },
158 {
159 label:'Login After',
160 description: 'User can only login after this hour (0-24)',
161 fieldtype: 'Int', fieldname: 'login_after'
162 },
163 {
164 label:'Login Before',
165 description: 'User can only login before this hour (0-24)',
166 fieldtype: 'Int', fieldname: 'login_before'
167 },
168 {
169 label:'New Password',
170 description: 'Update the current user password',
171 fieldtype: 'Data', fieldname: 'new_password'
172 },
173 {
174 label:'Update', fieldtype:'Button', fieldname:'update'
175 }
176 ]
177 });
178
179 this.settings_dialog.fields_dict.update.input.onclick = function() {
180 var btn = this;
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +0530181 var args = me.settings_dialog.get_values();
182 args.user = me.uid;
183
184 if (args.new_password) {
185 me.get_password(btn, args);
186 } else {
Rushabh Mehtaffb25fc2012-03-01 11:29:22 +0530187 me.update_security(btn, args);
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +0530188 }
189 };
190
191 },
Rushabh Mehtaffb25fc2012-03-01 11:29:22 +0530192 update_security: function(btn, args) {
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +0530193 var me = wn.pages.users;
Rushabh Mehtaffb25fc2012-03-01 11:29:22 +0530194 $(btn).set_working();
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +0530195 $c_page('utilities', 'users', 'update_security', JSON.stringify(args), function(r,rt) {
Rushabh Mehtaffb25fc2012-03-01 11:29:22 +0530196 $(btn).done_working();
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +0530197 if(r.exc) {
198 msgprint(r.exc);
199 return;
200 }
201 me.settings_dialog.hide();
202 $.extend(me.profiles[me.uid], me.settings_dialog.get_values());
203 me.refresh();
204 });
205 },
206 get_password: function(btn, args) {
207 var me = wn.pages.users;
208 var pass_d = new wn.widgets.Dialog({
209 title: 'Your Password',
210 width: 300,
211 fields: [
212 {
213 label: 'Please Enter <b style="color: black">Your Password</b>',
214 description: "Your password is required to update the user's password",
215 fieldtype: 'Password', fieldname: 'sys_admin_pwd', reqd: 1
216 },
217 {
218 label: 'Continue', fieldtype: 'Button', fieldname: 'continue'
219 }
220 ]
221 });
222
223 pass_d.fields_dict.continue.input.onclick = function() {
224 btn.pwd_dialog.hide();
225 args.sys_admin_pwd = btn.pwd_dialog.get_values().sys_admin_pwd;
226 btn.set_working();
Anand Doshiecd8df82012-03-02 12:18:47 +0530227 me.update_security(btn, args);
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +0530228 btn.done_working();
229 }
230
231 pass_d.show();
232 btn.pwd_dialog = pass_d;
233 btn.done_working();
234 },
235 add_user: function() {
236 var me = wn.pages.users;
Anand Doshi1ed4ef12012-04-27 15:30:23 +0530237 var active_users = $('.user-card:not(.disabled)');
Anand Doshi5c2a7922012-04-30 20:03:23 +0530238 if(wn.boot.max_users && (active_users.length >= wn.boot.max_users)) {
Rushabh Mehtad47efd52012-07-13 11:15:25 +0530239 msgprint(repl("You already have <b>%(active_users)s</b> active users, \
Anand Doshi1ed4ef12012-04-27 15:30:23 +0530240 which is the maximum number that you are currently allowed to add. <br /><br /> \
241 So, to add more users, you can:<br /> \
242 1. <b>Upgrade to the unlimited users plan</b>, or<br /> \
243 2. <b>Disable one or more of your existing users and try again</b>",
244 {active_users: active_users.length}));
245 return;
246 }
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +0530247 var d = new wn.widgets.Dialog({
248 title: 'Add User',
249 width: 400,
250 fields: [{
251 fieldtype: 'Data', fieldname: 'user', reqd: 1,
252 label: 'Email Id of the user to add'
253 }, {
254 fieldtype: 'Data', fieldname: 'first_name', reqd: 1, label: 'First Name'
255 }, {
256 fieldtype: 'Data', fieldname: 'last_name', label: 'Last Name'
257 }, {
258 fieldtype: 'Data', fieldname: 'password', reqd: 1, label: 'Password'
259 }, {
260 fieldtype: 'Button', label: 'Add', fieldname: 'add'
261 }]
262 });
263
264 d.make();
265 d.fields_dict.add.input.onclick = function() {
266 v = d.get_values();
267 if(v) {
268 d.fields_dict.add.input.set_working();
269 $c_page('utilities', 'users', 'add_user', v, function(r,rt) {
270 if(r.exc) { msgprint(r.exc); return; }
271 else {
Anand Doshia6952c92012-03-07 19:37:23 +0530272 wn.boot.user_info[v.user] = {fullname:v.first_name + ' ' + (v.last_name || '')};
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +0530273 d.hide();
274 me.refresh();
275 }
276 })
277 }
278 }
279 d.show();
280 }
281});
282
283erpnext.RoleEditor = Class.extend({
284 init: function() {
285 this.dialog = new wn.widgets.Dialog({
286 title: 'Set Roles'
287 });
288 var me = this;
289 $(this.dialog.body).html('<div class="help">Loading...</div>')
290 wn.call({
291 method:'utilities.page.users.users.get_roles',
292 callback: function(r) {
293 me.roles = r.message;
294 me.show_roles();
295 }
296 });
297 },
298 show_roles: function() {
299 var me = this;
300 $(this.dialog.body).empty();
301 for(var i in this.roles) {
302 $(this.dialog.body).append(repl('<div class="user-role" \
303 data-user-role="%(role)s">\
304 <input type="checkbox"> \
305 <a href="#"><i class="icon-question-sign"></i></a> %(role)s\
306 </div>', {role: this.roles[i]}));
307 }
308 $(this.dialog.body).append('<div style="clear: both">\
Rushabh Mehtab9004bd2012-03-05 18:28:33 +0530309 <button class="btn btn-small btn-info">Save</button></div>');
310 $(this.dialog.body).find('button.btn-info').click(function() {
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +0530311 me.save();
312 });
313 $(this.dialog.body).find('.user-role a').click(function() {
314 me.show_permissions($(this).parent().attr('data-user-role'))
315 return false;
316 })
317 },
318 show: function(uid) {
319 var me = this;
320 this.uid = uid;
321 this.dialog.show();
322 // set user roles
323 wn.call({
324 method:'utilities.page.users.users.get_user_roles',
325 args: {uid:uid},
326 callback: function(r, rt) {
327 $(me.dialog.body).find('input[type="checkbox"]').attr('checked', false);
328 for(var i in r.message) {
329 $(me.dialog.body)
330 .find('[data-user-role="'+r.message[i]
331 +'"] input[type="checkbox"]').attr('checked',true);
332 }
333 }
334 })
335 },
336 save: function() {
337 var set_roles = [];
338 var unset_roles = [];
339 $(this.dialog.body).find('[data-user-role]').each(function() {
340 var $check = $(this).find('input[type="checkbox"]');
341 if($check.attr('checked')) {
342 set_roles.push($(this).attr('data-user-role'));
343 } else {
344 unset_roles.push($(this).attr('data-user-role'));
345 }
346 })
347 wn.call({
348 method:'utilities.page.users.users.update_roles',
349 args: {
350 set_roles: JSON.stringify(set_roles),
351 unset_roles: JSON.stringify(unset_roles),
352 uid: this.uid
353 },
Rushabh Mehtab9004bd2012-03-05 18:28:33 +0530354 btn: $(this.dialog.body).find('.btn-info').get(0),
Rushabh Mehtaaaf86ba2012-02-28 17:40:13 +0530355 callback: function() {
356
357 }
358 })
359 },
360 show_permissions: function(role) {
361 // show permissions for a role
362 var me = this;
363 if(!this.perm_dialog)
364 this.make_perm_dialog()
365 $(this.perm_dialog.body).empty();
366 wn.call({
367 method:'utilities.page.users.users.get_perm_info',
368 args: {role: role},
369 callback: function(r) {
370 var $body = $(me.perm_dialog.body);
371 $body.append('<table class="user-perm"><tbody><tr>\
372 <th style="text-align: left">Document Type</th>\
373 <th>Level</th>\
374 <th>Read</th>\
375 <th>Write</th>\
376 <th>Submit</th>\
377 <th>Cancel</th>\
378 <th>Amend</th></tr></tbody></table>');
379 for(var i in r.message) {
380 var perm = r.message[i];
381
382 // if permission -> icon
383 for(key in perm) {
384 if(key!='parent' && key!='permlevel') {
385 if(perm[key]) {
386 perm[key] = '<i class="icon-ok"></i>';
387 } else {
388 perm[key] = '';
389 }
390 }
391 }
392
393 $body.find('tbody').append(repl('<tr>\
394 <td style="text-align: left">%(parent)s</td>\
395 <td>%(permlevel)s</td>\
396 <td>%(read)s</td>\
397 <td>%(write)s</td>\
398 <td>%(submit)s</td>\
399 <td>%(cancel)s</td>\
400 <td>%(amend)s</td>\
401 </tr>', perm))
402 }
403
404 me.perm_dialog.show();
405 }
406 });
407
408 },
409 make_perm_dialog: function() {
410 this.perm_dialog = new wn.widgets.Dialog({
411 title:'Role Permissions',
412 width: 500
413 });
414 }
415})