Merge branch 'develop' into restore-fix
This commit is contained in:
commit
7aaf15a804
55 changed files with 669 additions and 255 deletions
22
.travis.yml
22
.travis.yml
|
|
@ -25,6 +25,7 @@ cache:
|
|||
# https://docs.cypress.io/guides/guides/continuous-integration.html#Caching
|
||||
- ~/.cache
|
||||
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- name: "Python 3.7 MariaDB"
|
||||
|
|
@ -46,7 +47,26 @@ matrix:
|
|||
script: bench --site test_site run-ui-tests frappe --headless
|
||||
|
||||
before_install:
|
||||
# install wkhtmltopdf
|
||||
# do we really want to run travis?
|
||||
- |
|
||||
ONLY_DOCS_CHANGES=$(git diff --name-only $TRAVIS_COMMIT_RANGE | grep -qvE '\.(md|png|jpg|jpeg)$|^.github|LICENSE' ; echo $?)
|
||||
ONLY_JS_CHANGES=$(git diff --name-only $TRAVIS_COMMIT_RANGE | grep -qvE '\.js$' ; echo $?)
|
||||
ONLY_PY_CHANGES=$(git diff --name-only $TRAVIS_COMMIT_RANGE | grep -qvE '\.py$' ; echo $?)
|
||||
|
||||
if [[ $ONLY_DOCS_CHANGES == "1" ]]; then
|
||||
echo "Only docs were updated, stopping build process.";
|
||||
exit;
|
||||
fi
|
||||
if [[ $ONLY_JS_CHANGES == "1" && $TYPE == "server" ]]; then
|
||||
echo "Only JavaScript code was updated; Stopping Python build process.";
|
||||
exit;
|
||||
fi
|
||||
if [[ $ONLY_PY_CHANGES == "1" && $TYPE == "ui" ]]; then
|
||||
echo "Only Python code was updated, stopping Cypress build process.";
|
||||
exit;
|
||||
fi
|
||||
|
||||
# install wkhtmltopdf
|
||||
- wget -O /tmp/wkhtmltox.tar.xz https://github.com/frappe/wkhtmltopdf/raw/master/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
|
||||
- tar -xf /tmp/wkhtmltox.tar.xz -C /tmp
|
||||
- sudo mv /tmp/wkhtmltox/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf
|
||||
|
|
|
|||
|
|
@ -1559,10 +1559,10 @@ def get_doctype_app(doctype):
|
|||
|
||||
loggers = {}
|
||||
log_level = None
|
||||
def logger(module=None, with_more_info=True):
|
||||
def logger(module=None, with_more_info=False):
|
||||
'''Returns a python logger that uses StreamHandler'''
|
||||
from frappe.utils.logger import get_logger
|
||||
return get_logger(module or 'default', with_more_info=with_more_info)
|
||||
return get_logger(module=module, with_more_info=with_more_info)
|
||||
|
||||
def log_error(message=None, title=_("Error")):
|
||||
'''Log error to Error Log'''
|
||||
|
|
|
|||
|
|
@ -99,6 +99,16 @@ def application(request):
|
|||
frappe.monitor.stop(response)
|
||||
frappe.recorder.dump()
|
||||
|
||||
frappe.logger("web").info({
|
||||
"site": get_site_name(request.host),
|
||||
"remote_addr": getattr(request, "remote_addr", "NOTFOUND"),
|
||||
"base_url": getattr(request, "base_url", "NOTFOUND"),
|
||||
"full_path": getattr(request, "full_path", "NOTFOUND"),
|
||||
"method": getattr(request, "method", "NOTFOUND"),
|
||||
"scheme": getattr(request, "scheme", "NOTFOUND"),
|
||||
"http_status_code": getattr(response, "status_code", "NOTFOUND")
|
||||
})
|
||||
|
||||
if response and hasattr(frappe.local, 'rate_limiter'):
|
||||
response.headers.extend(frappe.local.rate_limiter.headers())
|
||||
|
||||
|
|
@ -195,7 +205,6 @@ def handle_exception(e):
|
|||
frappe.local.login_manager.clear_cookies()
|
||||
|
||||
if http_status_code >= 500:
|
||||
frappe.logger().error('Request Error', exc_info=True)
|
||||
make_error_snapshot(e)
|
||||
|
||||
if return_as_message:
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ from frappe.email.inbox import get_email_accounts
|
|||
from frappe.social.doctype.energy_point_settings.energy_point_settings import is_energy_point_enabled
|
||||
from frappe.website.doctype.web_page_view.web_page_view import is_tracking_enabled
|
||||
from frappe.social.doctype.energy_point_log.energy_point_log import get_energy_points
|
||||
from frappe.model.base_document import get_controller
|
||||
from frappe.social.doctype.post.post import frequently_visited_links
|
||||
|
||||
def get_bootinfo():
|
||||
|
|
@ -106,6 +107,7 @@ def load_desktop_data(bootinfo):
|
|||
from frappe.desk.desktop import get_desk_sidebar_items
|
||||
bootinfo.allowed_modules = get_modules_from_all_apps_for_user()
|
||||
bootinfo.allowed_workspaces = get_desk_sidebar_items(True)
|
||||
bootinfo.module_page_map = get_controller("Desk Page").get_module_page_map()
|
||||
bootinfo.dashboards = frappe.get_all("Dashboard")
|
||||
|
||||
def get_allowed_pages(cache=False):
|
||||
|
|
|
|||
|
|
@ -447,7 +447,7 @@ def _drop_site(site, root_login='root', root_password=None, archived_sites_path=
|
|||
else:
|
||||
click.echo("="*80)
|
||||
click.echo("Error: The operation has stopped because backup of {s}'s database failed.".format(s=site))
|
||||
click.echo("Reason: {reason}{sep}".format(reason=err[1], sep="\n"))
|
||||
click.echo("Reason: {reason}{sep}".format(reason=str(err), sep="\n"))
|
||||
click.echo("Fix the issue and try again.")
|
||||
click.echo(
|
||||
"Hint: Use 'bench drop-site {s} --force' to force the removal of {s}".format(sep="\n", tab="\t", s=site)
|
||||
|
|
|
|||
|
|
@ -158,11 +158,7 @@ class TestAccessLog(unittest.TestCase):
|
|||
request = requests.post(private_file_link, headers=self.header)
|
||||
last_doc = frappe.get_last_doc('Access Log')
|
||||
|
||||
if request.status_code == 403:
|
||||
# if file is not accessible, access log wont be generated
|
||||
pass
|
||||
|
||||
else:
|
||||
if request.ok:
|
||||
# check for the access log of downloaded file
|
||||
self.assertEqual(new_private_file.doctype, last_doc.export_from)
|
||||
self.assertEqual(new_private_file.name, last_doc.reference_document)
|
||||
|
|
|
|||
|
|
@ -259,7 +259,12 @@ class Communication(Document):
|
|||
|
||||
# Timeline Links
|
||||
def set_timeline_links(self):
|
||||
contacts = get_contacts([self.sender, self.recipients, self.cc, self.bcc])
|
||||
contacts = []
|
||||
if (self.email_account and frappe.db.get_value("Email Account", self.email_account, "create_contact")) or \
|
||||
frappe.flags.in_test:
|
||||
|
||||
contacts = get_contacts([self.sender, self.recipients, self.cc, self.bcc])
|
||||
|
||||
for contact_name in contacts:
|
||||
self.add_link('Contact', contact_name)
|
||||
|
||||
|
|
|
|||
|
|
@ -202,6 +202,8 @@ class TestCommunication(unittest.TestCase):
|
|||
self.assertIn(("Note", note.name), doc_links)
|
||||
|
||||
def create_email_account():
|
||||
frappe.delete_doc_if_exists("Email Account", "_Test Comm Account 1")
|
||||
|
||||
frappe.flags.mute_emails = False
|
||||
frappe.flags.sent_mail = None
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ class ScheduledJobType(Document):
|
|||
|
||||
def log_status(self, status):
|
||||
# log file
|
||||
frappe.logger(__name__).info('Scheduled Job {0}: {1} for {2}'.format(status, self.method, frappe.local.site))
|
||||
frappe.logger("scheduler").info('Scheduled Job {0}: {1} for {2}'.format(status, self.method, frappe.local.site))
|
||||
self.update_scheduler_log(status)
|
||||
|
||||
def update_scheduler_log(self, status):
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ class CustomField(Document):
|
|||
if not self.fieldname:
|
||||
frappe.throw(_("Fieldname not set for Custom Field"))
|
||||
|
||||
if self.fieldname in fieldnames:
|
||||
frappe.throw(_("A field with the name '{}' already exists in doctype {}.").format(self.fieldname, self.dt))
|
||||
|
||||
if self.get('translatable', 0) and not supports_translation(self.fieldtype):
|
||||
self.translatable = 0
|
||||
|
||||
|
|
|
|||
|
|
@ -251,6 +251,7 @@ frappe.ui.form.on('Dashboard Chart', {
|
|||
render_filters_table: function(frm) {
|
||||
frm.set_df_property("filters_section", "hidden", 0);
|
||||
let is_document_type = frm.doc.chart_type!== 'Report' && frm.doc.chart_type!=='Custom';
|
||||
let is_dynamic_filter = f => ['Date', 'DateRange'].includes(f.fieldtype) && f.default;
|
||||
|
||||
let wrapper = $(frm.get_field('filters_json').wrapper).empty();
|
||||
let table = $(`<table class="table table-bordered" style="cursor:pointer; margin:0px;">
|
||||
|
|
@ -268,6 +269,18 @@ frappe.ui.form.on('Dashboard Chart', {
|
|||
let filters = JSON.parse(frm.doc.filters_json || '[]');
|
||||
var filters_set = false;
|
||||
|
||||
// Set dynamic filters for reports
|
||||
if (frm.doc.chart_type == 'Report') {
|
||||
let set_filters = false;
|
||||
frm.chart_filters.forEach(f => {
|
||||
if (is_dynamic_filter(f)) {
|
||||
filters[f.fieldname] = f.default;
|
||||
set_filters = true;
|
||||
}
|
||||
});
|
||||
set_filters && frm.set_value('filters_json', JSON.stringify(filters));
|
||||
}
|
||||
|
||||
let fields;
|
||||
if (is_document_type) {
|
||||
fields = [
|
||||
|
|
@ -292,6 +305,7 @@ frappe.ui.form.on('Dashboard Chart', {
|
|||
}
|
||||
} else if (frm.chart_filters.length) {
|
||||
fields = frm.chart_filters.filter(f => f.fieldname);
|
||||
|
||||
fields.map( f => {
|
||||
if (filters[f.fieldname]) {
|
||||
let condition = '=';
|
||||
|
|
@ -318,7 +332,7 @@ frappe.ui.form.on('Dashboard Chart', {
|
|||
|
||||
let dialog = new frappe.ui.Dialog({
|
||||
title: __('Set Filters'),
|
||||
fields: fields,
|
||||
fields: fields.filter(f => !is_dynamic_filter(f)),
|
||||
primary_action: function() {
|
||||
let values = this.get_values();
|
||||
if (values) {
|
||||
|
|
@ -351,10 +365,15 @@ frappe.ui.form.on('Dashboard Chart', {
|
|||
}
|
||||
|
||||
dialog.show();
|
||||
//Set query report object so that it can be used while fetching filter values in the report
|
||||
frappe.query_report = new frappe.views.QueryReport({'filters': dialog.fields_list});
|
||||
frappe.query_reports[frm.doc.report_name].onload
|
||||
&& frappe.query_reports[frm.doc.report_name].onload(frappe.query_report);
|
||||
|
||||
if (frm.doc.chart_type == 'Report') {
|
||||
//Set query report object so that it can be used while fetching filter values in the report
|
||||
frappe.query_report = new frappe.views.QueryReport({'filters': dialog.fields_list});
|
||||
frappe.query_reports[frm.doc.report_name]
|
||||
&& frappe.query_reports[frm.doc.report_name].onload
|
||||
&& frappe.query_reports[frm.doc.report_name].onload(frappe.query_report);
|
||||
}
|
||||
|
||||
dialog.set_values(filters);
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -20,6 +20,17 @@ class DeskPage(Document):
|
|||
if frappe.conf.developer_mode and self.is_standard:
|
||||
export_to_files(record_list=[['Desk Page', self.name]], record_module=self.module)
|
||||
|
||||
@staticmethod
|
||||
def get_module_page_map():
|
||||
filters = {
|
||||
'extends_another_page': 0,
|
||||
'for_user': '',
|
||||
}
|
||||
|
||||
pages = frappe.get_all("Desk Page", fields=["name", "module"], filters=filters, as_list=1)
|
||||
|
||||
return { page[1]: page[0] for page in pages }
|
||||
|
||||
def disable_saving_as_standard():
|
||||
return frappe.flags.in_install or \
|
||||
frappe.flags.in_patch or \
|
||||
|
|
|
|||
|
|
@ -3,10 +3,43 @@
|
|||
|
||||
frappe.ui.form.on('Notification Log', {
|
||||
refresh: function(frm) {
|
||||
let dt = frm.doc.document_type;
|
||||
let dn = frm.doc.document_name;
|
||||
frm.fields_dict.document_name.$input_wrapper
|
||||
.find('.control-value')
|
||||
.wrapInner(`<a href='#Form/${dt}/${dn}'></a>`);
|
||||
if (frm.doc.attached_file) {
|
||||
frm.trigger('set_attachment');
|
||||
} else {
|
||||
frm.get_field('attachment_link').$wrapper.empty();
|
||||
}
|
||||
},
|
||||
|
||||
open_reference_document: function(frm) {
|
||||
const dt = frm.doc.document_type;
|
||||
const dn = frm.doc.document_name;
|
||||
frappe.set_route('Form', dt, dn);
|
||||
},
|
||||
|
||||
set_attachment: function(frm) {
|
||||
const attachment = JSON.parse(frm.doc.attached_file);
|
||||
|
||||
const $wrapper = frm.get_field('attachment_link').$wrapper;
|
||||
$wrapper.html(`
|
||||
<div class="attached-file text-medium">
|
||||
<div class="ellipsis">
|
||||
<i class="fa fa-paperclip"></i>
|
||||
<a class="attached-file-link">${attachment.name}.pdf</a>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
$wrapper.find(".attached-file-link").click(() => {
|
||||
const w = window.open(
|
||||
frappe.urllib.get_full_url(`/api/method/frappe.utils.print_format.download_pdf?
|
||||
doctype=${encodeURIComponent(attachment.doctype)}
|
||||
&name=${encodeURIComponent(attachment.name)}
|
||||
&format=${encodeURIComponent(attachment.print_format)}
|
||||
&lang=${encodeURIComponent(attachment.lang)}`)
|
||||
);
|
||||
if (!w) {
|
||||
frappe.msgprint(__("Please enable pop-ups"));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"actions": [],
|
||||
"creation": "2019-08-26 13:37:34.165254",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
|
|
@ -8,10 +9,12 @@
|
|||
"for_user",
|
||||
"type",
|
||||
"email_content",
|
||||
"column_break_4",
|
||||
"document_type",
|
||||
"read",
|
||||
"document_name",
|
||||
"attached_file",
|
||||
"attachment_link",
|
||||
"open_reference_document",
|
||||
"from_user"
|
||||
],
|
||||
"fields": [
|
||||
|
|
@ -20,57 +23,65 @@
|
|||
"fieldtype": "Text",
|
||||
"in_list_view": 1,
|
||||
"label": "Subject",
|
||||
"read_only": 1
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "for_user",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"label": "For User",
|
||||
"options": "User",
|
||||
"read_only": 1
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "type",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 1,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Type",
|
||||
"options": "Mention\nEnergy Point\nAssignment\nShare",
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
"options": "Mention\nEnergy Point\nAssignment\nShare\nAlert",
|
||||
"search_index": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "email_content",
|
||||
"fieldtype": "Text",
|
||||
"label": "Email Content",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
"fieldtype": "Text Editor",
|
||||
"label": "Message",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "document_type",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"label": "Document Type",
|
||||
"options": "DocType",
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
"search_index": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "document_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Document Name",
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
"hidden": 1,
|
||||
"label": "Document Link",
|
||||
"search_index": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "from_user",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"label": "From User",
|
||||
"options": "User",
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
"search_index": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
|
|
@ -78,26 +89,51 @@
|
|||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Read"
|
||||
"label": "Read",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "open_reference_document",
|
||||
"fieldtype": "Button",
|
||||
"label": "Open Reference Document",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "attached_file",
|
||||
"fieldtype": "Code",
|
||||
"hidden": 1,
|
||||
"label": "Attached File",
|
||||
"options": "JSON",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "attachment_link",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Attachment Link",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
}
|
||||
],
|
||||
"hide_toolbar": 1,
|
||||
"in_create": 1,
|
||||
"modified": "2019-11-12 15:22:35.283678",
|
||||
"links": [],
|
||||
"modified": "2020-05-31 22:31:12.886950",
|
||||
"modified_by": "umair@erpnext.com",
|
||||
"module": "Desk",
|
||||
"name": "Notification Log",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "All",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
"share": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ def enqueue_create_notification(users, doc):
|
|||
|
||||
if isinstance(users, frappe.string_types):
|
||||
users = [user.strip() for user in users.split(',') if user.strip()]
|
||||
users = list(set(users))
|
||||
|
||||
frappe.enqueue(
|
||||
'frappe.desk.doctype.notification_log.notification_log.make_notification_logs',
|
||||
|
|
@ -58,6 +59,7 @@ def enqueue_create_notification(users, doc):
|
|||
|
||||
def make_notification_logs(doc, users):
|
||||
from frappe.social.doctype.energy_point_settings.energy_point_settings import is_energy_point_enabled
|
||||
|
||||
for user in users:
|
||||
if frappe.db.exists('User', user):
|
||||
if is_notifications_enabled(user):
|
||||
|
|
@ -68,7 +70,7 @@ def make_notification_logs(doc, users):
|
|||
_doc.update(doc)
|
||||
_doc.for_user = user
|
||||
_doc.subject = _doc.subject.replace('<div>', '').replace('</div>', '')
|
||||
if _doc.for_user != _doc.from_user or doc.type == 'Energy Point':
|
||||
if _doc.for_user != _doc.from_user or doc.type == 'Energy Point' or doc.type == 'Alert':
|
||||
_doc.insert(ignore_permissions=True)
|
||||
|
||||
def send_notification_email(doc):
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"actions": [],
|
||||
"autoname": "Prompt",
|
||||
"creation": "2019-09-11 22:15:44.851526",
|
||||
"doctype": "DocType",
|
||||
|
|
@ -21,52 +22,68 @@
|
|||
"default": "1",
|
||||
"fieldname": "enabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enabled"
|
||||
"label": "Enabled",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "subscribed_documents",
|
||||
"fieldtype": "Table MultiSelect",
|
||||
"label": "Subscribed Documents",
|
||||
"options": "Notification Subscribed Document"
|
||||
"options": "Notification Subscribed Document",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Email Settings"
|
||||
"label": "Email Settings",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "enable_email_notifications",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enable Email Notifications"
|
||||
"label": "Enable Email Notifications",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"depends_on": "enable_email_notifications",
|
||||
"fieldname": "enable_email_mention",
|
||||
"fieldtype": "Check",
|
||||
"label": "Mentions"
|
||||
"label": "Mentions",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"depends_on": "enable_email_notifications",
|
||||
"fieldname": "enable_email_assignment",
|
||||
"fieldtype": "Check",
|
||||
"label": "Assignments"
|
||||
"label": "Assignments",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"depends_on": "enable_email_notifications",
|
||||
"fieldname": "enable_email_energy_point",
|
||||
"fieldtype": "Check",
|
||||
"label": "Energy Points"
|
||||
"label": "Energy Points",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"depends_on": "enable_email_notifications",
|
||||
"fieldname": "enable_email_share",
|
||||
"fieldtype": "Check",
|
||||
"label": "Document Share"
|
||||
"label": "Document Share",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "__user",
|
||||
|
|
@ -75,18 +92,23 @@
|
|||
"hidden": 1,
|
||||
"label": "User",
|
||||
"options": "User",
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "seen",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"label": "Seen"
|
||||
"label": "Seen",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
}
|
||||
],
|
||||
"in_create": 1,
|
||||
"modified": "2019-11-19 12:57:59.356786",
|
||||
"links": [],
|
||||
"modified": "2020-05-31 22:16:40.798019",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Desk",
|
||||
"name": "Notification Settings",
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ def is_email_notifications_enabled_for_type(user, notification_type):
|
|||
if not is_email_notifications_enabled(user):
|
||||
return False
|
||||
|
||||
if notification_type == 'Alert':
|
||||
return False
|
||||
|
||||
fieldname = 'enable_email_' + frappe.scrub(notification_type)
|
||||
enabled = frappe.db.get_value('Notification Settings', user, fieldname)
|
||||
if enabled is None:
|
||||
|
|
|
|||
|
|
@ -110,7 +110,11 @@ class UserProfile {
|
|||
|
||||
|
||||
render_line_chart() {
|
||||
this.line_chart_filters = [['Energy Point Log', 'user', '=', this.user_id, false]];
|
||||
this.line_chart_filters = [
|
||||
['Energy Point Log', 'user', '=', this.user_id, false],
|
||||
['Energy Point Log', 'type', '!=', 'Review', false]
|
||||
];
|
||||
|
||||
this.line_chart_config = {
|
||||
timespan: 'Last Month',
|
||||
time_interval: 'Daily',
|
||||
|
|
@ -186,7 +190,10 @@ class UserProfile {
|
|||
options: ['All', 'Auto', 'Criticism', 'Appreciation', 'Revert'],
|
||||
action: (selected_item) => {
|
||||
if (selected_item === 'All') {
|
||||
if (this.line_chart_filters.length > 1) this.line_chart_filters.pop();
|
||||
this.line_chart_filters = [
|
||||
['Energy Point Log', 'user', '=', this.user_id, false],
|
||||
['Energy Point Log', 'type', '!=', 'Review', false]
|
||||
];
|
||||
} else {
|
||||
this.line_chart_filters[1] = ['Energy Point Log', 'type', '=', selected_item, false];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
"default_incoming",
|
||||
"email_sync_option",
|
||||
"initial_sync_count",
|
||||
"create_contact",
|
||||
"section_break_12",
|
||||
"enable_automatic_linking",
|
||||
"section_break_13",
|
||||
|
|
@ -114,9 +115,9 @@
|
|||
"depends_on": "eval:!doc.service",
|
||||
"fieldname": "domain",
|
||||
"fieldtype": "Link",
|
||||
"label": "Domain",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Domain",
|
||||
"options": "Email Domain"
|
||||
},
|
||||
{
|
||||
|
|
@ -408,11 +409,17 @@
|
|||
"fieldname": "use_ssl_for_outgoing",
|
||||
"fieldtype": "Check",
|
||||
"label": "Use SSL for Outgoing"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "create_contact",
|
||||
"fieldtype": "Check",
|
||||
"label": "Create Contacts from Incoming Emails"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-inbox",
|
||||
"links": [],
|
||||
"modified": "2020-04-06 19:20:50.491146",
|
||||
"modified": "2020-05-11 15:18:43.931499",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Email",
|
||||
"name": "Email Account",
|
||||
|
|
@ -427,11 +434,11 @@
|
|||
"write": 1
|
||||
},
|
||||
{
|
||||
"read": 1,
|
||||
"role": "Inbox User"
|
||||
"read": 1,
|
||||
"role": "Inbox User"
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,6 @@ frappe.ui.form.on("Notification", {
|
|||
});
|
||||
},
|
||||
refresh: function(frm) {
|
||||
frm.toggle_reqd("recipients", frm.doc.channel=="Email");
|
||||
frappe.notification.setup_fieldname_select(frm);
|
||||
frm.get_field("is_standard").toggle(frappe.boot.developer_mode);
|
||||
frm.trigger('event');
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"autoname": "Prompt",
|
||||
"creation": "2014-07-11 17:18:09.923399",
|
||||
|
|
@ -22,6 +23,7 @@
|
|||
"days_in_advance",
|
||||
"value_changed",
|
||||
"sender",
|
||||
"send_system_notification",
|
||||
"sender_email",
|
||||
"section_break_9",
|
||||
"condition",
|
||||
|
|
@ -46,32 +48,43 @@
|
|||
"default": "1",
|
||||
"fieldname": "enabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enabled"
|
||||
"label": "Enabled",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break"
|
||||
"fieldtype": "Column Break",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "Email",
|
||||
"depends_on": "eval: !doc.disable_channel",
|
||||
"fieldname": "channel",
|
||||
"fieldtype": "Select",
|
||||
"label": "Channel",
|
||||
"options": "Email\nSlack",
|
||||
"options": "Email\nSlack\nSystem Notification",
|
||||
"reqd": 1,
|
||||
"set_only_once": 1
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.channel=='Slack'",
|
||||
"fieldname": "slack_webhook_url",
|
||||
"fieldtype": "Link",
|
||||
"label": "Slack Channel",
|
||||
"options": "Slack Webhook URL"
|
||||
"mandatory_depends_on": "eval:doc.channel=='Slack'",
|
||||
"options": "Slack Webhook URL",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "filters",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Filters"
|
||||
"label": "Filters",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"description": "To add dynamic subject, use jinja tags like\n\n<div><pre><code>{{ doc.name }} Delivered</code></pre></div>",
|
||||
|
|
@ -80,7 +93,9 @@
|
|||
"ignore_xss_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Subject",
|
||||
"reqd": 1
|
||||
"reqd": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "document_type",
|
||||
|
|
@ -90,13 +105,17 @@
|
|||
"label": "Document Type",
|
||||
"options": "DocType",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
"search_index": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "is_standard",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Standard"
|
||||
"label": "Is Standard",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "is_standard",
|
||||
|
|
@ -104,11 +123,15 @@
|
|||
"fieldtype": "Link",
|
||||
"in_standard_filter": 1,
|
||||
"label": "Module",
|
||||
"options": "Module Def"
|
||||
"options": "Module Def",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "col_break_1",
|
||||
"fieldtype": "Column Break"
|
||||
"fieldtype": "Column Break",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "event",
|
||||
|
|
@ -117,21 +140,27 @@
|
|||
"label": "Send Alert On",
|
||||
"options": "\nNew\nSave\nSubmit\nCancel\nDays After\nDays Before\nValue Change\nMethod\nCustom",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
"search_index": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.event=='Method'",
|
||||
"description": "Trigger on valid methods like \"before_insert\", \"after_update\", etc (will depend on the DocType selected)",
|
||||
"fieldname": "method",
|
||||
"fieldtype": "Data",
|
||||
"label": "Trigger Method"
|
||||
"label": "Trigger Method",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.event==\"Days After\" || doc.event==\"Days Before\"",
|
||||
"description": "Send alert if date matches this field's value",
|
||||
"fieldname": "date_changed",
|
||||
"fieldtype": "Select",
|
||||
"label": "Reference Date"
|
||||
"label": "Reference Date",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
|
|
@ -139,31 +168,41 @@
|
|||
"description": "Send days before or after the reference date",
|
||||
"fieldname": "days_in_advance",
|
||||
"fieldtype": "Int",
|
||||
"label": "Days Before or After"
|
||||
"label": "Days Before or After",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.event==\"Value Change\"",
|
||||
"description": "Send alert if this field's value changes",
|
||||
"fieldname": "value_changed",
|
||||
"fieldtype": "Select",
|
||||
"label": "Value Changed"
|
||||
"label": "Value Changed",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "sender",
|
||||
"fieldtype": "Link",
|
||||
"label": "Sender",
|
||||
"options": "Email Account"
|
||||
"options": "Email Account",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "sender_email",
|
||||
"fieldtype": "Data",
|
||||
"label": "Sender Email",
|
||||
"options": "Email",
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_9",
|
||||
"fieldtype": "Section Break"
|
||||
"fieldtype": "Section Break",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"description": "Optional: The alert will be sent if this expression is true",
|
||||
|
|
@ -171,99 +210,143 @@
|
|||
"fieldtype": "Code",
|
||||
"ignore_xss_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Condition"
|
||||
"label": "Condition",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_6",
|
||||
"fieldtype": "Column Break"
|
||||
"fieldtype": "Column Break",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "html_7",
|
||||
"fieldtype": "HTML",
|
||||
"options": "<p><strong>Condition Examples:</strong></p>\n<pre>doc.status==\"Open\"<br>doc.due_date==nowdate()<br>doc.total > 40000\n</pre>\n"
|
||||
"options": "<p><strong>Condition Examples:</strong></p>\n<pre>doc.status==\"Open\"<br>doc.due_date==nowdate()<br>doc.total > 40000\n</pre>\n",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "property_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Set Property After Alert"
|
||||
"label": "Set Property After Alert",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "set_property_after_alert",
|
||||
"fieldtype": "Select",
|
||||
"label": "Set Property After Alert"
|
||||
"label": "Set Property After Alert",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "property_value",
|
||||
"fieldtype": "Data",
|
||||
"label": "Value To Be Set"
|
||||
"label": "Value To Be Set",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.channel=='Email'",
|
||||
"depends_on": "eval:doc.channel!=='Slack'",
|
||||
"fieldname": "column_break_5",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Recipients"
|
||||
"label": "Recipients",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "recipients",
|
||||
"fieldtype": "Table",
|
||||
"label": "Recipients",
|
||||
"options": "Notification Recipient"
|
||||
"mandatory_depends_on": "eval:doc.channel!=='Slack'",
|
||||
"options": "Notification Recipient",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "message_sb",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Message"
|
||||
"label": "Message",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "Add your message here",
|
||||
"fieldname": "message",
|
||||
"fieldtype": "Code",
|
||||
"ignore_xss_filter": 1,
|
||||
"label": "Message"
|
||||
"label": "Message",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.channel=='Email'",
|
||||
"fieldname": "message_examples",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Message Examples",
|
||||
"options": "<h5>Message Example</h5>\n\n<pre><h3>Order Overdue</h3>\n\n<p>Transaction {{ doc.name }} has exceeded Due Date. Please take necessary action.</p>\n\n<!-- show last comment -->\n{% if comments %}\nLast comment: {{ comments[-1].comment }} by {{ comments[-1].by }}\n{% endif %}\n\n<h4>Details</h4>\n\n<ul>\n<li>Customer: {{ doc.customer }}\n<li>Amount: {{ doc.grand_total }}\n</ul>\n</pre>"
|
||||
"options": "<h5>Message Example</h5>\n\n<pre><h3>Order Overdue</h3>\n\n<p>Transaction {{ doc.name }} has exceeded Due Date. Please take necessary action.</p>\n\n<!-- show last comment -->\n{% if comments %}\nLast comment: {{ comments[-1].comment }} by {{ comments[-1].by }}\n{% endif %}\n\n<h4>Details</h4>\n\n<ul>\n<li>Customer: {{ doc.customer }}\n<li>Amount: {{ doc.grand_total }}\n</ul>\n</pre>",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.channel=='Slack'",
|
||||
"fieldname": "slack_message_examples",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Message Examples",
|
||||
"options": "<h5>Message Example</h5>\n\n<pre>*Order Overdue*\n\nTransaction {{ doc.name }} has exceeded Due Date. Please take necessary action.\n\n<!-- show last comment -->\n{% if comments %}\nLast comment: {{ comments[-1].comment }} by {{ comments[-1].by }}\n{% endif %}\n\n*Details*\n\n\u2022 Customer: {{ doc.customer }}\n\u2022 Amount: {{ doc.grand_total }}\n</pre>"
|
||||
"options": "<h5>Message Example</h5>\n\n<pre>*Order Overdue*\n\nTransaction {{ doc.name }} has exceeded Due Date. Please take necessary action.\n\n<!-- show last comment -->\n{% if comments %}\nLast comment: {{ comments[-1].comment }} by {{ comments[-1].by }}\n{% endif %}\n\n*Details*\n\n\u2022 Customer: {{ doc.customer }}\n\u2022 Amount: {{ doc.grand_total }}\n</pre>",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "view_properties",
|
||||
"fieldtype": "Button",
|
||||
"label": "View Properties (via Customize Form)"
|
||||
"label": "View Properties (via Customize Form)",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "attach_print",
|
||||
"fieldname": "column_break_25",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Print Settings"
|
||||
"label": "Print Settings",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "attach_print",
|
||||
"fieldtype": "Check",
|
||||
"label": "Attach Print"
|
||||
"label": "Attach Print",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "attach_print",
|
||||
"fieldname": "print_format",
|
||||
"fieldtype": "Link",
|
||||
"label": "Print Format",
|
||||
"options": "Print Format"
|
||||
"options": "Print Format",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval: doc.channel !== 'System Notification'",
|
||||
"description": "If enabled, the notification will show up in the notifications dropdown on the top right corner of the navigation bar.",
|
||||
"fieldname": "send_system_notification",
|
||||
"fieldtype": "Check",
|
||||
"label": "Send System Notification",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-envelope",
|
||||
"modified": "2019-07-15 13:17:02.585013",
|
||||
"links": [],
|
||||
"modified": "2020-05-29 16:03:10.914526",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Email",
|
||||
"name": "Notification",
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ from frappe.utils.jinja import validate_template
|
|||
from frappe.modules.utils import export_module_json, get_doc_module
|
||||
from six import string_types
|
||||
from frappe.integrations.doctype.slack_webhook_url.slack_webhook_url import send_slack_message
|
||||
from frappe.desk.doctype.notification_log.notification_log import enqueue_create_notification
|
||||
|
||||
class Notification(Document):
|
||||
def onload(self):
|
||||
|
|
@ -125,6 +126,9 @@ def get_context(context):
|
|||
if self.channel == 'Slack':
|
||||
self.send_a_slack_msg(doc, context)
|
||||
|
||||
if self.channel == 'System Notification' or self.send_system_notification:
|
||||
self.create_system_notification(doc, context)
|
||||
|
||||
if self.set_property_after_alert:
|
||||
allow_update = True
|
||||
if doc.docstatus == 1 and not doc.meta.get_field(self.set_property_after_alert).allow_on_submit:
|
||||
|
|
@ -143,6 +147,25 @@ def get_context(context):
|
|||
except Exception:
|
||||
frappe.log_error(title='Document update failed', message=frappe.get_traceback())
|
||||
|
||||
def create_system_notification(self, doc, context):
|
||||
subject = self.subject
|
||||
if "{" in subject:
|
||||
subject = frappe.render_template(self.subject, context)
|
||||
|
||||
attachments = self.get_attachment(doc)
|
||||
recipients, cc, bcc = self.get_list_of_recipients(doc, context)
|
||||
users = recipients + cc + bcc
|
||||
|
||||
notification_doc = {
|
||||
'type': 'Alert',
|
||||
'document_type': doc.doctype,
|
||||
'document_name': doc.name,
|
||||
'subject': subject,
|
||||
'email_content': frappe.render_template(self.message, context),
|
||||
'attached_file': attachments and json.dumps(attachments[0])
|
||||
}
|
||||
enqueue_create_notification(users, notification_doc)
|
||||
|
||||
def send_an_email(self, doc, context):
|
||||
from email.utils import formataddr
|
||||
subject = self.subject
|
||||
|
|
@ -228,8 +251,7 @@ def get_context(context):
|
|||
|
||||
# ignoring attachment as draft and cancelled documents are not allowed to print
|
||||
status = "Draft" if doc.docstatus == 0 else "Cancelled"
|
||||
frappe.throw(_("""Not allowed to attach {0} document,
|
||||
please enable Allow Print For {0} in Print Settings""".format(status)),
|
||||
frappe.throw(_("""Not allowed to attach {0} document, please enable Allow Print For {0} in Print Settings""").format(status),
|
||||
title=_("Error in Notification"))
|
||||
else:
|
||||
return [{
|
||||
|
|
|
|||
|
|
@ -269,6 +269,7 @@ def make_site_dirs():
|
|||
os.path.join(site_private_path, 'backups'),
|
||||
os.path.join(site_public_path, 'files'),
|
||||
os.path.join(site_private_path, 'files'),
|
||||
os.path.join(frappe.local.site_path, 'logs'),
|
||||
os.path.join(frappe.local.site_path, 'task-logs')):
|
||||
if not os.path.exists(dir_path):
|
||||
os.makedirs(dir_path)
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ def backup_to_dropbox(upload_db_backup=True):
|
|||
dropbox_settings['access_token'] = access_token['oauth2_token']
|
||||
set_dropbox_access_token(access_token['oauth2_token'])
|
||||
|
||||
dropbox_client = dropbox.Dropbox(dropbox_settings['access_token'])
|
||||
dropbox_client = dropbox.Dropbox(dropbox_settings['access_token'], timeout=None)
|
||||
|
||||
if upload_db_backup:
|
||||
if frappe.flags.create_new_backup:
|
||||
|
|
|
|||
|
|
@ -147,11 +147,14 @@ def sync_contacts_from_google_contacts(g_contact):
|
|||
results = []
|
||||
contacts_updated = 0
|
||||
|
||||
sync_token = account.get_password(fieldname="next_sync_token", raise_exception=False) or None
|
||||
contacts = frappe._dict()
|
||||
|
||||
while True:
|
||||
try:
|
||||
sync_token = account.get_password(fieldname="next_sync_token", raise_exception=False) or None
|
||||
contacts = google_contacts.people().connections().list(resourceName='people/me',syncToken=sync_token,
|
||||
personFields="names,emailAddresses,organizations,phoneNumbers").execute()
|
||||
contacts = google_contacts.people().connections().list(resourceName='people/me', pageToken=contacts.get("nextPageToken"),
|
||||
syncToken=sync_token, pageSize=2000, requestSyncToken=True, personFields="names,emailAddresses,organizations,phoneNumbers").execute()
|
||||
|
||||
except HttpError as err:
|
||||
frappe.throw(_("Google Contacts - Could not sync contacts from Google Contacts {0}, error code {1}.").format(account.name, err.resp.status))
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ from __future__ import unicode_literals
|
|||
import frappe
|
||||
from frappe import _
|
||||
import json
|
||||
import hmac
|
||||
import hashlib
|
||||
from six.moves.urllib.parse import urlencode
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import get_url, call_hook_method, cint, get_timestamp
|
||||
|
|
@ -317,6 +319,20 @@ class RazorpaySettings(Document):
|
|||
except Exception:
|
||||
frappe.log_error(frappe.get_traceback())
|
||||
|
||||
def verify_signature(self, body, signature, key):
|
||||
key = bytes(key, 'utf-8')
|
||||
body = bytes(body, 'utf-8')
|
||||
|
||||
dig = hmac.new(key=key, msg=body, digestmod=hashlib.sha256)
|
||||
|
||||
generated_signature = dig.hexdigest()
|
||||
result = hmac.compare_digest(generated_signature, signature)
|
||||
|
||||
if not result:
|
||||
frappe.throw(_('Razorpay Signature Verification Failed'), exc=frappe.PermissionError)
|
||||
|
||||
return result
|
||||
|
||||
def capture_payment(is_sandbox=False, sanbox_response=None):
|
||||
"""
|
||||
Verifies the purchase as complete by the merchant.
|
||||
|
|
|
|||
|
|
@ -693,7 +693,7 @@ class BaseDocument(object):
|
|||
df = self.meta.get_field(fieldname)
|
||||
sanitized_value = value
|
||||
|
||||
if df and df.get("fieldtype") in ("Data", "Code", "Small Text") and df.get("options")=="Email":
|
||||
if df and df.get("fieldtype") in ("Data", "Code", "Small Text", "Text") and df.get("options")=="Email":
|
||||
sanitized_value = sanitize_email(value)
|
||||
|
||||
elif df and (df.get("ignore_xss_filter")
|
||||
|
|
|
|||
|
|
@ -299,6 +299,7 @@ def set_workflow_state_on_action(doc, workflow_name, action):
|
|||
return
|
||||
|
||||
action_map = {
|
||||
'update_after_submit': '1',
|
||||
'submit': '1',
|
||||
'cancel': '2'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -278,6 +278,7 @@ frappe.patches.v13_0.set_path_for_homepage_in_web_page_view
|
|||
frappe.patches.v13_0.migrate_translation_column_data
|
||||
frappe.patches.v13_0.set_read_times
|
||||
frappe.patches.v13_0.remove_web_view
|
||||
frappe.patches.v13_0.site_wise_logging
|
||||
frappe.patches.v13_0.set_unique_for_page_view
|
||||
frappe.patches.v13_0.remove_tailwind_from_page_builder
|
||||
frappe.patches.v13_0.rename_onboarding
|
||||
|
|
@ -285,4 +286,4 @@ frappe.patches.v13_0.email_unsubscribe
|
|||
execute:frappe.delete_doc("Web Template", "Section with Left Image", force=1)
|
||||
execute:frappe.delete_doc("DocType", "Onboarding Slide")
|
||||
execute:frappe.delete_doc("DocType", "Onboarding Slide Field")
|
||||
execute:frappe.delete_doc("DocType", "Onboarding Slide Help Link")
|
||||
execute:frappe.delete_doc("DocType", "Onboarding Slide Help Link")
|
||||
|
|
|
|||
10
frappe/patches/v13_0/site_wise_logging.py
Normal file
10
frappe/patches/v13_0/site_wise_logging.py
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import os
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
site = frappe.local.site
|
||||
|
||||
log_folder = os.path.join(site, 'logs')
|
||||
if not os.path.exists(log_folder):
|
||||
os.mkdir(log_folder)
|
||||
|
|
@ -650,13 +650,14 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
frappe.utils.play_sound("submit");
|
||||
callback && callback();
|
||||
me.script_manager.trigger("on_submit")
|
||||
.then(() => resolve(me));
|
||||
if (frappe.route_hooks.after_submit) {
|
||||
let route_callback = frappe.route_hooks.after_submit;
|
||||
delete frappe.route_hooks.after_submit;
|
||||
|
||||
route_callback(me);
|
||||
}
|
||||
.then(() => resolve(me))
|
||||
.then(() => {
|
||||
if (frappe.route_hooks.after_submit) {
|
||||
let route_callback = frappe.route_hooks.after_submit;
|
||||
delete frappe.route_hooks.after_submit;
|
||||
route_callback(me);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, btn, () => me.handle_save_fail(btn, on_error), resolve);
|
||||
});
|
||||
|
|
@ -1586,7 +1587,7 @@ frappe.ui.form.Form = class FrappeForm {
|
|||
let steps = frappe.tour[this.doctype].map(step => {
|
||||
let field = this.get_docfield(step.fieldname);
|
||||
return {
|
||||
element: `.frappe-control[title='${step.fieldname}']`,
|
||||
element: `.frappe-control[data-fieldname='${step.fieldname}']`,
|
||||
popover: {
|
||||
title: step.title || field.label,
|
||||
description: step.description
|
||||
|
|
|
|||
|
|
@ -16,12 +16,22 @@ frappe.ui.form.get_event_handler_list = function(doctype, fieldname) {
|
|||
frappe.ui.form.on = frappe.ui.form.on_change = function(doctype, fieldname, handler) {
|
||||
var add_handler = function(fieldname, handler) {
|
||||
var handler_list = frappe.ui.form.get_event_handler_list(doctype, fieldname);
|
||||
handler_list.push(handler);
|
||||
|
||||
let _handler = (...args) => {
|
||||
try {
|
||||
handler(...args);
|
||||
} catch (error) {
|
||||
console.error(handler);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
handler_list.push(_handler);
|
||||
|
||||
// add last handler to events so it can be called as
|
||||
// frm.events.handler(frm)
|
||||
if(cur_frm && cur_frm.doctype===doctype) {
|
||||
cur_frm.events[fieldname] = handler;
|
||||
cur_frm.events[fieldname] = _handler;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -287,7 +287,8 @@ frappe.socketio.SocketIOUploader = class SocketIOUploader {
|
|||
}
|
||||
|
||||
function fallback_required() {
|
||||
return !frappe.boot.sysdefaults.use_socketio_to_upload_file || !frappe.socketio.socket.connected;
|
||||
return !frappe.socketio.socket.connected
|
||||
|| !( !frappe.boot.sysdefaults || frappe.boot.sysdefaults.use_socketio_to_upload_file );
|
||||
}
|
||||
|
||||
if (fallback_required()) {
|
||||
|
|
|
|||
|
|
@ -304,10 +304,7 @@ frappe.ui.Notifications = class Notifications {
|
|||
}
|
||||
|
||||
get_dropdown_item_html(field) {
|
||||
let doc_link = frappe.utils.get_form_link(
|
||||
field.document_type,
|
||||
field.document_name
|
||||
);
|
||||
let doc_link = this.get_item_link(field);
|
||||
let read_class = field.read ? '' : 'unread';
|
||||
let mark_read_action = field.read ? '': 'data-action="mark_as_read"';
|
||||
let message = field.subject;
|
||||
|
|
@ -336,6 +333,17 @@ frappe.ui.Notifications = class Notifications {
|
|||
return item_html;
|
||||
}
|
||||
|
||||
get_item_link(notification_doc) {
|
||||
const link_doctype =
|
||||
notification_doc.type == 'Alert' ? 'Notification Log': notification_doc.document_type;
|
||||
const link_docname =
|
||||
notification_doc.type == 'Alert' ? notification_doc.name: notification_doc.document_name;
|
||||
return frappe.utils.get_form_link(
|
||||
link_doctype,
|
||||
link_docname
|
||||
);
|
||||
}
|
||||
|
||||
render_dropdown_headers() {
|
||||
this.categories = [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -811,19 +811,19 @@ Object.assign(frappe.utils, {
|
|||
let total_duration = frappe.utils.seconds_to_duration(value, duration_options);
|
||||
|
||||
if (total_duration.days) {
|
||||
duration += total_duration.days + 'd';
|
||||
duration += total_duration.days + __('d', null, 'Days (Field: Duration)');
|
||||
}
|
||||
if (total_duration.hours) {
|
||||
duration += (duration.length ? " " : "");
|
||||
duration += total_duration.hours + 'h';
|
||||
duration += total_duration.hours + __('h', null, 'Hours (Field: Duration)');
|
||||
}
|
||||
if (total_duration.minutes) {
|
||||
duration += (duration.length ? " " : "");
|
||||
duration += total_duration.minutes + 'm';
|
||||
duration += total_duration.minutes + __('m', null, 'Minutes (Field: Duration)');
|
||||
}
|
||||
if (total_duration.seconds) {
|
||||
duration += (duration.length ? " " : "");
|
||||
duration += total_duration.seconds + 's';
|
||||
duration += total_duration.seconds + __('s', null, 'Seconds (Field: Duration)');
|
||||
}
|
||||
}
|
||||
return duration;
|
||||
|
|
@ -998,4 +998,4 @@ String.prototype.plural = function(revert) {
|
|||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
frappe.ui.form.on("Web Page Block", {
|
||||
edit_values(frm, cdt, cdn) {
|
||||
let row = frm.selected_doc;
|
||||
frappe.model.with_doc("Web Template", row.web_template).then((doc) => {
|
||||
let d = new frappe.ui.Dialog({
|
||||
title: __("Edit Values"),
|
||||
fields: doc.fields.map((df) => {
|
||||
if (df.fieldtype == "Section Break") {
|
||||
df.collapsible = 1;
|
||||
}
|
||||
return df;
|
||||
}),
|
||||
primary_action(values) {
|
||||
frappe.model.set_value(
|
||||
cdt,
|
||||
cdn,
|
||||
"web_template_values",
|
||||
JSON.stringify(values)
|
||||
);
|
||||
d.hide();
|
||||
},
|
||||
});
|
||||
let values = JSON.parse(row.web_template_values || "{}");
|
||||
d.set_values(values);
|
||||
d.show();
|
||||
|
||||
d.sections.forEach((sect) => {
|
||||
let fields_with_value = sect.fields_list.filter(
|
||||
(field) => values[field.df.fieldname]
|
||||
);
|
||||
|
||||
if (fields_with_value.length) {
|
||||
sect.collapse(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -89,16 +89,21 @@ frappe.breadcrumbs = {
|
|||
breadcrumbs.module = frappe.breadcrumbs.module_map[breadcrumbs.module];
|
||||
}
|
||||
|
||||
if(frappe.get_module(breadcrumbs.module)) {
|
||||
let current_module = breadcrumbs.module
|
||||
// Check if a desk page exists
|
||||
if (frappe.boot.module_page_map[breadcrumbs.module]) {
|
||||
breadcrumbs.module = frappe.boot.module_page_map[breadcrumbs.module];
|
||||
}
|
||||
|
||||
if(frappe.get_module(current_module)) {
|
||||
// if module access exists
|
||||
var module_info = frappe.get_module(breadcrumbs.module),
|
||||
var module_info = frappe.get_module(current_module),
|
||||
icon = module_info && module_info.icon,
|
||||
label = module_info ? module_info.label : breadcrumbs.module;
|
||||
|
||||
|
||||
if(module_info && !module_info.blocked && frappe.visible_modules.includes(module_info.module_name)) {
|
||||
$(repl('<li><a href="#workspace/%(module)s">%(label)s</a></li>',
|
||||
{ module: breadcrumbs.module, label: __(label) }))
|
||||
{ module: breadcrumbs.module, label: __(breadcrumbs.module) }))
|
||||
.appendTo($breadcrumbs);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,6 @@ export default class ChartWidget extends Widget {
|
|||
this.chart_settings = {};
|
||||
}
|
||||
this.setup_container();
|
||||
this.prepare_chart_object();
|
||||
if (!this.in_customize_mode) {
|
||||
this.action_area.empty();
|
||||
this.prepare_chart_actions();
|
||||
|
|
@ -110,7 +109,10 @@ export default class ChartWidget extends Widget {
|
|||
this.render_time_series_filters();
|
||||
}
|
||||
}
|
||||
this.fetch_and_update_chart();
|
||||
frappe.run_serially([
|
||||
() => this.prepare_chart_object(),
|
||||
() => this.fetch_and_update_chart(),
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -625,13 +627,41 @@ export default class ChartWidget extends Widget {
|
|||
}
|
||||
|
||||
prepare_chart_object() {
|
||||
let saved_filters = this.chart_settings.filters || null;
|
||||
this.filters =
|
||||
saved_filters || this.filters || JSON.parse(this.chart_doc.filters_json || "[]");
|
||||
|
||||
if (this.chart_doc.type == 'Heatmap' && !this.chart_doc.heatmap_year) {
|
||||
this.chart_doc.heatmap_year = frappe.dashboard_utils.get_year(frappe.datetime.now_date());
|
||||
}
|
||||
|
||||
return this.set_chart_filters();
|
||||
}
|
||||
|
||||
set_chart_filters() {
|
||||
let user_saved_filters = this.chart_settings.filters || null;
|
||||
let chart_saved_filters = JSON.parse(this.chart_doc.filters_json || "null");
|
||||
|
||||
if (this.chart_doc.chart_type == 'Report') {
|
||||
return frappe.dashboard_utils
|
||||
.get_filters_for_chart_type(this.chart_doc).then(filters => {
|
||||
chart_saved_filters = this.update_default_date_filters(filters, chart_saved_filters);
|
||||
this.filters =
|
||||
user_saved_filters || this.filters || chart_saved_filters;
|
||||
});
|
||||
} else {
|
||||
this.filters =
|
||||
user_saved_filters || this.filters || chart_saved_filters;
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
update_default_date_filters(report_filters, chart_filters) {
|
||||
report_filters.map(f => {
|
||||
if (['Date', 'DateRange'].includes(f.fieldtype) && f.default) {
|
||||
if (f.reqd || chart_filters[f.fieldname]) {
|
||||
chart_filters[f.fieldname] = f.default;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return chart_filters;
|
||||
}
|
||||
|
||||
get_settings() {
|
||||
|
|
|
|||
|
|
@ -29,9 +29,13 @@ export default class ShortcutWidget extends Widget {
|
|||
name: this.link_to,
|
||||
type: this.type,
|
||||
is_query_report: this.is_query_report,
|
||||
doctype: this.ref_doctype
|
||||
doctype: this.ref_doctype,
|
||||
});
|
||||
|
||||
let filters = this.get_doctype_filter();
|
||||
if (this.type == "DocType" && filters) {
|
||||
frappe.route_options = filters;
|
||||
}
|
||||
frappe.set_route(route);
|
||||
});
|
||||
}
|
||||
|
|
@ -40,16 +44,26 @@ export default class ShortcutWidget extends Widget {
|
|||
if (this.in_customize_mode) return;
|
||||
|
||||
this.widget.addClass("shortcut-widget-box");
|
||||
const get_filter = new Function(`return ${this.stats_filter}`);
|
||||
if (this.type == "DocType" && this.stats_filter) {
|
||||
|
||||
let filters = this.get_doctype_filter();
|
||||
if (this.type == "DocType" && filters) {
|
||||
frappe.db
|
||||
.count(this.link_to, {
|
||||
filters: get_filter(),
|
||||
filters: filters,
|
||||
})
|
||||
.then((count) => this.set_count(count));
|
||||
}
|
||||
}
|
||||
|
||||
get_doctype_filter() {
|
||||
let count_filter = new Function(`return ${this.stats_filter}`)();
|
||||
if (count_filter) {
|
||||
return count_filter;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
set_title() {
|
||||
if (this.icon) {
|
||||
this.title_field[0].innerHTML = `<div>
|
||||
|
|
@ -82,4 +96,4 @@ export default class ShortcutWidget extends Widget {
|
|||
|
||||
buttons.appendTo(this.action_area);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -241,11 +241,14 @@ class ShortcutDialog extends WidgetDialog {
|
|||
|
||||
if (this.dialog.get_value("type") == "DocType" && this.filter_group) {
|
||||
let filters = this.filter_group.get_filters();
|
||||
filters.forEach((arr) => {
|
||||
stats_filter[arr[1]] = [arr[2], arr[3]];
|
||||
});
|
||||
|
||||
data.stats_filter = JSON.stringify(stats_filter);
|
||||
if (filters.length) {
|
||||
filters.forEach((arr) => {
|
||||
stats_filter[arr[1]] = [arr[2], arr[3]];
|
||||
});
|
||||
|
||||
data.stats_filter = JSON.stringify(stats_filter);
|
||||
}
|
||||
}
|
||||
|
||||
data.label = data.label
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
from __future__ import unicode_literals, print_function
|
||||
from werkzeug.test import Client
|
||||
import os, re, sys, json, hashlib, requests, traceback
|
||||
import functools
|
||||
from .html_utils import sanitize_html
|
||||
import frappe
|
||||
from frappe.utils.identicon import Identicon
|
||||
|
|
@ -360,6 +361,7 @@ def decode_dict(d, encoding="utf-8"):
|
|||
|
||||
return d
|
||||
|
||||
@functools.lru_cache()
|
||||
def get_site_name(hostname):
|
||||
return hostname.split(':')[0]
|
||||
|
||||
|
|
|
|||
|
|
@ -89,10 +89,14 @@ def sync_dashboards(app=None):
|
|||
config = get_config(app_name, module_name)
|
||||
if config:
|
||||
frappe.flags.in_import = True
|
||||
make_records(config.charts, "Dashboard Chart")
|
||||
make_records(config.number_cards, "Number Card")
|
||||
make_records(config.dashboards, "Dashboard")
|
||||
frappe.flags.in_import = False
|
||||
try:
|
||||
make_records(config.charts, "Dashboard Chart")
|
||||
make_records(config.number_cards, "Number Card")
|
||||
make_records(config.dashboards, "Dashboard")
|
||||
except Exception as e:
|
||||
frappe.log_error(e, _("Dashboard Import Error"))
|
||||
finally:
|
||||
frappe.flags.in_import = False
|
||||
|
||||
def make_records(config, doctype):
|
||||
if not config:
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ def make_error_snapshot(exception):
|
|||
if frappe.conf.disable_error_snapshot:
|
||||
return
|
||||
|
||||
logger = frappe.logger(__name__, with_more_info=False)
|
||||
logger = frappe.logger(with_more_info=True)
|
||||
|
||||
try:
|
||||
error_id = '{timestamp:s}-{ip:s}-{hash:s}'.format(
|
||||
|
|
|
|||
|
|
@ -1,30 +1,53 @@
|
|||
# imports - compatibility imports
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
# imports - standard imports
|
||||
import logging
|
||||
import os
|
||||
from logging.handlers import RotatingFileHandler
|
||||
|
||||
# imports - third party imports
|
||||
from six import text_type
|
||||
|
||||
default_log_level = logging.DEBUG
|
||||
LOG_FILENAME = '../logs/{}-frappe.log'.format(frappe.local.site)
|
||||
# imports - module imports
|
||||
import frappe
|
||||
|
||||
def get_logger(module, with_more_info=True):
|
||||
|
||||
default_log_level = logging.DEBUG
|
||||
site = getattr(frappe.local, 'site', None)
|
||||
|
||||
|
||||
def get_logger(module, with_more_info=False):
|
||||
global site
|
||||
if module in frappe.loggers:
|
||||
return frappe.loggers[module]
|
||||
|
||||
formatter = logging.Formatter('[%(levelname)s] %(asctime)s | %(pathname)s:\n%(message)s')
|
||||
# handler = logging.StreamHandler()
|
||||
if not module:
|
||||
module = "frappe"
|
||||
with_more_info = True
|
||||
|
||||
handler = RotatingFileHandler(
|
||||
LOG_FILENAME, maxBytes=100000, backupCount=20)
|
||||
handler.setFormatter(formatter)
|
||||
logfile = module + '.log'
|
||||
site = getattr(frappe.local, 'site', None)
|
||||
LOG_FILENAME = os.path.join('..', 'logs', logfile)
|
||||
|
||||
logger = logging.getLogger(module)
|
||||
logger.setLevel(frappe.log_level or default_log_level)
|
||||
logger.propagate = False
|
||||
|
||||
formatter = logging.Formatter('%(asctime)s %(levelname)s %(name)s %(message)s')
|
||||
handler = RotatingFileHandler(LOG_FILENAME, maxBytes=100_000, backupCount=20)
|
||||
logger.addHandler(handler)
|
||||
#
|
||||
if site:
|
||||
SITELOG_FILENAME = os.path.join(site, 'logs', logfile)
|
||||
site_handler = RotatingFileHandler(SITELOG_FILENAME, maxBytes=100_000, backupCount=20)
|
||||
site_handler.setFormatter(formatter)
|
||||
logger.addHandler(site_handler)
|
||||
|
||||
if with_more_info:
|
||||
handler.addFilter(SiteContextFilter())
|
||||
|
||||
logger = logging.getLogger(module)
|
||||
logger.setLevel(frappe.log_level or default_log_level)
|
||||
logger.addHandler(handler)
|
||||
logger.propagate = False
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
frappe.loggers[module] = logger
|
||||
|
||||
|
|
@ -33,25 +56,9 @@ def get_logger(module, with_more_info=True):
|
|||
class SiteContextFilter(logging.Filter):
|
||||
"""This is a filter which injects request information (if available) into the log."""
|
||||
def filter(self, record):
|
||||
record.msg = get_more_info_for_log() + text_type(record.msg)
|
||||
return True
|
||||
|
||||
def get_more_info_for_log():
|
||||
'''Adds Site, Form Dict into log entry'''
|
||||
more_info = []
|
||||
site = getattr(frappe.local, 'site', None)
|
||||
if site:
|
||||
more_info.append('Site: {0}'.format(site))
|
||||
|
||||
form_dict = getattr(frappe.local, 'form_dict', None)
|
||||
if form_dict:
|
||||
more_info.append('Form Dict: {0}'.format(frappe.as_json(form_dict)))
|
||||
|
||||
if more_info:
|
||||
# to append a \n
|
||||
more_info = more_info + ['']
|
||||
|
||||
return '\n'.join(more_info)
|
||||
if "Form Dict" not in text_type(record.msg):
|
||||
record.msg = text_type(record.msg) + "\nSite: {0}\nForm Dict: {1}".format(site, getattr(frappe.local, 'form_dict', None))
|
||||
return True
|
||||
|
||||
def set_log_level(level):
|
||||
'''Use this method to set log level to something other than the default DEBUG'''
|
||||
|
|
|
|||
|
|
@ -7,17 +7,24 @@ Events:
|
|||
monthly
|
||||
weekly
|
||||
"""
|
||||
# imports - compatibility imports
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
from __future__ import unicode_literals, print_function
|
||||
# imports - standard imports
|
||||
import os
|
||||
import time
|
||||
|
||||
import frappe, os, time
|
||||
# imports - third party imports
|
||||
import schedule
|
||||
from frappe.utils import now_datetime, get_datetime
|
||||
from frappe.utils import get_sites
|
||||
from frappe.installer import update_site_config
|
||||
|
||||
# imports - module imports
|
||||
import frappe
|
||||
from frappe.core.doctype.user.user import STANDARD_USERS
|
||||
from frappe.installer import update_site_config
|
||||
from frappe.utils import get_sites, now_datetime
|
||||
from frappe.utils.background_jobs import get_jobs
|
||||
|
||||
|
||||
DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
|
||||
|
||||
def start_scheduler():
|
||||
|
|
@ -48,9 +55,8 @@ def enqueue_events_for_all_sites():
|
|||
|
||||
def enqueue_events_for_site(site):
|
||||
def log_and_raise():
|
||||
frappe.logger(__name__).error('Exception in Enqueue Events for Site {0}'.format(site) +
|
||||
'\n' + frappe.get_traceback())
|
||||
raise # pylint: disable=misplaced-bare-raise
|
||||
error_message = 'Exception in Enqueue Events for Site {0}\n{1}'.format(site, frappe.get_traceback())
|
||||
frappe.logger("scheduler").error(error_message)
|
||||
|
||||
try:
|
||||
frappe.init(site=site)
|
||||
|
|
@ -60,10 +66,10 @@ def enqueue_events_for_site(site):
|
|||
|
||||
enqueue_events(site=site)
|
||||
|
||||
frappe.logger(__name__).debug('Queued events for site {0}'.format(site))
|
||||
frappe.logger("scheduler").debug('Queued events for site {0}'.format(site))
|
||||
except frappe.db.OperationalError as e:
|
||||
if frappe.db.is_access_denied(e):
|
||||
frappe.logger(__name__).debug('Access denied for site {0}'.format(site))
|
||||
frappe.logger("scheduler").debug('Access denied for site {0}'.format(site))
|
||||
else:
|
||||
log_and_raise()
|
||||
except:
|
||||
|
|
|
|||
|
|
@ -38,10 +38,11 @@
|
|||
"docstatus": 0,
|
||||
"doctype": "Desk Page",
|
||||
"extends_another_page": 0,
|
||||
"hide_custom": 0,
|
||||
"idx": 0,
|
||||
"is_standard": 1,
|
||||
"label": "Website",
|
||||
"modified": "2020-05-05 18:17:13.232473",
|
||||
"modified": "2020-05-28 13:53:10.736212",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Website",
|
||||
"name": "Website",
|
||||
|
|
@ -51,7 +52,7 @@
|
|||
"pin_to_top": 0,
|
||||
"shortcuts": [
|
||||
{
|
||||
"color": "",
|
||||
"color": "#cef6d1",
|
||||
"format": "{} Published",
|
||||
"label": "Blog Post",
|
||||
"link_to": "Blog Post",
|
||||
|
|
@ -59,6 +60,7 @@
|
|||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"color": "#cef6d1",
|
||||
"format": "{} Active",
|
||||
"label": "Blogger",
|
||||
"link_to": "Blogger",
|
||||
|
|
@ -66,8 +68,11 @@
|
|||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"color": "#cef6d1",
|
||||
"format": "{} Published",
|
||||
"label": "Web Page",
|
||||
"link_to": "Web Page",
|
||||
"stats_filter": "{ \"published\": 1 }",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,9 +2,6 @@
|
|||
// MIT License. See license.txt
|
||||
|
||||
frappe.ui.form.on('Web Page', {
|
||||
onload: function() {
|
||||
frappe.require('/assets/frappe/js/frappe/utils/web_page_block.js');
|
||||
},
|
||||
title: function(frm) {
|
||||
if (frm.doc.title && !frm.doc.route) {
|
||||
frm.set_value('route', frappe.scrub(frm.doc.title, '-'));
|
||||
|
|
@ -49,6 +46,45 @@ frappe.ui.form.on('Web Page', {
|
|||
}
|
||||
});
|
||||
|
||||
frappe.ui.form.on("Web Page Block", {
|
||||
edit_values(frm, cdt, cdn) {
|
||||
let row = frm.selected_doc;
|
||||
frappe.model.with_doc("Web Template", row.web_template).then((doc) => {
|
||||
let d = new frappe.ui.Dialog({
|
||||
title: __("Edit Values"),
|
||||
fields: doc.fields.map((df) => {
|
||||
if (df.fieldtype == "Section Break") {
|
||||
df.collapsible = 1;
|
||||
}
|
||||
return df;
|
||||
}),
|
||||
primary_action(values) {
|
||||
frappe.model.set_value(
|
||||
cdt,
|
||||
cdn,
|
||||
"web_template_values",
|
||||
JSON.stringify(values)
|
||||
);
|
||||
d.hide();
|
||||
},
|
||||
});
|
||||
let values = JSON.parse(row.web_template_values || "{}");
|
||||
d.set_values(values);
|
||||
d.show();
|
||||
|
||||
d.sections.forEach((sect) => {
|
||||
let fields_with_value = sect.fields_list.filter(
|
||||
(field) => values[field.df.fieldname]
|
||||
);
|
||||
|
||||
if (fields_with_value.length) {
|
||||
sect.collapse(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
frappe.tour['Web Page'] = [
|
||||
{
|
||||
fieldname: "title",
|
||||
|
|
@ -102,4 +138,4 @@ frappe.tour['Web Page'] = [
|
|||
title: __("Meta Image"),
|
||||
description: __("The meta image is unique image representing the content of the page. Images for this Card should be at least 280px in width, and at least 150px in height.")
|
||||
},
|
||||
];
|
||||
];
|
||||
|
|
|
|||
|
|
@ -2,9 +2,6 @@
|
|||
// MIT License. See license.txt
|
||||
|
||||
frappe.ui.form.on('Website Theme', {
|
||||
onload: function() {
|
||||
frappe.require('/assets/frappe/js/frappe/utils/web_page_block.js');
|
||||
},
|
||||
refresh(frm) {
|
||||
frm.clear_custom_buttons();
|
||||
frm.toggle_display(["module", "custom"], !frappe.boot.developer_mode);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
"documentation_url": "https://docs.erpnext.com/docs/user/manual/en/website",
|
||||
"idx": 0,
|
||||
"is_complete": 0,
|
||||
"modified": "2020-05-13 12:32:35.269025",
|
||||
"modified": "2020-05-28 13:51:57.535269",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Website",
|
||||
"name": "Website",
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@
|
|||
"is_mandatory": 0,
|
||||
"is_single": 0,
|
||||
"is_skipped": 0,
|
||||
"modified": "2020-04-30 19:06:10.750976",
|
||||
"modified": "2020-05-28 13:51:53.157256",
|
||||
"modified_by": "Administrator",
|
||||
"name": "Add Blog Category",
|
||||
"owner": "Administrator",
|
||||
"reference_document": "Blog Category",
|
||||
"title": "Add Blog Category"
|
||||
"show_full_form": 0,
|
||||
"title": "Add Blog Category",
|
||||
"validate_action": 0
|
||||
}
|
||||
|
|
@ -13,5 +13,7 @@
|
|||
"name": "Create Blogger",
|
||||
"owner": "Administrator",
|
||||
"reference_document": "Blogger",
|
||||
"title": "Create Blogger"
|
||||
"show_full_form": 0,
|
||||
"title": "Create Blogger",
|
||||
"validate_action": 0
|
||||
}
|
||||
|
|
@ -14,6 +14,8 @@
|
|||
"name": "Enable Website Tracking",
|
||||
"owner": "Administrator",
|
||||
"reference_document": "Website Settings",
|
||||
"show_full_form": 0,
|
||||
"title": "Enable Website Tracking",
|
||||
"validate_action": 0,
|
||||
"value_to_validate": "1"
|
||||
}
|
||||
|
|
@ -8,10 +8,12 @@
|
|||
"is_mandatory": 1,
|
||||
"is_single": 0,
|
||||
"is_skipped": 0,
|
||||
"modified": "2020-04-30 19:06:10.578218",
|
||||
"modified": "2020-05-28 13:51:51.485924",
|
||||
"modified_by": "Administrator",
|
||||
"name": "Introduction to Website",
|
||||
"owner": "Administrator",
|
||||
"show_full_form": 0,
|
||||
"title": "Introduction to Website",
|
||||
"validate_action": 0,
|
||||
"video_url": "https://www.youtube.com/watch?v=lyW6mfFBSNw"
|
||||
}
|
||||
|
|
@ -8,10 +8,12 @@
|
|||
"is_mandatory": 0,
|
||||
"is_single": 0,
|
||||
"is_skipped": 0,
|
||||
"modified": "2020-05-13 12:32:15.966570",
|
||||
"modified": "2020-05-28 13:51:54.264456",
|
||||
"modified_by": "Administrator",
|
||||
"name": "Web Page Tour",
|
||||
"owner": "Administrator",
|
||||
"reference_document": "Web Page",
|
||||
"title": "Learn about Web Pages"
|
||||
"show_full_form": 0,
|
||||
"title": "Learn about Web Pages",
|
||||
"validate_action": 0
|
||||
}
|
||||
|
|
@ -7,9 +7,9 @@
|
|||
"custom_overrides": "",
|
||||
"docstatus": 0,
|
||||
"doctype": "Website Theme",
|
||||
"font_properties": "wght:400;500;600;700;800",
|
||||
"idx": 28,
|
||||
"modified": "2020-05-19 00:33:58.011046",
|
||||
"font_properties": "400,500,600,700,800",
|
||||
"idx": 26,
|
||||
"modified": "2020-05-20 14:47:12.938879",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Website",
|
||||
"name": "Standard",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue