feat: custom user type with doctypes
This commit is contained in:
parent
431eb5046f
commit
112784e7ae
30 changed files with 754 additions and 25 deletions
|
|
@ -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
frappe/core/doctype/user_document_type/__init__.py
Normal file
0
frappe/core/doctype/user_document_type/__init__.py
Normal file
|
|
@ -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
|
||||
}
|
||||
10
frappe/core/doctype/user_document_type/user_document_type.py
Normal file
10
frappe/core/doctype/user_document_type/user_document_type.py
Normal file
|
|
@ -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
frappe/core/doctype/user_type/__init__.py
Normal file
0
frappe/core/doctype/user_type/__init__.py
Normal file
10
frappe/core/doctype/user_type/test_user_type.py
Normal file
10
frappe/core/doctype/user_type/test_user_type.py
Normal file
|
|
@ -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
|
||||
70
frappe/core/doctype/user_type/user_type.js
Normal file
70
frappe/core/doctype/user_type/user_type.js
Normal file
|
|
@ -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));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
128
frappe/core/doctype/user_type/user_type.json
Normal file
128
frappe/core/doctype/user_type/user_type.json
Normal file
|
|
@ -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
|
||||
}
|
||||
209
frappe/core/doctype/user_type/user_type.py
Normal file
209
frappe/core/doctype/user_type/user_type.py
Normal file
|
|
@ -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]))
|
||||
13
frappe/core/doctype/user_type/user_type_dashboard.py
Normal file
13
frappe/core/doctype/user_type/user_type_dashboard.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
from __future__ import unicode_literals
|
||||
from frappe import _
|
||||
|
||||
def get_data():
|
||||
return {
|
||||
'fieldname': 'user_type',
|
||||
'transactions': [
|
||||
{
|
||||
'label': _('Reference'),
|
||||
'items': ['User']
|
||||
}
|
||||
]
|
||||
}
|
||||
10
frappe/core/doctype/user_type/user_type_list.js
Normal file
10
frappe/core/doctype/user_type/user_type_list.js
Normal file
|
|
@ -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
frappe/core/doctype/user_type_module/__init__.py
Normal file
0
frappe/core/doctype/user_type_module/__init__.py
Normal file
33
frappe/core/doctype/user_type_module/user_type_module.json
Normal file
33
frappe/core/doctype/user_type_module/user_type_module.json
Normal file
|
|
@ -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
|
||||
}
|
||||
10
frappe/core/doctype/user_type_module/user_type_module.py
Normal file
10
frappe/core/doctype/user_type_module/user_type_module.py
Normal file
|
|
@ -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
|
||||
|
|
|
|||
10
frappe/patches/v13_0/make_user_type.py
Normal file
10
frappe/patches/v13_0/make_user_type.py
Normal file
|
|
@ -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 = [
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue