Check permission on client side form actions like Save, Submit etc. and also while creating buttons for these actions
This commit is contained in:
parent
adbcd41497
commit
cded652e9e
11 changed files with 130 additions and 60 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -218,15 +218,28 @@ frappe.RoleEditor = Class.extend({
|
|||
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) {
|
||||
// TODO fix the overflow issue and also display perms like report, import, etc.
|
||||
|
||||
$body.append('<table class="user-perm"><thead><tr>'
|
||||
+ '<th style="text-align: left">' + __('Document Type') + '</th>'
|
||||
+ '<th>' + __('Level') + '</th>'
|
||||
+ '<th>' + __('Read') + '</th>'
|
||||
+ '<th>' + __('Only Restricted Documents') + '</th>'
|
||||
+ '<th>' + __('Write') + '</th>'
|
||||
+ '<th>' + __('Create') + '</th>'
|
||||
+ '<th>' + __('Delete') + '</th>'
|
||||
+ '<th>' + __('Submit') + '</th>'
|
||||
+ '<th>' + __('Cancel') + '</th>'
|
||||
+ '<th>' + __('Amend') + '</th>'
|
||||
// + '<th>' + __('Report') + '</th>'
|
||||
// + '<th>' + __('Import') + '</th>'
|
||||
// + '<th>' + __('Export') + '</th>'
|
||||
// + '<th>' + __('Print') + '</th>'
|
||||
// + '<th>' + __('Email') + '</th>'
|
||||
+ '<th>' + __('Can Restrict') + '</th>'
|
||||
+ '</tr></thead><tbody></tbody></table>');
|
||||
|
||||
for(var i=0, l=r.message.length; i<l; i++) {
|
||||
var perm = r.message[i];
|
||||
|
||||
// if permission -> icon
|
||||
|
|
@ -244,10 +257,19 @@ frappe.RoleEditor = Class.extend({
|
|||
<td style="text-align: left">%(parent)s</td>\
|
||||
<td>%(permlevel)s</td>\
|
||||
<td>%(read)s</td>\
|
||||
<td>%(restricted)s</td>\
|
||||
<td>%(write)s</td>\
|
||||
<td>%(create)s</td>\
|
||||
<td>%(delete)s</td>\
|
||||
<td>%(submit)s</td>\
|
||||
<td>%(cancel)s</td>\
|
||||
<td>%(amend)s</td>\
|
||||
<td>%(amend)s</td>'
|
||||
// + '<td>%(report)s</td>\
|
||||
// <td>%(import)s</td>\
|
||||
// <td>%(export)s</td>\
|
||||
// <td>%(print)s</td>\
|
||||
// <td>%(email)s</td>'
|
||||
+ '<td>%(restrict)s</td>\
|
||||
</tr>', 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"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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(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");
|
||||
if (this.can_submit()) {
|
||||
status = "Submit";
|
||||
} else if (this.can_save()) {
|
||||
if (!this.frm.save_disabled) {
|
||||
status = "Save";
|
||||
}
|
||||
} else {
|
||||
this.appframe.set_title_right();
|
||||
} 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;
|
||||
}
|
||||
|
||||
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 {
|
||||
this.appframe.set_title_right();
|
||||
}
|
||||
},
|
||||
make_cancel_amend_button: function() {
|
||||
var me = this;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -99,6 +99,9 @@ function msgprint(msg, title) {
|
|||
if(msg_dialog.msg_area.html()) msg_dialog.msg_area.append("<hr>");
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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)]));
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue