@@ -35,6 +35,7 @@ before_script: | |||||
- echo "USE mysql;\nGRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost';\n" | mysql -u root -ptravis | - echo "USE mysql;\nGRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost';\n" | mysql -u root -ptravis | ||||
- cd ~/frappe-bench | - cd ~/frappe-bench | ||||
- npm install babel-core less chokidar babel-preset-es2015 babel-preset-es2016 babel-preset-es2017 babel-preset-babili | |||||
- bench use test_site | - bench use test_site | ||||
- bench reinstall --yes | - bench reinstall --yes | ||||
- bench start & | - bench start & | ||||
@@ -13,7 +13,7 @@ import os, sys, importlib, inspect, json | |||||
from .exceptions import * | from .exceptions import * | ||||
from .utils.jinja import get_jenv, get_template, render_template | from .utils.jinja import get_jenv, get_template, render_template | ||||
__version__ = '8.0.55' | |||||
__version__ = '8.0.56' | |||||
__title__ = "Frappe Framework" | __title__ = "Frappe Framework" | ||||
local = Local() | local = Local() | ||||
@@ -65,7 +65,7 @@ def application(request): | |||||
elif frappe.request.path.startswith('/private/files/'): | elif frappe.request.path.startswith('/private/files/'): | ||||
response = frappe.utils.response.download_private_file(request.path) | response = frappe.utils.response.download_private_file(request.path) | ||||
elif frappe.local.request.method in ('GET', 'HEAD'): | |||||
elif frappe.local.request.method in ('GET', 'HEAD', 'POST'): | |||||
response = frappe.website.render.render() | response = frappe.website.render.render() | ||||
else: | else: | ||||
@@ -122,6 +122,7 @@ def make_form_dict(request): | |||||
frappe.local.form_dict.pop("_") | frappe.local.form_dict.pop("_") | ||||
def handle_exception(e): | def handle_exception(e): | ||||
response = None | |||||
http_status_code = getattr(e, "http_status_code", 500) | http_status_code = getattr(e, "http_status_code", 500) | ||||
return_as_message = False | return_as_message = False | ||||
@@ -185,6 +185,9 @@ class LoginManager: | |||||
if not (user and pwd): | if not (user and pwd): | ||||
self.fail('Incomplete login details', user=user) | self.fail('Incomplete login details', user=user) | ||||
if cint(frappe.db.get_value("System Settings", "System Settings", "allow_login_using_mobile_number")): | |||||
user = frappe.db.get_value("User", filters={"mobile_no": user}, fieldname="name") or user | |||||
self.check_if_enabled(user) | self.check_if_enabled(user) | ||||
self.user = self.check_password(user, pwd) | self.user = self.check_password(user, pwd) | ||||
@@ -24,7 +24,7 @@ const build_map = make_build_map(); | |||||
// command line args | // command line args | ||||
const action = process.argv[2] || '--build'; | const action = process.argv[2] || '--build'; | ||||
if (!['--build', '--watch'].includes(action)) { | |||||
if (['--build', '--watch'].indexOf(action) === -1) { | |||||
console.log('Invalid argument: ', action); | console.log('Invalid argument: ', action); | ||||
return; | return; | ||||
} | } | ||||
@@ -31,7 +31,7 @@ def bundle(no_compress, make_copy=False, verbose=False): | |||||
make_asset_dirs(make_copy=make_copy) | make_asset_dirs(make_copy=make_copy) | ||||
# new nodejs build system | # new nodejs build system | ||||
command = 'node ../apps/frappe/frappe/build.js --build' | |||||
command = 'node --use_strict ../apps/frappe/frappe/build.js --build' | |||||
if not no_compress: | if not no_compress: | ||||
command += ' --minify' | command += ' --minify' | ||||
subprocess.call(command.split(' ')) | subprocess.call(command.split(' ')) | ||||
@@ -42,7 +42,7 @@ def watch(no_compress): | |||||
"""watch and rebuild if necessary""" | """watch and rebuild if necessary""" | ||||
# new nodejs file watcher | # new nodejs file watcher | ||||
command = 'node ../apps/frappe/frappe/build.js --watch' | |||||
command = 'node --use_strict ../apps/frappe/frappe/build.js --watch' | |||||
subprocess.call(command.split(' ')) | subprocess.call(command.split(' ')) | ||||
# setup() | # setup() | ||||
@@ -11,7 +11,8 @@ from frappe.core.doctype.communication.comment import (notify_mentions, | |||||
from frappe.core.doctype.communication.email import (validate_email, | from frappe.core.doctype.communication.email import (validate_email, | ||||
notify, _notify, update_parent_status) | notify, _notify, update_parent_status) | ||||
from frappe.utils.bot import BotReply | from frappe.utils.bot import BotReply | ||||
from email.utils import parseaddr | |||||
from frappe.utils import parse_addr | |||||
from collections import Counter | from collections import Counter | ||||
exclude_from_linked_with = True | exclude_from_linked_with = True | ||||
@@ -140,14 +141,9 @@ class Communication(Document): | |||||
else: | else: | ||||
if self.sent_or_received=='Sent': | if self.sent_or_received=='Sent': | ||||
validate_email_add(self.sender, throw=True) | validate_email_add(self.sender, throw=True) | ||||
sender_name, sender_email = parseaddr(self.sender) | |||||
if not sender_name: | |||||
sender_name = get_fullname(sender_email) | |||||
if sender_name == sender_email: | |||||
sender_name = None | |||||
sender_name, sender_email = parse_addr(self.sender) | |||||
if sender_name == sender_email: | |||||
sender_name = None | |||||
self.sender = sender_email | self.sender = sender_email | ||||
self.sender_full_name = sender_name or get_fullname(frappe.session.user) if frappe.session.user!='Administrator' else None | self.sender_full_name = sender_name or get_fullname(frappe.session.user) if frappe.session.user!='Administrator' else None | ||||
@@ -5,9 +5,9 @@ from __future__ import unicode_literals, absolute_import | |||||
from six.moves import range | from six.moves import range | ||||
import frappe | import frappe | ||||
import json | import json | ||||
from email.utils import formataddr, parseaddr | |||||
from email.utils import formataddr | |||||
from frappe.utils import (get_url, get_formatted_email, cint, | from frappe.utils import (get_url, get_formatted_email, cint, | ||||
validate_email_add, split_emails, time_diff_in_seconds) | |||||
validate_email_add, split_emails, time_diff_in_seconds, parse_addr) | |||||
from frappe.utils.file_manager import get_file | from frappe.utils.file_manager import get_file | ||||
from frappe.email.queue import check_email_limit | from frappe.email.queue import check_email_limit | ||||
from frappe.utils.scheduler import log | from frappe.utils.scheduler import log | ||||
@@ -321,11 +321,11 @@ def get_cc(doc, recipients=None, fetched_from_email_account=False): | |||||
# exclude unfollows, recipients and unsubscribes | # exclude unfollows, recipients and unsubscribes | ||||
exclude = [] #added to remove account check | exclude = [] #added to remove account check | ||||
exclude += [d[0] for d in frappe.db.get_all("User", ["name"], {"thread_notify": 0}, as_list=True)] | exclude += [d[0] for d in frappe.db.get_all("User", ["name"], {"thread_notify": 0}, as_list=True)] | ||||
exclude += [(parseaddr(email)[1] or "").lower() for email in recipients] | |||||
exclude += [(parse_addr(email)[1] or "").lower() for email in recipients] | |||||
if fetched_from_email_account: | if fetched_from_email_account: | ||||
# exclude sender when pulling email | # exclude sender when pulling email | ||||
exclude += [parseaddr(doc.sender)[1]] | |||||
exclude += [parse_addr(doc.sender)[1]] | |||||
if doc.reference_doctype and doc.reference_name: | if doc.reference_doctype and doc.reference_name: | ||||
exclude += [d[0] for d in frappe.db.get_all("Email Unsubscribe", ["email"], | exclude += [d[0] for d in frappe.db.get_all("Email Unsubscribe", ["email"], | ||||
@@ -356,7 +356,7 @@ def filter_email_list(doc, email_list, exclude, is_cc=False): | |||||
email_address_list = [] | email_address_list = [] | ||||
for email in list(set(email_list)): | for email in list(set(email_list)): | ||||
email_address = (parseaddr(email)[1] or "").lower() | |||||
email_address = (parse_addr(email)[1] or "").lower() | |||||
if not email_address: | if not email_address: | ||||
continue | continue | ||||
@@ -4,8 +4,27 @@ from __future__ import unicode_literals | |||||
import frappe | import frappe | ||||
import unittest | import unittest | ||||
test_records = frappe.get_test_records('Communication') | test_records = frappe.get_test_records('Communication') | ||||
class TestCommunication(unittest.TestCase): | class TestCommunication(unittest.TestCase): | ||||
pass | |||||
def test_parse_addr(self): | |||||
valid_email_list = ["me@example.com", "a.nonymous@example.com", "name@tag@example.com", | |||||
"foo@example.com", 'Full Name <full@example.com>', | |||||
'"Full Name with quotes and <weird@chars.com>" <weird@example.com>', | |||||
'foo@bar@google.com', 'Surname, Name <name.surname@domain.com>', | |||||
'Purchase@ABC <purchase@abc.com>', 'xyz@abc2.com <xyz@abc.com>', | |||||
'Name [something else] <name@domain.com>', | |||||
'.com@test@yahoo.com'] | |||||
invalid_email_list = ['[invalid!email]', 'invalid-email', | |||||
'tes2', 'e', 'rrrrrrrr', 'manas','[[[sample]]]', | |||||
'[invalid!email].com'] | |||||
for x in valid_email_list: | |||||
self.assertTrue(frappe.utils.parse_addr(x)) | |||||
for x in invalid_email_list: | |||||
self.assertFalse(frappe.utils.parse_addr(x)[0]) | |||||
@@ -770,6 +770,37 @@ | |||||
"set_only_once": 0, | "set_only_once": 0, | ||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | |||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"description": "User can login using Email id or Mobile number", | |||||
"fieldname": "allow_login_using_mobile_number", | |||||
"fieldtype": "Check", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_global_search": 0, | |||||
"in_list_view": 0, | |||||
"in_standard_filter": 0, | |||||
"label": "Allow Login using Mobile Number", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"remember_last_selected_value": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | { | ||||
"allow_bulk_edit": 0, | "allow_bulk_edit": 0, | ||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
@@ -902,7 +933,7 @@ | |||||
"issingle": 1, | "issingle": 1, | ||||
"istable": 0, | "istable": 0, | ||||
"max_attachments": 0, | "max_attachments": 0, | ||||
"modified": "2017-05-11 15:27:11.079447", | |||||
"modified": "2017-05-19 09:12:50.353887", | |||||
"modified_by": "Administrator", | "modified_by": "Administrator", | ||||
"module": "Core", | "module": "Core", | ||||
"name": "System Settings", | "name": "System Settings", | ||||
@@ -14,6 +14,7 @@ | |||||
"engine": "InnoDB", | "engine": "InnoDB", | ||||
"fields": [ | "fields": [ | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -42,6 +43,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -73,6 +75,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -102,6 +105,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -133,6 +137,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -163,6 +168,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -193,6 +199,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 1, | "bold": 1, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -223,6 +230,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -252,6 +260,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 1, | "bold": 1, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -283,6 +292,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -311,6 +321,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -341,6 +352,7 @@ | |||||
"width": "50%" | "width": "50%" | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -370,6 +382,7 @@ | |||||
"unique": 1 | "unique": 1 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -400,6 +413,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -429,6 +443,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -458,6 +473,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -488,6 +504,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -516,6 +533,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -546,6 +564,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 1, | "collapsible": 1, | ||||
@@ -575,6 +594,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -606,6 +626,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -635,6 +656,37 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"fieldname": "mobile_no", | |||||
"fieldtype": "Data", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_global_search": 0, | |||||
"in_list_view": 0, | |||||
"in_standard_filter": 0, | |||||
"label": "Mobile No", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"remember_last_selected_value": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 1 | |||||
}, | |||||
{ | |||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -665,6 +717,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -693,6 +746,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -720,6 +774,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -748,6 +803,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -777,6 +833,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 1, | "collapsible": 1, | ||||
@@ -806,6 +863,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -834,6 +892,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -864,6 +923,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -892,6 +952,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -921,6 +982,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 1, | "collapsible": 1, | ||||
@@ -951,6 +1013,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -981,6 +1044,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1009,6 +1073,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 1, | "collapsible": 1, | ||||
@@ -1038,6 +1103,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1069,6 +1135,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 1, | "collapsible": 1, | ||||
@@ -1099,6 +1166,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1128,6 +1196,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1158,6 +1227,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 1, | "collapsible": 1, | ||||
@@ -1189,6 +1259,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1218,6 +1289,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1248,6 +1320,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1280,6 +1353,7 @@ | |||||
"width": "50%" | "width": "50%" | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1310,6 +1384,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 1, | "collapsible": 1, | ||||
@@ -1340,6 +1415,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1370,6 +1446,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1403,6 +1480,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1432,6 +1510,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1461,6 +1540,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1490,6 +1570,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1520,6 +1601,7 @@ | |||||
"width": "50%" | "width": "50%" | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1550,6 +1632,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1580,6 +1663,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1609,6 +1693,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1639,6 +1724,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 1, | "collapsible": 1, | ||||
@@ -1668,6 +1754,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1696,6 +1783,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1724,6 +1812,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1752,6 +1841,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1780,6 +1870,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1808,6 +1899,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1836,6 +1928,7 @@ | |||||
"unique": 0 | "unique": 0 | ||||
}, | }, | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -1878,7 +1971,7 @@ | |||||
"istable": 0, | "istable": 0, | ||||
"max_attachments": 5, | "max_attachments": 5, | ||||
"menu_index": 0, | "menu_index": 0, | ||||
"modified": "2017-04-01 14:38:25.869060", | |||||
"modified": "2017-05-19 09:12:35.697915", | |||||
"modified_by": "Administrator", | "modified_by": "Administrator", | ||||
"module": "Core", | "module": "Core", | ||||
"name": "User", | "name": "User", | ||||
@@ -149,6 +149,7 @@ frappe.customize_form.set_primary_action = function(frm) { | |||||
callback: function(r) { | callback: function(r) { | ||||
if(!r.exc) { | if(!r.exc) { | ||||
frappe.customize_form.clear_locals_and_refresh(frm); | frappe.customize_form.clear_locals_and_refresh(frm); | ||||
frm.script_manager.trigger("doc_type"); | |||||
} | } | ||||
} | } | ||||
}); | }); | ||||
@@ -7,7 +7,7 @@ import frappe | |||||
from frappe import _ | from frappe import _ | ||||
from frappe.utils import validate_email_add | from frappe.utils import validate_email_add | ||||
from frappe.model.document import Document | from frappe.model.document import Document | ||||
from email.utils import parseaddr | |||||
from frappe.utils import parse_addr | |||||
class EmailGroup(Document): | class EmailGroup(Document): | ||||
def onload(self): | def onload(self): | ||||
@@ -26,7 +26,7 @@ class EmailGroup(Document): | |||||
for user in frappe.db.get_all(doctype, [email_field, unsubscribed_field or "name"]): | for user in frappe.db.get_all(doctype, [email_field, unsubscribed_field or "name"]): | ||||
try: | try: | ||||
email = parseaddr(user.get(email_field))[1] | |||||
email = parse_addr(user.get(email_field))[1] | |||||
if email: | if email: | ||||
frappe.get_doc({ | frappe.get_doc({ | ||||
"doctype": "Email Group Member", | "doctype": "Email Group Member", | ||||
@@ -14,6 +14,7 @@ from frappe.utils.scheduler import log | |||||
from frappe.email.queue import send | from frappe.email.queue import send | ||||
from frappe.email.doctype.email_group.email_group import add_subscribers | from frappe.email.doctype.email_group.email_group import add_subscribers | ||||
from frappe.utils.file_manager import get_file | from frappe.utils.file_manager import get_file | ||||
from frappe.utils import parse_addr | |||||
class Newsletter(Document): | class Newsletter(Document): | ||||
@@ -135,17 +136,15 @@ def return_unsubscribed_page(email, name): | |||||
def create_lead(email_id): | def create_lead(email_id): | ||||
"""create a lead if it does not exist""" | """create a lead if it does not exist""" | ||||
from email.utils import parseaddr | |||||
from frappe.model.naming import get_default_naming_series | from frappe.model.naming import get_default_naming_series | ||||
real_name, email_id = parseaddr(email_id) | |||||
full_name, email_id = parse_addr(email_id) | |||||
if frappe.db.get_value("Lead", {"email_id": email_id}): | if frappe.db.get_value("Lead", {"email_id": email_id}): | ||||
return | return | ||||
lead = frappe.get_doc({ | lead = frappe.get_doc({ | ||||
"doctype": "Lead", | "doctype": "Lead", | ||||
"email_id": email_id, | "email_id": email_id, | ||||
"lead_name": real_name or email_id, | |||||
"lead_name": full_name or email_id, | |||||
"status": "Lead", | "status": "Lead", | ||||
"naming_series": get_default_naming_series("Lead"), | "naming_series": get_default_naming_series("Lead"), | ||||
"company": frappe.db.get_default("Company"), | "company": frappe.db.get_default("Company"), | ||||
@@ -8,6 +8,7 @@ from frappe.email.smtp import get_outgoing_email_account | |||||
from frappe.utils import (get_url, scrub_urls, strip, expand_relative_urls, cint, | from frappe.utils import (get_url, scrub_urls, strip, expand_relative_urls, cint, | ||||
split_emails, to_markdown, markdown, encode, random_string) | split_emails, to_markdown, markdown, encode, random_string) | ||||
import email.utils | import email.utils | ||||
from frappe.utils import parse_addr | |||||
def get_email(recipients, sender='', msg='', subject='[No Subject]', | def get_email(recipients, sender='', msg='', subject='[No Subject]', | ||||
text_content = None, footer=None, print_html=None, formatted=None, attachments=None, | text_content = None, footer=None, print_html=None, formatted=None, attachments=None, | ||||
@@ -179,8 +180,7 @@ class EMail: | |||||
def replace_sender(self): | def replace_sender(self): | ||||
if cint(self.email_account.always_use_account_email_id_as_sender): | if cint(self.email_account.always_use_account_email_id_as_sender): | ||||
self.set_header('X-Original-From', self.sender) | self.set_header('X-Original-From', self.sender) | ||||
sender_name, sender_email = email.utils.parseaddr(self.sender) | |||||
sender_name, sender_email = parse_addr(self.sender) | |||||
self.sender = email.utils.formataddr((sender_name or self.email_account.name, self.email_account.email_id)) | self.sender = email.utils.formataddr((sender_name or self.email_account.name, self.email_account.email_id)) | ||||
def set_message_id(self, message_id, is_notification=False): | def set_message_id(self, message_id, is_notification=False): | ||||
@@ -9,7 +9,7 @@ from email.header import decode_header | |||||
import frappe | import frappe | ||||
from frappe import _ | from frappe import _ | ||||
from frappe.utils import (extract_email_id, convert_utc_to_user_timezone, now, | from frappe.utils import (extract_email_id, convert_utc_to_user_timezone, now, | ||||
cint, cstr, strip, markdown) | |||||
cint, cstr, strip, markdown, parse_addr) | |||||
from frappe.utils.scheduler import log | from frappe.utils.scheduler import log | ||||
from frappe.utils.file_manager import get_random_filename, save_file, MaxFileSizeReachedError | from frappe.utils.file_manager import get_random_filename, save_file, MaxFileSizeReachedError | ||||
import re | import re | ||||
@@ -411,7 +411,7 @@ class Email: | |||||
if self.from_email: | if self.from_email: | ||||
self.from_email = self.from_email.lower() | self.from_email = self.from_email.lower() | ||||
self.from_real_name = email.utils.parseaddr(_from_email)[0] if "@" in _from_email else _from_email | |||||
self.from_real_name = parse_addr(_from_email)[0] if "@" in _from_email else _from_email | |||||
def decode_email(self, email): | def decode_email(self, email): | ||||
if not email: return | if not email: return | ||||
@@ -5,9 +5,6 @@ import frappe | |||||
''' | ''' | ||||
FrappeClient is a library that helps you connect with other frappe systems | FrappeClient is a library that helps you connect with other frappe systems | ||||
''' | ''' | ||||
class AuthError(Exception): | class AuthError(Exception): | ||||
@@ -29,7 +29,11 @@ | |||||
</div> | </div> | ||||
{% endif %} | {% endif %} | ||||
<div class="print-format"> | |||||
<div class="print-format {% if landscape %} landscape {% endif %}" | |||||
{% if columns.length > 20 %} | |||||
style="font-size: 4.0pt" | |||||
{% endif %} | |||||
> | |||||
{% if print_settings.letter_head %} | {% if print_settings.letter_head %} | ||||
<div {% if print_settings.repeat_header_footer %} id="header-html" class="hidden-pdf" {% endif %}> | <div {% if print_settings.repeat_header_footer %} id="header-html" class="hidden-pdf" {% endif %}> | ||||
<div class="letter-head">{{ print_settings.letter_head.header }}</div> | <div class="letter-head">{{ print_settings.letter_head.header }}</div> | ||||
@@ -29,8 +29,7 @@ frappe.search.AwesomeBar = Class.extend({ | |||||
}, | }, | ||||
item: function(item, term) { | item: function(item, term) { | ||||
var d = this.get_item(item.value); | var d = this.get_item(item.value); | ||||
var name = d.prefix ? __(d.prefix + ' ' + (d.label || d.value)) : | |||||
__(d.label || d.value); | |||||
var name = __(d.label || d.value); | |||||
var html = '<span>' + name + '</span>'; | var html = '<span>' + name + '</span>'; | ||||
if(d.description && d.value!==d.description) { | if(d.description && d.value!==d.description) { | ||||
html += '<br><span class="text-muted ellipsis">' + __(d.description) + '</span>'; | html += '<br><span class="text-muted ellipsis">' + __(d.description) + '</span>'; | ||||
@@ -123,8 +122,7 @@ frappe.search.AwesomeBar = Class.extend({ | |||||
add_help: function() { | add_help: function() { | ||||
this.options.push({ | this.options.push({ | ||||
label: __("Help on Search"), | |||||
value: "Help on Search", | |||||
value: __("Help on Search"), | |||||
index: -10, | index: -10, | ||||
default: "Help", | default: "Help", | ||||
onclick: function() { | onclick: function() { | ||||
@@ -140,7 +138,7 @@ frappe.search.AwesomeBar = Class.extend({ | |||||
<tr><td>'+__("Calculate")+'</td><td>'+ | <tr><td>'+__("Calculate")+'</td><td>'+ | ||||
__("e.g. (55 + 434) / 4 or =Math.sin(Math.PI/2)...")+'</td></tr>\ | __("e.g. (55 + 434) / 4 or =Math.sin(Math.PI/2)...")+'</td></tr>\ | ||||
</table>' | </table>' | ||||
msgprint(txt, "Search Help"); | |||||
msgprint(txt, __("Search Help")); | |||||
} | } | ||||
}); | }); | ||||
}, | }, | ||||
@@ -208,8 +206,8 @@ frappe.search.AwesomeBar = Class.extend({ | |||||
make_global_search: function(txt) { | make_global_search: function(txt) { | ||||
var me = this; | var me = this; | ||||
this.options.push({ | this.options.push({ | ||||
label: __("Search for '" + txt.bold() + "'"), | |||||
value: __("Search for '" + txt + "'"), | |||||
label: __("Search for '{0}'", [txt.bold()]), | |||||
value: __("Search for '{0}'", [txt]), | |||||
match: txt, | match: txt, | ||||
index: 100, | index: 100, | ||||
default: "Search", | default: "Search", | ||||
@@ -87,8 +87,7 @@ frappe.search.utils = { | |||||
if(level) { | if(level) { | ||||
out.push({ | out.push({ | ||||
type: "In List", | type: "In List", | ||||
prefix: __("Find {0} in ", [__(parts[0]).bold()]), | |||||
label: me.bolden_match_part(__(item), parts[1]), | |||||
label: __('Find {0} in {1}', [__(parts[0]), me.bolden_match_part(__(item), parts[1])]), | |||||
value: __('Find {0} in {1}', [__(parts[0]), __(item)]), | value: __('Find {0} in {1}', [__(parts[0]), __(item)]), | ||||
route_options: {"name": ["like", "%" + parts[0] + "%"]}, | route_options: {"name": ["like", "%" + parts[0] + "%"]}, | ||||
index: 1 + level, | index: 1 + level, | ||||
@@ -110,8 +109,7 @@ frappe.search.utils = { | |||||
if(level) { | if(level) { | ||||
out.push({ | out.push({ | ||||
type: "New", | type: "New", | ||||
prefix: "New ", | |||||
label: me.bolden_match_part(__(item), keywords.substr(4)), | |||||
label: __("New {0}", [me.bolden_match_part(__(item), keywords.substr(4))]), | |||||
value: __("New {0}", [__(item)]), | value: __("New {0}", [__(item)]), | ||||
index: 1 + level, | index: 1 + level, | ||||
match: item, | match: item, | ||||
@@ -131,8 +129,8 @@ frappe.search.utils = { | |||||
var option = function(type, route, order) { | var option = function(type, route, order) { | ||||
return { | return { | ||||
type: type, | type: type, | ||||
label: __("{0}" + " " + type, [me.bolden_match_part(__(target), keywords)]), | |||||
value: __(__(target) + " " + type), | |||||
label: me.bolden_match_part(__(target), keywords) + " " + __(type), | |||||
value: __(target) + " " + __(type), | |||||
index: level + order, | index: level + order, | ||||
match: target, | match: target, | ||||
route: route, | route: route, | ||||
@@ -191,8 +189,7 @@ frappe.search.utils = { | |||||
route = ["query-report", item]; | route = ["query-report", item]; | ||||
out.push({ | out.push({ | ||||
type: "Report", | type: "Report", | ||||
prefix: "Report ", | |||||
label: me.bolden_match_part(__(item), keywords), | |||||
label: __("Report {0}" , [me.bolden_match_part(__(item), keywords)]), | |||||
value: __("Report {0}" , [__(item)]), | value: __("Report {0}" , [__(item)]), | ||||
index: level, | index: level, | ||||
route: route | route: route | ||||
@@ -216,8 +213,7 @@ frappe.search.utils = { | |||||
var page = me.pages[item]; | var page = me.pages[item]; | ||||
out.push({ | out.push({ | ||||
type: "Page", | type: "Page", | ||||
prefix: "Open ", | |||||
label: me.bolden_match_part(__(item), keywords), | |||||
label: __("Open {0}", [me.bolden_match_part(__(item), keywords)]), | |||||
value: __("Open {0}", [__(item)]), | value: __("Open {0}", [__(item)]), | ||||
match: item, | match: item, | ||||
index: level, | index: level, | ||||
@@ -229,8 +225,6 @@ frappe.search.utils = { | |||||
if(__('calendar').indexOf(keywords.toLowerCase()) === 0) { | if(__('calendar').indexOf(keywords.toLowerCase()) === 0) { | ||||
out.push({ | out.push({ | ||||
type: "Calendar", | type: "Calendar", | ||||
prefix: "Open ", | |||||
label: __('Calendar'), | |||||
value: __("Open {0}", [__(target)]), | value: __("Open {0}", [__(target)]), | ||||
index: me.fuzzy_search(keywords, 'Calendar'), | index: me.fuzzy_search(keywords, 'Calendar'), | ||||
match: target, | match: target, | ||||
@@ -240,8 +234,6 @@ frappe.search.utils = { | |||||
if(__('email inbox').indexOf(keywords.toLowerCase()) === 0) { | if(__('email inbox').indexOf(keywords.toLowerCase()) === 0) { | ||||
out.push({ | out.push({ | ||||
type: "Inbox", | type: "Inbox", | ||||
prefix: "Open ", | |||||
label: __('Email Inbox'), | |||||
value: __("Open {0}", [__('Email Inbox')]), | value: __("Open {0}", [__('Email Inbox')]), | ||||
index: me.fuzzy_search(keywords, 'email inbox'), | index: me.fuzzy_search(keywords, 'email inbox'), | ||||
match: target, | match: target, | ||||
@@ -261,8 +253,7 @@ frappe.search.utils = { | |||||
if(module._doctype) return; | if(module._doctype) return; | ||||
ret = { | ret = { | ||||
type: "Module", | type: "Module", | ||||
prefix: "Open ", | |||||
label: me.bolden_match_part(__(item), keywords), | |||||
label: __("Open {0}", [me.bolden_match_part(__(item), keywords)]), | |||||
value: __("Open {0}", [__(item)]), | value: __("Open {0}", [__(item)]), | ||||
index: level, | index: level, | ||||
} | } | ||||
@@ -575,6 +566,5 @@ frappe.search.utils = { | |||||
return rendered; | return rendered; | ||||
} | } | ||||
} | |||||
} | |||||
}, | |||||
} |
@@ -77,7 +77,8 @@ frappe.views.ReportView = frappe.ui.BaseList.extend({ | |||||
this.add_totals_row = 0; | this.add_totals_row = 0; | ||||
this.page = this.parent.page; | this.page = this.parent.page; | ||||
this._body = $('<div>').appendTo(this.page.main); | this._body = $('<div>').appendTo(this.page.main); | ||||
this.page_title = __('Report')+ ': ' + __(this.docname ? (this.doctype + ' - ' + this.docname) : this.doctype); | |||||
this.page_title = __('Report')+ ': ' + (this.docname ? | |||||
__(this.doctype) + ' - ' + __(this.docname) : __(this.doctype)); | |||||
this.page.set_title(this.page_title); | this.page.set_title(this.page_title); | ||||
this.init_user_settings(); | this.init_user_settings(); | ||||
this.make({ | this.make({ | ||||
@@ -723,7 +724,7 @@ frappe.views.ReportView = frappe.ui.BaseList.extend({ | |||||
} | } | ||||
open_url_post(frappe.request.url, args); | open_url_post(frappe.request.url, args); | ||||
}, __("Export Report: " + me.doctype), __("Download")); | |||||
}, __("Export Report: {0}",[__(me.doctype)]), __("Download")); | |||||
}, true); | }, true); | ||||
}, | }, | ||||
@@ -95,6 +95,11 @@ frappe.render_grid = function(opts) { | |||||
} | } | ||||
} | } | ||||
// show landscape view if columns more than 10 | |||||
if(opts.columns.length > 10) { | |||||
opts.landscape = true; | |||||
} | |||||
// render content | // render content | ||||
if(!opts.content) { | if(!opts.content) { | ||||
opts.content = frappe.render_template("print_grid", opts); | opts.content = frappe.render_template("print_grid", opts); | ||||
@@ -106,6 +111,11 @@ frappe.render_grid = function(opts) { | |||||
var html = frappe.render_template("print_template", opts); | var html = frappe.render_template("print_template", opts); | ||||
var w = window.open(); | var w = window.open(); | ||||
if(!w) { | |||||
frappe.msgprint(__("Please enable pop-ups in your browser")) | |||||
} | |||||
w.document.write(html); | w.document.write(html); | ||||
w.document.close(); | w.document.close(); | ||||
} | } |
@@ -12,6 +12,11 @@ | |||||
margin: auto; | margin: auto; | ||||
} | } | ||||
.print-format.landscape { | |||||
max-width: 11.69in; | |||||
padding: 0.2in; | |||||
} | |||||
.page-break { | .page-break { | ||||
padding: 30px 0px; | padding: 30px 0px; | ||||
border-bottom: 1px dashed #888; | border-bottom: 1px dashed #888; | ||||
@@ -8,10 +8,9 @@ from werkzeug.test import Client | |||||
import os, re, urllib, sys, json, hashlib, requests, traceback | import os, re, urllib, sys, json, hashlib, requests, traceback | ||||
from markdown2 import markdown as _markdown | from markdown2 import markdown as _markdown | ||||
from .html_utils import sanitize_html | from .html_utils import sanitize_html | ||||
import frappe | import frappe | ||||
from frappe.utils.identicon import Identicon | from frappe.utils.identicon import Identicon | ||||
from email.utils import parseaddr, formataddr | |||||
# utility functions like cint, int, flt, etc. | # utility functions like cint, int, flt, etc. | ||||
from frappe.utils.data import * | from frappe.utils.data import * | ||||
@@ -62,9 +61,8 @@ def get_formatted_email(user): | |||||
def extract_email_id(email): | def extract_email_id(email): | ||||
"""fetch only the email part of the Email Address""" | """fetch only the email part of the Email Address""" | ||||
from email.utils import parseaddr | |||||
fullname, email_id = parseaddr(email) | |||||
if isinstance(email_id, basestring) and not isinstance(email_id, unicode): | |||||
full_name, email_id = parse_addr(email) | |||||
if email_id and isinstance(email_id, basestring) and not isinstance(email_id, unicode): | |||||
email_id = email_id.decode("utf-8", "ignore") | email_id = email_id.decode("utf-8", "ignore") | ||||
return email_id | return email_id | ||||
@@ -88,13 +86,12 @@ def validate_email_add(email_str, throw=False): | |||||
else: | else: | ||||
e = extract_email_id(e) | e = extract_email_id(e) | ||||
match = re.match("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", e.lower()) | |||||
match = re.match("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", e.lower()) if e else None | |||||
if not match: | if not match: | ||||
_valid = False | _valid = False | ||||
else: | else: | ||||
matched = match.group(0) | matched = match.group(0) | ||||
if match: | if match: | ||||
match = matched==e.lower() | match = matched==e.lower() | ||||
@@ -450,18 +447,47 @@ def markdown(text, sanitize=True, linkify=True): | |||||
return html | return html | ||||
def sanitize_email(emails): | def sanitize_email(emails): | ||||
from email.utils import parseaddr, formataddr | |||||
sanitized = [] | sanitized = [] | ||||
for e in split_emails(emails): | for e in split_emails(emails): | ||||
if not validate_email_add(e): | if not validate_email_add(e): | ||||
continue | continue | ||||
fullname, email_id = parseaddr(e) | |||||
sanitized.append(formataddr((fullname, email_id))) | |||||
full_name, email_id = parse_addr(e) | |||||
sanitized.append(formataddr((full_name, email_id))) | |||||
return ", ".join(sanitized) | return ", ".join(sanitized) | ||||
def parse_addr(email_string): | |||||
""" | |||||
Return email_id and user_name based on email string | |||||
Raise error if email string is not valid | |||||
""" | |||||
name, email = parseaddr(email_string) | |||||
if check_format(email): | |||||
return (name, email) | |||||
else: | |||||
email_regex = re.compile(r"([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)") | |||||
email_list = re.findall(email_regex, email_string) | |||||
if len(email_list) > 0 and check_format(email_list[0]): | |||||
#take only first email address | |||||
return (name, email_list[0]) | |||||
return (None, email) | |||||
def check_format(email_id): | |||||
""" | |||||
Check if email_id is valid. valid email:text@example.com | |||||
String check ensures that email_id contains both '.' and | |||||
'@' and index of '@' is less than '.' | |||||
""" | |||||
is_valid = False | |||||
try: | |||||
pos = email_id.rindex("@") | |||||
is_valid = pos > 0 and (email_id.rindex(".") > pos) and (len(email_id) - pos > 4) | |||||
except Exception, e: | |||||
#print(e) | |||||
pass | |||||
return is_valid | |||||
def get_installed_apps_info(): | def get_installed_apps_info(): | ||||
out = [] | out = [] | ||||
for app in frappe.get_installed_apps(): | for app in frappe.get_installed_apps(): | ||||
@@ -102,10 +102,11 @@ def get_allowed_functions_for_jenv(): | |||||
"user": user, | "user": user, | ||||
"get_fullname": frappe.utils.get_fullname, | "get_fullname": frappe.utils.get_fullname, | ||||
"get_gravatar": frappe.utils.get_gravatar_url, | "get_gravatar": frappe.utils.get_gravatar_url, | ||||
"full_name": getattr(frappe.local, "session", None) and frappe.local.session.data.full_name or "Guest", | |||||
"full_name": frappe.local.session.data.full_name if getattr(frappe.local, "session", None) else "Guest", | |||||
"render_template": frappe.render_template, | "render_template": frappe.render_template, | ||||
'session': { | 'session': { | ||||
'user': user | |||||
'user': user, | |||||
'csrf_token': frappe.local.session.data.csrf_token if getattr(frappe.local, "session", None) else '' | |||||
}, | }, | ||||
}, | }, | ||||
"autodoc": { | "autodoc": { | ||||
@@ -16,7 +16,12 @@ | |||||
</div> | </div> | ||||
<input type="text" id="login_email" | <input type="text" id="login_email" | ||||
class="form-control" placeholder="{{ _('Email address') }}" required autofocus> | |||||
class="form-control" placeholder="{{ | |||||
_('Email address or Mobile number') | |||||
if frappe.utils.cint(frappe.db.get_value('System Settings', 'System Settings', 'allow_login_using_mobile_number')) | |||||
else _('Email address') }}" | |||||
required autofocus> | |||||
<input type="password" id="login_password" | <input type="password" id="login_password" | ||||
class="form-control" placeholder="{{ _('Password') }}" required> | class="form-control" placeholder="{{ _('Password') }}" required> | ||||
@@ -0,0 +1,30 @@ | |||||
{ | |||||
"name": "frappe", | |||||
"scripts": { | |||||
"test": "echo \"Error: no test specified\" && exit 1" | |||||
}, | |||||
"repository": { | |||||
"type": "git", | |||||
"url": "git+https://github.com/frappe/frappe.git" | |||||
}, | |||||
"author": "Frappé Technologies Pvt. Ltd.", | |||||
"license": "MIT", | |||||
"bugs": { | |||||
"url": "https://github.com/frappe/frappe/issues" | |||||
}, | |||||
"homepage": "https://frappe.io", | |||||
"dependencies": { | |||||
"babel-core": "^6.24.1", | |||||
"babel-preset-babili": "0.0.12", | |||||
"babel-preset-es2015": "^6.24.1", | |||||
"babel-preset-es2016": "^6.24.1", | |||||
"babel-preset-es2017": "^6.24.1", | |||||
"chokidar": "^1.7.0", | |||||
"cookie": "^0.3.1", | |||||
"express": "^4.15.3", | |||||
"less": "^2.7.2", | |||||
"redis": "^2.7.1", | |||||
"socket.io": "^2.0.1", | |||||
"superagent": "^3.5.2" | |||||
} | |||||
} |
@@ -6,7 +6,7 @@ httplib2 | |||||
jinja2 | jinja2 | ||||
markdown2 | markdown2 | ||||
markupsafe | markupsafe | ||||
mysql-python==1.2.5 | |||||
mysqlclient==1.3.8 | |||||
python-geoip | python-geoip | ||||
python-geoip-geolite2 | python-geoip-geolite2 | ||||
python-dateutil | python-dateutil | ||||