Merge branch 'develop' of https://github.com/frappe/frappe into fix-blog-post-pagination
This commit is contained in:
commit
dce13faa52
26 changed files with 289 additions and 697 deletions
36
.github/frappe_linter/translation.py
vendored
36
.github/frappe_linter/translation.py
vendored
|
|
@ -7,22 +7,28 @@ start_pattern = re.compile(r"_{1,2}\([\"']{1,3}")
|
|||
|
||||
# skip first argument
|
||||
files = sys.argv[1:]
|
||||
for _file in files:
|
||||
if not _file.endswith(('.py', '.js')):
|
||||
continue
|
||||
files_to_scan = [_file for _file in files if _file.endswith(('.py', '.js'))]
|
||||
|
||||
for _file in files_to_scan:
|
||||
with open(_file, 'r') as f:
|
||||
print(f'Checking: {_file}')
|
||||
for num, line in enumerate(f, 1):
|
||||
all_matches = start_pattern.finditer(line)
|
||||
if all_matches:
|
||||
for match in all_matches:
|
||||
verify = pattern.search(line)
|
||||
if not verify:
|
||||
errors_encounter += 1
|
||||
print(f'A syntax error has been discovered at line number: {num}')
|
||||
print(f'Syntax error occurred with: {line}')
|
||||
file_lines = f.readlines()
|
||||
for line_number, line in enumerate(file_lines, 1):
|
||||
start_matches = start_pattern.search(line)
|
||||
if start_matches:
|
||||
match = pattern.search(line)
|
||||
if not match and line.endswith(',\n'):
|
||||
# concat remaining text to validate multiline pattern
|
||||
line = "".join(file_lines[line_number - 1:])
|
||||
line = line[start_matches.start() + 1:]
|
||||
match = pattern.match(line)
|
||||
|
||||
if not match:
|
||||
errors_encounter += 1
|
||||
print(f'\nTranslation syntax error at line number: {line_number + 1}\n{line.strip()[:100]}')
|
||||
|
||||
if errors_encounter > 0:
|
||||
print('You can visit "https://frappeframework.com/docs/user/en/translations" to resolve this error.')
|
||||
assert 1+1 == 3
|
||||
print('\nYou can visit "https://frappeframework.com/docs/user/en/translations" to resolve this error.')
|
||||
sys.exit(1)
|
||||
else:
|
||||
print('Good To Go!')
|
||||
print('\nGood To Go!')
|
||||
|
|
|
|||
|
|
@ -61,10 +61,10 @@ context('Recorder', () => {
|
|||
|
||||
cy.visit('/desk#recorder');
|
||||
|
||||
cy.get('.list-row-container span').contains('frappe.desk.reportview.get').click();
|
||||
cy.get('.list-row-container span').contains('/api/method/frappe').click();
|
||||
|
||||
cy.location('hash').should('contain', '#recorder/request/');
|
||||
cy.get('form').should('contain', 'frappe.desk.reportview.get');
|
||||
cy.get('form').should('contain', '/api/method/frappe');
|
||||
|
||||
cy.get('#page-recorder .primary-action').should('contain', 'Stop').click();
|
||||
cy.get('#page-recorder .btn-secondary').should('contain', 'Clear').click();
|
||||
|
|
|
|||
|
|
@ -1110,8 +1110,8 @@ def get_newargs(fn, kwargs):
|
|||
if (a in fnargs) or varkw:
|
||||
newargs[a] = kwargs.get(a)
|
||||
|
||||
if "flags" in newargs:
|
||||
del newargs["flags"]
|
||||
newargs.pop("ignore_permissions", None)
|
||||
newargs.pop("flags", None)
|
||||
|
||||
return newargs
|
||||
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ def reset_perms(context):
|
|||
def execute(context, method, args=None, kwargs=None, profile=False):
|
||||
"Execute a function"
|
||||
for site in context.sites:
|
||||
ret = ""
|
||||
try:
|
||||
frappe.init(site=site)
|
||||
frappe.connect()
|
||||
|
|
@ -154,7 +155,10 @@ def execute(context, method, args=None, kwargs=None, profile=False):
|
|||
pr = cProfile.Profile()
|
||||
pr.enable()
|
||||
|
||||
ret = frappe.get_attr(method)(*args, **kwargs)
|
||||
try:
|
||||
ret = frappe.get_attr(method)(*args, **kwargs)
|
||||
except Exception:
|
||||
ret = frappe.safe_eval(method + "(*args, **kwargs)", eval_globals=globals(), eval_locals=locals())
|
||||
|
||||
if profile:
|
||||
pr.disable()
|
||||
|
|
|
|||
|
|
@ -1,731 +1,184 @@
|
|||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
{
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
"autoname": "",
|
||||
"beta": 0,
|
||||
"creation": "2017-10-05 11:10:38.780133",
|
||||
"custom": 0,
|
||||
"description": "Keep track of all update feeds",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"editable_grid": 0,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"subject",
|
||||
"section_break_8",
|
||||
"content",
|
||||
"column_break_5",
|
||||
"additional_info",
|
||||
"communication_date",
|
||||
"column_break_7",
|
||||
"operation",
|
||||
"status",
|
||||
"reference_section",
|
||||
"reference_doctype",
|
||||
"reference_name",
|
||||
"reference_owner",
|
||||
"column_break_14",
|
||||
"timeline_doctype",
|
||||
"timeline_name",
|
||||
"link_doctype",
|
||||
"link_name",
|
||||
"user",
|
||||
"full_name"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "subject",
|
||||
"fieldtype": "Small Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Subject",
|
||||
"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
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_8",
|
||||
"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
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "content",
|
||||
"fieldtype": "Text Editor",
|
||||
"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": "Message",
|
||||
"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,
|
||||
"width": "400"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_5",
|
||||
"fieldtype": "Column 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
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"columns": 0,
|
||||
"fieldname": "additional_info",
|
||||
"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": "More Information",
|
||||
"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
|
||||
"label": "More Information"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Now",
|
||||
"fieldname": "communication_date",
|
||||
"fieldtype": "Datetime",
|
||||
"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": "Date",
|
||||
"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
|
||||
"label": "Date"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_7",
|
||||
"fieldtype": "Column 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
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "operation",
|
||||
"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": "Operation",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "\nLogin\nLogout",
|
||||
"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
|
||||
"options": "\nLogin\nLogout"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"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": "Status",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "\nSuccess\nFailed\nLinked\nClosed",
|
||||
"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
|
||||
"options": "\nSuccess\nFailed\nLinked\nClosed"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"columns": 0,
|
||||
"fieldname": "reference_section",
|
||||
"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": "Reference",
|
||||
"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
|
||||
"label": "Reference"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "reference_doctype",
|
||||
"fieldtype": "Link",
|
||||
"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": "Reference Document Type",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "DocType",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"options": "DocType"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "reference_name",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"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": "Reference Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "reference_doctype",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"options": "reference_doctype"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "reference_name.owner",
|
||||
"fieldname": "reference_owner",
|
||||
"fieldtype": "Read Only",
|
||||
"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": "Reference Owner",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"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": 1,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_14",
|
||||
"fieldtype": "Column 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
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "timeline_doctype",
|
||||
"fieldtype": "Link",
|
||||
"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": "Timeline DocType",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "DocType",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"options": "DocType"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "timeline_name",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"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": "Timeline Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "timeline_doctype",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"options": "timeline_doctype"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "link_doctype",
|
||||
"fieldtype": "Link",
|
||||
"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": "Link DocType",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "DocType",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "link_name",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"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": "Link Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "link_doctype",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "__user",
|
||||
"fieldname": "user",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 1,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "User",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "User",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "full_name",
|
||||
"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": "Full Name",
|
||||
"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
|
||||
"label": "Full Name"
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"icon": "fa fa-comment",
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-09-05 14:22:27.664645",
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2020-08-28 11:43:57.504565",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "Activity Log",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
"share": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 1,
|
||||
"if_owner": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 1,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "All",
|
||||
"set_user_permissions": 0,
|
||||
"share": 0,
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
"share": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"search_fields": "subject",
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "subject",
|
||||
|
|
|
|||
|
|
@ -25,9 +25,6 @@ class ActivityLog(Document):
|
|||
if self.reference_doctype and self.reference_name:
|
||||
self.status = "Linked"
|
||||
|
||||
def on_trash(self): # pylint: disable=no-self-use
|
||||
frappe.throw(_("Sorry! You cannot delete auto-generated comments"))
|
||||
|
||||
def on_doctype_update():
|
||||
"""Add indexes in `tabActivity Log`"""
|
||||
frappe.db.add_index("Activity Log", ["reference_doctype", "reference_name"])
|
||||
|
|
|
|||
|
|
@ -278,25 +278,26 @@ class File(Document):
|
|||
base_url = os.path.dirname(self.file_url)
|
||||
|
||||
files = []
|
||||
with zipfile.ZipFile(zip_path) as zf:
|
||||
zf.extractall(os.path.dirname(zip_path))
|
||||
for info in zf.infolist():
|
||||
if not info.filename.startswith('__MACOSX'):
|
||||
file_url = file_url = base_url + '/' + info.filename
|
||||
file_name = frappe.db.get_value('File', dict(file_url=file_url))
|
||||
if file_name:
|
||||
file_doc = frappe.get_doc('File', file_name)
|
||||
else:
|
||||
file_doc = frappe.new_doc("File")
|
||||
file_doc.file_name = info.filename
|
||||
file_doc.file_size = info.file_size
|
||||
file_doc.folder = self.folder
|
||||
file_doc.is_private = self.is_private
|
||||
file_doc.file_url = file_url
|
||||
file_doc.attached_to_doctype = self.attached_to_doctype
|
||||
file_doc.attached_to_name = self.attached_to_name
|
||||
file_doc.save()
|
||||
files.append(file_doc)
|
||||
with zipfile.ZipFile(zip_path) as z:
|
||||
for file in z.filelist:
|
||||
if file.is_dir() or file.filename.startswith('__MACOSX/'):
|
||||
# skip directories and macos hidden directory
|
||||
continue
|
||||
|
||||
filename = os.path.basename(file.filename)
|
||||
if filename.startswith('.'):
|
||||
# skip hidden files
|
||||
continue
|
||||
|
||||
file_doc = frappe.new_doc('File')
|
||||
file_doc.content = z.read(file.filename)
|
||||
file_doc.file_name = filename
|
||||
file_doc.folder = self.folder
|
||||
file_doc.is_private = self.is_private
|
||||
file_doc.attached_to_doctype = self.attached_to_doctype
|
||||
file_doc.attached_to_name = self.attached_to_name
|
||||
file_doc.save()
|
||||
files.append(file_doc)
|
||||
|
||||
frappe.delete_doc('File', self.name)
|
||||
return files
|
||||
|
|
@ -941,7 +942,7 @@ def attach_files_to_document(doc, event):
|
|||
# we dont want the update to fail if file cannot be attached for some reason
|
||||
try:
|
||||
value = doc.get(df.fieldname)
|
||||
if not value.startswith(("/files", "/private/files")):
|
||||
if not (value or '').startswith(("/files", "/private/files")):
|
||||
return
|
||||
|
||||
if frappe.db.exists("File", {
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ def export_package():
|
|||
@frappe.whitelist()
|
||||
def import_package(package=None):
|
||||
"""Import package from JSON."""
|
||||
frappe.only_for("System Manager")
|
||||
if isinstance(package, string_types):
|
||||
package = json.loads(package)
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class Workspace:
|
|||
|
||||
self.doc = self.get_page_for_user()
|
||||
|
||||
if self.doc.module not in self.allowed_modules:
|
||||
if self.doc.module and self.doc.module not in self.allowed_modules:
|
||||
raise frappe.PermissionError
|
||||
|
||||
self.can_read = self.get_cached('user_perm_can_read', self.get_can_read_items)
|
||||
|
|
|
|||
|
|
@ -60,11 +60,11 @@ def has_permission(doc, ptype, user):
|
|||
|
||||
|
||||
if doc.chart_type == 'Report':
|
||||
allowed_reports = tuple([key.encode('UTF8') for key in get_allowed_reports()])
|
||||
allowed_reports = [key if type(key) == str else key.encode('UTF8') for key in get_allowed_reports()]
|
||||
if doc.report_name in allowed_reports:
|
||||
return True
|
||||
else:
|
||||
allowed_doctypes = tuple(frappe.permissions.get_doctypes_with_read())
|
||||
allowed_doctypes = [frappe.permissions.get_doctypes_with_read()]
|
||||
if doc.document_type in allowed_doctypes:
|
||||
return True
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class DeskPage(Document):
|
|||
|
||||
pages = frappe.get_all("Desk Page", fields=["name", "module"], filters=filters, as_list=1)
|
||||
|
||||
return { page[1]: page[0] for page in pages }
|
||||
return { page[1]: page[0] for page in pages if page[1] }
|
||||
|
||||
def disable_saving_as_standard():
|
||||
return frappe.flags.in_install or \
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Callback URL",
|
||||
"read_only": 1,
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
},
|
||||
|
|
@ -28,19 +29,20 @@
|
|||
"fieldname": "api_key",
|
||||
"fieldtype": "Data",
|
||||
"label": "API Key",
|
||||
"read_only": 1
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "api_secret",
|
||||
"fieldtype": "Password",
|
||||
"label": "API Secret",
|
||||
"read_only": 1
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "user",
|
||||
"fieldtype": "Link",
|
||||
"label": "Event Subscriber",
|
||||
"options": "User",
|
||||
"read_only": 1,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
|
|
@ -69,7 +71,7 @@
|
|||
],
|
||||
"in_create": 1,
|
||||
"links": [],
|
||||
"modified": "2020-09-06 15:42:00.746493",
|
||||
"modified": "2020-09-08 16:42:39.828085",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Event Streaming",
|
||||
"name": "Event Consumer",
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import frappe
|
|||
import json
|
||||
import requests
|
||||
import os
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.frappeclient import FrappeClient
|
||||
from frappe.utils.data import get_url
|
||||
|
|
@ -23,6 +24,10 @@ class EventConsumer(Document):
|
|||
|
||||
def on_update(self):
|
||||
if not self.incoming_change:
|
||||
doc_before_save = self.get_doc_before_save()
|
||||
if doc_before_save.api_key != self.api_key or doc_before_save.api_secret != self.api_secret:
|
||||
return
|
||||
|
||||
self.update_consumer_status()
|
||||
else:
|
||||
frappe.db.set_value(self.doctype, self.name, 'incoming_change', 0)
|
||||
|
|
@ -58,17 +63,26 @@ class EventConsumer(Document):
|
|||
return 'offline'
|
||||
return 'online'
|
||||
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
@frappe.whitelist()
|
||||
def register_consumer(data):
|
||||
"""create an event consumer document for registering a consumer"""
|
||||
data = json.loads(data)
|
||||
# to ensure that consumer is created only once
|
||||
if frappe.db.exists('Event Consumer', data['event_consumer']):
|
||||
return None
|
||||
|
||||
user = data['user']
|
||||
if not frappe.db.exists('User', user):
|
||||
frappe.throw(_('User {0} not found on the producer site').format(user))
|
||||
|
||||
if "System Manager" not in frappe.get_roles(user):
|
||||
frappe.throw(_("Event Subscriber has to be a System Manager."))
|
||||
|
||||
consumer = frappe.new_doc('Event Consumer')
|
||||
consumer.callback_url = data['event_consumer']
|
||||
consumer.user = data['user']
|
||||
consumer.api_key = data['api_key']
|
||||
consumer.api_secret = data['api_secret']
|
||||
consumer.incoming_change = True
|
||||
consumer_doctypes = json.loads(data['consumer_doctypes'])
|
||||
|
||||
|
|
@ -78,18 +92,13 @@ def register_consumer(data):
|
|||
'status': 'Pending'
|
||||
})
|
||||
|
||||
api_key = frappe.generate_hash(length=10)
|
||||
api_secret = frappe.generate_hash(length=10)
|
||||
consumer.api_key = api_key
|
||||
consumer.api_secret = api_secret
|
||||
consumer.insert(ignore_permissions=True)
|
||||
frappe.db.commit()
|
||||
consumer.insert()
|
||||
|
||||
# consumer's 'last_update' field should point to the latest update
|
||||
# in producer's update log when subscribing
|
||||
# so that, updates after subscribing are consumed and not the old ones.
|
||||
last_update = str(get_last_update())
|
||||
return json.dumps({'api_key': api_key, 'api_secret': api_secret, 'last_update': last_update})
|
||||
return json.dumps({'last_update': last_update})
|
||||
|
||||
|
||||
def get_consumer_site(consumer_url):
|
||||
|
|
@ -98,8 +107,7 @@ def get_consumer_site(consumer_url):
|
|||
consumer_site = FrappeClient(
|
||||
url=consumer_url,
|
||||
api_key=consumer_doc.api_key,
|
||||
api_secret=consumer_doc.get_password('api_secret'),
|
||||
frappe_authorization_source='Event Producer'
|
||||
api_secret=consumer_doc.get_password('api_secret')
|
||||
)
|
||||
return consumer_site
|
||||
|
||||
|
|
|
|||
|
|
@ -32,23 +32,26 @@
|
|||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"description": "API Key of the user(Event Subscriber) on the producer site",
|
||||
"fieldname": "api_key",
|
||||
"fieldtype": "Data",
|
||||
"label": "API Key",
|
||||
"read_only": 1
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"description": "API Secret of the user(Event Subscriber) on the producer site",
|
||||
"fieldname": "api_secret",
|
||||
"fieldtype": "Password",
|
||||
"label": "API Secret",
|
||||
"read_only": 1
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "user",
|
||||
"fieldtype": "Link",
|
||||
"label": "Event Subscriber",
|
||||
"options": "User",
|
||||
"reqd": 1
|
||||
"reqd": 1,
|
||||
"set_only_once": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_6",
|
||||
|
|
@ -74,7 +77,7 @@
|
|||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2019-12-26 13:04:11.438349",
|
||||
"modified": "2020-09-08 18:50:57.687979",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Event Streaming",
|
||||
"name": "Event Producer",
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ from frappe import _
|
|||
from frappe.model.document import Document
|
||||
from frappe.frappeclient import FrappeClient
|
||||
from frappe.utils.background_jobs import get_jobs
|
||||
from frappe.utils.data import get_url
|
||||
from frappe.utils.data import get_url, get_link_to_form
|
||||
from frappe.utils.password import get_decrypted_password
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
|
||||
from frappe.integrations.oauth2 import validate_url
|
||||
|
||||
|
|
@ -20,19 +21,35 @@ from frappe.integrations.oauth2 import validate_url
|
|||
class EventProducer(Document):
|
||||
def before_insert(self):
|
||||
self.check_url()
|
||||
self.validate_event_subscriber()
|
||||
self.incoming_change = True
|
||||
self.create_event_consumer()
|
||||
self.create_custom_fields()
|
||||
|
||||
def validate(self):
|
||||
self.validate_event_subscriber()
|
||||
if frappe.flags.in_test:
|
||||
for entry in self.producer_doctypes:
|
||||
entry.status = 'Approved'
|
||||
|
||||
def validate_event_subscriber(self):
|
||||
if not frappe.db.get_value('User', self.user, 'api_key'):
|
||||
frappe.throw(_('Please generate keys for the Event Subscriber User {0} first.').format(
|
||||
frappe.bold(get_link_to_form('User', self.user))
|
||||
))
|
||||
|
||||
def on_update(self):
|
||||
if not self.incoming_change:
|
||||
self.update_event_consumer()
|
||||
self.create_custom_fields()
|
||||
if frappe.db.exists('Event Producer', self.name):
|
||||
if not self.api_key or not self.api_secret:
|
||||
frappe.throw(_('Please set API Key and Secret on the producer and consumer sites first.'))
|
||||
else:
|
||||
doc_before_save = self.get_doc_before_save()
|
||||
if doc_before_save.api_key != self.api_key or doc_before_save.api_secret != self.api_secret:
|
||||
return
|
||||
|
||||
self.update_event_consumer()
|
||||
self.create_custom_fields()
|
||||
else:
|
||||
# when producer doc is updated it updates the consumer doc, set flag to avoid deadlock
|
||||
self.db_set('incoming_change', 0)
|
||||
|
|
@ -50,15 +67,18 @@ class EventProducer(Document):
|
|||
def create_event_consumer(self):
|
||||
"""register event consumer on the producer site"""
|
||||
if self.is_producer_online():
|
||||
producer_site = FrappeClient(self.producer_url, verify=False)
|
||||
producer_site = FrappeClient(
|
||||
url=self.producer_url,
|
||||
api_key=self.api_key,
|
||||
api_secret=self.get_password('api_secret')
|
||||
)
|
||||
|
||||
response = producer_site.post_api(
|
||||
'frappe.event_streaming.doctype.event_consumer.event_consumer.register_consumer',
|
||||
params={'data': json.dumps(self.get_request_data())}
|
||||
)
|
||||
if response:
|
||||
response = json.loads(response)
|
||||
self.api_key = response['api_key']
|
||||
self.api_secret = response['api_secret']
|
||||
self.last_update = response['last_update']
|
||||
else:
|
||||
frappe.throw(_('Failed to create an Event Consumer or an Event Consumer for the current site is already registered.'))
|
||||
|
|
@ -72,10 +92,14 @@ class EventProducer(Document):
|
|||
else:
|
||||
consumer_doctypes.append(entry.ref_doctype)
|
||||
|
||||
user_key = frappe.db.get_value('User', self.user, 'api_key')
|
||||
user_secret = get_decrypted_password('User', self.user, 'api_secret')
|
||||
return {
|
||||
'event_consumer': get_url(),
|
||||
'consumer_doctypes': json.dumps(consumer_doctypes),
|
||||
'user': self.user
|
||||
'user': self.user,
|
||||
'api_key': user_key,
|
||||
'api_secret': user_secret
|
||||
}
|
||||
|
||||
def create_custom_fields(self):
|
||||
|
|
@ -131,8 +155,7 @@ def get_producer_site(producer_url):
|
|||
producer_site = FrappeClient(
|
||||
url=producer_url,
|
||||
api_key=producer_doc.api_key,
|
||||
api_secret=producer_doc.get_password('api_secret'),
|
||||
frappe_authorization_source='Event Consumer'
|
||||
api_secret=producer_doc.get_password('api_secret')
|
||||
)
|
||||
return producer_site
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import unittest
|
|||
import json
|
||||
from frappe.frappeclient import FrappeClient
|
||||
from frappe.event_streaming.doctype.event_producer.event_producer import pull_from_node
|
||||
from frappe.core.doctype.user.user import generate_keys
|
||||
|
||||
producer_url = 'http://test_site_producer:8000'
|
||||
|
||||
|
|
@ -166,16 +167,6 @@ class TestEventProducer(unittest.TestCase):
|
|||
def pull_producer_data(self):
|
||||
pull_from_node(producer_url)
|
||||
|
||||
def get_remote_site(self):
|
||||
producer_doc = frappe.get_doc('Event Producer', producer_url)
|
||||
producer_site = FrappeClient(
|
||||
url=producer_doc.producer_url,
|
||||
api_key=producer_doc.api_key,
|
||||
api_secret=producer_doc.get_password('api_secret'),
|
||||
frappe_authorization_source='Event Consumer'
|
||||
)
|
||||
return producer_site
|
||||
|
||||
def test_mapping(self):
|
||||
producer = get_remote_site()
|
||||
event_producer = frappe.get_doc('Event Producer', producer_url, for_update=True)
|
||||
|
|
@ -298,6 +289,20 @@ def create_event_producer(producer_url):
|
|||
event_producer.save()
|
||||
return
|
||||
|
||||
generate_keys('Administrator')
|
||||
|
||||
producer_site = connect()
|
||||
|
||||
response = producer_site.post_api(
|
||||
'frappe.core.doctype.user.user.generate_keys',
|
||||
params={'user': 'Administrator'}
|
||||
)
|
||||
|
||||
api_secret = response.get('api_secret')
|
||||
|
||||
response = producer_site.get_value('User', 'api_key', {'name': 'Administrator'})
|
||||
api_key = response.get('api_key')
|
||||
|
||||
event_producer = frappe.new_doc('Event Producer')
|
||||
event_producer.producer_doctypes = []
|
||||
event_producer.producer_url = producer_url
|
||||
|
|
@ -310,6 +315,8 @@ def create_event_producer(producer_url):
|
|||
'use_same_name': 1
|
||||
})
|
||||
event_producer.user = 'Administrator'
|
||||
event_producer.api_key = api_key
|
||||
event_producer.api_secret = api_secret
|
||||
event_producer.save()
|
||||
|
||||
def reset_configuration(producer_url):
|
||||
|
|
@ -331,9 +338,9 @@ def get_remote_site():
|
|||
producer_doc = frappe.get_doc('Event Producer', producer_url)
|
||||
producer_site = FrappeClient(
|
||||
url=producer_doc.producer_url,
|
||||
api_key=producer_doc.api_key,
|
||||
api_secret=producer_doc.get_password('api_secret'),
|
||||
frappe_authorization_source='Event Consumer'
|
||||
username='Administrator',
|
||||
password='admin',
|
||||
verify=False
|
||||
)
|
||||
return producer_site
|
||||
|
||||
|
|
@ -341,4 +348,17 @@ def unsubscribe_doctypes(producer_url):
|
|||
event_producer = frappe.get_doc('Event Producer', producer_url)
|
||||
for entry in event_producer.producer_doctypes:
|
||||
entry.unsubscribe = 1
|
||||
event_producer.save()
|
||||
event_producer.save()
|
||||
|
||||
def connect():
|
||||
def _connect():
|
||||
return FrappeClient(
|
||||
url=producer_url,
|
||||
username='Administrator',
|
||||
password='admin',
|
||||
verify=False
|
||||
)
|
||||
try:
|
||||
return _connect()
|
||||
except Exception:
|
||||
return _connect()
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ def update_document_title(doctype, docname, title_field=None, old_title=None, ne
|
|||
|
||||
return docname
|
||||
|
||||
@frappe.whitelist()
|
||||
def rename_doc(doctype, old, new, force=False, merge=False, ignore_permissions=False, ignore_if_exists=False, show_alert=True):
|
||||
"""
|
||||
Renames a doc(dt, old) to doc(dt, new) and
|
||||
|
|
|
|||
|
|
@ -308,3 +308,4 @@ frappe.patches.v13_0.remove_duplicate_navbar_items
|
|||
frappe.patches.v13_0.set_route_for_blog_category
|
||||
frappe.patches.v13_0.enable_custom_script
|
||||
frappe.patches.v13_0.update_newsletter_content_type
|
||||
frappe.patches.v13_0.delete_event_producer_and_consumer_keys
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# MIT License. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
if frappe.db.exists("DocType", "Event Producer"):
|
||||
frappe.db.sql("""UPDATE `tabEvent Producer` SET api_key='', api_secret=''""")
|
||||
if frappe.db.exists("DocType", "Event Consumer"):
|
||||
frappe.db.sql("""UPDATE `tabEvent Consumer` SET api_key='', api_secret=''""")
|
||||
|
|
@ -1259,7 +1259,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
|
|||
return;
|
||||
}
|
||||
|
||||
this.export_dialog = frappe.prompt([
|
||||
let export_dialog_fields = [
|
||||
{
|
||||
label: __('Select File Format'),
|
||||
fieldname: 'file_format',
|
||||
|
|
@ -1267,13 +1267,18 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
|
|||
options: ['Excel', 'CSV'],
|
||||
default: 'Excel',
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
}
|
||||
];
|
||||
|
||||
if (this.tree_report) {
|
||||
export_dialog_fields.push({
|
||||
label: __("Include indentation"),
|
||||
fieldname: "include_indentation",
|
||||
fieldtype: "Check",
|
||||
}
|
||||
], ({ file_format, include_indentation }) => {
|
||||
});
|
||||
}
|
||||
|
||||
this.export_dialog = frappe.prompt(export_dialog_fields, ({ file_format, include_indentation }) => {
|
||||
this.make_access_log('Export', file_format);
|
||||
if (file_format === 'CSV') {
|
||||
const column_row = this.columns.reduce((acc, col) => {
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@
|
|||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.report-wrapper {
|
||||
.report-wrapper, .datatable-wrapper {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
|
|
|
|||
46
frappe/tests/test_commands.py
Normal file
46
frappe/tests/test_commands.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
|
||||
# imports - standard imports
|
||||
import shlex
|
||||
import subprocess
|
||||
import unittest
|
||||
|
||||
# imports - module imports
|
||||
import frappe
|
||||
|
||||
|
||||
def clean(value):
|
||||
if isinstance(value, (bytes, str)):
|
||||
value = value.decode().strip()
|
||||
return value
|
||||
|
||||
|
||||
class BaseTestCommands:
|
||||
def execute(self, command):
|
||||
command = command.format(**{"site": frappe.local.site})
|
||||
command = shlex.split(command)
|
||||
self._proc = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
self.stdout = clean(self._proc.stdout)
|
||||
self.stderr = clean(self._proc.stderr)
|
||||
self.returncode = clean(self._proc.returncode)
|
||||
|
||||
|
||||
class TestCommands(BaseTestCommands, unittest.TestCase):
|
||||
def test_execute(self):
|
||||
# test 1: execute a command expecting a numeric output
|
||||
self.execute("bench --site {site} execute frappe.db.get_database_size")
|
||||
self.assertEquals(self.returncode, 0)
|
||||
self.assertIsInstance(float(self.stdout), float)
|
||||
|
||||
# test 2: execute a command expecting an errored output as local won't exist
|
||||
self.execute("bench --site {site} execute frappe.local.site")
|
||||
self.assertEquals(self.returncode, 1)
|
||||
self.assertIsNotNone(self.stderr)
|
||||
|
||||
# test 3: execute a command with kwargs
|
||||
# Note:
|
||||
# terminal command has been escaped to avoid .format string replacement
|
||||
# The returned value has quotes which have been trimmed for the test
|
||||
self.execute("""bench --site {site} execute frappe.bold --kwargs '{{"text": "DocType"}}'""")
|
||||
self.assertEquals(self.returncode, 0)
|
||||
self.assertEquals(self.stdout[1:-1], frappe.bold(text='DocType'))
|
||||
|
|
@ -135,7 +135,8 @@ def validate_email_address(email_str, throw=False):
|
|||
|
||||
if not _valid:
|
||||
if throw:
|
||||
frappe.throw(frappe._("{0} is not a valid Email Address").format(e),
|
||||
invalid_email = frappe.utils.escape_html(e)
|
||||
frappe.throw(frappe._("{0} is not a valid Email Address").format(invalid_email),
|
||||
frappe.InvalidEmailAddressError)
|
||||
return None
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -33,9 +33,9 @@ frappe.ui.form.on('Blog Post', {
|
|||
});
|
||||
|
||||
function generate_google_search_preview(frm) {
|
||||
if (!frm.doc.title) return;
|
||||
if (!(frm.doc.meta_title || frm.doc.title)) return;
|
||||
let google_preview = frm.get_field("google_preview");
|
||||
let seo_title = (frm.doc.title).slice(0, 60);
|
||||
let seo_title = (frm.doc.meta_title || frm.doc.title).slice(0, 60);
|
||||
let seo_description = (frm.doc.meta_description || frm.doc.blog_intro || "").slice(0, 160);
|
||||
let date = frm.doc.published_on ? new frappe.datetime.datetime(frm.doc.published_on).moment.format('ll') + ' - ' : '';
|
||||
let route_array = frm.doc.route ? frm.doc.route.split('/') : [];
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
"content_html",
|
||||
"email_sent",
|
||||
"meta_tags",
|
||||
"meta_title",
|
||||
"meta_description",
|
||||
"column_break_18",
|
||||
"meta_image",
|
||||
|
|
@ -110,7 +111,6 @@
|
|||
"depends_on": "eval:doc.content_type === 'Markdown'",
|
||||
"fieldname": "content_md",
|
||||
"fieldtype": "Markdown Editor",
|
||||
"ignore_xss_filter": 1,
|
||||
"label": "Content (Markdown)"
|
||||
},
|
||||
{
|
||||
|
|
@ -185,6 +185,12 @@
|
|||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"label": "Hide CTA"
|
||||
},
|
||||
{
|
||||
"fieldname": "meta_title",
|
||||
"fieldtype": "Data",
|
||||
"label": "Meta Title",
|
||||
"length": 60
|
||||
}
|
||||
],
|
||||
"has_web_view": 1,
|
||||
|
|
@ -194,7 +200,7 @@
|
|||
"is_published_field": "published",
|
||||
"links": [],
|
||||
"max_attachments": 5,
|
||||
"modified": "2020-08-31 16:55:03.687862",
|
||||
"modified": "2020-08-31 21:01:51.100349",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Website",
|
||||
"name": "Blog Post",
|
||||
|
|
|
|||
|
|
@ -36,6 +36,11 @@ class BlogPost(WebsiteGenerator):
|
|||
if self.blog_intro:
|
||||
self.blog_intro = self.blog_intro[:200]
|
||||
|
||||
if not self.meta_title:
|
||||
self.meta_title = self.title[:60]
|
||||
else:
|
||||
self.meta_title = self.meta_title[:60]
|
||||
|
||||
if not self.meta_description:
|
||||
self.meta_description = self.blog_intro[:140]
|
||||
else:
|
||||
|
|
@ -88,7 +93,7 @@ class BlogPost(WebsiteGenerator):
|
|||
context.description = self.meta_description or self.blog_intro or strip_html_tags(context.content[:140])
|
||||
|
||||
context.metatags = {
|
||||
"name": self.title,
|
||||
"name": self.meta_title,
|
||||
"description": context.description,
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue