Check permission on client side form actions like Save, Submit etc. and also while creating buttons for these actions

This commit is contained in:
Anand Doshi 2014-04-30 14:58:17 +05:30
parent adbcd41497
commit cded652e9e
11 changed files with 130 additions and 60 deletions

View file

@ -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
}

View file

@ -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 {

View file

@ -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"
});
}
});

View file

@ -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)

View file

@ -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)

View file

@ -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 \

View file

@ -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;

View file

@ -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();
}
});
});

View file

@ -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;

View file

@ -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)]));
}
};

View file

@ -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)