added users
diff --git a/css/all-app.css b/css/all-app.css
index b2fd2e5..b49caed 100644
--- a/css/all-app.css
+++ b/css/all-app.css
@@ -1043,7 +1043,7 @@
}
div.dialog_body {
- padding: 8px 4px 16px 4px;
+ padding: 8px 8px 16px;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
diff --git a/css/all-web.css b/css/all-web.css
index 9359de8..bebfe9a 100644
--- a/css/all-web.css
+++ b/css/all-web.css
@@ -362,7 +362,7 @@
}
div.dialog_body {
- padding: 8px 4px 16px 4px;
+ padding: 8px 8px 16px;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
diff --git a/erpnext/home/page/my_company/my_company.js b/erpnext/home/page/my_company/my_company.js
index 775c89e..8217cc7 100644
--- a/erpnext/home/page/my_company/my_company.js
+++ b/erpnext/home/page/my_company/my_company.js
@@ -758,253 +758,3 @@
-// ========================== Role object =====================================
-
-pscript.all_roles = null;
-
-RoleObj = function(profile_id){
- this.roles_dict = {};
- this.profile_id = profile_id;
- this.setup_done = 0;
-
- var d = new Dialog(500,500,'Assign Roles');
- d.make_body([
- ['HTML','roles']
- ]);
-
- this.dialog = d;
- this.make_role_body(profile_id);
- this.make_help_body();
-
- this.body.innerHTML = '<span style="color:#888">Loading...</span> <img src="lib/images/ui/button-load.gif">'
- var me=this;
-
- d.onshow = function() {
- if(!me.setup_done)
- me.get_all_roles(me.profile_id);
- }
-}
-
-// make role body
-RoleObj.prototype.make_role_body = function(id){
- var me = this;
- var d = this.dialog;
- this.role_div = $a(d.widgets['roles'],'div');
-
- this.head = $a(this.role_div,'div','',{marginLeft:'4px', marginBottom:'4px',fontWeight:'bold'});
- this.body = $a(this.role_div,'div');
- this.footer = $a(this.role_div,'div');
-
- this.update_btn = $btn(this.footer,'Update',function() { me.update_roles(me.profile_id); },{marginRight:'4px'},'',1);
-}
-
-// make help body
-RoleObj.prototype.make_help_body = function(){
- var me = this;
-
- var d = this.dialog;
- this.help_div = $a(d.widgets['roles'],'div');
-
- var head = $a(this.help_div,'div'); this.help_div.head = head;
- var body = $a(this.help_div,'div'); this.help_div.body = body;
- var tail = $a(this.help_div,'div'); this.help_div.tail = tail;
-
- var back_btn = $btn(tail,'Back', function() {
- // back to assign roles
- $(me.role_div).slideToggle('medium');
- $(me.help_div).slideToggle('medium');
- });
- this.help_div.back_btn = back_btn;
- $dh(this.help_div);
-}
-
-// get all roles
-RoleObj.prototype.get_all_roles = function(id){
- if(pscript.all_roles) {
- this.make_roles(id);
- return;
- }
-
- var me = this;
- var callback = function(r,rt){
- pscript.all_roles = r.message;
- me.make_roles(id);
- }
- $c_obj('Company Control','get_all_roles','',callback);
-}
-
-// make roles
-RoleObj.prototype.make_roles = function(id){
- var me = this;
- var list = pscript.all_roles;
- me.setup_done = 1;
- me.body.innerHTML = '';
-
- var tbl = make_table( me.body, cint(list.length / 2) + 1,4,'100%',['5%','45%','5%','45%'],{padding:'4px'});
- var in_right = 0; var ridx = 0;
-
- for(i=0;i<list.length;i++){
- var cidx = in_right * 2;
-
- me.make_checkbox(tbl, ridx, cidx, list[i]);
- me.make_label(tbl, ridx, cidx + 1, list[i]);
-
- // change column
- if(in_right) {in_right = 0; ridx++ } else in_right = 1;
- }
- me.get_user_roles(id);
-}
-
-// make checkbox
-RoleObj.prototype.make_checkbox = function(tbl,ridx,cidx, role){
- var me = this;
-
- var a = $a_input($a($td(tbl, ridx, cidx),'div'),'checkbox');
- a.role = role;
- me.roles_dict[role] = a;
-
- $y(a,{width:'20px'});
- $y($td(tbl, ridx, cidx),{textAlign:'right'});
-}
-
-
-// make label
-RoleObj.prototype.make_label = function(tbl, ridx, cidx, role){
- var me = this;
-
- var t = make_table($td(tbl, ridx, cidx),1,2,null,['16px', null],{marginRight:'5px'});
- var ic = $a($td(t,0,0), 'img','',{cursor:'pointer', marginRight:'5px'});
- ic.src= 'lib/images/icons/help.png';
- ic.role = role;
-
- ic.onclick = function(){
- me.get_permissions(this.role);
- }
- $td(t,0,1).innerHTML= role;
-
-}
-
-// get user roles
-RoleObj.prototype.get_user_roles = function(id){
- var me = this;
- me.head.innerHTML = 'Roles for ' + id;
-
- $ds(me.role_div);
- $dh(me.help_div);
-
- var callback = function(r,rt){
- me.set_user_roles(r.message);
- }
- $c_obj('Company Control','get_user_roles', id,callback);
-}
-
-
-// set user roles
-RoleObj.prototype.set_user_roles = function(list){
- var me = this;
- for(d in me.roles_dict){
- me.roles_dict[d].checked = 0;
- }
- for(l=0; l<list.length; l++){
- me.roles_dict[list[l]].checked = 1;
- }
-}
-
-
-// update roles
-RoleObj.prototype.update_roles = function(id){
- var me = this;
-
-
- if(id == user && has_common(['System Manager'], user_roles) && !me.roles_dict['System Manager'].checked){
- var callback = function(r,rt){
- if(r.message){
- if(r.message > 1){
- var c = confirm("You have unchecked the System Manager role.\nYou will lose administrative rights and will not be able to set roles.\n\nDo you want to continue anyway?");
- if(!c) return;
- }
- else{
- var c = "There should be atleast one user with System Manager role.";
- me.roles_dict['System Manager'].checked = 1;
- }
- }
- me.set_roles(id);
- }
- $c_obj('Company Control','get_sm_count','',callback);
- }
- else{
- me.set_roles(id);
- }
-}
-
-// set roles
-RoleObj.prototype.set_roles = function(id){
-
- var me = this;
- var role_list = [];
-
- for(d in me.roles_dict){
- if(me.roles_dict[d].checked){
- role_list.push(d);
- }
- }
-
- var callback = function(r,rt){
- me.update_btn.done_working();
- me.dialog.hide();
- }
- var arg = {'usr':id, 'role_list':role_list};
- me.update_btn.set_working();
- $c_obj('Company Control','update_roles',docstring(arg), callback);
-
-}
-
-// get permission
-RoleObj.prototype.get_permissions = function(role){
- var me = this;
-
- var callback = function(r,rt){
- $(me.help_div).slideToggle('medium');
- $(me.role_div).slideToggle('medium');
- me.set_permissions(r.message, role);
- }
- $c_obj('Company Control','get_permission',role,callback);
-}
-
-
-// set permission
-RoleObj.prototype.set_permissions = function(perm, role){
- var me = this;
- me.help_div.body.innerHTML ='';
-
- if(perm){
- me.help_div.head.innerHTML = 'Permissions for ' + role + ':<br><br>';
-
- perm_tbl = make_table(me.help_div.body,cint(perm.length)+2,7,'100%',['30%','10%','10%','10%','10%','10%','10%'],{padding:'4px'});
-
- var head_lst = ['Document','Read','Write','Create','Submit','Cancel','Amend'];
-
- for(var i=0; i<(head_lst.length-1);i++){
- $td(perm_tbl,0,i).innerHTML= "<b>"+head_lst[i]+"</b>";
- }
- var accept_img1 = 'lib/images/icons/accept.gif';
- var cancel_img1 = 'lib/images/icons/cancel.gif';
-
- for(i=1; i<perm.length+1; i++){
- $td(perm_tbl,i,0).innerHTML= get_doctype_label(perm[i-1][0]);
-
- for(var j=1;j<(head_lst.length-1);j++){
-
- if(perm[i-1][j]){
- var accept_img = $a($td(perm_tbl,i,j), 'img'); accept_img.src= accept_img1;
- }
- else {
- var cancel_img = $a($td(perm_tbl,i,j), 'img'); cancel_img.src= cancel_img1;
- }
- $y($td(perm_tbl,i,j),{textAlign:'center'});
- }
- }
- }
- else
- me.help_div.head.innerHTML = 'No Permission set for ' + role + '.<br><br>';
-}
diff --git a/erpnext/support/doctype/customer_issue/customer_issue.py b/erpnext/support/doctype/customer_issue/customer_issue.py
index b00a6a0..af839cf 100644
--- a/erpnext/support/doctype/customer_issue/customer_issue.py
+++ b/erpnext/support/doctype/customer_issue/customer_issue.py
@@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Please edit this list and import only required elements
+
import webnotes
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
diff --git a/erpnext/utilities/page/messages/messages.js b/erpnext/utilities/page/messages/messages.js
index 39f7974..43adce4 100644
--- a/erpnext/utilities/page/messages/messages.js
+++ b/erpnext/utilities/page/messages/messages.js
@@ -1,3 +1,19 @@
+// ERPNext - web based ERP (http://erpnext.com)
+// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
wn.provide('erpnext.messages');
wn.pages.messages.onload = function(wrapper) {
diff --git a/erpnext/utilities/page/messages/messages.py b/erpnext/utilities/page/messages/messages.py
index d7c6026..8e92ff9 100644
--- a/erpnext/utilities/page/messages/messages.py
+++ b/erpnext/utilities/page/messages/messages.py
@@ -1,3 +1,19 @@
+# ERPNext - web based ERP (http://erpnext.com)
+# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
import webnotes
@webnotes.whitelist()
diff --git a/erpnext/utilities/page/todo/todo.js b/erpnext/utilities/page/todo/todo.js
index 77e4625..4350023 100644
--- a/erpnext/utilities/page/todo/todo.js
+++ b/erpnext/utilities/page/todo/todo.js
@@ -1,3 +1,19 @@
+// ERPNext - web based ERP (http://erpnext.com)
+// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
wn.provide('erpnext.todo');
erpnext.todo.refresh = function() {
diff --git a/erpnext/utilities/page/todo/todo.py b/erpnext/utilities/page/todo/todo.py
index c10809e..05d55fe 100644
--- a/erpnext/utilities/page/todo/todo.py
+++ b/erpnext/utilities/page/todo/todo.py
@@ -1,3 +1,19 @@
+# ERPNext - web based ERP (http://erpnext.com)
+# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
import webnotes
from webnotes.model.doc import Document
diff --git a/erpnext/utilities/page/users/__init__.py b/erpnext/utilities/page/users/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/utilities/page/users/__init__.py
diff --git a/erpnext/utilities/page/users/users.css b/erpnext/utilities/page/users/users.css
new file mode 100644
index 0000000..1a85d15
--- /dev/null
+++ b/erpnext/utilities/page/users/users.css
@@ -0,0 +1,35 @@
+.user-card {
+ border-radius: 5px;
+ width: 200px;
+ margin: 11px;
+ padding: 11px;
+ background-color: #FFEDBD;
+ box-shadow: 3px 3px 5px #888;
+ float: left;
+ overflow: hidden;
+}
+
+.user-card.disabled {
+ background-color: #eee;
+}
+
+.user-card img {
+ height: 60px;
+}
+
+.user-role {
+ padding: 5px;
+ width: 45%;
+ float: left;
+}
+
+table.user-perm {
+ border-collapse: collapse;
+}
+
+table.user-perm td, table.user-perm th {
+ padding: 5px;
+ text-align: center;
+ border-bottom: 1px solid #aaa;
+ min-width: 30px;
+}
\ No newline at end of file
diff --git a/erpnext/utilities/page/users/users.html b/erpnext/utilities/page/users/users.html
new file mode 100644
index 0000000..fe2f000
--- /dev/null
+++ b/erpnext/utilities/page/users/users.html
@@ -0,0 +1,13 @@
+<div class="layout-wrapper">
+ <a class="close" onclick="window.history.back();">×</a>
+ <h1>Users</h1>
+ <hr>
+ <div class="help" style="margin-bottom: 20px">Add, disable, delete users and change their roles, passwords and security settings</div>
+ <div style="margin: 11px">
+ <button class="btn btn-small add-user" onclick="wn.pages.users.add_user()"
+ ><i class="icon-plus"></i> Add User</button>
+ </div>
+ <div class="users-area">
+ </div>
+ <div style="clear: both"></div>
+</div>
\ No newline at end of file
diff --git a/erpnext/utilities/page/users/users.js b/erpnext/utilities/page/users/users.js
new file mode 100644
index 0000000..21519b8
--- /dev/null
+++ b/erpnext/utilities/page/users/users.js
@@ -0,0 +1,377 @@
+// ERPNext - web based ERP (http://erpnext.com)
+// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+$.extend(wn.pages.users, {
+ onload: function(wrapper) {
+ wn.pages.users.profiles = {};
+ wn.pages.users.refresh();
+ wn.pages.users.setup();
+ wn.pages.users.role_editor = new erpnext.RoleEditor();
+ },
+ setup: function() {
+ // set roles
+ $('.users-area').on('click', '.btn.user-roles', function() {
+ var uid = $(this).parent().parent().attr('data-name');
+ wn.pages.users.role_editor.show(uid);
+ });
+
+ // settings
+ $('.users-area').on('click', '.btn.user-settings', function() {
+ var uid = $(this).parent().parent().attr('data-name');
+ wn.pages.users.show_settings(uid);
+ });
+
+ // delete
+ $('.users-area').on('click', 'a.close', function() {
+ $card = $(this).parent();
+ var uid = $card.attr('data-name');
+ $card.css('opacity', 0.6);
+ wn.call({
+ method: 'utilities.page.users.users.delete',
+ args: {'uid': uid},
+ callback: function(r,rt) {
+ if(!r.exc)
+ $card.fadeOut()
+ }
+ });
+ })
+
+ },
+ refresh: function() {
+ // make the list
+ wn.call({
+ method:'utilities.page.users.users.get',
+ callback: function(r, rt) {
+ $('.users-area').empty();
+ for(var i in r.message) {
+ var p = r.message[i];
+ wn.pages.users.profiles[p.name] = p;
+ wn.pages.users.render(p);
+ }
+ }
+ });
+ },
+ render: function(data) {
+ if(data.file_list) {
+ data.imgsrc = 'files/' + data.files_list.split('\n')[0].split(',')[1];
+ } else {
+ data.imgsrc = 'lib/images/ui/no_img_' + (data.gender=='Female' ? 'f' : 'm');
+ }
+ data.fullname = wn.boot.user_fullnames[data.name];
+ data.delete_html = '';
+ if(!data.enabled)
+ data.delete_html = '<a class="close" title="delete">×</a>';
+
+ $('.users-area').append(repl('<div class="user-card" data-name="%(name)s">\
+ %(delete_html)s\
+ <img src="%(imgsrc)s">\
+ <div class="user-info">\
+ <b class="user-fullname">%(fullname)s</b><br>\
+ %(name)s<br>\
+ <button class="btn btn-small user-roles"><i class="icon-user"></i> Roles</button>\
+ <button class="btn btn-small user-settings"><i class="icon-cog"></i> Settings</button>\
+ </div>\
+ </div>', data));
+
+ if(!data.enabled) {
+ $('.users-area .user-card:last')
+ .addClass('disabled')
+ .find('.user-fullname').html('Disabled');
+ }
+ },
+ show_settings: function(uid) {
+ var me = wn.pages.users;
+ if(!me.settings_dialog)
+ me.make_settings_dialog();
+
+ var p = me.profiles[uid];
+ me.uid = uid;
+
+ me.settings_dialog.set_values({
+ restrict_ip: p.restrict_ip || '',
+ login_before: p.login_before || '',
+ login_after: p.login_after || '',
+ enabled: p.enabled || 0,
+ new_password: ''
+ });
+
+ me.settings_dialog.show();
+
+ },
+ make_settings_dialog: function() {
+ var me = wn.pages.users;
+ me.settings_dialog = new wn.widgets.Dialog({
+ title: 'Set User Security',
+ width: 500,
+ fields: [
+ {
+ label:'Enabled',
+ description: 'Uncheck to disable',
+ fieldtype: 'Check', fieldname: 'enabled'
+ },
+ {
+ label:'IP Address',
+ description: 'Restrict user login by IP address, partial ips (111.111.111), \
+ multiple addresses (separated by commas) allowed',
+ fieldname:'restrict_ip', fieldtype:'Data'
+ },
+ {
+ label:'Login After',
+ description: 'User can only login after this hour (0-24)',
+ fieldtype: 'Int', fieldname: 'login_after'
+ },
+ {
+ label:'Login Before',
+ description: 'User can only login before this hour (0-24)',
+ fieldtype: 'Int', fieldname: 'login_before'
+ },
+ {
+ label:'New Password',
+ description: 'Update the current user password',
+ fieldtype: 'Data', fieldname: 'new_password'
+ },
+ {
+ label:'Update', fieldtype:'Button', fieldname:'update'
+ }
+ ]
+ });
+
+ this.settings_dialog.fields_dict.update.input.onclick = function() {
+ var btn = this;
+ this.set_working();
+ var args = me.settings_dialog.get_values();
+ args.user = me.uid;
+
+ if (args.new_password) {
+ me.get_password(btn, args);
+ } else {
+ btn.set_working();
+ me.update_security(args);
+ }
+ };
+
+ },
+ update_security: function(args) {
+ var me = wn.pages.users;
+ $c_page('utilities', 'users', 'update_security', JSON.stringify(args), function(r,rt) {
+ if(r.exc) {
+ msgprint(r.exc);
+ return;
+ }
+ me.settings_dialog.hide();
+ $.extend(me.profiles[me.uid], me.settings_dialog.get_values());
+ me.refresh();
+ });
+ },
+ get_password: function(btn, args) {
+ var me = wn.pages.users;
+ var pass_d = new wn.widgets.Dialog({
+ title: 'Your Password',
+ width: 300,
+ fields: [
+ {
+ label: 'Please Enter <b style="color: black">Your Password</b>',
+ description: "Your password is required to update the user's password",
+ fieldtype: 'Password', fieldname: 'sys_admin_pwd', reqd: 1
+ },
+ {
+ label: 'Continue', fieldtype: 'Button', fieldname: 'continue'
+ }
+ ]
+ });
+
+ pass_d.fields_dict.continue.input.onclick = function() {
+ btn.pwd_dialog.hide();
+ args.sys_admin_pwd = btn.pwd_dialog.get_values().sys_admin_pwd;
+ btn.set_working();
+ me.update_security(args);
+ btn.done_working();
+ }
+
+ pass_d.show();
+ btn.pwd_dialog = pass_d;
+ btn.done_working();
+ },
+ add_user: function() {
+ var me = wn.pages.users;
+ var d = new wn.widgets.Dialog({
+ title: 'Add User',
+ width: 400,
+ fields: [{
+ fieldtype: 'Data', fieldname: 'user', reqd: 1,
+ label: 'Email Id of the user to add'
+ }, {
+ fieldtype: 'Data', fieldname: 'first_name', reqd: 1, label: 'First Name'
+ }, {
+ fieldtype: 'Data', fieldname: 'last_name', label: 'Last Name'
+ }, {
+ fieldtype: 'Data', fieldname: 'password', reqd: 1, label: 'Password'
+ }, {
+ fieldtype: 'Button', label: 'Add', fieldname: 'add'
+ }]
+ });
+
+ d.make();
+ d.fields_dict.add.input.onclick = function() {
+ v = d.get_values();
+ if(v) {
+ d.fields_dict.add.input.set_working();
+ $c_page('utilities', 'users', 'add_user', v, function(r,rt) {
+ if(r.exc) { msgprint(r.exc); return; }
+ else {
+ d.hide();
+ me.refresh();
+ }
+ })
+ }
+ }
+ d.show();
+ }
+});
+
+erpnext.RoleEditor = Class.extend({
+ init: function() {
+ this.dialog = new wn.widgets.Dialog({
+ title: 'Set Roles'
+ });
+ var me = this;
+ $(this.dialog.body).html('<div class="help">Loading...</div>')
+ wn.call({
+ method:'utilities.page.users.users.get_roles',
+ callback: function(r) {
+ me.roles = r.message;
+ me.show_roles();
+ }
+ });
+ },
+ show_roles: function() {
+ var me = this;
+ $(this.dialog.body).empty();
+ for(var i in this.roles) {
+ $(this.dialog.body).append(repl('<div class="user-role" \
+ data-user-role="%(role)s">\
+ <input type="checkbox"> \
+ <a href="#"><i class="icon-question-sign"></i></a> %(role)s\
+ </div>', {role: this.roles[i]}));
+ }
+ $(this.dialog.body).append('<div style="clear: both">\
+ <button class="btn btn-small btn-primary">Save</button></div>');
+ $(this.dialog.body).find('button.btn-primary').click(function() {
+ me.save();
+ });
+ $(this.dialog.body).find('.user-role a').click(function() {
+ me.show_permissions($(this).parent().attr('data-user-role'))
+ return false;
+ })
+ },
+ show: function(uid) {
+ var me = this;
+ this.uid = uid;
+ this.dialog.show();
+ // set user roles
+ wn.call({
+ method:'utilities.page.users.users.get_user_roles',
+ args: {uid:uid},
+ callback: function(r, rt) {
+ $(me.dialog.body).find('input[type="checkbox"]').attr('checked', false);
+ for(var i in r.message) {
+ $(me.dialog.body)
+ .find('[data-user-role="'+r.message[i]
+ +'"] input[type="checkbox"]').attr('checked',true);
+ }
+ }
+ })
+ },
+ save: function() {
+ var set_roles = [];
+ var unset_roles = [];
+ $(this.dialog.body).find('[data-user-role]').each(function() {
+ var $check = $(this).find('input[type="checkbox"]');
+ if($check.attr('checked')) {
+ set_roles.push($(this).attr('data-user-role'));
+ } else {
+ unset_roles.push($(this).attr('data-user-role'));
+ }
+ })
+ wn.call({
+ method:'utilities.page.users.users.update_roles',
+ args: {
+ set_roles: JSON.stringify(set_roles),
+ unset_roles: JSON.stringify(unset_roles),
+ uid: this.uid
+ },
+ btn: $(this.dialog.body).find('.btn-primary').get(0),
+ callback: function() {
+
+ }
+ })
+ },
+ show_permissions: function(role) {
+ // show permissions for a role
+ var me = this;
+ if(!this.perm_dialog)
+ this.make_perm_dialog()
+ $(this.perm_dialog.body).empty();
+ wn.call({
+ method:'utilities.page.users.users.get_perm_info',
+ args: {role: role},
+ callback: function(r) {
+ var $body = $(me.perm_dialog.body);
+ $body.append('<table class="user-perm"><tbody><tr>\
+ <th style="text-align: left">Document Type</th>\
+ <th>Level</th>\
+ <th>Read</th>\
+ <th>Write</th>\
+ <th>Submit</th>\
+ <th>Cancel</th>\
+ <th>Amend</th></tr></tbody></table>');
+ for(var i in r.message) {
+ var perm = r.message[i];
+
+ // if permission -> icon
+ for(key in perm) {
+ if(key!='parent' && key!='permlevel') {
+ if(perm[key]) {
+ perm[key] = '<i class="icon-ok"></i>';
+ } else {
+ perm[key] = '';
+ }
+ }
+ }
+
+ $body.find('tbody').append(repl('<tr>\
+ <td style="text-align: left">%(parent)s</td>\
+ <td>%(permlevel)s</td>\
+ <td>%(read)s</td>\
+ <td>%(write)s</td>\
+ <td>%(submit)s</td>\
+ <td>%(cancel)s</td>\
+ <td>%(amend)s</td>\
+ </tr>', perm))
+ }
+
+ me.perm_dialog.show();
+ }
+ });
+
+ },
+ make_perm_dialog: function() {
+ this.perm_dialog = new wn.widgets.Dialog({
+ title:'Role Permissions',
+ width: 500
+ });
+ }
+})
diff --git a/erpnext/utilities/page/users/users.py b/erpnext/utilities/page/users/users.py
new file mode 100644
index 0000000..44e2fb2
--- /dev/null
+++ b/erpnext/utilities/page/users/users.py
@@ -0,0 +1,192 @@
+# ERPNext - web based ERP (http://erpnext.com)
+# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import webnotes
+import json
+
+from webnotes.model.doc import Document
+from webnotes.utils import cint
+
+@webnotes.whitelist()
+def get(arg=None):
+ """return all users"""
+ return webnotes.conn.sql("""select name, file_list, enabled, gender,
+ restrict_ip, login_before, login_after from tabProfile
+ where docstatus<2 and name not in ('Administrator', 'Guest') order by
+ ifnull(enabled,0) desc, name""", as_dict=1)
+
+@webnotes.whitelist()
+def get_roles(arg=None):
+ """return all roles"""
+ return [r[0] for r in webnotes.conn.sql("""select name from tabRole
+ where name not in ('Administrator', 'Guest', 'All') order by name""")]
+
+@webnotes.whitelist()
+def get_user_roles(arg=None):
+ """get roles for a user"""
+ return [r[0] for r in webnotes.conn.sql("""select role from tabUserRole
+ where parent=%s""", webnotes.form_dict['uid'])]
+
+@webnotes.whitelist()
+def get_perm_info(arg=None):
+ """get permission info"""
+ return webnotes.conn.sql("""select parent, permlevel, `read`, `write`, submit,
+ cancel, amend from tabDocPerm where role=%s
+ and docstatus<2 order by parent, permlevel""",
+ webnotes.form_dict['role'], as_dict=1)
+
+@webnotes.whitelist()
+def update_roles(arg=None):
+ """update set and unset roles"""
+ # remove roles
+ unset = json.loads(webnotes.form_dict['unset_roles'])
+ webnotes.conn.sql("""delete from tabUserRole where parent='%s'
+ and role in ('%s')""" % (webnotes.form_dict['uid'], "','".join(unset)))
+
+ # check for 1 system manager
+ if not webnotes.conn.sql("""select parent from tabUserRole where role='System Manager'
+ and docstatus<2"""):
+ webnotes.msgprint("Sorry there must be atleast one 'System Manager'")
+ raise webnotes.ValidationError
+
+ # add roles
+ roles = get_user_roles()
+ toset = json.loads(webnotes.form_dict['set_roles'])
+ for role in toset:
+ if not role in roles:
+ d = Document('UserRole')
+ d.role = role
+ d.parent = webnotes.form_dict['uid']
+ d.save()
+
+ webnotes.msgprint('Roles Updated')
+
+@webnotes.whitelist()
+def update_security(args=''):
+ args = json.loads(args)
+ webnotes.conn.set_value('Profile', args['user'], 'restrict_ip', args.get('restrict_ip'))
+ webnotes.conn.set_value('Profile', args['user'], 'login_after', args.get('login_after'))
+ webnotes.conn.set_value('Profile', args['user'], 'login_before', args.get('login_before'))
+ webnotes.conn.set_value('Profile', args['user'], 'enabled', int(args.get('enabled',0)) or 0)
+
+ if 'new_password' in args:
+ if cint(webnotes.conn.get_value('Control Panel',None,'sync_with_gateway')):
+ import server_tools.gateway_utils
+ res = server_tools.gateway_utils.change_password('', args['new_password'],
+ args['user'], args['sys_admin_pwd'])
+ if 'Traceback' not in res['message']:
+ webnotes.msgprint(res['message'])
+ webnotes.conn.sql("update tabProfile set password=password(%s) where name=%s",
+ (args['new_password'], args['user']))
+ else:
+ webnotes.msgprint('Settings Updated')
+
+
+
+#
+# user addition
+#
+
+@webnotes.whitelist()
+def add_user(args):
+ args = json.loads(args)
+ # erpnext-saas
+ if cint(webnotes.conn.get_value('Control Panel', None, 'sync_with_gateway')):
+ from server_tools.gateway_utils import add_user_gateway
+ add_user_gateway(args['user'])
+
+ add_profile(args)
+
+@webnotes.whitelist()
+def add_profile(args):
+ from webnotes.utils import validate_email_add, now
+ email = args['user']
+
+ sql = webnotes.conn.sql
+
+ if not email:
+ email = webnotes.form_dict.get('user')
+ if not validate_email_add(email):
+ raise Exception
+ return 'Invalid Email Id'
+
+ if sql("select name from tabProfile where name = %s", email):
+ # exists, enable it
+ sql("update tabProfile set enabled = 1, docstatus=0 where name = %s", email)
+ webnotes.msgprint('Profile exists, enabled it with new password')
+ else:
+ # does not exist, create it!
+ pr = Document('Profile')
+ pr.name = email
+ pr.email = email
+ pr.first_name = args.get('first_name')
+ pr.last_name = args.get('last_name')
+ pr.enabled = 1
+ pr.user_type = 'System User'
+ pr.save(1)
+
+ if args.get('password'):
+ sql("""
+ UPDATE tabProfile
+ SET password = PASSWORD(%s), modified = %s
+ WHERE name = %s""", (args.get('password'), now, email))
+
+ send_welcome_mail(email, args)
+
+@webnotes.whitelist()
+def send_welcome_mail(email, args):
+ """send welcome mail to user with password and login url"""
+ pr = Document('Profile', email)
+ from webnotes.utils.email_lib import sendmail_md
+ args.update({
+ 'company': webnotes.conn.get_default('company'),
+ 'password': args.get('password'),
+ 'account_url': webnotes.conn.get_default('account_url')
+ })
+ if not args.get('last_name'): args['last_name'] = ''
+ sendmail_md(pr.email, subject="Welcome to ERPNext", msg=welcome_txt % args, from_defs=1)
+
+#
+# delete user
+#
+@webnotes.whitelist()
+def delete(arg=None):
+ """delete user"""
+ webnotes.conn.sql("update tabProfile set enabled=0, docstatus=2 where name=%s",
+ webnotes.form_dict['uid'])
+ # erpnext-saas
+ if int(webnotes.conn.get_value('Control Panel', None, 'sync_with_gateway')):
+ from server_tools.gateway_utils import remove_user_gateway
+ remove_user_gateway(webnotes.form_dict['uid'])
+
+ webnotes.login_manager.logout(user=webnotes.form_dict['uid'])
+
+welcome_txt = """
+## %(company)s
+
+Dear %(first_name)s %(last_name)s
+
+Welcome!
+
+A new account has been created for you, here are your details:
+
+login-id: %(user)s
+password: %(password)s
+
+To login to your new ERPNext account, please go to:
+
+%(account_url)s
+"""
\ No newline at end of file
diff --git a/erpnext/utilities/page/users/users.txt b/erpnext/utilities/page/users/users.txt
new file mode 100644
index 0000000..165cc16
--- /dev/null
+++ b/erpnext/utilities/page/users/users.txt
@@ -0,0 +1,28 @@
+# Page, users
+[
+
+ # These values are common in all dictionaries
+ {
+ 'creation': '2012-02-28 10:29:39',
+ 'docstatus': 0,
+ 'modified': '2012-02-28 10:29:39',
+ 'modified_by': u'Administrator',
+ 'owner': u'Administrator'
+ },
+
+ # These values are common for all Page
+ {
+ 'doctype': 'Page',
+ 'module': u'Utilities',
+ 'name': '__common__',
+ 'page_name': u'users',
+ 'standard': u'Yes',
+ 'title': u'Users'
+ },
+
+ # Page, users
+ {
+ 'doctype': 'Page',
+ 'name': u'users'
+ }
+]
\ No newline at end of file
diff --git a/version.num b/version.num
index 8c28da6..5cd7ca2 100644
--- a/version.num
+++ b/version.num
@@ -1 +1 @@
-747
\ No newline at end of file
+748
\ No newline at end of file