Merge branch 'hotfix'
This commit is contained in:
commit
1a06bc2c15
18 changed files with 719 additions and 501 deletions
|
|
@ -23,7 +23,7 @@ if sys.version[0] == '2':
|
|||
reload(sys)
|
||||
sys.setdefaultencoding("utf-8")
|
||||
|
||||
__version__ = '11.1.28'
|
||||
__version__ = '11.1.29'
|
||||
__title__ = "Frappe Framework"
|
||||
|
||||
local = Local()
|
||||
|
|
@ -187,15 +187,20 @@ def connect(site=None, db_name=None):
|
|||
local.db = Database(user=db_name or local.conf.db_name)
|
||||
set_user("Administrator")
|
||||
|
||||
def connect_read_only():
|
||||
def connect_replica():
|
||||
from frappe.database import Database
|
||||
user = local.conf.db_name
|
||||
password = local.conf.db_password
|
||||
|
||||
local.read_only_db = Database(local.conf.slave_host, local.conf.slave_db_name,
|
||||
local.conf.slave_db_password)
|
||||
if local.conf.different_credentials_for_replica:
|
||||
user = local.conf.replica_db_name
|
||||
password = local.conf.replica_db_password
|
||||
|
||||
local.replica_db = Database(host=local.conf.replica_host, user=user, password=password)
|
||||
|
||||
# swap db connections
|
||||
local.master_db = local.db
|
||||
local.db = local.read_only_db
|
||||
local.primary_db = local.db
|
||||
local.db = local.replica_db
|
||||
|
||||
def get_site_config(sites_path=None, site_path=None):
|
||||
"""Returns `site_config.json` combined with `sites/common_site_config.json`.
|
||||
|
|
@ -495,16 +500,17 @@ def whitelist(allow_guest=False, xss_safe=False):
|
|||
def read_only():
|
||||
def innfn(fn):
|
||||
def wrapper_fn(*args, **kwargs):
|
||||
if conf.use_slave_for_read_only:
|
||||
connect_read_only()
|
||||
if conf.read_from_replica:
|
||||
connect_replica()
|
||||
|
||||
try:
|
||||
retval = fn(*args, **get_newargs(fn, kwargs))
|
||||
except:
|
||||
raise
|
||||
finally:
|
||||
if local and hasattr(local, 'master_db'):
|
||||
if local and hasattr(local, 'primary_db'):
|
||||
local.db.close()
|
||||
local.db = local.master_db
|
||||
local.db = local.primary_db
|
||||
|
||||
return retval
|
||||
return wrapper_fn
|
||||
|
|
|
|||
|
|
@ -152,3 +152,11 @@ def filter_dynamic_link_doctypes(doctype, txt, searchfield, start, page_len, fil
|
|||
valid_doctypes = [[doctype] for doctype in valid_doctypes]
|
||||
|
||||
return valid_doctypes
|
||||
|
||||
def set_link_title(doc):
|
||||
if not doc.links:
|
||||
return
|
||||
for link in doc.links:
|
||||
if not link.link_title:
|
||||
linked_doc = frappe.get_doc(link.link_doctype, link.link_name)
|
||||
link.link_title = linked_doc.get("title_field") or linked_doc.get("name")
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ from frappe.model.naming import make_autoname
|
|||
from frappe.core.doctype.dynamic_link.dynamic_link import deduplicate_dynamic_links
|
||||
from six import iteritems, string_types
|
||||
from past.builtins import cmp
|
||||
from frappe.contacts.address_and_contact import set_link_title
|
||||
|
||||
import functools
|
||||
|
||||
|
|
@ -39,6 +40,7 @@ class Address(Document):
|
|||
def validate(self):
|
||||
self.link_address()
|
||||
self.validate_reference()
|
||||
set_link_title(self)
|
||||
deduplicate_dynamic_links(self)
|
||||
|
||||
def link_address(self):
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ from frappe.core.doctype.dynamic_link.dynamic_link import deduplicate_dynamic_li
|
|||
from six import iteritems
|
||||
from past.builtins import cmp
|
||||
from frappe.model.naming import append_number_if_name_exists
|
||||
from frappe.contacts.address_and_contact import set_link_title
|
||||
|
||||
import functools
|
||||
|
||||
|
|
@ -31,6 +32,7 @@ class Contact(Document):
|
|||
if self.email_id:
|
||||
self.email_id = self.email_id.strip()
|
||||
self.set_user()
|
||||
set_link_title(self)
|
||||
if self.email_id and not self.image:
|
||||
self.image = has_gravatar(self.email_id)
|
||||
|
||||
|
|
|
|||
|
|
@ -51,14 +51,14 @@ def run_background(prepared_report):
|
|||
instance.status = "Completed"
|
||||
instance.columns = json.dumps(result["columns"])
|
||||
instance.report_end_time = frappe.utils.now()
|
||||
instance.save()
|
||||
instance.save(ignore_permissions=True)
|
||||
|
||||
except Exception:
|
||||
frappe.log_error(frappe.get_traceback())
|
||||
instance = frappe.get_doc("Prepared Report", prepared_report)
|
||||
instance.status = "Error"
|
||||
instance.error_message = frappe.get_traceback()
|
||||
instance.save()
|
||||
instance.save(ignore_permissions=True)
|
||||
|
||||
frappe.publish_realtime(
|
||||
'report_generated',
|
||||
|
|
|
|||
|
|
@ -34,9 +34,15 @@ class AutoRepeat(Document):
|
|||
validate_template(self.message or "")
|
||||
|
||||
def before_submit(self):
|
||||
start_date_copy = self.start_date
|
||||
today_copy = add_days(today(), -1)
|
||||
|
||||
if start_date_copy <= today_copy:
|
||||
start_date_copy = today_copy
|
||||
|
||||
if not self.next_schedule_date:
|
||||
self.next_schedule_date = get_next_schedule_date(
|
||||
self.start_date, self.frequency, self.repeat_on_day)
|
||||
start_date_copy, self.frequency, self.repeat_on_day)
|
||||
|
||||
def on_submit(self):
|
||||
self.update_auto_repeat_id()
|
||||
|
|
@ -116,14 +122,15 @@ class AutoRepeat(Document):
|
|||
days = 60 if self.frequency in ['Daily', 'Weekly'] else 365
|
||||
end_date_copy = add_days(today_copy, days)
|
||||
|
||||
start_date_copy = get_next_schedule_date(start_date_copy, self.frequency, self.repeat_on_day)
|
||||
while (getdate(start_date_copy) < getdate(end_date_copy)):
|
||||
start_date_copy = get_next_schedule_date(start_date_copy, self.frequency, self.repeat_on_day)
|
||||
row = {
|
||||
"reference_document" : self.reference_document,
|
||||
"frequency" : self.frequency,
|
||||
"next_scheduled_date" : start_date_copy
|
||||
}
|
||||
schedule_details.append(row)
|
||||
start_date_copy = get_next_schedule_date(start_date_copy, self.frequency, self.repeat_on_day)
|
||||
|
||||
return schedule_details
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import unittest
|
|||
import frappe
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
|
||||
from frappe.desk.doctype.auto_repeat.auto_repeat import get_auto_repeat_entries, create_repeated_entries, disable_auto_repeat
|
||||
from frappe.utils import today, add_days, getdate
|
||||
from frappe.utils import today, add_days, getdate, add_months
|
||||
|
||||
|
||||
def add_custom_fields():
|
||||
|
|
@ -44,8 +44,8 @@ class TestAutoRepeat(unittest.TestCase):
|
|||
self.assertEqual(todo.get('description'), new_todo.get('description'))
|
||||
|
||||
def test_monthly_auto_repeat(self):
|
||||
start_date = '2018-01-01'
|
||||
end_date = '2018-12-31'
|
||||
start_date = today()
|
||||
end_date = add_months(start_date, 12)
|
||||
|
||||
todo = frappe.get_doc(
|
||||
dict(doctype='ToDo', description='test recurring todo', assigned_by='Administrator')).insert()
|
||||
|
|
@ -103,7 +103,7 @@ def make_auto_repeat(**args):
|
|||
'reference_document': args.reference_document or frappe.db.get_value('ToDo', {'docstatus': 1}, 'name'),
|
||||
'frequency': args.frequency or 'Daily',
|
||||
'start_date': args.start_date or add_days(today(), -1),
|
||||
'end_date': args.end_date or add_days(today(), 1),
|
||||
'end_date': args.end_date or add_days(today(), 2),
|
||||
'submit_on_creation': args.submit_on_creation or 0,
|
||||
'notify_by_email': args.notify or 0,
|
||||
'recipients': args.recipients or "",
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ def get_report_list(module, is_standard="No"):
|
|||
out.append({
|
||||
"type": "report",
|
||||
"doctype": r.ref_doctype,
|
||||
"is_query_report": 1 if r.report_type in ("Query Report", "Script Report") else 0,
|
||||
"is_query_report": 1 if r.report_type in ("Query Report", "Script Report", "Custom Report") else 0,
|
||||
"label": _(r.name),
|
||||
"name": r.name
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2329,6 +2329,7 @@
|
|||
},
|
||||
"Suriname": {
|
||||
"code": "sr",
|
||||
"currency": "SRD",
|
||||
"currency_fraction": "Cent",
|
||||
"currency_fraction_units": 100,
|
||||
"currency_symbol": "$",
|
||||
|
|
|
|||
|
|
@ -1,317 +1,363 @@
|
|||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2016-09-22 04:16:48.829658",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "System",
|
||||
"editable_grid": 1,
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2016-09-22 04:16:48.829658",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "System",
|
||||
"editable_grid": 1,
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "enabled",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Enabled",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "ldap_server_url",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "LDAP Server Url",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "organizational_unit",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Organizational Unit",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "base_dn",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Base Distinguished Name (DN)",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "password",
|
||||
"fieldtype": "Password",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Password for Base DN",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "ldap_search_string",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "LDAP Search String",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "ldap_first_name_field",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "LDAP First Name Field",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "ldap_email_field",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "LDAP Email Field",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "ldap_username_field",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "LDAP Username Field",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "enabled",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Enabled",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "ldap_server_url",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "LDAP Server Url",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "organizational_unit",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Organizational Unit",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "base_dn",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Base Distinguished Name (DN)",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "password",
|
||||
"fieldtype": "Password",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Password for Base DN",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "ldap_search_string",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "LDAP Search String",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "ldap_first_name_field",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "LDAP First Name Field",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "ldap_email_field",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "LDAP Email Field",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "ldap_username_field",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "LDAP Username Field",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "ldap_security",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "LDAP Security",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
|
|
@ -325,22 +371,28 @@
|
|||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Off",
|
||||
"description": "",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "ssl_tls_mode",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "SSL/TLS Mode",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
|
|
@ -355,21 +407,27 @@
|
|||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "No",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "require_trusted_certificate",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Require Trusted Certificate",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
|
|
@ -384,53 +442,153 @@
|
|||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "local_private_key_file",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Path to private Key File",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "local_server_certificate_file",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Path to Server Certificate",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "local_ca_certs_file",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Path to CA Certs File",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 1,
|
||||
"is_submittable": 0,
|
||||
"issingle": 1,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-01-30 11:02:41.011412",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Integrations",
|
||||
"name": "LDAP Settings",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 1,
|
||||
"is_submittable": 0,
|
||||
"issingle": 1,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-04-29 10:56:42.322696",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Integrations",
|
||||
"name": "LDAP Settings",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 1,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 1,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
|
|
@ -5,56 +5,90 @@
|
|||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import cstr
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class LDAPSettings(Document):
|
||||
def validate(self):
|
||||
if not self.flags.ignore_mandatory:
|
||||
self.validate_ldap_credentails()
|
||||
if self.ldap_search_string.endswith("={0}"):
|
||||
if self.enabled:
|
||||
connect_to_ldap(server_url=self.ldap_server_url,
|
||||
base_dn=self.base_dn,
|
||||
password=self.get_password(raise_exception=False),
|
||||
ssl_tls_mode=self.ssl_tls_mode,
|
||||
trusted_cert=self.require_trusted_certificate,
|
||||
private_key_file=self.local_private_key_file,
|
||||
server_cert_file=self.local_server_certificate_file,
|
||||
ca_certs_file=self.local_ca_certs_file)
|
||||
else:
|
||||
frappe.throw(_("LDAP Search String needs to end with a placeholder, eg sAMAccountName={0}"))
|
||||
|
||||
def validate_ldap_credentails(self):
|
||||
try:
|
||||
import ldap
|
||||
conn = ldap.initialize(self.ldap_server_url)
|
||||
try:
|
||||
if self.ssl_tls_mode == 'StartTLS':
|
||||
conn.set_option(ldap.OPT_X_TLS_DEMAND, True)
|
||||
if self.require_trusted_certificate == 'Yes':
|
||||
conn.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_DEMAND)
|
||||
conn.start_tls_s()
|
||||
except:
|
||||
frappe.throw(_("StartTLS is not supported"))
|
||||
|
||||
conn.simple_bind_s(self.base_dn, self.get_password(raise_exception=False))
|
||||
except ImportError:
|
||||
msg = """
|
||||
<div>
|
||||
{{_("Seems ldap is not installed on system.<br>Guidelines to install ldap dependancies and python package")}},
|
||||
<a href="https://discuss.erpnext.com/t/frappe-v-7-1-beta-ldap-dependancies/15841" target="_blank">{{_("Click here")}}</a>,
|
||||
</div>
|
||||
"""
|
||||
frappe.throw(msg, title=_("LDAP Not Installed"))
|
||||
def get_ldap_client_settings():
|
||||
#return the settings to be used on the client side.
|
||||
result = {
|
||||
"enabled": False
|
||||
}
|
||||
settings = frappe.get_doc("LDAP Settings")
|
||||
|
||||
except ldap.LDAPError:
|
||||
conn.unbind_s()
|
||||
frappe.throw(_("Incorrect UserId or Password"))
|
||||
if settings and settings.enabled:
|
||||
result["enabled"] = True
|
||||
result["method"] = "frappe.integrations.doctype.ldap_settings.ldap_settings.login"
|
||||
return result
|
||||
|
||||
def get_ldap_settings():
|
||||
|
||||
def connect_to_ldap(server_url,
|
||||
base_dn,
|
||||
password,
|
||||
ssl_tls_mode,
|
||||
trusted_cert,
|
||||
private_key_file,
|
||||
server_cert_file,
|
||||
ca_certs_file):
|
||||
try:
|
||||
settings = frappe.get_doc("LDAP Settings")
|
||||
import ldap3
|
||||
import ssl
|
||||
|
||||
if trusted_cert == 'Yes':
|
||||
tls_configuration = ldap3.Tls(validate=ssl.CERT_REQUIRED,
|
||||
version=ssl.PROTOCOL_TLSv1)
|
||||
else:
|
||||
tls_configuration = ldap3.Tls(validate=ssl.CERT_NONE,
|
||||
version=ssl.PROTOCOL_TLSv1)
|
||||
|
||||
if private_key_file:
|
||||
tls_configuration.private_key_file = private_key_file
|
||||
if server_cert_file:
|
||||
tls_configuration.certificate_file = server_cert_file
|
||||
if ca_certs_file:
|
||||
tls_configuration.ca_certs_file = ca_certs_file
|
||||
|
||||
server = ldap3.Server(host=server_url,
|
||||
tls=tls_configuration)
|
||||
bind_type = ldap3.AUTO_BIND_TLS_BEFORE_BIND if ssl_tls_mode == "StartTLS" else True
|
||||
|
||||
conn = ldap3.Connection(server=server,
|
||||
user=base_dn,
|
||||
password=password,
|
||||
auto_bind=bind_type,
|
||||
read_only=True,
|
||||
raise_exceptions=True)
|
||||
|
||||
return conn
|
||||
|
||||
except ImportError:
|
||||
msg = _("Please Install the ldap3 library via pip to use ldap functionality.")
|
||||
frappe.throw(msg, title=_("LDAP Not Installed"))
|
||||
except ldap3.core.exceptions.LDAPInvalidCredentialsResult:
|
||||
frappe.throw(_("Invalid Credentials"))
|
||||
except Exception as ex:
|
||||
frappe.throw(_(str(ex)))
|
||||
|
||||
settings.update({
|
||||
"method": "frappe.integrations.doctype.ldap_settings.ldap_settings.login"
|
||||
})
|
||||
return settings
|
||||
except Exception:
|
||||
# this will return blank settings
|
||||
return frappe._dict()
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def login():
|
||||
#### LDAP LOGIN LOGIC #####
|
||||
# LDAP LOGIN LOGIC
|
||||
args = frappe.form_dict
|
||||
user = authenticate_ldap_user(frappe.as_unicode(args.usr), frappe.as_unicode(args.pwd))
|
||||
|
||||
|
|
@ -64,64 +98,57 @@ def login():
|
|||
# because of a GET request!
|
||||
frappe.db.commit()
|
||||
|
||||
def authenticate_ldap_user(user=None, password=None):
|
||||
dn = None
|
||||
|
||||
def authenticate_ldap_user(user=None,
|
||||
password=None):
|
||||
|
||||
params = {}
|
||||
settings = get_ldap_settings()
|
||||
settings = frappe.get_doc("LDAP Settings")
|
||||
if settings and settings.enabled:
|
||||
conn = connect_to_ldap(server_url=settings.ldap_server_url,
|
||||
base_dn=settings.base_dn,
|
||||
password=settings.get_password(raise_exception=False),
|
||||
ssl_tls_mode=settings.ssl_tls_mode,
|
||||
trusted_cert=settings.require_trusted_certificate,
|
||||
private_key_file=settings.local_private_key_file,
|
||||
server_cert_file=settings.local_server_certificate_file,
|
||||
ca_certs_file=settings.local_ca_certs_file)
|
||||
|
||||
try:
|
||||
import ldap
|
||||
except:
|
||||
msg = """
|
||||
<div>
|
||||
{{_("Seems ldap is not installed on system.")}}<br>
|
||||
<a href"https://discuss.erpnext.com/t/frappe-v-7-1-beta-ldap-dependancies/15841">{{_("Click here")}}</a>,
|
||||
{{_("Guidelines to install ldap dependancies and python")}}
|
||||
</div>
|
||||
"""
|
||||
frappe.throw(msg, title=_("LDAP Not Installed"))
|
||||
user_filter = settings.ldap_search_string.format(user)
|
||||
conn.search(search_base=settings.organizational_unit,
|
||||
search_filter="({0})".format(user_filter),
|
||||
attributes=[settings.ldap_email_field,
|
||||
settings.ldap_username_field,
|
||||
settings.ldap_first_name_field])
|
||||
|
||||
conn = ldap.initialize(settings.ldap_server_url)
|
||||
|
||||
try:
|
||||
try:
|
||||
# set TLS settings for secure connection
|
||||
if settings.ssl_tls_mode == 'StartTLS':
|
||||
conn.set_option(ldap.OPT_X_TLS_DEMAND, True)
|
||||
if settings.require_trusted_certificate == 'Yes':
|
||||
conn.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_DEMAND)
|
||||
conn.start_tls_s()
|
||||
except:
|
||||
frappe.throw(_("StartTLS is not supported"))
|
||||
|
||||
# simple_bind_s is synchronous binding to server, it takes two param DN and password
|
||||
conn.simple_bind_s(settings.base_dn, settings.get_password(raise_exception=False))
|
||||
|
||||
#search for surnames beginning with a
|
||||
#available options for how deep a search you want.
|
||||
#LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL,LDAP_SCOPE_SUBTREE,
|
||||
result = conn.search_s(settings.organizational_unit, ldap.SCOPE_SUBTREE,
|
||||
settings.ldap_search_string.format(user))
|
||||
|
||||
for dn, r in result:
|
||||
dn = cstr(dn)
|
||||
params["email"] = cstr(r[settings.ldap_email_field][0])
|
||||
params["username"] = cstr(r[settings.ldap_username_field][0])
|
||||
params["first_name"] = cstr(r[settings.ldap_first_name_field][0])
|
||||
|
||||
if dn:
|
||||
conn.simple_bind_s(dn, frappe.as_unicode(password))
|
||||
if len(conn.entries) > 0 and conn.entries[0]:
|
||||
user = conn.entries[0]
|
||||
params["email"] = str(user[settings.ldap_email_field])
|
||||
params["username"] = str(user[settings.ldap_username_field])
|
||||
params["first_name"] = str(user[settings.ldap_first_name_field])
|
||||
connect_to_ldap(server_url=settings.ldap_server_url,
|
||||
base_dn=user.entry_dn,
|
||||
password=frappe.as_unicode(password),
|
||||
ssl_tls_mode=settings.ssl_tls_mode,
|
||||
trusted_cert=settings.require_trusted_certificate,
|
||||
private_key_file=settings.local_private_key_file,
|
||||
server_cert_file=settings.local_server_certificate_file,
|
||||
ca_certs_file=settings.local_ca_certs_file
|
||||
)
|
||||
return create_user(params)
|
||||
else:
|
||||
frappe.throw(_("Not a valid LDAP user"))
|
||||
else:
|
||||
frappe.throw(_("LDAP is not enabled."))
|
||||
|
||||
except ldap.LDAPError:
|
||||
conn.unbind_s()
|
||||
frappe.throw(_("Incorrect UserId or Password"))
|
||||
|
||||
def create_user(params):
|
||||
if frappe.db.exists("User", params["email"]):
|
||||
return frappe.get_doc("User", params["email"])
|
||||
user = frappe.get_doc("User", params["email"])
|
||||
user.first_name = params["first_name"]
|
||||
user.username = params["username"]
|
||||
user.save(ignore_permissions=True)
|
||||
return user
|
||||
|
||||
else:
|
||||
params.update({
|
||||
|
|
@ -135,6 +162,5 @@ def create_user(params):
|
|||
})
|
||||
|
||||
user = frappe.get_doc(params).insert(ignore_permissions=True)
|
||||
frappe.db.commit()
|
||||
|
||||
return user
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import re
|
|||
def execute():
|
||||
""" Create Contact for each User if not present """
|
||||
frappe.reload_doc('contacts', 'doctype', 'contact')
|
||||
frappe.reload_doc('core', 'doctype', 'dynamic_link')
|
||||
|
||||
users = frappe.get_all('User', filters={"name": ('not in', 'Administrator, Guest')}, fields=["*"])
|
||||
for user in users:
|
||||
|
|
|
|||
|
|
@ -167,13 +167,12 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
|
|||
}
|
||||
|
||||
if(!me.df.only_select) {
|
||||
if(frappe.model.can_create(doctype)
|
||||
&& me.df.fieldtype !== "Dynamic Link") {
|
||||
if(frappe.model.can_create(doctype)) {
|
||||
// new item
|
||||
r.results.push({
|
||||
label: "<span class='text-primary link-option'>"
|
||||
+ "<i class='fa fa-plus' style='margin-right: 5px;'></i> "
|
||||
+ __("Create a new {0}", [__(me.df.options)])
|
||||
+ __("Create a new {0}", [__(me.get_options())])
|
||||
+ "</span>",
|
||||
value: "create_new__link_option",
|
||||
action: me.new_doc
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ frappe.ui.form.MultiSelectDialog = Class.extend({
|
|||
let me = this;
|
||||
|
||||
this.page_length = 20;
|
||||
this.start = 0;
|
||||
|
||||
let fields = [
|
||||
{
|
||||
|
|
@ -55,7 +56,12 @@ frappe.ui.form.MultiSelectDialog = Class.extend({
|
|||
},
|
||||
{ fieldtype: "Section Break" },
|
||||
{ fieldtype: "HTML", fieldname: "results_area" },
|
||||
{ fieldtype: "Button", fieldname: "make_new", label: __("Make a new " + me.doctype) }
|
||||
{ fieldtype: "Button", fieldname: "more_btn", label: __("More"),
|
||||
click: function(){
|
||||
me.start += 20;
|
||||
me.get_results();
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
let doctype_plural = !this.doctype.endsWith('y') ? this.doctype + 's'
|
||||
|
|
@ -65,25 +71,30 @@ frappe.ui.form.MultiSelectDialog = Class.extend({
|
|||
title: __("Select {0}", [(this.doctype=='[Select]') ? __("value") : __(doctype_plural)]),
|
||||
fields: fields,
|
||||
primary_action_label: __("Get Items"),
|
||||
secondary_action_label: __("Make {0}", [me.doctype]),
|
||||
primary_action: function() {
|
||||
me.action(me.get_checked_values(), me.args);
|
||||
},
|
||||
secondary_action: function(e) {
|
||||
// If user wants to close the modal
|
||||
if (e) {
|
||||
frappe.route_options = {};
|
||||
|
||||
Object.keys(me.setters).forEach(function(setter) {
|
||||
frappe.route_options[setter] = me.dialog.fields_dict[setter].get_value() || undefined;
|
||||
});
|
||||
|
||||
frappe.new_doc(me.doctype, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.$parent = $(this.dialog.body);
|
||||
this.$wrapper = this.dialog.fields_dict.results_area.$wrapper.append(`<div class="results"
|
||||
style="border: 1px solid #d1d8dd; border-radius: 3px; height: 300px; overflow: auto;"></div>`);
|
||||
this.$results = this.$wrapper.find('.results');
|
||||
this.$make_new_btn = this.dialog.fields_dict.make_new.$wrapper;
|
||||
|
||||
this.$placeholder = $(`<div class="multiselect-empty-state">
|
||||
<span class="text-center" style="margin-top: -40px;">
|
||||
<i class="fa fa-2x fa-tags text-extra-muted"></i>
|
||||
<p class="text-extra-muted">No ${this.doctype} found</p>
|
||||
<button class="btn btn-default btn-xs text-muted" data-fieldtype="Button"
|
||||
data-fieldname="make_new" placeholder="" value="">Make a new ${this.doctype}</button>
|
||||
</span>
|
||||
</div>`);
|
||||
this.$results = this.$wrapper.find('.results');
|
||||
this.$results.append(this.make_list_row());
|
||||
|
||||
this.args = {};
|
||||
|
||||
|
|
@ -94,6 +105,7 @@ frappe.ui.form.MultiSelectDialog = Class.extend({
|
|||
|
||||
bind_events: function() {
|
||||
let me = this;
|
||||
|
||||
this.$results.on('click', '.list-item-container', function (e) {
|
||||
if (!$(e.target).is(':checkbox') && !$(e.target).is('a')) {
|
||||
$(this).find(':checkbox').trigger('click');
|
||||
|
|
@ -119,14 +131,6 @@ frappe.ui.form.MultiSelectDialog = Class.extend({
|
|||
me.get_results();
|
||||
}, 300));
|
||||
});
|
||||
|
||||
this.$parent.on('click', '.btn[data-fieldname="make_new"]', (e) => {
|
||||
frappe.route_options = {};
|
||||
Object.keys(this.setters).forEach(function(setter) {
|
||||
frappe.route_options[setter] = me.dialog.fields_dict[setter].get_value() || undefined;
|
||||
});
|
||||
frappe.new_doc(this.doctype, true);
|
||||
});
|
||||
},
|
||||
|
||||
get_checked_values: function() {
|
||||
|
|
@ -170,23 +174,21 @@ frappe.ui.form.MultiSelectDialog = Class.extend({
|
|||
|
||||
render_result_list: function(results, more = 0) {
|
||||
var me = this;
|
||||
this.$results.empty();
|
||||
if(results.length === 0) {
|
||||
this.$make_new_btn.addClass('hide');
|
||||
this.$results.append(me.$placeholder);
|
||||
return;
|
||||
}
|
||||
this.$make_new_btn.removeClass('hide');
|
||||
|
||||
this.$results.append(this.make_list_row());
|
||||
var more_btn = me.dialog.fields_dict.more_btn.$wrapper;
|
||||
if(results.length === 0) {
|
||||
this.$results.empty();
|
||||
more_btn.hide();
|
||||
return;
|
||||
} else {
|
||||
more_btn.show();
|
||||
}
|
||||
|
||||
results.forEach((result) => {
|
||||
me.$results.append(me.make_list_row(result));
|
||||
})
|
||||
if (more) {
|
||||
let message = __("Only {0} entries shown. Please filter for more specific results.", [this.page_length]);
|
||||
me.$results.append($(`<div class="text-muted small" style="text-align: center;
|
||||
margin: 10px;">${message}</div>`));
|
||||
}
|
||||
});
|
||||
|
||||
this.$results.animate({scrollTop: me.$results.prop('scrollHeight')}, 500);
|
||||
},
|
||||
|
||||
get_results: function() {
|
||||
|
|
@ -208,6 +210,7 @@ frappe.ui.form.MultiSelectDialog = Class.extend({
|
|||
txt: me.dialog.fields_dict["search_term"].get_value(),
|
||||
filters: filters,
|
||||
filter_fields: Object.keys(me.setters).concat([me.date_field]),
|
||||
start: this.start,
|
||||
page_length: this.page_length + 1,
|
||||
query: this.get_query ? this.get_query().query : '',
|
||||
as_dict: 1
|
||||
|
|
@ -219,8 +222,8 @@ frappe.ui.form.MultiSelectDialog = Class.extend({
|
|||
args: args,
|
||||
callback: function(r) {
|
||||
let results = [], more = 0;
|
||||
if(r.values.length) {
|
||||
if(r.values.length > me.page_length){
|
||||
if (r.values.length) {
|
||||
if (r.values.length > me.page_length) {
|
||||
r.values.pop();
|
||||
more = 1;
|
||||
}
|
||||
|
|
@ -241,7 +244,9 @@ frappe.ui.form.MultiSelectDialog = Class.extend({
|
|||
});
|
||||
|
||||
// Preselect oldest entry
|
||||
results[0].checked = 1
|
||||
if (me.start < 1) {
|
||||
results[0].checked = 1;
|
||||
}
|
||||
}
|
||||
me.render_result_list(results, more);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,15 +31,17 @@
|
|||
{% var value = col.fieldname ? row[col.fieldname] : row[col.id]; %}
|
||||
|
||||
<td>
|
||||
{{
|
||||
col.formatter
|
||||
? col.formatter(row._index, col._index, value, col, row, true)
|
||||
: col.format
|
||||
? col.format(value, row, col, data)
|
||||
: col.docfield
|
||||
? frappe.format(value, col.docfield)
|
||||
: value
|
||||
}}
|
||||
<span {% if col._index == 0 %} style="padding-left: {%= cint(row.indent) * 2 %}em" {% endif %}>
|
||||
{{
|
||||
col.formatter
|
||||
? col.formatter(row._index, col._index, value, col, row, true)
|
||||
: col.format
|
||||
? col.format(value, row, col, data)
|
||||
: col.docfield
|
||||
? frappe.format(value, col.docfield)
|
||||
: value
|
||||
}}
|
||||
</span>
|
||||
</td>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
|
|
|||
|
|
@ -999,9 +999,11 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
|
|||
change: () => {
|
||||
let doctype = d.get_value('doctype');
|
||||
frappe.model.with_doctype(doctype, () => {
|
||||
let fields = frappe.meta.get_docfields(doctype)
|
||||
let options = frappe.meta.get_docfields(doctype)
|
||||
.filter(frappe.model.is_value_type)
|
||||
.map(df => ({ label: df.label, value: df.fieldname }));
|
||||
d.set_df_property('field', 'options', fields);
|
||||
|
||||
d.set_df_property('field', 'options', options);
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ login.bind_events = function() {
|
|||
}
|
||||
});
|
||||
|
||||
{% if ldap_settings %}
|
||||
{% if ldap_settings.enabled %}
|
||||
$(".btn-ldap-login").on("click", function(){
|
||||
var args = {};
|
||||
args.cmd = "{{ ldap_settings.method }}";
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from frappe.utils.oauth import get_oauth2_authorize_url, get_oauth_keys, login_v
|
|||
import json
|
||||
from frappe import _
|
||||
from frappe.auth import LoginManager
|
||||
from frappe.integrations.doctype.ldap_settings.ldap_settings import get_ldap_settings
|
||||
from frappe.integrations.doctype.ldap_settings.ldap_settings import get_ldap_client_settings
|
||||
from frappe.utils.password import get_decrypted_password
|
||||
from frappe.utils.html_utils import get_icon_html
|
||||
|
||||
|
|
@ -38,8 +38,7 @@ def get_context(context):
|
|||
"icon": icon
|
||||
})
|
||||
context["social_login"] = True
|
||||
|
||||
ldap_settings = get_ldap_settings()
|
||||
ldap_settings = get_ldap_client_settings()
|
||||
context["ldap_settings"] = ldap_settings
|
||||
|
||||
login_name_placeholder = [_("Email address")]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue