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 Type | \
- Level | \
- Read | \
- Write | \
- Submit | \
- Cancel | \
- Amend |
');
- 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)