@@ -13,6 +13,17 @@ | |||
frappe.ui.form.on('DocType', { | |||
refresh: function(frm) { | |||
frm.set_query('role', 'permissions', function(doc) { | |||
if (doc.custom && frappe.session.user != 'Administrator') { | |||
return { | |||
query: "frappe.core.doctype.role.role.role_query", | |||
filters: { | |||
name: ['not in', ['All']] | |||
} | |||
}; | |||
} | |||
}); | |||
if(frappe.session.user !== "Administrator" || !frappe.boot.developer_mode) { | |||
if(frm.is_new()) { | |||
frm.set_value("custom", 1); | |||
@@ -1112,6 +1112,20 @@ def validate_permissions(doctype, for_remove=False, alert=False): | |||
if d.get("import") and not isimportable: | |||
frappe.throw(_("{0}: Cannot set import as {1} is not importable").format(get_txt(d), doctype)) | |||
def validate_permission_for_all_role(d): | |||
if frappe.session.user == 'Administrator': return | |||
if doctype.custom: | |||
if d.role == 'All': | |||
frappe.throw(_('Row # {0}: Non administrator user can not set the role {1} to the custom doctype') | |||
.format(d.idx, frappe.bold(_('All'))), title=_('Permissions Error')) | |||
roles = [row.name for row in frappe.get_all('Role', filters={'is_custom': 1})] | |||
if d.role in roles: | |||
frappe.throw(_('Row # {0}: Non administrator user can not set the role {1} to the custom doctype') | |||
.format(d.idx, frappe.bold(_(d.role))), title=_('Permissions Error')) | |||
for d in permissions: | |||
if not d.permlevel: | |||
d.permlevel=0 | |||
@@ -1123,6 +1137,7 @@ def validate_permissions(doctype, for_remove=False, alert=False): | |||
check_if_importable(d) | |||
check_level_zero_is_set(d) | |||
remove_rights_for_single(d) | |||
validate_permission_for_all_role(d) | |||
def make_module_and_roles(doc, perm_fieldname="permissions"): | |||
"""Make `Module Def` and `Role` records if already not made. Called while installing.""" | |||
@@ -3,6 +3,9 @@ | |||
frappe.ui.form.on('Role', { | |||
refresh: function(frm) { | |||
frm.set_df_property('is_custom', 'read_only', | |||
frappe.session.user == 'Administrator' ? false : true); | |||
frm.add_custom_button("Role Permissions Manager", function() { | |||
frappe.route_options = {"role": frm.doc.name}; | |||
frappe.set_route("permission-manager"); | |||
@@ -25,7 +25,8 @@ | |||
"form_settings_section", | |||
"form_sidebar", | |||
"timeline", | |||
"dashboard" | |||
"dashboard", | |||
"is_custom" | |||
], | |||
"fields": [ | |||
{ | |||
@@ -141,13 +142,20 @@ | |||
"fieldname": "notifications", | |||
"fieldtype": "Check", | |||
"label": "Notifications" | |||
}, | |||
{ | |||
"default": "0", | |||
"fieldname": "is_custom", | |||
"fieldtype": "Check", | |||
"in_list_view": 1, | |||
"label": "Is Custom" | |||
} | |||
], | |||
"icon": "fa fa-bookmark", | |||
"idx": 1, | |||
"index_web_pages_for_search": 1, | |||
"links": [], | |||
"modified": "2020-12-03 14:08:38.181035", | |||
"modified": "2021-01-27 10:35:37.638350", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "Role", | |||
@@ -53,7 +53,6 @@ class Role(Document): | |||
if user_type != user.user_type: | |||
user.save() | |||
def get_info_based_on_role(role, field='email'): | |||
''' Get information of all users that have been assigned this role ''' | |||
users = frappe.get_list("Has Role", filters={"role": role, "parenttype": "User"}, | |||
@@ -73,3 +72,15 @@ def get_user_info(users, field='email'): | |||
def get_users(role): | |||
return [d.parent for d in frappe.get_all("Has Role", filters={"role": role, "parenttype": "User"}, | |||
fields=["parent"])] | |||
# searches for active employees | |||
@frappe.whitelist() | |||
@frappe.validate_and_sanitize_search_inputs | |||
def role_query(doctype, txt, searchfield, start, page_len, filters): | |||
filters.update({ | |||
'is_custom': 0, 'name': ('like', '%{0}%'.format(txt)) | |||
}) | |||
return frappe.get_all('Role', limit_start=start, limit_page_length=page_len, | |||
filters=filters, as_list=1) |
@@ -59,10 +59,11 @@ frappe.ui.form.on('User', { | |||
onload: function(frm) { | |||
frm.can_edit_roles = has_access_to_edit_user(); | |||
if (frm.can_edit_roles && !frm.is_new()) { | |||
if (!frm.roles_editor) { | |||
if (frm.can_edit_roles && !frm.is_new() && frm.doc.user_type == 'System User') { | |||
if(!frm.roles_editor) { | |||
const role_area = $('<div class="role-editor">') | |||
.appendTo(frm.fields_dict.roles_html.wrapper); | |||
frm.roles_editor = new frappe.RoleEditor(role_area, frm, frm.doc.role_profile_name ? 1 : 0); | |||
var module_area = $('<div>') | |||
@@ -75,7 +76,7 @@ frappe.ui.form.on('User', { | |||
}, | |||
refresh: function(frm) { | |||
var doc = frm.doc; | |||
if(!frm.is_new() && !frm.roles_editor && frm.can_edit_roles) { | |||
if (frm.doc.user_type == 'System User' && !frm.is_new() && !frm.roles_editor && frm.can_edit_roles) { | |||
frm.reload_doc(); | |||
return; | |||
} | |||
@@ -191,7 +191,7 @@ | |||
"print_hide": 1 | |||
}, | |||
{ | |||
"depends_on": "enabled", | |||
"depends_on": "eval:doc.user_type == 'System User' && doc.enabled == 1", | |||
"fieldname": "sb1", | |||
"fieldtype": "Section Break", | |||
"label": "Roles", | |||
@@ -391,6 +391,7 @@ | |||
}, | |||
{ | |||
"collapsible": 1, | |||
"depends_on": "eval:doc.user_type == 'System User'", | |||
"fieldname": "sb_allow_modules", | |||
"fieldtype": "Section Break", | |||
"label": "Allow Modules", | |||
@@ -453,18 +454,18 @@ | |||
"label": "Simultaneous Sessions" | |||
}, | |||
{ | |||
"bold": 1, | |||
"default": "System User", | |||
"description": "If the user has any role checked, then the user becomes a \"System User\". \"System User\" has access to the desktop", | |||
"fieldname": "user_type", | |||
"fieldtype": "Select", | |||
"fieldtype": "Link", | |||
"in_list_view": 1, | |||
"in_standard_filter": 1, | |||
"label": "User Type", | |||
"oldfieldname": "user_type", | |||
"oldfieldtype": "Select", | |||
"options": "System User\nWebsite User", | |||
"permlevel": 1, | |||
"read_only": 1 | |||
"options": "User Type", | |||
"permlevel": 1 | |||
}, | |||
{ | |||
"description": "Allow user to login only after this hour (0-24)", | |||
@@ -669,7 +670,7 @@ | |||
} | |||
], | |||
"max_attachments": 5, | |||
"modified": "2021-02-01 16:11:06.037543", | |||
"modified": "2021-02-02 16:11:06.037543", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "User", | |||
@@ -10,7 +10,8 @@ import frappe.share | |||
import frappe.defaults | |||
import frappe.permissions | |||
from frappe.model.document import Document | |||
from frappe.utils import cint, flt, has_gravatar, escape_html, format_datetime, now_datetime, get_formatted_email, today | |||
from frappe.utils import (cint, flt, has_gravatar, escape_html, format_datetime, | |||
now_datetime, get_formatted_email, today) | |||
from frappe import throw, msgprint, _ | |||
from frappe.utils.password import update_password as _update_password, check_password, get_password_reset_limit | |||
from frappe.desk.notifications import clear_notifications | |||
@@ -19,6 +20,7 @@ from frappe.utils.user import get_system_managers | |||
from frappe.website.utils import is_signup_enabled | |||
from frappe.rate_limiter import rate_limit | |||
from frappe.utils.background_jobs import enqueue | |||
from frappe.core.doctype.user_type.user_type import user_linked_with_permission_on_doctype | |||
STANDARD_USERS = ("Guest", "Administrator") | |||
@@ -186,11 +188,36 @@ class User(Document): | |||
_update_password(user=self.name, pwd=new_password, logout_all_sessions=self.logout_all_sessions) | |||
def set_system_user(self): | |||
'''Set as System User if any of the given roles has desk_access''' | |||
if self.has_desk_access() or self.name == 'Administrator': | |||
self.user_type = 'System User' | |||
'''For the standard users like admin and guest, the user type is fixed.''' | |||
user_type_mapper = { | |||
'Administrator': 'System User', | |||
'Guest': 'Website User' | |||
} | |||
if self.user_type and not frappe.get_cached_value('User Type', self.user_type, 'is_standard'): | |||
if user_type_mapper.get(self.name): | |||
self.user_type = user_type_mapper.get(self.name) | |||
else: | |||
self.set_roles_and_modules_based_on_user_type() | |||
else: | |||
self.user_type = 'Website User' | |||
'''Set as System User if any of the given roles has desk_access''' | |||
self.user_type = 'System User' if self.has_desk_access() else 'Website User' | |||
def set_roles_and_modules_based_on_user_type(self): | |||
user_type_doc = frappe.get_cached_doc('User Type', self.user_type) | |||
if user_type_doc.role: | |||
self.roles = [] | |||
# Check whether User has linked with the 'Apply User Permission On' doctype or not | |||
if user_linked_with_permission_on_doctype(user_type_doc, self.name): | |||
self.append('roles', { | |||
'role': user_type_doc.role | |||
}) | |||
frappe.msgprint(_('Role has been set as per the user type {0}') | |||
.format(self.user_type), alert=True) | |||
user_type_doc.update_modules_in_user(self) | |||
def has_desk_access(self): | |||
'''Return true if any of the set roles has desk access''' | |||
@@ -877,7 +904,8 @@ def reset_password(user): | |||
def user_query(doctype, txt, searchfield, start, page_len, filters): | |||
from frappe.desk.reportview import get_match_cond, get_filters_cond | |||
conditions=[] | |||
user_type_condition = "and user_type = 'System User'" | |||
user_type_condition = "and user_type != 'Website User'" | |||
if filters and filters.get('ignore_user_type'): | |||
user_type_condition = '' | |||
filters.pop('ignore_user_type') | |||
@@ -0,0 +1,76 @@ | |||
{ | |||
"actions": [], | |||
"creation": "2021-01-13 01:51:40.158521", | |||
"doctype": "DocType", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"document_type", | |||
"column_break_2", | |||
"is_custom", | |||
"permissions_section", | |||
"read", | |||
"write", | |||
"create" | |||
], | |||
"fields": [ | |||
{ | |||
"fieldname": "document_type", | |||
"fieldtype": "Link", | |||
"in_list_view": 1, | |||
"label": "Document Type", | |||
"options": "DocType", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "permissions_section", | |||
"fieldtype": "Section Break", | |||
"label": "Role Permissions" | |||
}, | |||
{ | |||
"default": "1", | |||
"fieldname": "read", | |||
"fieldtype": "Check", | |||
"in_list_view": 1, | |||
"label": "Read" | |||
}, | |||
{ | |||
"default": "0", | |||
"fieldname": "write", | |||
"fieldtype": "Check", | |||
"in_list_view": 1, | |||
"label": "Write" | |||
}, | |||
{ | |||
"default": "0", | |||
"fieldname": "create", | |||
"fieldtype": "Check", | |||
"in_list_view": 1, | |||
"label": "Create" | |||
}, | |||
{ | |||
"fieldname": "column_break_2", | |||
"fieldtype": "Column Break" | |||
}, | |||
{ | |||
"default": "0", | |||
"fetch_from": "document_type.custom", | |||
"fieldname": "is_custom", | |||
"fieldtype": "Check", | |||
"label": "Is Custom", | |||
"read_only": 1 | |||
} | |||
], | |||
"index_web_pages_for_search": 1, | |||
"istable": 1, | |||
"links": [], | |||
"modified": "2021-01-19 01:25:34.773430", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "User Document Type", | |||
"owner": "Administrator", | |||
"permissions": [], | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_changes": 1 | |||
} |
@@ -0,0 +1,10 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2021, Frappe Technologies and contributors | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
# import frappe | |||
from frappe.model.document import Document | |||
class UserDocumentType(Document): | |||
pass |
@@ -0,0 +1,33 @@ | |||
{ | |||
"actions": [], | |||
"creation": "2021-01-17 18:28:14.208576", | |||
"doctype": "DocType", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"document_type" | |||
], | |||
"fields": [ | |||
{ | |||
"fieldname": "document_type", | |||
"fieldtype": "Link", | |||
"in_list_view": 1, | |||
"label": "Document Type", | |||
"options": "DocType", | |||
"reqd": 1 | |||
} | |||
], | |||
"index_web_pages_for_search": 1, | |||
"istable": 1, | |||
"links": [], | |||
"modified": "2021-01-17 18:45:44.993190", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "User Select Document Type", | |||
"owner": "Administrator", | |||
"permissions": [], | |||
"quick_entry": 1, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_changes": 1 | |||
} |
@@ -0,0 +1,10 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2021, Frappe Technologies and contributors | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
# import frappe | |||
from frappe.model.document import Document | |||
class UserSelectDocumentType(Document): | |||
pass |
@@ -0,0 +1,10 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2021, Frappe Technologies and Contributors | |||
# See license.txt | |||
from __future__ import unicode_literals | |||
# import frappe | |||
import unittest | |||
class TestUserType(unittest.TestCase): | |||
pass |
@@ -0,0 +1,70 @@ | |||
// Copyright (c) 2021, Frappe Technologies and contributors | |||
// For license information, please see license.txt | |||
frappe.ui.form.on('User Type', { | |||
refresh: function(frm) { | |||
frm.toggle_display('is_standard', frappe.boot.developer_mode ? true : false); | |||
frm.set_df_property('is_standard', 'read_only', frappe.boot.developer_mode ? false : true); | |||
const fields = ['role', 'apply_user_permission_on', 'user_id_field', | |||
'user_doctypes', 'select_doctypes', 'user_type_modules']; | |||
frm.toggle_display(fields, frm.doc.is_standard ? false : true); | |||
frm.set_query('document_type', 'user_doctypes', function() { | |||
return { | |||
filters: { | |||
istable: 0 | |||
} | |||
}; | |||
}); | |||
frm.set_query('document_type', 'select_doctypes', function() { | |||
return { | |||
filters: { | |||
istable: 0, | |||
is_submittable: 0 | |||
} | |||
}; | |||
}); | |||
frm.set_query('role', function() { | |||
return { | |||
filters: { | |||
is_custom: 1, | |||
disabled: 0, | |||
desk_access: 1 | |||
} | |||
}; | |||
}); | |||
frm.set_query('apply_user_permission_on', function() { | |||
return { | |||
query: "frappe.core.doctype.user_type.user_type.get_user_linked_doctypes" | |||
}; | |||
}); | |||
}, | |||
onload: function(frm) { | |||
frm.trigger('get_user_id_fields'); | |||
}, | |||
apply_user_permission_on: function(frm) { | |||
frm.set_value('user_id_field', ''); | |||
frm.trigger('get_user_id_fields'); | |||
}, | |||
get_user_id_fields: function(frm) { | |||
if (frm.doc.apply_user_permission_on) { | |||
frappe.call({ | |||
method: 'frappe.core.doctype.user_type.user_type.get_user_id', | |||
args: { | |||
parent: frm.doc.apply_user_permission_on | |||
}, | |||
callback: function(r) { | |||
set_field_options('user_id_field', [""].concat(r.message)); | |||
} | |||
}); | |||
} | |||
} | |||
}); |
@@ -0,0 +1,128 @@ | |||
{ | |||
"actions": [], | |||
"autoname": "Prompt", | |||
"creation": "2021-01-13 01:48:02.378548", | |||
"doctype": "DocType", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"is_standard", | |||
"section_break_2", | |||
"role", | |||
"column_break_4", | |||
"apply_user_permission_on", | |||
"user_id_field", | |||
"section_break_6", | |||
"user_doctypes", | |||
"select_doctypes", | |||
"allowed_modules_section", | |||
"user_type_modules" | |||
], | |||
"fields": [ | |||
{ | |||
"default": "0", | |||
"fieldname": "is_standard", | |||
"fieldtype": "Check", | |||
"label": "Is Standard" | |||
}, | |||
{ | |||
"depends_on": "eval: !doc.is_standard", | |||
"fieldname": "section_break_2", | |||
"fieldtype": "Section Break", | |||
"label": "Document Types and Permissions" | |||
}, | |||
{ | |||
"fieldname": "user_doctypes", | |||
"fieldtype": "Table", | |||
"label": "Document Types", | |||
"mandatory_depends_on": "eval: !doc.is_standard", | |||
"options": "User Document Type" | |||
}, | |||
{ | |||
"fieldname": "role", | |||
"fieldtype": "Link", | |||
"in_list_view": 1, | |||
"label": "Role", | |||
"mandatory_depends_on": "eval: !doc.is_standard", | |||
"options": "Role" | |||
}, | |||
{ | |||
"fieldname": "select_doctypes", | |||
"fieldtype": "Table", | |||
"label": "Document Types (Select Permissions Only)", | |||
"options": "User Select Document Type" | |||
}, | |||
{ | |||
"fieldname": "column_break_4", | |||
"fieldtype": "Column Break" | |||
}, | |||
{ | |||
"description": "Can only list down the document types which has been linked to the User document type.", | |||
"fieldname": "apply_user_permission_on", | |||
"fieldtype": "Link", | |||
"label": "Apply User Permission On", | |||
"mandatory_depends_on": "eval: !doc.is_standard", | |||
"options": "DocType" | |||
}, | |||
{ | |||
"depends_on": "eval: !doc.is_standard", | |||
"fieldname": "section_break_6", | |||
"fieldtype": "Section Break", | |||
"hide_border": 1 | |||
}, | |||
{ | |||
"depends_on": "apply_user_permission_on", | |||
"fieldname": "user_id_field", | |||
"fieldtype": "Select", | |||
"label": "User Id Field", | |||
"mandatory_depends_on": "eval: !doc.is_standard" | |||
}, | |||
{ | |||
"depends_on": "eval: !doc.is_standard", | |||
"fieldname": "allowed_modules_section", | |||
"fieldtype": "Section Break", | |||
"label": "Allowed Modules" | |||
}, | |||
{ | |||
"fieldname": "user_type_modules", | |||
"fieldtype": "Table", | |||
"no_copy": 1, | |||
"options": "User Type Module", | |||
"print_hide": 1, | |||
"read_only": 1 | |||
} | |||
], | |||
"index_web_pages_for_search": 1, | |||
"links": [], | |||
"modified": "2021-01-24 04:47:08.243320", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "User Type", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"create": 1, | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Administrator", | |||
"share": 1, | |||
"write": 1 | |||
}, | |||
{ | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "System Manager", | |||
"share": 1, | |||
"write": 1 | |||
} | |||
], | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_changes": 1 | |||
} |
@@ -0,0 +1,209 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2021, Frappe Technologies and contributors | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
from frappe import _ | |||
from six import iteritems | |||
from frappe.utils import get_link_to_form | |||
from frappe.config import get_modules_from_app | |||
from frappe.permissions import add_permission, add_user_permission | |||
from frappe.model.document import Document | |||
class UserType(Document): | |||
def validate(self): | |||
self.set_modules() | |||
def on_update(self): | |||
if self.is_standard: return | |||
self.validate_document_type_limit() | |||
self.validate_role() | |||
self.add_role_permissions_for_user_doctypes() | |||
self.add_role_permissions_for_select_doctypes() | |||
self.update_users() | |||
get_non_standard_user_type_details() | |||
self.remove_permission_for_deleted_doctypes() | |||
def on_trash(self): | |||
if self.is_standard: | |||
frappe.throw(_('Standard user type {0} can not be deleted.') | |||
.format(frappe.bold(self.name))) | |||
def set_modules(self): | |||
if not self.user_doctypes: return | |||
modules = frappe.get_all('DocType', fields=['distinct module as module'], | |||
filters={'name': ('in', [d.document_type for d in self.user_doctypes])}) | |||
self.set('user_type_modules', []) | |||
for row in modules: | |||
self.append('user_type_modules', { | |||
'module': row.module | |||
}) | |||
def validate_document_type_limit(self): | |||
limit = frappe.conf.get('user_type_doctype_limit').get(frappe.scrub(self.name)) or 10 | |||
if self.user_doctypes and len(self.user_doctypes) > limit: | |||
frappe.throw(_('The total number of user document types limit has been crossed.'), | |||
title=_('User Document Types Limit Exceeded')) | |||
custom_doctypes = [row.document_type for row in self.user_doctypes if row.is_custom] | |||
if custom_doctypes and len(custom_doctypes) > 3: | |||
frappe.throw(_('You can only set the 3 custom doctypes in the Document Types table.'), | |||
title=_('Custom Document Types Limit Exceeded')) | |||
def validate_role(self): | |||
if not self.role: | |||
frappe.throw(_("The field {0} is mandatory") | |||
.format(frappe.bold(_('Role')))) | |||
if not frappe.db.get_value('Role', self.role, 'is_custom'): | |||
frappe.throw(_("The role {0} should be a custom role.") | |||
.format(frappe.bold(get_link_to_form('Role', self.role)))) | |||
def update_users(self): | |||
for row in frappe.get_all('User', filters = {'user_type': self.name}): | |||
user = frappe.get_cached_doc('User', row.name) | |||
self.update_roles_in_user(user) | |||
self.update_modules_in_user(user) | |||
user.update_children() | |||
def update_roles_in_user(self, user): | |||
user.set('roles', []) | |||
user.append('roles', { | |||
'role': self.role | |||
}) | |||
def update_modules_in_user(self, user): | |||
block_modules = frappe.get_all('Module Def', fields = ['name as module'], | |||
filters={'name': ['not in', [d.module for d in self.user_type_modules]]}) | |||
if block_modules: | |||
user.set('block_modules', block_modules) | |||
def add_role_permissions_for_user_doctypes(self): | |||
perms = ['read', 'write', 'create'] | |||
for row in self.user_doctypes: | |||
docperm = add_role_permissions(row.document_type, self.role) | |||
values = {perm:row.get(perm) for perm in perms} | |||
for perm in ['print', 'email', 'share']: | |||
values[perm] = 1 | |||
frappe.db.set_value('Custom DocPerm', docperm, values) | |||
def add_role_permissions_for_select_doctypes(self): | |||
for row in self.select_doctypes: | |||
docperm = add_role_permissions(row.document_type, self.role) | |||
frappe.db.set_value('Custom DocPerm', docperm, | |||
{'select': 1, 'read': 0, 'create': 0, 'write': 0}) | |||
def remove_permission_for_deleted_doctypes(self): | |||
doctypes = [d.document_type for d in self.user_doctypes] | |||
for dt in self.select_doctypes: | |||
doctypes.append(dt.document_type) | |||
for perm in frappe.get_all('Custom DocPerm', | |||
filters = {'role': self.role, 'parent': ['not in', doctypes]}): | |||
frappe.delete_doc('Custom DocPerm', perm.name) | |||
def add_role_permissions(doctype, role): | |||
name = frappe.get_value('Custom DocPerm', dict(parent=doctype, | |||
role=role, permlevel=0)) | |||
if not name: | |||
name = add_permission(doctype, role, 0) | |||
return name | |||
def get_non_standard_user_type_details(): | |||
user_types = frappe.get_all('User Type', | |||
fields=['apply_user_permission_on', 'name', 'user_id_field'], | |||
filters={'is_standard': 0}) | |||
if user_types: | |||
user_type_details = {d.name: [d.apply_user_permission_on, d.user_id_field] for d in user_types} | |||
frappe.cache().set_value('non_standard_user_types', user_type_details) | |||
return user_type_details | |||
@frappe.whitelist() | |||
@frappe.validate_and_sanitize_search_inputs | |||
def get_user_linked_doctypes(doctype, txt, searchfield, start, page_len, filters): | |||
modules = [d.get('module_name') for d in get_modules_from_app('frappe')] | |||
filters = [['DocField', 'options', '=', 'User'], ['DocType', 'is_submittable', '=', 0], | |||
['DocType', 'issingle', '=', 0], ['DocType', 'module', 'not in', modules], | |||
['DocType', 'read_only', '=', 0], ['DocType', 'name', 'like', '%{0}%'.format(txt)]] | |||
doctypes = frappe.get_all('DocType', fields = ['`tabDocType`.`name`'], filters=filters, | |||
order_by = '`tabDocType`.`idx` desc', limit_start=start, limit_page_length=page_len, as_list=1, debug=1) | |||
custom_dt_filters = [['Custom Field', 'dt', 'like', '%{0}%'.format(txt)], | |||
['Custom Field', 'options', '=', 'User'], ['Custom Field', 'fieldtype', '=', 'Link']] | |||
custom_doctypes = frappe.get_all('Custom Field', fields = ['dt as name'], | |||
filters= custom_dt_filters, as_list=1) | |||
return doctypes + custom_doctypes | |||
@frappe.whitelist() | |||
def get_user_id(parent): | |||
data = frappe.get_all('DocField', fields = ['label', 'fieldname as value'], | |||
filters= {'options': 'User', 'fieldtype': 'Link', 'parent': parent}) or [] | |||
data.extend(frappe.get_all('Custom Field', fields = ['label', 'fieldname as value'], | |||
filters= {'options': 'User', 'fieldtype': 'Link', 'dt': parent})) | |||
return data | |||
def user_linked_with_permission_on_doctype(doc, user): | |||
if not doc.apply_user_permission_on: return True | |||
if not doc.user_id_field: | |||
frappe.throw(_('User Id Field is mandatory in the user type {0}') | |||
.format(frappe.bold(doc.name))) | |||
if frappe.db.get_value(doc.apply_user_permission_on, | |||
{doc.user_id_field: user}, 'name'): | |||
return True | |||
else: | |||
label = frappe.get_meta(doc.apply_user_permission_on).get_field(doc.user_id_field).label | |||
frappe.msgprint(_("To set the role {0} in the user {1}, kindly set the {2} field as {3} in one of the {4} record.") | |||
.format(frappe.bold(doc.role), frappe.bold(user), frappe.bold(label), | |||
frappe.bold(user), frappe.bold(doc.apply_user_permission_on))) | |||
return False | |||
def apply_permissions_for_non_standard_user_type(doc, method=None): | |||
'''Create user permission for the non standard user type''' | |||
user_types = frappe.cache().get_value('non_standard_user_types') | |||
if not user_types: | |||
user_types = get_non_standard_user_type_details() | |||
for user_type, data in iteritems(user_types): | |||
if doc.doctype != data[0]: continue | |||
if frappe.get_cached_value('User', doc.get(data[1]), 'user_type') != user_type: | |||
return | |||
if (doc.get(data[1]) and (doc.get(data[1]) != doc._doc_before_save.get(data[1]) | |||
or not frappe.db.get_value('User Permission', | |||
{'user': doc.get(data[1]), 'allow': data[0], 'for_value': doc.name}, 'name'))): | |||
perm_data = frappe.db.get_value('User Permission', | |||
{'allow': doc.doctype, 'for_value': doc.name}, ['name', 'user']) | |||
if not perm_data: | |||
user_doc = frappe.get_cached_doc('User', doc.get(data[1])) | |||
user_doc.set_roles_and_modules_based_on_user_type() | |||
user_doc.update_children() | |||
add_user_permission(doc.doctype, doc.name, doc.get(data[1])) | |||
else: | |||
frappe.db.set_value('User Permission', perm_data[0], 'user', doc.get(data[1])) |
@@ -0,0 +1,13 @@ | |||
from __future__ import unicode_literals | |||
from frappe import _ | |||
def get_data(): | |||
return { | |||
'fieldname': 'user_type', | |||
'transactions': [ | |||
{ | |||
'label': _('Reference'), | |||
'items': ['User'] | |||
} | |||
] | |||
} |
@@ -0,0 +1,10 @@ | |||
frappe.listview_settings['User Type'] = { | |||
add_fields: ["is_standard"], | |||
get_indicator: function (doc) { | |||
if (doc.is_standard) { | |||
return [__("Standard"), "green", "is_standard,=,1"]; | |||
} else { | |||
return [__("Custom"), "blue", "is_standard,=,0"]; | |||
} | |||
} | |||
}; |
@@ -0,0 +1,33 @@ | |||
{ | |||
"actions": [], | |||
"creation": "2021-01-24 03:05:24.634719", | |||
"doctype": "DocType", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"module" | |||
], | |||
"fields": [ | |||
{ | |||
"fieldname": "module", | |||
"fieldtype": "Link", | |||
"in_list_view": 1, | |||
"label": "Module", | |||
"options": "Module Def", | |||
"reqd": 1 | |||
} | |||
], | |||
"index_web_pages_for_search": 1, | |||
"istable": 1, | |||
"links": [], | |||
"modified": "2021-01-24 03:07:43.602927", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "User Type Module", | |||
"owner": "Administrator", | |||
"permissions": [], | |||
"quick_entry": 1, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_changes": 1 | |||
} |
@@ -0,0 +1,10 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2021, Frappe Technologies and contributors | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
# import frappe | |||
from frappe.model.document import Document | |||
class UserTypeModule(Document): | |||
pass |
@@ -30,8 +30,16 @@ def get_roles_and_doctypes(): | |||
"restrict_to_domain": ("in", active_domains) | |||
}, fields=["name"]) | |||
restricted_roles = ['Administrator'] | |||
if frappe.session.user != 'Administrator': | |||
custom_user_type_roles = frappe.get_all('User Type', filters = {'is_standard': 0}, fields=['role']) | |||
for row in custom_user_type_roles: | |||
restricted_roles.append(row.role) | |||
restricted_roles.append('All') | |||
roles = frappe.get_all("Role", filters={ | |||
"name": ("not in", "Administrator"), | |||
"name": ("not in", restricted_roles), | |||
"disabled": 0, | |||
}, or_filters={ | |||
"ifnull(restrict_to_domain, '')": "", | |||
@@ -54,9 +62,14 @@ def get_permissions(doctype=None, role=None): | |||
if doctype: | |||
out = [p for p in out if p.parent == doctype] | |||
else: | |||
out = frappe.get_all('Custom DocPerm', fields='*', filters=dict(parent = doctype), order_by="permlevel") | |||
filters=dict(parent = doctype) | |||
if frappe.session.user != 'Administrator': | |||
custom_roles = frappe.get_all('Role', filters={'is_custom': 1}) | |||
filters['role'] = ['not in', [row.name for row in custom_roles]] | |||
out = frappe.get_all('Custom DocPerm', fields='*', filters=filters, order_by="permlevel") | |||
if not out: | |||
out = frappe.get_all('DocPerm', fields='*', filters=dict(parent = doctype), order_by="permlevel") | |||
out = frappe.get_all('DocPerm', fields='*', filters=filters, order_by="permlevel") | |||
linked_doctypes = {} | |||
for d in out: | |||
@@ -78,14 +91,14 @@ def add(parent, role, permlevel): | |||
@frappe.whitelist() | |||
def update(doctype, role, permlevel, ptype, value=None): | |||
"""Update role permission params | |||
Args: | |||
doctype (str): Name of the DocType to update params for | |||
role (str): Role to be updated for, eg "Website Manager". | |||
permlevel (int): perm level the provided rule applies to | |||
ptype (str): permission type, example "read", "delete", etc. | |||
value (None, optional): value for ptype, None indicates False | |||
Returns: | |||
str: Refresh flag is permission is updated successfully | |||
""" | |||
@@ -147,6 +147,7 @@ doc_events = { | |||
"frappe.core.doctype.file.file.attach_files_to_document", | |||
"frappe.event_streaming.doctype.event_update_log.event_update_log.notify_consumers", | |||
"frappe.automation.doctype.assignment_rule.assignment_rule.update_due_date", | |||
"frappe.core.doctype.user_type.user_type.apply_permissions_for_non_standard_user_type" | |||
], | |||
"after_rename": "frappe.desk.notifications.clear_doctype_notifications", | |||
"on_cancel": [ | |||
@@ -333,3 +333,4 @@ frappe.patches.v13_0.delete_package_publish_tool | |||
frappe.patches.v13_0.rename_list_view_setting_to_list_view_settings | |||
frappe.patches.v13_0.remove_twilio_settings | |||
frappe.patches.v12_0.rename_uploaded_files_with_proper_name | |||
frappe.patches.v13_0.make_user_type |
@@ -0,0 +1,10 @@ | |||
import frappe | |||
from frappe.utils.install import create_user_type | |||
def execute(): | |||
frappe.reload_doc('core', 'doctype', 'role') | |||
frappe.reload_doc('core', 'doctype', 'user_document_type') | |||
frappe.reload_doc('core', 'doctype', 'user_select_document_type') | |||
frappe.reload_doc('core', 'doctype', 'user_type') | |||
create_user_type() |
@@ -471,7 +471,7 @@ def setup_custom_perms(parent): | |||
copy_perms(parent) | |||
return True | |||
def add_permission(doctype, role, permlevel=0): | |||
def add_permission(doctype, role, permlevel=0, ptype=None): | |||
'''Add a new permission rule to the given doctype | |||
for the given Role and Permission Level''' | |||
from frappe.core.doctype.doctype.doctype import validate_permissions_for_doctype | |||
@@ -481,6 +481,9 @@ def add_permission(doctype, role, permlevel=0): | |||
permlevel=permlevel, if_owner=0)): | |||
return | |||
if not ptype: | |||
ptype = 'read' | |||
custom_docperm = frappe.get_doc({ | |||
"doctype":"Custom DocPerm", | |||
"__islocal": 1, | |||
@@ -488,13 +491,14 @@ def add_permission(doctype, role, permlevel=0): | |||
"parenttype": "DocType", | |||
"parentfield": "permissions", | |||
"role": role, | |||
'read': 1, | |||
"permlevel": permlevel, | |||
ptype: 1, | |||
}) | |||
custom_docperm.save() | |||
validate_permissions_for_doctype(doctype) | |||
return custom_docperm.name | |||
def copy_perms(parent): | |||
'''Copy all DocPerm in to Custom DocPerm for the given document''' | |||
@@ -18,6 +18,7 @@ def after_install(): | |||
# reset installed apps for re-install | |||
frappe.db.set_global("installed_apps", '["frappe"]') | |||
create_user_type() | |||
install_basic_docs() | |||
from frappe.core.doctype.file.file import make_home_folder | |||
@@ -49,6 +50,15 @@ def after_install(): | |||
frappe.db.commit() | |||
def create_user_type(): | |||
for user_type in ['System User', 'Website User']: | |||
if not frappe.db.exists('User Type', user_type): | |||
frappe.get_doc({ | |||
'doctype': 'User Type', | |||
'name': user_type, | |||
'is_standard': 1 | |||
}).insert(ignore_permissions=True) | |||
def install_basic_docs(): | |||
# core users / roles | |||
install_docs = [ | |||