diff --git a/frappe/cache_manager.py b/frappe/cache_manager.py index f1b5d95056..f723e43173 100644 --- a/frappe/cache_manager.py +++ b/frappe/cache_manager.py @@ -17,6 +17,10 @@ def clear_user_cache(user=None): "defaults", "user_permissions", "home_page", "linked_with", "desktop_icons", 'portal_menu_items') + # this will automatically reload the global cache + # so it is important to clear this first + clear_notifications(user) + if user: for name in groups: cache.hdel(name, user) @@ -28,8 +32,6 @@ def clear_user_cache(user=None): clear_defaults_cache() clear_global_cache() - clear_notifications(user) - def clear_global_cache(): from frappe.website.render import clear_cache as clear_website_cache diff --git a/frappe/commands/site.py b/frappe/commands/site.py index d24f8f2155..5634e6108d 100755 --- a/frappe/commands/site.py +++ b/frappe/commands/site.py @@ -184,15 +184,17 @@ def list_apps(context): @click.argument('email') @click.option('--first-name') @click.option('--last-name') +@click.option('--password') @click.option('--send-welcome-email', default=False, is_flag=True) @pass_context -def add_system_manager(context, email, first_name, last_name, send_welcome_email): +def add_system_manager(context, email, first_name, last_name, send_welcome_email, password): "Add a new system manager to a site" import frappe.utils.user for site in context.sites: frappe.connect(site=site) try: - frappe.utils.user.add_system_manager(email, first_name, last_name, send_welcome_email) + frappe.utils.user.add_system_manager(email, first_name, last_name, + send_welcome_email, password) frappe.db.commit() finally: frappe.destroy() diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index 5196bc9eef..984d078dae 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -9,6 +9,8 @@ from frappe.commands import pass_context, get_site from frappe.utils import update_progress_bar, get_bench_path from frappe.utils.response import json_handler from coverage import Coverage +import cProfile, pstats +from six import StringIO @click.command('build') @click.option('--app', help='Build assets for app') @@ -114,8 +116,9 @@ def reset_perms(context): @click.argument('method') @click.option('--args') @click.option('--kwargs') +@click.option('--profile', is_flag=True, default=False) @pass_context -def execute(context, method, args=None, kwargs=None): +def execute(context, method, args=None, kwargs=None, profile=False): "Execute a function" for site in context.sites: try: @@ -135,8 +138,18 @@ def execute(context, method, args=None, kwargs=None): else: kwargs = {} + if profile: + pr = cProfile.Profile() + pr.enable() + ret = frappe.get_attr(method)(*args, **kwargs) + if profile: + pr.disable() + s = StringIO() + pstats.Stats(pr, stream=s).sort_stats('cumulative').print_stats(.5) + print(s.getvalue()) + if frappe.db: frappe.db.commit() finally: diff --git a/frappe/contacts/doctype/address_template/address_template.py b/frappe/contacts/doctype/address_template/address_template.py index 9336f75027..2ca9aebff5 100644 --- a/frappe/contacts/doctype/address_template/address_template.py +++ b/frappe/contacts/doctype/address_template/address_template.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document +from frappe.utils import cint from frappe.utils.jinja import validate_template from frappe import _ @@ -17,7 +18,8 @@ class AddressTemplate(Document): if not self.is_default: if not self.defaults: self.is_default = 1 - frappe.msgprint(_("Setting this Address Template as default as there is no other default")) + if cint(frappe.db.get_single_value('System Settings', 'setup_complete')): + frappe.msgprint(_("Setting this Address Template as default as there is no other default")) validate_template(self.template) diff --git a/frappe/custom/doctype/custom_field/custom_field.py b/frappe/custom/doctype/custom_field/custom_field.py index 29595fccf1..361680af44 100644 --- a/frappe/custom/doctype/custom_field/custom_field.py +++ b/frappe/custom/doctype/custom_field/custom_field.py @@ -106,7 +106,9 @@ def create_custom_field(doctype, df, ignore_validate=False): "dt": doctype, "permlevel": 0, "fieldtype": 'Data', - "hidden": 0 + "hidden": 0, + # Looks like we always use this programatically? + # "is_standard": 1 }) custom_field.update(df) custom_field.flags.ignore_validate = ignore_validate @@ -125,6 +127,7 @@ def create_custom_fields(custom_fields, ignore_validate = False, update=True): field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": df["fieldname"]}) if not field: try: + df["owner"] = "Administrator" create_custom_field(doctype, df, ignore_validate=ignore_validate) except frappe.exceptions.DuplicateEntryError: pass diff --git a/frappe/desk/doctype/kanban_board/kanban_board.py b/frappe/desk/doctype/kanban_board/kanban_board.py index cc207c19e6..923ca8aa6b 100644 --- a/frappe/desk/doctype/kanban_board/kanban_board.py +++ b/frappe/desk/doctype/kanban_board/kanban_board.py @@ -137,7 +137,8 @@ def quick_kanban_board(doctype, board_name, field_name, project=None): 'label': 'Kanban Column', 'fieldname': 'kanban_column', 'fieldtype': 'Select', - 'hidden': 1 + 'hidden': 1, + 'owner': 'Administrator' }) meta = frappe.get_meta(doctype) diff --git a/frappe/desk/notifications.py b/frappe/desk/notifications.py index b3100a43da..fa350d9d8d 100644 --- a/frappe/desk/notifications.py +++ b/frappe/desk/notifications.py @@ -29,7 +29,7 @@ def get_notifications(): notification_count[name] = count return { - "open_count_doctype": get_notifications_for_doctypes(config, notification_count), + "open_count_doctype": {}, "open_count_module": get_notifications_for_modules(config, notification_count), "open_count_other": get_notifications_for_other(config, notification_count), "targets": get_notifications_for_targets(config, notification_percent), diff --git a/frappe/desk/page/setup_wizard/setup_wizard.py b/frappe/desk/page/setup_wizard/setup_wizard.py index 4ab8941c64..cf8f5f502b 100755 --- a/frappe/desk/page/setup_wizard/setup_wizard.py +++ b/frappe/desk/page/setup_wizard/setup_wizard.py @@ -356,3 +356,55 @@ def enable_twofactor_all_roles(): all_role.two_factor_auth = True all_role.save(ignore_permissions=True) +def make_records(records, debug=False): + from frappe import _dict + from frappe.modules import scrub + + if debug: + print("make_records: in DEBUG mode") + + # LOG every success and failure + for record in records: + + doctype = record.get("doctype") + condition = record.get('__condition') + + if condition and not condition(): + continue + + doc = frappe.new_doc(doctype) + doc.update(record) + + # ignore mandatory for root + parent_link_field = ("parent_" + scrub(doc.doctype)) + if doc.meta.get_field(parent_link_field) and not doc.get(parent_link_field): + doc.flags.ignore_mandatory = True + + try: + doc.insert(ignore_permissions=True) + + except frappe.DuplicateEntryError as e: + # print("Failed to insert duplicate {0} {1}".format(doctype, doc.name)) + + # pass DuplicateEntryError and continue + if e.args and e.args[0]==doc.doctype and e.args[1]==doc.name: + # make sure DuplicateEntryError is for the exact same doc and not a related doc + pass + else: + raise + + except Exception as e: + exception = record.get('__exception') + if exception: + config = _dict(exception) + if isinstance(e, config.exception): + config.handler() + else: + show_document_insert_error() + else: + show_document_insert_error() + + +def show_document_insert_error(): + print("Document Insert Error") + print(frappe.get_traceback()) diff --git a/frappe/hooks.py b/frappe/hooks.py index 9d7cd27c7a..bb3458d35a 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -12,7 +12,7 @@ source_link = "https://github.com/frappe/frappe" app_license = "MIT" develop_version = '12.x.x-develop' -staging_version = '11.0.3-beta.36' +staging_version = '11.0.3-beta.37' app_email = "info@frappe.io" diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js index 16bd93a622..2f428f83db 100644 --- a/frappe/public/js/frappe/desk.js +++ b/frappe/public/js/frappe/desk.js @@ -80,6 +80,11 @@ frappe.Application = Class.extend({ this.show_update_available(); + if(frappe.ui.startup_setup_dialog && !frappe.boot.setup_complete) { + frappe.ui.startup_setup_dialog.pre_show(); + frappe.ui.startup_setup_dialog.show(); + } + // listen to csrf_update frappe.realtime.on("csrf_generated", function(data) { // handles the case when a user logs in again from another tab diff --git a/frappe/public/js/frappe/form/controls/comment.js b/frappe/public/js/frappe/form/controls/comment.js index bd7189d5f3..3abbbd0ff6 100644 --- a/frappe/public/js/frappe/form/controls/comment.js +++ b/frappe/public/js/frappe/form/controls/comment.js @@ -124,4 +124,8 @@ frappe.ui.form.ControlComment = frappe.ui.form.ControlTextEditor.extend({ ['clean'] ]; }, -}); \ No newline at end of file + + clear() { + this.quill.setText(''); + } +}); diff --git a/frappe/public/js/frappe/list/list_sidebar.js b/frappe/public/js/frappe/list/list_sidebar.js index b755edbd73..1735bae13d 100644 --- a/frappe/public/js/frappe/list/list_sidebar.js +++ b/frappe/public/js/frappe/list/list_sidebar.js @@ -125,8 +125,11 @@ frappe.views.ListSidebar = class ListSidebar { add_reports(this.list_view.settings.reports); } + // Sort reports alphabetically + var reports = Object.values(frappe.boot.user.all_reports).sort((a,b) => a.title.localeCompare(b.title)) || []; + // from specially tagged reports - add_reports(frappe.boot.user.all_reports || []); + add_reports(reports); } setup_list_filter() { diff --git a/frappe/public/js/frappe/misc/utils.js b/frappe/public/js/frappe/misc/utils.js index 67d877bb87..4175ace769 100644 --- a/frappe/public/js/frappe/misc/utils.js +++ b/frappe/public/js/frappe/misc/utils.js @@ -92,6 +92,15 @@ Object.assign(frappe.utils, { return txt.toLowerCase().substr(0,7)=='http://' || txt.toLowerCase().substr(0,8)=='https://' }, + to_title_case: function(string, with_space=false) { + let titlecased_string = string.toLowerCase().replace(/(?:^|[\s-/])\w/g, function(match) { + return match.toUpperCase(); + }); + + let replace_with = with_space ? ' ' : ''; + + return titlecased_string.replace(/-|_/g, replace_with); + }, toggle_blockquote: function(txt) { if (!txt) return txt; diff --git a/frappe/public/js/frappe/router.js b/frappe/public/js/frappe/router.js index 8bf3505c0a..ad2fe9a058 100644 --- a/frappe/public/js/frappe/router.js +++ b/frappe/public/js/frappe/router.js @@ -44,19 +44,24 @@ frappe.route = function() { frappe.route_history.push(route); - if(route[0] && route[1] && frappe.views[route[0] + "Factory"]) { - // has a view generator, generate! - if(!frappe.view_factory[route[0]]) { - frappe.view_factory[route[0]] = new frappe.views[route[0] + "Factory"](); - } + if(route[0]) { + const title_cased_route = frappe.utils.to_title_case(route[0]); - frappe.view_factory[route[0]].show(); - } else { - // show page - const route_name = frappe.utils.xss_sanitise(route[0]); - if (frappe.views.pageview) { + if(route[1] && frappe.views[title_cased_route + "Factory"]) { + // has a view generator, generate! + if(!frappe.view_factory[title_cased_route]) { + frappe.view_factory[title_cased_route] = new frappe.views[title_cased_route + "Factory"](); + } + + frappe.view_factory[title_cased_route].show(); + } else { + // show page + const route_name = frappe.utils.xss_sanitise(route[0]); frappe.views.pageview.show(route_name); } + } else { + // Show desk + frappe.views.pageview.show(''); } diff --git a/frappe/public/js/frappe/ui/dialog.js b/frappe/public/js/frappe/ui/dialog.js index 2815cbbda3..cd76db91d4 100644 --- a/frappe/public/js/frappe/ui/dialog.js +++ b/frappe/public/js/frappe/ui/dialog.js @@ -20,6 +20,14 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup { make() { this.$wrapper = frappe.get_modal("", ""); + if(this.static) { + this.$wrapper.modal({ + backdrop: 'static', + keyboard: false + }); + this.get_close_btn().hide(); + } + this.wrapper = this.$wrapper.find('.modal-dialog') .get(0); if ( this.size == "small" ) diff --git a/frappe/public/js/frappe/ui/sort_selector.html b/frappe/public/js/frappe/ui/sort_selector.html index 2452c40d5e..ab41953e68 100644 --- a/frappe/public/js/frappe/ui/sort_selector.html +++ b/frappe/public/js/frappe/ui/sort_selector.html @@ -17,7 +17,7 @@ \ No newline at end of file diff --git a/frappe/public/js/frappe/ui/toolbar/navbar.html b/frappe/public/js/frappe/ui/toolbar/navbar.html index 7115f17726..dc13b357cc 100644 --- a/frappe/public/js/frappe/ui/toolbar/navbar.html +++ b/frappe/public/js/frappe/ui/toolbar/navbar.html @@ -11,13 +11,6 @@