diff --git a/frappe/__init__.py b/frappe/__init__.py index d3d9c31d43..33eeccc6a3 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -15,7 +15,7 @@ from past.builtins import cmp from .exceptions import * from .utils.jinja import get_jenv, get_template, render_template, get_email_from_template -__version__ = '10.1.6' +__version__ = '10.1.7' __title__ = "Frappe Framework" local = Local() diff --git a/frappe/core/doctype/communication/email.py b/frappe/core/doctype/communication/email.py index 00b9918933..8acececa03 100755 --- a/frappe/core/doctype/communication/email.py +++ b/frappe/core/doctype/communication/email.py @@ -88,7 +88,7 @@ def make(doctype=None, name=None, content=None, subject=None, sent_or_received = frappe.db.commit() if cint(send_email): - frappe.flags.print_letterhead = print_letterhead + frappe.flags.print_letterhead = cint(print_letterhead) comm.send(print_html, print_format, attachments, send_me_a_copy=send_me_a_copy) return { diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py index 3a620dae44..8f528edcec 100644 --- a/frappe/core/doctype/user/user.py +++ b/frappe/core/doctype/user/user.py @@ -68,6 +68,7 @@ class User(Document): self.validate_user_email_inbox() ask_pass_update() self.validate_roles() + self.validate_user_image() if self.language == "Loading...": self.language = None @@ -81,6 +82,10 @@ class User(Document): self.set('roles', []) self.append_roles(*[role.role for role in role_profile.roles]) + def validate_user_image(self): + if self.user_image and len(self.user_image) > 2000: + frappe.throw(_("Not a valid User Image.")) + def on_update(self): # clear new password self.validate_user_limit() diff --git a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.js b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.js index 2e3c707a5e..c264d12dec 100644 --- a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.js +++ b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.js @@ -3,6 +3,7 @@ frappe.ui.form.on('Dropbox Settings', { refresh: function(frm) { + frm.toggle_display(["app_access_key", "app_secret_key"], !(frm.doc.__onload && frm.doc.__onload.dropbox_setup_via_site_config)); frm.clear_custom_buttons(); frm.events.take_backup(frm); }, @@ -19,7 +20,7 @@ frappe.ui.form.on('Dropbox Settings', { } }) } - else if (frm.doc.dropbox_setup_via_site_config) { + else if (frm.doc.__onload && frm.doc.__onload.dropbox_setup_via_site_config) { frappe.call({ method: "frappe.integrations.doctype.dropbox_settings.dropbox_settings.get_redirect_url", freeze: true, @@ -36,7 +37,7 @@ frappe.ui.form.on('Dropbox Settings', { }, take_backup: function(frm) { - if ((frm.doc.app_access_key && frm.doc.app_secret_key) || frm.doc.dropbox_setup_via_site_config){ + if ((frm.doc.app_access_key && frm.doc.app_secret_key) || (frm.doc.__onload && frm.doc.__onload.dropbox_setup_via_site_config)){ frm.add_custom_button(__("Take Backup Now"), function(frm){ frappe.call({ method: "frappe.integrations.doctype.dropbox_settings.dropbox_settings.take_backup", diff --git a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.json b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.json index cbe1fe8b1a..a8ab581bf7 100644 --- a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.json +++ b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.json @@ -54,7 +54,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 0, "label": "Send Notifications To", "length": 0, @@ -84,7 +84,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 0, "label": "Backup Frequency", "length": 0, @@ -108,7 +108,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "eval:!doc.dropbox_setup_via_site_config", + "depends_on": "", "fieldname": "app_access_key", "fieldtype": "Data", "hidden": 0, @@ -139,7 +139,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "eval:!doc.dropbox_setup_via_site_config", + "depends_on": "", "fieldname": "app_secret_key", "fieldtype": "Password", "hidden": 0, @@ -283,36 +283,6 @@ "search_index": 0, "set_only_once": 0, "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "dropbox_setup_via_site_config", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Dropbox Setup via Site Config", - "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 } ], "has_web_view": 0, @@ -325,7 +295,7 @@ "issingle": 1, "istable": 0, "max_attachments": 0, - "modified": "2017-06-20 15:45:33.683827", + "modified": "2018-03-22 16:02:00.597029", "modified_by": "Administrator", "module": "Integrations", "name": "Dropbox Settings", diff --git a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py index 35027b90c9..283546320f 100644 --- a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py +++ b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py @@ -20,7 +20,8 @@ ignore_list = [".DS_Store"] class DropboxSettings(Document): def onload(self): if not self.app_access_key and frappe.conf.dropbox_access_key: - self.dropbox_setup_via_site_config = 1 + self.set_onload("dropbox_setup_via_site_config", 1) + @frappe.whitelist() def take_backup(): @@ -171,7 +172,7 @@ def upload_file_to_dropbox(filename, folder, dropbox_client): cursor.offset = f.tell() except dropbox.exceptions.ApiError as e: if isinstance(e.error, dropbox.files.UploadError): - error = "File Path: {path}\n".foramt(path=path) + error = "File Path: {path}\n".format(path=path) error += frappe.get_traceback() frappe.log_error(error) else: @@ -201,7 +202,7 @@ def get_dropbox_settings(redirect_uri=False): if redirect_uri: app_details.update({ - 'rediret_uri': get_request_site_address(True) \ + 'redirect_uri': get_request_site_address(True) \ + '/api/method/frappe.integrations.doctype.dropbox_settings.dropbox_settings.dropbox_auth_finish' \ if settings.app_secret_key else frappe.conf.dropbox_broker_site\ + '/api/method/dropbox_erpnext_broker.www.setup_dropbox.generate_dropbox_access_token', @@ -233,7 +234,7 @@ def get_dropbox_authorize_url(): dropbox_oauth_flow = dropbox.DropboxOAuth2Flow( app_details["app_key"], app_details["app_secret"], - app_details["rediret_uri"], + app_details["redirect_uri"], {}, "dropbox-auth-csrf-token" ) @@ -254,7 +255,7 @@ def dropbox_auth_finish(return_access_token=False): dropbox_oauth_flow = dropbox.DropboxOAuth2Flow( app_details["app_key"], app_details["app_secret"], - app_details["rediret_uri"], + app_details["redirect_uri"], { 'dropbox-auth-csrf-token': callback.state }, diff --git a/frappe/integrations/doctype/stripe_settings/stripe_settings.py b/frappe/integrations/doctype/stripe_settings/stripe_settings.py index c96b508743..62d90cbe53 100644 --- a/frappe/integrations/doctype/stripe_settings/stripe_settings.py +++ b/frappe/integrations/doctype/stripe_settings/stripe_settings.py @@ -23,12 +23,18 @@ class StripeSettings(Document): "XAF", "XOF", "XPF", "YER", "ZAR" ] + currency_wise_minimum_charge_amount = { + 'JPY': 50, 'MXN': 10, 'DKK': 2.50, 'HKD': 4.00, 'NOK': 3.00, 'SEK': 3.00, + 'USD': 0.50, 'AUD': 0.50, 'BRL': 0.50, 'CAD': 0.50, 'CHF': 0.50, 'EUR': 0.50, + 'GBP': 0.30, 'NZD': 0.50, 'SGD': 0.50 + } + def validate(self): create_payment_gateway('Stripe') call_hook_method('payment_gateway_enabled', gateway='Stripe') if not self.flags.ignore_mandatory: self.validate_stripe_credentails() - + def validate_stripe_credentails(self): if self.publishable_key and self.secret_key: header = {"Authorization": "Bearer {0}".format(self.get_password(fieldname="secret_key", raise_exception=False))} @@ -36,11 +42,17 @@ class StripeSettings(Document): make_get_request(url="https://api.stripe.com/v1/charges", headers=header) except Exception: frappe.throw(_("Seems Publishable Key or Secret Key is wrong !!!")) - + def validate_transaction_currency(self, currency): if currency not in self.supported_currencies: frappe.throw(_("Please select another payment method. Stripe does not support transactions in currency '{0}'").format(currency)) + def validate_minimum_transaction_amount(self, currency, amount): + if currency in self.currency_wise_minimum_charge_amount: + if flt(amount) < self.currency_wise_minimum_charge_amount.get(currency, 0.0): + frappe.throw(_("For currency {0}, the minimum transaction amount should be {1}").format(currency, + self.currency_wise_minimum_charge_amount.get(currency, 0.0))) + def get_payment_url(self, **kwargs): return get_url("./integrations/stripe_checkout?{0}".format(urlencode(kwargs))) diff --git a/frappe/model/naming.py b/frappe/model/naming.py index f6f7fd57a2..70eb44abcd 100644 --- a/frappe/model/naming.py +++ b/frappe/model/naming.py @@ -47,7 +47,7 @@ def set_new_name(doc): if autoname.startswith("naming_series:"): set_name_by_naming_series(doc) elif "#" in autoname: - doc.name = make_autoname(autoname) + doc.name = make_autoname(autoname, doc=doc) elif autoname.lower()=='prompt': # set from __newname in save.py if not doc.name: diff --git a/frappe/public/js/frappe/model/sync.js b/frappe/public/js/frappe/model/sync.js index 7e6f377017..0d478364b0 100644 --- a/frappe/public/js/frappe/model/sync.js +++ b/frappe/public/js/frappe/model/sync.js @@ -19,7 +19,12 @@ $.extend(frappe.model, { for(var i=0, l=r.docs.length; i d[fieldname].length) { + local_doc[fieldname].length = d[fieldname].length; + } + } else { + // literal + local_doc[fieldname] = d[fieldname]; + } + } } }); diff --git a/frappe/public/js/frappe/upload.js b/frappe/public/js/frappe/upload.js index 3eb203c5b3..7704b6fd65 100644 --- a/frappe/public/js/frappe/upload.js +++ b/frappe/public/js/frappe/upload.js @@ -313,26 +313,38 @@ frappe.upload = { if (opts.no_socketio || frappe.flags.no_socketio || file_not_big_enough) { upload_with_filedata(); return; + } else { + args.file_size = fileobj.size; + frappe.call({ + method: 'frappe.utils.file_manager.validate_filename', + args: {"filename": args.filename}, + callback: function(r) { + args.filename = r.message; + upload_through_socketio(); + } + }); } - frappe.socketio.uploader.start({ - file: fileobj, - filename: args.filename, - is_private: args.is_private, - fallback: () => { - // if fails, use old filereader - upload_with_filedata(); - }, - callback: (data) => { - args.file_url = data.file_url; - frappe.upload._upload_file(fileobj, args, opts); - }, - on_progress: (percent_complete) => { - let increment = (flt(percent_complete) / frappe.upload.total_files); - frappe.show_progress(__('Uploading'), - start_complete + increment); - } - }); + var upload_through_socketio = function() { + frappe.socketio.uploader.start({ + file: fileobj, + filename: args.filename, + is_private: args.is_private, + fallback: () => { + // if fails, use old filereader + upload_with_filedata(); + }, + callback: (data) => { + args.file_url = data.file_url; + frappe.upload._upload_file(fileobj, args, opts); + }, + on_progress: (percent_complete) => { + let increment = (flt(percent_complete) / frappe.upload.total_files); + frappe.show_progress(__('Uploading'), + start_complete + increment); + } + }); + } }, upload_to_server: function(file, args, opts) { diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js index 06d61c4373..bbbd42aee9 100755 --- a/frappe/public/js/frappe/views/communication.js +++ b/frappe/public/js/frappe/views/communication.js @@ -555,10 +555,10 @@ frappe.views.CommunicationComposer = Class.extend({ is_print_letterhead_checked: function() { if (this.frm && $(this.frm.wrapper).find('.form-print-wrapper').is(':visible')){ - return $(this.frm.wrapper).find('.print-letterhead').prop('checked'); + return $(this.frm.wrapper).find('.print-letterhead').prop('checked') ? 1 : 0; } else { return (frappe.model.get_doc(":Print Settings", "Print Settings") || - { with_letterhead: 1 }).with_letterhead ? true : false; + { with_letterhead: 1 }).with_letterhead ? 1 : 0; } }, diff --git a/frappe/utils/file_manager.py b/frappe/utils/file_manager.py index 40b612174a..546381d1e8 100644 --- a/frappe/utils/file_manager.py +++ b/frappe/utils/file_manager.py @@ -88,6 +88,7 @@ def save_url(file_url, filename, dt, dn, folder, is_private, df=None): # return None, None file_url = unquote(file_url) + file_size = frappe.form_dict.file_size f = frappe.get_doc({ "doctype": "File", @@ -97,6 +98,7 @@ def save_url(file_url, filename, dt, dn, folder, is_private, df=None): "attached_to_name": dn, "attached_to_field": df, "folder": folder, + "file_size": file_size, "is_private": is_private }) f.flags.ignore_permissions = True @@ -416,3 +418,8 @@ def get_random_filename(extn=None, content_type=None): extn = mimetypes.guess_extension(content_type) return random_string(7) + (extn or "") + +@frappe.whitelist() +def validate_filename(filename): + fname = get_file_name(filename, hashlib.md5(filename).hexdigest()[-6:]) + return fname diff --git a/frappe/www/printview.html b/frappe/www/printview.html index 6136426593..ecefab57ad 100644 --- a/frappe/www/printview.html +++ b/frappe/www/printview.html @@ -9,6 +9,9 @@ href="/assets/frappe/css/bootstrap.css"> + {%- if has_rtl -%} + + {%- endif -%} diff --git a/frappe/www/printview.py b/frappe/www/printview.py index c0fff90a90..7a40b96c49 100644 --- a/frappe/www/printview.py +++ b/frappe/www/printview.py @@ -41,7 +41,8 @@ def get_context(context): no_letterhead=frappe.form_dict.no_letterhead), "css": get_print_style(frappe.form_dict.style, print_format), "comment": frappe.session.user, - "title": doc.get(meta.title_field) if meta.title_field else doc.name + "title": doc.get(meta.title_field) if meta.title_field else doc.name, + "has_rtl": True if frappe.local.lang in ["ar", "he", "fa"] else False } def get_print_format_doc(print_format_name, meta): diff --git a/frappe/www/search.py b/frappe/www/search.py index baf2be4e63..c55970c1fc 100644 --- a/frappe/www/search.py +++ b/frappe/www/search.py @@ -4,13 +4,14 @@ from frappe.utils.global_search import web_search from html2text import html2text from frappe import _ from jinja2 import utils +from frappe.utils import sanitize_html def get_context(context): context.no_cache = 1 if frappe.form_dict.q: - frappe.form_dict.q = str(utils.escape(frappe.form_dict.q)) - context.title = _('Search Results for "{0}"').format(frappe.form_dict.q) - context.update(get_search_results(frappe.form_dict.q)) + query = str(utils.escape(sanitize_html(frappe.form_dict.q))) + context.title = _('Search Results for "{0}"').format(query) + context.update(get_search_results(query)) else: context.title = _('Search')