From 7a12d3399f40f7e7ab0a1c64c4e414a33da4cf21 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Tue, 22 Jan 2019 23:01:14 +0530 Subject: [PATCH 01/35] fix(email): Pass args as unicode in Py2 & bytes in Py3 to SMTP.login --- frappe/email/smtp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/email/smtp.py b/frappe/email/smtp.py index fa6b92fc33..1794c8215d 100644 --- a/frappe/email/smtp.py +++ b/frappe/email/smtp.py @@ -210,7 +210,7 @@ class SMTPServer: self._sess.ehlo() if self.login and self.password: - ret = self._sess.login((self.login or ""), (self.password or "")) + ret = self._sess.login(str(self.login or ""), str(self.password or "")) # check if logged correctly if ret[0]!=235: From 6b72faf44fa7f9ea350dad89d309bcf1729fbc25 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 23 Jan 2019 16:39:55 +0530 Subject: [PATCH 02/35] style: Linting fixes (#6809) * style: Remove unused imports * style: Remove unused local variables --- frappe/commands/scheduler.py | 2 +- frappe/commands/translate.py | 1 - frappe/core/utils.py | 2 +- frappe/desk/query_builder.py | 16 +++++----------- frappe/desk/reportview.py | 1 - frappe/email/email_body.py | 2 +- frappe/email/test_email_body.py | 2 +- frappe/model/__init__.py | 1 - frappe/model/base_document.py | 2 +- frappe/modules/export_file.py | 2 +- frappe/tests/__init__.py | 8 ++++---- frappe/tests/test_fmt_money.py | 3 +-- frappe/tests/test_form_load.py | 2 +- frappe/tests/test_geo_ip.py | 1 - frappe/tests/test_permissions.py | 4 +--- frappe/tests/test_twofactor.py | 2 +- frappe/utils/backups.py | 2 -- frappe/utils/boilerplate.py | 2 +- frappe/utils/change_log.py | 7 +++---- frappe/utils/data.py | 2 +- frappe/utils/dateutils.py | 4 ++-- frappe/utils/error.py | 1 - frappe/utils/file_manager.py | 1 - frappe/utils/goal.py | 2 +- frappe/utils/password_strength.py | 2 +- frappe/utils/pdf.py | 2 +- frappe/utils/print_format.py | 7 ++----- frappe/utils/reset_doc.py | 5 ++--- frappe/utils/xlsxutils.py | 5 ++--- frappe/website/render.py | 4 ++-- frappe/www/profile.py | 5 +---- frappe/www/rss.py | 1 - frappe/www/sitemap.py | 2 -- frappe/www/website_theme.py | 1 - 34 files changed, 38 insertions(+), 68 deletions(-) diff --git a/frappe/commands/scheduler.py b/frappe/commands/scheduler.py index caa0d7ed62..8d1cca286d 100755 --- a/frappe/commands/scheduler.py +++ b/frappe/commands/scheduler.py @@ -1,6 +1,6 @@ from __future__ import unicode_literals, absolute_import, print_function import click -import json, sys +import sys import frappe from frappe.utils import cint from frappe.commands import pass_context, get_site diff --git a/frappe/commands/translate.py b/frappe/commands/translate.py index 1a94210566..5a48e2b409 100644 --- a/frappe/commands/translate.py +++ b/frappe/commands/translate.py @@ -1,6 +1,5 @@ from __future__ import unicode_literals, absolute_import, print_function import click -import frappe from frappe.commands import pass_context, get_site # translation diff --git a/frappe/core/utils.py b/frappe/core/utils.py index 89aba20cd8..42193d0cb9 100644 --- a/frappe/core/utils.py +++ b/frappe/core/utils.py @@ -2,7 +2,7 @@ # MIT License. See license.txt import frappe -from frappe import _ + def get_parent_doc(doc): """Returns document of `reference_doctype`, `reference_doctype`""" diff --git a/frappe/desk/query_builder.py b/frappe/desk/query_builder.py index 2acf0c4526..a952e86cdb 100644 --- a/frappe/desk/query_builder.py +++ b/frappe/desk/query_builder.py @@ -1,5 +1,5 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# MIT License. See license.txt +# MIT License. See license.txt from __future__ import unicode_literals import frappe @@ -78,7 +78,7 @@ def add_match_conditions(q, tl): q = q[0] + condition_st + '(' + ' OR '.join(sl) + ') ' + condition_end + q[1] else: q = q + condition_st + '(' + ' OR '.join(sl) + ')' - + return q def guess_type(m): @@ -178,7 +178,7 @@ def runquery(q='', ret=0, from_export=0): meta = get_sql_meta(tl) q = add_match_conditions(q, tl) - + # replace special variables q = q.replace('__user', frappe.session.user) q = q.replace('__today', frappe.utils.nowdate()) @@ -223,9 +223,6 @@ def runquery(q='', ret=0, from_export=0): def runquery_csv(): global out - # run query - res = runquery(from_export = 1) - q = frappe.form_dict.get('query') rep_name = frappe.form_dict.get('report_name') @@ -237,9 +234,6 @@ def runquery_csv(): if not rep_name: rep_name = 'DataExport' - # Headings - heads = [] - rows = [[rep_name], out['colnames']] + out['values'] from six import StringIO @@ -264,9 +258,9 @@ def add_limit_to_query(query, args): if args.get('limit_page_length'): query += """ limit %(limit_start)s, %(limit_page_length)s""" - + import frappe.utils args['limit_start'] = frappe.utils.cint(args.get('limit_start')) args['limit_page_length'] = frappe.utils.cint(args.get('limit_page_length')) - + return query, args diff --git a/frappe/desk/reportview.py b/frappe/desk/reportview.py index 76dbf38d11..7c6e7a4b75 100644 --- a/frappe/desk/reportview.py +++ b/frappe/desk/reportview.py @@ -45,7 +45,6 @@ def get_form_params(): else: data["save_user_settings"] = True - doctype = data["doctype"] fields = data["fields"] for field in fields: diff --git a/frappe/email/email_body.py b/frappe/email/email_body.py index f41e6d76c9..0cdaa66a58 100755 --- a/frappe/email/email_body.py +++ b/frappe/email/email_body.py @@ -6,7 +6,7 @@ import frappe, re, os from frappe.utils.pdf import get_pdf from frappe.email.smtp import get_outgoing_email_account from frappe.utils import (get_url, scrub_urls, strip, expand_relative_urls, cint, - split_emails, to_markdown, markdown, encode, random_string, parse_addr) + split_emails, to_markdown, markdown, random_string, parse_addr) import email.utils from six import iteritems, text_type, string_types from email.mime.multipart import MIMEMultipart diff --git a/frappe/email/test_email_body.py b/frappe/email/test_email_body.py index 3f6502cdd4..b0bfddd4f0 100644 --- a/frappe/email/test_email_body.py +++ b/frappe/email/test_email_body.py @@ -2,7 +2,7 @@ # License: GNU General Public License v3. See license.txt from __future__ import unicode_literals -import frappe, unittest, os, base64 +import unittest, os, base64 from frappe.email.email_body import (replace_filename_with_cid, get_email, inline_style_in_html, get_header) diff --git a/frappe/model/__init__.py b/frappe/model/__init__.py index f4f8207ba0..8c8a4bea32 100644 --- a/frappe/model/__init__.py +++ b/frappe/model/__init__.py @@ -4,7 +4,6 @@ # model __init__.py from __future__ import unicode_literals import frappe -import json no_value_fields = ('Section Break', 'Column Break', 'HTML', 'Table', 'Button', 'Image', diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index d97c580f3d..3ce9e7f854 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -6,7 +6,7 @@ from six import iteritems, string_types import datetime import frappe, sys from frappe import _ -from frappe.utils import (cint, flt, now, cstr, strip_html, getdate, get_datetime, to_timedelta, +from frappe.utils import (cint, flt, now, cstr, strip_html, sanitize_html, sanitize_email, cast_fieldtype) from frappe.model import default_fields from frappe.model.naming import set_new_name diff --git a/frappe/modules/export_file.py b/frappe/modules/export_file.py index 275db10b13..66a6a9f6b7 100644 --- a/frappe/modules/export_file.py +++ b/frappe/modules/export_file.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals -import frappe, os, json +import frappe, os import frappe.model from frappe.modules import scrub, get_module_path, scrub_dt_dn diff --git a/frappe/tests/__init__.py b/frappe/tests/__init__.py index b00c7368cc..d8426429bb 100644 --- a/frappe/tests/__init__.py +++ b/frappe/tests/__init__.py @@ -14,7 +14,7 @@ def insert_test_data(doctype, sort_fn=None): def get_test_doclist(doctype, name=None): """get test doclist, collection of doclists""" - import os, frappe + import os from frappe import conf from frappe.modules.utils import peval_doclist from frappe.modules import scrub @@ -22,17 +22,17 @@ def get_test_doclist(doctype, name=None): doctype = scrub(doctype) doctype_path = os.path.join(os.path.dirname(os.path.abspath(conf.__file__)), conf.test_data_path, doctype) - + if name: with open(os.path.join(doctype_path, scrub(name) + ".json"), 'r') as txtfile: doclist = peval_doclist(txtfile.read()) return doclist - + else: all_doclists = [] for fname in filter(lambda n: n.endswith(".json"), os.listdir(doctype_path)): with open(os.path.join(doctype_path, scrub(fname)), 'r') as txtfile: all_doclists.append(peval_doclist(txtfile.read())) - + return all_doclists diff --git a/frappe/tests/test_fmt_money.py b/frappe/tests/test_fmt_money.py index 888360d097..a1321658b7 100644 --- a/frappe/tests/test_fmt_money.py +++ b/frappe/tests/test_fmt_money.py @@ -3,8 +3,7 @@ from __future__ import unicode_literals import frappe -from frappe import _ -from frappe.utils import flt, cstr, fmt_money +from frappe.utils import fmt_money import unittest class TestFmtMoney(unittest.TestCase): diff --git a/frappe/tests/test_form_load.py b/frappe/tests/test_form_load.py index d07e61c600..11dada17d0 100644 --- a/frappe/tests/test_form_load.py +++ b/frappe/tests/test_form_load.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe, unittest from frappe.desk.form.load import getdoctype, getdoc from frappe.core.page.permission_manager.permission_manager import update, reset -from frappe.permissions import get_valid_perms + class TestFormLoad(unittest.TestCase): def test_load(self): diff --git a/frappe/tests/test_geo_ip.py b/frappe/tests/test_geo_ip.py index 23a2881ec5..b292e43ba5 100644 --- a/frappe/tests/test_geo_ip.py +++ b/frappe/tests/test_geo_ip.py @@ -2,7 +2,6 @@ # MIT License. See license.txt from __future__ import unicode_literals -import frappe import unittest class TestGeoIP(unittest.TestCase): diff --git a/frappe/tests/test_permissions.py b/frappe/tests/test_permissions.py index 13106697c5..465034d7a2 100644 --- a/frappe/tests/test_permissions.py +++ b/frappe/tests/test_permissions.py @@ -7,11 +7,9 @@ from __future__ import unicode_literals import frappe import frappe.defaults import unittest -import json import frappe.model.meta from frappe.permissions import (add_user_permission, remove_user_permission, - clear_user_permissions_for_doctype, get_doc_permissions, add_permission, - get_valid_perms) + clear_user_permissions_for_doctype, get_doc_permissions, add_permission) from frappe.core.page.permission_manager.permission_manager import update, reset from frappe.test_runner import make_test_records_for_doctype from frappe.core.doctype.user_permission.user_permission import clear_user_permissions diff --git a/frappe/tests/test_twofactor.py b/frappe/tests/test_twofactor.py index b5eccec81d..c98cf213b2 100644 --- a/frappe/tests/test_twofactor.py +++ b/frappe/tests/test_twofactor.py @@ -9,7 +9,7 @@ from frappe.auth import HTTPRequest from frappe.utils import cint from frappe.twofactor import (should_run_2fa, authenticate_for_2factor, get_cached_user_pass, two_factor_is_enabled_for_, confirm_otp_token, get_otpsecret_for_, get_verification_obj, - render_string_template, two_factor_is_enabled) + render_string_template) import time diff --git a/frappe/utils/backups.py b/frappe/utils/backups.py index 7254ba7fd4..4ec68e536d 100644 --- a/frappe/utils/backups.py +++ b/frappe/utils/backups.py @@ -58,8 +58,6 @@ class BackupGenerator: self.backup_path_private_files = last_private_file def set_backup_file_name(self): - import random - todays_date = now_datetime().strftime('%Y%m%d_%H%M%S') site = frappe.local.site or frappe.generate_hash(length=8) site = site.replace('.', '_') diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index 6da734916c..abb0a41aa6 100755 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -6,7 +6,7 @@ from __future__ import unicode_literals, print_function from six.moves import input import frappe, os, re -from frappe.utils import touch_file, encode, cstr +from frappe.utils import touch_file, cstr def make_boilerplate(dest, app_name): if not os.path.exists(dest): diff --git a/frappe/utils/change_log.py b/frappe/utils/change_log.py index 22de21ea93..c63cd4c34d 100644 --- a/frappe/utils/change_log.py +++ b/frappe/utils/change_log.py @@ -11,7 +11,7 @@ import subprocess # nosec from frappe.utils import cstr from frappe.utils.gitutils import get_app_branch from frappe import _, safe_decode -import git + def get_change_log(user=None): if not user: user = frappe.session.user @@ -123,7 +123,7 @@ def get_app_branch(app): result = safe_decode(result) result = result.strip() return result - except Exception as e: + except Exception: return '' def get_app_last_commit_ref(app): @@ -133,7 +133,7 @@ def get_app_last_commit_ref(app): result = safe_decode(result) result = result.strip() return result - except Exception as e: + except Exception: return '' def check_for_update(): @@ -222,7 +222,6 @@ def show_update_popup(): return updates = json.loads(update_info) - current_versions = get_versions() # Check if user is int the set of users to send update message to update_message = "" diff --git a/frappe/utils/data.py b/frappe/utils/data.py index 73458b5952..dd3d9e3c94 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -6,7 +6,7 @@ from __future__ import unicode_literals # IMPORTANT: only import safe functions as this module will be included in jinja environment import frappe import operator -import re, urllib, datetime, math, time +import re, datetime, math, time import babel.dates from babel.core import UnknownLocaleError from dateutil import parser diff --git a/frappe/utils/dateutils.py b/frappe/utils/dateutils.py index ec9d6edc86..d5b7a3136b 100644 --- a/frappe/utils/dateutils.py +++ b/frappe/utils/dateutils.py @@ -30,7 +30,7 @@ def user_to_str(date, date_format=None): try: return datetime.datetime.strptime(date, dateformats[date_format]).strftime('%Y-%m-%d') - except ValueError as e: + except ValueError: raise ValueError("Date %s must be in format %s" % (date, date_format)) def parse_date(date): @@ -50,7 +50,7 @@ def parse_date(date): parsed_date = user_to_str(date, f) if parsed_date: break - except ValueError as e: + except ValueError: pass if not parsed_date: diff --git a/frappe/utils/error.py b/frappe/utils/error.py index 9269d6b3cb..f249355ee5 100644 --- a/frappe/utils/error.py +++ b/frappe/utils/error.py @@ -13,7 +13,6 @@ import traceback import linecache import pydoc import cgitb -import types import datetime import json import six diff --git a/frappe/utils/file_manager.py b/frappe/utils/file_manager.py index 2d638b733a..ffe337df0b 100644 --- a/frappe/utils/file_manager.py +++ b/frappe/utils/file_manager.py @@ -28,7 +28,6 @@ def upload(): # get record details dt = frappe.form_dict.doctype dn = frappe.form_dict.docname - df = frappe.form_dict.docfield file_url = frappe.form_dict.file_url filename = frappe.form_dict.filename frappe.form_dict.is_private = cint(frappe.form_dict.is_private) diff --git a/frappe/utils/goal.py b/frappe/utils/goal.py index b699555fca..44415f43db 100644 --- a/frappe/utils/goal.py +++ b/frappe/utils/goal.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe from frappe import _ -from six.moves import xrange + def get_monthly_results(goal_doctype, goal_field, date_col, filter_str, aggregation = 'sum'): '''Get monthly aggregation values for given field of doctype''' diff --git a/frappe/utils/password_strength.py b/frappe/utils/password_strength.py index 203a24cae1..a4182d1cab 100644 --- a/frappe/utils/password_strength.py +++ b/frappe/utils/password_strength.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals try: from zxcvbn import zxcvbn -except Exception as e: +except Exception: import zxcvbn import frappe diff --git a/frappe/utils/pdf.py b/frappe/utils/pdf.py index 4d6bcde17e..45d14c0595 100644 --- a/frappe/utils/pdf.py +++ b/frappe/utils/pdf.py @@ -6,7 +6,7 @@ import pdfkit, os, frappe from frappe.utils import scrub_urls from frappe import _ from bs4 import BeautifulSoup -from PyPDF2 import PdfFileWriter, PdfFileReader +from PyPDF2 import PdfFileReader import re def get_pdf(html, options=None, output = None): diff --git a/frappe/utils/print_format.py b/frappe/utils/print_format.py index 26f90e16f2..a254f0b8d1 100644 --- a/frappe/utils/print_format.py +++ b/frappe/utils/print_format.py @@ -1,13 +1,10 @@ from __future__ import unicode_literals -import frappe, os, copy, json, re +import frappe, os from frappe import _ -from frappe.modules import get_doc_path -from jinja2 import TemplateNotFound -from frappe.utils import cint, strip_html from frappe.utils.pdf import get_pdf,cleanup -from PyPDF2 import PdfFileWriter, PdfFileReader +from PyPDF2 import PdfFileWriter no_cache = 1 no_sitemap = 1 diff --git a/frappe/utils/reset_doc.py b/frappe/utils/reset_doc.py index ef20b0157b..3dc91408dd 100755 --- a/frappe/utils/reset_doc.py +++ b/frappe/utils/reset_doc.py @@ -1,10 +1,9 @@ import frappe import json, os -from frappe.modules import scrub, get_module_path, load_doctype_module, utils +from frappe.modules import scrub, get_module_path, utils from frappe.custom.doctype.customize_form.customize_form import doctype_properties, docfield_properties from frappe.custom.doctype.property_setter.property_setter import make_property_setter from frappe.custom.doctype.custom_field.custom_field import create_custom_field -from frappe.modules.import_file import get_file_path, read_doc_from_file from frappe.core.page.permission_manager.permission_manager import get_standard_permissions from frappe.permissions import setup_custom_perms from six.moves.urllib.request import urlopen @@ -89,7 +88,7 @@ def make_custom_fields(doctype, local_doc, original_doc): custom_docfield_properties, prev = get_custom_docfield_properties(), "" for field, field_dict in local_fields: - df, doc = {}, {} + df = {} if field not in original_fields: for prop in field_dict: if prop in custom_docfield_properties: diff --git a/frappe/utils/xlsxutils.py b/frappe/utils/xlsxutils.py index 1a4331328d..17e5e7683a 100644 --- a/frappe/utils/xlsxutils.py +++ b/frappe/utils/xlsxutils.py @@ -3,13 +3,12 @@ from __future__ import unicode_literals import frappe -from frappe.utils import encode, cstr, cint, flt, comma_or import openpyxl import re from openpyxl.styles import Font from openpyxl import load_workbook -from six import StringIO, BytesIO, string_types +from six import BytesIO, string_types ILLEGAL_CHARACTERS_RE = re.compile(r'[\000-\010]|[\013-\014]|[\016-\037]') # return xlsx file object @@ -53,7 +52,7 @@ def handle_html(data): if '>' not in data: return data - from html2text import unescape, HTML2Text + from html2text import HTML2Text h = HTML2Text() h.unicode_snob = True diff --git a/frappe/website/render.py b/frappe/website/render.py index 88e0eb235d..b0f0641ac5 100644 --- a/frappe/website/render.py +++ b/frappe/website/render.py @@ -43,7 +43,7 @@ def render(path=None, http_status_code=None): else: try: data = render_page_by_language(path) - except frappe.DoesNotExistError as e: + except frappe.DoesNotExistError: doctype, name = get_doctype_from_path(path) if doctype and name: path = "printview" @@ -77,7 +77,7 @@ def render(path=None, http_status_code=None): data = add_csrf_token(data) - except frappe.Redirect as e: + except frappe.Redirect: return build_response(path, "", 301, { "Location": frappe.flags.redirect_location or (frappe.local.response or {}).get('location'), "Cache-Control": "no-store, no-cache, must-revalidate" diff --git a/frappe/www/profile.py b/frappe/www/profile.py index 3d56f672f2..f066a13ed7 100644 --- a/frappe/www/profile.py +++ b/frappe/www/profile.py @@ -2,10 +2,7 @@ # MIT License. See license.txt from __future__ import unicode_literals -import frappe -from frappe import _ -from frappe.utils.user import get_fullname_and_avatar -import frappe.www.list + no_cache = 1 no_sitemap = 1 diff --git a/frappe/www/rss.py b/frappe/www/rss.py index 4edeaef83b..a389304e5e 100644 --- a/frappe/www/rss.py +++ b/frappe/www/rss.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals import frappe -import urllib from frappe.utils import escape_html, get_request_site_address, now, cstr from six.moves.urllib.parse import quote, urljoin diff --git a/frappe/www/sitemap.py b/frappe/www/sitemap.py index b465492058..bd1d02e26d 100644 --- a/frappe/www/sitemap.py +++ b/frappe/www/sitemap.py @@ -3,8 +3,6 @@ from __future__ import unicode_literals -import urllib -import frappe from frappe.utils import get_request_site_address, get_datetime, nowdate from frappe.website.router import get_pages, get_all_page_context_from_doctypes from six import iteritems diff --git a/frappe/www/website_theme.py b/frappe/www/website_theme.py index ca84a303b7..972cbe0acd 100644 --- a/frappe/www/website_theme.py +++ b/frappe/www/website_theme.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals import re -import frappe from frappe.website.utils import get_shade from frappe.website.doctype.website_theme.website_theme import get_active_theme From 7bd056c2d12a63e200d7bf60d2f6118e8e86a9b8 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 23 Jan 2019 16:43:37 +0530 Subject: [PATCH 03/35] fix: Use ImportError instead of ModuleNotFoundError (#6808) ModuleNotFoundError is available in python 3.6 This should have been included in Frappe PR #6797 --- frappe/printing/doctype/print_settings/print_settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/printing/doctype/print_settings/print_settings.py b/frappe/printing/doctype/print_settings/print_settings.py index 8043130358..2758f0aa9c 100644 --- a/frappe/printing/doctype/print_settings/print_settings.py +++ b/frappe/printing/doctype/print_settings/print_settings.py @@ -18,7 +18,7 @@ class PrintSettings(Document): printer_list = [] try: import cups - except ModuleNotFoundError: + except ImportError: frappe.throw("You need to install pycups to use this feature!") return try: From 236fa87051a310ceae3020bd734eddd0772cb1a0 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Wed, 23 Jan 2019 16:47:16 +0530 Subject: [PATCH 04/35] fix(comment): Encoding issue in jinja for mention in comment (#6813) --- frappe/core/doctype/communication/comment.py | 6 ++++-- frappe/templates/emails/mentioned_in_comment.html | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/communication/comment.py b/frappe/core/doctype/communication/comment.py index 0ceb93219c..fa3a7b2dcc 100644 --- a/frappe/core/doctype/communication/comment.py +++ b/frappe/core/doctype/communication/comment.py @@ -96,15 +96,17 @@ def notify_mentions(doc): recipients = [frappe.db.get_value("User", {"enabled": 1, "name": name, "user_type": "System User"}, "email") for name in mentions] + link = get_link_to_form(doc.reference_doctype, doc.reference_name, label=parent_doc_label) + frappe.sendmail( recipients=recipients, sender=frappe.session.user, subject=subject, template="mentioned_in_comment", args={ - "sender_fullname": sender_fullname, + "body_content": _("{0} mentioned you in a comment in {1}").format(sender_fullname, link), "comment": doc, - "link": get_link_to_form(doc.reference_doctype, doc.reference_name, label=parent_doc_label) + "link": link }, header=[_('New Mention'), 'orange'] ) diff --git a/frappe/templates/emails/mentioned_in_comment.html b/frappe/templates/emails/mentioned_in_comment.html index becf1dfd25..92bf15723a 100644 --- a/frappe/templates/emails/mentioned_in_comment.html +++ b/frappe/templates/emails/mentioned_in_comment.html @@ -1,5 +1,5 @@

- {{ _("{0} mentioned you in a comment in {1}").format(sender_fullname, link) }} + {{ body_content }}

From 8bdb0dc5f8445273716c7c907e19e46c3b7a2390 Mon Sep 17 00:00:00 2001 From: Zarrar Date: Wed, 23 Jan 2019 16:51:02 +0530 Subject: [PATCH 05/35] feat: Download json file (#6793) * feat: download file as json type * fix: make raw type files downloadable --- frappe/utils/response.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/response.py b/frappe/utils/response.py index 4809fcb45b..8b19fc4607 100644 --- a/frappe/utils/response.py +++ b/frappe/utils/response.py @@ -68,7 +68,7 @@ def as_txt(): def as_raw(): response = Response() response.mimetype = frappe.response.get("content_type") or mimetypes.guess_type(frappe.response['filename'])[0] or "application/unknown" - response.headers["Content-Disposition"] = ("filename=\"%s\"" % frappe.response['filename'].replace(' ', '_')).encode("utf-8") + response.headers["Content-Disposition"] = ("attachment; filename=\"%s\"" % frappe.response['filename'].replace(' ', '_')).encode("utf-8") response.data = frappe.response['filecontent'] return response From 5ffdeb19fc6d76402638c171cdbcc900dad5ce2d Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 24 Jan 2019 14:26:27 +0530 Subject: [PATCH 06/35] feat: New filter type "Is Set", "Is Not Set" --- frappe/model/db_query.py | 14 +++++++++++++- .../js/frappe/ui/filters/edit_filter.html | 18 +++--------------- frappe/public/js/frappe/ui/filters/filter.js | 16 ++++++++++++++-- frappe/utils/data.py | 3 ++- 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/frappe/model/db_query.py b/frappe/model/db_query.py index ca7558c77a..116255106c 100644 --- a/frappe/model/db_query.py +++ b/frappe/model/db_query.py @@ -409,6 +409,19 @@ class DatabaseQuery(object): value = get_time(f.value).strftime("%H:%M:%S.%f") fallback = "'00:00:00'" + elif f.operator.lower() == "is": + if f.value == 'set': + f.operator = '!=' + elif f.value == 'not set': + f.operator = '=' + + value = "" + fallback = '""' + can_be_null = True + + if 'ifnull' not in column_name: + column_name = 'ifnull({}, {})'.format(column_name, fallback) + elif f.operator.lower() in ("like", "not like") or (isinstance(f.value, string_types) and (not df or df.fieldtype not in ["Float", "Int", "Currency", "Percent", "Check"])): value = "" if f.value==None else f.value @@ -417,7 +430,6 @@ class DatabaseQuery(object): if f.operator.lower() in ("like", "not like") and isinstance(value, string_types): # because "like" uses backslash (\) for escaping value = value.replace("\\", "\\\\").replace("%", "%%") - else: value = flt(f.value) fallback = 0 diff --git a/frappe/public/js/frappe/ui/filters/edit_filter.html b/frappe/public/js/frappe/ui/filters/edit_filter.html index 88f3a5b20c..50b1e1b4e6 100644 --- a/frappe/public/js/frappe/ui/filters/edit_filter.html +++ b/frappe/public/js/frappe/ui/filters/edit_filter.html @@ -3,21 +3,9 @@
diff --git a/frappe/public/js/frappe/ui/filters/filter.js b/frappe/public/js/frappe/ui/filters/filter.js index 1cbbc5fc2d..6b1be4bd0f 100644 --- a/frappe/public/js/frappe/ui/filters/filter.js +++ b/frappe/public/js/frappe/ui/filters/filter.js @@ -13,13 +13,16 @@ frappe.ui.Filter = class { ["not like", __("Not Like")], ["in", __("In")], ["not in", __("Not In")], + ["is", __("Is")], [">", ">"], ["<", "<"], [">=", ">="], ["<=", "<="], ["Between", __("Between")], ["descendants of", __("Descendants Of")], - ["ancestors of", __("Ancestors Of")] + ["not descendants of", __("Not Descendants Of")], + ["ancestors of", __("Ancestors Of")], + ["not ancestors of", __("Not Ancestors Of")] ]; this.invalid_condition_map = { Date: ['like', 'not like'], @@ -37,7 +40,9 @@ frappe.ui.Filter = class { } make() { - this.filter_edit_area = $(frappe.render_template("edit_filter", {})) + this.filter_edit_area = $(frappe.render_template("edit_filter", { + conditions: this.conditions + })) .appendTo(this.parent.find('.filter-edit-area')); } @@ -395,5 +400,12 @@ frappe.ui.filter_utils = { if(condition == "Between" && (df.fieldtype == 'Date' || df.fieldtype == 'Datetime')){ df.fieldtype = 'DateRange'; } + if (condition === 'is') { + df.fieldtype = 'Select' + df.options = [ + { label: __('Set'), value: 'set' }, + { label: __('Not Set'), value: 'not set' }, + ] + } } }; diff --git a/frappe/utils/data.py b/frappe/utils/data.py index dd3d9e3c94..3e92d3e5b9 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -835,7 +835,8 @@ def get_filter(doctype, f): f.operator = "=" valid_operators = ("=", "!=", ">", "<", ">=", "<=", "like", "not like", "in", "not in", - "between", "descendants of", "ancestors of", "not descendants of", "not ancestors of") + "between", "descendants of", "ancestors of", "not descendants of", "not ancestors of", "is") + if f.operator.lower() not in valid_operators: frappe.throw(frappe._("Operator must be one of {0}").format(", ".join(valid_operators))) From 2b336c235c1e2ab15881179009def4cf15754d0c Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 24 Jan 2019 14:43:44 +0530 Subject: [PATCH 07/35] tests: Add tests for "Is Set" and "Is Not Set" filter --- frappe/tests/test_db_query.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/frappe/tests/test_db_query.py b/frappe/tests/test_db_query.py index 132fb0d01d..484b17e024 100644 --- a/frappe/tests/test_db_query.py +++ b/frappe/tests/test_db_query.py @@ -336,6 +336,17 @@ class TestReportview(unittest.TestCase): self.assertTrue(len(frappe.get_all('File', {'name': ('not ancestors of', 'Home')})) == len(frappe.get_all('File'))) + def test_is_set_is_not_set(self): + res = DatabaseQuery("DocType").execute(filters={"autoname": ["is", "not set"]}) + self.assertTrue({'name': 'Integration Request'} in res) + self.assertTrue({'name': 'User'} in res) + self.assertFalse({'name': 'Blogger'} in res) + + res = DatabaseQuery("DocType").execute(filters={"autoname": ["is", "set"]}) + self.assertTrue({'name': 'DocField'} in res) + self.assertTrue({'name': 'Prepared Report'} in res) + self.assertFalse({'name': 'Property Setter'} in res) + def create_event(subject="_Test Event", starts_on=None): """ create a test event """ From 5f5ea18a72b7a6f33efd10e124f1864544c9dd4a Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 24 Jan 2019 15:13:13 +0530 Subject: [PATCH 08/35] style: missing semicolon --- frappe/public/js/frappe/ui/filters/filter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/ui/filters/filter.js b/frappe/public/js/frappe/ui/filters/filter.js index 6b1be4bd0f..80ccb8b35b 100644 --- a/frappe/public/js/frappe/ui/filters/filter.js +++ b/frappe/public/js/frappe/ui/filters/filter.js @@ -401,11 +401,11 @@ frappe.ui.filter_utils = { df.fieldtype = 'DateRange'; } if (condition === 'is') { - df.fieldtype = 'Select' + df.fieldtype = 'Select'; df.options = [ { label: __('Set'), value: 'set' }, { label: __('Not Set'), value: 'not set' }, - ] + ]; } } }; From 75f8847ad49c78290ac3b1b23c2aae436e316a18 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 24 Jan 2019 19:15:49 +0530 Subject: [PATCH 09/35] fix: Skip get_notifications before setup_complete (#6828) --- frappe/desk/notifications.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/desk/notifications.py b/frappe/desk/notifications.py index 7a5676cca6..b13bc3e9d4 100644 --- a/frappe/desk/notifications.py +++ b/frappe/desk/notifications.py @@ -11,7 +11,8 @@ import json @frappe.whitelist() def get_notifications(): - if frappe.flags.in_install: + if (frappe.flags.in_install or + not frappe.db.get_single_value('System Settings', 'setup_complete')): return config = get_notification_config() From 14911900c8d71b931e501b79c37192714fe18ff4 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Thu, 24 Jan 2019 19:56:03 +0530 Subject: [PATCH 10/35] fix: return empty dict if site is in installation state or setup wiz not completed --- frappe/desk/notifications.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/desk/notifications.py b/frappe/desk/notifications.py index b13bc3e9d4..bcd1911107 100644 --- a/frappe/desk/notifications.py +++ b/frappe/desk/notifications.py @@ -13,7 +13,7 @@ import json def get_notifications(): if (frappe.flags.in_install or not frappe.db.get_single_value('System Settings', 'setup_complete')): - return + return { } config = get_notification_config() From 97152b5a1e77ee3d5b53e204c64b4645a78d18b8 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Fri, 25 Jan 2019 10:22:13 +0530 Subject: [PATCH 11/35] fix: return empty dict if setup wizard is not completed (#6830) --- frappe/desk/notifications.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frappe/desk/notifications.py b/frappe/desk/notifications.py index bcd1911107..2107cbdbec 100644 --- a/frappe/desk/notifications.py +++ b/frappe/desk/notifications.py @@ -13,7 +13,13 @@ import json def get_notifications(): if (frappe.flags.in_install or not frappe.db.get_single_value('System Settings', 'setup_complete')): - return { } + return { + "open_count_doctype": {}, + "open_count_module": {}, + "open_count_other": {}, + "targets": {}, + "new_messages": [] + } config = get_notification_config() From d8187a3f9d54f557438d4cb3a4c2b530e1a74add Mon Sep 17 00:00:00 2001 From: Zarrar Date: Fri, 25 Jan 2019 10:24:40 +0530 Subject: [PATCH 12/35] fix: unicode character throws error for python 2 (#6822) --- frappe/desk/reportview.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/desk/reportview.py b/frappe/desk/reportview.py index 7c6e7a4b75..fef0db9f74 100644 --- a/frappe/desk/reportview.py +++ b/frappe/desk/reportview.py @@ -214,7 +214,7 @@ def delete_items(): """delete selected items""" import json - il = sorted(json.loads(frappe.form_dict.get('items')), reverse=True, key=str) + il = sorted(json.loads(frappe.form_dict.get('items')), reverse=True, key=frappe.safe_decode) doctype = frappe.form_dict.get('doctype') failed = [] From 3250553738118e930a632105ea6d48c4926dd498 Mon Sep 17 00:00:00 2001 From: Chinmay Pai Date: Fri, 25 Jan 2019 05:49:17 +0000 Subject: [PATCH 13/35] fix(notifications): ignore mysql internal error 1684 for concurrent ddl statements (#6826) apparently this occurs when get_notifcations is called, and at the same time, a table is being modified. to fix this, we just skip the table that is currently being modified. Signed-off-by: Chinmay Pai --- frappe/desk/notifications.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frappe/desk/notifications.py b/frappe/desk/notifications.py index 2107cbdbec..59c783c524 100644 --- a/frappe/desk/notifications.py +++ b/frappe/desk/notifications.py @@ -114,7 +114,8 @@ def get_notifications_for_doctypes(config, notification_count): except Exception as e: # OperationalError: (1412, 'Table definition has changed, please retry transaction') - if e.args[0]!=1412: + # InternalError: (1684, 'Table definition is being modified by concurrent DDL statement') + if e.args[0] not in (1412, 1684): raise else: @@ -154,7 +155,7 @@ def get_notifications_for_targets(config, notification_percent): frappe.clear_messages() pass except Exception as e: - if e.args[0]!=1412: + if e.args[0] not in (1412, 1684): raise else: From cc033a67ebd527d2c3b1e5131649f3ca923bbb0b Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Fri, 25 Jan 2019 11:19:57 +0530 Subject: [PATCH 14/35] fix(PrintFormat): Section Labels with spaces in them got truncated (#6819) --- .../page/print_format_builder/print_format_builder_section.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/printing/page/print_format_builder/print_format_builder_section.html b/frappe/printing/page/print_format_builder/print_format_builder_section.html index f5a96faede..d08a7ca5b2 100644 --- a/frappe/printing/page/print_format_builder/print_format_builder_section.html +++ b/frappe/printing/page/print_format_builder/print_format_builder_section.html @@ -1,4 +1,4 @@ -