diff --git a/.travis.yml b/.travis.yml index 0dbd382702..df66db88a7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,43 +2,88 @@ language: python dist: trusty sudo: required -python: - - 2.7 - - 3.6 - -env: - - DB=mariadb - - DB=postgres - - TEST_TYPE=ui - -services: - - mysql - addons: - postgresql: "9.5" hosts: - test_site - - test_site_postgres - - test_site_ui + mariadb: 10.3 + postgresql: 9.5 + +git: + depth: 1 + +cache: + - pip + - npm + - yarn matrix: - exclude: - - python: 2.7 - env: DB=postgres - - python: 2.7 - env: TEST_TYPE=ui + include: + - name: "Python 3.6 MariaDB" + python: 3.6 + env: DB=mariadb TYPE=server + script: bench --site test_site run-tests --coverage + + - name: "Python 3.6 PostgreSQL" + python: 3.6 + env: DB=postgres TYPE=server + script: bench --site test_site run-tests --coverage + + - name: "Cypress" + python: 3.6 + env: DB=mariadb TYPE=ui + before_script: bench --site test_site execute frappe.utils.install.complete_setup_wizard + script: bench --site test_site run-ui-tests frappe --headless + + - name: "Python 2.7 MariaDB" + python: 2.7 + env: DB=mariadb TYPE=server + script: bench --site test_site run-tests --coverage install: - - $TRAVIS_BUILD_DIR/.travis/install.sh + - cd ~ + - source ./.nvm/nvm.sh + - nvm install v8.10.0 + + - git clone https://github.com/frappe/bench --depth 1 + - pip install -e ./bench + + - bench init frappe-bench --skip-assets --python $(which python) --frappe-path $TRAVIS_BUILD_DIR + + - mkdir ~/frappe-bench/sites/test_site + - cp $TRAVIS_BUILD_DIR/.travis/$DB.json ~/frappe-bench/sites/test_site/site_config.json + + - mysql -u root -e "SET GLOBAL character_set_server = 'utf8mb4'" + - mysql -u root -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'" + + - mysql -u root -e "CREATE DATABASE test_frappe" + - mysql -u root -e "CREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe'" + - mysql -u root -e "GRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost'" + + - mysql -u root -e "UPDATE mysql.user SET Password=PASSWORD('travis') WHERE User='root'" + - mysql -u root -e "FLUSH PRIVILEGES" + + - psql -c "CREATE DATABASE test_frappe" -U postgres + - psql -c "CREATE USER test_frappe WITH PASSWORD 'test_frappe'" -U postgres + + - wget -O /tmp/wkhtmltox.tar.xz https://github.com/frappe/wkhtmltopdf/raw/master/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz + - tar -xf /tmp/wkhtmltox.tar.xz -C /tmp + - sudo mv /tmp/wkhtmltox/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf + - sudo chmod o+x /usr/local/bin/wkhtmltopdf + + - cd ./frappe-bench + + - 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 == "ui" ]; then bench setup requirements --node; fi -before_script: - - cd ~/frappe-bench - - sed -i 's/9000/9001/g' sites/common_site_config.json - bench start & - - sleep 10 - -script: - - $TRAVIS_BUILD_DIR/.travis/run-tests.sh + - bench --site test_site reinstall --yes + - bench build --app frappe after_script: - - coveralls -b apps/frappe -d ../../sites/.coverage \ No newline at end of file + - pip install python-coveralls + - coveralls -b apps/frappe -d ../../sites/.coverage diff --git a/.travis/install.sh b/.travis/install.sh deleted file mode 100755 index a457939b22..0000000000 --- a/.travis/install.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -set -e - -sudo rm /etc/apt/sources.list.d/mongodb*.list -sudo rm /etc/apt/sources.list.d/docker.list -sudo apt-get install hhvm && rm -rf /home/travis/.kiex/ -sudo apt-get purge -y mysql-common mysql-server mysql-client -source ~/.nvm/nvm.sh -nvm install v8.10.0 - -pip install python-coveralls - -wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py - -sudo python install.py --develop --user travis --without-bench-setup -sudo pip install -e ~/bench - -rm $TRAVIS_BUILD_DIR/.git/shallow -cd ~/ && bench init frappe-bench --python $(which python) --frappe-path $TRAVIS_BUILD_DIR -if [[ $DB == 'mariadb' ]]; then - cp -r $TRAVIS_BUILD_DIR/test_sites/test_site ~/frappe-bench/sites/ -elif [[ $TEST_TYPE == 'ui' ]]; then - cp -r $TRAVIS_BUILD_DIR/test_sites/test_site_ui ~/frappe-bench/sites/ -elif [[ $DB == 'postgres' ]]; then - cp -r $TRAVIS_BUILD_DIR/test_sites/test_site_postgres ~/frappe-bench/sites/ -fi diff --git a/.travis/mariadb.json b/.travis/mariadb.json new file mode 100644 index 0000000000..550ad94769 --- /dev/null +++ b/.travis/mariadb.json @@ -0,0 +1,14 @@ +{ + "db_host": "localhost", + "db_name": "test_frappe", + "db_password": "test_frappe", + "db_type": "mariadb", + "auto_email_id": "test@example.com", + "mail_server": "smtp.example.com", + "mail_login": "test@example.com", + "mail_password": "test", + "admin_password": "admin", + "root_login": "root", + "root_password": "travis", + "host_name": "http://test_site:8000" +} diff --git a/.travis/postgres.json b/.travis/postgres.json new file mode 100644 index 0000000000..619dd91f10 --- /dev/null +++ b/.travis/postgres.json @@ -0,0 +1,14 @@ +{ + "db_host": "localhost", + "db_name": "test_frappe", + "db_password": "test_frappe", + "db_type": "postgres", + "auto_email_id": "test@example.com", + "mail_server": "smtp.example.com", + "mail_login": "test@example.com", + "mail_password": "test", + "admin_password": "admin", + "root_login": "postgres", + "root_password": "travis", + "host_name": "http://test_site:8000" +} diff --git a/.travis/run-tests.sh b/.travis/run-tests.sh deleted file mode 100755 index 177e191088..0000000000 --- a/.travis/run-tests.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -set -e - -setup_mariadb_env() { - mysql -u root -ptravis -e "create database $1" - mysql -u root -ptravis -e "USE mysql; CREATE USER '$1'@'localhost' IDENTIFIED BY '$1'; FLUSH PRIVILEGES; " - mysql -u root -ptravis -e "USE mysql; GRANT ALL PRIVILEGES ON \`$1\`.* TO '$1'@'localhost';" -} - -if [[ $DB == 'mariadb' ]]; then - setup_mariadb_env 'test_frappe' - bench --site test_site reinstall --yes - bench --site test_site scheduler disable - bench --site test_site run-tests --coverage - -elif [[ $TEST_TYPE == 'ui' ]]; then - setup_mariadb_env 'test_site_ui' - bench --site test_site_ui reinstall --yes - bench --site test_site_ui execute frappe.utils.install.complete_setup_wizard - bench --site test_site_ui scheduler disable - cd apps/frappe && yarn && yarn cypress:run - -elif [[ $DB == 'postgres' ]]; then - psql -c "CREATE DATABASE test_frappe;" -U postgres - psql -c "CREATE USER test_frappe WITH PASSWORD 'test_frappe';" -U postgres - bench --site test_site_postgres reinstall --yes - bench --site test_site_postgres scheduler disable - bench --site test_site_postgres run-tests --coverage -fi diff --git a/frappe/change_log/v12/v12_0_0.md b/frappe/change_log/v12/v12_0_0.md index 897b351122..215b612794 100644 --- a/frappe/change_log/v12/v12_0_0.md +++ b/frappe/change_log/v12/v12_0_0.md @@ -1,29 +1,29 @@ # Version 12 Release Notes ### UI/UX Enhancements -1. [New Desktop](/docs/user/manual/en/using-erpnext/desktop) -1. [Keyboard Navigation](/docs/user/manual/en/using-erpnext/articles/keyboard-shortcuts) -1. [Link Preview](/version-12/release-notes/features#link-preview) -1. [New Upload Dialog](/version-12/release-notes/features#new-upload-dialog) -1. [Frequently visited links appear in Awesomebar results](/version-12/release-notes/features#frequently-visited-links-appear-in-awesomebar-results) -1. [Full Width Container]((/version-12/release-notes/features#full-width-container)) -1. [List View Enhancements](/version-12/release-notes/features#list-view-enhancements) +1. [New Desktop](https://erpnext.com/docs/user/manual/en/using-erpnext/desktop) +1. [Keyboard Navigation](https://erpnext.com/docs/user/manual/en/using-erpnext/articles/keyboard-shortcuts) +1. [Link Preview](https://erpnext.com/version-12/release-notes/features#link-preview) +1. [New Upload Dialog](https://erpnext.com/version-12/release-notes/features#new-upload-dialog) +1. [Frequently visited links appear in Awesomebar results](https://erpnext.com/version-12/release-notes/features#frequently-visited-links-appear-in-awesomebar-results) +1. [Full Width Container]((https://erpnext.com/version-12/release-notes/features#full-width-container)) +1. [List View Enhancements](https://erpnext.com/version-12/release-notes/features#list-view-enhancements) ### New Automation Module -1. [Assignment Rule](/docs/user/manual/en/setting-up/automation/assignment-rule) -1. [Milestones](/docs/user/manual/en/setting-up/automation/milestone-tracker) -1. [Auto Repeat](/docs/user/manual/en/setting-up/automation/auto-repeat) +1. [Assignment Rule](https://erpnext.com/docs/user/manual/en/setting-up/automation/assignment-rule) +1. [Milestones](https://erpnext.com/docs/user/manual/en/setting-up/automation/milestone-tracker) +1. [Auto Repeat](https://erpnext.com/docs/user/manual/en/setting-up/automation/auto-repeat) ### Other Changes & Enhancements -1. [Document Follow](/docs/user/manual/en/setting-up/email/document-follow) -1. [Energy Points](/docs/user/manual/en/setting-up/energy-point-system) -1. [Dashboards](/docs/user/manual/en/customize-erpnext/dashboard) -1. [Disable customization for single doctypes](/version-12/release-notes/features#disable-customization-for-single-doctypes) -1. [Email Linking](/docs/user/manual/en/setting-up/email/linking-emails-to-document) -1. [Google Contacts](/docs/user/manual/en/erpnext_integration/google_contacts) -1. [PDF Encryption](/version-12/release-notes/features#pdf-encryption) -1. [Raw Printing](/docs/user/manual/en/setting-up/print/raw-printing) -1. [Web Form Refactor](/version-12/release-notes/features#web-form-refactor) -1. [Website Refactor](/docs/user/manual/en/website) -1. [Added Track Views field to Customize Form](/version-12/release-notes/features#added-track-views-field-to-customize-form) -1. [Add custom columns to any report](/version-12/release-notes/features#add-custom-columns-to-any-report) +1. [Document Follow](https://erpnext.com/docs/user/manual/en/setting-up/email/document-follow) +1. [Energy Points](https://erpnext.com/docs/user/manual/en/setting-up/energy-point-system) +1. [Dashboards](https://erpnext.com/docs/user/manual/en/customize-erpnext/dashboard) +1. [Disable customization for single doctypes](https://erpnext.com/version-12/release-notes/features#disable-customization-for-single-doctypes) +1. [Email Linking](https://erpnext.com/docs/user/manual/en/setting-up/email/linking-emails-to-document) +1. [Google Contacts](https://erpnext.com/docs/user/manual/en/erpnext_integration/google_contacts) +1. [PDF Encryption](https://erpnext.com/version-12/release-notes/features#pdf-encryption) +1. [Raw Printing](https://erpnext.com/docs/user/manual/en/setting-up/print/raw-printing) +1. [Web Form Refactor](https://erpnext.com/version-12/release-notes/features#web-form-refactor) +1. [Website Refactor](https://erpnext.com/docs/user/manual/en/website) +1. [Added Track Views field to Customize Form](https://erpnext.com/version-12/release-notes/features#added-track-views-field-to-customize-form) +1. [Add custom columns to any report](https://erpnext.com/version-12/release-notes/features#add-custom-columns-to-any-report) diff --git a/frappe/commands/__init__.py b/frappe/commands/__init__.py index 84e5f4937f..8110f2ec19 100644 --- a/frappe/commands/__init__.py +++ b/frappe/commands/__init__.py @@ -62,7 +62,7 @@ def popen(command, *args, **kwargs): return_ = proc.wait() - if raise_err: + if return_ and raise_err: raise subprocess.CalledProcessError(return_, command) return return_ diff --git a/frappe/commands/site.py b/frappe/commands/site.py index 0eb6a36098..5668759882 100755 --- a/frappe/commands/site.py +++ b/frappe/commands/site.py @@ -220,8 +220,9 @@ def disable_user(context, email): @click.command('migrate') @click.option('--rebuild-website', help="Rebuild webpages after migration") +@click.option('--skip-failing', is_flag=True, help="Skip patches that fail to run") @pass_context -def migrate(context, rebuild_website=False): +def migrate(context, rebuild_website=False, skip_failing=False): "Run patches, sync schema and rebuild files/translations" from frappe.migrate import migrate @@ -230,7 +231,7 @@ def migrate(context, rebuild_website=False): frappe.init(site=site) frappe.connect() try: - migrate(context.verbose, rebuild_website=rebuild_website) + migrate(context.verbose, rebuild_website=rebuild_website, skip_failing=skip_failing) finally: frappe.destroy() diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index 6e0786a528..eb8cf0e088 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -478,7 +478,7 @@ def run_ui_tests(context, app, headless=False): run_or_open = 'run' if headless else 'open' command = '{site_env} {password_env} yarn run cypress {run_or_open}' formatted_command = command.format(site_env=site_env, password_env=password_env, run_or_open=run_or_open) - frappe.commands.popen(formatted_command, cwd=app_base_path) + frappe.commands.popen(formatted_command, cwd=app_base_path, raise_err=True) @click.command('run-setup-wizard-ui-test') @click.option('--app', help="App to run tests on, leave blank for all apps") diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index 47df90d18c..6e6cce52bf 100755 --- a/frappe/core/doctype/file/file.py +++ b/frappe/core/doctype/file/file.py @@ -188,14 +188,20 @@ class File(NestedSet): # check duplicate name # check duplicate assignement - n_records = frappe.db.sql("""select name from `tabFile` - where content_hash=%s - and name!=%s - and attached_to_doctype=%s - and attached_to_name=%s""", (self.content_hash, self.name, self.attached_to_doctype, - self.attached_to_name)) - if len(n_records) > 0: - self.duplicate_entry = n_records[0][0] + filters = { + 'content_hash': self.content_hash, + 'is_private': self.is_private, + 'name': ('!=', self.name) + } + if self.attached_to_doctype and self.attached_to_name: + filters.update({ + 'attached_to_doctype': self.attached_to_doctype, + 'attached_to_name': self.attached_to_name + }) + duplicate_file = frappe.db.get_value('File', filters) + + if duplicate_file: + self.duplicate_entry = duplicate_file frappe.throw(_("Same file has already been attached to the record"), frappe.DuplicateEntryError) @@ -451,7 +457,7 @@ class File(NestedSet): return self.file_url = unquote(self.file_url) - self.file_size = frappe.form_dict.file_size + self.file_size = frappe.form_dict.file_size or self.file_size def get_uploaded_content(self): @@ -484,7 +490,13 @@ class File(NestedSet): self.content_hash = get_content_hash(self.content) self.content_type = mimetypes.guess_type(self.file_name)[0] - _file = frappe.get_value("File", {"content_hash": self.content_hash}, ["file_url"]) + # check if a file exists with the same content hash and is also in the same folder (public or private) + _file = frappe.get_value("File", { + "content_hash": self.content_hash, + "is_private": self.is_private + }, + ["file_url"]) + if _file: self.file_url = _file file_exists = True diff --git a/test_sites/apps.txt b/frappe/core/doctype/session_default/__init__.py similarity index 100% rename from test_sites/apps.txt rename to frappe/core/doctype/session_default/__init__.py diff --git a/frappe/core/doctype/session_default/session_default.json b/frappe/core/doctype/session_default/session_default.json new file mode 100644 index 0000000000..d382e12456 --- /dev/null +++ b/frappe/core/doctype/session_default/session_default.json @@ -0,0 +1,29 @@ +{ + "creation": "2019-07-17 16:21:33.546379", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "ref_doctype" + ], + "fields": [ + { + "fieldname": "ref_doctype", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Document Type", + "options": "DocType" + } + ], + "istable": 1, + "modified": "2019-07-21 13:22:25.752553", + "modified_by": "Administrator", + "module": "Core", + "name": "Session Default", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/frappe/core/doctype/session_default/session_default.py b/frappe/core/doctype/session_default/session_default.py new file mode 100644 index 0000000000..8a8db46ff1 --- /dev/null +++ b/frappe/core/doctype/session_default/session_default.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019, Frappe Technologies and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +# import frappe +from frappe.model.document import Document + +class SessionDefault(Document): + pass diff --git a/frappe/core/doctype/session_default_settings/__init__.py b/frappe/core/doctype/session_default_settings/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/core/doctype/session_default_settings/session_default_settings.json b/frappe/core/doctype/session_default_settings/session_default_settings.json new file mode 100644 index 0000000000..3eeb3f4167 --- /dev/null +++ b/frappe/core/doctype/session_default_settings/session_default_settings.json @@ -0,0 +1,39 @@ +{ + "creation": "2019-07-17 16:22:31.300991", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "session_defaults" + ], + "fields": [ + { + "fieldname": "session_defaults", + "fieldtype": "Table", + "label": "Session Defaults", + "options": "Session Default" + } + ], + "issingle": 1, + "modified": "2019-07-19 16:04:33.971089", + "modified_by": "Administrator", + "module": "Core", + "name": "Session Default Settings", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/frappe/core/doctype/session_default_settings/session_default_settings.py b/frappe/core/doctype/session_default_settings/session_default_settings.py new file mode 100644 index 0000000000..453ece2890 --- /dev/null +++ b/frappe/core/doctype/session_default_settings/session_default_settings.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019, Frappe Technologies and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe import _ +import json +from frappe.model.document import Document + +class SessionDefaultSettings(Document): + pass + +@frappe.whitelist() +def get_session_default_values(): + settings = frappe.get_single('Session Default Settings') + fields = [] + for default_values in settings.session_defaults: + reference_doctype = frappe.scrub(default_values.ref_doctype) + fields.append({ + 'fieldname': reference_doctype, + 'fieldtype': 'Link', + 'options': default_values.ref_doctype, + 'label': _('Default {0}').format(_(default_values.ref_doctype)), + 'default': frappe.defaults.get_user_default(reference_doctype) + }) + return json.dumps(fields) + +@frappe.whitelist() +def set_session_default_values(default_values): + if not frappe.flags.in_test: + default_values = json.loads(default_values) + for entry in default_values: + try: + frappe.defaults.set_user_default(entry, default_values.get(entry)) + except Exception: + return + return "success" + +#called on hook 'on_logout' to clear defaults for the session +def clear_session_defaults(): + settings = frappe.get_single('Session Default Settings').session_defaults + for entry in settings: + frappe.defaults.clear_user_default(frappe.scrub(entry.ref_doctype)) diff --git a/frappe/core/doctype/session_default_settings/test_session_default_settings.py b/frappe/core/doctype/session_default_settings/test_session_default_settings.py new file mode 100644 index 0000000000..12aa14d343 --- /dev/null +++ b/frappe/core/doctype/session_default_settings/test_session_default_settings.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019, Frappe Technologies and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest +from frappe.core.doctype.session_default_settings.session_default_settings import set_session_default_values, clear_session_defaults + +class TestSessionDefaultSettings(unittest.TestCase): + def test_set_session_default_settings(self): + frappe.set_user("Administrator") + settings = frappe.get_single("Session Default Settings") + settings.session_defaults = [] + settings.append("session_defaults", { + "ref_doctype": "Role" + }) + settings.save() + + set_session_default_values({"role": "Website Manager"}) + + todo = frappe.get_doc(dict(doctype="ToDo", description="test session defaults set", assigned_by="Administrator")).insert() + self.assertEqual(todo.role, "Website Manager") + + def test_clear_session_defaults(self): + clear_session_defaults() + todo = frappe.get_doc(dict(doctype="ToDo", description="test session defaults cleared", assigned_by="Administrator")).insert() + self.assertNotEqual(todo.role, "Website Manager") diff --git a/frappe/desk/form/load.py b/frappe/desk/form/load.py index 3b67b78144..e790bf6d06 100644 --- a/frappe/desk/form/load.py +++ b/frappe/desk/form/load.py @@ -252,4 +252,4 @@ def get_view_logs(doctype, docname): if view_logs: logs = view_logs - return logs \ No newline at end of file + return logs diff --git a/frappe/hooks.py b/frappe/hooks.py index 253dad0543..a4c3822c47 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -80,6 +80,8 @@ on_session_creation = [ "frappe.utils.scheduler.reset_enabled_scheduler_events", ] +on_logout = "frappe.core.doctype.session_default_settings.session_default_settings.clear_session_defaults" + # permissions permission_query_conditions = { diff --git a/frappe/migrate.py b/frappe/migrate.py index 7b5ce55b36..6778a3f18f 100644 --- a/frappe/migrate.py +++ b/frappe/migrate.py @@ -17,7 +17,7 @@ from frappe.core.doctype.language.language import sync_languages from frappe.modules.utils import sync_customizations from frappe.utils import global_search -def migrate(verbose=True, rebuild_website=False): +def migrate(verbose=True, rebuild_website=False, skip_failing=False): '''Migrate all apps to the latest version, will: - run before migrate hooks - run patches @@ -45,7 +45,7 @@ def migrate(verbose=True, rebuild_website=False): frappe.get_attr(fn)() # run patches - frappe.modules.patch_handler.run_all() + frappe.modules.patch_handler.run_all(skip_failing) # sync frappe.model.sync.sync_all(verbose=verbose) frappe.translate.clear_cache() diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 47380c6550..570835bc32 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -175,10 +175,11 @@ class BaseDocument(object): if not self.doctype: return value if not isinstance(value, BaseDocument): - if "doctype" not in value: + if "doctype" not in value or value['doctype'] is None: value["doctype"] = self.get_table_field_doctype(key) if not value["doctype"]: raise AttributeError(key) + value = get_controller(value["doctype"])(value) value.init_valid_columns() diff --git a/frappe/modules/patch_handler.py b/frappe/modules/patch_handler.py index 685d755fbd..b3237b8b76 100644 --- a/frappe/modules/patch_handler.py +++ b/frappe/modules/patch_handler.py @@ -19,23 +19,31 @@ import os class PatchError(Exception): pass -def run_all(): +def run_all(skip_failing=False): """run all pending patches""" executed = [p[0] for p in frappe.db.sql("""select patch from `tabPatch Log`""")] frappe.flags.final_patches = [] - for patch in get_all_patches(): - if patch and (patch not in executed): + + def run_patch(patch): + try: if not run_single(patchmodule = patch): log(patch + ': failed: STOPPED') raise PatchError(patch) + except Exception: + if not skip_failing: + raise + else: + log('Failed to execute patch') + + for patch in get_all_patches(): + if patch and (patch not in executed): + run_patch(patch) # patches to be run in the end for patch in frappe.flags.final_patches: patch = patch.replace('finally:', '') - if not run_single(patchmodule = patch): - log(patch + ': failed: STOPPED') - raise PatchError(patch) + run_patch(patch) def get_all_patches(): patches = [] diff --git a/frappe/public/js/frappe/ui/toolbar/navbar.html b/frappe/public/js/frappe/ui/toolbar/navbar.html index 799cc9bb3b..5e49d533bf 100644 --- a/frappe/public/js/frappe/ui/toolbar/navbar.html +++ b/frappe/public/js/frappe/ui/toolbar/navbar.html @@ -28,6 +28,8 @@ {%= __("My Profile") %}
  • {%= __("My Settings") %}
  • +
  • + {%= __("Session Defaults") %}
  • diff --git a/frappe/public/js/frappe/ui/toolbar/toolbar.js b/frappe/public/js/frappe/ui/toolbar/toolbar.js index d1826cc688..ed5091b52f 100644 --- a/frappe/public/js/frappe/ui/toolbar/toolbar.js +++ b/frappe/public/js/frappe/ui/toolbar/toolbar.js @@ -235,3 +235,50 @@ frappe.ui.toolbar.show_about = function() { } return false; }; + +frappe.ui.toolbar.setup_session_defaults = function() { + let fields = []; + frappe.call({ + method: 'frappe.core.doctype.session_default_settings.session_default_settings.get_session_default_values', + callback: function (data) { + fields = JSON.parse(data.message); + let perms = frappe.perm.get_perm('Session Default Settings'); + //add settings button only if user is a System Manager or has permission on 'Session Default Settings' + if ((in_list(frappe.user_roles, 'System Manager')) || (perms[0].read == 1)) { + fields[fields.length] = { + 'fieldname': 'settings', + 'fieldtype': 'Button', + 'label': __('Settings'), + 'click': () => { + frappe.set_route('Form', 'Session Default Settings', 'Session Default Settings'); + } + }; + } + frappe.prompt(fields, function(values) { + frappe.call({ + method: 'frappe.core.doctype.session_default_settings.session_default_settings.set_session_default_values', + args: { + default_values: values, + }, + callback: function(data) { + if (data.message == "success") { + frappe.show_alert({ + 'message': __('Session Defaults Saved'), + 'indicator': 'green' + }); + frappe.clear_cache(); + } else { + frappe.show_alert({ + 'message': __('An error occurred while setting Session Defaults'), + 'indicator': 'red' + }); + } + } + }); + }, + __('Session Defaults'), + __('Save'), + ); + } + }); +}; diff --git a/frappe/utils/jinja.py b/frappe/utils/jinja.py index 7a27fb3c3b..f8745b82c3 100644 --- a/frappe/utils/jinja.py +++ b/frappe/utils/jinja.py @@ -71,7 +71,7 @@ def render_template(template, context, is_path=None, safe_render=True): or (template.endswith('.html') and '\n' not in template)): return get_jenv().get_template(template).render(context) else: - if safe_render and ".__" in template: + if safe_render and "__" in template: throw("Illegal template") try: return get_jenv().from_string(template).render(context) diff --git a/test_sites/test_site/site_config.json b/test_sites/test_site/site_config.json deleted file mode 100644 index 40a2d62b6d..0000000000 --- a/test_sites/test_site/site_config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "test_frappe", - "db_password": "test_frappe", - "auto_email_id": "test@example.com", - "mail_server": "smtp.example.com", - "mail_login": "test@example.com", - "mail_password": "test", - "admin_password": "admin", - "root_password": "travis", - "run_selenium_tests": 1, - "host_name": "http://test_site:8000" -} diff --git a/test_sites/test_site_postgres/site_config.json b/test_sites/test_site_postgres/site_config.json deleted file mode 100644 index 5f00580c53..0000000000 --- a/test_sites/test_site_postgres/site_config.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_host": "localhost", - "db_name": "test_frappe", - "db_password": "test_frappe", - "db_type": "postgres", - "auto_email_id": "test@example.com", - "mail_server": "smtp.example.com", - "mail_login": "test@example.com", - "mail_password": "test", - "admin_password": "admin", - "root_login": "postgres", - "root_password": "travis", - "run_selenium_tests": 1, - "host_name": "http://test_site_postgres:8000" -} diff --git a/test_sites/test_site_ui/site_config.json b/test_sites/test_site_ui/site_config.json deleted file mode 100644 index d233a6b553..0000000000 --- a/test_sites/test_site_ui/site_config.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "developer_mode": 1, - "db_name": "test_site_ui", - "db_password": "test_site_ui", - "db_type": "mariadb", - "auto_email_id": "test@example.com", - "mail_server": "smtp.example.com", - "mail_login": "test@example.com", - "mail_password": "test", - "admin_password": "admin", - "root_password": "travis", - "run_selenium_tests": 1, - "host_name": "http://test_site_ui:8000" -}