Skip to content

Commit cc77f58

Browse files
committed
Merge branch 'staging' into production
2 parents a165d5d + 4c9fc8f commit cc77f58

File tree

6 files changed

+141
-42
lines changed

6 files changed

+141
-42
lines changed

frappe/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
sys.setdefaultencoding("utf-8")
2525

2626
__frappe_version__ = '12.8.1'
27-
__version__ = '2.0.5'
27+
__version__ = '2.0.6'
2828
__title__ = "Frappe Framework"
2929

3030
local = Local()

frappe/public/js/frappe/desk.js

Lines changed: 30 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -172,53 +172,45 @@ frappe.Application = Class.extend({
172172
email_password_prompt: function(email_account,user,i) {
173173
var me = this;
174174
var d = new frappe.ui.Dialog({
175-
title: __('Email Account setup please enter your password for: '+email_account[i]["email_id"]),
175+
title: __('Email Account Setup: {0}', [email_account[i]["email_id"]]),
176176
fields: [
177177
{ 'fieldname': 'password',
178178
'fieldtype': 'Password',
179179
'label': 'Email Account Password',
180180
'reqd': 1
181-
},
182-
{
183-
"fieldtype": "Button",
184-
"label": __("Submit")
185181
}
186-
]
187-
});
188-
d.get_input("submit").on("click", function() {
189-
//setup spinner
190-
d.hide();
191-
var s = new frappe.ui.Dialog({
192-
title: __("Checking one moment"),
193-
fields: [{
194-
"fieldtype": "HTML",
195-
"fieldname": "checking"
196-
}]
197-
});
198-
s.fields_dict.checking.$wrapper.html('<i class="fa fa-spinner fa-spin fa-4x"></i>');
199-
s.show();
200-
frappe.call({
201-
method: 'frappe.core.doctype.user.user.set_email_password',
202-
args: {
203-
"email_account": email_account[i]["email_account"],
204-
"user": user,
205-
"password": d.get_value("password")
206-
},
207-
callback: function(passed) {
208-
s.hide();
209-
d.hide();//hide waiting indication
210-
if (!passed["message"]) {
211-
frappe.show_alert("Login Failed please try again", 5);
212-
me.email_password_prompt(email_account, user, i);
213-
} else {
214-
if (i + 1 < email_account.length) {
215-
i = i + 1;
182+
],
183+
primary_action() {
184+
d.hide();
185+
186+
frappe.call({
187+
method: 'frappe.core.doctype.user.user.set_email_password',
188+
args: {
189+
"email_account": email_account[i]["email_account"],
190+
"user": user,
191+
"password": d.get_value("password")
192+
},
193+
callback: function(r) {
194+
if (!r.message) {
195+
frappe.show_alert({
196+
indicator: 'red',
197+
message: __('Login Failed. Please try again.')
198+
});
216199
me.email_password_prompt(email_account, user, i);
200+
return;
217201
}
218-
}
219202

220-
}
221-
});
203+
frappe.show_alert({
204+
indicator: 'green',
205+
message: __('Email Account {0} configured.', [email_account[i]["email_account"]])
206+
});
207+
208+
if (i++ < email_account.length) {
209+
me.email_password_prompt(email_account, user, i++);
210+
}
211+
}
212+
});
213+
},
222214
});
223215
d.show();
224216
},

frappe/public/js/frappe/ui/field_group.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ frappe.ui.FieldGroup = frappe.ui.form.Layout.extend({
8686
var f = this.fields_dict[key];
8787
if(f.get_value) {
8888
var v = f.get_value();
89-
if(f.df.reqd && is_null(strip_html(v)))
89+
if(f.df.reqd && is_null(strip_html(v || "")))
9090
errors.push(__(f.df.label));
9191

9292
if(!is_null(v)) ret[f.df.fieldname] = v;

frappe/public/js/frappe/utils/utils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ Object.assign(frappe.utils, {
253253
regExp = /^\w+$/;
254254
break;
255255
case "email":
256-
regExp = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
256+
regExp = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/;
257257
break;
258258
case "url":
259259
regExp = /^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i;

frappe/utils/mock.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
from frappe.model.document import Document
2+
from frappe.model.meta import Meta
3+
4+
def mock_field(**kwargs):
5+
"""Creats a mock field definition. Used during unittesting to reduce framework calls and
6+
only test the smallest unit of work required.
7+
8+
Params:
9+
kwargs: dict -> All fields you need to test against. Refer to doctype json file definitions.
10+
11+
Returns:
12+
A dict containing meta information of this field.
13+
"""
14+
15+
meta = {
16+
"doctype": "DocField",
17+
"owner": "Administrator",
18+
"modified_by": "Administrator",
19+
"parentfield": "fields",
20+
"parenttype": "DocType"
21+
}
22+
23+
if kwargs and len(kwargs) > 0:
24+
meta.update(kwargs)
25+
26+
return meta
27+
28+
def mock_meta(doctype, fields):
29+
"""Creates a mock metadata for a given doctype. Used during unittesting to reduce framework calls and
30+
only test the smallest unit of work required.'
31+
32+
Params:
33+
doctype: string -> The doctype to mock.
34+
fields: list -> A list of dict defining individual fields. Only define what you are testing against.
35+
36+
Returns:
37+
A Meta instance defining our mock doctype
38+
"""
39+
40+
return Meta({
41+
"doctype": "DocType",
42+
"name": doctype,
43+
"parent": None,
44+
"parentfield": None,
45+
"parenttype": None,
46+
"document_type": "Document",
47+
"fields": [ mock_field(doctype=doctype, **field) for field in fields ]
48+
})
49+
50+
def build_get_meta_side_effects(metas):
51+
"""Returns a mock side effects method to be used as a side effect for the purpose of unit testing.
52+
This method replaces doctype metas for user defined ones. The returned method should be passed
53+
to a unittest.mock.MagicMock instance via patch or mock. This prevents database calls and enforces
54+
unit test isolation.
55+
56+
Params:
57+
metas: list -> A list of Meta instances created with mock_meta()
58+
59+
Example:
60+
@patch('frappe.get_doc')
61+
@patch('frappe.get_meta')
62+
def test_fetch_quotation(self, get_meta, get_doc):
63+
# Mock Quotation
64+
get_doc.side_effect = [Document({
65+
"doctype": "Quotation",
66+
"name": "test-quotation",
67+
"customer_name": "test-customer"
68+
})]
69+
70+
# Mock Quotation Metadata. Notice the limited set of fields.
71+
get_meta.side_effect = build_get_meta_side_effects(
72+
mock_meta("Quotation", fields=[
73+
{ "fieldname": "name", "fieldtype": "Data" },
74+
{ "fieldname": "customer_name", "fieldtype": "Link", "options": "Customer" }
75+
])
76+
)
77+
78+
# Fetches the mocked quotation
79+
doc = frappe.get_doc("Quotation", "test-quotation")
80+
81+
# Then perform your tests
82+
get_doc.assert_called()
83+
get_meta.assert_called()
84+
self.assertTrue(doc.customer == "test-customer")
85+
"""
86+
87+
def side_effect(doctype, cached=False):
88+
for meta in metas:
89+
if meta.name == doctype:
90+
return meta
91+
92+
raise Exception("Unexpected get_meta doctype: {}".format(doctype))
93+
94+
return side_effect
95+
96+
def build_get_doc_side_effect(docs):
97+
"""Builds a side effect method to wrap frappe.get_doc method. This makes it
98+
convenient to store multiple mock documents during unittests"""
99+
100+
def get_doc(doctype, name):
101+
for doc in docs:
102+
if doc.name == name:
103+
return doc
104+
105+
raise Exception("Mock document not found: {}: {}".format(doctype, name))
106+
107+
return get_doc

frappe/website/js/website.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ $.extend(frappe, {
375375

376376
window.valid_email = function(id) {
377377
// eslint-disable-next-line
378-
return /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(id.toLowerCase());
378+
return /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/.test(id.toLowerCase());
379379
}
380380

381381
window.validate_email = valid_email;

0 commit comments

Comments
 (0)