浏览代码

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

version-14
Anand Doshi 11 年前
父节点
当前提交
cded652e9e
共有 11 个文件被更改,包括 129 次插入59 次删除
  1. +4
    -3
      frappe/core/doctype/docperm/docperm.json
  2. +4
    -0
      frappe/core/doctype/user/user.css
  3. +33
    -11
      frappe/core/doctype/user/user.js
  4. +3
    -3
      frappe/core/doctype/user/user.py
  5. +5
    -1
      frappe/database.py
  6. +2
    -2
      frappe/permissions.py
  7. +38
    -24
      frappe/public/js/frappe/form/toolbar.js
  8. +9
    -7
      frappe/public/js/frappe/ui/dialog.js
  9. +3
    -0
      frappe/public/js/frappe/ui/messages.js
  10. +27
    -7
      frappe/public/js/legacy/form.js
  11. +1
    -1
      frappe/widgets/form/load.py

+ 4
- 3
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
}

+ 4
- 0
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 {


+ 33
- 11
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('<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"
});
}
});

+ 3
- 3
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)


+ 5
- 1
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)


+ 2
- 2
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 \


+ 38
- 24
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;


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

+ 3
- 0
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("<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;


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

+ 1
- 1
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)


正在加载...
取消
保存