diff --git a/.travis.yml b/.travis.yml index 2331217363..23fb525138 100644 --- a/.travis.yml +++ b/.travis.yml @@ -104,11 +104,11 @@ install: - cd ./frappe-bench - - sed -i 's/watch:/# watch:/g' Procfile - - sed -i 's/schedule:/# schedule:/g' Procfile + - sed -i 's/^watch:/# watch:/g' Procfile + - sed -i 's/^schedule:/# schedule:/g' Procfile - - if [ $TYPE == "server" ]; then sed -i 's/socketio:/# socketio:/g' Procfile; fi - - if [ $TYPE == "server" ]; then sed -i 's/redis_socketio:/# redis_socketio:/g' Procfile; fi + - if [ $TYPE == "server" ]; then sed -i 's/^socketio:/# socketio:/g' Procfile; fi + - if [ $TYPE == "server" ]; then sed -i 's/^redis_socketio:/# redis_socketio:/g' Procfile; fi - if [ $TYPE == "ui" ]; then bench setup requirements --node; fi diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py index 2fa36b5514..b19f6cf9f0 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py @@ -73,7 +73,7 @@ def has_permission(doc, ptype, user): if doc.report_name in allowed_reports: return True else: - allowed_doctypes = [frappe.permissions.get_doctypes_with_read()] + allowed_doctypes = frappe.permissions.get_doctypes_with_read() if doc.document_type in allowed_doctypes: return True diff --git a/frappe/desk/page/setup_wizard/install_fixtures.py b/frappe/desk/page/setup_wizard/install_fixtures.py index 60e1f3242a..6d3aaee22b 100644 --- a/frappe/desk/page/setup_wizard/install_fixtures.py +++ b/frappe/desk/page/setup_wizard/install_fixtures.py @@ -18,14 +18,14 @@ def install(): @frappe.whitelist() def update_genders(): - default_genders = [_("Male"), _("Female"), _("Other"),_("Transgender"), _("Genderqueer"), _("Non-Conforming"),_("Prefer not to say")] + default_genders = ["Male", "Female", "Other","Transgender", "Genderqueer", "Non-Conforming","Prefer not to say"] records = [{'doctype': 'Gender', 'gender': d} for d in default_genders] for record in records: frappe.get_doc(record).insert(ignore_permissions=True, ignore_if_duplicate=True) @frappe.whitelist() def update_salutations(): - default_salutations = [_("Mr"), _("Ms"), _('Mx'), _("Dr"), _("Mrs"), _("Madam"), _("Miss"), _("Master"), _("Prof")] + default_salutations = ["Mr", "Ms", 'Mx', "Dr", "Mrs", "Madam", "Miss", "Master", "Prof"] records = [{'doctype': 'Salutation', 'salutation': d} for d in default_salutations] for record in records: doc = frappe.new_doc(record.get("doctype")) diff --git a/frappe/email/doctype/auto_email_report/auto_email_report.py b/frappe/email/doctype/auto_email_report/auto_email_report.py index 539f6c9db8..de27fafee3 100644 --- a/frappe/email/doctype/auto_email_report/auto_email_report.py +++ b/frappe/email/doctype/auto_email_report/auto_email_report.py @@ -81,7 +81,7 @@ class AutoEmailReport(Document): if self.format == 'HTML': columns, data = make_links(columns, data) - + columns = update_field_types(columns) return self.get_html_table(columns, data) elif self.format == 'XLSX': @@ -236,5 +236,14 @@ def make_links(columns, data): elif col.fieldtype == "Dynamic Link": if col.options and row.get(col.fieldname) and row.get(col.options): row[col.fieldname] = get_link_to_form(row[col.options], row[col.fieldname]) + elif col.fieldtype == "Currency": + row[col.fieldname] = frappe.format_value(row[col.fieldname], col) return columns, data + +def update_field_types(columns): + for col in columns: + if col.fieldtype in ("Link", "Dynamic Link", "Currency") and col.options != "Currency": + col.fieldtype = "Data" + col.options = "" + return columns \ No newline at end of file diff --git a/frappe/email/doctype/newsletter/test_newsletter.py b/frappe/email/doctype/newsletter/test_newsletter.py index ee7f123b7e..bd8fadc29c 100644 --- a/frappe/email/doctype/newsletter/test_newsletter.py +++ b/frappe/email/doctype/newsletter/test_newsletter.py @@ -2,58 +2,66 @@ # License: GNU General Public License v3. See license.txt from __future__ import unicode_literals -import frappe, unittest -from frappe.utils import getdate, add_days +import unittest +from random import choice -from frappe.email.doctype.newsletter.newsletter import confirmed_unsubscribe, send_scheduled_email -from six.moves.urllib.parse import unquote +import frappe +from frappe.email.doctype.newsletter.newsletter import ( + confirmed_unsubscribe, + send_scheduled_email, +) +from frappe.email.doctype.newsletter.newsletter import get_newsletter_list +from frappe.email.queue import flush +from frappe.utils import add_days, getdate test_dependencies = ["Email Group"] +emails = [ + "test_subscriber1@example.com", + "test_subscriber2@example.com", + "test_subscriber3@example.com", + "test1@example.com", +] -emails = ["test_subscriber1@example.com", "test_subscriber2@example.com", - "test_subscriber3@example.com", "test1@example.com"] class TestNewsletter(unittest.TestCase): def setUp(self): frappe.set_user("Administrator") - frappe.db.sql('delete from `tabEmail Group Member`') + frappe.db.sql("delete from `tabEmail Group Member`") + + if not frappe.db.exists("Email Group", "_Test Email Group"): + frappe.get_doc({"doctype": "Email Group", "title": "_Test Email Group"}).insert() - group_exist=frappe.db.exists("Email Group", "_Test Email Group") - if len(group_exist) == 0: - frappe.get_doc({ - "doctype": "Email Group", - "title": "_Test Email Group" - }).insert() for email in emails: - frappe.get_doc({ - "doctype": "Email Group Member", - "email": email, - "email_group": "_Test Email Group" - }).insert() + frappe.get_doc({ + "doctype": "Email Group Member", + "email": email, + "email_group": "_Test Email Group" + }).insert() def test_send(self): - name = self.send_newsletter() + self.send_newsletter() - email_queue_list = [frappe.get_doc('Email Queue', e.name) for e in frappe.get_all("Email Queue")] + email_queue_list = [frappe.get_doc("Email Queue", e.name) for e in frappe.get_all("Email Queue")] self.assertEqual(len(email_queue_list), 4) - recipients = [e.recipients[0].recipient for e in email_queue_list] - for email in emails: - self.assertTrue(email in recipients) + + recipients = set([e.recipients[0].recipient for e in email_queue_list]) + self.assertTrue(set(emails).issubset(recipients)) def test_unsubscribe(self): - # test unsubscribe name = self.send_newsletter() - from frappe.email.queue import flush + to_unsubscribe = choice(emails) + group = frappe.get_all("Newsletter Email Group", filters={"parent": name}, fields=["email_group"]) + flush(from_test=True) - to_unsubscribe = unquote(frappe.local.flags.signed_query_string.split("email=")[1].split("&")[0]) - group = frappe.get_all("Newsletter Email Group", filters={"parent" : name}, fields=["email_group"]) confirmed_unsubscribe(to_unsubscribe, group[0].email_group) name = self.send_newsletter() - - email_queue_list = [frappe.get_doc('Email Queue', e.name) for e in frappe.get_all("Email Queue")] + email_queue_list = [ + frappe.get_doc("Email Queue", e.name) for e in frappe.get_all("Email Queue") + ] self.assertEqual(len(email_queue_list), 3) recipients = [e.recipients[0].recipient for e in email_queue_list] + for email in emails: if email != to_unsubscribe: self.assertTrue(email in recipients) @@ -86,7 +94,6 @@ class TestNewsletter(unittest.TestCase): def test_portal(self): self.send_newsletter(1) frappe.set_user("test1@example.com") - from frappe.email.doctype.newsletter.newsletter import get_newsletter_list newsletters = get_newsletter_list("Newsletter", None, None, 0) self.assertEqual(len(newsletters), 1) @@ -106,4 +113,4 @@ class TestNewsletter(unittest.TestCase): self.assertEqual(len(email_queue_list), 4) recipients = [e.recipients[0].recipient for e in email_queue_list] for email in emails: - self.assertTrue(email in recipients) \ No newline at end of file + self.assertTrue(email in recipients) diff --git a/frappe/public/js/frappe/form/controls/geolocation.js b/frappe/public/js/frappe/form/controls/geolocation.js index 9e4d1d82ec..dfd0f4d174 100644 --- a/frappe/public/js/frappe/form/controls/geolocation.js +++ b/frappe/public/js/frappe/form/controls/geolocation.js @@ -17,7 +17,7 @@ frappe.ui.form.ControlGeolocation = frappe.ui.form.ControlData.extend({ this.map_area.prependTo($input_wrapper); this.$wrapper.find('.control-input').addClass("hidden"); - if ($input_wrapper.is(':visible')) { + if (this.frm) { this.make_map(); } else { $(document).on('frappe.ui.Dialog:shown', () => { diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js index c69be04347..0389770783 100755 --- a/frappe/public/js/frappe/views/communication.js +++ b/frappe/public/js/frappe/views/communication.js @@ -672,10 +672,19 @@ frappe.views.CommunicationComposer = Class.extend({ } }, - setup_earlier_reply: function() { + get_default_outgoing_email_account_signature: function() { + return frappe.db.get_value('Email Account', { 'default_outgoing': 1, 'add_signature': 1 }, 'signature'); + }, + + setup_earlier_reply: async function() { let fields = this.dialog.fields_dict; let signature = frappe.boot.user.email_signature || ""; + if (!signature) { + const res = await this.get_default_outgoing_email_account_signature(); + signature = res.message.signature; + } + if(!frappe.utils.is_html(signature)) { signature = signature.replace(/\n/g, "
"); } @@ -756,4 +765,3 @@ frappe.views.CommunicationComposer = Class.extend({ return text.replace(/\n{3,}/g, '\n\n'); } }); - diff --git a/frappe/utils/data.py b/frappe/utils/data.py index c24b9f186e..da2c910e20 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -154,14 +154,22 @@ def get_time_zone(): return frappe.cache().get_value("time_zone", _get_time_zone) -def convert_utc_to_user_timezone(utc_timestamp): +def convert_utc_to_timezone(utc_timestamp, time_zone): from pytz import timezone, UnknownTimeZoneError utcnow = timezone('UTC').localize(utc_timestamp) try: - return utcnow.astimezone(timezone(get_time_zone())) + return utcnow.astimezone(timezone(time_zone)) except UnknownTimeZoneError: return utcnow +def get_datetime_in_timezone(time_zone): + utc_timestamp = datetime.datetime.utcnow() + return convert_utc_to_timezone(utc_timestamp, time_zone) + +def convert_utc_to_user_timezone(utc_timestamp): + time_zone = get_time_zone() + return convert_utc_to_timezone(utc_timestamp, time_zone) + def now(): """return current datetime as yyyy-mm-dd hh:mm:ss""" if frappe.flags.current_date: @@ -369,7 +377,7 @@ def format_duration(seconds, hide_days=False): example: converts 12885 to '3h 34m 45s' where 12885 = seconds in float """ - + seconds = cint(seconds) total_duration = { diff --git a/frappe/utils/oauth.py b/frappe/utils/oauth.py index d090aabffc..e7672cedb3 100644 --- a/frappe/utils/oauth.py +++ b/frappe/utils/oauth.py @@ -230,12 +230,19 @@ def update_oauth_user(user, data, provider): save = True user = frappe.new_doc("User") + + gender = (data.get("gender") or "").title() + + if not frappe.db.exists("Gender", gender): + doc = frappe.new_doc("Gender", {"gender": gender}) + doc.insert(ignore_permissions=True) + user.update({ "doctype":"User", "first_name": get_first_name(data), "last_name": get_last_name(data), "email": get_email(data), - "gender": (data.get("gender") or "").title(), + "gender": gender, "enabled": 1, "new_password": frappe.generate_hash(get_email(data)), "location": data.get("location"), diff --git a/frappe/utils/safe_exec.py b/frappe/utils/safe_exec.py index 2aacf5eda8..06a192c05e 100644 --- a/frappe/utils/safe_exec.py +++ b/frappe/utils/safe_exec.py @@ -222,6 +222,7 @@ VALID_UTILS = ( "get_last_day_of_week", "get_last_day", "get_time", +"get_datetime_in_timezone", "get_datetime_str", "get_date_str", "get_time_str", diff --git a/requirements.txt b/requirements.txt index 3cc92264a2..e128790e45 100644 --- a/requirements.txt +++ b/requirements.txt @@ -49,7 +49,7 @@ pypng==0.0.20 PyQRCode==1.2.1 python-dateutil==2.8.1 pytz==2019.3 -PyYAML==5.3.1 +PyYAML==5.4 rauth==0.7.3 redis==3.5.3 requests-oauthlib==1.3.0