Преглед изворни кода

feat: custom user type with doctypes

version-14
Rohit Waghchaure пре 4 година
родитељ
комит
112784e7ae
30 измењених фајлова са 754 додато и 25 уклоњено
  1. +11
    -0
      frappe/core/doctype/doctype/doctype.js
  2. +15
    -0
      frappe/core/doctype/doctype/doctype.py
  3. +3
    -0
      frappe/core/doctype/role/role.js
  4. +10
    -2
      frappe/core/doctype/role/role.json
  5. +12
    -1
      frappe/core/doctype/role/role.py
  6. +4
    -3
      frappe/core/doctype/user/user.js
  7. +7
    -6
      frappe/core/doctype/user/user.json
  8. +34
    -6
      frappe/core/doctype/user/user.py
  9. +0
    -0
      frappe/core/doctype/user_document_type/__init__.py
  10. +76
    -0
      frappe/core/doctype/user_document_type/user_document_type.json
  11. +10
    -0
      frappe/core/doctype/user_document_type/user_document_type.py
  12. +0
    -0
      frappe/core/doctype/user_select_document_type/__init__.py
  13. +33
    -0
      frappe/core/doctype/user_select_document_type/user_select_document_type.json
  14. +10
    -0
      frappe/core/doctype/user_select_document_type/user_select_document_type.py
  15. +0
    -0
      frappe/core/doctype/user_type/__init__.py
  16. +10
    -0
      frappe/core/doctype/user_type/test_user_type.py
  17. +70
    -0
      frappe/core/doctype/user_type/user_type.js
  18. +128
    -0
      frappe/core/doctype/user_type/user_type.json
  19. +209
    -0
      frappe/core/doctype/user_type/user_type.py
  20. +13
    -0
      frappe/core/doctype/user_type/user_type_dashboard.py
  21. +10
    -0
      frappe/core/doctype/user_type/user_type_list.js
  22. +0
    -0
      frappe/core/doctype/user_type_module/__init__.py
  23. +33
    -0
      frappe/core/doctype/user_type_module/user_type_module.json
  24. +10
    -0
      frappe/core/doctype/user_type_module/user_type_module.py
  25. +18
    -5
      frappe/core/page/permission_manager/permission_manager.py
  26. +1
    -0
      frappe/hooks.py
  27. +1
    -0
      frappe/patches.txt
  28. +10
    -0
      frappe/patches/v13_0/make_user_type.py
  29. +6
    -2
      frappe/permissions.py
  30. +10
    -0
      frappe/utils/install.py

+ 11
- 0
frappe/core/doctype/doctype/doctype.js Прегледај датотеку

@@ -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);


+ 15
- 0
frappe/core/doctype/doctype/doctype.py Прегледај датотеку

@@ -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
- 0
frappe/core/doctype/role/role.js Прегледај датотеку

@@ -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");


+ 10
- 2
frappe/core/doctype/role/role.json Прегледај датотеку

@@ -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",


+ 12
- 1
frappe/core/doctype/role/role.py Прегледај датотеку

@@ -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)

+ 4
- 3
frappe/core/doctype/user/user.js Прегледај датотеку

@@ -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;
}


+ 7
- 6
frappe/core/doctype/user/user.json Прегледај датотеку

@@ -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",


+ 34
- 6
frappe/core/doctype/user/user.py Прегледај датотеку

@@ -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
frappe/core/doctype/user_document_type/__init__.py Прегледај датотеку


+ 76
- 0
frappe/core/doctype/user_document_type/user_document_type.json Прегледај датотеку

@@ -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
- 0
frappe/core/doctype/user_document_type/user_document_type.py Прегледај датотеку

@@ -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
frappe/core/doctype/user_select_document_type/__init__.py Прегледај датотеку


+ 33
- 0
frappe/core/doctype/user_select_document_type/user_select_document_type.json Прегледај датотеку

@@ -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
}

+ 10
- 0
frappe/core/doctype/user_select_document_type/user_select_document_type.py Прегледај датотеку

@@ -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
frappe/core/doctype/user_type/__init__.py Прегледај датотеку


+ 10
- 0
frappe/core/doctype/user_type/test_user_type.py Прегледај датотеку

@@ -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
- 0
frappe/core/doctype/user_type/user_type.js Прегледај датотеку

@@ -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
- 0
frappe/core/doctype/user_type/user_type.json Прегледај датотеку

@@ -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
- 0
frappe/core/doctype/user_type/user_type.py Прегледај датотеку

@@ -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
- 0
frappe/core/doctype/user_type/user_type_dashboard.py Прегледај датотеку

@@ -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
- 0
frappe/core/doctype/user_type/user_type_list.js Прегледај датотеку

@@ -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
frappe/core/doctype/user_type_module/__init__.py Прегледај датотеку


+ 33
- 0
frappe/core/doctype/user_type_module/user_type_module.json Прегледај датотеку

@@ -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
- 0
frappe/core/doctype/user_type_module/user_type_module.py Прегледај датотеку

@@ -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

+ 18
- 5
frappe/core/page/permission_manager/permission_manager.py Прегледај датотеку

@@ -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
"""


+ 1
- 0
frappe/hooks.py Прегледај датотеку

@@ -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": [


+ 1
- 0
frappe/patches.txt Прегледај датотеку

@@ -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
- 0
frappe/patches/v13_0/make_user_type.py Прегледај датотеку

@@ -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()

+ 6
- 2
frappe/permissions.py Прегледај датотеку

@@ -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'''


+ 10
- 0
frappe/utils/install.py Прегледај датотеку

@@ -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…
Откажи
Сачувај