diff --git a/frappe/__init__.py b/frappe/__init__.py index 8ab079ab58..af64977665 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -14,7 +14,7 @@ import os, sys, importlib, inspect, json from .exceptions import * from .utils.jinja import get_jenv, get_template, render_template, get_email_from_template -__version__ = '10.1.42' +__version__ = '10.1.43' __title__ = "Frappe Framework" local = Local() diff --git a/frappe/core/doctype/user/test_user.py b/frappe/core/doctype/user/test_user.py index 55745f97df..a5b54e7b8d 100644 --- a/frappe/core/doctype/user/test_user.py +++ b/frappe/core/doctype/user/test_user.py @@ -260,6 +260,8 @@ class TestUser(unittest.TestCase): def test_comment_mentions(self): user_name = "@test.comment@example.com" self.assertEqual(extract_mentions(user_name)[0], "test.comment@example.com") + user_name = "@test.comment@test-example.com" + self.assertEqual(extract_mentions(user_name)[0], "test.comment@test-example.com") user_name = "Testing comment, @test-user please check." self.assertEqual(extract_mentions(user_name)[0], "test-user") user_name = "Testing comment, @test.user@example.com please check." diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py index 4b2de59778..cb85399fb9 100644 --- a/frappe/core/doctype/user/user.py +++ b/frappe/core/doctype/user/user.py @@ -901,6 +901,7 @@ def notify_admin_access_to_system_manager(login_manager=None): def extract_mentions(txt): """Find all instances of @name in the string. The mentions will be separated by non-word characters or may appear at the start of the string""" + txt = re.sub(r'(<[a-zA-Z\/][^>]*>)', '', txt) return re.findall(r'(?:[^\w\.\-\@]|^)@([\w\.\-\@]*)', txt) diff --git a/frappe/desk/doctype/calendar_view/calendar_view.json b/frappe/desk/doctype/calendar_view/calendar_view.json index 227aa90f75..da2bdc3e34 100644 --- a/frappe/desk/doctype/calendar_view/calendar_view.json +++ b/frappe/desk/doctype/calendar_view/calendar_view.json @@ -42,6 +42,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -72,6 +73,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -99,9 +101,10 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -129,9 +132,10 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -145,7 +149,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-11-14 14:14:11.544811", + "modified": "2018-07-20 08:23:23.737254", "modified_by": "Administrator", "module": "Desk", "name": "Calendar View", diff --git a/frappe/public/js/frappe/form/footer/timeline.js b/frappe/public/js/frappe/form/footer/timeline.js index 177d168fb5..7c760b80a3 100644 --- a/frappe/public/js/frappe/form/footer/timeline.js +++ b/frappe/public/js/frappe/form/footer/timeline.js @@ -310,9 +310,9 @@ frappe.ui.form.Timeline = Class.extend({ // bold @mentions if(c.comment_type==="Comment" && // avoid adding tag a 2nd time - !c.content_html.match(/(^|\W)(@\w+)<\/b>/) + !c.content_html.match(/(^|\W)(@[^\s]+)<\/b>/) ) { - c.content_html = c.content_html.replace(/(^|\W)(@\w+)/g, "$1$2"); + c.content_html = c.content_html.replace(/(^|\W)(@[^\s]+)/g, "$1$2"); } if (this.is_communication_or_comment(c)) { diff --git a/frappe/public/js/frappe/ui/base_list.js b/frappe/public/js/frappe/ui/base_list.js index 0d3b1957e8..3a239f5bc0 100644 --- a/frappe/public/js/frappe/ui/base_list.js +++ b/frappe/public/js/frappe/ui/base_list.js @@ -322,7 +322,6 @@ frappe.ui.BaseList = Class.extend({ return frappe.call({ method: this.opts.method || 'frappe.desk.query_builder.runquery', - type: "GET", freeze: this.opts.freeze !== undefined ? this.opts.freeze : true, args: args, callback: function (r) { diff --git a/frappe/public/js/frappe/views/reports/reportview.js b/frappe/public/js/frappe/views/reports/reportview.js index 9e4b84bfaf..40cf915bc7 100644 --- a/frappe/public/js/frappe/views/reports/reportview.js +++ b/frappe/public/js/frappe/views/reports/reportview.js @@ -391,7 +391,7 @@ frappe.views.ReportView = frappe.ui.BaseList.extend({ var me = this; var data = this.get_unique_data(this.column_info); - this.set_totals_row(data); + this.set_totals_row(data, this.column_info); // add sr in data $.each(data, function(i, v) { @@ -617,13 +617,23 @@ frappe.views.ReportView = frappe.ui.BaseList.extend({ }); }, - set_totals_row: function(data) { + set_totals_row: function(data, columns) { + const field_map = {}; + const numeric_fieldtypes = ['Int', 'Currency', 'Float']; + columns.forEach(function(row) { + if (row.docfield) { + let r = row.docfield; + if (numeric_fieldtypes.includes(r.fieldtype)) { + field_map[r.fieldname] = [r.fieldtype]; + } + } + }) if(this.add_totals_row) { var totals_row = {_totals_row: 1}; if(data.length) { data.forEach(function(row, ri) { $.each(row, function(key, value) { - if($.isNumeric(value)) { + if (key in field_map) { totals_row[key] = (totals_row[key] || 0) + value; } }); diff --git a/frappe/utils/__init__.py b/frappe/utils/__init__.py index d807c018f1..390cedffb4 100644 --- a/frappe/utils/__init__.py +++ b/frappe/utils/__init__.py @@ -548,3 +548,37 @@ def get_site_info(): # dumps -> loads to prevent datatype conflicts return json.loads(frappe.as_json(site_info)) + +def get_db_count(*args): + """ + Pass a doctype or a series of doctypes to get the count of docs in them + Parameters: + *args: Variable length argument list of doctype names whose doc count you need + + Returns: + dict: A dict with the count values. + + Example: + via terminal: + bench --site erpnext.local execute frappe.utils.get_db_count --args "['DocType', 'Communication']" + """ + db_count = {} + for doctype in args: + db_count[doctype] = frappe.db.count(doctype) + + return json.loads(frappe.as_json(db_count)) + +def call(fn, *args, **kwargs): + """ + Pass a doctype or a series of doctypes to get the count of docs in them + Parameters: + fn: frappe function to be called + + Returns: + based on the function you call: output of the function you call + + Example: + via terminal: + bench --site erpnext.local execute frappe.utils.call --args '''["frappe.get_all", "Activity Log"]''' --kwargs '''{"fields": ["user", "creation", "full_name"], "filters":{"Operation": "Login", "Status": "Success"}, "limit": "10"}''' + """ + return json.loads(frappe.as_json(frappe.call(fn, *args, **kwargs))) diff --git a/frappe/utils/pdf.py b/frappe/utils/pdf.py index 57c4051be6..dd22066c55 100644 --- a/frappe/utils/pdf.py +++ b/frappe/utils/pdf.py @@ -7,6 +7,7 @@ from frappe.utils import scrub_urls from frappe import _ from bs4 import BeautifulSoup from PyPDF2 import PdfFileWriter, PdfFileReader +import re def get_pdf(html, options=None, output = None): html = scrub_urls(html) @@ -16,7 +17,7 @@ def get_pdf(html, options=None, output = None): try: pdfkit.from_string(html, fname, options=options or {}) if output: - append_pdf(PdfFileReader(file(fname,"rb")),output) + append_pdf(PdfFileReader(fname),output) else: with open(fname, "rb") as fileobj: filedata = fileobj.read() @@ -88,12 +89,13 @@ def read_options_from_html(html): toggle_visible_pdf(soup) - # extract pdfkit options from html - for html_id in ("margin-top", "margin-bottom", "margin-left", "margin-right", "page-size"): + # use regex instead of soup-parser + for attr in ("margin-top", "margin-bottom", "margin-left", "margin-right", "page-size"): try: - tag = soup.find(id=html_id) - if tag and tag.contents: - options[html_id] = tag.contents + pattern = re.compile(r"(\.print-format)([\S|\s][^}]*?)(" + str(attr) + r":)(.+)(mm;)") + match = pattern.findall(html) + if match: + options[attr] = str(match[-1][3]).strip() except: pass