diff --git a/frappe/__init__.py b/frappe/__init__.py index f3fbc6b885..9afa2d8721 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -13,7 +13,6 @@ from MySQLdb import ProgrammingError as SQLError import os, sys, importlib, inspect import json -import semantic_version from .exceptions import * @@ -54,15 +53,8 @@ def get_lang_dict(fortype, name=None): return get_dict(fortype, name) def set_user_lang(user, user_language=None): - from frappe.translate import get_lang_dict - - if not user_language: - user_language = db.get_value("User", user, "language") - - if user_language: - lang_dict = get_lang_dict() - if user_language in lang_dict: - local.lang = lang_dict[user_language] + from frappe.translate import get_user_lang + local.lang = get_user_lang(user) # local-globals db = local("db") diff --git a/frappe/auth.py b/frappe/auth.py index 58e164fdcb..b9276ad186 100644 --- a/frappe/auth.py +++ b/frappe/auth.py @@ -51,33 +51,8 @@ class HTTPRequest: frappe.local.login_manager.run_trigger('on_session_creation') def set_lang(self, lang): - if not lang: - return - - import translate - lang_list = translate.get_all_languages() or [] - - if ";" in lang: # not considering weightage - lang = lang.split(";")[0] - if "," in lang: - lang = lang.split(",") - else: - lang = [lang] - - for l in lang: - code = l.strip() - if code in lang_list: - frappe.local.lang = code - break - - # check if parent language (pt) is setup, if variant (pt-BR) - if "-" in code: - code = code.split("-")[0] - if code in lang_list: - frappe.local.lang = code - break - - print frappe.local.lang + from frappe.translate import guess_language_from_http_header + frappe.local.lang = guess_language_from_http_header(lang) def setup_user(self): frappe.local.user = frappe.utils.user.User() diff --git a/frappe/boot.py b/frappe/boot.py index 679464ca8d..53d8251ebb 100644 --- a/frappe/boot.py +++ b/frappe/boot.py @@ -83,7 +83,7 @@ def add_allowed_pages(bootinfo): def load_translations(bootinfo): frappe.set_user_lang(frappe.session.user) - if frappe.lang != 'en': + if frappe.local.lang != 'en': bootinfo["__messages"] = frappe.get_lang_dict("boot") bootinfo["lang"] = frappe.lang diff --git a/frappe/config/setup.py b/frappe/config/setup.py index be66214ed1..4ffa119167 100644 --- a/frappe/config/setup.py +++ b/frappe/config/setup.py @@ -33,15 +33,15 @@ data = [ ] }, { - "label": _("Tools"), + "label": _("Settings"), "icon": "icon-wrench", "items": [ { - "type": "page", - "name": "data-import-tool", - "label": _("Import / Export Data"), - "icon": "icon-upload", - "description": _("Import / Export Data from .csv files.") + "type": "doctype", + "name": "System Settings", + "label": _("System Settings"), + "description": _("Language, Date and Time settings"), + "hide_count": True }, { "type": "page", @@ -56,6 +56,19 @@ data = [ "description": _("Set numbering series for transactions."), "hide_count": True }, + ] + }, + { + "label": _("Data"), + "icon": "icon-th", + "items": [ + { + "type": "page", + "name": "data-import-tool", + "label": _("Import / Export Data"), + "icon": "icon-upload", + "description": _("Import / Export Data from .csv files.") + }, { "type": "doctype", "name": "Rename Tool", diff --git a/frappe/core/doctype/system_settings/__init__.py b/frappe/core/doctype/system_settings/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/core/doctype/system_settings/system_settings.js b/frappe/core/doctype/system_settings/system_settings.js new file mode 100644 index 0000000000..c5c48cfe05 --- /dev/null +++ b/frappe/core/doctype/system_settings/system_settings.js @@ -0,0 +1,17 @@ +frappe.ui.form.on("System Settings", "refresh", function(frm) { + frappe.call({ + method: "frappe.core.doctype.system_settings.system_settings.load", + callback: function(data) { + frappe.all_timezones = data.message.timezones; + frappe.languages = data.message.languages; + frm.set_df_property("time_zone", "options", frappe.all_timezones); + frm.set_df_property("language", "options", frappe.languages); + + $.each(data.message.defaults, function(key, val) { + frm.set_value(key, val); + sys_defaults[key] = val; + }) + } + }); +}); + diff --git a/frappe/core/doctype/system_settings/system_settings.json b/frappe/core/doctype/system_settings/system_settings.json new file mode 100644 index 0000000000..df30c669e9 --- /dev/null +++ b/frappe/core/doctype/system_settings/system_settings.json @@ -0,0 +1,339 @@ +{ + "_last_update": null, + "_user_tags": null, + "allow_attach": null, + "allow_copy": null, + "allow_email": null, + "allow_import": null, + "allow_print": null, + "allow_rename": null, + "allow_trash": null, + "autoname": null, + "change_log": null, + "client_script": null, + "client_script_core": null, + "client_string": null, + "colour": null, + "creation": "2014-04-17 16:53:52.640856", + "custom": null, + "default_print_format": null, + "description": null, + "docstatus": 0, + "doctype": "DocType", + "document_type": "System", + "dt_template": null, + "fields": [ + { + "allow_on_submit": null, + "default": null, + "depends_on": null, + "description": null, + "fieldname": "localization", + "fieldtype": "Section Break", + "hidden": null, + "ignore_restrictions": null, + "in_filter": null, + "in_list_view": null, + "label": "Localization", + "no_column": null, + "no_copy": null, + "oldfieldname": null, + "oldfieldtype": null, + "options": null, + "permlevel": 0, + "print_hide": null, + "print_width": null, + "read_only": null, + "report_hide": null, + "reqd": null, + "search_index": null, + "set_only_once": null, + "trigger": null, + "width": null + }, + { + "allow_on_submit": null, + "default": null, + "depends_on": null, + "description": null, + "fieldname": "language", + "fieldtype": "Select", + "hidden": null, + "ignore_restrictions": null, + "in_filter": null, + "in_list_view": 1, + "label": "Language", + "no_column": null, + "no_copy": null, + "oldfieldname": null, + "oldfieldtype": null, + "options": "Loading...", + "permlevel": 0, + "print_hide": null, + "print_width": null, + "read_only": null, + "report_hide": null, + "reqd": 1, + "search_index": 0, + "set_only_once": null, + "trigger": null, + "width": null + }, + { + "allow_on_submit": null, + "default": null, + "depends_on": null, + "description": null, + "fieldname": "time_zone", + "fieldtype": "Select", + "hidden": null, + "ignore_restrictions": null, + "in_filter": null, + "in_list_view": null, + "label": "Time Zone", + "no_column": null, + "no_copy": null, + "oldfieldname": null, + "oldfieldtype": null, + "options": null, + "permlevel": 0, + "print_hide": null, + "print_width": null, + "read_only": null, + "report_hide": null, + "reqd": 1, + "search_index": null, + "set_only_once": null, + "trigger": null, + "width": null + }, + { + "allow_on_submit": null, + "default": null, + "depends_on": null, + "description": null, + "fieldname": "date_and_number_format", + "fieldtype": "Section Break", + "hidden": null, + "ignore_restrictions": null, + "in_filter": null, + "in_list_view": null, + "label": "Date and Number Format", + "no_column": null, + "no_copy": null, + "oldfieldname": null, + "oldfieldtype": null, + "options": null, + "permlevel": 0, + "print_hide": null, + "print_width": null, + "read_only": null, + "report_hide": null, + "reqd": null, + "search_index": null, + "set_only_once": null, + "trigger": null, + "width": null + }, + { + "allow_on_submit": null, + "default": null, + "depends_on": null, + "description": null, + "fieldname": "date_format", + "fieldtype": "Select", + "hidden": null, + "ignore_restrictions": null, + "in_filter": null, + "in_list_view": null, + "label": "Date Format", + "no_column": null, + "no_copy": null, + "oldfieldname": null, + "oldfieldtype": null, + "options": "yyyy-mm-dd\ndd-mm-yyyy\ndd/mm/yyyy\nmm/dd/yyyy\nmm-dd-yyyy", + "permlevel": 0, + "print_hide": null, + "print_width": null, + "read_only": null, + "report_hide": null, + "reqd": 1, + "search_index": null, + "set_only_once": null, + "trigger": null, + "width": null + }, + { + "allow_on_submit": null, + "default": null, + "depends_on": null, + "description": null, + "fieldname": "number_format", + "fieldtype": "Select", + "hidden": null, + "ignore_restrictions": null, + "in_filter": null, + "in_list_view": null, + "label": "Number Format", + "no_column": null, + "no_copy": null, + "oldfieldname": null, + "oldfieldtype": null, + "options": "#,###.##\n#.###,##\n# ###.##\n#,###.###\n#,##,###.##\n#.###\n#,###", + "permlevel": 0, + "print_hide": null, + "print_width": null, + "read_only": null, + "report_hide": null, + "reqd": 1, + "search_index": null, + "set_only_once": null, + "trigger": null, + "width": null + }, + { + "allow_on_submit": null, + "default": null, + "depends_on": null, + "description": null, + "fieldname": "float_precision", + "fieldtype": "Select", + "hidden": null, + "ignore_restrictions": null, + "in_filter": null, + "in_list_view": null, + "label": "Float Precision", + "no_column": null, + "no_copy": null, + "oldfieldname": null, + "oldfieldtype": null, + "options": "\n2\n3\n4\n5\n6", + "permlevel": 0, + "print_hide": null, + "print_width": null, + "read_only": null, + "report_hide": null, + "reqd": null, + "search_index": null, + "set_only_once": null, + "trigger": null, + "width": null + }, + { + "allow_on_submit": null, + "default": null, + "depends_on": null, + "description": null, + "fieldname": "security", + "fieldtype": "Section Break", + "hidden": null, + "ignore_restrictions": null, + "in_filter": null, + "in_list_view": null, + "label": "Security", + "no_column": null, + "no_copy": null, + "oldfieldname": null, + "oldfieldtype": null, + "options": null, + "permlevel": 0, + "print_hide": null, + "print_width": null, + "read_only": null, + "report_hide": null, + "reqd": null, + "search_index": null, + "set_only_once": null, + "trigger": null, + "width": null + }, + { + "allow_on_submit": null, + "default": "06:00", + "depends_on": null, + "description": "Session Expiry in Hours e.g. 06:00", + "fieldname": "session_expiry", + "fieldtype": "Data", + "hidden": null, + "ignore_restrictions": null, + "in_filter": null, + "in_list_view": null, + "label": "Session Expiry", + "no_column": null, + "no_copy": null, + "oldfieldname": null, + "oldfieldtype": null, + "options": "", + "permlevel": 0, + "print_hide": null, + "print_width": null, + "read_only": null, + "report_hide": null, + "reqd": null, + "search_index": null, + "set_only_once": null, + "trigger": null, + "width": null + } + ], + "hide_heading": null, + "hide_toolbar": null, + "icon": "icon-cog", + "idx": null, + "in_create": null, + "in_dialog": null, + "is_submittable": null, + "is_transaction_doc": null, + "issingle": 1, + "istable": null, + "max_attachments": null, + "menu_index": null, + "modified": "2014-04-17 17:52:27.046530", + "modified_by": "Administrator", + "module": "Core", + "name": "System Settings", + "name_case": "", + "owner": "Administrator", + "parent": null, + "parent_node": null, + "parentfield": null, + "parenttype": null, + "permissions": [ + { + "amend": null, + "cancel": null, + "create": 1, + "delete": null, + "email": null, + "export": null, + "import": null, + "match": null, + "permlevel": 0, + "print": null, + "read": 1, + "report": null, + "restrict": null, + "restricted": null, + "role": "System Manager", + "submit": null, + "write": 1 + } + ], + "plugin": null, + "print_outline": null, + "read_only": null, + "read_only_onload": null, + "search_fields": null, + "section_style": null, + "server_code": null, + "server_code_compiled": null, + "server_code_core": null, + "server_code_error": null, + "show_in_menu": null, + "smallicon": null, + "subject": null, + "tag_fields": null, + "title_field": null, + "use_template": null, + "version": null +} \ No newline at end of file diff --git a/frappe/core/doctype/system_settings/system_settings.py b/frappe/core/doctype/system_settings/system_settings.py new file mode 100644 index 0000000000..2491a4a9b0 --- /dev/null +++ b/frappe/core/doctype/system_settings/system_settings.py @@ -0,0 +1,45 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe, pytz +from frappe import _ +from frappe.model.document import Document +from frappe.translate import get_lang_dict, set_default_language +from frappe.utils import cint + +class SystemSettings(Document): + def validate(self): + if self.session_expiry: + parts = self.session_expiry.split(":") + if len(parts)!=2 or not (cint(parts[0]) or cint(parts[1])): + frappe.throw(_("Session Expiry must be in format {0}").format("hh:mm")) + + def on_update(self): + for df in self.meta.get("fields"): + if df.fieldtype in ("Select", "Data"): + frappe.db.set_default(df.fieldname, self.get(df.fieldname)) + + set_default_language(self.language) + + +@frappe.whitelist() +def load(): + if not "System Manager" in frappe.get_roles(): + frappe.throw(_("Not permitted"), frappe.PermissionError) + + all_defaults = frappe.db.get_defaults() + defaults = {} + + for df in frappe.get_meta("System Settings").get("fields"): + if df.fieldtype in ("Select", "Data"): + defaults[df.fieldname] = all_defaults.get(df.fieldname) + + languages = get_lang_dict().keys() + languages.sort() + + return { + "timezones": pytz.all_timezones, + "languages": [""] + languages, + "defaults": defaults + } diff --git a/frappe/public/js/frappe/form/infobar.js b/frappe/public/js/frappe/form/infobar.js index e2c059fdea..330c070b3e 100644 --- a/frappe/public/js/frappe/form/infobar.js +++ b/frappe/public/js/frappe/form/infobar.js @@ -11,32 +11,32 @@ frappe.ui.form.InfoBar = Class.extend({ var me = this; this.appframe.iconbar.clear(2); - this.$reload = this.appframe.add_icon_btn("2", "icon-refresh", __("Reload Page"), + this.$reload = this.appframe.add_icon_btn("2", "icon-refresh", __("Reload Page"), function() { me.frm.reload_doc(); }) - this.$timestamp = this.appframe.add_icon_btn("2", "icon-user", __("Creation / Modified By"), + this.$timestamp = this.appframe.add_icon_btn("2", "icon-user", __("Creation / Modified By"), function() { }) this.$comments = this.appframe.add_icon_btn("2", "icon-comments", __("Comments"), function() { me.scroll_to(".form-comments"); }); - + this.$attachments = this.appframe.add_icon_btn("2", "icon-paper-clip", __("Attachments"), function() { me.scroll_to(".form-attachments"); }); this.$assignments = this.appframe.add_icon_btn("2", "icon-flag", __("Assignments"), function() { me.scroll_to(".form-attachments"); - }); + }); - this.$links = this.appframe.add_icon_btn("2", "icon-link", __("Linked With"), + this.$links = this.appframe.add_icon_btn("2", "icon-link", __("Linked With"), function() { me.frm.toolbar.show_linked_with(); }); - + // link to user restrictions - if(frappe.model.can_restrict(me.frm.doctype, me.frm)) { - this.$user_properties = this.appframe.add_icon_btn("2", "icon-shield", + if(!me.frm.meta.issingle && frappe.model.can_restrict(me.frm.doctype, me.frm)) { + this.$user_properties = this.appframe.add_icon_btn("2", "icon-shield", __("User Permission Restrictions"), function() { frappe.route_options = { property: me.frm.doctype, @@ -47,36 +47,36 @@ frappe.ui.form.InfoBar = Class.extend({ } if(frappe.model.can_print(me.frm.doctype, me.frm)) { - this.$print = this.appframe.add_icon_btn("2", "icon-print", __("Print"), + this.$print = this.appframe.add_icon_btn("2", "icon-print", __("Print"), function() { me.frm.print_doc(); }); } if(frappe.model.can_email(me.frm.doctype, me.frm)) { - this.$print = this.appframe.add_icon_btn("2", "icon-envelope", __("Email"), + this.$print = this.appframe.add_icon_btn("2", "icon-envelope", __("Email"), function() { me.frm.email_doc(); }); } - + if(!this.frm.meta.issingle) { - this.$prev = this.appframe.add_icon_btn("2", "icon-arrow-left", __("Previous Record"), + this.$prev = this.appframe.add_icon_btn("2", "icon-arrow-left", __("Previous Record"), function() { me.go_prev_next(true); }); - - this.$next = this.appframe.add_icon_btn("2", "icon-arrow-right", __("Next Record"), + + this.$next = this.appframe.add_icon_btn("2", "icon-arrow-right", __("Next Record"), function() { me.go_prev_next(false); }); } - + }, - - refresh: function() { + + refresh: function() { if(!this.frm.doc.__islocal) { this.docinfo = frappe.model.docinfo[this.frm.doctype][this.frm.docname]; // highlight comments this.highlight_items(); } }, - + highlight_items: function() { var me = this; - + this.$timestamp .popover("destroy") .popover({ @@ -92,15 +92,15 @@ frappe.ui.form.InfoBar = Class.extend({ this.$comments .popover("destroy") - + if(this.docinfo.comments && this.docinfo.comments.length) { var last = this.docinfo.comments[0]; this.$comments .popover({ title: "Last Comment", - content: last.comment + content: last.comment + '

By ' - + frappe.user_info(last.comment_by).fullname + + frappe.user_info(last.comment_by).fullname + " / " + comment_when(last.creation) + '

', trigger:"hover", @@ -108,7 +108,7 @@ frappe.ui.form.InfoBar = Class.extend({ placement: "bottom" }); } - + $.each(["comments", "attachments", "assignments"], function(i, v) { if(me.docinfo[v] && me.docinfo[v].length) me["$" + v].addClass("appframe-iconbar-active"); @@ -122,7 +122,7 @@ frappe.ui.form.InfoBar = Class.extend({ scrollTop: $(this.frm.wrapper).find(cls).offset().top }, 1000); }, - + go_prev_next: function(prev) { var me = this; return frappe.call({ @@ -138,4 +138,4 @@ frappe.ui.form.InfoBar = Class.extend({ } }); }, -}) \ No newline at end of file +}) diff --git a/frappe/public/js/frappe/misc/user.js b/frappe/public/js/frappe/misc/user.js index db7ba73e1c..43a3f337ad 100644 --- a/frappe/public/js/frappe/misc/user.js +++ b/frappe/public/js/frappe/misc/user.js @@ -5,7 +5,7 @@ frappe.user_info = function(uid) { var def = { - 'fullname':uid, + 'fullname':uid, 'image': 'assets/frappe/images/ui/avatar.png' } if(!frappe.boot.user_info) return def @@ -27,14 +27,15 @@ frappe.avatar = function(user, large, title) { image: image, title: title, small_or_large: large ? "avatar-large" : "avatar-small" - }); + }); } -frappe.ui.set_user_background = function(src) { +frappe.ui.set_user_background = function(src, selector) { + if(!selector) selector = "#page-desktop"; if(!src) src = "assets/frappe/images/ui/random-polygons.jpg"; - frappe.dom.set_style(repl('#page-desktop { \ + frappe.dom.set_style(repl('%(selector)s { \ background: url("%(src)s") center center; \ - }', {src:src})) + }', {src:src, selector:selector})) } frappe.provide('frappe.user'); @@ -53,7 +54,7 @@ $.extend(frappe.user, { return frappe.avatar(uid, large); }, has_role: function(rl) { - if(typeof rl=='string') + if(typeof rl=='string') rl = [rl]; for(var i in rl) { if((frappe.boot ? frappe.boot.user.roles : ['Guest']).indexOf(rl[i])!=-1) @@ -74,12 +75,12 @@ $.extend(frappe.user, { } }); } - + if(!modules_list || !modules_list.length) { // all modules modules_list = keys(frappe.modules).sort(); } - + // filter hidden modules if(frappe.boot.hidden_modules && modules_list) { var hidden_list = JSON.parse(frappe.boot.hidden_modules); @@ -137,7 +138,7 @@ $(document).bind('mousemove', function() { $(document).trigger("session_alive"); } frappe.session_alive = true; - if(frappe.session_alive_timeout) + if(frappe.session_alive_timeout) clearTimeout(frappe.session_alive_timeout); frappe.session_alive_timeout = setTimeout('frappe.session_alive=false;', 30000); -}) \ No newline at end of file +}) diff --git a/frappe/public/js/frappe/request.js b/frappe/public/js/frappe/request.js index c77587d018..8589b3f256 100644 --- a/frappe/public/js/frappe/request.js +++ b/frappe/public/js/frappe/request.js @@ -24,13 +24,6 @@ frappe.call = function(opts) { args.cmd = opts.method; } - // stringify args if required - for(key in args) { - if(args[key] && typeof args[key] != 'string') { - args[key] = JSON.stringify(args[key]); - } - } - return frappe.request.call({ type: opts.type || "POST", args: args, @@ -64,7 +57,12 @@ frappe.request.call = function(opts) { msgprint(__("Not permitted")); }, 200: function(data, xhr) { + if(typeof data === "string") data = JSON.parse(data); opts.success && opts.success(data, xhr.responseText); + }, + 501: function(data, xhr) { + if(typeof data === "string") data = JSON.parse(data); + opts.error && opts.error(data, xhr.responseText) } }, async: opts.async @@ -101,6 +99,9 @@ frappe.request.call = function(opts) { opts.error && opts.error(xhr) }) .always(function(data) { + if(typeof data==="string") { + data = JSON.parse(data); + } if(data.responseText) { data = JSON.parse(data.responseText); } @@ -119,6 +120,13 @@ frappe.request.prepare = function(opts) { // freeze page if(opts.freeze) frappe.dom.freeze(); + // stringify args if required + for(key in opts.args) { + if(opts.args[key] && ($.isPlainObject(opts.args[key]) || $.isArray(opts.args[key]))) { + opts.args[key] = JSON.stringify(opts.args[key]); + } + } + // no cmd? if(!opts.args.cmd) { console.log(opts) diff --git a/frappe/public/js/frappe/views/pageview.js b/frappe/public/js/frappe/views/pageview.js index 6534809cb0..950b8be475 100644 --- a/frappe/public/js/frappe/views/pageview.js +++ b/frappe/public/js/frappe/views/pageview.js @@ -24,17 +24,19 @@ frappe.views.pageview = { } else { // get fresh return frappe.call({ - method: 'frappe.widgets.page.getpage', + method: 'frappe.widgets.page.getpage', args: {'name':name }, callback: function(r) { localStorage["_page:" + name] = JSON.stringify(r.docs); callback(); } }); - } + } }, show: function(name) { - if(!name) name = (frappe.boot ? frappe.boot.home_page : window.page_name); + if(!name) { + name = (frappe.boot ? frappe.boot.home_page : window.page_name); + } frappe.model.with_doctype("Page", function() { frappe.views.pageview.with_page(name, function(r) { if(r && r.exc) { @@ -68,7 +70,7 @@ frappe.views.Page = Class.extend({ this.wrapper = frappe.container.add_page(this.name); this.wrapper.label = this.pagedoc.title || this.pagedoc.name; this.wrapper.page_name = this.pagedoc.name; - + // set content, script and style if(this.pagedoc.content) this.wrapper.innerHTML = this.pagedoc.content; @@ -77,7 +79,7 @@ frappe.views.Page = Class.extend({ } this.trigger('onload'); - + // set events $(this.wrapper).bind('show', function() { cur_frm = null; @@ -88,7 +90,7 @@ frappe.views.Page = Class.extend({ trigger: function(eventname) { var me = this; if(pscript[eventname+'_'+this.name]) { - pscript[eventname+'_'+this.name](me.wrapper); + pscript[eventname+'_'+this.name](me.wrapper); } else if(me.wrapper[eventname]) { me.wrapper[eventname](me.wrapper); } @@ -96,12 +98,12 @@ frappe.views.Page = Class.extend({ }) frappe.show_not_found = function(page_name) { - frappe.show_message_page(page_name, ' ' + __("Not Found"), + frappe.show_message_page(page_name, ' ' + __("Not Found"), __("Sorry we were unable to find what you were looking for.")); } frappe.show_not_permitted = function(page_name) { - frappe.show_message_page(page_name, ' ' +__("Not Permitted"), + frappe.show_message_page(page_name, ' ' +__("Not Permitted"), __("Sorry you are not permitted to view this page.")); } @@ -116,4 +118,4 @@ frappe.show_message_page = function(page_name, title, message) { \ '); frappe.container.change_to(page_name); -} \ No newline at end of file +} diff --git a/frappe/public/js/legacy/form.js b/frappe/public/js/legacy/form.js index 1d80e9d2b1..39dd17be75 100644 --- a/frappe/public/js/legacy/form.js +++ b/frappe/public/js/legacy/form.js @@ -61,7 +61,7 @@ _f.Frm.prototype.check_doctype_conflict = function(docname) { msgprint(__('Allowing DocType, DocType. Be careful!')) } else if(this.doctype=='DocType') { if (frappe.views.formview[docname] || frappe.pages['List/'+docname]) { - msgprint(__("Cannot open {0} when its instance is open"), ['DocType']) + msgprint(__("Cannot open {0} when its instance is open", ['DocType'])) throw 'doctype open conflict' } } else { diff --git a/frappe/sessions.py b/frappe/sessions.py index 3608cc37b7..c563259ded 100644 --- a/frappe/sessions.py +++ b/frappe/sessions.py @@ -28,17 +28,23 @@ def clear_cache(user=None): cache = frappe.cache() frappe.model.meta.clear_cache() - cache.delete_value(["app_hooks", "installed_apps", "app_modules", "module_apps", "home_page"]) + cache.delete_value(["app_hooks", "installed_apps", "app_modules", "module_apps", "home_page", + "time_zone"]) - if user: - cache.delete_value("bootinfo:" + user) - cache.delete_value("lang:" + user) - cache.delete_value("roles:" + user) - cache.delete_value("restrictions:" + user) + def delete_user_cache(user): + for key in ("bootinfo", "lang", "roles", "restrictions"): + cache.delete_value(key + ":" + user) - # clear notifications + def clear_notifications(user=None): if frappe.flags.in_install_app!="frappe": - frappe.db.sql("""delete from `tabNotification Count` where owner=%s""", (user,)) + if user: + frappe.db.sql("""delete from `tabNotification Count` where owner=%s""", (user,)) + else: + frappe.db.sql("""delete from `tabNotification Count`""") + + if user: + delete_user_cache(user) + clear_notifications(user) if frappe.session: if user==frappe.session.user and frappe.session.sid: @@ -51,9 +57,10 @@ def clear_cache(user=None): frappe.defaults.clear_cache(user) else: for sess in frappe.db.sql("""select user, sid from tabSessions""", as_dict=1): - cache.delete_value("lang:" + sess.user) + delete_user_cache(sess.user) cache.delete_value("session:" + sess.sid) - cache.delete_value("bootinfo:" + sess.user) + + clear_notifications() frappe.defaults.clear_cache() def clear_sessions(user=None, keep_current=False): @@ -160,8 +167,7 @@ class Session: else: self.start_as_guest() - frappe.local.lang = frappe.cache().get_value("lang:" + self.data.user, - lambda: frappe.translate.get_user_lang(self.data.user)) + frappe.local.lang = frappe.translate.get_user_lang(self.data.user) def get_session_record(self): """get session record, or return the standard Guest Record""" diff --git a/frappe/translate.py b/frappe/translate.py index 65f3571c23..483163639c 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -18,14 +18,62 @@ Contributing: import frappe, os, re, codecs, json +def guess_language_from_http_header(lang): + """set frappe.local.lang from HTTP headers at beginning of request""" + if not lang: + return frappe.local.lang + + guess = None + lang_list = get_all_languages() or [] + + if ";" in lang: # not considering weightage + lang = lang.split(";")[0] + if "," in lang: + lang = lang.split(",") + else: + lang = [lang] + + for l in lang: + code = l.strip() + if code in lang_list: + guess = code + break + + # check if parent language (pt) is setup, if variant (pt-BR) + if "-" in code: + code = code.split("-")[0] + if code in lang_list: + guess = code + break + + return guess or frappe.local.lang + def get_user_lang(user=None): + """set frappe.local.lang from user preferences on session beginning or resumption""" if not user: user = frappe.session.user - user_lang = frappe.db.get_value("User", user, "language") - if user_lang: - return get_lang_dict().get(user_lang!="Loading..." and user_lang or "english") - else: - return frappe.local.lang + + # via cache + lang = frappe.cache().get_value("lang:" + user) + + if not lang: + + # if defined in user profile + user_lang = frappe.db.get_value("User", user, "language") + if user_lang and user_lang!="Loading...": + lang = get_lang_dict().get(user_lang) + else: + default_lang = frappe.db.get_default("lang") + lang = default_lang or frappe.local.lang + + frappe.cache().set_value("lang:" + user, lang) + + return lang + +def set_default_language(language): + lang = get_lang_dict()[language] + frappe.db.set_default("lang", lang) + frappe.local.lang = lang def get_all_languages(): return [a.split()[0] for a in get_lang_info()] diff --git a/frappe/widgets/form/run_method.py b/frappe/widgets/form/run_method.py index 1992576015..9f88186c7c 100644 --- a/frappe/widgets/form/run_method.py +++ b/frappe/widgets/form/run_method.py @@ -34,15 +34,16 @@ def runserverobj(): args = frappe.form_dict.get('args', frappe.form_dict.get("arg")) args = json.loads(args) except ValueError: - r = doc.run_method(method, args) - except TypeError: - r = doc.run_method(method) - else: - fnargs, varargs, varkw, defaults = inspect.getargspec(getattr(doc, method)) - if "args" in fnargs: + try: r = doc.run_method(method, args) + except TypeError: + r = doc.run_method(method) else: - r = doc.run_method(method, **args) + fnargs, varargs, varkw, defaults = inspect.getargspec(getattr(doc, method)) + if "args" in fnargs: + r = doc.run_method(method, args) + else: + r = doc.run_method(method, **args) if r: #build output as csv