Merge branch 'staging-fixes' of https://github.com/frappe/frappe into staging-fixes

This commit is contained in:
Suraj Shetty 2018-11-21 13:18:33 +05:30
commit e79cfc531a
58 changed files with 1034 additions and 854 deletions

View file

@ -1,4 +1,3 @@
<div align="center">
<img src=".github/frappe-bird.png" height="150">
<h1>

View file

@ -17,7 +17,7 @@ from faker import Faker
from .exceptions import *
from .utils.jinja import (get_jenv, get_template, render_template, get_email_from_template, get_jloader)
__version__ = '10.1.58'
__version__ = '10.1.63'
__title__ = "Frappe Framework"
local = Local()

View file

@ -195,7 +195,10 @@ def create(kind, owner, users = None, name = None):
for user in dsettings.chat_operators:
if user.user not in users:
room.append('users', user)
# appending user to room.users will remove the user from chat_operators
# this is undesirable, create a new Chat Room User instead
chat_room_user = {"doctype": "Chat Room User", "user": user.user}
room.append('users', chat_room_user)
room.save(ignore_permissions = True)

View file

@ -10,6 +10,7 @@ from frappe.core.doctype.communication.comment import (notify_mentions,
update_comment_in_doc, on_trash)
from frappe.core.doctype.communication.email import (validate_email,
notify, _notify, update_parent_mins_to_first_response)
from frappe.core.utils import get_parent_doc, set_timeline_doc
from frappe.utils.bot import BotReply
from frappe.utils import parse_addr
@ -241,34 +242,6 @@ class Communication(Document):
if commit:
frappe.db.commit()
def get_parent_doc(doc):
"""Returns document of `reference_doctype`, `reference_doctype`"""
if not hasattr(doc, "parent_doc"):
if doc.reference_doctype and doc.reference_name:
doc.parent_doc = frappe.get_doc(doc.reference_doctype, doc.reference_name)
else:
doc.parent_doc = None
return doc.parent_doc
def set_timeline_doc(doc):
"""Set timeline_doctype and timeline_name"""
parent_doc = get_parent_doc(doc)
if (doc.timeline_doctype and doc.timeline_name) or not parent_doc:
return
timeline_field = parent_doc.meta.timeline_field
if not timeline_field:
return
doctype = parent_doc.meta.get_link_doctype(timeline_field)
name = parent_doc.get(timeline_field)
if doctype and name:
doc.timeline_doctype = doctype
doc.timeline_name = name
else:
return
def on_doctype_update():
"""Add indexes in `tabCommunication`"""

View file

@ -19,16 +19,7 @@ frappe.listview_settings['Communication'] = {
});
},
set_primary_action: function(list_view) {
var me = this;
if (list_view.new_doctype) {
list_view.page.set_primary_action(
__("New"),
function() { new frappe.views.CommunicationComposer({ doc: {} }) },
"octicon octicon-plus"
);
} else {
list_view.page.clear_primary_action();
}
primary_action: function() {
new frappe.views.CommunicationComposer({ doc: {} });
}
};

View file

@ -200,6 +200,13 @@ frappe.data_import.download_dialog = function(frm) {
"options": "Excel\nCSV",
"default": "Excel"
},
{
"label": __("Download with Data"),
"fieldname": "with_data",
"fieldtype": "Check",
"hidden": !frm.doc.overwrite,
"default": 1
},
{
"label": __("Select All"),
"fieldname": "select_all",
@ -270,7 +277,7 @@ frappe.data_import.download_dialog = function(frm) {
doctype: frm.doc.reference_doctype,
parent_doctype: frm.doc.reference_doctype,
select_columns: JSON.stringify(columns),
with_data: frm.doc.overwrite,
with_data: frm.doc.overwrite && data.with_data,
all_doctypes: true,
file_type: data.file_type,
template: true

View file

@ -38,9 +38,10 @@ class File(NestedSet):
self.set_folder_name()
def get_name_based_on_parent_folder(self):
path = get_breadcrumbs(self.folder)
folder_name = frappe.get_value("File", self.folder, "file_name")
return "/".join([d.file_name for d in path] + [folder_name, self.file_name])
if self.folder:
path = get_breadcrumbs(self.folder)
folder_name = frappe.get_value("File", self.folder, "file_name")
return "/".join([d.file_name for d in path] + [folder_name, self.file_name])
def autoname(self):
"""Set name for folder"""

View file

@ -74,7 +74,7 @@ def create_csv_file(columns, data, dt, dn):
new_row = []
for col in columns:
key = col.get('fieldname') or col.get('label')
new_row.append(frappe.format(row.get(key, ''), col))
new_row.append(row.get(key, ''))
rows.append(new_row)
rows = [tuple(columns_without_meta)] + rows

View file

@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
@ -252,7 +253,7 @@
"columns": 0,
"fieldname": "full_name",
"fieldtype": "Data",
"hidden": 1,
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
@ -266,7 +267,7 @@
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@ -2206,7 +2207,7 @@
"istable": 0,
"max_attachments": 5,
"menu_index": 0,
"modified": "2018-09-28 16:34:06.215199",
"modified": "2018-11-06 12:41:33.864058",
"modified_by": "Administrator",
"module": "Core",
"name": "User",
@ -2259,5 +2260,6 @@
"sort_order": "DESC",
"title_field": "full_name",
"track_changes": 1,
"track_seen": 0
"track_seen": 0,
"track_views": 0
}

View file

@ -18,13 +18,14 @@
"is_standard": 1,
"login_required": 1,
"max_attachment_size": 0,
"modified": "2018-06-12 22:24:21.913166",
"modified": "2018-11-01 19:35:43.552429",
"modified_by": "Administrator",
"module": "Core",
"name": "edit-profile",
"owner": "Administrator",
"published": 1,
"route": "update-profile",
"show_in_grid": 0,
"show_sidebar": 1,
"sidebar_items": [],
"success_message": "Profile updated successfully.",
@ -32,6 +33,7 @@
"title": "Update Profile",
"web_form_fields": [
{
"allow_read_on_all_link_options": 0,
"fieldname": "first_name",
"fieldtype": "Data",
"hidden": 0,
@ -39,9 +41,11 @@
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 1
"reqd": 1,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "middle_name",
"fieldtype": "Data",
"hidden": 0,
@ -49,9 +53,11 @@
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "last_name",
"fieldtype": "Data",
"hidden": 0,
@ -59,29 +65,35 @@
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"description": "",
"fieldname": "user_image",
"fieldtype": "Attach",
"fieldtype": "Attach Image",
"hidden": 0,
"label": "User Image",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldtype": "Section Break",
"hidden": 0,
"label": "More Information",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "phone",
"fieldtype": "Data",
"hidden": 0,
@ -89,9 +101,11 @@
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "mobile_no",
"fieldtype": "Data",
"hidden": 0,
@ -99,9 +113,11 @@
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"description": "",
"fieldname": "language",
"fieldtype": "Link",
@ -111,9 +127,11 @@
"max_value": 0,
"options": "Language",
"read_only": 0,
"reqd": 0
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "roles",
"fieldtype": "Table",
"hidden": 0,
@ -122,7 +140,8 @@
"max_value": 0,
"options": "Has Role",
"read_only": 0,
"reqd": 0
"reqd": 0,
"show_in_filter": 0
}
]
}

View file

@ -60,9 +60,7 @@ def search_widget(doctype, txt, query=None, searchfield=None, start=0,
page_length=10, filters=None, filter_fields=None, as_dict=False, reference_doctype=None, ignore_user_permissions=False):
if isinstance(filters, string_types):
filters = json.loads(filters)
meta = frappe.get_meta(doctype)
if searchfield:
sanitize_searchfield(searchfield)
@ -80,6 +78,8 @@ def search_widget(doctype, txt, query=None, searchfield=None, start=0,
search_widget(doctype, txt, standard_queries[doctype][0],
searchfield, start, page_length, filters)
else:
meta = frappe.get_meta(doctype)
if query:
frappe.throw(_("This query style is discontinued"))
# custom query

View file

@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 1,
@ -15,6 +16,7 @@
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -42,11 +44,12 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -75,11 +78,12 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -107,11 +111,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -137,16 +142,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 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_from": "report.report_type",
"fetch_from": "report.report_type",
"fieldname": "report_type",
"fieldtype": "Read Only",
"hidden": 0,
@ -170,11 +176,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -201,11 +208,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -233,11 +241,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -267,11 +276,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -300,14 +310,15 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible": 1,
"columns": 0,
"depends_on": "eval:doc.report_type !== 'Report Builder'",
"fieldname": "report_filters",
@ -332,11 +343,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -363,11 +375,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -394,11 +407,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -425,11 +439,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -456,11 +471,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -487,11 +503,12 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -521,11 +538,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -551,11 +569,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -572,7 +591,7 @@
"label": "Frequency",
"length": 0,
"no_copy": 0,
"options": "Daily\nWeekly\nMonthly",
"options": "Daily\nWeekdays\nWeekly\nMonthly",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -583,11 +602,12 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -615,11 +635,12 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@ -646,11 +667,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -677,7 +699,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"translatable": 0,
"unique": 0
}
],
@ -691,7 +713,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-05-16 22:42:57.093530",
"modified": "2018-11-13 01:59:17.816718",
"modified_by": "Administrator",
"module": "Email",
"name": "Auto Email Report",
@ -744,5 +766,6 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
"track_seen": 0,
"track_views": 0
}

View file

@ -3,17 +3,22 @@
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe, json
import calendar
import json
from datetime import timedelta
import frappe
from frappe import _
from frappe.model.document import Document
from datetime import timedelta
import frappe.utils
from frappe.utils import now, global_date_format, format_time
from frappe.utils.xlsxutils import make_xlsx
from frappe.utils import (format_time, get_link_to_form, get_url_to_report,
global_date_format, now, now_datetime, validate_email_add)
from frappe.utils.csvutils import to_csv
from frappe.utils.xlsxutils import make_xlsx
max_reports_per_user = frappe.local.conf.max_reports_per_user or 3
class AutoEmailReport(Document):
def autoname(self):
self.name = _(self.report)
@ -31,7 +36,7 @@ class AutoEmailReport(Document):
valid = []
for email in self.email_to.split():
if email:
frappe.utils.validate_email_add(email, True)
validate_email_add(email, True)
valid.append(email)
self.email_to = '\n'.join(valid)
@ -55,7 +60,7 @@ class AutoEmailReport(Document):
if self.report_type=='Report Builder' and self.data_modified_till:
self.filters = json.loads(self.filters) if self.filters else {}
self.filters['modified'] = ('>', frappe.utils.now_datetime() - timedelta(hours=self.data_modified_till))
self.filters['modified'] = ('>', now_datetime() - timedelta(hours=self.data_modified_till))
columns, data = report.get_data(limit=self.no_of_rows or 100, user = self.user,
filters = self.filters, as_dict=True)
@ -94,11 +99,9 @@ class AutoEmailReport(Document):
'date_time': date_time,
'columns': columns,
'data': data,
'report_url': frappe.utils.get_url_to_report(self.report,
self.report_type, report_doctype),
'report_url': get_url_to_report(self.report, self.report_type, report_doctype),
'report_name': self.report,
'edit_report_settings': frappe.utils.get_link_to_form('Auto Email Report',
self.name)
'edit_report_settings': get_link_to_form('Auto Email Report', self.name)
})
@staticmethod
@ -169,15 +172,20 @@ def send_now(name):
def send_daily():
'''Check reports to be sent daily'''
now = frappe.utils.now_datetime()
for report in frappe.get_all('Auto Email Report',
{'enabled': 1, 'frequency': ('in', ('Daily', 'Weekly'))}):
current_day = calendar.day_name[now_datetime().weekday()]
enabled_reports = frappe.get_all('Auto Email Report',
filters={'enabled': 1, 'frequency': ('in', ('Daily', 'Weekdays', 'Weekly'))})
for report in enabled_reports:
auto_email_report = frappe.get_doc('Auto Email Report', report.name)
# if not correct weekday, skip
if auto_email_report.frequency=='Weekly':
if now.weekday()!={'Monday':0,'Tuesday':1,'Wednesday':2,
'Thursday':3,'Friday':4,'Saturday':5,'Sunday':6}[auto_email_report.day_of_week]:
if auto_email_report.frequency == "Weekdays":
if current_day in ("Saturday", "Sunday"):
continue
elif auto_email_report.frequency == 'Weekly':
if auto_email_report.day_of_week != current_day:
continue
auto_email_report.send()

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,23 @@
/* eslint-disable */
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: Email Queue", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially([
// insert a new Email Queue
() => frappe.tests.make('Email Queue', [
// values to be set
{key: 'value'}
]),
() => {
assert.equal(cur_frm.doc.key, 'value');
},
() => done()
]);
});

View file

@ -1124,7 +1124,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2018-08-29 14:32:02.179599",
"modified": "2018-10-05 14:32:02.179599",
"modified_by": "Administrator",
"module": "Email",
"name": "Notification",

View file

@ -133,14 +133,16 @@ def get_context(context):
subject = frappe.render_template(self.subject, context)
attachments = self.get_attachment(doc)
recipients = self.get_list_of_recipients(doc, context)
recipients, cc, bcc = self.get_list_of_recipients(doc, context)
sender = None
if self.sender and self.sender_email:
sender = formataddr((self.sender, self.sender_email))
frappe.sendmail(recipients=recipients, subject=subject,
sender=sender,
message= frappe.render_template(self.message, context),
frappe.sendmail(recipients = recipients,
subject = subject,
sender = sender,
cc = cc,
bcc = bcc,
message = frappe.render_template(self.message, context),
reference_doctype = doc.doctype,
reference_name = doc.name,
attachments = attachments,
@ -156,6 +158,8 @@ def get_context(context):
def get_list_of_recipients(self, doc, context):
recipients = []
cc = []
bcc = []
for recipient in self.recipients:
if recipient.condition:
if not frappe.safe_eval(recipient.condition, None, context):
@ -173,7 +177,14 @@ def get_context(context):
if recipient.cc:
recipient.cc = recipient.cc.replace(",", "\n")
recipients = recipients + recipient.cc.split("\n")
cc = cc + recipient.cc.split("\n")
if recipient.bcc and "{" in recipient.bcc:
recipient.bcc = frappe.render_template(recipient.bcc, context)
if recipient.bcc:
recipient.bcc = recipient.bcc.replace(",", "\n")
bcc = bcc + recipient.bcc.split("\n")
#For sending emails to specified role
if recipient.email_by_role:
@ -182,10 +193,9 @@ def get_context(context):
for email in emails:
recipients = recipients + email.split("\n")
if not recipients:
return
return list(set(recipients))
if not recipients and not cc and not bcc:
return None, None, None
return list(set(recipients)), list(set(cc)), list(set(bcc))
def get_attachment(self, doc):
""" check print settings are attach the pdf """
@ -285,7 +295,6 @@ def evaluate_alert(doc, alert, event):
# reload the doc for the latest values & comments,
# except for validate type event.
doc = frappe.get_doc(doc.doctype, doc.name)
alert.send(doc)
except TemplateError:
frappe.throw(_("Error while evaluating Notification {0}. Please fix your template.").format(alert))

View file

@ -110,6 +110,38 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "bcc",
"fieldtype": "Code",
"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": "BCC",
"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,
@ -153,7 +185,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-05-31 15:44:44.161293",
"modified": "2018-09-03 18:37:57.043251",
"modified_by": "Administrator",
"module": "Email",
"name": "Notification Recipient",
@ -167,5 +199,6 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
"track_seen": 0,
"track_views": 0
}

View file

@ -209,7 +209,6 @@ class EMail:
"To": ', '.join(self.recipients) if self.expose_recipients=="header" else "<!--recipient-->",
"Date": email.utils.formatdate(),
"Reply-To": self.reply_to if self.reply_to else None,
"Bcc": ', '.join(self.bcc) if self.bcc else None,
"CC": ', '.join(self.cc) if self.cc and self.expose_recipients=="header" else None,
'X-Frappe-Site': get_url(),
}

View file

@ -276,10 +276,7 @@ def get_unsubscribe_message(unsubscribe_message, expose_recipients):
target="_blank">{0}</a>'''.format(_('Unsubscribe'))
unsubscribe_html = _("{0} to stop receiving emails of this type").format(unsubscribe_link)
html = """<div class="email-pixel">
<!--email open check-->
</div>
<div class="email-unsubscribe">
html = """<div class="email-unsubscribe">
<!--cc message-->
<div>
{0}

View file

@ -11,8 +11,8 @@ app_color = "orange"
source_link = "https://github.com/frappe/frappe"
app_license = "MIT"
develop_version = '11.x.x-develop'
staging_version = '11.0.3-beta.19'
develop_version = '12.x.x-develop'
staging_version = '11.0.3-beta.29'
app_email = "info@frappe.io"

View file

@ -199,8 +199,7 @@ class DatabaseQuery(object):
'''
sub_query_regex = re.compile("^.*[,();].*")
blacklisted_keywords = ['select', 'create', 'insert', 'delete', 'drop', 'update', 'case',
'from', 'group', 'order', 'by']
blacklisted_keywords = ['select', 'create', 'insert', 'delete', 'drop', 'update', 'case']
blacklisted_functions = ['concat', 'concat_ws', 'if', 'ifnull', 'nullif', 'coalesce',
'connection_id', 'current_user', 'database', 'last_insert_id', 'session_user',
'system_user', 'user', 'version']
@ -694,6 +693,7 @@ def get_order_by(doctype, meta):
def get_list(doctype, *args, **kwargs):
'''wrapper for DatabaseQuery'''
kwargs.pop('cmd', None)
kwargs.pop('ignore_permissions', None)
return DatabaseQuery(doctype).execute(None, *args, **kwargs)
def is_parent_only_filter(doctype, filters):

View file

@ -365,7 +365,7 @@ class Meta(Document):
def set_custom_permissions(self):
'''Reset `permissions` with Custom DocPerm if exists'''
if frappe.flags.in_patch or frappe.flags.in_import or frappe.flags.in_install:
if frappe.flags.in_patch or frappe.flags.in_install:
return
if not self.istable and self.name not in ('DocType', 'DocField', 'DocPerm',

View file

@ -1,5 +1,6 @@
import frappe
def execute():
frappe.flags.in_patch = True
frappe.reload_doc('core', 'doctype', 'user_permission')
frappe.db.commit()
frappe.db.commit()

View file

@ -1,6 +1,7 @@
import frappe
from frappe.permissions import setup_custom_perms
from frappe.core.page.permission_manager.permission_manager import get_standard_permissions
from frappe.utils.reset_doc import setup_perms_for
'''
Copy DocPerm to Custom DocPerm where permissions are set differently
@ -9,30 +10,3 @@ Copy DocPerm to Custom DocPerm where permissions are set differently
def execute():
for d in frappe.db.get_all('DocType', dict(istable=0, issingle=0, custom=0)):
setup_perms_for(d.name)
def setup_perms_for(doctype):
perms = frappe.get_all('DocPerm', fields='*', filters=dict(parent=doctype), order_by='idx asc')
# get default perms
try:
standard_perms = get_standard_permissions(doctype)
except (IOError, KeyError):
# no json file, doctype no longer exists!
return
same = True
if len(standard_perms) != len(perms):
same = False
else:
for i, p in enumerate(perms):
standard = standard_perms[i]
for fieldname in frappe.get_meta('DocPerm').get_fieldnames_with_value():
if p.get(fieldname) != standard.get(fieldname):
same = False
break
if not same:
break
if not same:
setup_custom_perms(doctype)

View file

@ -5,6 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cint
from frappe.model.document import Document
@ -31,3 +32,11 @@ class PrintSettings(Document):
except ValidationError:
frappe.throw(_("Failed to connect to server"))
return printer_list
@frappe.whitelist()
def is_print_server_enabled():
if not hasattr(frappe.local, 'enable_print_server'):
frappe.local.enable_print_server = cint(frappe.db.get_single_value('Print Settings',
'enable_print_server'))
return frappe.local.enable_print_server

View file

@ -62,5 +62,9 @@ frappe.ui.form.ControlAttachImage = frappe.ui.form.ControlAttach.extend({
this.img_container.toggle(false);
this.remove_image_link.toggle(false);
}
},
set_upload_options() {
this._super();
this.upload_options.restrict_to_images = true;
}
});

View file

@ -85,6 +85,9 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
return val==null ? "" : val;
},
validate: function(v) {
if(this.df.is_filter) {
return v;
}
if(this.df.options == 'Phone') {
if(v+''=='') {
return '';

View file

@ -13,7 +13,7 @@ frappe.ui.form.ControlDynamicLink = frappe.ui.form.ControlLink.extend({
let input = null;
if (cur_list) {
// for list page
input = cur_list.wrapper.find(selector);
input = cur_list.filter_area.standard_filters_wrapper.find(selector);
}
if (cur_page) {
input = $(cur_page.page).find(selector);

View file

@ -16,6 +16,23 @@ Table.create = (value) => {
}
Quill.register(Table, true);
// hidden blot
class HiddenBlock extends Block {
static create(value) {
const node = super.create(value);
node.setAttribute('data-comment', value);
node.classList.add('hidden');
return node;
}
static formats(node) {
return node.getAttribute('data-comment');
}
}
HiddenBlock.blotName = 'hiddenblot';
HiddenBlock.tagName = 'DIV';
Quill.register(HiddenBlock, true);
// image uploader
const Uploader = Quill.import('modules/uploader');
Uploader.DEFAULTS.mimetypes.push('image/gif');
@ -154,7 +171,9 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({
return;
}
this.quill.root.innerHTML = value;
// set html without triggering a focus
const delta = this.quill.clipboard.convert({ html: value, text: '' });
this.quill.setContents(delta);
},
get_input_value() {

View file

@ -336,7 +336,7 @@ frappe.ui.form.Timeline = class Timeline {
});
} else {
if(c.communication_type=="Communication" && c.communication_medium=="Email") {
c.content = c.content.split("<!-- original-reply -->")[0];
c.content = c.content.split('<div data-comment="original-reply">')[0];
c.content = frappe.utils.strip_original_content(c.content);
c.original_content = c.content;

View file

@ -67,7 +67,7 @@
var indicator_class = "green";
} else if (data.delivery_status === "Sending") {
var indicator_class = "orange";
} else if (in_list("Opened", "Read", data.delivery_status)) {
} else if (in_list(["Opened", "Read"], data.delivery_status)) {
var indicator_class = "blue";
} else {
var indicator_class = "red";

View file

@ -158,35 +158,25 @@ frappe.ui.form.PrintPreview = Class.extend({
let print_server ;
var me = this;
frappe.call({
async: false,
"method": "frappe.client.get",
args: {
doctype: "Print Settings",
name: "enable_print_server"
},
method: "frappe.printing.doctype.print_settings.print_settings.is_print_server_enabled",
callback: function (data) {
print_server = data.message.enable_print_server;
if (data.message) {
frappe.call({
"method": "frappe.utils.print_format.print_by_server",
args: {
doctype: me.frm.doc.doctype,
name: me.frm.doc.name,
print_format: me.selected_format(),
no_letterhead: me.with_letterhead()
},
callback: function (data) {
}
});
} else {
me.new_page_preview(true);
}
}
});
if(print_server){
frappe.call({
async: false,
"method": "frappe.utils.print_format.print_by_server",
args: {
doctype: me.frm.doc.doctype,
name: me.frm.doc.name,
print_format: me.selected_format(),
no_letterhead: me.with_letterhead()
},
callback: function (data) {
}
});
}else{
this.new_page_preview(true);
}
},
new_page_preview: function (printit) {
var me = this;
@ -299,18 +289,14 @@ frappe.ui.get_print_settings = function (pdf, callback, letter_head) {
depends_on: "with_letter_head",
options: $.map(frappe.boot.letter_heads, function (i, d) { return d }),
default: letter_head || default_letter_head
}, {
fieldtype: "Select",
fieldname: "orientation",
label: __("Orientation"),
options: "Landscape\nPortrait",
default: "Landscape"
}];
if (pdf) {
columns.push({
fieldtype: "Select",
fieldname: "orientation",
label: __("Orientation"),
options: "Landscape\nPortrait",
default: "Landscape"
})
}
frappe.prompt(columns, function (data) {
var data = $.extend(print_settings, data);
if (!data.with_letter_head) {

View file

@ -6,7 +6,11 @@ frappe.views.BaseList = class BaseList {
}
show() {
this.init().then(() => this.refresh());
frappe.run_serially([
() => this.init(),
() => this.before_refresh(),
() => this.refresh()
]);
}
init() {
@ -344,6 +348,11 @@ frappe.views.BaseList = class BaseList {
};
}
before_refresh() {
// modify args here just before making the request
// see list_view.js
}
refresh() {
this.freeze(true);
// fetch data from server

View file

@ -34,7 +34,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
return;
}
this.init().then(() => this.refresh());
super.show();
}
get view_name() {
@ -48,36 +48,6 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
setup_defaults() {
super.setup_defaults();
if (frappe.route_options) {
// Priority 1: route filters
let filters = [];
for (let key in frappe.route_options) {
let value = frappe.route_options[key];
if (value.startsWith('[') && value.endsWith(']')) {
value = JSON.parse(value);
} else {
value = ['=', value];
}
filters.push([this.doctype, key, ...value])
}
this.filters = filters;
frappe.route_options = null;
} else if (this.view_user_settings.filters) {
// Priority 2: saved filters
const saved_filters = this.view_user_settings.filters;
this.filters = this.validate_filters(saved_filters);
} else {
// Priority 3: filters in listview_settings
const filters = (this.settings.filters || []).map(f => {
if (f.length === 3) {
f = [this.doctype, f[0], f[1], f[2]];
}
return f;
});
this.filters = filters;
}
// initialize with saved order by
this.sort_by = this.view_user_settings.sort_by || 'modified';
this.sort_order = this.view_user_settings.sort_order || 'desc';
@ -179,7 +149,11 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
set_primary_action() {
if (this.can_create) {
this.page.set_primary_action(__('New'), () => {
this.make_new_doc();
if (this.settings.primary_action) {
this.settings.primary_action();
} else {
this.make_new_doc();
}
}, 'octicon octicon-plus');
} else {
this.page.clear_primary_action();
@ -290,6 +264,32 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
});
}
before_refresh() {
if (frappe.route_options) {
// Priority 1: route filters
this.filters = this.parse_filters_from_route_options();
} else if (this.view_user_settings.filters) {
// Priority 2: saved filters
const saved_filters = this.view_user_settings.filters;
this.filters = this.validate_filters(saved_filters);
} else {
// Priority 3: filters in listview_settings
this.filters = (this.settings.filters || []).map(f => {
if (f.length === 3) {
f = [this.doctype, f[0], f[1], f[2]];
}
return f;
});
}
if (this.filters.length) {
return this.filter_area.clear(false)
.then(() => this.filter_area.set(this.filters));
}
return Promise.resolve();
}
toggle_result_area() {
super.toggle_result_area();
this.toggle_actions_menu_button(
@ -1126,11 +1126,17 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
return actions_menu_items;
}
set_filters_from_route_options() {
parse_filters_from_route_options() {
const filters = [];
for (let field in frappe.route_options) {
var value = frappe.route_options[field];
var doctype = null;
let doctype = null;
let value = frappe.route_options[field];
if (typeof value === 'string' && value.startsWith('[') && value.endsWith(']')) {
value = JSON.parse(value);
}
// if `Child DocType.fieldname`
if (field.includes('.')) {
@ -1157,10 +1163,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
}
frappe.route_options = null;
this.filter_area.clear(false)
.then(() => {
this.filter_area.add(filters);
});
return filters;
}
static trigger_list_update(data) {

View file

@ -97,8 +97,8 @@ frappe.slickgrid_tools = {
var res = [];
var col_map = $.map(columns, function(v) { return v.field; });
for (var i=0, len=dataView.getLength(); i<len; i++) {
var d = dataView.getItem(i);
for (var i=0, len=dataView.length; i<len; i++) {
var d = dataView[i];
var row = [];
$.each(col_map, function(i, col) {
var val = d[col];

View file

@ -48,7 +48,8 @@ frappe.route = function() {
frappe.view_factory[route[0]].show();
} else {
// show page
frappe.views.pageview.show(route[0]);
const route_name = frappe.utils.xss_sanitise(route[0]);
frappe.views.pageview.show(route_name);
}

View file

@ -118,7 +118,7 @@ frappe.ui.FieldSelect = Class.extend({
// child tables
$.each(me.table_fields, function(i, table_df) {
if(table_df.options && !table_df.hidden) {
if(table_df.options) {
var child_table_fields = [].concat(frappe.meta.docfield_list[table_df.options]);
$.each(frappe.utils.sort(child_table_fields, "label", "string"), function(i, df) {
// show fields where user has read access and if report hide flag is not set
@ -145,7 +145,7 @@ frappe.ui.FieldSelect = Class.extend({
}
if(frappe.model.no_value_type.indexOf(df.fieldtype) == -1 &&
!(me.fields_by_name[df.parent] && me.fields_by_name[df.parent][df.fieldname]) && !df.hidden) {
!(me.fields_by_name[df.parent] && me.fields_by_name[df.parent][df.fieldname])) {
this.options.push({
label: label,
value: table + "." + df.fieldname,

View file

@ -162,7 +162,9 @@ frappe.ui.Filter = class {
let df = copy_dict(original_docfield);
// filter field shouldn't be read only or hidden
df.read_only = 0; df.hidden = 0;
df.read_only = 0;
df.hidden = 0;
df.is_filter = true;
let c = condition ? condition : this.utils.get_default_condition(df);
this.set_condition(c);

View file

@ -642,7 +642,7 @@ frappe.ui.FieldSelect = Class.extend({
// child tables
$.each(me.table_fields, function(i, table_df) {
if(table_df.options && !table_df.hidden) {
if(table_df.options) {
var child_table_fields = [].concat(frappe.meta.docfield_list[table_df.options]);
$.each(frappe.utils.sort(child_table_fields, "label", "string"), function(i, df) {
// show fields where user has read access and if report hide flag is not set
@ -664,7 +664,7 @@ frappe.ui.FieldSelect = Class.extend({
var table = df.parent;
}
if(frappe.model.no_value_type.indexOf(df.fieldtype) == -1 &&
!(me.fields_by_name[df.parent] && me.fields_by_name[df.parent][df.fieldname]) && !df.hidden) {
!(me.fields_by_name[df.parent] && me.fields_by_name[df.parent][df.fieldname])) {
this.options.push({
label: label,
value: table + "." + df.fieldname,

View file

@ -36,7 +36,8 @@ frappe.ui.Tags = class {
bind() {
this.$input.keypress((e) => {
if(e.which == 13 || e.keyCode == 13) {
this.addTag(this.$input.val());
const tagValue = frappe.utils.xss_sanitise(this.$input.val());
this.addTag(tagValue);
this.$input.val('');
}
});

View file

@ -41,6 +41,11 @@ frappe.upload = {
$upload.find(".btn-browse").on("click",
function() { $file_input.click(); });
// restrict to images
if (opts.restrict_to_images) {
$file_input.prop('accept', 'image/*');
}
// dropzone upload
const $dropzone = $('<div style="padding: 20px 10px 0px 10px;"/>');
new frappe.ui.DropZone($dropzone, {
@ -179,11 +184,12 @@ frappe.upload = {
});
},
make_file_row: function(file, { show_private } = {}) {
const safe_file_name = frappe.utils.xss_sanitise(file.name);
var template = `
<div class="list-item-container" data-filename="${file.name}">
<div class="list-item-container" data-filename="${safe_file_name}">
<div class="list-item">
<div class="list-item__content list-item__content--flex-2 ellipsis">
<span>${file.name}</span>
<span>${safe_file_name}</span>
<span style="margin-top: 1px; margin-left: 5px;"
class="fa fa-fw text-warning ${file.is_private ? 'fa-lock': 'fa-unlock-alt'}">
</span>

View file

@ -509,7 +509,12 @@ frappe.views.CommunicationComposer = Class.extend({
delete_saved_draft() {
if (this.dialog) {
localStorage.removeItem(this.frm.doctype + this.frm.docname);
try {
localStorage.removeItem(this.frm.doctype + this.frm.docname);
} catch (e) {
console.log(e);
console.warn('[Communication] Cannot delete localStorage item'); // eslint-disable-line
}
}
},
@ -574,16 +579,6 @@ frappe.views.CommunicationComposer = Class.extend({
cur_frm.reload_doc();
}
if (localStorage.getItem(this.frm.doctype + this.frm.docname)) {
try {
localStorage.removeItem(this.frm.doctype + this.frm.docname);
} catch (e) {
// silently fail
console.log(e);
console.warn('[Communication] Failed to delete draft.');
}
}
// try the success callback if it exists
if (me.success) {
try {
@ -635,7 +630,10 @@ frappe.views.CommunicationComposer = Class.extend({
this.message = this.txt + (this.message ? ("<br><br>" + this.message) : "");
} else {
// saved draft in localStorage
this.message = localStorage.getItem(this.frm.doctype + this.frm.docname) || '';
const { doctype, docname } = this.frm || {};
if (doctype && docname) {
this.message = localStorage.getItem(doctype + docname) || '';
}
}
if(this.real_name) {
@ -657,7 +655,7 @@ frappe.views.CommunicationComposer = Class.extend({
var communication_date = last_email.communication_date || last_email.creation;
content = '<div><br></div>'
+ reply
+ "<br><!-- original-reply --><br>"
+ "<div data-comment='original-reply'></div>"
+ '<blockquote>' +
'<p>' + __("On {0}, {1} wrote:",
[frappe.datetime.global_date_format(communication_date) , last_email.sender]) + '</p>' +
@ -668,4 +666,4 @@ frappe.views.CommunicationComposer = Class.extend({
}
fields.content.set_value(content);
}
});
});

View file

@ -830,7 +830,7 @@ frappe.views.TreeGridReport = frappe.views.GridReportWithPlot.extend({
var with_groups = $(msgbox.body).find("[name='with_groups']").prop("checked");
var with_ledgers = $(msgbox.body).find("[name='with_ledgers']").prop("checked");
var data = frappe.slickgrid_tools.get_view_data(me.columns, me.dataView,
var data = frappe.slickgrid_tools.get_view_data(me.columns, me.data,
function(row, item) {
if(with_groups) {
// add row

View file

@ -258,7 +258,8 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
report_name: this.report_name,
filters: filters,
},
callback: resolve
callback: resolve,
always: () => this.page.btn_secondary.prop('disabled', false)
})
}).then(r => {
let data = r.message;
@ -664,12 +665,14 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
print_report(print_settings) {
const custom_format = this.report_settings.html_format || null;
const filters_html = this.get_filters_html_for_print();
const landscape = print_settings.orientation == 'Landscape';
frappe.render_grid({
template: custom_format,
title: __(this.report_name),
subtitle: filters_html,
print_settings: print_settings,
landscape: landscape,
filters: this.get_filter_values(),
data: custom_format ? this.data : this.get_data_for_print(),
columns: custom_format ? this.columns : this.get_columns_for_print(),
@ -729,17 +732,29 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
return;
}
this.export_dialog = frappe.prompt({
label: __('Select File Format'),
fieldname: 'file_format',
fieldtype: 'Select',
options: ['Excel', 'CSV'],
default: 'Excel',
reqd: 1
}, ({ file_format }) => {
this.export_dialog = frappe.prompt([
{
label: __('Select File Format'),
fieldname: 'file_format',
fieldtype: 'Select',
options: ['Excel', 'CSV'],
default: 'Excel',
reqd: 1,
onchange: () => {
this.export_dialog.set_df_property('with_indentation',
'hidden', this.export_dialog.get_value('file_format') !== 'CSV');
}
},
{
label: __('With Group Indentation'),
fieldname: 'with_indentation',
fieldtype: 'Check',
hidden: 1
}
], ({ file_format, with_indentation }) => {
if (file_format === 'CSV') {
const column_row = this.columns.map(col => col.label);
const data = this.get_data_for_csv();
const data = this.get_data_for_csv(with_indentation);
const out = [column_row].concat(data);
frappe.tools.downloadify(out, null, this.report_name);
@ -762,10 +777,21 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
}, __('Export Report: '+ this.report_name), __('Download'));
}
get_data_for_csv() {
get_data_for_csv(with_indentation = false) {
const indices = this.datatable.datamanager.getFilteredRowIndices();
const out = indices.map(i => this.datatable.datamanager.getRow(i).map(c => c.content));
return out.map(row => row.slice(1));
const rows = indices.map(i => this.datatable.datamanager.getRow(i));
return rows.map(row => {
const standard_column_count = this.datatable.datamanager.getStandardColumnCount();
return row
.slice(standard_column_count)
.map((cell, i) => {
if (with_indentation && i === 0) {
return ' '.repeat(row.meta.indent) + cell.content;
}
return cell.content;
});
});
}
get_data_for_print() {

View file

@ -496,29 +496,25 @@ _f.Frm.prototype.render_form = function(is_a_different_doc) {
// clear layout message
this.layout.show_message();
// header must be refreshed before client methods
// because add_custom_button
this.refresh_header(is_a_different_doc);
// call trigger
this.script_manager.trigger("refresh");
// trigger global trigger
// to use this
$(document).trigger('form-refresh', [this]);
// fields
this.refresh_fields();
// call onload post render for callbacks to be fired
if(this.cscript.is_onload) {
this.script_manager.trigger("onload_post_render");
}
// update dashboard after refresh
frappe.timeout(0.1).then(() => this.dashboard.after_refresh());
frappe.run_serially([
// header must be refreshed before client methods
// because add_custom_button
() => this.refresh_header(is_a_different_doc),
// call trigger
() => this.script_manager.trigger("refresh"),
// trigger global trigger
// to use this
() => $(document).trigger('form-refresh', [this]),
// fields
() => this.refresh_fields(),
// call onload post render for callbacks to be fired
() => {
if(this.cscript.is_onload) {
return this.script_manager.trigger("onload_post_render");
}
},
() => this.dashboard.after_refresh()
]);
// focus on first input
if(this.is_new()) {

View file

@ -96,10 +96,12 @@ frappe.render_grid = function(opts) {
}
// show landscape view if columns more than 10
if (opts.columns && opts.columns.length > 10) {
opts.landscape = true;
} else {
opts.landscape = false;
if (opts.landscape == null) {
if(opts.columns && opts.columns.length > 10) {
opts.landscape = true;
} else {
opts.landscape = false;
}
}
// render content

View file

@ -17,6 +17,10 @@
<!--unsubscribe link here-->
<div class="email-pixel">
<!--email open check-->
</div>
<!-- default_mail_footer -->
{% if default_mail_footer %}
<div class="default-mail-footer">
@ -26,4 +30,4 @@
</div>
{% endif %}
</div>
</div>

View file

@ -20,6 +20,7 @@ function setup_list_filters() {
fieldtype: df.fieldtype,
label: df.label,
options: df.options,
is_filter: true,
change: (e) => {
const query_params = Object.assign(frappe.utils.get_query_params(), {
[df.fieldname]: f.get_value()

View file

@ -158,7 +158,9 @@ acceptable_attributes = [
'step', 'style', 'summary', 'suppress', 'tabindex', 'target',
'template', 'title', 'toppadding', 'type', 'unselectable', 'usemap',
'urn', 'valign', 'value', 'variable', 'volume', 'vspace', 'vrml',
'width', 'wrap', 'xml:lang'
'width', 'wrap', 'xml:lang', 'data-row', 'data-list', 'data-language',
'data-value', 'role', 'frameborder', 'allowfullscreen', 'spellcheck',
'data-mode', 'data-gramm', 'data-placeholder', 'data-comment'
]
mathml_attributes = [

View file

@ -1,5 +1,5 @@
import frappe
import json, urllib2, os
import json, os
from frappe.modules import scrub, get_module_path, load_doctype_module, utils
from frappe.custom.doctype.customize_form.customize_form import doctype_properties, docfield_properties
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
@ -7,6 +7,7 @@ from frappe.custom.doctype.custom_field.custom_field import create_custom_field
from frappe.modules.import_file import get_file_path, read_doc_from_file
from frappe.core.page.permission_manager.permission_manager import get_standard_permissions
from frappe.permissions import setup_custom_perms
from six.moves.urllib.request import urlopen
branch = 'develop'
@ -28,7 +29,7 @@ def reset_doc(doctype):
try:
git_link = '/'.join(['https://raw.githubusercontent.com/frappe',\
app, branch, doc_path.split('apps/'+app)[1]])
original_file = urllib2.urlopen(git_link).read()
original_file = urlopen(git_link).read()
except:
print('Did not find {0} in {1}'.format(doctype, app))
return

View file

@ -81,7 +81,7 @@ def read_xlsx_file_from_attached_file(file_id=None, fcontent=None, filepath=None
return
rows = []
wb1 = load_workbook(filename=filename, read_only=True)
wb1 = load_workbook(filename=filename, read_only=True, data_only=True)
ws1 = wb1.active
for row in ws1.iter_rows():
tmp_list = []

View file

@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@ -61,7 +62,7 @@
"label": "Fieldtype",
"length": 0,
"no_copy": 0,
"options": "Attach\nCheck\nData\nDate\nDatetime\nFloat\nHTML\nInt\nLink\nSelect\nSmall Text\nText\nText Editor\nTable\nSection Break\nColumn Break\nPage Break",
"options": "Attach\nAttach Image\nCheck\nData\nDate\nDatetime\nFloat\nHTML\nInt\nLink\nSelect\nSmall Text\nText\nText Editor\nTable\nSection Break\nColumn Break\nPage Break",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@ -554,7 +555,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-09-20 10:01:13.346598",
"modified": "2018-11-01 19:35:17.742547",
"modified_by": "Administrator",
"module": "Website",
"name": "Web Form Field",
@ -568,5 +569,6 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
"track_seen": 0,
"track_views": 0
}

View file

@ -421,7 +421,9 @@ frappe.ready(function() {
callback: (r) => {
if (r.message) {
frappe.require('/assets/js/moment-bundle.min.js', () => {
frappe.require('/assets/js/chat.js');
frappe.require('/assets/js/chat.js', () => {
frappe.chat.setup();
});
});
}
}

View file

@ -19,7 +19,7 @@
"awesomplete": "^1.1.2",
"cookie": "^0.3.1",
"express": "^4.16.2",
"frappe-datatable": "^1.5.0",
"frappe-datatable": "^1.5.3",
"frappe-gantt": "^0.1.0",
"fuse.js": "^3.2.0",
"highlight.js": "^9.12.0",

View file

@ -13,7 +13,7 @@ werkzeug
semantic_version
rauth>=0.6.2
requests
redis
redis==2.10.6
selenium
babel
ipython

View file

@ -63,7 +63,13 @@ function build_assets(app) {
function build(inputOptions, outputOptions) {
return rollup.rollup(inputOptions)
.then(bundle => bundle.write(outputOptions))
.catch(err => log(chalk.red(err)));
.catch(err => {
log(chalk.red(err));
// Kill process to fail in a CI environment
if (process.env.CI) {
process.kill(process.pid)
}
});
}
function concatenate_files() {

View file

@ -1219,10 +1219,10 @@ forwarded@~0.1.2:
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
frappe-datatable@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/frappe-datatable/-/frappe-datatable-1.5.0.tgz#eea78a87e799876b71e58dbdc128fd9badb5e2c6"
integrity sha512-h9yP33UqRcEfcs5FVSFFUigya/KT5qFrB1vOqayhxqPoxdVH2pGKi+Qh/BO5KRNd6uVk8rVwXMhA8A9TU+2uEg==
frappe-datatable@^1.5.3:
version "1.5.3"
resolved "https://registry.yarnpkg.com/frappe-datatable/-/frappe-datatable-1.5.3.tgz#f60e619a92b77b60cdbb8376e521398a2933995a"
integrity sha512-1sEcnOUxN+vI5BgrPJPNJNc72kAX4RQRNBJjR2RWVotczIE+YJZ4e8M1k6d4xXFWOj687qD9wha7uveSKy2jkQ==
dependencies:
hyperlist "^1.0.0-beta"
lodash "^4.17.5"