@@ -244,30 +244,24 @@ def validate_permissions(permissions, for_remove=False): | |||
webnotes.msgprint(get_txt(d) + " Higher level permissions are meaningless if level 0 permission is not set.", | |||
raise_exception=True) | |||
if d.create: | |||
webnotes.msgprint("Create Permission has no meaning at level " + d.permlevel, | |||
raise_exception=True) | |||
if d.submit: | |||
webnotes.msgprint("Submit Permission has no meaning at level " + d.permlevel, | |||
raise_exception=True) | |||
if d.cancel: | |||
webnotes.msgprint("Cancel Permission has no meaning at level " + d.permlevel, | |||
raise_exception=True) | |||
if d.amend: | |||
webnotes.msgprint("Amend Permission has no meaning at level " + d.permlevel, | |||
raise_exception=True) | |||
if d.match: | |||
webnotes.msgprint("Match rules have no meaning at level " + d.permlevel, | |||
if d.create or d.submit or d.cancel or d.amend or d.match: | |||
webnotes.msgprint("Create, Submit, Cancel, Amend, Match has no meaning at level " + d.permlevel, | |||
raise_exception=True) | |||
def check_permission_dependency(d): | |||
if d.write and not d.read: | |||
webnotes.msgprint(get_txt(d) + " Cannot set Write permission if Read is not set.", | |||
raise_exception=True) | |||
if (d.submit or d.cancel or d.amend) and not d.write: | |||
webnotes.msgprint(get_txt(d) + " Cannot set Submit, Cancel, Amend permission if Write is not set.", | |||
raise_exception=True) | |||
for d in permissions: | |||
if not d.permlevel: d.permlevel=0 | |||
if not d.permlevel: | |||
d.permlevel=0 | |||
check_atleast_one_set(d) | |||
if not for_remove: | |||
check_double(d) | |||
check_level_zero_is_set(d) | |||
check_permission_dependency(d) | |||
@@ -22,18 +22,22 @@ cur_frm.cscript.refresh = function(doc) { | |||
// update display settings | |||
wn.ui.set_theme(doc.theme); | |||
if(doc.background_image) { | |||
wn.ui.set_user_background(doc.background_image); | |||
wn.ui.set_user_background(doc.background_image); | |||
} | |||
if(doc.user_image) { | |||
wn.boot.user_info[user].image = wn.utils.get_file_link(doc.user_image); | |||
} | |||
} | |||
} | |||
cur_frm.add_custom_button("Set Properties", function() { | |||
wn.set_route("user-properties", doc.name); | |||
}) | |||
} | |||
cur_frm.cscript.enabled = function(doc) { | |||
if(!doc.__islocal) { | |||
cur_frm.toggle_display(['sb1', 'sb2', 'sb3'], doc.enabled); | |||
cur_frm.toggle_display(['sb1', 'sb2'], doc.enabled); | |||
cur_frm.toggle_enable('*', doc.enabled); | |||
cur_frm.set_df_property('enabled', 'disabled', false); | |||
} | |||
@@ -4,7 +4,7 @@ | |||
"docstatus": 0, | |||
"creation": "2012-12-07 15:15:20", | |||
"modified_by": "Administrator", | |||
"modified": "2012-12-21 12:35:01" | |||
"modified": "2013-01-02 14:47:27" | |||
}, | |||
{ | |||
"istable": 0, | |||
@@ -111,6 +111,7 @@ | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"print_width": "50%", | |||
"oldfieldtype": "Column Break", | |||
"doctype": "DocField", | |||
"width": "50%", | |||
@@ -297,12 +298,14 @@ | |||
}, | |||
{ | |||
"description": "These values will be automatically updated in transactions and also will be useful to restrict permissions for this user on transactions containing these values.", | |||
"print_width": "50%", | |||
"oldfieldtype": "Column Break", | |||
"doctype": "DocField", | |||
"label": "Defaults", | |||
"width": "50%", | |||
"fieldname": "sb2", | |||
"fieldtype": "Section Break", | |||
"hidden": 1, | |||
"permlevel": 1 | |||
}, | |||
{ | |||
@@ -312,6 +315,7 @@ | |||
"options": "DefaultValue", | |||
"fieldname": "defaults", | |||
"fieldtype": "Table", | |||
"hidden": 1, | |||
"permlevel": 0 | |||
}, | |||
{ | |||
@@ -347,6 +351,7 @@ | |||
"permlevel": 1 | |||
}, | |||
{ | |||
"print_width": "50%", | |||
"oldfieldtype": "Column Break", | |||
"doctype": "DocField", | |||
"width": "50%", | |||
@@ -409,13 +414,21 @@ | |||
"match": "owner" | |||
}, | |||
{ | |||
"amend": 0, | |||
"create": 0, | |||
"doctype": "DocPerm", | |||
"submit": 0, | |||
"role": "Administrator", | |||
"cancel": 0, | |||
"permlevel": 1 | |||
}, | |||
{ | |||
"amend": 0, | |||
"create": 0, | |||
"doctype": "DocPerm", | |||
"submit": 0, | |||
"role": "System Manager", | |||
"cancel": 0, | |||
"permlevel": 1 | |||
} | |||
] |
@@ -2,45 +2,41 @@ | |||
{ | |||
"owner": "Administrator", | |||
"docstatus": 0, | |||
"creation": "2012-07-03 13:30:34", | |||
"creation": "2012-07-13 16:53:46", | |||
"modified_by": "Administrator", | |||
"modified": "2012-07-13 12:25:07" | |||
"modified": "2013-01-02 12:46:21" | |||
}, | |||
{ | |||
"section_style": "Simple", | |||
"istable": 0, | |||
"istable": 1, | |||
"allow_print": 0, | |||
"module": "Core", | |||
"server_code_error": " ", | |||
"issingle": 0, | |||
"autoname": "UR.#####", | |||
"read_only": 0, | |||
"allow_email": 0, | |||
"hide_heading": 0, | |||
"autoname": "UR.#####", | |||
"issingle": 0, | |||
"name": "__common__", | |||
"colour": "White:FFF", | |||
"doctype": "DocType", | |||
"show_in_menu": 0, | |||
"version": 1, | |||
"hide_toolbar": 0, | |||
"allow_copy": 0 | |||
}, | |||
{ | |||
"parent": "UserRole", | |||
"permlevel": 0, | |||
"print_width": "200px", | |||
"oldfieldtype": "Link", | |||
"doctype": "DocField", | |||
"oldfieldname": "role", | |||
"reqd": 0, | |||
"name": "__common__", | |||
"doctype": "DocField", | |||
"label": "Role", | |||
"width": "200px", | |||
"parenttype": "DocType", | |||
"options": "Role", | |||
"fieldname": "role", | |||
"fieldtype": "Link", | |||
"search_index": 0, | |||
"hidden": 0, | |||
"options": "Role", | |||
"permlevel": 0, | |||
"parentfield": "fields" | |||
}, | |||
{ | |||
@@ -4,6 +4,69 @@ wn.pages['permission-manager'].onload = function(wrapper) { | |||
title: 'Permission Manager', | |||
single_column: true | |||
}); | |||
$(wrapper).find(".layout-main").html("<div class='perm-engine'></div>\ | |||
<table class='table table-bordered' style='background-color: #f9f9f9;'>\ | |||
<tr><td>\ | |||
<h4><i class='icon-question-sign'></i> Quick Help for Setting Permissions:</h4>\ | |||
<ol>\ | |||
<li>Permissions are set on Roles and Document Types (called DocTypes) by restricting \ | |||
read, write, create, submit, cancel and amend rights.</li>\ | |||
<li>Permissions translate to Users based on what Role they are assigned.</li>\ | |||
<li>To set user roles, just go to <a href='#List/Profile'>Setup > Users</a> \ | |||
and click on the user to assign roles.</li>\ | |||
<li>The system provides pre-defined roles, but you can <a href='#List/Role'>add new roles</a>\ | |||
to set finer permissions.</li>\ | |||
<li>Permissions are automatically translated to Standard Reports and Searches.</li>\ | |||
<li>As a best practice, do not assign the same set of permission rule to different Roles\ | |||
instead set multiple Roles to the User.</li>\ | |||
</ol>\ | |||
</tr></td>\ | |||
<tr><td>\ | |||
<h4><i class='icon-hand-right'></i> Meaning of Submit, Cancel, Amend:</h4>\ | |||
<ol>\ | |||
<li>Certain documents should not be changed once final, like an\ | |||
Invoice for example. The final state for such documents is called <b>Submitted</b>.\ | |||
You can restrict which roles can Submit.</li>\ | |||
<li><b>Cancel</b> allows you change Submitted documents by cancelling them and amending them.\ | |||
Cancel permissions also allows the user to delete a document (if it is not linked to any other document).</li>\ | |||
<li>When you <b>Amend</b> a document after cancel and save it, it will get a new number that is\ | |||
a version of the old number. For example if you cancel and amend 'INV004' it will become a new\ | |||
document 'INV004-1'. This helps you to keep track of each amendment.</li>\ | |||
</ol>\ | |||
</tr></td>\ | |||
<tr><td>\ | |||
<h4><i class='icon-user'></i> Restricting By User:</h4>\ | |||
<ol>\ | |||
<li>To restrict a User of a particular Role to documents that are only self-created,\ | |||
Click on button in the 'Condition' column and select the option 'User is the creator of the document'.</li>\ | |||
<li>To restrict a User of a particular Role to documents that are explicitly assigned to them,\ | |||
create a Custom Field of type Link (Profile) and then use the 'Condition' settings\ | |||
to map that field to the Permission rule.\ | |||
</ol>\ | |||
</tr></td>\ | |||
<tr><td>\ | |||
<h4><i class='icon-cog'></i> Advanced Settings:</h4>\ | |||
<p>To further restrict permissions based on certain values in a document, use the\ | |||
'Condition' settings. <br><br>For example: You want to restrict users to transactions marked\ | |||
with a certain property called 'Territory':</p>\ | |||
<ol>\ | |||
<li>Make sure that the transactions you want to restrict have a Link \ | |||
field 'territory' that maps to a 'Territory' master. If not, create a\ | |||
<a href='#List/Custom Field'>Custom Field</a> of type Link.</li>\ | |||
<li>In the Permission Manager, click on the button in the 'Condition' column\ | |||
for the Role you want to restrict.</li>\ | |||
<li>A new pop will open that will ask you to select further conditions. \ | |||
If the 'territory' Link Field exists, it will give you an option to select \ | |||
it.</li>\ | |||
<li>Go to Setup > <a href='#user-properties'>User Properties</a> to set \ | |||
'territory' for diffent Users.</li>\ | |||
</ol>\ | |||
<p>Once you have set this, the users will only be able access documents with that property</p>\ | |||
<hr>\ | |||
<p>If these instructions where not helpful, please add in your suggestions at\ | |||
<a href='https://github.com/webnotes/wnframework/issues'>GitHub Issues</a></p>\ | |||
</tr></td>\ | |||
</table>"); | |||
wrapper.permission_engine = new wn.PermissionEngine(wrapper); | |||
} | |||
wn.pages['permission-manager'].refresh = function(wrapper) { | |||
@@ -13,7 +76,7 @@ wn.pages['permission-manager'].refresh = function(wrapper) { | |||
wn.PermissionEngine = Class.extend({ | |||
init: function(wrapper) { | |||
this.wrapper = wrapper; | |||
this.body = $(this.wrapper).find(".layout-main"); | |||
this.body = $(this.wrapper).find(".perm-engine"); | |||
this.make(); | |||
this.refresh(); | |||
this.add_check_events(); | |||
@@ -68,7 +131,7 @@ wn.PermissionEngine = Class.extend({ | |||
callback: function() { me.refresh(); } | |||
}); | |||
})); | |||
}, 'icon-retweet'); | |||
}, 'icon-retweet').toggle(false); | |||
}, | |||
get_doctype: function() { | |||
var doctype = this.doctype_select.val(); | |||
@@ -112,7 +175,6 @@ wn.PermissionEngine = Class.extend({ | |||
this.show_permission_table(perm_list); | |||
} | |||
this.show_add_rule(); | |||
this.show_explain(); | |||
}, | |||
show_permission_table: function(perm_list) { | |||
var me = this; | |||
@@ -152,7 +214,8 @@ wn.PermissionEngine = Class.extend({ | |||
if(!d.permlevel) d.permlevel = 0; | |||
var row = $("<tr>").appendTo(me.table.find("tbody")); | |||
add_cell(row, d, "parent"); | |||
add_cell(row, d, "role"); | |||
me.set_show_users(add_cell(row, d, "role"), d.role); | |||
var cell = add_cell(row, d, "permlevel"); | |||
if(d.permlevel==0) { | |||
cell.css("font-weight", "bold"); | |||
@@ -170,6 +233,30 @@ wn.PermissionEngine = Class.extend({ | |||
me.add_delete_button(row, d); | |||
}); | |||
}, | |||
set_show_users: function(cell, role) { | |||
cell.html("<a href='#'>"+role+"</a>") | |||
.find("a") | |||
.attr("data-role", role) | |||
.click(function() { | |||
var role = $(this).attr("data-role"); | |||
wn.call({ | |||
module: "core", | |||
page: "permission_manager", | |||
method: "get_users_with_role", | |||
args: { | |||
role: role | |||
}, | |||
callback: function(r) { | |||
r.message = $.map(r.message, function(p) { | |||
return '<a href="#Form/Profile/'+p+'">'+p+'</a>'; | |||
}) | |||
msgprint("<h4>Users with role "+role+":</h4>" | |||
+ r.message.join("<br>")); | |||
} | |||
}) | |||
return false; | |||
}) | |||
}, | |||
add_match_button: function(row, d) { | |||
var me = this; | |||
if(d.permlevel > 0) { | |||
@@ -231,7 +318,6 @@ wn.PermissionEngine = Class.extend({ | |||
chk.attr("checked", chk.is(":checked") ? null : "checked"); | |||
} else { | |||
me.get_perm(args.name)[args.ptype]=args.value; | |||
me.show_explain(); | |||
} | |||
} | |||
}) | |||
@@ -367,79 +453,5 @@ wn.PermissionEngine = Class.extend({ | |||
get_link_fields: function(doctype) { | |||
return link_fields = wn.model.get("DocField", {parent:doctype, | |||
fieldtype:"Link", options:["not in", ["Profile", '[Select]']]}); | |||
}, | |||
show_explain: function() { | |||
$(".perm-explain").remove(); | |||
if(!this.get_doctype()) return; | |||
var wrapper = $("<div class='perm-explain well'></div>").appendTo(this.body); | |||
var doctype = null; | |||
var core_finished = false; | |||
$.each(this.perm_list, function(i, p) { | |||
if(p.parent != doctype) { | |||
core_finished = false; | |||
doctype = p.parent; | |||
$('<h3>For ' + doctype + '</h3><h4>Document Permissions</h4>') | |||
.appendTo(wrapper); | |||
} | |||
if(p.permlevel==0) { | |||
var perms = $.map(["read", "write", "create", "submit", "cancel", "amend"], function(type) { | |||
if(p[type]) return type; | |||
}).join(", "); | |||
if(!p.match) { | |||
var _p = $('<p>').html("A user with role <b>"+p.role + "</b> can " | |||
+ perms + " a document of type <b>" + doctype + "</b>.") | |||
} else { | |||
if(p.match=="owner") { | |||
var _p = $('<p>').html("A user with role <b>"+p.role + "</b> can " | |||
+ perms + " <b>" + doctype + "</b> <u>only if</u> that document is created by that user."); | |||
} else if(p.match.indexOf(":")!=-1) { | |||
var field = p.match.split(":")[0]; | |||
var _p = $('<p>').html("A user with role <b>"+p.role + "</b> can " | |||
+ perms + " <b>" + doctype + "</b> <u>only if</u> <b>"+field+"</b> equals User's Id."); | |||
} else { | |||
var _p = $('<p>').html("A user with role <b>"+p.role + "</b> can " | |||
+ perms + " <b>" + doctype + "</b> <u>only for</u> records with user's <b>"+p.match+"</b> property."); | |||
} | |||
} | |||
} else { | |||
if(!core_finished) { | |||
core_finished = true; | |||
$("<br><h4>Field Level Permissions</h4>").appendTo(wrapper); | |||
} | |||
var perms = $.map(["read", "write"], function(type) { | |||
if(p[type]) return type; | |||
}).join(", "); | |||
var _p = $('<p>').html("A user with role <b>"+p.role + "</b> can only <u>" | |||
+ perms + "</u> fields at level <b>"+ p.permlevel +"</b> in a <b>" + doctype + "</b>.") | |||
} | |||
$("<a>Show Users</a>").appendTo(_p).attr("data-role", p.role) | |||
.css("margin-left", "7px") | |||
.click(function() { | |||
var link = $(this); | |||
wn.call({ | |||
module: "core", | |||
page: "permission_manager", | |||
method: "get_users_with_role", | |||
args: { | |||
role: link.attr("data-role"), | |||
}, | |||
callback: function(r) { | |||
$.each(r.message, function(i, uid) { | |||
msgprint("<a href='#Form/Profile/"+uid+"'>" | |||
+ wn.user_info(uid).fullname + "</a> ("+ | |||
uid+")"); | |||
}); | |||
cur_dialog.set_title("Users with role " | |||
+ link.attr("data-role")); | |||
} | |||
}); | |||
}); | |||
_p.appendTo(wrapper); | |||
}) | |||
} | |||
}) |
@@ -7,7 +7,7 @@ def get_roles_and_doctypes(): | |||
"doctypes": [d[0] for d in webnotes.conn.sql("""select name from tabDocType where | |||
ifnull(istable,0)=0 and | |||
ifnull(issingle,0)=0 and | |||
module != 'Core' """)], | |||
name not in ('DocType')""")], | |||
"roles": [d[0] for d in webnotes.conn.sql("""select name from tabRole where name not in | |||
('All', 'Guest', 'Administrator')""")] | |||
} | |||
@@ -4,6 +4,21 @@ wn.pages['user-properties'].onload = function(wrapper) { | |||
title: 'User Properties', | |||
single_column: true | |||
}); | |||
$(wrapper).find(".layout-main").html("<div class='user-settings'></div>\ | |||
<table class='table table-bordered' style='background-color: #f9f9f9;'>\ | |||
<tr><td>\ | |||
<h4><i class='icon-question-sign'></i> Quick Help for User Properties:</h4>\ | |||
<ol>\ | |||
<li>You can set various 'properties' to Users.</li>\ | |||
<li>These properties are Link Type fields from all Documents.</li>\ | |||
<li>These properties will appear as values in forms that contain them.</li>\ | |||
<li>These properties can also be used to 'assign' a particular document, \ | |||
whose property matches with the User's property to a User. These can be set\ | |||
using the <a href='#permission-manager'>Permission Manager</a></li>\ | |||
<li>A user can have multiple values for a property.</li>\ | |||
</ol>\ | |||
</tr></td>\ | |||
</table>"); | |||
wrapper.user_properties = new wn.UserProperties(wrapper); | |||
} | |||
@@ -14,7 +29,7 @@ wn.pages['user-properties'].refresh = function(wrapper) { | |||
wn.UserProperties = Class.extend({ | |||
init: function(wrapper) { | |||
this.wrapper = wrapper; | |||
this.body = $(this.wrapper).find(".layout-main"); | |||
this.body = $(this.wrapper).find(".user-settings"); | |||
this.make(); | |||
this.refresh(); | |||
}, | |||
@@ -72,11 +87,6 @@ wn.UserProperties = Class.extend({ | |||
this.show_property_table(); | |||
} | |||
this.show_add_property(); | |||
$("<div class='well'>User Properties appear as default values in forms.\ | |||
<br>They are also used to restrict permissions \ | |||
in the <a href='#permission-manager'>Permission Manager</a>\ | |||
<br>You can also set multiple values for one property. \ | |||
If so, the permission rules will apply if any of the values match.</div>").appendTo(this.body); | |||
}, | |||
refresh: function() { | |||
var me = this; | |||
@@ -119,7 +129,8 @@ wn.UserProperties = Class.extend({ | |||
$.each(this.prop_list, function(i, d) { | |||
var row = $("<tr>").appendTo(me.table.find("tbody")); | |||
$("<td>").html(d.parent).appendTo(row); | |||
$("<td>").html('<a href="#Form/Profile/'+d.parent+'">' | |||
+d.parent+'</a>').appendTo(row); | |||
$("<td>").html(d.defkey).appendTo(row); | |||
$("<td>").html(d.defvalue).appendTo(row); | |||
@@ -184,7 +195,7 @@ wn.UserProperties = Class.extend({ | |||
if(l[0]==key) return l[1]; | |||
})[0]; | |||
return 'select name from `tab'+doctype | |||
+'` where name like "%s"' | |||
+'` where name like "%s" limit 20' | |||
} | |||
d.get_input("add").click(function() { | |||
var args = d.get_values(); | |||
@@ -3,11 +3,17 @@ import webnotes | |||
@webnotes.whitelist(allow_roles=["System Manager", "Administrator"]) | |||
def get_users_and_links(): | |||
links = list(set(webnotes.conn.sql("""select fieldname, options | |||
links, all_fields = [], [] | |||
for l in webnotes.conn.sql("""select fieldname, options | |||
from tabDocField where fieldtype='Link' | |||
and parent not in ('[Select]', 'DocType', 'Module Def') | |||
""") + webnotes.conn.sql("""select fieldname, options | |||
from `tabCustom Field` where fieldtype='Link'"""))) | |||
from `tabCustom Field` where fieldtype='Link'"""): | |||
if not l[0] in all_fields: | |||
links.append([l[0], l[1]]) | |||
all_fields.append(l[0]) | |||
links.sort() | |||
return { | |||
@@ -21,10 +27,11 @@ def get_users_and_links(): | |||
def get_properties(user=None, key=None): | |||
return webnotes.conn.sql("""select name, parent, defkey, defvalue | |||
from tabDefaultValue | |||
where %s%s and parent!='Control Panel' order by parent, defkey""" % (\ | |||
user and (" parent='%s'" % user) or "", | |||
key and ((user and " and " or "") + " defkey='%s'" % key) or "", | |||
), as_dict=True) | |||
where parent!='Control Panel' | |||
and substr(defkey,0,1)!='_' | |||
%s%s order by parent, defkey""" % (\ | |||
user and (" and parent='%s'" % user) or "", | |||
key and (" and defkey='%s'" % key) or ""), as_dict=True) | |||
@webnotes.whitelist(allow_roles=["System Manager", "Administrator"]) | |||
def remove(user, name): | |||
@@ -150,10 +150,10 @@ | |||
"lib/public/js/legacy/widgets/form/form_comments.js", | |||
"lib/public/js/legacy/wn/widgets/form/sidebar.js", | |||
"lib/public/js/legacy/wn/widgets/form/comments.js", | |||
"lib/public/js/legacy/wn/widgets/form/assign_to.js", | |||
"lib/public/js/wn/form/attachments.js", | |||
"lib/public/js/wn/form/linked_with.js", | |||
"lib/public/js/wn/form/states.js", | |||
"lib/public/js/wn/form/assign_to.js", | |||
"lib/public/js/wn/print/print_table.js", | |||
'lib/public/js/lib/jquery/jquery.ui.interactions.min.js', | |||
@@ -215,7 +215,7 @@ textarea { | |||
.input-block-level { | |||
display: block; | |||
width: 100%; | |||
min-height: 28px; | |||
min-height: 30px; | |||
-webkit-box-sizing: border-box; | |||
-moz-box-sizing: border-box; | |||
box-sizing: border-box; | |||
@@ -225,7 +225,7 @@ body { | |||
margin: 0; | |||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; | |||
font-size: 13px; | |||
line-height: 18px; | |||
line-height: 20px; | |||
color: #333333; | |||
background-color: #ffffff; | |||
} | |||
@@ -407,7 +407,7 @@ a:hover { | |||
display: block; | |||
float: left; | |||
width: 100%; | |||
min-height: 28px; | |||
min-height: 30px; | |||
margin-left: 2.127659574468085%; | |||
*margin-left: 2.074468085106383%; | |||
-webkit-box-sizing: border-box; | |||
@@ -648,14 +648,14 @@ a:hover { | |||
} | |||
p { | |||
margin: 0 0 9px; | |||
margin: 0 0 10px; | |||
} | |||
.lead { | |||
margin-bottom: 18px; | |||
margin-bottom: 20px; | |||
font-size: 19.5px; | |||
font-weight: 200; | |||
line-height: 27px; | |||
line-height: 30px; | |||
} | |||
small { | |||
@@ -720,10 +720,10 @@ h3, | |||
h4, | |||
h5, | |||
h6 { | |||
margin: 9px 0; | |||
margin: 10px 0; | |||
font-family: inherit; | |||
font-weight: bold; | |||
line-height: 18px; | |||
line-height: 20px; | |||
color: inherit; | |||
text-rendering: optimizelegibility; | |||
} | |||
@@ -742,7 +742,7 @@ h6 small { | |||
h1, | |||
h2, | |||
h3 { | |||
line-height: 36px; | |||
line-height: 40px; | |||
} | |||
h1 { | |||
@@ -786,15 +786,15 @@ h4 small { | |||
} | |||
.page-header { | |||
padding-bottom: 8px; | |||
margin: 18px 0 27px; | |||
padding-bottom: 9px; | |||
margin: 20px 0 30px; | |||
border-bottom: 1px solid #eeeeee; | |||
} | |||
ul, | |||
ol { | |||
padding: 0; | |||
margin: 0 0 9px 25px; | |||
margin: 0 0 10px 25px; | |||
} | |||
ul ul, | |||
@@ -805,7 +805,7 @@ ol ul { | |||
} | |||
li { | |||
line-height: 18px; | |||
line-height: 20px; | |||
} | |||
ul.unstyled, | |||
@@ -828,12 +828,12 @@ ol.inline > li { | |||
} | |||
dl { | |||
margin-bottom: 18px; | |||
margin-bottom: 20px; | |||
} | |||
dt, | |||
dd { | |||
line-height: 18px; | |||
line-height: 20px; | |||
} | |||
dt { | |||
@@ -841,7 +841,7 @@ dt { | |||
} | |||
dd { | |||
margin-left: 9px; | |||
margin-left: 10px; | |||
} | |||
.dl-horizontal { | |||
@@ -874,7 +874,7 @@ dd { | |||
} | |||
hr { | |||
margin: 18px 0; | |||
margin: 20px 0; | |||
border: 0; | |||
border-top: 1px solid #eeeeee; | |||
border-bottom: 1px solid #ffffff; | |||
@@ -893,7 +893,7 @@ abbr.initialism { | |||
blockquote { | |||
padding: 0 0 0 15px; | |||
margin: 0 0 18px; | |||
margin: 0 0 20px; | |||
border-left: 5px solid #eeeeee; | |||
} | |||
@@ -901,12 +901,12 @@ blockquote p { | |||
margin-bottom: 0; | |||
font-size: 16px; | |||
font-weight: 300; | |||
line-height: 22.5px; | |||
line-height: 25px; | |||
} | |||
blockquote small { | |||
display: block; | |||
line-height: 18px; | |||
line-height: 20px; | |||
color: #999999; | |||
} | |||
@@ -944,9 +944,9 @@ blockquote:after { | |||
address { | |||
display: block; | |||
margin-bottom: 18px; | |||
margin-bottom: 20px; | |||
font-style: normal; | |||
line-height: 18px; | |||
line-height: 20px; | |||
} | |||
code, | |||
@@ -970,10 +970,10 @@ code { | |||
pre { | |||
display: block; | |||
padding: 8.5px; | |||
margin: 0 0 9px; | |||
padding: 9.5px; | |||
margin: 0 0 10px; | |||
font-size: 12px; | |||
line-height: 18px; | |||
line-height: 20px; | |||
word-break: break-all; | |||
word-wrap: break-word; | |||
white-space: pre; | |||
@@ -987,7 +987,7 @@ pre { | |||
} | |||
pre.prettyprint { | |||
margin-bottom: 18px; | |||
margin-bottom: 20px; | |||
} | |||
pre code { | |||
@@ -1005,7 +1005,7 @@ pre code { | |||
} | |||
form { | |||
margin: 0 0 18px; | |||
margin: 0 0 20px; | |||
} | |||
fieldset { | |||
@@ -1018,16 +1018,16 @@ legend { | |||
display: block; | |||
width: 100%; | |||
padding: 0; | |||
margin-bottom: 18px; | |||
margin-bottom: 20px; | |||
font-size: 19.5px; | |||
line-height: 36px; | |||
line-height: 40px; | |||
color: #333333; | |||
border: 0; | |||
border-bottom: 1px solid #e5e5e5; | |||
} | |||
legend small { | |||
font-size: 13.5px; | |||
font-size: 15px; | |||
color: #999999; | |||
} | |||
@@ -1038,7 +1038,7 @@ select, | |||
textarea { | |||
font-size: 13px; | |||
font-weight: normal; | |||
line-height: 18px; | |||
line-height: 20px; | |||
} | |||
input, | |||
@@ -1071,11 +1071,11 @@ input[type="tel"], | |||
input[type="color"], | |||
.uneditable-input { | |||
display: inline-block; | |||
height: 18px; | |||
height: 20px; | |||
padding: 4px 6px; | |||
margin-bottom: 9px; | |||
margin-bottom: 10px; | |||
font-size: 13px; | |||
line-height: 18px; | |||
line-height: 20px; | |||
color: #555555; | |||
vertical-align: middle; | |||
-webkit-border-radius: 4px; | |||
@@ -1166,13 +1166,13 @@ input[type="checkbox"] { | |||
select, | |||
input[type="file"] { | |||
height: 28px; | |||
height: 30px; | |||
/* In IE7, the height of the select element cannot be changed by height, only font-size */ | |||
*margin-top: 4px; | |||
/* For IE7, add top margin to align select with labels */ | |||
line-height: 28px; | |||
line-height: 30px; | |||
} | |||
select { | |||
@@ -1233,7 +1233,7 @@ textarea::-webkit-input-placeholder { | |||
.radio, | |||
.checkbox { | |||
min-height: 18px; | |||
min-height: 20px; | |||
padding-left: 20px; | |||
} | |||
@@ -1607,9 +1607,9 @@ select:focus:invalid:focus { | |||
} | |||
.form-actions { | |||
padding: 17px 20px 18px; | |||
margin-top: 18px; | |||
margin-bottom: 18px; | |||
padding: 19px 20px 20px; | |||
margin-top: 20px; | |||
margin-bottom: 20px; | |||
background-color: #f5f5f5; | |||
border-top: 1px solid #e5e5e5; | |||
*zoom: 1; | |||
@@ -1633,7 +1633,7 @@ select:focus:invalid:focus { | |||
.help-block { | |||
display: block; | |||
margin-bottom: 9px; | |||
margin-bottom: 10px; | |||
} | |||
.help-inline { | |||
@@ -1690,12 +1690,12 @@ select:focus:invalid:focus { | |||
.input-prepend .add-on { | |||
display: inline-block; | |||
width: auto; | |||
height: 18px; | |||
height: 20px; | |||
min-width: 16px; | |||
padding: 4px 5px; | |||
font-size: 13px; | |||
font-weight: normal; | |||
line-height: 18px; | |||
line-height: 20px; | |||
text-align: center; | |||
text-shadow: 0 1px 0 #ffffff; | |||
background-color: #eeeeee; | |||
@@ -1911,16 +1911,16 @@ input.search-query { | |||
} | |||
.control-group { | |||
margin-bottom: 9px; | |||
margin-bottom: 10px; | |||
} | |||
legend + .control-group { | |||
margin-top: 18px; | |||
margin-top: 20px; | |||
-webkit-margin-top-collapse: separate; | |||
} | |||
.form-horizontal .control-group { | |||
margin-bottom: 18px; | |||
margin-bottom: 20px; | |||
*zoom: 1; | |||
} | |||
@@ -1963,7 +1963,7 @@ legend + .control-group { | |||
.form-horizontal .uneditable-input + .help-block, | |||
.form-horizontal .input-prepend + .help-block, | |||
.form-horizontal .input-append + .help-block { | |||
margin-top: 9px; | |||
margin-top: 10px; | |||
} | |||
.form-horizontal .form-actions { | |||
@@ -1979,13 +1979,13 @@ table { | |||
.table { | |||
width: 100%; | |||
margin-bottom: 18px; | |||
margin-bottom: 20px; | |||
} | |||
.table th, | |||
.table td { | |||
padding: 8px; | |||
line-height: 18px; | |||
line-height: 20px; | |||
text-align: left; | |||
vertical-align: top; | |||
border-top: 1px solid #dddddd; | |||
@@ -2308,7 +2308,7 @@ table th[class*="span"], | |||
.dropdown-menu .divider { | |||
*width: 100%; | |||
height: 1px; | |||
margin: 8px 1px; | |||
margin: 9px 1px; | |||
*margin: -5px 0 5px; | |||
overflow: hidden; | |||
background-color: #e5e5e5; | |||
@@ -2320,7 +2320,7 @@ table th[class*="span"], | |||
padding: 3px 20px; | |||
clear: both; | |||
font-weight: normal; | |||
line-height: 18px; | |||
line-height: 20px; | |||
color: #333333; | |||
white-space: nowrap; | |||
} | |||
@@ -2529,7 +2529,7 @@ table th[class*="span"], | |||
float: right; | |||
font-size: 20px; | |||
font-weight: bold; | |||
line-height: 18px; | |||
line-height: 20px; | |||
color: #000000; | |||
text-shadow: 0 1px 0 #ffffff; | |||
opacity: 0.2; | |||
@@ -2559,7 +2559,7 @@ button.close { | |||
margin-bottom: 0; | |||
*margin-left: .3em; | |||
font-size: 13px; | |||
line-height: 18px; | |||
line-height: 20px; | |||
color: #333333; | |||
text-align: center; | |||
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); | |||
@@ -2989,8 +2989,8 @@ input[type="submit"].btn.btn-mini { | |||
} | |||
.btn-toolbar { | |||
margin-top: 9px; | |||
margin-bottom: 9px; | |||
margin-top: 10px; | |||
margin-bottom: 10px; | |||
font-size: 0; | |||
} | |||
@@ -3224,7 +3224,7 @@ input[type="submit"].btn.btn-mini { | |||
.alert { | |||
padding: 8px 35px 8px 14px; | |||
margin-bottom: 18px; | |||
margin-bottom: 20px; | |||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); | |||
background-color: #fcf8e3; | |||
border: 1px solid #fbeed5; | |||
@@ -3246,7 +3246,7 @@ input[type="submit"].btn.btn-mini { | |||
position: relative; | |||
top: -2px; | |||
right: -21px; | |||
line-height: 18px; | |||
line-height: 20px; | |||
} | |||
.alert-success { | |||
@@ -3296,7 +3296,7 @@ input[type="submit"].btn.btn-mini { | |||
} | |||
.nav { | |||
margin-bottom: 18px; | |||
margin-bottom: 20px; | |||
margin-left: 0; | |||
list-style: none; | |||
} | |||
@@ -3323,7 +3323,7 @@ input[type="submit"].btn.btn-mini { | |||
padding: 3px 15px; | |||
font-size: 11px; | |||
font-weight: bold; | |||
line-height: 18px; | |||
line-height: 20px; | |||
color: #999999; | |||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); | |||
text-transform: uppercase; | |||
@@ -3365,7 +3365,7 @@ input[type="submit"].btn.btn-mini { | |||
.nav-list .divider { | |||
*width: 100%; | |||
height: 1px; | |||
margin: 8px 1px; | |||
margin: 9px 1px; | |||
*margin: -5px 0 5px; | |||
overflow: hidden; | |||
background-color: #e5e5e5; | |||
@@ -3415,7 +3415,7 @@ input[type="submit"].btn.btn-mini { | |||
.nav-tabs > li > a { | |||
padding-top: 8px; | |||
padding-bottom: 8px; | |||
line-height: 18px; | |||
line-height: 20px; | |||
border: 1px solid transparent; | |||
-webkit-border-radius: 4px 4px 0 0; | |||
-moz-border-radius: 4px 4px 0 0; | |||
@@ -3696,7 +3696,7 @@ input[type="submit"].btn.btn-mini { | |||
.navbar { | |||
*position: relative; | |||
*z-index: 2; | |||
margin-bottom: 18px; | |||
margin-bottom: 20px; | |||
overflow: visible; | |||
} | |||
@@ -3745,7 +3745,7 @@ input[type="submit"].btn.btn-mini { | |||
.navbar .brand { | |||
display: block; | |||
float: left; | |||
padding: 11px 20px 11px; | |||
padding: 10px 20px 10px; | |||
margin-left: -20px; | |||
font-size: 20px; | |||
font-weight: 200; | |||
@@ -3939,7 +3939,7 @@ input[type="submit"].btn.btn-mini { | |||
.navbar .nav > li > a { | |||
float: none; | |||
padding: 11px 15px 11px; | |||
padding: 10px 15px 10px; | |||
color: #777777; | |||
text-decoration: none; | |||
text-shadow: 0 1px 0 #ffffff; | |||
@@ -4268,7 +4268,7 @@ input[type="submit"].btn.btn-mini { | |||
.breadcrumb { | |||
padding: 8px 15px; | |||
margin: 0 0 18px; | |||
margin: 0 0 20px; | |||
list-style: none; | |||
background-color: #f5f5f5; | |||
-webkit-border-radius: 4px; | |||
@@ -4293,7 +4293,7 @@ input[type="submit"].btn.btn-mini { | |||
} | |||
.pagination { | |||
margin: 18px 0; | |||
margin: 20px 0; | |||
} | |||
.pagination ul { | |||
@@ -4318,7 +4318,7 @@ input[type="submit"].btn.btn-mini { | |||
.pagination ul > li > span { | |||
float: left; | |||
padding: 4px 12px; | |||
line-height: 18px; | |||
line-height: 20px; | |||
text-decoration: none; | |||
background-color: #ffffff; | |||
border: 1px solid #dddddd; | |||
@@ -4437,7 +4437,7 @@ input[type="submit"].btn.btn-mini { | |||
} | |||
.pager { | |||
margin: 18px 0; | |||
margin: 20px 0; | |||
text-align: center; | |||
list-style: none; | |||
*zoom: 1; | |||
@@ -4858,14 +4858,14 @@ input[type="submit"].btn.btn-mini { | |||
.thumbnails > li { | |||
float: left; | |||
margin-bottom: 18px; | |||
margin-bottom: 20px; | |||
margin-left: 20px; | |||
} | |||
.thumbnail { | |||
display: block; | |||
padding: 4px; | |||
line-height: 18px; | |||
line-height: 20px; | |||
border: 1px solid #ddd; | |||
-webkit-border-radius: 4px; | |||
-moz-border-radius: 4px; | |||
@@ -5082,8 +5082,8 @@ a.badge:hover { | |||
} | |||
.progress { | |||
height: 18px; | |||
margin-bottom: 18px; | |||
height: 20px; | |||
margin-bottom: 20px; | |||
overflow: hidden; | |||
background-color: #f7f7f7; | |||
background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); | |||
@@ -5245,7 +5245,7 @@ a.badge:hover { | |||
} | |||
.accordion { | |||
margin-bottom: 18px; | |||
margin-bottom: 20px; | |||
} | |||
.accordion-group { | |||
@@ -5276,7 +5276,7 @@ a.badge:hover { | |||
.carousel { | |||
position: relative; | |||
margin-bottom: 18px; | |||
margin-bottom: 20px; | |||
line-height: 1; | |||
} | |||
@@ -5383,7 +5383,7 @@ a.badge:hover { | |||
.carousel-caption h4, | |||
.carousel-caption p { | |||
line-height: 18px; | |||
line-height: 20px; | |||
color: #ffffff; | |||
} | |||
@@ -5400,7 +5400,7 @@ a.badge:hover { | |||
margin-bottom: 30px; | |||
font-size: 18px; | |||
font-weight: 200; | |||
line-height: 27px; | |||
line-height: 30px; | |||
color: inherit; | |||
background-color: #eeeeee; | |||
-webkit-border-radius: 6px; | |||
@@ -5417,7 +5417,7 @@ a.badge:hover { | |||
} | |||
.hero-unit li { | |||
line-height: 27px; | |||
line-height: 30px; | |||
} | |||
.pull-right { | |||
@@ -1,117 +0,0 @@ | |||
// Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com) | |||
// | |||
// MIT License (MIT) | |||
// | |||
// Permission is hereby granted, free of charge, to any person obtaining a | |||
// copy of this software and associated documentation files (the "Software"), | |||
// to deal in the Software without restriction, including without limitation | |||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, | |||
// and/or sell copies of the Software, and to permit persons to whom the | |||
// Software is furnished to do so, subject to the following conditions: | |||
// | |||
// The above copyright notice and this permission notice shall be included in | |||
// all copies or substantial portions of the Software. | |||
// | |||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | |||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | |||
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE | |||
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
// | |||
// assign to is lined to todo | |||
// refresh - load todos | |||
// create - new todo | |||
// delete to do | |||
wn.widgets.form.sidebar.AssignTo = Class.extend({ | |||
init: function(parent, sidebar, doctype, docname) { | |||
var me = this; | |||
this.doctype = doctype; | |||
this.name = docname; | |||
this.wrapper = $a(parent, 'div', 'sidebar-comment-wrapper'); | |||
this.body = $a(this.wrapper, 'div'); | |||
this.add_btn = $("<button class='btn btn-small'>\ | |||
<i class='icon-plus'></i></button>") | |||
.click(function() { me.add(); }).appendTo(this.wrapper).get(0); | |||
this.refresh(); | |||
}, | |||
refresh: function() { | |||
var me = this; | |||
$c('webnotes.widgets.form.assign_to.get', { | |||
doctype: me.doctype, | |||
name: me.name | |||
}, function(r,rt) { | |||
me.render(r.message) | |||
}) | |||
}, | |||
render: function(d) { | |||
var me = this; | |||
$(this.body).empty(); | |||
if(this.dialog) { | |||
this.dialog.hide(); | |||
} | |||
for(var i=0; i<d.length; i++) { | |||
$(this.body).append(repl('<div>%(owner)s \ | |||
<a class="close" href="#" data-owner="%(owner)s">×</a></div>', d[i])) | |||
} | |||
// set remove | |||
$(this.body).find('a.close').click(function() { | |||
$c('webnotes.widgets.form.assign_to.remove', { | |||
doctype: me.doctype, | |||
name: me.name, | |||
assign_to: $(this).attr('data-owner') | |||
}, function(r,rt) {me.render(r.message);}); | |||
return false; | |||
}); | |||
}, | |||
add: function() { | |||
var me = this; | |||
if(!me.dialog) { | |||
me.dialog = new wn.ui.Dialog({ | |||
title: 'Add to To Do', | |||
width: 350, | |||
fields: [ | |||
{fieldtype:'Link', fieldname:'assign_to', options:'Profile', | |||
label:'Assign To', | |||
description:'Add to To Do List of', reqd:true}, | |||
{fieldtype:'Data', fieldname:'description', label:'Comment'}, | |||
{fieldtype:'Date', fieldname:'date', label:'Complete By'}, | |||
{fieldtype:'Select', fieldname:'priority', label:'Priority', | |||
options:'Low\nMedium\nHigh', 'default':'Medium'}, | |||
{fieldtype:'Check', fieldname:'notify', label:'Notify By Email'}, | |||
{fieldtype:'Button', label:'Add', fieldname:'add_btn'} | |||
] | |||
}); | |||
me.dialog.fields_dict.add_btn.input.onclick = function() { | |||
var assign_to = me.dialog.fields_dict.assign_to.get_value(); | |||
if(assign_to) { | |||
$c('webnotes.widgets.form.assign_to.add', { | |||
doctype: me.doctype, | |||
name: me.name, | |||
assign_to: assign_to, | |||
description: me.dialog.fields_dict.description.get_value(), | |||
priority: me.dialog.fields_dict.priority.get_value(), | |||
date: me.dialog.fields_dict.date.get_value(), | |||
notify: me.dialog.fields_dict.notify.get_value() | |||
}, function(r,rt) {me.render(r.message);}); | |||
} | |||
}; | |||
me.dialog.fields_dict.assign_to.get_query = function() { | |||
return "select name, concat_ws(' ', first_name, middle_name, last_name) \ | |||
from `tabProfile` where ifnull(enabled, 0)=1 and docstatus < 2 and \ | |||
(%(key)s like \"%s\" or \ | |||
concat_ws(' ', first_name, middle_name, last_name) like \"%%%s\") \ | |||
limit 50"; | |||
}; | |||
} | |||
me.dialog.clear(); | |||
me.dialog.show(); | |||
} | |||
}); | |||
@@ -115,7 +115,11 @@ wn.widgets.form.sidebar = { Sidebar: function(form) { | |||
{ | |||
title: 'Assign', | |||
render: function(wrapper) { | |||
me.form.assign_to = new wn.widgets.form.sidebar.AssignTo(wrapper, me, me.form.doctype, me.form.docname); | |||
me.form.assign_to = new wn.ui.form.AssignTo({ | |||
parent: $(wrapper), | |||
frm: me.form | |||
}); | |||
me.form.assign_to.refresh(); | |||
}, | |||
display: function() { return !me.form.doc.__islocal } | |||
}, | |||
@@ -123,7 +127,10 @@ wn.widgets.form.sidebar = { Sidebar: function(form) { | |||
{ | |||
title: 'Attachments', | |||
render: function(wrapper) { | |||
me.form.attachments = new wn.ui.form.Attachments({parent: $(wrapper), frm:me.form}); | |||
me.form.attachments = new wn.ui.form.Attachments({ | |||
parent: $(wrapper), | |||
frm:me.form | |||
}); | |||
me.form.attachments.refresh(); | |||
}, | |||
display: function() { return me.form.meta.allow_attach } | |||
@@ -77,7 +77,7 @@ wn.ui.form.Attachments = Class.extend({ | |||
var me = this; | |||
$(repl('<div class="alert alert-info"><span style="display: inline-block; width: 90%;\ | |||
text-overflow: ellipsis; white-space: nowrap; overflow: hidden;">\ | |||
<i class="icon icon-file"></i> <a href="%(href)s"\ | |||
<i class="icon-file"></i> <a href="%(href)s"\ | |||
target="_blank" title="%(filename)s">%(filename)s</a></span><a href="#" class="close">×</a>\ | |||
</div>', { | |||
filename: filename, | |||
@@ -63,9 +63,16 @@ wn.ui.Dialog = wn.ui.FieldGroup.extend({ | |||
this.appframe.$titlebar.find('.appframe-title').html(t || ''); | |||
}, | |||
set_postion: function() { | |||
this.zindex = 1; | |||
if(cur_dialog) { | |||
this.zindex = cur_dialog.zindex + 1; | |||
} | |||
// place it at the center | |||
this.wrapper.style.left = (($(window).width() - cint(this.wrapper.style.width))/2) + 'px'; | |||
this.wrapper.style.top = ($(window).scrollTop() + 60) + 'px'; | |||
$(this.wrapper).css({ | |||
left: (($(window).width() - cint(this.wrapper.style.width))/2) + 'px', | |||
top: ($(window).scrollTop() + 60) + 'px', | |||
"z-index": this.zindex | |||
}) | |||
}, | |||
show: function() { | |||
// already live, do nothing | |||
@@ -72,53 +72,11 @@ class Database: | |||
self._conn.select_db(db_name) | |||
self.cur_db_name = db_name | |||
def check_transaction_status(self, query): | |||
""" | |||
Update *in_transaction* and check if "START TRANSACTION" is not called twice | |||
""" | |||
if self.in_transaction and query and query.strip().split()[0].lower() in ['start', 'alter', 'drop', 'create']: | |||
raise Exception, 'This statement can cause implicit commit' | |||
if query and query.strip().lower()=='start transaction': | |||
self.in_transaction = 1 | |||
self.transaction_writes = 0 | |||
if query and query.strip().split()[0].lower() in ['commit', 'rollback']: | |||
self.in_transaction = 0 | |||
if self.in_transaction and query[:6].lower() in ['update', 'insert']: | |||
self.transaction_writes += 1 | |||
if self.transaction_writes > 10000: | |||
if self.auto_commit_on_many_writes: | |||
webnotes.conn.commit() | |||
webnotes.conn.begin() | |||
else: | |||
webnotes.msgprint('A very long query was encountered. If you are trying to import data, please do so using smaller files') | |||
raise Exception, 'Bad Query!!! Too many writes' | |||
def fetch_as_dict(self, formatted=0, as_utf8=0): | |||
""" | |||
Internal - get results as dictionary | |||
""" | |||
result = self._cursor.fetchall() | |||
ret = [] | |||
for r in result: | |||
row_dict = webnotes._dict({}) | |||
for i in range(len(r)): | |||
val = self.convert_to_simple_type(r[i], formatted) | |||
if as_utf8 and type(val) is unicode: | |||
val = val.encode('utf-8') | |||
row_dict[self._cursor.description[i][0]] = val | |||
ret.append(row_dict) | |||
return ret | |||
def validate_query(self, q): | |||
cmd = q.strip().lower().split()[0] | |||
if cmd in ['alter', 'drop', 'truncate'] and webnotes.user.name != 'Administrator': | |||
webnotes.msgprint('Not allowed to execute query') | |||
raise Execption | |||
# ====================================================================================== | |||
def sql(self, query, values=(), as_dict = 0, as_list = 0, formatted = 0, | |||
debug=0, ignore_ddl=0, as_utf8=0, auto_commit=0, update=None): | |||
@@ -168,15 +126,43 @@ class Database: | |||
else: | |||
return self._cursor.fetchall() | |||
def check_transaction_status(self, query): | |||
if self.in_transaction and query and query.strip().split()[0].lower() in ['start', 'alter', 'drop', 'create']: | |||
raise Exception, 'This statement can cause implicit commit' | |||
if query and query.strip().lower()=='start transaction': | |||
self.in_transaction = 1 | |||
self.transaction_writes = 0 | |||
if query and query.strip().split()[0].lower() in ['commit', 'rollback']: | |||
self.in_transaction = 0 | |||
if self.in_transaction and query[:6].lower() in ['update', 'insert']: | |||
self.transaction_writes += 1 | |||
if self.transaction_writes > 10000: | |||
if self.auto_commit_on_many_writes: | |||
webnotes.conn.commit() | |||
webnotes.conn.begin() | |||
else: | |||
webnotes.msgprint('A very long query was encountered. If you are trying to import data, please do so using smaller files') | |||
raise Exception, 'Bad Query!!! Too many writes' | |||
def fetch_as_dict(self, formatted=0, as_utf8=0): | |||
result = self._cursor.fetchall() | |||
ret = [] | |||
for r in result: | |||
row_dict = webnotes._dict({}) | |||
for i in range(len(r)): | |||
val = self.convert_to_simple_type(r[i], formatted) | |||
if as_utf8 and type(val) is unicode: | |||
val = val.encode('utf-8') | |||
row_dict[self._cursor.description[i][0]] = val | |||
ret.append(row_dict) | |||
return ret | |||
def get_description(self): | |||
""" | |||
Get metadata of the last query | |||
""" | |||
return self._cursor.description | |||
# ====================================================================================== | |||
def convert_to_simple_type(self, v, formatted=0): | |||
import datetime | |||
from webnotes.utils import formatdate, fmt_money | |||
@@ -211,12 +197,7 @@ class Database: | |||
return v | |||
# ====================================================================================== | |||
def convert_to_lists(self, res, formatted=0, as_utf8=0): | |||
""" | |||
Convert the given result set to a list of lists (with cleaned up dates and decimals) | |||
""" | |||
nres = [] | |||
for r in res: | |||
nr = [] | |||
@@ -227,13 +208,8 @@ class Database: | |||
nr.append(val) | |||
nres.append(nr) | |||
return nres | |||
# ====================================================================================== | |||
def convert_to_utf8(self, res, formatted=0): | |||
""" | |||
Convert the given result set to a list of lists and as utf8 (with cleaned up dates and decimals) | |||
""" | |||
nres = [] | |||
for r in res: | |||
nr = [] | |||
@@ -311,8 +287,6 @@ class Database: | |||
self.set_value(doc.doctype, doc.name, field, val, doc.modified, doc.modified_by) | |||
doc.fields[field] = val | |||
# ====================================================================================== | |||
def set_global(self, key, val, user='__global'): | |||
res = self.sql('select defkey from `tabDefaultValue` where defkey=%s and parent=%s', (key, user)) | |||
if res: | |||
@@ -324,8 +298,6 @@ class Database: | |||
g = self.sql("select defvalue from tabDefaultValue where defkey=%s and parent=%s", (key, user)) | |||
return g and g[0][0] or None | |||
# ====================================================================================== | |||
def set_default(self, key, val, parent="Control Panel"): | |||
"""set control panel default (tabDefaultVal)""" | |||
@@ -338,7 +310,6 @@ class Database: | |||
else: | |||
self.add_default(key, val, parent) | |||
def add_default(self, key, val, parent="Control Panel"): | |||
d = webnotes.doc('DefaultValue') | |||
d.parent = parent | |||
@@ -374,22 +345,13 @@ class Database: | |||
def commit(self): | |||
self.sql("commit") | |||
def rollback(self): | |||
self.sql("ROLLBACK") | |||
# ====================================================================================== | |||
def field_exists(self, dt, fn): | |||
""" | |||
Returns True if `fn` exists in `DocType` `dt` | |||
""" | |||
return self.sql("select name from tabDocField where fieldname=%s and parent=%s", (dt, fn)) | |||
def exists(self, dt, dn=None): | |||
""" | |||
Returns true if the record exists | |||
""" | |||
if isinstance(dt, basestring): | |||
try: | |||
return self.sql('select name from `tab%s` where name=%s' % (dt, '%s'), dn) | |||
@@ -409,11 +371,7 @@ class Database: | |||
def get_table_columns(self, doctype): | |||
return [r[0] for r in self.sql("DESC `tab%s`" % doctype)] | |||
# ====================================================================================== | |||
def close(self): | |||
""" | |||
Close my connection | |||
""" | |||
if self._conn: | |||
self._cursor.close() | |||
self._conn.close() | |||
@@ -76,7 +76,7 @@ def add(args=None): | |||
return get(args) | |||
@webnotes.whitelist() | |||
def remove(args=None): | |||
def remove(doctype, name, assign_to): | |||
"""remove from todo""" | |||
if not args: | |||
args = webnotes.form_dict | |||
@@ -84,11 +84,15 @@ def remove(args=None): | |||
res = webnotes.conn.sql("""\ | |||
select assigned_by, owner, reference_type, reference_name from `tabToDo` | |||
where reference_type=%(doctype)s and reference_name=%(name)s | |||
and owner=%(assign_to)s""", args) | |||
and owner=%(assign_to)s""", locals()) | |||
webnotes.conn.sql("""delete from `tabToDo` | |||
where reference_type=%(doctype)s and reference_name=%(name)s | |||
and owner=%(assign_to)s""", args) | |||
and owner=%(assign_to)s""", locals()) | |||
# clear assigned_to if field exists | |||
if "assigned_to" in webnotes.conn.get_columns(doctype): | |||
webnotes.conn.set_value(doctype, name, "assigned_to", None) | |||
if res and res[0]: notify_assignment(res[0][0], res[0][1], res[0][2], res[0][3]) | |||