diff --git a/frappe/core/doctype/docperm/docperm.json b/frappe/core/doctype/docperm/docperm.json index 6cb159a495..ebcd67e301 100644 --- a/frappe/core/doctype/docperm/docperm.json +++ b/frappe/core/doctype/docperm/docperm.json @@ -1,7 +1,7 @@ { "allow_copy": 0, "autoname": "PERM.#####", - "creation": "2013-02-22 01:27:33.000000", + "creation": "2013-02-22 01:27:33", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -70,7 +70,7 @@ "description": "Only restricted users can access", "fieldname": "restricted", "fieldtype": "Check", - "label": "Restricted", + "label": "Only Restricted Documents", "permlevel": 0 }, { @@ -207,10 +207,11 @@ "idx": 1, "issingle": 0, "istable": 1, - "modified": "2014-01-22 14:32:34.000000", + "modified": "2014-04-30 00:31:21.598463", "modified_by": "Administrator", "module": "Core", "name": "DocPerm", "owner": "Administrator", + "permissions": [], "read_only": 0 } \ No newline at end of file diff --git a/frappe/core/doctype/user/user.css b/frappe/core/doctype/user/user.css index bf22d45aac..b89fca3355 100644 --- a/frappe/core/doctype/user/user.css +++ b/frappe/core/doctype/user/user.css @@ -6,6 +6,10 @@ table.user-perm { border-collapse: collapse; + width: 100%; + overflow-x: scroll; + -webkit-overflow-scrolling: touch; + -ms-overflow-style: -ms-autohiding-scrollbar; } table.user-perm td, table.user-perm th { diff --git a/frappe/core/doctype/user/user.js b/frappe/core/doctype/user/user.js index 19fc5684fd..e4dac31ccf 100644 --- a/frappe/core/doctype/user/user.js +++ b/frappe/core/doctype/user/user.js @@ -218,15 +218,28 @@ frappe.RoleEditor = Class.extend({ args: {role: role}, callback: function(r) { var $body = $(me.perm_dialog.body); - $body.append('\ - \ - \ - \ - \ - \ - \ -
Document TypeLevelReadWriteSubmitCancelAmend
'); - for(var i in r.message) { + // TODO fix the overflow issue and also display perms like report, import, etc. + + $body.append('' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + // + '' + // + '' + // + '' + // + '' + // + '' + + '' + + '
' + __('Document Type') + '' + __('Level') + '' + __('Read') + '' + __('Only Restricted Documents') + '' + __('Write') + '' + __('Create') + '' + __('Delete') + '' + __('Submit') + '' + __('Cancel') + '' + __('Amend') + '' + __('Report') + '' + __('Import') + '' + __('Export') + '' + __('Print') + '' + __('Email') + '' + __('Can Restrict') + '
'); + + for(var i=0, l=r.message.length; i icon @@ -244,10 +257,19 @@ frappe.RoleEditor = Class.extend({ %(parent)s\ %(permlevel)s\ %(read)s\ + %(restricted)s\ %(write)s\ + %(create)s\ + %(delete)s\ %(submit)s\ %(cancel)s\ - %(amend)s\ + %(amend)s' + // + '%(report)s\ + // %(import)s\ + // %(export)s\ + // %(print)s\ + // %(email)s' + + '%(restrict)s\ ', perm)) } @@ -259,7 +281,7 @@ frappe.RoleEditor = Class.extend({ make_perm_dialog: function() { this.perm_dialog = new frappe.ui.Dialog({ title:'Role Permissions', - width: 500 + width: "800px" }); } }); diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py index 2a4dc67fdd..b79bcfccb7 100644 --- a/frappe/core/doctype/user/user.py +++ b/frappe/core/doctype/user/user.py @@ -6,6 +6,7 @@ import frappe from frappe.utils import cint, now from frappe import throw, msgprint, _ from frappe.auth import _update_password +import frappe.permissions STANDARD_USERS = ("Guest", "Administrator") @@ -270,9 +271,8 @@ def get_user_roles(arg=None): @frappe.whitelist() def get_perm_info(arg=None): """get permission info""" - return frappe.db.sql("""select parent, permlevel, `read`, `write`, submit, - cancel, amend from tabDocPerm where role=%s - and docstatus<2 order by parent, permlevel""", + return frappe.db.sql("""select parent, permlevel, `{}` from tabDocPerm where role=%s + and docstatus<2 order by parent, permlevel""".format("`, `".join(frappe.permissions.rights)), (frappe.form_dict['role'],), as_dict=1) @frappe.whitelist(allow_guest=True) diff --git a/frappe/database.py b/frappe/database.py index dff475c9af..d3fd430134 100644 --- a/frappe/database.py +++ b/frappe/database.py @@ -7,8 +7,9 @@ from __future__ import unicode_literals import MySQLdb import warnings -import frappe import datetime +import frappe +import frappe.model.meta from frappe.utils import now, get_datetime from frappe import _ @@ -327,6 +328,9 @@ class Database: return self.get_values_from_single(fields, filters, doctype, as_dict, debug, update) def get_values_from_single(self, fields, filters, doctype, as_dict=False, debug=False, update=None): + if not frappe.model.meta.is_single(doctype): + raise frappe.DoesNotExistError("DocType", doctype) + if fields=="*" or isinstance(filters, dict): # check if single doc matches with filters values = self.get_singles_dict(doctype) diff --git a/frappe/permissions.py b/frappe/permissions.py index 7b04dfa6ca..4dfa1533f0 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -6,8 +6,8 @@ import frappe from frappe import _, msgprint from frappe.utils import cint -rights = ["read", "write", "create", "submit", "cancel", "amend", - "report", "import", "export", "print", "email", "restrict", "delete", "restricted"] +rights = ("read", "write", "create", "submit", "cancel", "amend", + "report", "import", "export", "print", "email", "restrict", "delete", "restricted") def check_admin_or_system_manager(): if ("System Manager" not in frappe.get_roles()) and \ diff --git a/frappe/public/js/frappe/form/toolbar.js b/frappe/public/js/frappe/form/toolbar.js index 35ec1ee800..b8b705e5d6 100644 --- a/frappe/public/js/frappe/form/toolbar.js +++ b/frappe/public/js/frappe/form/toolbar.js @@ -209,34 +209,48 @@ frappe.ui.form.Toolbar = Class.extend({ this.appframe.clear_primary_action(); - if(this.can_submit()) { - status = "Submit"; - } else if(this.can_save()) { - if(!this.frm.save_disabled) { - status = "Save"; - } - } else if(this.can_update()) { - status = "Update"; - } else if(this.can_cancel()) { - status = "Cancel"; - } else if(this.can_amend()) { - status = "Amend"; - } + if (this.can_submit()) { + status = "Submit"; + } else if (this.can_save()) { + if (!this.frm.save_disabled) { + status = "Save"; + } + } else if (this.can_update()) { + status = "Update"; + } else if (this.can_cancel()) { + status = "Cancel"; + } else if (this.can_amend()) { + status = "Amend"; + } + + if (status) { + if (status !== current) { + var perm_to_check = this.frm.action_perm_type_map[status]; + if(!this.frm.perm[0][perm_to_check]) { + return; + } - if(status) { - if(status!==current) { - this.appframe.set_title_right(__(status), { - "Save": function() { me.frm.save('Save', null, this); }, - "Submit": function() { me.frm.savesubmit(this); }, - "Update": function() { me.frm.save('Update', null, this); }, - "Cancel": function() { me.frm.savecancel(this); }, - "Amend": function() { me.frm.amend_doc(); } - }[status], null, status==="Cancel" ? "btn-default" : "btn-primary"); + this.appframe.set_title_right(__(status), { + "Save": function() { + me.frm.save('Save', null, this); + }, + "Submit": function() { + me.frm.savesubmit(this); + }, + "Update": function() { + me.frm.save('Update', null, this); + }, + "Cancel": function() { + me.frm.savecancel(this); + }, + "Amend": function() { + me.frm.amend_doc(); + } + }[status], null, status === "Cancel" ? "btn-default" : "btn-primary"); } - } else { + } else { this.appframe.set_title_right(); } - }, make_cancel_amend_button: function() { var me = this; diff --git a/frappe/public/js/frappe/ui/dialog.js b/frappe/public/js/frappe/ui/dialog.js index 81fbdb57f5..1c8f67de87 100644 --- a/frappe/public/js/frappe/ui/dialog.js +++ b/frappe/public/js/frappe/ui/dialog.js @@ -1,5 +1,5 @@ // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -// MIT License. See license.txt +// MIT License. See license.txt frappe.provide('frappe.ui'); @@ -30,13 +30,15 @@ frappe.ui.Dialog = frappe.ui.FieldGroup.extend({ }, make: function() { this.$wrapper = frappe.get_modal("", ""); - this.wrapper = this.$wrapper.find('.modal-dialog').get(0); + this.wrapper = this.$wrapper.find('.modal-dialog') + .css("width", this.width) + .get(0); this.make_head(); this.body = this.$wrapper.find(".modal-body").get(0); - + // make fields (if any) this._super(); - + var me = this; this.$wrapper .on("hide.bs.modal", function() { @@ -65,8 +67,8 @@ frappe.ui.Dialog = frappe.ui.FieldGroup.extend({ } me.onshow && me.onshow(); }) - - + + }, make_head: function() { var me = this; @@ -94,4 +96,4 @@ $(document).bind('keydown', function(e) { if(cur_dialog && !cur_dialog.no_cancel_flag && e.which==27) { cur_dialog.hide(); } -}); \ No newline at end of file +}); diff --git a/frappe/public/js/frappe/ui/messages.js b/frappe/public/js/frappe/ui/messages.js index 99ffdfd929..106050387c 100644 --- a/frappe/public/js/frappe/ui/messages.js +++ b/frappe/public/js/frappe/ui/messages.js @@ -99,6 +99,9 @@ function msgprint(msg, title) { if(msg_dialog.msg_area.html()) msg_dialog.msg_area.append("
"); msg_dialog.msg_area.append(msg); + + // make msgprint always appear on top + msg_dialog.$wrapper.css("z-index", 2000); msg_dialog.show(); return msg_dialog; diff --git a/frappe/public/js/legacy/form.js b/frappe/public/js/legacy/form.js index 39dd17be75..56d887d334 100644 --- a/frappe/public/js/legacy/form.js +++ b/frappe/public/js/legacy/form.js @@ -570,11 +570,7 @@ _f.Frm.prototype.runscript = function(scriptname, callingfield, onrefresh) { } _f.Frm.prototype.copy_doc = function(onload, from_amend) { - if(!this.perm[0].create) { - msgprint(__('You are not allowed to create {0}', [this.meta.name])); - return; - } - + this.validate_form_action("Create"); var newdoc = frappe.model.copy_doc(this.doc, from_amend); newdoc.idx = null; @@ -609,6 +605,8 @@ _f.Frm.prototype.save = function(save_action, callback, btn, on_error) { _f.Frm.prototype._save = function(save_action, callback, btn, on_error) { var me = this; + if(!save_action) save_action = "Save"; + this.validate_form_action(save_action); if((!this.meta.in_dialog || this.in_form) && !this.meta.istable) scroll(0, 0); @@ -641,12 +639,13 @@ _f.Frm.prototype._save = function(save_action, callback, btn, on_error) { } } - frappe.ui.form.save(me, save_action || "Save", after_save, btn); + frappe.ui.form.save(me, save_action, after_save, btn); } _f.Frm.prototype.savesubmit = function(btn, on_error) { var me = this; + this.validate_form_action("Submit"); frappe.confirm(__("Permanently Submit {0}?", [this.docname]), function() { validated = true; me.script_manager.trigger("before_submit"); @@ -662,10 +661,11 @@ _f.Frm.prototype.savesubmit = function(btn, on_error) { } }, btn, on_error); }); -} +}; _f.Frm.prototype.savecancel = function(btn, on_error) { var me = this; + this.validate_form_action('Cancel'); frappe.confirm(__("Permanently Cancel {0}?", [this.docname]), function() { validated = true; me.script_manager.trigger("before_cancel"); @@ -689,6 +689,7 @@ _f.Frm.prototype.savecancel = function(btn, on_error) { // delete the record _f.Frm.prototype.savetrash = function() { + this.validate_form_action("Delete"); frappe.model.delete_doc(this.doctype, this.docname, function(r) { window.history.back(); }) @@ -699,6 +700,7 @@ _f.Frm.prototype.amend_doc = function() { alert('"amended_from" field must be present to do an amendment.'); return; } + this.validate_form_action("Amend"); var me = this; var fn = function(newdoc) { newdoc.amended_from = me.docname; @@ -770,3 +772,21 @@ _f.Frm.prototype.add_fetch = function(link_field, src_field, tar_field) { _f.Frm.prototype.set_print_heading = function(txt) { this.pformat[cur_frm.docname] = txt; } + +_f.Frm.prototype.action_perm_type_map = { + "Create": "create", + "Save": "write", + "Submit": "submit", + "Update": "submit", + "Cancel": "cancel", + "Amend": "amend", + "Delete": "delete" +}; + +_f.Frm.prototype.validate_form_action = function(action) { + var perm_to_check = this.action_perm_type_map[action]; + + if (!this.perm[0][perm_to_check]) { + frappe.throw (__("No permission to '{0}' {1}", [__(action), __(this.doc.doctype)])); + } +}; diff --git a/frappe/widgets/form/load.py b/frappe/widgets/form/load.py index 18e928a077..b81e2a4bd4 100644 --- a/frappe/widgets/form/load.py +++ b/frappe/widgets/form/load.py @@ -30,7 +30,7 @@ def getdoc(doctype, name, user=None): doc.run_method("onload") if not doc.has_permission("read"): - raise frappe.PermissionError + raise frappe.PermissionError, "read" # add file list get_docinfo(doctype, name)