diff --git a/frappe/config/setup.py b/frappe/config/setup.py
index 1a8079f1ed..389757e632 100644
--- a/frappe/config/setup.py
+++ b/frappe/config/setup.py
@@ -20,7 +20,7 @@ def get_data():
{
"type": "page",
"name": "permission-manager",
- "label": "Role Permissions Manager",
+ "label": _("Role Permissions Manager"),
"icon": "icon-lock",
"description": _("Set Permissions on Document Types and Roles")
},
diff --git a/frappe/core/doctype/docperm/docperm.json b/frappe/core/doctype/docperm/docperm.json
index f575e9f08d..4a57765d3b 100644
--- a/frappe/core/doctype/docperm/docperm.json
+++ b/frappe/core/doctype/docperm/docperm.json
@@ -53,6 +53,15 @@
"search_index": 0,
"width": "40px"
},
+ {
+ "depends_on": "",
+ "description": "JSON list of DocTypes used to apply User Permissions. If empty, all linked DocTypes will be used to apply User Permissions.",
+ "fieldname": "user_permission_doctypes",
+ "fieldtype": "Text",
+ "label": "User Permission DocTypes",
+ "permlevel": 0,
+ "read_only": 1
+ },
{
"fieldname": "section_break_4",
"fieldtype": "Section Break",
@@ -207,7 +216,7 @@
"idx": 1,
"issingle": 0,
"istable": 1,
- "modified": "2014-05-26 03:46:53.737397",
+ "modified": "2014-08-26 01:43:31.499363",
"modified_by": "Administrator",
"module": "Core",
"name": "DocPerm",
diff --git a/frappe/core/page/permission_manager/permission_manager.js b/frappe/core/page/permission_manager/permission_manager.js
index 44314b9ca8..36ff5b7e8d 100644
--- a/frappe/core/page/permission_manager/permission_manager.js
+++ b/frappe/core/page/permission_manager/permission_manager.js
@@ -41,13 +41,13 @@ frappe.PermissionEngine = Class.extend({
setup_appframe: function() {
var me = this;
this.doctype_select
- = this.wrapper.appframe.add_select("doctypes",
+ = this.wrapper.appframe.add_select(__("Document Types"),
[{value: "", label: __("Select Document Type")+"..."}].concat(this.options.doctypes))
.change(function() {
frappe.set_route("permission-manager", $(this).val());
});
this.role_select
- = this.wrapper.appframe.add_select("roles",
+ = this.wrapper.appframe.add_select(__("Roles"),
[__("Select Role")+"..."].concat(this.options.roles))
.change(function() {
me.refresh();
@@ -95,7 +95,7 @@ frappe.PermissionEngine = Class.extend({
page:"permission_manager",
method:"reset",
args: {
- doctype:me.get_doctype(),
+ doctype: me.get_doctype(),
},
callback: function() { me.refresh(); }
});
@@ -130,7 +130,7 @@ frappe.PermissionEngine = Class.extend({
refresh: function() {
var me = this;
if(!me.doctype_select) {
- this.body.html("
Loading...
");
+ this.body.html("" + __("Loading") + "...
");
return;
}
if(!me.get_doctype() && !me.get_role()) {
@@ -164,6 +164,7 @@ frappe.PermissionEngine = Class.extend({
this.make_reset_button();
},
show_permission_table: function(perm_list) {
+
var me = this;
this.table = $("").appendTo(me.table.find("tbody"));
- add_cell(row, d, "parent");
- var role_cell = add_cell(row, d, "role");
+ me.add_cell(row, d, "parent");
+ var role_cell = me.add_cell(row, d, "role");
me.set_show_users(role_cell, d.role);
if (d.permlevel===0) {
- d.help = '';
- add_check(role_cell, d, "apply_user_permissions")
- .removeClass("col-md-4")
- .css({"margin-top": "15px"});
- d.help = "";
+ me.setup_user_permissions(d, role_cell);
}
- var cell = add_cell(row, d, "permlevel");
+ var cell = me.add_cell(row, d, "permlevel");
if(d.permlevel==0) {
cell.css("font-weight", "bold");
row.addClass("warning");
}
- var perm_cell = add_cell(row, d, "permissions").css("padding-top", 0);
+ var perm_cell = me.add_cell(row, d, "permissions").css("padding-top", 0);
var perm_container = $("").appendTo(perm_cell);
$.each(me.rights, function(i, r) {
- add_check(perm_container, d, r);
+ me.add_check(perm_container, d, r);
});
// buttons
me.add_delete_button(row, d);
});
},
+
+ add_cell: function(row, d, fieldname) {
+ return $("").appendTo(row)
+ .attr("data-fieldname", fieldname)
+ .html(__(d[fieldname]));
+ },
+
+ add_check: function(cell, d, fieldname, label) {
+ var me = this;
+
+ if(!label) label = toTitle(fieldname.replace(/_/g, " "));
+ if(d.permlevel > 0 && ["read", "write"].indexOf(fieldname)==-1) {
+ return;
+ }
+
+ var checkbox = $("").appendTo(cell)
+ .attr("data-fieldname", fieldname);
+
+ checkbox.find("input")
+ .prop("checked", d[fieldname] ? true: false)
+ .attr("data-ptype", fieldname)
+ .attr("data-name", d.name)
+ .attr("data-doctype", d.parent)
+
+ checkbox.find("label")
+ .css("text-transform", "capitalize");
+
+ return checkbox;
+ },
+
+ setup_user_permissions: function(d, role_cell) {
+ var me = this;
+ d.help = frappe.render('', {});
+
+ var checkbox = this.add_check(role_cell, d, "apply_user_permissions")
+ .removeClass("col-md-4")
+ .css({"margin-top": "15px"});
+
+ checkbox.find(".show-user-permission-doctypes").on("click", function() {
+ me.show_user_permission_doctypes(d);
+ });
+
+ var toggle_user_permissions = function() {
+ checkbox.find(".user-permission-help").toggleClass("hidden", !checkbox.find("input").prop("checked"));
+ };
+
+ toggle_user_permissions();
+ checkbox.find("input").on('click', function() {
+ toggle_user_permissions();
+ });
+
+ d.help = "";
+ },
+
rights: ["read", "write", "create", "delete", "submit", "cancel", "amend",
"print", "email", "report", "import", "export", "set_user_permissions"],
set_show_users: function(cell, role) {
- cell.html(""+role+"")
+ cell.html(""+__(role)+"")
.find("a")
.attr("data-role", role)
.click(function() {
@@ -331,14 +359,14 @@ frappe.PermissionEngine = Class.extend({
var d = new frappe.ui.Dialog({
title: __("Add New Permission Rule"),
fields: [
- {fieldtype:"Select", label:"Document Type",
+ {fieldtype:"Select", label:__("Document Type"),
options:me.options.doctypes, reqd:1, fieldname:"parent"},
- {fieldtype:"Select", label:"Role",
+ {fieldtype:"Select", label:__("Role"),
options:me.options.roles, reqd:1},
- {fieldtype:"Select", label:"Permission Level",
+ {fieldtype:"Select", label:__("Permission Level"),
options:[0,1,2,3,4,5,6,7,8,9], reqd:1, fieldname: "permlevel",
description: __("Level 0 is for document level permissions, higher levels for field level permissions.")},
- {fieldtype:"Button", label:"Add"},
+ {fieldtype:"Button", label:__("Add")},
]
});
if(me.get_doctype()) {
@@ -374,10 +402,86 @@ frappe.PermissionEngine = Class.extend({
});
},
+ show_user_permission_doctypes: function(d) {
+ if (!d.dialog) {
+ var fields = [];
+ for (var i=0, l=d.linked_doctypes.length; i\
- Restore Original Permissions')
+ ' + __("Restore Original Permissions") + '')
.appendTo(this.body.find(".permission-toolbar"))
.on("click", function() {
me.get_standard_permissions(function(data) {
@@ -478,6 +582,9 @@ var permissions_help = ['' + __('Setup > User Permissions Manager') + ')',
'',
+ '',
+ __("Select Document Types to set which User Permissions are used to limit access."),
+ '',
'',
__("Once you have set this, the users will only be able access documents (eg. Blog Post) where the link exists (eg. Blogger)."),
'',
diff --git a/frappe/core/page/permission_manager/permission_manager.py b/frappe/core/page/permission_manager/permission_manager.py
index 6ae405f9ca..43c8531791 100644
--- a/frappe/core/page/permission_manager/permission_manager.py
+++ b/frappe/core/page/permission_manager/permission_manager.py
@@ -5,11 +5,13 @@ from __future__ import unicode_literals
import frappe
import frappe.defaults
from frappe.modules.import_file import get_file_path, read_doc_from_file
+from frappe.translate import send_translations
from frappe.core.doctype.notification_count.notification_count import delete_notification_count_for
@frappe.whitelist()
def get_roles_and_doctypes():
frappe.only_for("System Manager")
+ send_translations(frappe.get_lang_dict("doctype", "DocPerm"))
return {
"doctypes": [d[0] for d in frappe.db.sql("""select name from `tabDocType` dt where
ifnull(istable,0)=0 and
@@ -22,12 +24,27 @@ def get_roles_and_doctypes():
@frappe.whitelist()
def get_permissions(doctype=None, role=None):
frappe.only_for("System Manager")
- return frappe.db.sql("""select * from tabDocPerm
+ out = frappe.db.sql("""select * from tabDocPerm
where %s%s order by parent, permlevel, role""" %
(doctype and (" parent='%s'" % doctype.replace("'", "\'")) or "",
role and ((doctype and " and " or "") + " role='%s'" % role.replace("'", "\'")) or ""),
as_dict=True)
+ def get_linked_doctypes(dt):
+ return list(set([dt] + [d.options for d in
+ frappe.get_meta(dt).get("fields", {
+ "fieldtype":"Link",
+ "ignore_user_permissions":("!=", 1),
+ "options": ("!=", "[Select]")
+ })
+ ]))
+
+ linked_doctypes = {}
+ for d in out:
+ d.linked_doctypes = linked_doctypes.setdefault(d.parent, get_linked_doctypes(d.parent))
+
+ return out
+
@frappe.whitelist()
def remove(doctype, name):
frappe.only_for("System Manager")
@@ -51,7 +68,7 @@ def add(parent, role, permlevel):
validate_and_reset(parent)
@frappe.whitelist()
-def update(name, doctype, ptype, value=0):
+def update(name, doctype, ptype, value=None):
frappe.only_for("System Manager")
frappe.db.sql("""update tabDocPerm set `%s`=%s where name=%s"""\
% (ptype, '%s', '%s'), (value, name))
@@ -88,6 +105,7 @@ def get_users_with_role(role):
@frappe.whitelist()
def get_standard_permissions(doctype):
+ frappe.only_for("System Manager")
module = frappe.db.get_value("DocType", doctype, "module")
path = get_file_path(module, "DocType", doctype)
return read_doc_from_file(path).get("permissions")
diff --git a/frappe/model/db_query.py b/frappe/model/db_query.py
index 334710bed0..b5c091dade 100644
--- a/frappe/model/db_query.py
+++ b/frappe/model/db_query.py
@@ -15,7 +15,7 @@ class DatabaseQuery(object):
self.doctype = doctype
self.tables = []
self.conditions = []
- self.fields = ["name"]
+ self.fields = ["`tab{0}`.`name`".format(doctype)]
self.user = None
self.ignore_permissions = False
@@ -223,15 +223,18 @@ class DatabaseQuery(object):
if role_permissions.get("apply_user_permissions", {}).get("read"):
# get user permissions
user_permissions = frappe.defaults.get_user_permissions(self.user)
- self.add_user_permissions(user_permissions)
+ self.add_user_permissions(user_permissions,
+ user_permission_doctypes=role_permissions.get("user_permission_doctypes"))
if as_condition:
return self.build_match_condition_string()
else:
return self.match_filters
- def add_user_permissions(self, user_permissions):
- fields_to_check = frappe.get_meta(self.doctype).get_fields_to_check_permissions(user_permissions.keys())
+ def add_user_permissions(self, user_permissions, user_permission_doctypes=None):
+ user_permission_doctypes = frappe.permissions.get_user_permission_doctypes(user_permission_doctypes,
+ user_permissions)
+ fields_to_check = frappe.get_meta(self.doctype).get_fields_to_check_permissions(user_permission_doctypes)
# check in links
for df in fields_to_check:
diff --git a/frappe/model/meta.py b/frappe/model/meta.py
index 8387170179..bbc8154c26 100644
--- a/frappe/model/meta.py
+++ b/frappe/model/meta.py
@@ -194,15 +194,15 @@ class Meta(Document):
self.set("fields", newlist)
- def get_fields_to_check_permissions(self, user_permissions_doctypes):
+ def get_fields_to_check_permissions(self, user_permission_doctypes):
fields = self.get("fields", {
"fieldtype":"Link",
"parent": self.name,
"ignore_user_permissions":("!=", 1),
- "options":("in", user_permissions_doctypes)
+ "options":("in", user_permission_doctypes)
})
- if self.name in user_permissions_doctypes:
+ if self.name in user_permission_doctypes:
fields.append(frappe._dict({
"label":"Name",
"fieldname":"name",
diff --git a/frappe/permissions.py b/frappe/permissions.py
index 1085c17181..f1f85d50d1 100644
--- a/frappe/permissions.py
+++ b/frappe/permissions.py
@@ -2,7 +2,7 @@
# MIT License. See license.txt
from __future__ import unicode_literals
-import frappe, copy
+import frappe, copy, json
from frappe import _, msgprint
from frappe.utils import cint
@@ -42,7 +42,8 @@ def has_permission(doctype, ptype="read", doc=None, verbose=True, user=None):
doc = frappe.get_doc(meta.name, doc)
if role_permissions["apply_user_permissions"].get(ptype):
- if not user_has_permission(doc, verbose=verbose, user=user):
+ if not user_has_permission(doc, verbose=verbose, user=user,
+ user_permission_doctypes=role_permissions.get("user_permission_doctypes")):
return False
if not has_controller_permissions(doc, ptype, user=user):
@@ -66,7 +67,8 @@ def get_doc_permissions(doc, verbose=False, user=None):
if not cint(meta.allow_import):
role_permissions["import"] = 0
- if not user_has_permission(doc, verbose=verbose, user=user):
+ if not user_has_permission(doc, verbose=verbose, user=user,
+ user_permission_doctypes=role_permissions.get("user_permission_doctypes")):
# no user permissions, switch off all user-level permissions
for ptype in role_permissions:
if role_permissions["apply_user_permissions"].get(ptype):
@@ -88,7 +90,20 @@ def get_role_permissions(meta, user=None):
perms[ptype] = perms.get(ptype, 0) or cint(p.get(ptype))
if ptype != "set_user_permissions" and p.get(ptype):
- perms["apply_user_permissions"][ptype] = perms["apply_user_permissions"].get(ptype, 1) and p.get("apply_user_permissions")
+ perms["apply_user_permissions"][ptype] = (perms["apply_user_permissions"].get(ptype, 1)
+ and p.get("apply_user_permissions"))
+
+ if p.apply_user_permissions and p.user_permission_doctypes:
+ # set user_permission_doctypes in perms
+ user_permission_doctypes = (json.loads(p.user_permission_doctypes)
+ if p.user_permission_doctypes else None)
+
+ if user_permission_doctypes and (not perms.get("user_permission_doctypes") or
+ len(user_permission_doctypes) <= len(perms["user_permission_doctypes"])):
+ # selecting the least no. of "user_permission_doctypes" for lesser filtering
+ # why? if there is a conflict of two user_permission_doctypes, the least restrictive should win
+ # hence, using the simplistic approach of less no. of "user_permission_doctypes" implies least restrictive!
+ perms["user_permission_doctypes"] = user_permission_doctypes
for key, value in perms.get("apply_user_permissions").items():
if not value:
@@ -98,16 +113,17 @@ def get_role_permissions(meta, user=None):
return frappe.local.role_permissions[cache_key]
-def user_has_permission(doc, verbose=True, user=None):
+def user_has_permission(doc, verbose=True, user=None, user_permission_doctypes=None):
from frappe.defaults import get_user_permissions
user_permissions = get_user_permissions(user)
- user_permissions_keys = user_permissions.keys()
+ user_permission_doctypes = get_user_permission_doctypes(user_permission_doctypes, user_permissions)
def check_user_permission(d):
result = True
meta = frappe.get_meta(d.get("doctype"))
- for df in meta.get_fields_to_check_permissions(user_permissions_keys):
- if d.get(df.fieldname) and d.get(df.fieldname) not in user_permissions[df.options]:
+ for df in meta.get_fields_to_check_permissions(user_permission_doctypes):
+ if (df.options in user_permissions and d.get(df.fieldname)
+ and d.get(df.fieldname) not in user_permissions[df.options]):
result = False
if verbose:
@@ -192,3 +208,12 @@ def apply_user_permissions(doctype, ptype, user=None):
"""Check if apply_user_permissions is checked for a doctype, perm type, user combination"""
role_permissions = get_role_permissions(frappe.get_meta(doctype), user=user)
return role_permissions.get("apply_user_permissions", {}).get(ptype)
+
+def get_user_permission_doctypes(user_permission_doctypes, user_permissions):
+ if user_permission_doctypes:
+ # select those user permission doctypes for which user permissions exist!
+ user_permission_doctypes = list(set(user_permission_doctypes).intersection(set(user_permissions.keys())))
+ else:
+ user_permission_doctypes = user_permissions.keys()
+
+ return user_permission_doctypes
diff --git a/frappe/public/js/frappe/model/meta.js b/frappe/public/js/frappe/model/meta.js
index f886a7e5b9..4ab3bfbbf0 100644
--- a/frappe/public/js/frappe/model/meta.js
+++ b/frappe/public/js/frappe/model/meta.js
@@ -62,14 +62,13 @@ $.extend(frappe.meta, {
return docfields;
},
- get_fields_to_check_permissions: function(doctype, name, user_permissions) {
- var user_permissions_doctypes = Object.keys(user_permissions);
+ get_fields_to_check_permissions: function(doctype, name, user_permission_doctypes) {
var fields = $.map(frappe.meta.get_docfields(doctype, name), function(df) {
return (df.fieldtype==="Link" && df.ignore_user_permissions!==1 &&
- user_permissions_doctypes.indexOf(df.options)!==-1) ? df : null;
+ user_permission_doctypes.indexOf(df.options)!==-1) ? df : null;
});
- if (user_permissions_doctypes.indexOf(doctype)!==-1) {
+ if (user_permission_doctypes.indexOf(doctype)!==-1) {
fields = fields.concat({label: "Name", fieldname: name, options: doctype});
}
diff --git a/frappe/public/js/frappe/model/perm.js b/frappe/public/js/frappe/model/perm.js
index 09dcd62b13..eb3174e24d 100644
--- a/frappe/public/js/frappe/model/perm.js
+++ b/frappe/public/js/frappe/model/perm.js
@@ -82,6 +82,20 @@ $.extend(frappe.perm, {
apply_user_permissions[key] = current_value && p.apply_user_permissions;
}
});
+
+ if (permlevel===0 && p.apply_user_permissions && p.user_permission_doctypes) {
+ // set user_permission_doctypes in perms
+ var user_permission_doctypes = p.user_permission_doctypes
+ ? JSON.parse(p.user_permission_doctypes) : null;
+
+ if (user_permission_doctypes && (!perm[permlevel].user_permission_doctypes ||
+ user_permission_doctypes.length <= perm[permlevel].user_permission_doctypes.length)) {
+ // selecting the least no. of "user_permission_doctypes" for lesser filtering
+ // why? if there is a conflict of two user_permission_doctypes, the least restrictive should win
+ // hence, using the simplistic approach of less no. of "user_permission_doctypes" implies least restrictive!
+ perm[permlevel]["user_permission_doctypes"] = user_permission_doctypes;
+ }
+ }
}
});
@@ -94,6 +108,8 @@ $.extend(frappe.perm, {
},
get_match_rules: function(doctype, ptype) {
+ var me = this;
+
if (!ptype) ptype = "read";
var perm = frappe.perm.get_perm(doctype);
@@ -105,7 +121,10 @@ $.extend(frappe.perm, {
var match_rules = {};
var user_permissions = frappe.defaults.get_user_permissions();
if(user_permissions && !$.isEmptyObject(user_permissions)) {
- var fields_to_check = frappe.meta.get_fields_to_check_permissions(doctype, null, user_permissions);
+ var user_permission_doctypes = me.get_user_permission_doctypes(perm[0].user_permission_doctypes,
+ user_permissions);
+
+ var fields_to_check = frappe.meta.get_fields_to_check_permissions(doctype, null, user_permission_doctypes);
$.each(fields_to_check, function(i, df) {
match_rules[df.label] = user_permissions[df.options];
});
@@ -114,6 +133,20 @@ $.extend(frappe.perm, {
return match_rules;
},
+ get_user_permission_doctypes: function(user_permission_doctypes, user_permissions) {
+ if (user_permission_doctypes) {
+ var out = [];
+ $.each(user_permission_doctypes, function(i, doctype) {
+ if (user_permissions[doctype]) {
+ out.push(doctype);
+ }
+ });
+ return out;
+ } else {
+ return Object.keys(user_permissions);
+ }
+ },
+
get_field_display_status: function(df, doc, perm, explain) {
if(!doc) return "Write";
diff --git a/frappe/public/js/frappe/ui/appframe.js b/frappe/public/js/frappe/ui/appframe.js
index 186fa57073..1f53dae77b 100644
--- a/frappe/public/js/frappe/ui/appframe.js
+++ b/frappe/public/js/frappe/ui/appframe.js
@@ -116,7 +116,8 @@ frappe.ui.AppFrame = Class.extend({
views.push({
icon: module_info.icon,
route: "Module/" + meta.module,
- type: "module"
+ type: "module",
+ label: __("Module")
})
}
@@ -124,6 +125,7 @@ frappe.ui.AppFrame = Class.extend({
icon: "icon-file-alt",
route: "",
type: "form",
+ label: __("Form"),
set_route: function() {
console.log(me.doctype);
if(frappe.views.formview[me.doctype]) {
@@ -140,7 +142,8 @@ frappe.ui.AppFrame = Class.extend({
views.push({
icon: "icon-list",
route: "List/" + doctype,
- type: "list"
+ type: "list",
+ label: __("List")
});
}
@@ -148,7 +151,8 @@ frappe.ui.AppFrame = Class.extend({
views.push({
icon: "icon-calendar",
route: "Calendar/" + doctype,
- type: "calendar"
+ type: "calendar",
+ label: __("Calendar")
});
}
@@ -156,7 +160,8 @@ frappe.ui.AppFrame = Class.extend({
views.push({
icon: "icon-tasks",
route: "Gantt/" + doctype,
- type: "gantt"
+ type: "gantt",
+ label: __("Gantt Chart")
});
}
@@ -164,7 +169,8 @@ frappe.ui.AppFrame = Class.extend({
views.push({
icon: "icon-table",
route: "Report/" + doctype,
- type: "report"
+ type: "report",
+ label: __("Report")
});
}
@@ -174,7 +180,7 @@ frappe.ui.AppFrame = Class.extend({
set_views: function(views, active_view) {
var me = this;
$.each(views, function(i, e) {
- var btn = me.add_icon_btn("3", e.icon, __(toTitle(e.type)), e.set_route || function() {
+ var btn = me.add_icon_btn("3", e.icon, __(e.label) || __(toTitle(e.type)), e.set_route || function() {
window.location.hash = "#" + $(this).attr("data-route");
}).attr("data-route", e.route);
diff --git a/frappe/public/js/frappe/views/doclistview.js b/frappe/public/js/frappe/views/doclistview.js
index 8a55d84269..56a1328035 100644
--- a/frappe/public/js/frappe/views/doclistview.js
+++ b/frappe/public/js/frappe/views/doclistview.js
@@ -63,7 +63,7 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
this.appframe = this.page.appframe;
var module = locals.DocType[this.doctype].module;
- this.appframe.set_title(__("{0} List", [this.doctype]));
+ this.appframe.set_title(__("{0} List", [__(this.doctype)]));
this.appframe.add_module_icon(module, this.doctype, null, true);
this.appframe.set_title_left(function() {
frappe.set_route(frappe.listview_parent_route[me.doctype]
@@ -253,14 +253,11 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
make_no_result: function() {
var new_button = frappe.boot.user.can_create.indexOf(this.doctype)!=-1
? (' ')
+ list_view_doc="' + this.doctype + '">'+
+ __('Make a new {0}', [__(this.doctype)]) + '')
: '';
- var no_result_message = repl('\
- ' + __("No") + ' %(doctype_label)s ' + __("found") + ' ' + new_button + ' ', {
- doctype_label: __(this.doctype),
- doctype: this.doctype,
- });
+ var no_result_message = '\
+ ' + __("No {0} found", [__(this.doctype)]) + ' ' + new_button + ' ';
return no_result_message;
},
diff --git a/frappe/translate.py b/frappe/translate.py
index 62c26a35f1..741fe41658 100644
--- a/frappe/translate.py
+++ b/frappe/translate.py
@@ -106,6 +106,7 @@ def get_dict(fortype, name=None):
elif fortype=="boot":
messages = get_messages_from_include_files()
messages += frappe.db.sql_list("select name from tabDocType")
+ messages += frappe.db.sql_list("select name from tabRole")
messages += frappe.db.sql_list("select name from `tabModule Def`")
translation_assets[asset_key] = make_dict_from_messages(messages)
@@ -193,6 +194,7 @@ def get_messages_from_doctype(name):
messages = [meta.name, meta.module]
+ # translations of field labels, description and options
for d in meta.get("fields"):
messages.extend([d.label, d.description])
@@ -202,6 +204,11 @@ def get_messages_from_doctype(name):
if not "icon" in options[0]:
messages.extend(options)
+ # translations of roles
+ for d in meta.get("permissions"):
+ if d.role:
+ messages.append(d.role)
+
# extract from js, py files
doctype_file_path = frappe.get_module_path(meta.module, "doctype", meta.name, meta.name)
messages.extend(get_messages_from_file(doctype_file_path + ".js"))
@@ -301,6 +308,8 @@ def get_untranslated(lang, untranslated_file, get_all=False):
for app in apps:
messages.extend(get_messages_for_app(app))
+ messages = list(set(messages))
+
def escape_newlines(s):
return (s.replace("\\\n", "|||||")
.replace("\\n", "||||")
@@ -366,3 +375,10 @@ def write_translations_file(app, lang, full_dict=None):
frappe.create_folder(tpath)
write_csv_file(os.path.join(tpath, lang + ".csv"),
app_messages, full_dict or get_full_dict(lang))
+
+def send_translations(translation_dict):
+ """send these translations in response"""
+ if "__messages" not in frappe.local.response:
+ frappe.local.response["__messages"] = {}
+
+ frappe.local.response["__messages"].update(translation_dict)
diff --git a/frappe/utils/response.py b/frappe/utils/response.py
index 9c8db420f8..1a7b8754a5 100644
--- a/frappe/utils/response.py
+++ b/frappe/utils/response.py
@@ -43,14 +43,14 @@ def build_response(response_type=None):
def as_csv():
response = Response()
response.headers[b"Content-Type"] = b"text/csv; charset: utf-8"
- response.headers[b"Content-Disposition"] = ("attachment; filename=%s.csv" % frappe.response['doctype'].replace(' ', '_')).encode("utf-8")
+ response.headers[b"Content-Disposition"] = ("attachment; filename=\"%s.csv\"" % frappe.response['doctype'].replace(' ', '_')).encode("utf-8")
response.data = frappe.response['result']
return response
def as_raw():
response = Response()
response.headers[b"Content-Type"] = frappe.response.get("content_type") or mimetypes.guess_type(frappe.response['filename'])[0] or b"application/unknown"
- response.headers[b"Content-Disposition"] = ("filename=%s" % frappe.response['filename'].replace(' ', '_')).encode("utf-8")
+ response.headers[b"Content-Disposition"] = ("filename=\"%s\"" % frappe.response['filename'].replace(' ', '_')).encode("utf-8")
response.data = frappe.response['filecontent']
return response
diff --git a/frappe/website/doctype/blog_post/test_blog_post.py b/frappe/website/doctype/blog_post/test_blog_post.py
index ce48b53ab7..187daeeba2 100644
--- a/frappe/website/doctype/blog_post/test_blog_post.py
+++ b/frappe/website/doctype/blog_post/test_blog_post.py
@@ -6,6 +6,8 @@
import frappe
import frappe.defaults
import unittest
+import json
+import frappe.model.meta
from frappe.core.page.user_permissions.user_permissions import add, remove, get_permissions
from frappe.permissions import clear_user_permissions_for_doctype, get_doc_permissions
@@ -30,6 +32,9 @@ class TestBlogPost(unittest.TestCase):
clear_user_permissions_for_doctype("Blog Category")
clear_user_permissions_for_doctype("Blog Post")
clear_user_permissions_for_doctype("Blogger")
+ frappe.db.sql("""update `tabDocPerm` set user_permission_doctypes=null
+ where parent='Blog Post' and permlevel=0 and apply_user_permissions=1
+ and `read`=1""")
def test_basic_permission(self):
post = frappe.get_doc("Blog Post", "_test-blog-post")
@@ -145,3 +150,25 @@ class TestBlogPost(unittest.TestCase):
doc.title = "New"
self.assertRaises(frappe.CannotChangeConstantError, doc.save)
blog_post.get_field("title").set_only_once = 0
+
+ def test_user_permission_doctypes(self):
+ frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category 1",
+ "test2@example.com")
+ frappe.permissions.add_user_permission("Blogger", "_Test Blogger 1",
+ "test2@example.com")
+
+ frappe.set_user("test2@example.com")
+
+ frappe.db.sql("""update `tabDocPerm` set user_permission_doctypes=%s
+ where parent='Blog Post' and permlevel=0 and apply_user_permissions=1
+ and `read`=1""", json.dumps(["Blogger"]))
+
+ frappe.model.meta.clear_cache("Blog Post")
+
+ doc = frappe.get_doc("Blog Post", "_test-blog-post")
+ self.assertFalse(doc.has_permission("read"))
+
+ doc = frappe.get_doc("Blog Post", "_test-blog-post-2")
+ self.assertTrue(doc.has_permission("read"))
+
+ frappe.model.meta.clear_cache("Blog Post")
diff --git a/frappe/widgets/page.py b/frappe/widgets/page.py
index 0908986913..8e1e26cdc2 100644
--- a/frappe/widgets/page.py
+++ b/frappe/widgets/page.py
@@ -1,8 +1,9 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-# MIT License. See license.txt
+# MIT License. See license.txt
from __future__ import unicode_literals
import frappe
+from frappe.translate import send_translations
@frappe.whitelist()
def get(name):
@@ -28,14 +29,14 @@ def getpage():
# load translations
if frappe.lang != "en":
- frappe.response["__messages"] = frappe.get_lang_dict("page", page)
+ send_translations(frappe.get_lang_dict("page", page))
frappe.response.docs.append(doc)
def has_permission(page):
if frappe.user.name == "Administrator" or "System Manager" in frappe.user.get_roles():
return True
-
+
page_roles = [d.role for d in page.get("roles")]
if page_roles:
if frappe.session.user == "Guest" and "Guest" not in page_roles:
@@ -43,7 +44,7 @@ def has_permission(page):
elif not set(page_roles).intersection(set(frappe.get_roles())):
# check if roles match
return False
-
+
if not frappe.has_permission("Page", ptype="read", doc=page):
# check if there are any user_permissions
return False
diff --git a/frappe/widgets/query_report.py b/frappe/widgets/query_report.py
index e32f574283..1b310079f6 100644
--- a/frappe/widgets/query_report.py
+++ b/frappe/widgets/query_report.py
@@ -9,6 +9,7 @@ import os, json
from frappe import _
from frappe.modules import scrub, get_module_path
from frappe.utils import flt, cint, get_html_format
+from frappe.translate import send_translations
import frappe.widgets.reportview
def get_report_doc(report_name):
@@ -50,7 +51,7 @@ def get_script(report_name):
# load translations
if frappe.lang != "en":
- frappe.response["__messages"] = frappe.get_lang_dict("report", report_name)
+ send_translations(frappe.get_lang_dict("report", report_name))
return {
"script": script,
diff --git a/frappe/widgets/search.py b/frappe/widgets/search.py
index 1d8b92c564..5be24c05f2 100644
--- a/frappe/widgets/search.py
+++ b/frappe/widgets/search.py
@@ -74,7 +74,7 @@ def search_widget(doctype, txt, query=None, searchfield=None, start=0,
fields = get_std_fields_list(meta, searchfield or "name")
# find relevance as location of search term from the beginning of string `name`. used for sorting results.
- fields.append("""locate("{_txt}", name) as `_relevance`""".format(
+ fields.append("""locate("{_txt}", `tab{doctype}`.`name`) as `_relevance`""".format(
_txt=frappe.db.escape((txt or "").replace("%", "")), doctype=doctype))
values = frappe.widgets.reportview.execute(doctype,
|