From 724a5b2536850cfc0d34deb21688507c10903060 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 30 Apr 2021 21:09:24 +0530 Subject: [PATCH 01/27] fix: Evaluate boolean values better via /api/resource/ `GET /api/resource/ToDo?limit=10&debug=False&as_dict=0` would be received by the resource handler as debug="False" and as_dict="0" which are both truthy values. So, even though you requested for a list of lists response without debugging on, you'd get the exact opposite; debug on and a list of dicts. - Evaluate boolean values for `GET /api/resource/` - Added `limit` parameter as an alias for `limit_page_length` - Added `frappe.utils.data.sbool` that converts strings to bool values if applicable. - Added some seemingly stupid comments for the sake of consistency. --- frappe/api.py | 47 +++++++++++++++++++++++++++++--------------- frappe/utils/data.py | 20 +++++++++++++++++++ 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/frappe/api.py b/frappe/api.py index 9039ae0e5f..c69f76a755 100644 --- a/frappe/api.py +++ b/frappe/api.py @@ -11,6 +11,7 @@ import frappe.client import frappe.handler from frappe import _ from frappe.utils.response import build_response +from frappe.utils.data import sbool def handle(): @@ -108,25 +109,39 @@ def handle(): elif doctype: if frappe.local.request.method == "GET": - if frappe.local.form_dict.get('fields'): - frappe.local.form_dict['fields'] = json.loads(frappe.local.form_dict['fields']) - frappe.local.form_dict.setdefault('limit_page_length', 20) - frappe.local.response.update({ - "data": frappe.call( - frappe.client.get_list, - doctype, - **frappe.local.form_dict - ) - }) + # set fields for frappe.get_list + if frappe.local.form_dict.get("fields"): + frappe.local.form_dict["fields"] = json.loads(frappe.local.form_dict["fields"]) + + # set limit of records for frappe.get_list + frappe.local.form_dict.setdefault( + "limit_page_length", + frappe.local.form_dict.limit or frappe.local.form_dict.limit_page_length or 20, + ) + + # convert strings to native types + frappe.local.form_dict.update( + {x: sbool(y) for x, y in frappe.local.form_dict.items()} + ) + + # evaluate frappe.get_list + data = frappe.call(frappe.client.get_list, doctype, **frappe.local.form_dict) + + # set frappe.get_list result to response + frappe.local.response.update({"data": data}) if frappe.local.request.method == "POST": + # fetch data from from dict data = get_request_form_data() - data.update({ - "doctype": doctype - }) - frappe.local.response.update({ - "data": frappe.get_doc(data).insert().as_dict() - }) + data.update({"doctype": doctype}) + + # insert document from request data + doc = frappe.get_doc(data).insert() + + # set response data + frappe.local.response.update({"data": doc.as_dict()}) + + # commit for POST requests frappe.db.commit() else: raise frappe.DoesNotExistError diff --git a/frappe/utils/data.py b/frappe/utils/data.py index 3ffa8dc874..9d81aac467 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -622,6 +622,26 @@ def ceil(s): def cstr(s, encoding='utf-8'): return frappe.as_unicode(s, encoding) +def sbool(x): + """Converts str object to Boolean if possible. + Example: + "true" becomes True + "1" becomes True + "{}" remains "{}" + + Args: + x (str): String to be converted to Bool + + Returns: + object: Returns Boolean or type(x) + """ + from distutils.util import strtobool + + try: + return bool(strtobool(x)) + except Exception: + return x + def rounded(num, precision=0): """round method for round halfs to nearest even algorithm aka banker's rounding - compatible with python3""" precision = cint(precision) From c822c54f558383f2f7c92a688d3db8b198aa2bb8 Mon Sep 17 00:00:00 2001 From: hasnain2808 Date: Wed, 12 May 2021 17:03:25 +0530 Subject: [PATCH 02/27] fix: allow updating naming series --- .../document_naming_rule.js | 41 +++++++++++++++++++ .../document_naming_rule.py | 5 +++ 2 files changed, 46 insertions(+) diff --git a/frappe/core/doctype/document_naming_rule/document_naming_rule.js b/frappe/core/doctype/document_naming_rule/document_naming_rule.js index 56b5c2fdf4..dcb60cd7d5 100644 --- a/frappe/core/doctype/document_naming_rule/document_naming_rule.js +++ b/frappe/core/doctype/document_naming_rule/document_naming_rule.js @@ -4,6 +4,7 @@ frappe.ui.form.on('Document Naming Rule', { refresh: function(frm) { frm.trigger('document_type'); + frm.trigger("add_button") }, document_type: (frm) => { // update the select field options with fieldnames @@ -20,5 +21,45 @@ frappe.ui.form.on('Document Naming Rule', { ); }); } + }, + add_button: (frm) => { + frm.add_custom_button(__('Update Counter'), function() { + + const fields = [{ + fieldtype: 'Data', + fieldname: 'new_counter', + label: __('New Counter'), + default: frm.doc.counter, + reqd: 1, + description: __('This will update the counter and will affect all documents that will be created') + }] + + let primary_action_label = __('Save'); + + let primary_action = (fields) => { + debugger + frappe.call({ + method: 'frappe.core.doctype.document_naming_rule.document_naming_rule.update_current', + args: { + name: frm.doc.name, + new_counter: fields.new_counter + }, + callback: function() { + frm.set_value("counter", fields.new_counter) + dialog.hide() + } + }) + }; + + var dialog = new frappe.ui.Dialog({ + title: __('Update Counter Value for Prefix: ' + frm.doc.prefix), + fields, + primary_action_label, + primary_action + }); + + dialog.show() + + }); } }); diff --git a/frappe/core/doctype/document_naming_rule/document_naming_rule.py b/frappe/core/doctype/document_naming_rule/document_naming_rule.py index 4b34293af6..13d54dffdd 100644 --- a/frappe/core/doctype/document_naming_rule/document_naming_rule.py +++ b/frappe/core/doctype/document_naming_rule/document_naming_rule.py @@ -30,3 +30,8 @@ class DocumentNamingRule(Document): counter = frappe.db.get_value(self.doctype, self.name, 'counter', for_update=True) or 0 doc.name = self.prefix + ('%0'+str(self.prefix_digits)+'d') % (counter + 1) frappe.db.set_value(self.doctype, self.name, 'counter', counter + 1) + +@frappe.whitelist() +def update_current(name, new_counter): + frappe.db.set_value('Document Naming Rule', name, 'counter', new_counter) + frappe.db.commit() From c246c82a85d8a83fc71193905bf75febef89634a Mon Sep 17 00:00:00 2001 From: Mohammad Hasnain Mohsin Rajan Date: Wed, 12 May 2021 17:10:35 +0530 Subject: [PATCH 03/27] fix: remove debugger --- frappe/core/doctype/document_naming_rule/document_naming_rule.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/core/doctype/document_naming_rule/document_naming_rule.js b/frappe/core/doctype/document_naming_rule/document_naming_rule.js index dcb60cd7d5..5d1540588d 100644 --- a/frappe/core/doctype/document_naming_rule/document_naming_rule.js +++ b/frappe/core/doctype/document_naming_rule/document_naming_rule.js @@ -37,7 +37,6 @@ frappe.ui.form.on('Document Naming Rule', { let primary_action_label = __('Save'); let primary_action = (fields) => { - debugger frappe.call({ method: 'frappe.core.doctype.document_naming_rule.document_naming_rule.update_current', args: { From bb4be327511eb7f736282fee6eaf5ee6d88ebc7a Mon Sep 17 00:00:00 2001 From: Mohammad Hasnain Mohsin Rajan Date: Wed, 12 May 2021 17:15:18 +0530 Subject: [PATCH 04/27] chore: add semicolons --- .../document_naming_rule/document_naming_rule.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frappe/core/doctype/document_naming_rule/document_naming_rule.js b/frappe/core/doctype/document_naming_rule/document_naming_rule.js index 5d1540588d..e837ca2d6c 100644 --- a/frappe/core/doctype/document_naming_rule/document_naming_rule.js +++ b/frappe/core/doctype/document_naming_rule/document_naming_rule.js @@ -4,7 +4,7 @@ frappe.ui.form.on('Document Naming Rule', { refresh: function(frm) { frm.trigger('document_type'); - frm.trigger("add_button") + frm.trigger("add_button"); }, document_type: (frm) => { // update the select field options with fieldnames @@ -32,7 +32,7 @@ frappe.ui.form.on('Document Naming Rule', { default: frm.doc.counter, reqd: 1, description: __('This will update the counter and will affect all documents that will be created') - }] + }]; let primary_action_label = __('Save'); @@ -44,10 +44,10 @@ frappe.ui.form.on('Document Naming Rule', { new_counter: fields.new_counter }, callback: function() { - frm.set_value("counter", fields.new_counter) - dialog.hide() + frm.set_value("counter", fields.new_counter); + dialog.hide(); } - }) + }); }; var dialog = new frappe.ui.Dialog({ @@ -57,7 +57,7 @@ frappe.ui.form.on('Document Naming Rule', { primary_action }); - dialog.show() + dialog.show(); }); } From ed1a9e15591b7e8d4e1053fd97e528bbfb9cc43d Mon Sep 17 00:00:00 2001 From: hasnain2808 Date: Thu, 13 May 2021 09:55:27 +0530 Subject: [PATCH 05/27] fix: do not show counter on unsaved forms --- .../core/doctype/document_naming_rule/document_naming_rule.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/core/doctype/document_naming_rule/document_naming_rule.js b/frappe/core/doctype/document_naming_rule/document_naming_rule.js index e837ca2d6c..23a22ee33c 100644 --- a/frappe/core/doctype/document_naming_rule/document_naming_rule.js +++ b/frappe/core/doctype/document_naming_rule/document_naming_rule.js @@ -4,7 +4,7 @@ frappe.ui.form.on('Document Naming Rule', { refresh: function(frm) { frm.trigger('document_type'); - frm.trigger("add_button"); + if(!frm.doc.__islocal) frm.trigger("add_button"); }, document_type: (frm) => { // update the select field options with fieldnames From 90f786b0e5641f8c03b7e7e33988c82412aa4d4b Mon Sep 17 00:00:00 2001 From: Mohammad Hasnain Mohsin Rajan Date: Thu, 13 May 2021 09:57:10 +0530 Subject: [PATCH 06/27] chore: spaces --- .../core/doctype/document_naming_rule/document_naming_rule.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/core/doctype/document_naming_rule/document_naming_rule.js b/frappe/core/doctype/document_naming_rule/document_naming_rule.js index 23a22ee33c..7dbf533975 100644 --- a/frappe/core/doctype/document_naming_rule/document_naming_rule.js +++ b/frappe/core/doctype/document_naming_rule/document_naming_rule.js @@ -4,7 +4,7 @@ frappe.ui.form.on('Document Naming Rule', { refresh: function(frm) { frm.trigger('document_type'); - if(!frm.doc.__islocal) frm.trigger("add_button"); + if (!frm.doc.__islocal) frm.trigger("add_button"); }, document_type: (frm) => { // update the select field options with fieldnames From 2e1c4650baf004c2a0e756d388bd4389c9335853 Mon Sep 17 00:00:00 2001 From: Mohammad Hasnain Mohsin Rajan Date: Thu, 13 May 2021 19:54:56 +0530 Subject: [PATCH 07/27] Update frappe/core/doctype/document_naming_rule/document_naming_rule.js Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> --- .../core/doctype/document_naming_rule/document_naming_rule.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/core/doctype/document_naming_rule/document_naming_rule.js b/frappe/core/doctype/document_naming_rule/document_naming_rule.js index 7dbf533975..5e77e71820 100644 --- a/frappe/core/doctype/document_naming_rule/document_naming_rule.js +++ b/frappe/core/doctype/document_naming_rule/document_naming_rule.js @@ -51,7 +51,7 @@ frappe.ui.form.on('Document Naming Rule', { }; var dialog = new frappe.ui.Dialog({ - title: __('Update Counter Value for Prefix: ' + frm.doc.prefix), + title: __('Update Counter Value for Prefix: {0}', [frm.doc.prefix]), fields, primary_action_label, primary_action From 98100437d0f3476c88814159929e3a73dbabea40 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 20 May 2021 16:52:48 +0530 Subject: [PATCH 08/27] chore: Renamed test files "appropriately" --- frappe/tests/{test_api.py => test_frappe_client.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename frappe/tests/{test_api.py => test_frappe_client.py} (100%) diff --git a/frappe/tests/test_api.py b/frappe/tests/test_frappe_client.py similarity index 100% rename from frappe/tests/test_api.py rename to frappe/tests/test_frappe_client.py From bcbc14d047cc16b3847d03bc7db4b28d0b2f363a Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 20 May 2021 17:11:12 +0530 Subject: [PATCH 09/27] chore: Rename test suite and remove unused imports --- frappe/tests/test_frappe_client.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frappe/tests/test_frappe_client.py b/frappe/tests/test_frappe_client.py index 6453062877..e1cdbb6ccd 100644 --- a/frappe/tests/test_frappe_client.py +++ b/frappe/tests/test_frappe_client.py @@ -1,8 +1,7 @@ # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # MIT License. See license.txt -from __future__ import unicode_literals -import unittest, frappe, os +import unittest, frappe from frappe.core.doctype.user.user import generate_keys from frappe.frappeclient import FrappeClient, FrappeException from frappe.utils.data import get_url @@ -10,7 +9,7 @@ from frappe.utils.data import get_url import requests import base64 -class TestAPI(unittest.TestCase): +class TestFrappeClient(unittest.TestCase): def test_insert_many(self): server = FrappeClient(get_url(), "Administrator", "admin", verify=False) frappe.db.sql("delete from `tabNote` where title in ('Sing','a','song','of','sixpence')") From 4a814571a8008672cbae058351a21d9a8665b714 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 20 May 2021 19:26:11 +0530 Subject: [PATCH 10/27] test: Added tests for Frappe APIs * Added tests for /api/resource usage * Added tests for /api/method base endpoints --- frappe/tests/test_api.py | 170 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 frappe/tests/test_api.py diff --git a/frappe/tests/test_api.py b/frappe/tests/test_api.py new file mode 100644 index 0000000000..4d00df22a5 --- /dev/null +++ b/frappe/tests/test_api.py @@ -0,0 +1,170 @@ +import unittest +from random import choice + +import requests +from semantic_version import Version + +import frappe +from frappe.utils import get_site_url + + +def maintain_state(f): + def wrapper(*args, **kwargs): + frappe.db.rollback() + r = f(*args, **kwargs) + frappe.db.commit() + return r + + return wrapper + + +class TestResourceAPI(unittest.TestCase): + SITE_URL = get_site_url(frappe.local.site) + RESOURCE_URL = f"{SITE_URL}/api/resource" + DOCTYPE = "ToDo" + GENERATED_DOCUMENTS = [] + + @classmethod + @maintain_state + def setUpClass(self): + for _ in range(10): + doc = frappe.get_doc( + {"doctype": "ToDo", "description": frappe.mock("paragraph")} + ).insert() + self.GENERATED_DOCUMENTS.append(doc.name) + + @classmethod + @maintain_state + def tearDownClass(self): + for name in self.GENERATED_DOCUMENTS: + frappe.delete_doc_if_exists(self.DOCTYPE, name) + + @property + def sid(self): + if not getattr(self, "_sid", None): + self._sid = requests.post( + f"{self.SITE_URL}/api/method/login", + data={ + "usr": "Administrator", + "pwd": "root" or frappe.conf.admin_password or "admin", + }, + ).cookies.get("sid") + + return self._sid + + def get(self, path, params=""): + return requests.get(f"{self.RESOURCE_URL}/{path}?sid={self.sid}{params}") + + def post(self, path, data): + return requests.post( + f"{self.RESOURCE_URL}/{path}?sid={self.sid}", data=frappe.as_json(data) + ) + + def put(self, path, data): + return requests.put( + f"{self.RESOURCE_URL}/{path}?sid={self.sid}", data=frappe.as_json(data) + ) + + def delete(self, path): + return requests.delete(f"{self.RESOURCE_URL}/{path}?sid={self.sid}") + + def test_unauthorized_call(self): + # test 1: fetch documents without auth + response = requests.get(f"{self.RESOURCE_URL}/{self.DOCTYPE}") + self.assertEqual(response.status_code, 403) + + def test_get_list(self): + # test 2: fetch documents without params + response = self.get(self.DOCTYPE) + self.assertEqual(response.status_code, 200) + self.assertIsInstance(response.json(), dict) + self.assertIn("data", response.json()) + + def test_get_list_limit(self): + # test 3: fetch data with limit + response = self.get(self.DOCTYPE, "&limit=2") + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.json()["data"]), 2) + + def test_get_list_dict(self): + # test 4: fetch response as (not) dict + response = self.get(self.DOCTYPE, "&as_dict=True") + json = frappe._dict(response.json()) + self.assertEqual(response.status_code, 200) + self.assertIsInstance(json.data, list) + self.assertIsInstance(json.data[0], dict) + + response = self.get(self.DOCTYPE, "&as_dict=False") + json = frappe._dict(response.json()) + self.assertEqual(response.status_code, 200) + self.assertIsInstance(json.data, list) + self.assertIsInstance(json.data[0], list) + + def test_get_list_debug(self): + # test 5: fetch response with debug + response = self.get(self.DOCTYPE, "&debug=true") + self.assertEqual(response.status_code, 200) + self.assertIn("exc", response.json()) + self.assertIsInstance(response.json()["exc"], str) + self.assertIsInstance(eval(response.json()["exc"]), list) + + def test_get_list_fields(self): + # test 6: fetch response with fields + response = self.get(self.DOCTYPE, r'&fields=["description"]') + self.assertEqual(response.status_code, 200) + json = frappe._dict(response.json()) + self.assertIn("description", json.data[0]) + + def test_create_document(self): + # test 7: POST method on /api/resource to create doc + data = {"description": frappe.mock("paragraph")} + response = self.post(self.DOCTYPE, data) + self.assertEqual(response.status_code, 200) + docname = response.json()["data"]["name"] + self.assertIsInstance(docname, str) + self.GENERATED_DOCUMENTS.append(docname) + + def test_update_document(self): + # test 8: PUT method on /api/resource to update doc + generated_desc = frappe.mock("paragraph") + data = {"description": generated_desc} + random_doc = choice(self.GENERATED_DOCUMENTS) + desc_before_update = frappe.db.get_value(self.DOCTYPE, random_doc, "description") + + response = self.put(f"{self.DOCTYPE}/{random_doc}", data=data) + self.assertEqual(response.status_code, 200) + self.assertNotEqual(response.json()["data"]["description"], desc_before_update) + self.assertEqual(response.json()["data"]["description"], generated_desc) + + def test_delete_document(self): + # test 9: DELETE method on /api/resource + doc_to_delete = choice(self.GENERATED_DOCUMENTS) + response = self.delete(f"{self.DOCTYPE}/{doc_to_delete}") + self.assertEqual(response.status_code, 202) + self.assertDictEqual(response.json(), {"message": "ok"}) + + non_existent_doc = frappe.generate_hash(length=12) + response = self.delete(f"{self.DOCTYPE}/{non_existent_doc}") + self.assertEqual(response.status_code, 404) + self.assertDictEqual(response.json(), {}) + + +class TestMethodAPI(unittest.TestCase): + METHOD_URL = f"{get_site_url(frappe.local.site)}/api/method" + + def test_version(self): + # test 1: test for /api/method/version + response = requests.get(f"{self.METHOD_URL}/version") + json = frappe._dict(response.json()) + + self.assertEqual(response.status_code, 200) + self.assertIsInstance(json, dict) + self.assertIsInstance(json.message, str) + self.assertEqual(Version(json.message), Version(frappe.__version__)) + + def test_ping(self): + # test 2: test for /api/method/ping + response = requests.get(f"{self.METHOD_URL}/ping") + self.assertEqual(response.status_code, 200) + self.assertIsInstance(response.json(), dict) + self.assertEqual(response.json()['message'], "pong") From 969e2b6db95d1c865730776921e853cdeb0284ef Mon Sep 17 00:00:00 2001 From: Mohammad Hasnain Mohsin Rajan Date: Thu, 20 May 2021 20:04:40 +0530 Subject: [PATCH 11/27] fix: allow only system manager Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> --- frappe/core/doctype/document_naming_rule/document_naming_rule.py | 1 + 1 file changed, 1 insertion(+) diff --git a/frappe/core/doctype/document_naming_rule/document_naming_rule.py b/frappe/core/doctype/document_naming_rule/document_naming_rule.py index 13d54dffdd..7fa7c73efd 100644 --- a/frappe/core/doctype/document_naming_rule/document_naming_rule.py +++ b/frappe/core/doctype/document_naming_rule/document_naming_rule.py @@ -33,5 +33,6 @@ class DocumentNamingRule(Document): @frappe.whitelist() def update_current(name, new_counter): + frappe.only_for('System Manager') frappe.db.set_value('Document Naming Rule', name, 'counter', new_counter) frappe.db.commit() From 730bcc8c035bc5aec5173f1feb0b06a2e5c664de Mon Sep 17 00:00:00 2001 From: Mohammad Hasnain Mohsin Rajan Date: Thu, 20 May 2021 20:05:00 +0530 Subject: [PATCH 12/27] fix: do not explicitly commit Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> --- frappe/core/doctype/document_naming_rule/document_naming_rule.py | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/core/doctype/document_naming_rule/document_naming_rule.py b/frappe/core/doctype/document_naming_rule/document_naming_rule.py index 7fa7c73efd..653c056caa 100644 --- a/frappe/core/doctype/document_naming_rule/document_naming_rule.py +++ b/frappe/core/doctype/document_naming_rule/document_naming_rule.py @@ -35,4 +35,3 @@ class DocumentNamingRule(Document): def update_current(name, new_counter): frappe.only_for('System Manager') frappe.db.set_value('Document Naming Rule', name, 'counter', new_counter) - frappe.db.commit() From e16988b887d129c13fe30f9d67e27ff0fad93a82 Mon Sep 17 00:00:00 2001 From: Mohammad Hasnain Mohsin Rajan Date: Thu, 20 May 2021 20:05:58 +0530 Subject: [PATCH 13/27] chore: change description --- .../core/doctype/document_naming_rule/document_naming_rule.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/core/doctype/document_naming_rule/document_naming_rule.js b/frappe/core/doctype/document_naming_rule/document_naming_rule.js index 5e77e71820..f4b7428aff 100644 --- a/frappe/core/doctype/document_naming_rule/document_naming_rule.js +++ b/frappe/core/doctype/document_naming_rule/document_naming_rule.js @@ -31,7 +31,7 @@ frappe.ui.form.on('Document Naming Rule', { label: __('New Counter'), default: frm.doc.counter, reqd: 1, - description: __('This will update the counter and will affect all documents that will be created') + description: __('Updating counter may lead to document name conflicts if not done properly') }]; let primary_action_label = __('Save'); From dfc23eb3a3e42869430cf686a29f0b4188894618 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 21 May 2021 11:22:19 +0530 Subject: [PATCH 14/27] fix(test): Set admin password correctly --- frappe/tests/test_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/tests/test_api.py b/frappe/tests/test_api.py index 4d00df22a5..7e77aab779 100644 --- a/frappe/tests/test_api.py +++ b/frappe/tests/test_api.py @@ -46,7 +46,7 @@ class TestResourceAPI(unittest.TestCase): f"{self.SITE_URL}/api/method/login", data={ "usr": "Administrator", - "pwd": "root" or frappe.conf.admin_password or "admin", + "pwd": frappe.conf.admin_password or "admin", }, ).cookies.get("sid") From c9dc4ee441eae931b0d1918ba18fd0ce81df5967 Mon Sep 17 00:00:00 2001 From: Mohammad Hasnain Mohsin Rajan Date: Fri, 21 May 2021 11:38:36 +0530 Subject: [PATCH 15/27] Update frappe/core/doctype/document_naming_rule/document_naming_rule.js Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> --- .../core/doctype/document_naming_rule/document_naming_rule.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/core/doctype/document_naming_rule/document_naming_rule.js b/frappe/core/doctype/document_naming_rule/document_naming_rule.js index f4b7428aff..cd85615f5f 100644 --- a/frappe/core/doctype/document_naming_rule/document_naming_rule.js +++ b/frappe/core/doctype/document_naming_rule/document_naming_rule.js @@ -31,7 +31,7 @@ frappe.ui.form.on('Document Naming Rule', { label: __('New Counter'), default: frm.doc.counter, reqd: 1, - description: __('Updating counter may lead to document name conflicts if not done properly') + description: __('Warning: Updating counter may lead to document name conflicts if not done properly') }]; let primary_action_label = __('Save'); From bcb4c5182ffdb9d7d70b239d8ee6b222ece63f0e Mon Sep 17 00:00:00 2001 From: Mohammad Hasnain Mohsin Rajan Date: Fri, 21 May 2021 11:38:43 +0530 Subject: [PATCH 16/27] Update frappe/core/doctype/document_naming_rule/document_naming_rule.js Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> --- .../core/doctype/document_naming_rule/document_naming_rule.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/core/doctype/document_naming_rule/document_naming_rule.js b/frappe/core/doctype/document_naming_rule/document_naming_rule.js index cd85615f5f..b1123cba28 100644 --- a/frappe/core/doctype/document_naming_rule/document_naming_rule.js +++ b/frappe/core/doctype/document_naming_rule/document_naming_rule.js @@ -50,7 +50,7 @@ frappe.ui.form.on('Document Naming Rule', { }); }; - var dialog = new frappe.ui.Dialog({ + const dialog = new frappe.ui.Dialog({ title: __('Update Counter Value for Prefix: {0}', [frm.doc.prefix]), fields, primary_action_label, From 3f056d147dea656dd531c7e794da05a513aa44f7 Mon Sep 17 00:00:00 2001 From: Mohammad Hasnain Mohsin Rajan Date: Fri, 21 May 2021 11:38:49 +0530 Subject: [PATCH 17/27] Update frappe/core/doctype/document_naming_rule/document_naming_rule.js Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> --- .../core/doctype/document_naming_rule/document_naming_rule.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/core/doctype/document_naming_rule/document_naming_rule.js b/frappe/core/doctype/document_naming_rule/document_naming_rule.js index b1123cba28..3aea9e04a7 100644 --- a/frappe/core/doctype/document_naming_rule/document_naming_rule.js +++ b/frappe/core/doctype/document_naming_rule/document_naming_rule.js @@ -4,7 +4,7 @@ frappe.ui.form.on('Document Naming Rule', { refresh: function(frm) { frm.trigger('document_type'); - if (!frm.doc.__islocal) frm.trigger("add_button"); + if (!frm.doc.__islocal) frm.trigger("add_update_counter_button"); }, document_type: (frm) => { // update the select field options with fieldnames From fa53c47e58cf7f8c85bd1ba13ad6973ec998b2d0 Mon Sep 17 00:00:00 2001 From: Mohammad Hasnain Mohsin Rajan Date: Fri, 21 May 2021 11:38:57 +0530 Subject: [PATCH 18/27] Update frappe/core/doctype/document_naming_rule/document_naming_rule.js Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> --- .../core/doctype/document_naming_rule/document_naming_rule.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/core/doctype/document_naming_rule/document_naming_rule.js b/frappe/core/doctype/document_naming_rule/document_naming_rule.js index 3aea9e04a7..0f0bdd149c 100644 --- a/frappe/core/doctype/document_naming_rule/document_naming_rule.js +++ b/frappe/core/doctype/document_naming_rule/document_naming_rule.js @@ -22,7 +22,7 @@ frappe.ui.form.on('Document Naming Rule', { }); } }, - add_button: (frm) => { + add_update_counter_button: (frm) => { frm.add_custom_button(__('Update Counter'), function() { const fields = [{ From 58400d6214ec61ff9733a4caf46bad18dff71880 Mon Sep 17 00:00:00 2001 From: Mohammad Hasnain Mohsin Rajan Date: Fri, 21 May 2021 14:15:14 +0530 Subject: [PATCH 19/27] Update frappe/core/doctype/document_naming_rule/document_naming_rule.js Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> --- .../core/doctype/document_naming_rule/document_naming_rule.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/core/doctype/document_naming_rule/document_naming_rule.js b/frappe/core/doctype/document_naming_rule/document_naming_rule.js index 0f0bdd149c..097a4e9a6e 100644 --- a/frappe/core/doctype/document_naming_rule/document_naming_rule.js +++ b/frappe/core/doctype/document_naming_rule/document_naming_rule.js @@ -44,7 +44,7 @@ frappe.ui.form.on('Document Naming Rule', { new_counter: fields.new_counter }, callback: function() { - frm.set_value("counter", fields.new_counter); + frm.set_value("counter", fields.new_counter); dialog.hide(); } }); From ba7785eaa08d302f21daabaa7fcbeb007e574059 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 21 May 2021 18:53:44 +0530 Subject: [PATCH 20/27] fix: Don't strip 'app' from doctype route names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After creation of a new document and going back would break routes for doctypes that start with 'App'. In observed instance, it would clips the “app” portion in the appraisal and appraisal-template. --- frappe/public/js/frappe/router.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/router.js b/frappe/public/js/frappe/router.js index 5378294855..12caf4ab94 100644 --- a/frappe/public/js/frappe/router.js +++ b/frappe/public/js/frappe/router.js @@ -372,7 +372,8 @@ frappe.router = { strip_prefix(route) { if (route.substr(0, 1)=='/') route = route.substr(1); // for /app/sub - if (route.startsWith('app')) route = route.substr(4); // for desk/sub + if (route.startsWith('app/')) route = route.substr(4); // for desk/sub + if (route == 'app') route = route.substr(4); // for /app if (route.substr(0, 1)=='/') route = route.substr(1); if (route.substr(0, 1)=='#') route = route.substr(1); if (route.substr(0, 1)=='!') route = route.substr(1); From ad8b844942d1c87783cd3806d3e081b4f6398001 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Tue, 25 May 2021 15:51:59 +0530 Subject: [PATCH 21/27] feat: Add grid breakpoint css_variables So that other apps does not have to be dependant on 'variables' file to get grid sizes --- frappe/public/scss/desk/css_variables.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frappe/public/scss/desk/css_variables.scss b/frappe/public/scss/desk/css_variables.scss index 135bb7a9f5..5bb2614dcc 100644 --- a/frappe/public/scss/desk/css_variables.scss +++ b/frappe/public/scss/desk/css_variables.scss @@ -13,6 +13,14 @@ $input-height: 28px !default; --text-2xl: 20px; --text-3xl: 22px; + // breakpoints + --xxl-width: map-get($grid-breakpoints, '2xl'); + --xl-width: map-get($grid-breakpoints, 'xl'); + --lg-width: map-get($grid-breakpoints, 'lg'); + --md-width: map-get($grid-breakpoints, 'md'); + --sm-width: map-get($grid-breakpoints, 'sm'); + --xs-width: map-get($grid-breakpoints, 'xs'); + --text-bold: 500; --navbar-height: 60px; From e79ce22d4d7070c814da333e166830f64ca16c07 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Tue, 25 May 2021 19:08:19 +0530 Subject: [PATCH 22/27] fix: double checkboxes showing in editable grid --- frappe/public/js/frappe/form/controls/check.js | 4 +++- frappe/public/scss/common/grid.scss | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/check.js b/frappe/public/js/frappe/form/controls/check.js index 658ef640a9..1209f52e6d 100644 --- a/frappe/public/js/frappe/form/controls/check.js +++ b/frappe/public/js/frappe/form/controls/check.js @@ -14,8 +14,10 @@ frappe.ui.form.ControlCheck = class ControlCheck extends frappe.ui.form.ControlD `).appendTo(this.parent); } set_input_areas() { - this.label_area = this.label_span = this.$wrapper.find(".label-area").get(0); this.input_area = this.$wrapper.find(".input-area").get(0); + if (this.only_input) return; + + this.label_area = this.label_span = this.$wrapper.find(".label-area").get(0); this.disp_area = this.$wrapper.find(".disp-area").get(0); } make_input() { diff --git a/frappe/public/scss/common/grid.scss b/frappe/public/scss/common/grid.scss index 3cc5139d9e..aac949b1bf 100644 --- a/frappe/public/scss/common/grid.scss +++ b/frappe/public/scss/common/grid.scss @@ -140,7 +140,7 @@ .checkbox { margin: 0px; text-align: center; - margin-top: 9px; + margin-top: var(--padding-sm); } textarea { From b215921a971e3b95ff6f93d63da3ffc70a10766f Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 25 May 2021 21:44:54 +0530 Subject: [PATCH 23/27] fix: Convert only as_dict and debug values to bool Given the scope of its usage at this point, this becomes a problem when you'd have a field named y,n, true, false and order_by that field, or have the same values for a document name that parent parameter would accept out of all those that Frappe REST allows. --- frappe/api.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/frappe/api.py b/frappe/api.py index c69f76a755..6427cbfbd8 100644 --- a/frappe/api.py +++ b/frappe/api.py @@ -119,10 +119,11 @@ def handle(): frappe.local.form_dict.limit or frappe.local.form_dict.limit_page_length or 20, ) - # convert strings to native types - frappe.local.form_dict.update( - {x: sbool(y) for x, y in frappe.local.form_dict.items()} - ) + # convert strings to native types - only as_dict and debug accept bool + for param in ["as_dict", "debug"]: + param_val = frappe.local.form_dict.get(param) + if param_val is not None: + frappe.local.form_dict[param] = sbool(param_val) # evaluate frappe.get_list data = frappe.call(frappe.client.get_list, doctype, **frappe.local.form_dict) From 8764134309907f8c89336a90b1edb51ef1b23dff Mon Sep 17 00:00:00 2001 From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> Date: Wed, 26 May 2021 10:02:12 +0530 Subject: [PATCH 24/27] ci: Run mariadb tests after PR merge for coverage badge --- .github/workflows/server-mariadb-tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/server-mariadb-tests.yml b/.github/workflows/server-mariadb-tests.yml index 1742e813c6..1c7655528c 100644 --- a/.github/workflows/server-mariadb-tests.yml +++ b/.github/workflows/server-mariadb-tests.yml @@ -3,6 +3,8 @@ name: Server on: pull_request: workflow_dispatch: + push: + branches: [ develop ] jobs: test: From b0f1bbc37812daa2f4212401374e8317b200750c Mon Sep 17 00:00:00 2001 From: Akshay Kumar Tripathi <50769001+AkshayKumarTripathi@users.noreply.github.com> Date: Wed, 26 May 2021 10:37:50 +0530 Subject: [PATCH 25/27] fix: corrected the function get_url (#13330) * Removed /Form from the function get_url As per issue #12820, I think /Form was causing a problem so I removed it. Now the get_url returns URL in the format: "app/doctype/name". * fix: Change to f-strings * Implement slug on get_url * Removed slug for names --- frappe/model/document.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frappe/model/document.py b/frappe/model/document.py index 623916597e..a3f8ad0cfa 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -17,6 +17,7 @@ from frappe.model.workflow import set_workflow_state_on_action from frappe.utils.global_search import update_global_search from frappe.integrations.doctype.webhook import run_webhooks from frappe.desk.form.document_follow import follow_document +from frappe.desk.utils import slug from frappe.core.doctype.server_script.server_script_utils import run_server_script_for_doc_event # once_only validation @@ -1202,8 +1203,8 @@ class Document(BaseDocument): doc.set(fieldname, flt(doc.get(fieldname), self.precision(fieldname, doc.parentfield))) def get_url(self): - """Returns Desk URL for this document. `/app/Form/{doctype}/{name}`""" - return "/app/Form/{doctype}/{name}".format(doctype=self.doctype, name=self.name) + """Returns Desk URL for this document. `/app/{doctype}/{name}`""" + return f"/app/{slug(self.doctype)}/{self.name}" def add_comment(self, comment_type='Comment', text=None, comment_email=None, link_doctype=None, link_name=None, comment_by=None): """Add a comment to this document. From 71632073ecbb88996ce355a353715eba02b50304 Mon Sep 17 00:00:00 2001 From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> Date: Wed, 26 May 2021 15:45:02 +0530 Subject: [PATCH 26/27] chore: Fix status badge link --- README.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e00bea7857..11343a632a 100644 --- a/README.md +++ b/README.md @@ -14,18 +14,21 @@ From ab9b6bf36ec142fe4fc3bb47b46c9455fb4fa8b1 Mon Sep 17 00:00:00 2001 From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> Date: Wed, 26 May 2021 15:46:41 +0530 Subject: [PATCH 27/27] ci: Run ui tests after PR merge for status badge --- .github/workflows/ui-tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index d9ccb07da0..f2f43f10f8 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -3,6 +3,8 @@ name: UI on: pull_request: workflow_dispatch: + push: + branches: [ develop ] jobs: test: