* [refactor] user permissions * [fix] tests * [ux] user-permissions * [minor] cleanup system settings * [minor] end progressversion-14
@@ -17,6 +17,7 @@ from frappe.utils.change_log import get_versions | |||||
from frappe.translate import get_lang_dict | from frappe.translate import get_lang_dict | ||||
from frappe.email.inbox import get_email_accounts | from frappe.email.inbox import get_email_accounts | ||||
from frappe.core.doctype.feedback_trigger.feedback_trigger import get_enabled_feedback_trigger | from frappe.core.doctype.feedback_trigger.feedback_trigger import get_enabled_feedback_trigger | ||||
from frappe.core.doctype.user_permission.user_permission import get_user_permissions | |||||
def get_bootinfo(): | def get_bootinfo(): | ||||
"""build and return boot info""" | """build and return boot info""" | ||||
@@ -30,6 +31,7 @@ def get_bootinfo(): | |||||
# system info | # system info | ||||
bootinfo.sysdefaults = frappe.defaults.get_defaults() | bootinfo.sysdefaults = frappe.defaults.get_defaults() | ||||
bootinfo.user_permissions = get_user_permissions() | |||||
bootinfo.server_date = frappe.utils.nowdate() | bootinfo.server_date = frappe.utils.nowdate() | ||||
if frappe.session['user'] != 'Guest': | if frappe.session['user'] != 'Guest': | ||||
@@ -3,7 +3,6 @@ | |||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
import frappe | import frappe | ||||
import frappe.defaults | |||||
import frappe.permissions | import frappe.permissions | ||||
from frappe.model.document import Document | from frappe.model.document import Document | ||||
from frappe.utils import get_fullname | from frappe.utils import get_fullname | ||||
@@ -68,7 +67,7 @@ def get_feed_match_conditions(user=None, force=True): | |||||
conditions = ['`tabCommunication`.owner="{user}" or `tabCommunication`.reference_owner="{user}"'.format(user=frappe.db.escape(user))] | conditions = ['`tabCommunication`.owner="{user}" or `tabCommunication`.reference_owner="{user}"'.format(user=frappe.db.escape(user))] | ||||
user_permissions = frappe.defaults.get_user_permissions(user) | |||||
user_permissions = frappe.permissions.get_user_permissions(user) | |||||
can_read = frappe.get_user().get_can_read() | can_read = frappe.get_user().get_can_read() | ||||
can_read_doctypes = ['"{}"'.format(doctype) for doctype in | can_read_doctypes = ['"{}"'.format(doctype) for doctype in | ||||
@@ -527,7 +527,7 @@ | |||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 1, | "collapsible": 1, | ||||
"columns": 0, | "columns": 0, | ||||
"fieldname": "security", | |||||
"fieldname": "permissions", | |||||
"fieldtype": "Section Break", | "fieldtype": "Section Break", | ||||
"hidden": 0, | "hidden": 0, | ||||
"ignore_user_permissions": 0, | "ignore_user_permissions": 0, | ||||
@@ -536,10 +536,11 @@ | |||||
"in_global_search": 0, | "in_global_search": 0, | ||||
"in_list_view": 0, | "in_list_view": 0, | ||||
"in_standard_filter": 0, | "in_standard_filter": 0, | ||||
"label": "Security", | |||||
"label": "Permissions", | |||||
"length": 0, | "length": 0, | ||||
"no_copy": 0, | "no_copy": 0, | ||||
"permlevel": 0, | "permlevel": 0, | ||||
"precision": "", | |||||
"print_hide": 0, | "print_hide": 0, | ||||
"print_hide_if_no_value": 0, | "print_hide_if_no_value": 0, | ||||
"read_only": 0, | "read_only": 0, | ||||
@@ -556,10 +557,9 @@ | |||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
"columns": 0, | "columns": 0, | ||||
"default": "06:00", | |||||
"description": "Session Expiry in Hours e.g. 06:00", | |||||
"fieldname": "session_expiry", | |||||
"fieldtype": "Data", | |||||
"description": "If Apply User Permissions is checked for Report DocType but no User Permissions are defined for Report for a User, then all Reports are shown to that User", | |||||
"fieldname": "ignore_user_permissions_if_missing", | |||||
"fieldtype": "Check", | |||||
"hidden": 0, | "hidden": 0, | ||||
"ignore_user_permissions": 0, | "ignore_user_permissions": 0, | ||||
"ignore_xss_filter": 0, | "ignore_xss_filter": 0, | ||||
@@ -567,11 +567,11 @@ | |||||
"in_global_search": 0, | "in_global_search": 0, | ||||
"in_list_view": 0, | "in_list_view": 0, | ||||
"in_standard_filter": 0, | "in_standard_filter": 0, | ||||
"label": "Session Expiry", | |||||
"label": "Ignore User Permissions If Missing", | |||||
"length": 0, | "length": 0, | ||||
"no_copy": 0, | "no_copy": 0, | ||||
"options": "", | |||||
"permlevel": 0, | "permlevel": 0, | ||||
"precision": "", | |||||
"print_hide": 0, | "print_hide": 0, | ||||
"print_hide_if_no_value": 0, | "print_hide_if_no_value": 0, | ||||
"read_only": 0, | "read_only": 0, | ||||
@@ -588,10 +588,10 @@ | |||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
"columns": 0, | "columns": 0, | ||||
"default": "720:00", | |||||
"description": "In Hours", | |||||
"fieldname": "session_expiry_mobile", | |||||
"fieldtype": "Data", | |||||
"default": "0", | |||||
"description": "If Apply Strict User Permission is checked and User Permission is defined for a DocType for a User, then all the documents where value of the link is blank, will not be shown to that User", | |||||
"fieldname": "apply_strict_user_permissions", | |||||
"fieldtype": "Check", | |||||
"hidden": 0, | "hidden": 0, | ||||
"ignore_user_permissions": 0, | "ignore_user_permissions": 0, | ||||
"ignore_xss_filter": 0, | "ignore_xss_filter": 0, | ||||
@@ -599,7 +599,7 @@ | |||||
"in_global_search": 0, | "in_global_search": 0, | ||||
"in_list_view": 0, | "in_list_view": 0, | ||||
"in_standard_filter": 0, | "in_standard_filter": 0, | ||||
"label": "Session Expiry Mobile", | |||||
"label": "Apply Strict User Permissions", | |||||
"length": 0, | "length": 0, | ||||
"no_copy": 0, | "no_copy": 0, | ||||
"permlevel": 0, | "permlevel": 0, | ||||
@@ -614,16 +614,45 @@ | |||||
"set_only_once": 0, | "set_only_once": 0, | ||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | |||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 1, | |||||
"columns": 0, | |||||
"fieldname": "security", | |||||
"fieldtype": "Section Break", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_global_search": 0, | |||||
"in_list_view": 0, | |||||
"in_standard_filter": 0, | |||||
"label": "Security", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"permlevel": 0, | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"remember_last_selected_value": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | { | ||||
"allow_bulk_edit": 0, | "allow_bulk_edit": 0, | ||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
"columns": 0, | "columns": 0, | ||||
"default": "0", | |||||
"description": "If enabled, the password strength will be enforced based on the Minimum Password Score value. A value of 2 being medium strong and 4 being very strong.", | |||||
"fieldname": "enable_password_policy", | |||||
"fieldtype": "Check", | |||||
"default": "06:00", | |||||
"description": "Session Expiry in Hours e.g. 06:00", | |||||
"fieldname": "session_expiry", | |||||
"fieldtype": "Data", | |||||
"hidden": 0, | "hidden": 0, | ||||
"ignore_user_permissions": 0, | "ignore_user_permissions": 0, | ||||
"ignore_xss_filter": 0, | "ignore_xss_filter": 0, | ||||
@@ -631,11 +660,11 @@ | |||||
"in_global_search": 0, | "in_global_search": 0, | ||||
"in_list_view": 0, | "in_list_view": 0, | ||||
"in_standard_filter": 0, | "in_standard_filter": 0, | ||||
"label": "Enable Password Policy", | |||||
"label": "Session Expiry", | |||||
"length": 0, | "length": 0, | ||||
"no_copy": 0, | "no_copy": 0, | ||||
"options": "", | |||||
"permlevel": 0, | "permlevel": 0, | ||||
"precision": "", | |||||
"print_hide": 0, | "print_hide": 0, | ||||
"print_hide_if_no_value": 0, | "print_hide_if_no_value": 0, | ||||
"read_only": 0, | "read_only": 0, | ||||
@@ -652,10 +681,10 @@ | |||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
"columns": 0, | "columns": 0, | ||||
"default": "2", | |||||
"depends_on": "eval:doc.enable_password_policy==1", | |||||
"fieldname": "minimum_password_score", | |||||
"fieldtype": "Select", | |||||
"default": "720:00", | |||||
"description": "In Hours", | |||||
"fieldname": "session_expiry_mobile", | |||||
"fieldtype": "Data", | |||||
"hidden": 0, | "hidden": 0, | ||||
"ignore_user_permissions": 0, | "ignore_user_permissions": 0, | ||||
"ignore_xss_filter": 0, | "ignore_xss_filter": 0, | ||||
@@ -663,10 +692,9 @@ | |||||
"in_global_search": 0, | "in_global_search": 0, | ||||
"in_list_view": 0, | "in_list_view": 0, | ||||
"in_standard_filter": 0, | "in_standard_filter": 0, | ||||
"label": "Minimum Password Score", | |||||
"label": "Session Expiry Mobile", | |||||
"length": 0, | "length": 0, | ||||
"no_copy": 0, | "no_copy": 0, | ||||
"options": "2\n4", | |||||
"permlevel": 0, | "permlevel": 0, | ||||
"precision": "", | "precision": "", | ||||
"print_hide": 0, | "print_hide": 0, | ||||
@@ -685,8 +713,10 @@ | |||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
"columns": 0, | "columns": 0, | ||||
"fieldname": "column_break_13", | |||||
"fieldtype": "Column Break", | |||||
"default": "0", | |||||
"description": "If enabled, the password strength will be enforced based on the Minimum Password Score value. A value of 2 being medium strong and 4 being very strong.", | |||||
"fieldname": "enable_password_policy", | |||||
"fieldtype": "Check", | |||||
"hidden": 0, | "hidden": 0, | ||||
"ignore_user_permissions": 0, | "ignore_user_permissions": 0, | ||||
"ignore_xss_filter": 0, | "ignore_xss_filter": 0, | ||||
@@ -694,6 +724,7 @@ | |||||
"in_global_search": 0, | "in_global_search": 0, | ||||
"in_list_view": 0, | "in_list_view": 0, | ||||
"in_standard_filter": 0, | "in_standard_filter": 0, | ||||
"label": "Enable Password Policy", | |||||
"length": 0, | "length": 0, | ||||
"no_copy": 0, | "no_copy": 0, | ||||
"permlevel": 0, | "permlevel": 0, | ||||
@@ -714,9 +745,10 @@ | |||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
"columns": 0, | "columns": 0, | ||||
"description": "Note: Multiple sessions will be allowed in case of mobile device", | |||||
"fieldname": "deny_multiple_sessions", | |||||
"fieldtype": "Check", | |||||
"default": "2", | |||||
"depends_on": "eval:doc.enable_password_policy==1", | |||||
"fieldname": "minimum_password_score", | |||||
"fieldtype": "Select", | |||||
"hidden": 0, | "hidden": 0, | ||||
"ignore_user_permissions": 0, | "ignore_user_permissions": 0, | ||||
"ignore_xss_filter": 0, | "ignore_xss_filter": 0, | ||||
@@ -724,9 +756,10 @@ | |||||
"in_global_search": 0, | "in_global_search": 0, | ||||
"in_list_view": 0, | "in_list_view": 0, | ||||
"in_standard_filter": 0, | "in_standard_filter": 0, | ||||
"label": "Allow only one session per user", | |||||
"label": "Minimum Password Score", | |||||
"length": 0, | "length": 0, | ||||
"no_copy": 0, | "no_copy": 0, | ||||
"options": "2\n4", | |||||
"permlevel": 0, | "permlevel": 0, | ||||
"precision": "", | "precision": "", | ||||
"print_hide": 0, | "print_hide": 0, | ||||
@@ -745,9 +778,8 @@ | |||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
"columns": 0, | "columns": 0, | ||||
"description": "If Apply User Permissions is checked for Report DocType but no User Permissions are defined for Report for a User, then all Reports are shown to that User", | |||||
"fieldname": "ignore_user_permissions_if_missing", | |||||
"fieldtype": "Check", | |||||
"fieldname": "column_break_13", | |||||
"fieldtype": "Column Break", | |||||
"hidden": 0, | "hidden": 0, | ||||
"ignore_user_permissions": 0, | "ignore_user_permissions": 0, | ||||
"ignore_xss_filter": 0, | "ignore_xss_filter": 0, | ||||
@@ -755,7 +787,6 @@ | |||||
"in_global_search": 0, | "in_global_search": 0, | ||||
"in_list_view": 0, | "in_list_view": 0, | ||||
"in_standard_filter": 0, | "in_standard_filter": 0, | ||||
"label": "Ignore User Permissions If Missing", | |||||
"length": 0, | "length": 0, | ||||
"no_copy": 0, | "no_copy": 0, | ||||
"permlevel": 0, | "permlevel": 0, | ||||
@@ -776,9 +807,8 @@ | |||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
"columns": 0, | "columns": 0, | ||||
"default": "0", | |||||
"description": "If Apply Strict User Permission is checked and User Permission is defined for a DocType for a User, then all the documents where value of the link is blank, will not be shown to that User", | |||||
"fieldname": "apply_strict_user_permissions", | |||||
"description": "Note: Multiple sessions will be allowed in case of mobile device", | |||||
"fieldname": "deny_multiple_sessions", | |||||
"fieldtype": "Check", | "fieldtype": "Check", | ||||
"hidden": 0, | "hidden": 0, | ||||
"ignore_user_permissions": 0, | "ignore_user_permissions": 0, | ||||
@@ -787,7 +817,7 @@ | |||||
"in_global_search": 0, | "in_global_search": 0, | ||||
"in_list_view": 0, | "in_list_view": 0, | ||||
"in_standard_filter": 0, | "in_standard_filter": 0, | ||||
"label": "Apply Strict User Permissions", | |||||
"label": "Allow only one session per user", | |||||
"length": 0, | "length": 0, | ||||
"no_copy": 0, | "no_copy": 0, | ||||
"permlevel": 0, | "permlevel": 0, | ||||
@@ -997,7 +1027,7 @@ | |||||
"issingle": 1, | "issingle": 1, | ||||
"istable": 0, | "istable": 0, | ||||
"max_attachments": 0, | "max_attachments": 0, | ||||
"modified": "2017-06-23 07:48:10.453011", | |||||
"modified": "2017-07-20 22:57:56.466867", | |||||
"modified_by": "Administrator", | "modified_by": "Administrator", | ||||
"module": "Core", | "module": "Core", | ||||
"name": "System Settings", | "name": "System Settings", | ||||
@@ -1032,4 +1062,4 @@ | |||||
"sort_order": "ASC", | "sort_order": "ASC", | ||||
"track_changes": 1, | "track_changes": 1, | ||||
"track_seen": 0 | "track_seen": 0 | ||||
} | |||||
} |
@@ -35,6 +35,7 @@ class SystemSettings(Document): | |||||
frappe.cache().delete_value('system_settings') | frappe.cache().delete_value('system_settings') | ||||
frappe.cache().delete_value('time_zone') | frappe.cache().delete_value('time_zone') | ||||
frappe.local.system_settings = {} | |||||
@frappe.whitelist() | @frappe.whitelist() | ||||
def load(): | def load(): | ||||
@@ -0,0 +1,23 @@ | |||||
/* eslint-disable */ | |||||
// rename this file from _test_[name] to test_[name] to activate | |||||
// and remove above this line | |||||
QUnit.test("test: System Settings", function (assert) { | |||||
let done = assert.async(); | |||||
// number of asserts | |||||
assert.expect(1); | |||||
frappe.run_serially('System Settings', [ | |||||
// insert a new System Settings | |||||
() => frappe.tests.make([ | |||||
// values to be set | |||||
{key: 'value'} | |||||
]), | |||||
() => { | |||||
assert.equal(cur_frm.doc.key, 'value'); | |||||
}, | |||||
() => done() | |||||
]); | |||||
}); |
@@ -59,9 +59,13 @@ frappe.ui.form.on('User', { | |||||
frappe.route_options = { | frappe.route_options = { | ||||
"user": doc.name | "user": doc.name | ||||
}; | }; | ||||
frappe.set_route("user-permissions"); | |||||
frappe.set_route('List', 'User Permission'); | |||||
}, null, "btn-default") | }, null, "btn-default") | ||||
frm.add_custom_button(__('View Permitted Documents'), | |||||
() => frappe.set_route('query-report', 'Permitted Documents For User', | |||||
{user: frm.doc.name})); | |||||
frm.toggle_display(['sb1', 'sb3', 'modules_access'], true); | frm.toggle_display(['sb1', 'sb3', 'modules_access'], true); | ||||
} | } | ||||
@@ -0,0 +1,23 @@ | |||||
/* eslint-disable */ | |||||
// rename this file from _test_[name] to test_[name] to activate | |||||
// and remove above this line | |||||
QUnit.test("test: User Permission", function (assert) { | |||||
let done = assert.async(); | |||||
// number of asserts | |||||
assert.expect(1); | |||||
frappe.run_serially('User Permission', [ | |||||
// insert a new User Permission | |||||
() => frappe.tests.make([ | |||||
// values to be set | |||||
{key: 'value'} | |||||
]), | |||||
() => { | |||||
assert.equal(cur_frm.doc.key, 'value'); | |||||
}, | |||||
() => done() | |||||
]); | |||||
}); |
@@ -0,0 +1,10 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# Copyright (c) 2017, Frappe Technologies and Contributors | |||||
# See license.txt | |||||
from __future__ import unicode_literals | |||||
#import frappe | |||||
import unittest | |||||
class TestUserPermission(unittest.TestCase): | |||||
pass |
@@ -0,0 +1,10 @@ | |||||
// Copyright (c) 2017, Frappe Technologies and contributors | |||||
// For license information, please see license.txt | |||||
frappe.ui.form.on('User Permission', { | |||||
refresh: function(frm) { | |||||
frm.add_custom_button(__('View Permitted Documents'), | |||||
() => frappe.set_route('query-report', 'Permitted Documents For User', | |||||
{user: frm.doc.user})); | |||||
} | |||||
}); |
@@ -0,0 +1,188 @@ | |||||
{ | |||||
"allow_copy": 0, | |||||
"allow_guest_to_view": 0, | |||||
"allow_import": 0, | |||||
"allow_rename": 0, | |||||
"beta": 0, | |||||
"creation": "2017-07-17 14:25:27.881871", | |||||
"custom": 0, | |||||
"docstatus": 0, | |||||
"doctype": "DocType", | |||||
"document_type": "", | |||||
"editable_grid": 1, | |||||
"engine": "InnoDB", | |||||
"fields": [ | |||||
{ | |||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"fieldname": "user", | |||||
"fieldtype": "Link", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_global_search": 0, | |||||
"in_list_view": 1, | |||||
"in_standard_filter": 1, | |||||
"label": "User", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "User", | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"remember_last_selected_value": 0, | |||||
"report_hide": 0, | |||||
"reqd": 1, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"fieldname": "allow", | |||||
"fieldtype": "Link", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_global_search": 0, | |||||
"in_list_view": 1, | |||||
"in_standard_filter": 1, | |||||
"label": "Allow", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "DocType", | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"remember_last_selected_value": 0, | |||||
"report_hide": 0, | |||||
"reqd": 1, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"fieldname": "for_value", | |||||
"fieldtype": "Dynamic Link", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_global_search": 0, | |||||
"in_list_view": 1, | |||||
"in_standard_filter": 1, | |||||
"label": "For Value", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "allow", | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"remember_last_selected_value": 0, | |||||
"report_hide": 0, | |||||
"reqd": 1, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 1, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"default": "1", | |||||
"description": "If you un-check this, you will have to apply manually for each Role + Document Type combination", | |||||
"fieldname": "apply_for_all_roles", | |||||
"fieldtype": "Check", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_global_search": 0, | |||||
"in_list_view": 0, | |||||
"in_standard_filter": 0, | |||||
"label": "Apply for all Roles for this User", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"remember_last_selected_value": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
} | |||||
], | |||||
"has_web_view": 0, | |||||
"hide_heading": 0, | |||||
"hide_toolbar": 0, | |||||
"idx": 0, | |||||
"image_view": 0, | |||||
"in_create": 0, | |||||
"is_submittable": 0, | |||||
"issingle": 0, | |||||
"istable": 0, | |||||
"max_attachments": 0, | |||||
"modified": "2017-07-27 22:55:58.647315", | |||||
"modified_by": "Administrator", | |||||
"module": "Core", | |||||
"name": "User Permission", | |||||
"name_case": "", | |||||
"owner": "Administrator", | |||||
"permissions": [ | |||||
{ | |||||
"amend": 0, | |||||
"apply_user_permissions": 0, | |||||
"cancel": 0, | |||||
"create": 1, | |||||
"delete": 1, | |||||
"email": 1, | |||||
"export": 1, | |||||
"if_owner": 0, | |||||
"import": 0, | |||||
"permlevel": 0, | |||||
"print": 1, | |||||
"read": 1, | |||||
"report": 1, | |||||
"role": "System Manager", | |||||
"set_user_permissions": 0, | |||||
"share": 1, | |||||
"submit": 0, | |||||
"write": 1 | |||||
} | |||||
], | |||||
"quick_entry": 1, | |||||
"read_only": 0, | |||||
"read_only_onload": 0, | |||||
"show_name_in_global_search": 0, | |||||
"sort_field": "modified", | |||||
"sort_order": "DESC", | |||||
"title_field": "user", | |||||
"track_changes": 1, | |||||
"track_seen": 0 | |||||
} |
@@ -0,0 +1,80 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# Copyright (c) 2017, Frappe Technologies and contributors | |||||
# For license information, please see license.txt | |||||
from __future__ import unicode_literals | |||||
import frappe, json | |||||
from frappe.model.document import Document | |||||
from frappe.permissions import (get_valid_perms, update_permission_property) | |||||
from frappe import _ | |||||
class UserPermission(Document): | |||||
def on_update(self): | |||||
frappe.cache().delete_value('user_permissions') | |||||
if self.apply_for_all_roles: | |||||
self.apply_user_permissions_to_all_roles() | |||||
def apply_user_permissions_to_all_roles(self): | |||||
# add apply user permissions for all roles that | |||||
# for this doctype | |||||
def show_progress(i, l): | |||||
if l > 2: | |||||
frappe.publish_realtime("progress", | |||||
dict(progress=[i, l], title=_('Updating...')), | |||||
user=frappe.session.user) | |||||
roles = frappe.get_roles(self.user) | |||||
linked = frappe.db.sql('''select distinct parent from tabDocField | |||||
where fieldtype="Link" and options=%s''', self.allow) | |||||
for i, link in enumerate(linked): | |||||
doctype = link[0] | |||||
for perm in get_valid_perms(doctype, self.user): | |||||
# if the role is applicable to the user | |||||
show_progress(i+1, len(linked)) | |||||
if perm.role in roles: | |||||
if not perm.apply_user_permissions: | |||||
update_permission_property(doctype, perm.role, 0, | |||||
'apply_user_permissions', '1') | |||||
try: | |||||
user_permission_doctypes = json.loads(perm.user_permission_doctypes or '[]') | |||||
except ValueError: | |||||
user_permission_doctypes = [] | |||||
if self.allow not in user_permission_doctypes: | |||||
user_permission_doctypes.append(self.allow) | |||||
update_permission_property(doctype, perm.role, 0, | |||||
'user_permission_doctypes', json.dumps(user_permission_doctypes), validate=False) | |||||
show_progress(len(linked), len(linked)) | |||||
def on_trash(self): # pylint: disable=no-self-use | |||||
frappe.cache().delete_value('user_permissions') | |||||
def get_user_permissions(user=None): | |||||
'''Get all users permissions for the user as a dict of doctype''' | |||||
if not user: | |||||
user = frappe.session.user | |||||
out = frappe.cache().hget("user_permissions", user) | |||||
if not out: | |||||
out = {} | |||||
try: | |||||
for perm in frappe.get_all('User Permission', | |||||
fields=['allow', 'for_value'], filters=dict(user=user)): | |||||
out.setdefault(perm.allow, []).append(perm.for_value) | |||||
# add profile match | |||||
if user not in out.get("User", []): | |||||
out.setdefault("User", []).append(user) | |||||
frappe.cache().hset("user_permissions", user, out) | |||||
except frappe.SQLError, e: | |||||
if e.args[0]==1146: | |||||
# called from patch | |||||
pass | |||||
return out |
@@ -21,6 +21,7 @@ frappe.pages['permission-manager'].refresh = function(wrapper) { | |||||
frappe.PermissionEngine = Class.extend({ | frappe.PermissionEngine = Class.extend({ | ||||
init: function(wrapper) { | init: function(wrapper) { | ||||
this.wrapper = wrapper; | this.wrapper = wrapper; | ||||
this.page = wrapper.page; | |||||
this.body = $(this.wrapper).find(".perm-engine"); | this.body = $(this.wrapper).find(".perm-engine"); | ||||
this.make(); | this.make(); | ||||
this.refresh(); | this.refresh(); | ||||
@@ -55,6 +56,10 @@ frappe.PermissionEngine = Class.extend({ | |||||
.change(function() { | .change(function() { | ||||
me.refresh(); | me.refresh(); | ||||
}); | }); | ||||
this.page.add_inner_button(__('Set User Permissions'), () => { | |||||
return frappe.set_route('List', 'User Permission'); | |||||
}); | |||||
this.set_from_route(); | this.set_from_route(); | ||||
}, | }, | ||||
set_from_route: function() { | set_from_route: function() { | ||||
@@ -133,11 +138,11 @@ frappe.PermissionEngine = Class.extend({ | |||||
refresh: function() { | refresh: function() { | ||||
var me = this; | var me = this; | ||||
if(!me.doctype_select) { | if(!me.doctype_select) { | ||||
this.body.html("<p class='text-muted'>" + __("Loading") + "...</div>"); | |||||
this.body.html("<p class='text-muted'>" + __("Loading") + "...</p>"); | |||||
return; | return; | ||||
} | } | ||||
if(!me.get_doctype() && !me.get_role()) { | if(!me.get_doctype() && !me.get_role()) { | ||||
this.body.html("<p class='text-muted'>"+__("Select Document Type or Role to start.")+"</div>"); | |||||
this.body.html("<p class='text-muted'>"+__("Select Document Type or Role to start.")+"</p>"); | |||||
return; | return; | ||||
} | } | ||||
// get permissions | // get permissions | ||||
@@ -247,10 +252,13 @@ frappe.PermissionEngine = Class.extend({ | |||||
setup_user_permissions: function(d, role_cell) { | setup_user_permissions: function(d, role_cell) { | ||||
var me = this; | var me = this; | ||||
d.help = frappe.render('<ul class="user-permission-help small hidden" style="margin-left: -10px;">\ | |||||
<li style="margin-top: 7px;"><a class="show-user-permission-doctypes grey">{%= __("Select Document Types") %}</a></li>\ | |||||
<li style="margin-top: 3px;"><a class="show-user-permissions grey">{%= __("Show User Permissions") %}</a></li>\ | |||||
</ul>', {}); | |||||
d.help = `<ul class="user-permission-help small hidden" | |||||
style="margin-left: -10px;"> | |||||
<li style="margin-top: 7px;"><a class="show-user-permission-doctypes"> | |||||
${__("Select Document Types")}</a></li> | |||||
<li style="margin-top: 3px;"><a class="show-user-permissions"> | |||||
${__("Show User Permissions")}</a></li> | |||||
</ul>`; | |||||
var checkbox = this.add_check(role_cell, d, "apply_user_permissions") | var checkbox = this.add_check(role_cell, d, "apply_user_permissions") | ||||
.removeClass("col-md-4") | .removeClass("col-md-4") | ||||
@@ -336,8 +344,8 @@ frappe.PermissionEngine = Class.extend({ | |||||
var me = this; | var me = this; | ||||
this.body.on("click", ".show-user-permissions", function() { | this.body.on("click", ".show-user-permissions", function() { | ||||
frappe.route_options = { doctype: me.get_doctype() || "" }; | |||||
frappe.set_route("user-permissions"); | |||||
frappe.route_options = { allow: me.get_doctype() || "" }; | |||||
frappe.set_route('List', 'User Permission'); | |||||
}); | }); | ||||
this.body.on("click", "input[type='checkbox']", function() { | this.body.on("click", "input[type='checkbox']", function() { | ||||
@@ -7,7 +7,7 @@ import frappe.defaults | |||||
from frappe.modules.import_file import get_file_path, read_doc_from_file | from frappe.modules.import_file import get_file_path, read_doc_from_file | ||||
from frappe.translate import send_translations | from frappe.translate import send_translations | ||||
from frappe.permissions import (reset_perms, get_linked_doctypes, get_all_perms, | from frappe.permissions import (reset_perms, get_linked_doctypes, get_all_perms, | ||||
setup_custom_perms, add_permission) | |||||
setup_custom_perms, add_permission, update_permission_property) | |||||
from frappe.core.doctype.doctype.doctype import (clear_permissions_cache, | from frappe.core.doctype.doctype.doctype import (clear_permissions_cache, | ||||
validate_permissions_for_doctype) | validate_permissions_for_doctype) | ||||
from frappe import _ | from frappe import _ | ||||
@@ -68,18 +68,8 @@ def add(parent, role, permlevel): | |||||
@frappe.whitelist() | @frappe.whitelist() | ||||
def update(doctype, role, permlevel, ptype, value=None): | def update(doctype, role, permlevel, ptype, value=None): | ||||
frappe.only_for("System Manager") | frappe.only_for("System Manager") | ||||
out = None | |||||
if setup_custom_perms(doctype): | |||||
out = 'refresh' | |||||
name = frappe.get_value('Custom DocPerm', dict(parent=doctype, role=role, permlevel=permlevel)) | |||||
frappe.db.sql("""update `tabCustom DocPerm` set `%s`=%s where name=%s"""\ | |||||
% (frappe.db.escape(ptype), '%s', '%s'), (value, name)) | |||||
validate_permissions_for_doctype(doctype) | |||||
return out | |||||
out = update_permission_property(doctype, role, permlevel, ptype, value) | |||||
return 'refresh' if out else None | |||||
@frappe.whitelist() | @frappe.whitelist() | ||||
def remove(doctype, role, permlevel): | def remove(doctype, role, permlevel): | ||||
@@ -1 +0,0 @@ | |||||
Interface to set user defaults (DefaultValue). |
@@ -1,3 +0,0 @@ | |||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||||
# MIT License. See license.txt | |||||
@@ -1,365 +0,0 @@ | |||||
frappe.pages['user-permissions'].on_page_load = function(wrapper) { | |||||
var page = frappe.ui.make_app_page({ | |||||
parent: wrapper, | |||||
title: __("User Permissions Manager"), | |||||
icon: "fa fa-shield", | |||||
single_column: true | |||||
}); | |||||
frappe.breadcrumbs.add("Setup"); | |||||
$("<div class='user-settings' \ | |||||
style='min-height: 200px; padding: 15px;'></div>\ | |||||
<p style='padding: 15px; padding-bottom: 0px;'>\ | |||||
<a class='view-role-permissions grey'>" + __("Edit Role Permissions") + "</a>\ | |||||
</p><hr><div style='padding: 0px 15px;'>\ | |||||
<h4>"+__("Help for User Permissions")+":</h4>\ | |||||
<ol>\ | |||||
<li>" | |||||
+ __("Apart from Role based Permission Rules, you can apply User Permissions based on DocTypes.") | |||||
+ "</li>" | |||||
+ "<li>" | |||||
+ __("These permissions will apply for all transactions where the permitted record is linked. For example, if Company C is added to User Permissions of user X, user X will only be able to see transactions that has company C as a linked value.") | |||||
+ "</li>" | |||||
+ "<li>" | |||||
+ __("These will also be set as default values for those links, if only one such permission record is defined.") | |||||
+ "</li>" | |||||
+ "<li>" | |||||
+ __("A user can be permitted to multiple records of the same DocType.") | |||||
+ "</li>\ | |||||
</ol></div>").appendTo(page.main); | |||||
wrapper.user_permissions = new frappe.UserPermissions(wrapper); | |||||
} | |||||
frappe.pages['user-permissions'].refresh = function(wrapper) { | |||||
wrapper.user_permissions.set_from_route(); | |||||
} | |||||
frappe.UserPermissions = Class.extend({ | |||||
init: function(wrapper) { | |||||
this.wrapper = wrapper; | |||||
this.body = $(this.wrapper).find(".user-settings"); | |||||
this.filters = {}; | |||||
this.make(); | |||||
this.refresh(); | |||||
}, | |||||
make: function() { | |||||
var me = this; | |||||
$(this.wrapper).find(".view-role-permissions").on("click", function() { | |||||
frappe.route_options = { doctype: me.get_doctype() || "" }; | |||||
frappe.set_route("permission-manager"); | |||||
}) | |||||
return frappe.call({ | |||||
module:"frappe.core", | |||||
page:"user_permissions", | |||||
method: "get_users_and_links", | |||||
callback: function(r) { | |||||
me.options = r.message; | |||||
me.filters.user = me.wrapper.page.add_field({ | |||||
fieldname: "user", | |||||
label: __("User"), | |||||
fieldtype: "Select", | |||||
options: ([__("Select User") + "..."].concat(r.message.users)).join("\n") | |||||
}); | |||||
me.filters.doctype = me.wrapper.page.add_field({ | |||||
fieldname: "doctype", | |||||
label: __("DocType"), | |||||
fieldtype: "Select", | |||||
options: ([__("Select DocType") + "..."].concat(me.get_link_names())).join("\n") | |||||
}); | |||||
me.filters.user_permission = me.wrapper.page.add_field({ | |||||
fieldname: "user_permission", | |||||
label: __("Name"), | |||||
fieldtype: "Link", | |||||
options: "[Select]" | |||||
}); | |||||
if(frappe.user_roles.includes("System Manager")) { | |||||
me.download = me.wrapper.page.add_field({ | |||||
fieldname: "download", | |||||
label: __("Download"), | |||||
fieldtype: "Button", | |||||
icon: "fa fa-download" | |||||
}); | |||||
me.upload = me.wrapper.page.add_field({ | |||||
fieldname: "upload", | |||||
label: __("Upload"), | |||||
fieldtype: "Button", | |||||
icon: "fa fa-upload" | |||||
}); | |||||
} | |||||
// bind change event | |||||
$.each(me.filters, function(k, f) { | |||||
f.$input.on("change", function() { | |||||
me.refresh(); | |||||
}); | |||||
}); | |||||
// change options in user_permission link | |||||
me.filters.doctype.$input.on("change", function() { | |||||
me.filters.user_permission.df.options = me.get_doctype(); | |||||
}); | |||||
me.set_from_route(); | |||||
me.setup_download_upload(); | |||||
} | |||||
}); | |||||
}, | |||||
setup_download_upload: function() { | |||||
var me = this; | |||||
me.download.$input.on("click", function() { | |||||
window.location.href = frappe.urllib.get_base_url() | |||||
+ "/api/method/frappe.core.page.user_permissions.user_permissions.get_user_permissions_csv"; | |||||
}); | |||||
me.upload.$input.on("click", function() { | |||||
var d = new frappe.ui.Dialog({ | |||||
title: __("Upload User Permissions"), | |||||
fields: [ | |||||
{ | |||||
fieldtype:"HTML", | |||||
options: '<p class="text-muted"><ol>'+ | |||||
"<li>"+__("Upload CSV file containing all user permissions in the same format as Download.")+"</li>"+ | |||||
"<li><strong>"+__("Any existing permission will be deleted / overwritten.")+"</strong></li>"+ | |||||
'</p>' | |||||
}, | |||||
{ | |||||
fieldtype:"Attach", fieldname:"attach", | |||||
} | |||||
], | |||||
primary_action_label: __("Upload and Sync"), | |||||
primary_action: function() { | |||||
var filedata = d.fields_dict.attach.get_value(); | |||||
if(!filedata) { | |||||
frappe.msgprint(__("Please attach a file")); | |||||
return; | |||||
} | |||||
frappe.call({ | |||||
method:"frappe.core.page.user_permissions.user_permissions.import_user_permissions", | |||||
args: { | |||||
filedata: filedata | |||||
}, | |||||
callback: function(r) { | |||||
if(!r.exc) { | |||||
frappe.msgprint(__("Permissions Updated")); | |||||
d.hide(); | |||||
} | |||||
} | |||||
}); | |||||
} | |||||
}); | |||||
d.show(); | |||||
}) | |||||
}, | |||||
get_link_names: function() { | |||||
return this.options.link_fields; | |||||
}, | |||||
set_from_route: function() { | |||||
var me = this; | |||||
if(frappe.route_options && this.filters && !$.isEmptyObject(this.filters)) { | |||||
$.each(frappe.route_options, function(key, value) { | |||||
if(me.filters[key] && frappe.route_options[key]!=null) | |||||
me.set_filter(key, value); | |||||
}); | |||||
frappe.route_options = null; | |||||
} | |||||
this.refresh(); | |||||
}, | |||||
set_filter: function(key, value) { | |||||
this.filters[key].$input.val(value); | |||||
}, | |||||
get_user: function() { | |||||
var user = this.filters.user.$input.val(); | |||||
return user== __("Select User") + "..." ? null : user; | |||||
}, | |||||
get_doctype: function() { | |||||
var doctype = this.filters.doctype.$input.val(); | |||||
return doctype== __("Select DocType") + "..." ? null : doctype; | |||||
}, | |||||
get_user_permission: function() { | |||||
// autosuggest hack! | |||||
var user_permission = this.filters.user_permission.$input.val(); | |||||
return (user_permission === "%") ? null : user_permission; | |||||
}, | |||||
render: function(prop_list) { | |||||
var me = this; | |||||
this.body.empty(); | |||||
this.prop_list = prop_list; | |||||
if(!prop_list || !prop_list.length) { | |||||
this.add_message(__("No User Restrictions found.")); | |||||
} else { | |||||
this.show_user_permissions_table(); | |||||
} | |||||
this.show_add_user_permission(); | |||||
if(this.get_user() && this.get_doctype()) { | |||||
$('<button class="btn btn-default btn-sm" style="margin-left: 10px;">\ | |||||
Show Allowed Documents</button>').appendTo(this.body.find(".btn-area")).on("click", function() { | |||||
frappe.route_options = {doctype: me.get_doctype(), user:me.get_user() }; | |||||
frappe.set_route("query-report/Permitted Documents For User"); | |||||
}); | |||||
} | |||||
}, | |||||
add_message: function(txt) { | |||||
$('<p class="text-muted">' + txt + '</p>').appendTo(this.body); | |||||
}, | |||||
refresh: function() { | |||||
var me = this; | |||||
if(!me.filters.user) { | |||||
this.body.html("<p class='text-muted'>"+__("Loading")+"...</p>"); | |||||
return; | |||||
} | |||||
if(!me.get_user() && !me.get_doctype()) { | |||||
this.body.html("<p class='text-muted'>"+__("Select User or DocType to start.")+"</p>"); | |||||
return; | |||||
} | |||||
// get permissions | |||||
return frappe.call({ | |||||
module: "frappe.core", | |||||
page: "user_permissions", | |||||
method: "get_permissions", | |||||
args: { | |||||
parent: me.get_user(), | |||||
defkey: me.get_doctype(), | |||||
defvalue: me.get_user_permission() | |||||
}, | |||||
callback: function(r) { | |||||
me.render(r.message); | |||||
} | |||||
}); | |||||
}, | |||||
show_user_permissions_table: function() { | |||||
var me = this; | |||||
this.table = $("<table class='table table-bordered'>\ | |||||
<thead><tr></tr></thead>\ | |||||
<tbody></tbody>\ | |||||
</table>").appendTo(this.body); | |||||
$('<p class="text-muted small">' | |||||
+__("These restrictions will apply for Document Types where 'Apply User Permissions' is checked for the permission rule and a field with this value is present.") | |||||
+'</p>').appendTo(this.body); | |||||
$.each([[__("Allow User"), 150], [__("If Document Type"), 150], [__("Is"),150], ["", 50]], | |||||
function(i, col) { | |||||
$("<th>") | |||||
.html(col[0]) | |||||
.css("width", col[1]+"px") | |||||
.appendTo(me.table.find("thead tr")); | |||||
}); | |||||
$.each(this.prop_list, function(i, d) { | |||||
var row = $("<tr>").appendTo(me.table.find("tbody")); | |||||
$("<td>").html('<a class="grey" href="#Form/User/'+encodeURIComponent(d.parent)+'">' | |||||
+d.parent+'</a>').appendTo(row); | |||||
$("<td>").html(d.defkey).appendTo(row); | |||||
$("<td>").html(d.defvalue).appendTo(row); | |||||
me.add_delete_button(row, d); | |||||
}); | |||||
}, | |||||
add_delete_button: function(row, d) { | |||||
var me = this; | |||||
$("<button class='btn btn-sm btn-default'><i class='fa fa-remove'></i></button>") | |||||
.appendTo($("<td>").appendTo(row)) | |||||
.attr("data-name", d.name) | |||||
.attr("data-user", d.parent) | |||||
.attr("data-defkey", d.defkey) | |||||
.attr("data-defvalue", d.defvalue) | |||||
.click(function() { | |||||
return frappe.call({ | |||||
module: "frappe.core", | |||||
page: "user_permissions", | |||||
method: "remove", | |||||
args: { | |||||
name: $(this).attr("data-name"), | |||||
user: $(this).attr("data-user"), | |||||
defkey: $(this).attr("data-defkey"), | |||||
defvalue: $(this).attr("data-defvalue") | |||||
}, | |||||
callback: function(r) { | |||||
if(r.exc) { | |||||
frappe.msgprint(__("Did not remove")); | |||||
} else { | |||||
me.refresh(); | |||||
} | |||||
} | |||||
}) | |||||
}); | |||||
}, | |||||
show_add_user_permission: function() { | |||||
var me = this; | |||||
$("<button class='btn btn-default btn-sm'>"+__("Add A User Restriction")+"</button>") | |||||
.appendTo($('<p class="btn-area">').appendTo(this.body)) | |||||
.click(function() { | |||||
var d = new frappe.ui.Dialog({ | |||||
title: __("Add A New Restriction"), | |||||
fields: [ | |||||
{fieldtype:"Select", label:__("Allow User"), | |||||
options:me.options.users, reqd:1, fieldname:"user"}, | |||||
{fieldtype:"Select", label: __("If Document Type"), fieldname:"defkey", | |||||
options:me.get_link_names(), reqd:1}, | |||||
{fieldtype:"Link", label:__("Is"), fieldname:"defvalue", | |||||
options:'[Select]', reqd:1}, | |||||
{fieldtype:"Button", label: __("Add"), fieldname:"add"}, | |||||
] | |||||
}); | |||||
if(me.get_user()) { | |||||
d.set_value("user", me.get_user()); | |||||
d.get_input("user").prop("disabled", true); | |||||
} | |||||
if(me.get_doctype()) { | |||||
d.set_value("defkey", me.get_doctype()); | |||||
d.get_input("defkey").prop("disabled", true); | |||||
} | |||||
if(me.get_user_permission()) { | |||||
d.set_value("defvalue", me.get_user_permission()); | |||||
d.get_input("defvalue").prop("disabled", true); | |||||
} | |||||
d.fields_dict["defvalue"].get_query = function(txt) { | |||||
if(!d.get_value("defkey")) { | |||||
frappe.throw(__("Please select Document Type")); | |||||
} | |||||
return { | |||||
doctype: d.get_value("defkey") | |||||
} | |||||
}; | |||||
d.get_input("add").click(function() { | |||||
var args = d.get_values(); | |||||
if(!args) { | |||||
return; | |||||
} | |||||
frappe.call({ | |||||
module: "frappe.core", | |||||
page: "user_permissions", | |||||
method: "add", | |||||
args: args, | |||||
callback: function(r) { | |||||
if(r.exc) { | |||||
frappe.msgprint(__("Did not add")); | |||||
} else { | |||||
me.refresh(); | |||||
} | |||||
} | |||||
}) | |||||
d.hide(); | |||||
}); | |||||
d.show(); | |||||
}); | |||||
} | |||||
}) |
@@ -1,19 +0,0 @@ | |||||
{ | |||||
"content": null, | |||||
"creation": "2013-01-01 18:50:55", | |||||
"docstatus": 0, | |||||
"doctype": "Page", | |||||
"icon": "fa fa-user", | |||||
"idx": 1, | |||||
"modified": "2014-05-28 16:53:43.103533", | |||||
"modified_by": "Administrator", | |||||
"module": "Core", | |||||
"name": "user-permissions", | |||||
"owner": "Administrator", | |||||
"page_name": "user-permissions", | |||||
"roles": [], | |||||
"script": null, | |||||
"standard": "Yes", | |||||
"style": null, | |||||
"title": "User Permissions Manager" | |||||
} |
@@ -1,109 +0,0 @@ | |||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||||
# MIT License. See license.txt | |||||
from __future__ import unicode_literals | |||||
import frappe | |||||
from frappe import _ | |||||
import frappe.defaults | |||||
from frappe.permissions import (can_set_user_permissions, add_user_permission, | |||||
remove_user_permission, get_valid_perms) | |||||
from frappe.core.doctype.user.user import get_system_users | |||||
from frappe.utils.csvutils import UnicodeWriter, read_csv_content_from_uploaded_file | |||||
from frappe.defaults import clear_default | |||||
@frappe.whitelist() | |||||
def get_users_and_links(): | |||||
return { | |||||
"users": get_system_users(), | |||||
"link_fields": get_doctypes_for_user_permissions() | |||||
} | |||||
@frappe.whitelist() | |||||
def get_permissions(parent=None, defkey=None, defvalue=None): | |||||
if defkey and not can_set_user_permissions(defkey, defvalue): | |||||
raise frappe.PermissionError | |||||
conditions, values = _build_conditions(locals()) | |||||
permissions = frappe.db.sql("""select name, parent, defkey, defvalue | |||||
from tabDefaultValue | |||||
where parent not in ('__default', '__global') | |||||
and substr(defkey,1,1)!='_' | |||||
and parenttype='User Permission' | |||||
{conditions} | |||||
order by parent, defkey""".format(conditions=conditions), values, as_dict=True) | |||||
if not defkey: | |||||
out = [] | |||||
doctypes = get_doctypes_for_user_permissions() | |||||
for p in permissions: | |||||
if p.defkey in doctypes: | |||||
out.append(p) | |||||
permissions = out | |||||
return permissions | |||||
def _build_conditions(filters): | |||||
conditions = [] | |||||
values = {} | |||||
for key, value in filters.items(): | |||||
if filters.get(key): | |||||
conditions.append("and `{key}`=%({key})s".format(key=key)) | |||||
values[key] = value | |||||
return "\n".join(conditions), values | |||||
@frappe.whitelist() | |||||
def remove(user, name, defkey, defvalue): | |||||
if not can_set_user_permissions(defkey, defvalue): | |||||
frappe.throw(_("Cannot remove permission for DocType: {0} and Name: {1}").format( | |||||
defkey, defvalue), frappe.PermissionError) | |||||
remove_user_permission(defkey, defvalue, user, name) | |||||
@frappe.whitelist() | |||||
def add(user, defkey, defvalue): | |||||
if not can_set_user_permissions(defkey, defvalue): | |||||
frappe.throw(_("Cannot set permission for DocType: {0} and Name: {1}").format( | |||||
defkey, defvalue), frappe.PermissionError) | |||||
add_user_permission(defkey, defvalue, user, with_message=True) | |||||
def get_doctypes_for_user_permissions(): | |||||
'''Get doctypes for the current user where user permissions are applicable''' | |||||
user_roles = frappe.get_roles() | |||||
if "System Manager" in user_roles: | |||||
doctypes = set([p.parent for p in get_valid_perms()]) | |||||
else: | |||||
doctypes = set([p.parent for p in get_valid_perms() if p.set_user_permissions]) | |||||
single_doctypes = set([d.name for d in frappe.get_all("DocType", {"issingle": 1})]) | |||||
return sorted(doctypes.difference(single_doctypes)) | |||||
@frappe.whitelist() | |||||
def get_user_permissions_csv(): | |||||
out = [["User Permissions"], ["User", "Document Type", "Value"]] | |||||
out += [[a.parent, a.defkey, a.defvalue] for a in get_permissions()] | |||||
csv = UnicodeWriter() | |||||
for row in out: | |||||
csv.writerow(row) | |||||
frappe.response['result'] = str(csv.getvalue()) | |||||
frappe.response['type'] = 'csv' | |||||
frappe.response['doctype'] = "User Permissions" | |||||
@frappe.whitelist() | |||||
def import_user_permissions(): | |||||
frappe.only_for("System Manager") | |||||
rows = read_csv_content_from_uploaded_file(ignore_encoding=True) | |||||
clear_default(parenttype="User Permission") | |||||
if rows[0][0]!="User Permissions" and rows[1][0] != "User": | |||||
frappe.throw(frappe._("Please upload using the same template as download.")) | |||||
for row in rows[2:]: | |||||
add_user_permission(row[1], row[2], row[0]) |
@@ -48,25 +48,10 @@ def is_a_user_permission_key(key): | |||||
return ":" not in key and key != frappe.scrub(key) | return ":" not in key and key != frappe.scrub(key) | ||||
def get_user_permissions(user=None): | def get_user_permissions(user=None): | ||||
if not user: | |||||
user = frappe.session.user | |||||
return build_user_permissions(user) | |||||
def build_user_permissions(user): | |||||
out = frappe.cache().hget("user_permissions", user) | |||||
if out==None: | |||||
out = {} | |||||
for key, value in frappe.db.sql("""select defkey, ifnull(defvalue, '') as defvalue | |||||
from tabDefaultValue where parent=%s and parenttype='User Permission'""", (user,)): | |||||
out.setdefault(key, []).append(value) | |||||
# add profile match | |||||
if user not in out.get("User", []): | |||||
out.setdefault("User", []).append(user) | |||||
frappe.cache().hset("user_permissions", user, out) | |||||
return out | |||||
from frappe.core.doctype.user_permission.user_permission \ | |||||
import get_user_permissions as _get_user_permissions | |||||
'''Return frappe.core.doctype.user_permissions.user_permissions._get_user_permissions (kept for backward compatibility)''' | |||||
return _get_user_permissions(user) | |||||
def get_defaults(user=None): | def get_defaults(user=None): | ||||
globald = get_defaults_for() | globald = get_defaults_for() | ||||
@@ -70,7 +70,6 @@ def getdoctype(doctype, with_parent=False, cached_timestamp=None): | |||||
if not docs: | if not docs: | ||||
docs = get_meta_bundle(doctype) | docs = get_meta_bundle(doctype) | ||||
frappe.response['user_permissions'] = get_user_permissions(docs) | |||||
frappe.response['user_settings'] = get_user_settings(parent_dt or doctype) | frappe.response['user_settings'] = get_user_settings(parent_dt or doctype) | ||||
if cached_timestamp and docs[0].modified==cached_timestamp: | if cached_timestamp and docs[0].modified==cached_timestamp: | ||||
@@ -102,16 +101,6 @@ def get_docinfo(doc=None, doctype=None, name=None): | |||||
"rating": get_feedback_rating(doc.doctype, doc.name) | "rating": get_feedback_rating(doc.doctype, doc.name) | ||||
} | } | ||||
def get_user_permissions(meta): | |||||
out = {} | |||||
all_user_permissions = frappe.defaults.get_user_permissions() | |||||
for m in meta: | |||||
for df in m.get_fields_to_check_permissions(all_user_permissions): | |||||
out[df.options] = list(set(all_user_permissions[df.options])) | |||||
return out | |||||
def get_attachments(dt, dn): | def get_attachments(dt, dn): | ||||
return frappe.get_all("File", fields=["name", "file_name", "file_url", "is_private"], | return frappe.get_all("File", fields=["name", "file_name", "file_url", "is_private"], | ||||
filters = {"attached_to_name": dn, "attached_to_doctype": dt}) | filters = {"attached_to_name": dn, "attached_to_doctype": dt}) | ||||
@@ -11,6 +11,7 @@ from frappe.utils import nowdate, nowtime, now_datetime | |||||
import frappe.defaults | import frappe.defaults | ||||
from frappe.model.db_schema import type_map | from frappe.model.db_schema import type_map | ||||
import copy | import copy | ||||
from frappe.core.doctype.user_permission.user_permission import get_user_permissions | |||||
def get_new_doc(doctype, parent_doc = None, parentfield = None, as_dict=False): | def get_new_doc(doctype, parent_doc = None, parentfield = None, as_dict=False): | ||||
if doctype not in frappe.local.new_doc_templates: | if doctype not in frappe.local.new_doc_templates: | ||||
@@ -47,7 +48,7 @@ def make_new_doc(doctype): | |||||
return doc | return doc | ||||
def set_user_and_static_default_values(doc): | def set_user_and_static_default_values(doc): | ||||
user_permissions = frappe.defaults.get_user_permissions() | |||||
user_permissions = get_user_permissions() | |||||
defaults = frappe.defaults.get_defaults() | defaults = frappe.defaults.get_defaults() | ||||
for df in doc.meta.get("fields"): | for df in doc.meta.get("fields"): | ||||
@@ -103,7 +104,7 @@ def get_static_default_value(df, user_permissions): | |||||
def set_dynamic_default_values(doc, parent_doc, parentfield): | def set_dynamic_default_values(doc, parent_doc, parentfield): | ||||
# these values should not be cached | # these values should not be cached | ||||
user_permissions = frappe.defaults.get_user_permissions() | |||||
user_permissions = get_user_permissions() | |||||
for df in frappe.get_meta(doc["doctype"]).get("fields"): | for df in frappe.get_meta(doc["doctype"]).get("fields"): | ||||
if df.get("default"): | if df.get("default"): | ||||
@@ -388,7 +388,7 @@ class DatabaseQuery(object): | |||||
# apply user permissions? | # apply user permissions? | ||||
if role_permissions.get("apply_user_permissions", {}).get("read"): | if role_permissions.get("apply_user_permissions", {}).get("read"): | ||||
# get user permissions | # get user permissions | ||||
user_permissions = frappe.defaults.get_user_permissions(self.user) | |||||
user_permissions = frappe.permissions.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").get("read")) | user_permission_doctypes=role_permissions.get("user_permission_doctypes").get("read")) | ||||
@@ -11,7 +11,7 @@ from frappe.utils.file_manager import remove_all | |||||
from frappe.utils.password import delete_all_passwords_for | from frappe.utils.password import delete_all_passwords_for | ||||
from frappe import _ | from frappe import _ | ||||
from frappe.model.naming import revert_series_if_last | from frappe.model.naming import revert_series_if_last | ||||
from frappe.utils.global_search import delete_for_document | |||||
from frappe.utils.global_search import delete_for_document | |||||
def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reload=False, | def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reload=False, | ||||
ignore_permissions=False, flags=None, ignore_on_trash=False): | ignore_permissions=False, flags=None, ignore_on_trash=False): | ||||
@@ -158,8 +158,13 @@ def update_flags(doc, flags=None, ignore_permissions=False): | |||||
def check_permission_and_not_submitted(doc): | def check_permission_and_not_submitted(doc): | ||||
# permission | # permission | ||||
if not doc.flags.ignore_permissions and frappe.session.user!="Administrator" and (not doc.has_permission("delete") or (doc.doctype=="DocType" and not doc.custom)): | |||||
frappe.msgprint(_("User not allowed to delete {0}: {1}").format(doc.doctype, doc.name), raise_exception=True) | |||||
if (not doc.flags.ignore_permissions | |||||
and frappe.session.user!="Administrator" | |||||
and ( | |||||
not doc.has_permission("delete") | |||||
or (doc.doctype=="DocType" and not doc.custom))): | |||||
frappe.msgprint(_("User not allowed to delete {0}: {1}") | |||||
.format(doc.doctype, doc.name), raise_exception=frappe.PermissionError) | |||||
# check if submitted | # check if submitted | ||||
if doc.docstatus == 1: | if doc.docstatus == 1: | ||||
@@ -189,3 +189,4 @@ frappe.patches.v8_1.enable_allow_error_traceback_in_system_settings | |||||
frappe.patches.v8_1.update_format_options_in_auto_email_report | frappe.patches.v8_1.update_format_options_in_auto_email_report | ||||
frappe.patches.v8_1.delete_custom_docperm_if_doctype_not_exists | frappe.patches.v8_1.delete_custom_docperm_if_doctype_not_exists | ||||
frappe.patches.v8_5.delete_email_group_member_with_invalid_emails | frappe.patches.v8_5.delete_email_group_member_with_invalid_emails | ||||
frappe.patches.v8_x.update_user_permission |
@@ -0,0 +1,25 @@ | |||||
import frappe | |||||
def execute(): | |||||
frappe.reload_doc('core', 'doctype', 'user_permission') | |||||
frappe.delete_doc('core', 'page', 'user-permissions') | |||||
for perm in frappe.db.sql(""" | |||||
select | |||||
name, parent, defkey, defvalue | |||||
from | |||||
tabDefaultValue | |||||
where | |||||
parent not in ('__default', '__global') | |||||
and | |||||
substr(defkey,1,1)!='_' | |||||
and | |||||
parenttype='User Permission' | |||||
""", as_dict=True): | |||||
frappe.get_doc(dict( | |||||
doctype='User Permission', | |||||
user=perm.parent, | |||||
allow=perm.defkey, | |||||
for_value=perm.defvalue | |||||
)).insert(ignore_permissions = True) | |||||
frappe.db.sql('delete from tabDefaultValue where parenttype="User Permission"') |
@@ -7,7 +7,6 @@ import frappe, copy, json | |||||
from frappe import _, msgprint | from frappe import _, msgprint | ||||
from frappe.utils import cint | from frappe.utils import cint | ||||
import frappe.share | import frappe.share | ||||
rights = ("read", "write", "create", "delete", "submit", "cancel", "amend", | rights = ("read", "write", "create", "delete", "submit", "cancel", "amend", | ||||
"print", "email", "report", "import", "export", "set_user_permissions", "share") | "print", "email", "report", "import", "export", "set_user_permissions", "share") | ||||
@@ -25,6 +24,9 @@ def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None): | |||||
""" | """ | ||||
if not user: user = frappe.session.user | if not user: user = frappe.session.user | ||||
if verbose: | |||||
print('--- Checking for {0} {1} ---'.format(doctype, doc.name if doc else '-')) | |||||
if frappe.is_table(doctype): | if frappe.is_table(doctype): | ||||
if verbose: print("Table type, always true") | if verbose: print("Table type, always true") | ||||
return True | return True | ||||
@@ -40,7 +42,7 @@ def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None): | |||||
return False | return False | ||||
if user=="Administrator": | if user=="Administrator": | ||||
if verbose: print("Administrator") | |||||
if verbose: print("Allowing Administrator") | |||||
return True | return True | ||||
def false_if_not_shared(): | def false_if_not_shared(): | ||||
@@ -210,7 +212,10 @@ def get_role_permissions(meta, user=None, verbose=False): | |||||
if p.user_permission_doctypes: | if p.user_permission_doctypes: | ||||
# set user_permission_doctypes in perms | # set user_permission_doctypes in perms | ||||
user_permission_doctypes = json.loads(p.user_permission_doctypes) | |||||
try: | |||||
user_permission_doctypes = json.loads(p.user_permission_doctypes) | |||||
except ValueError: | |||||
user_permission_doctypes = [] | |||||
else: | else: | ||||
user_permission_doctypes = get_linked_doctypes(meta.name) | user_permission_doctypes = get_linked_doctypes(meta.name) | ||||
@@ -247,8 +252,12 @@ def get_role_permissions(meta, user=None, verbose=False): | |||||
return frappe.local.role_permissions[cache_key] | return frappe.local.role_permissions[cache_key] | ||||
def get_user_permissions(user): | |||||
from frappe.core.doctype.user_permission.user_permission import get_user_permissions | |||||
return get_user_permissions(user) | |||||
def user_has_permission(doc, verbose=True, user=None, user_permission_doctypes=None): | def user_has_permission(doc, verbose=True, user=None, user_permission_doctypes=None): | ||||
from frappe.defaults import get_user_permissions | |||||
from frappe.core.doctype.user_permission.user_permission import get_user_permissions | |||||
user_permissions = get_user_permissions(user) | user_permissions = get_user_permissions(user) | ||||
user_permission_doctypes = get_user_permission_doctypes(user_permission_doctypes, user_permissions) | user_permission_doctypes = get_user_permission_doctypes(user_permission_doctypes, user_permissions) | ||||
@@ -258,6 +267,10 @@ def user_has_permission(doc, verbose=True, user=None, user_permission_doctypes=N | |||||
messages = {} | messages = {} | ||||
if not user_permission_doctypes: | |||||
# no doctypes restricted | |||||
end_result = True | |||||
# check multiple sets of user_permission_doctypes using OR condition | # check multiple sets of user_permission_doctypes using OR condition | ||||
for doctypes in user_permission_doctypes: | for doctypes in user_permission_doctypes: | ||||
result = True | result = True | ||||
@@ -309,9 +322,9 @@ def has_controller_permissions(doc, ptype, user=None): | |||||
def get_doctypes_with_read(): | def get_doctypes_with_read(): | ||||
return list(set([p.parent for p in get_valid_perms()])) | return list(set([p.parent for p in get_valid_perms()])) | ||||
def get_valid_perms(doctype=None): | |||||
def get_valid_perms(doctype=None, user=None): | |||||
'''Get valid permissions for the current user from DocPerm and Custom DocPerm''' | '''Get valid permissions for the current user from DocPerm and Custom DocPerm''' | ||||
roles = get_roles() | |||||
roles = get_roles(user) | |||||
perms = get_perms_for(roles) | perms = get_perms_for(roles) | ||||
custom_perms = get_perms_for(roles, 'Custom DocPerm') | custom_perms = get_perms_for(roles, 'Custom DocPerm') | ||||
@@ -360,7 +373,8 @@ def get_roles(user=None, with_standard=True): | |||||
def get_perms_for(roles, perm_doctype='DocPerm'): | def get_perms_for(roles, perm_doctype='DocPerm'): | ||||
'''Get perms for given roles''' | '''Get perms for given roles''' | ||||
return frappe.db.sql("""select * from `tab{doctype}` where docstatus=0 | |||||
return frappe.db.sql(""" | |||||
select * from `tab{doctype}` where docstatus=0 | |||||
and ifnull(permlevel,0)=0 | and ifnull(permlevel,0)=0 | ||||
and role in ({roles})""".format(doctype = perm_doctype, | and role in ({roles})""".format(doctype = perm_doctype, | ||||
roles=", ".join(["%s"]*len(roles))), tuple(roles), as_dict=1) | roles=", ".join(["%s"]*len(roles))), tuple(roles), as_dict=1) | ||||
@@ -386,22 +400,28 @@ def set_user_permission_if_allowed(doctype, name, user, with_message=False): | |||||
if get_role_permissions(frappe.get_meta(doctype), user).set_user_permissions!=1: | if get_role_permissions(frappe.get_meta(doctype), user).set_user_permissions!=1: | ||||
add_user_permission(doctype, name, user, with_message) | add_user_permission(doctype, name, user, with_message) | ||||
def add_user_permission(doctype, name, user, with_message=False): | |||||
'''Add user default''' | |||||
if name not in frappe.defaults.get_user_permissions(user).get(doctype, []): | |||||
def add_user_permission(doctype, name, user, apply=False): | |||||
'''Add user permission''' | |||||
from frappe.core.doctype.user_permission.user_permission import get_user_permissions | |||||
if name not in get_user_permissions(user).get(doctype, []): | |||||
if not frappe.db.exists(doctype, name): | if not frappe.db.exists(doctype, name): | ||||
frappe.throw(_("{0} {1} not found").format(_(doctype), name), frappe.DoesNotExistError) | frappe.throw(_("{0} {1} not found").format(_(doctype), name), frappe.DoesNotExistError) | ||||
frappe.defaults.add_default(doctype, name, user, "User Permission") | |||||
elif with_message: | |||||
msgprint(_("Permission already set")) | |||||
frappe.get_doc(dict( | |||||
doctype='User Permission', | |||||
user=user, | |||||
allow=doctype, | |||||
for_value=name, | |||||
apply_for_all_roles=apply | |||||
)).insert() | |||||
def remove_user_permission(doctype, name, user, default_value_name=None): | |||||
frappe.defaults.clear_default(key=doctype, value=name, parent=user, parenttype="User Permission", | |||||
name=default_value_name) | |||||
def remove_user_permission(doctype, name, user): | |||||
user_permission_name = frappe.db.get_value('User Permission', | |||||
dict(user=user, allow=doctype, for_value=name)) | |||||
frappe.delete_doc('User Permission', user_permission_name) | |||||
def clear_user_permissions_for_doctype(doctype): | def clear_user_permissions_for_doctype(doctype): | ||||
frappe.defaults.clear_default(parenttype="User Permission", key=doctype) | |||||
frappe.cache().delete_value('user_permissions') | |||||
def can_import(doctype, raise_exception=False): | def can_import(doctype, raise_exception=False): | ||||
if not ("System Manager" in frappe.get_roles() or has_permission(doctype, "import")): | if not ("System Manager" in frappe.get_roles() or has_permission(doctype, "import")): | ||||
@@ -426,9 +446,10 @@ def apply_user_permissions(doctype, ptype, user=None): | |||||
def get_user_permission_doctypes(user_permission_doctypes, user_permissions): | def get_user_permission_doctypes(user_permission_doctypes, user_permissions): | ||||
"""returns a list of list like [["User", "Blog Post"], ["User"]]""" | """returns a list of list like [["User", "Blog Post"], ["User"]]""" | ||||
if cint(frappe.db.get_single_value("System Settings", "ignore_user_permissions_if_missing")): | |||||
if cint(frappe.get_system_settings('ignore_user_permissions_if_missing')): | |||||
# select those user permission doctypes for which user permissions exist! | # select those user permission doctypes for which user permissions exist! | ||||
user_permission_doctypes = [list(set(doctypes).intersection(set(user_permissions.keys()))) | |||||
user_permission_doctypes = [ | |||||
list(set(doctypes).intersection(set(user_permissions.keys()))) | |||||
for doctypes in user_permission_doctypes] | for doctypes in user_permission_doctypes] | ||||
if len(user_permission_doctypes) > 1: | if len(user_permission_doctypes) > 1: | ||||
@@ -452,6 +473,22 @@ def get_user_permission_doctypes(user_permission_doctypes, user_permissions): | |||||
return user_permission_doctypes | return user_permission_doctypes | ||||
def update_permission_property(doctype, role, permlevel, ptype, value=None, validate=True): | |||||
'''Update a property in Custom Perm''' | |||||
from frappe.core.doctype.doctype.doctype import validate_permissions_for_doctype | |||||
out = setup_custom_perms(doctype) | |||||
name = frappe.get_value('Custom DocPerm', dict(parent=doctype, role=role, | |||||
permlevel=permlevel)) | |||||
frappe.db.sql(""" | |||||
update `tabCustom DocPerm` | |||||
set `{0}`=%s where name=%s""".format(ptype), (value, name)) | |||||
if validate: | |||||
validate_permissions_for_doctype(doctype) | |||||
return out | |||||
def setup_custom_perms(parent): | def setup_custom_perms(parent): | ||||
'''if custom permssions are not setup for the current doctype, set them up''' | '''if custom permssions are not setup for the current doctype, set them up''' | ||||
if not frappe.db.exists('Custom DocPerm', dict(parent=parent)): | if not frappe.db.exists('Custom DocPerm', dict(parent=parent)): | ||||
@@ -77,10 +77,6 @@ frappe.defaults = { | |||||
}, | }, | ||||
get_user_permissions: function() { | get_user_permissions: function() { | ||||
return frappe.defaults.user_permissions; | |||||
return frappe.boot.user_permissions; | |||||
}, | }, | ||||
set_user_permissions: function(user_permissions) { | |||||
if(!user_permissions) return; | |||||
frappe.defaults.user_permissions = $.extend(frappe.defaults.user_permissions || {}, user_permissions); | |||||
} | |||||
} | } |
@@ -599,9 +599,9 @@ frappe.views.ListView = frappe.ui.BaseList.extend({ | |||||
}, true); | }, true); | ||||
} | } | ||||
if (frappe.model.can_set_user_permissions(this.doctype)) { | if (frappe.model.can_set_user_permissions(this.doctype)) { | ||||
this.page.add_menu_item(__('User Permissions Manager'), function () { | |||||
frappe.set_route('user-permissions', { | |||||
doctype: me.doctype | |||||
this.page.add_menu_item(__('User Permissions'), function () { | |||||
frappe.set_route('List', 'User Permission', { | |||||
allow: me.doctype | |||||
}); | }); | ||||
}, true); | }, true); | ||||
} | } | ||||
@@ -127,8 +127,10 @@ $.extend(frappe.model, { | |||||
var user_default = ""; | var user_default = ""; | ||||
var user_permissions = frappe.defaults.get_user_permissions(); | var user_permissions = frappe.defaults.get_user_permissions(); | ||||
var meta = frappe.get_meta(doc.doctype); | var meta = frappe.get_meta(doc.doctype); | ||||
var has_user_permissions = (df.fieldtype==="Link" && user_permissions | |||||
&& df.ignore_user_permissions != 1 && user_permissions[df.options]); | |||||
var has_user_permissions = (df.fieldtype==="Link" | |||||
&& user_permissions | |||||
&& df.ignore_user_permissions != 1 | |||||
&& user_permissions[df.options]); | |||||
// don't set defaults for "User" link field using User Permissions! | // don't set defaults for "User" link field using User Permissions! | ||||
if (df.fieldtype==="Link" && df.options!=="User") { | if (df.fieldtype==="Link" && df.options!=="User") { | ||||
@@ -112,7 +112,6 @@ $.extend(frappe.model, { | |||||
localStorage["_doctype:" + doctype] = JSON.stringify(r.docs); | localStorage["_doctype:" + doctype] = JSON.stringify(r.docs); | ||||
} | } | ||||
frappe.model.init_doctype(doctype); | frappe.model.init_doctype(doctype); | ||||
frappe.defaults.set_user_permissions(r.user_permissions); | |||||
if(r.user_settings) { | if(r.user_settings) { | ||||
// remember filters and other settings from last view | // remember filters and other settings from last view | ||||
@@ -103,7 +103,7 @@ frappe.views.QueryReport = Class.extend({ | |||||
doctype: "Report", | doctype: "Report", | ||||
name: me.report_name | name: me.report_name | ||||
}; | }; | ||||
frappe.set_route("user-permissions"); | |||||
frappe.set_route('List', 'User Permission'); | |||||
}, true); | }, true); | ||||
} | } | ||||
@@ -821,12 +821,12 @@ frappe.views.ReportView = frappe.ui.BaseList.extend({ | |||||
make_user_permissions: function() { | make_user_permissions: function() { | ||||
var me = this; | var me = this; | ||||
if(this.docname && frappe.model.can_set_user_permissions("Report")) { | if(this.docname && frappe.model.can_set_user_permissions("Report")) { | ||||
this.page.add_menu_item(__("User Permissions Manager"), function() { | |||||
this.page.add_menu_item(__("User Permissions"), function() { | |||||
frappe.route_options = { | frappe.route_options = { | ||||
doctype: "Report", | doctype: "Report", | ||||
name: me.docname | name: me.docname | ||||
}; | }; | ||||
frappe.set_route("user-permissions"); | |||||
frappe.set_route('List', 'User Permission'); | |||||
}, true); | }, true); | ||||
} | } | ||||
}, | }, | ||||
@@ -266,12 +266,12 @@ def make_test_records_for_doctype(doctype, verbose=0, force=False): | |||||
frappe.local.test_objects[doctype] += test_module._make_test_records(verbose) | frappe.local.test_objects[doctype] += test_module._make_test_records(verbose) | ||||
elif hasattr(test_module, "test_records"): | elif hasattr(test_module, "test_records"): | ||||
frappe.local.test_objects[doctype] += make_test_objects(doctype, test_module.test_records, verbose) | |||||
frappe.local.test_objects[doctype] += make_test_objects(doctype, test_module.test_records, verbose, force) | |||||
else: | else: | ||||
test_records = frappe.get_test_records(doctype) | test_records = frappe.get_test_records(doctype) | ||||
if test_records: | if test_records: | ||||
frappe.local.test_objects[doctype] += make_test_objects(doctype, test_records, verbose) | |||||
frappe.local.test_objects[doctype] += make_test_objects(doctype, test_records, verbose, force) | |||||
elif verbose: | elif verbose: | ||||
print_mandatory_fields(doctype) | print_mandatory_fields(doctype) | ||||
@@ -9,9 +9,11 @@ import frappe.defaults | |||||
import unittest | import unittest | ||||
import json | import json | ||||
import frappe.model.meta | 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 | |||||
from frappe.permissions import (add_user_permission, remove_user_permission, | |||||
clear_user_permissions_for_doctype, get_doc_permissions, add_permission, | |||||
get_valid_perms) | |||||
from frappe.core.page.permission_manager.permission_manager import update, reset | from frappe.core.page.permission_manager.permission_manager import update, reset | ||||
from frappe.test_runner import make_test_records_for_doctype | |||||
test_records = frappe.get_test_records('Blog Post') | test_records = frappe.get_test_records('Blog Post') | ||||
@@ -24,6 +26,7 @@ class TestPermissions(unittest.TestCase): | |||||
user = frappe.get_doc("User", "test1@example.com") | user = frappe.get_doc("User", "test1@example.com") | ||||
user.add_roles("Website Manager") | user.add_roles("Website Manager") | ||||
user.add_roles("System Manager") | |||||
user = frappe.get_doc("User", "test2@example.com") | user = frappe.get_doc("User", "test2@example.com") | ||||
user.add_roles("Blogger") | user.add_roles("Blogger") | ||||
@@ -36,6 +39,8 @@ class TestPermissions(unittest.TestCase): | |||||
reset('Contact') | reset('Contact') | ||||
reset('Salutation') | reset('Salutation') | ||||
frappe.db.sql('delete from `tabUser Permission`') | |||||
self.set_ignore_user_permissions_if_missing(0) | self.set_ignore_user_permissions_if_missing(0) | ||||
frappe.set_user("test1@example.com") | frappe.set_user("test1@example.com") | ||||
@@ -78,7 +83,7 @@ class TestPermissions(unittest.TestCase): | |||||
def test_user_permissions_in_doc(self): | def test_user_permissions_in_doc(self): | ||||
self.set_user_permission_doctypes(["Blog Category"]) | self.set_user_permission_doctypes(["Blog Category"]) | ||||
frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category 1", | |||||
add_user_permission("Blog Category", "_Test Blog Category 1", | |||||
"test2@example.com") | "test2@example.com") | ||||
frappe.set_user("test2@example.com") | frappe.set_user("test2@example.com") | ||||
@@ -94,7 +99,7 @@ class TestPermissions(unittest.TestCase): | |||||
def test_user_permissions_in_report(self): | def test_user_permissions_in_report(self): | ||||
self.set_user_permission_doctypes(["Blog Category"]) | self.set_user_permission_doctypes(["Blog Category"]) | ||||
frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category 1", "test2@example.com") | |||||
add_user_permission("Blog Category", "_Test Blog Category 1", "test2@example.com") | |||||
frappe.set_user("test2@example.com") | frappe.set_user("test2@example.com") | ||||
names = [d.name for d in frappe.get_list("Blog Post", fields=["name", "blog_category"])] | names = [d.name for d in frappe.get_list("Blog Post", fields=["name", "blog_category"])] | ||||
@@ -103,7 +108,7 @@ class TestPermissions(unittest.TestCase): | |||||
self.assertFalse("-test-blog-post" in names) | self.assertFalse("-test-blog-post" in names) | ||||
def test_default_values(self): | def test_default_values(self): | ||||
frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category 1", "test2@example.com") | |||||
add_user_permission("Blog Category", "_Test Blog Category 1", "test2@example.com") | |||||
frappe.set_user("test2@example.com") | frappe.set_user("test2@example.com") | ||||
doc = frappe.new_doc("Blog Post") | doc = frappe.new_doc("Blog Post") | ||||
@@ -139,14 +144,14 @@ class TestPermissions(unittest.TestCase): | |||||
def test_set_user_permissions(self): | def test_set_user_permissions(self): | ||||
frappe.set_user("test1@example.com") | frappe.set_user("test1@example.com") | ||||
add("test2@example.com", "Blog Post", "-test-blog-post") | |||||
add_user_permission("Blog Post", "-test-blog-post", "test2@example.com") | |||||
def test_not_allowed_to_set_user_permissions(self): | def test_not_allowed_to_set_user_permissions(self): | ||||
frappe.set_user("test2@example.com") | frappe.set_user("test2@example.com") | ||||
# this user can't add user permissions | # this user can't add user permissions | ||||
self.assertRaises(frappe.PermissionError, add, | |||||
"test2@example.com", "Blog Post", "-test-blog-post") | |||||
self.assertRaises(frappe.PermissionError, add_user_permission, | |||||
"Blog Post", "-test-blog-post", "test2@example.com") | |||||
def test_read_if_explicit_user_permissions_are_set(self): | def test_read_if_explicit_user_permissions_are_set(self): | ||||
self.set_user_permission_doctypes(["Blog Post"]) | self.set_user_permission_doctypes(["Blog Post"]) | ||||
@@ -165,13 +170,12 @@ class TestPermissions(unittest.TestCase): | |||||
def test_not_allowed_to_remove_user_permissions(self): | def test_not_allowed_to_remove_user_permissions(self): | ||||
self.test_set_user_permissions() | self.test_set_user_permissions() | ||||
defname = get_permissions("test2@example.com", "Blog Post", "-test-blog-post")[0].name | |||||
frappe.set_user("test2@example.com") | frappe.set_user("test2@example.com") | ||||
# user cannot remove their own user permissions | # user cannot remove their own user permissions | ||||
self.assertRaises(frappe.PermissionError, remove, | |||||
"test2@example.com", defname, "Blog Post", "-test-blog-post") | |||||
self.assertRaises(frappe.PermissionError, remove_user_permission, | |||||
"Blog Post", "-test-blog-post", "test2@example.com") | |||||
def test_user_permissions_based_on_blogger(self): | def test_user_permissions_based_on_blogger(self): | ||||
frappe.set_user("test2@example.com") | frappe.set_user("test2@example.com") | ||||
@@ -181,7 +185,7 @@ class TestPermissions(unittest.TestCase): | |||||
self.set_user_permission_doctypes(["Blog Post"]) | self.set_user_permission_doctypes(["Blog Post"]) | ||||
frappe.set_user("test1@example.com") | frappe.set_user("test1@example.com") | ||||
add("test2@example.com", "Blog Post", "-test-blog-post") | |||||
add_user_permission("Blog Post", "-test-blog-post", "test2@example.com") | |||||
frappe.set_user("test2@example.com") | frappe.set_user("test2@example.com") | ||||
doc = frappe.get_doc("Blog Post", "-test-blog-post-1") | doc = frappe.get_doc("Blog Post", "-test-blog-post-1") | ||||
@@ -199,9 +203,9 @@ class TestPermissions(unittest.TestCase): | |||||
blog_post.get_field("title").set_only_once = 0 | blog_post.get_field("title").set_only_once = 0 | ||||
def test_user_permission_doctypes(self): | def test_user_permission_doctypes(self): | ||||
frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category 1", | |||||
add_user_permission("Blog Category", "_Test Blog Category 1", | |||||
"test2@example.com") | "test2@example.com") | ||||
frappe.permissions.add_user_permission("Blogger", "_Test Blogger 1", | |||||
add_user_permission("Blogger", "_Test Blogger 1", | |||||
"test2@example.com") | "test2@example.com") | ||||
frappe.set_user("test2@example.com") | frappe.set_user("test2@example.com") | ||||
@@ -221,9 +225,9 @@ class TestPermissions(unittest.TestCase): | |||||
def if_owner_setup(self): | def if_owner_setup(self): | ||||
update('Blog Post', 'Blogger', 0, 'if_owner', 1) | update('Blog Post', 'Blogger', 0, 'if_owner', 1) | ||||
frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category 1", | |||||
add_user_permission("Blog Category", "_Test Blog Category 1", | |||||
"test2@example.com") | "test2@example.com") | ||||
frappe.permissions.add_user_permission("Blogger", "_Test Blogger 1", | |||||
add_user_permission("Blogger", "_Test Blogger 1", | |||||
"test2@example.com") | "test2@example.com") | ||||
update('Blog Post', 'Blogger', 0, 'user_permission_doctypes', json.dumps(["Blog Category"])) | update('Blog Post', 'Blogger', 0, 'user_permission_doctypes', json.dumps(["Blog Category"])) | ||||
@@ -231,11 +235,13 @@ class TestPermissions(unittest.TestCase): | |||||
frappe.model.meta.clear_cache("Blog Post") | frappe.model.meta.clear_cache("Blog Post") | ||||
def set_user_permission_doctypes(self, user_permission_doctypes): | def set_user_permission_doctypes(self, user_permission_doctypes): | ||||
set_user_permission_doctypes(doctype="Blog Post", role="Blogger", | |||||
set_user_permission_doctypes(["Blog Post"], role="Blogger", | |||||
apply_user_permissions=1, user_permission_doctypes=user_permission_doctypes) | apply_user_permissions=1, user_permission_doctypes=user_permission_doctypes) | ||||
def test_insert_if_owner_with_user_permissions(self): | def test_insert_if_owner_with_user_permissions(self): | ||||
"""If `If Owner` is checked for a Role, check if that document is allowed to be read, updated, submitted, etc. except be created, even if the document is restricted based on User Permissions.""" | """If `If Owner` is checked for a Role, check if that document is allowed to be read, updated, submitted, etc. except be created, even if the document is restricted based on User Permissions.""" | ||||
frappe.delete_doc('Blog Post', '-test-blog-post-title') | |||||
self.set_user_permission_doctypes(["Blog Category"]) | self.set_user_permission_doctypes(["Blog Category"]) | ||||
self.if_owner_setup() | self.if_owner_setup() | ||||
@@ -252,7 +258,7 @@ class TestPermissions(unittest.TestCase): | |||||
self.assertRaises(frappe.PermissionError, doc.insert) | self.assertRaises(frappe.PermissionError, doc.insert) | ||||
frappe.set_user("Administrator") | frappe.set_user("Administrator") | ||||
frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category", | |||||
add_user_permission("Blog Category", "_Test Blog Category", | |||||
"test2@example.com") | "test2@example.com") | ||||
frappe.set_user("test2@example.com") | frappe.set_user("test2@example.com") | ||||
@@ -273,8 +279,8 @@ class TestPermissions(unittest.TestCase): | |||||
self.set_user_permission_doctypes(['Blog Category', 'Blog Post', 'Blogger']) | self.set_user_permission_doctypes(['Blog Category', 'Blog Post', 'Blogger']) | ||||
frappe.set_user("Administrator") | frappe.set_user("Administrator") | ||||
frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category", | |||||
"test2@example.com") | |||||
# add_user_permission("Blog Category", "_Test Blog Category", | |||||
# "test2@example.com") | |||||
frappe.set_user("test2@example.com") | frappe.set_user("test2@example.com") | ||||
doc = frappe.get_doc({ | doc = frappe.get_doc({ | ||||
@@ -294,33 +300,73 @@ class TestPermissions(unittest.TestCase): | |||||
self.assertTrue(doc.has_permission("write")) | self.assertTrue(doc.has_permission("write")) | ||||
def test_strict_user_permissions(self): | def test_strict_user_permissions(self): | ||||
"""If `Strict User Permissions` is checked in System Settings, show records even if User Permissions are missing for a linked doctype""" | |||||
set_user_permission_doctypes(doctype="Contact", role="Sales User", | |||||
"""If `Strict User Permissions` is checked in System Settings, | |||||
show records even if User Permissions are missing for a linked | |||||
doctype""" | |||||
frappe.set_user("Administrator") | |||||
frappe.db.sql('delete from tabContact') | |||||
make_test_records_for_doctype('Contact', force=True) | |||||
set_user_permission_doctypes("Contact", role="Sales User", | |||||
apply_user_permissions=1, user_permission_doctypes=['Salutation']) | apply_user_permissions=1, user_permission_doctypes=['Salutation']) | ||||
set_user_permission_doctypes(doctype="Salutation", role="All", | |||||
set_user_permission_doctypes("Salutation", role="All", | |||||
apply_user_permissions=1, user_permission_doctypes=['Salutation']) | apply_user_permissions=1, user_permission_doctypes=['Salutation']) | ||||
frappe.set_user("Administrator") | |||||
frappe.permissions.add_user_permission("Salutation", "Mr", "test3@example.com") | |||||
add_user_permission("Salutation", "Mr", "test3@example.com") | |||||
self.set_strict_user_permissions(0) | self.set_strict_user_permissions(0) | ||||
frappe.set_user("test3@example.com") | frappe.set_user("test3@example.com") | ||||
self.assertEquals(len(frappe.get_list("Contact")),2) | |||||
self.assertEquals(len(frappe.get_list("Contact")), 2) | |||||
frappe.set_user("Administrator") | frappe.set_user("Administrator") | ||||
self.set_strict_user_permissions(1) | self.set_strict_user_permissions(1) | ||||
frappe.set_user("test3@example.com") | frappe.set_user("test3@example.com") | ||||
self.assertTrue(len(frappe.get_list("Contact")),1) | |||||
self.assertTrue(len(frappe.get_list("Contact")), 1) | |||||
frappe.set_user("Administrator") | frappe.set_user("Administrator") | ||||
self.set_strict_user_permissions(0) | self.set_strict_user_permissions(0) | ||||
def test_automatic_apply_user_permissions(self): | |||||
'''Test user permissions are automatically applied when a user permission | |||||
is created''' | |||||
# create a user | |||||
frappe.get_doc(dict(doctype='User', email='test_user_perm@example.com', | |||||
first_name='tester')).insert(ignore_if_duplicate=True) | |||||
frappe.get_doc(dict(doctype='Role', role_name='Test Role User Perm') | |||||
).insert(ignore_if_duplicate=True) | |||||
# add a permission for event | |||||
add_permission('DocType', 'Test Role User Perm') | |||||
frappe.get_doc('User', 'test_user_perm@example.com').add_roles('Test Role User Perm') | |||||
def set_user_permission_doctypes(doctype, role, apply_user_permissions, user_permission_doctypes): | |||||
# add user permission | |||||
add_user_permission('Module Def', 'Core', 'test_user_perm@example.com', True) | |||||
# check if user permission is applied in the new role | |||||
_perm = None | |||||
for perm in get_valid_perms('DocType', 'test_user_perm@example.com'): | |||||
if perm.role == 'Test Role User Perm': | |||||
_perm = perm | |||||
self.assertEqual(_perm.apply_user_permissions, 1) | |||||
# restrict by module | |||||
self.assertTrue('Module Def' in json.loads(_perm.user_permission_doctypes)) | |||||
def set_user_permission_doctypes(doctypes, role, apply_user_permissions, | |||||
user_permission_doctypes): | |||||
user_permission_doctypes = None if not user_permission_doctypes else json.dumps(user_permission_doctypes) | user_permission_doctypes = None if not user_permission_doctypes else json.dumps(user_permission_doctypes) | ||||
update(doctype, role, 0, 'apply_user_permissions', 1) | |||||
update(doctype, role, 0, 'user_permission_doctypes', user_permission_doctypes) | |||||
if isinstance(doctypes, basestring): | |||||
doctypes = [doctypes] | |||||
for doctype in doctypes: | |||||
update(doctype, role, 0, 'apply_user_permissions', 1) | |||||
update(doctype, role, 0, 'user_permission_doctypes', | |||||
user_permission_doctypes) | |||||
frappe.clear_cache(doctype=doctype) | |||||
frappe.clear_cache(doctype=doctype) |