Merge branch 'develop' into set-password
This commit is contained in:
commit
99a04d24d1
22 changed files with 939 additions and 380 deletions
|
|
@ -82,7 +82,7 @@ def handle():
|
|||
if frappe.local.request.method=="PUT":
|
||||
data = get_request_form_data()
|
||||
|
||||
doc = frappe.get_doc(doctype, name)
|
||||
doc = frappe.get_doc(doctype, name, for_update=True)
|
||||
|
||||
if "flags" in data:
|
||||
del data["flags"]
|
||||
|
|
|
|||
|
|
@ -154,7 +154,6 @@ class LoginManager:
|
|||
self.make_session()
|
||||
self.setup_boot_cache()
|
||||
self.set_user_info()
|
||||
self.clear_preferred_language()
|
||||
|
||||
def get_user_info(self):
|
||||
self.info = frappe.db.get_value("User", self.user,
|
||||
|
|
|
|||
|
|
@ -66,4 +66,92 @@ frappe.ui.form.on('DocType', {
|
|||
autoname: function(frm) {
|
||||
frm.set_df_property('fields', 'reqd', frm.doc.autoname !== 'Prompt');
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
frappe.ui.form.on("DocField", {
|
||||
form_render(frm, doctype, docname) {
|
||||
// Render two select fields for Fetch From instead of Small Text for better UX
|
||||
let field = frm.cur_grid.grid_form.fields_dict.fetch_from;
|
||||
$(field.input_area).hide();
|
||||
|
||||
let $doctype_select = $(`<select class="form-control">`);
|
||||
let $field_select = $(`<select class="form-control">`);
|
||||
let $wrapper = $('<div class="fetch-from-select row"><div>');
|
||||
$wrapper.append($doctype_select, $field_select);
|
||||
field.$input_wrapper.append($wrapper);
|
||||
$doctype_select.wrap('<div class="col"></div>');
|
||||
$field_select.wrap('<div class="col"></div>');
|
||||
|
||||
let row = frappe.get_doc(doctype, docname);
|
||||
let curr_value = { doctype: null, fieldname: null };
|
||||
if (row.fetch_from) {
|
||||
let [doctype, fieldname] = row.fetch_from.split(".");
|
||||
curr_value.doctype = doctype;
|
||||
curr_value.fieldname = fieldname;
|
||||
}
|
||||
let curr_df_link_doctype = row.fieldtype == "Link" ? row.options : null;
|
||||
|
||||
let doctypes = frm.doc.fields
|
||||
.filter(df => df.fieldtype == "Link")
|
||||
.filter(df => df.options && df.options != curr_df_link_doctype)
|
||||
.map(df => ({
|
||||
label: `${df.options} (${df.fieldname})`,
|
||||
value: df.fieldname
|
||||
}));
|
||||
$doctype_select.add_options([
|
||||
{ label: __("Select DocType"), value: "", selected: true },
|
||||
...doctypes
|
||||
]);
|
||||
|
||||
$doctype_select.on("change", () => {
|
||||
row.fetch_from = "";
|
||||
frm.dirty();
|
||||
update_fieldname_options();
|
||||
});
|
||||
|
||||
function update_fieldname_options() {
|
||||
$field_select.find("option").remove();
|
||||
|
||||
let link_fieldname = $doctype_select.val();
|
||||
if (!link_fieldname) return;
|
||||
let link_field = frm.doc.fields.find(
|
||||
df => df.fieldname === link_fieldname
|
||||
);
|
||||
let link_doctype = link_field.options;
|
||||
frappe.model.with_doctype(link_doctype, () => {
|
||||
let fields = frappe.meta
|
||||
.get_docfields(link_doctype, null, {
|
||||
fieldtype: ["not in", frappe.model.no_value_type]
|
||||
})
|
||||
.map(df => ({
|
||||
label: `${df.label} (${df.fieldtype})`,
|
||||
value: df.fieldname
|
||||
}));
|
||||
$field_select.add_options([
|
||||
{
|
||||
label: __("Select Field"),
|
||||
value: "",
|
||||
selected: true,
|
||||
disabled: true
|
||||
},
|
||||
...fields
|
||||
]);
|
||||
|
||||
if (curr_value.fieldname) {
|
||||
$field_select.val(curr_value.fieldname);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$field_select.on("change", () => {
|
||||
let fetch_from = `${$doctype_select.val()}.${$field_select.val()}`;
|
||||
row.fetch_from = fetch_from;
|
||||
frm.dirty();
|
||||
});
|
||||
|
||||
if (curr_value.doctype) {
|
||||
$doctype_select.val(curr_value.doctype);
|
||||
update_fieldname_options();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -931,6 +931,9 @@ def validate_fields(meta):
|
|||
if meta.website_search_field not in fieldname_list:
|
||||
frappe.throw(_("Website Search Field must be a valid fieldname"), InvalidFieldNameError)
|
||||
|
||||
if "title" not in fieldname_list:
|
||||
frappe.throw(_('Field "title" is mandatory if "Website Search Field" is set.'), title=_("Missing Field"))
|
||||
|
||||
def check_timeline_field(meta):
|
||||
if not meta.timeline_field:
|
||||
return
|
||||
|
|
|
|||
|
|
@ -8,35 +8,14 @@ from urllib.parse import parse_qs
|
|||
from frappe.utils import get_request_session
|
||||
from frappe import _
|
||||
|
||||
def make_get_request(url, auth=None, headers=None, data=None):
|
||||
if not auth:
|
||||
auth = ''
|
||||
if not data:
|
||||
data = {}
|
||||
if not headers:
|
||||
headers = {}
|
||||
def make_request(method, url, auth=None, headers=None, data=None):
|
||||
auth = auth or ''
|
||||
data = data or {}
|
||||
headers = headers or {}
|
||||
|
||||
try:
|
||||
s = get_request_session()
|
||||
frappe.flags.integration_request = s.get(url, data={}, auth=auth, headers=headers)
|
||||
frappe.flags.integration_request.raise_for_status()
|
||||
return frappe.flags.integration_request.json()
|
||||
|
||||
except Exception as exc:
|
||||
frappe.log_error(frappe.get_traceback())
|
||||
raise exc
|
||||
|
||||
def make_post_request(url, auth=None, headers=None, data=None):
|
||||
if not auth:
|
||||
auth = ''
|
||||
if not data:
|
||||
data = {}
|
||||
if not headers:
|
||||
headers = {}
|
||||
|
||||
try:
|
||||
s = get_request_session()
|
||||
frappe.flags.integration_request = s.post(url, data=data, auth=auth, headers=headers)
|
||||
frappe.flags.integration_request = s.request(method, url, data=data, auth=auth, headers=headers)
|
||||
frappe.flags.integration_request.raise_for_status()
|
||||
|
||||
if frappe.flags.integration_request.headers.get("content-type") == "text/plain; charset=utf-8":
|
||||
|
|
@ -47,6 +26,15 @@ def make_post_request(url, auth=None, headers=None, data=None):
|
|||
frappe.log_error()
|
||||
raise exc
|
||||
|
||||
def make_get_request(url, **kwargs):
|
||||
return make_request('GET', url, **kwargs)
|
||||
|
||||
def make_post_request(url, **kwargs):
|
||||
return make_request('POST', url, **kwargs)
|
||||
|
||||
def make_put_request(url, **kwargs):
|
||||
return make_request('PUT', url, **kwargs)
|
||||
|
||||
def create_request_log(data, integration_type, service_name, name=None, error=None):
|
||||
if isinstance(data, str):
|
||||
data = json.loads(data)
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ frappe.ui.form.ControlSelect = class ControlSelect extends frappe.ui.form.Contro
|
|||
var is_value_null = is_null(v.value);
|
||||
var is_label_null = is_null(v.label);
|
||||
var is_disabled = Boolean(v.disabled);
|
||||
var is_selected = Boolean(v.selected);
|
||||
|
||||
if (is_value_null && is_label_null) {
|
||||
value = v;
|
||||
|
|
@ -126,6 +127,7 @@ frappe.ui.form.ControlSelect = class ControlSelect extends frappe.ui.form.Contro
|
|||
$('<option>').html(cstr(label))
|
||||
.attr('value', value)
|
||||
.prop('disabled', is_disabled)
|
||||
.prop('selected', is_selected)
|
||||
.appendTo(this);
|
||||
}
|
||||
// select the first option
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ function get_version_comment(version_doc, text) {
|
|||
let unlinked_content = "";
|
||||
|
||||
try {
|
||||
text += '</>';
|
||||
Array.from($(text)).forEach(element => {
|
||||
if ($(element).is('a')) {
|
||||
version_comment += unlinked_content ? frappe.utils.get_form_link('Version', version_doc.name, true, unlinked_content) : "";
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ frappe.ui.form.FormTour = class FormTour {
|
|||
return {
|
||||
element,
|
||||
name,
|
||||
popover: { title, description, position: frappe.router.slug(position) },
|
||||
popover: { title, description, position: frappe.router.slug(position || 'Bottom') },
|
||||
onNext: on_next
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -264,15 +264,16 @@ export default class Grid {
|
|||
|
||||
make_head() {
|
||||
// labels
|
||||
if (!this.header_row) {
|
||||
this.header_row = new GridRow({
|
||||
parent: $(this.parent).find(".grid-heading-row"),
|
||||
parent_df: this.df,
|
||||
docfields: this.docfields,
|
||||
frm: this.frm,
|
||||
grid: this
|
||||
});
|
||||
if (this.header_row) {
|
||||
$(this.parent).find(".grid-heading-row .grid-row").remove();
|
||||
}
|
||||
this.header_row = new GridRow({
|
||||
parent: $(this.parent).find(".grid-heading-row"),
|
||||
parent_df: this.df,
|
||||
docfields: this.docfields,
|
||||
frm: this.frm,
|
||||
grid: this
|
||||
});
|
||||
}
|
||||
|
||||
refresh(force) {
|
||||
|
|
|
|||
|
|
@ -250,6 +250,14 @@ frappe.ui.form.Layout = class Layout {
|
|||
// collapse sections
|
||||
this.refresh_section_collapse();
|
||||
}
|
||||
|
||||
if (document.activeElement) {
|
||||
document.activeElement.focus();
|
||||
|
||||
if (document.activeElement.tagName == 'INPUT') {
|
||||
document.activeElement.select();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
refresh_sections() {
|
||||
|
|
|
|||
|
|
@ -514,7 +514,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
|
||||
render_skeleton() {
|
||||
const $row = this.get_list_row_html_skeleton(
|
||||
'<div><input type="checkbox" /></div>'
|
||||
'<div><input type="checkbox" class="render-list-checkbox"/></div>'
|
||||
);
|
||||
this.$result.append($row);
|
||||
}
|
||||
|
|
@ -927,10 +927,12 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
const seen = this.get_seen_class(doc);
|
||||
|
||||
let subject_html = `
|
||||
<input class="level-item list-row-checkbox hidden-xs" type="checkbox"
|
||||
data-name="${escape(doc.name)}">
|
||||
<span class="level-item" style="margin-bottom: 1px;">
|
||||
${this.get_like_html(doc)}
|
||||
<span class="level-item select-like">
|
||||
<input class="list-row-checkbox hidden-xs" type="checkbox"
|
||||
data-name="${escape(doc.name)}">
|
||||
<span class="list-row-like style="margin-bottom: 1px;">
|
||||
${this.get_like_html(doc)}
|
||||
</span>
|
||||
</span>
|
||||
<span class="level-item ${seen} ellipsis" title="${escaped_subject}">
|
||||
<a class="ellipsis"
|
||||
|
|
@ -1127,7 +1129,8 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
// don't open form when checkbox, like, filterable are clicked
|
||||
if (
|
||||
$target.hasClass("filterable") ||
|
||||
$target.hasClass("icon-heart") ||
|
||||
$target.hasClass("select-like") ||
|
||||
$target.hasClass("list-row-like") ||
|
||||
$target.is(":checkbox")
|
||||
) {
|
||||
e.stopPropagation();
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@
|
|||
<div class="grid-body">
|
||||
<div class="rows">
|
||||
<div class="grid-row" :class="showing == call.index ? 'grid-row-open' : ''" v-for="call in paginated(sorted(grouped(request.calls)))" :key="call.index">
|
||||
<div class="data-row row" v-if="showing != call.index" style="display: block;" @click="showing = call.index" >
|
||||
<div class="data-row row" @click="showing = showing == call.index ? null : call.index" >
|
||||
<div class="row-index col col-xs-1"><span>{{ call.index }}</span></div>
|
||||
<div class="col grid-static-col col-xs-6" data-fieldtype="Code">
|
||||
<div class="static-area"><span>{{ call.query }}</span></div>
|
||||
|
|
@ -76,16 +76,13 @@
|
|||
<div class="static-area ellipsis text-right">{{ call.exact_copies }}</div>
|
||||
</div>
|
||||
<div class="col col-xs-1"><a class="close btn-open-row">
|
||||
<span class="octicon octicon-triangle-down"></span></a>
|
||||
<span class="octicon" :class="showing == call.index? 'octicon-triangle-up' : 'octicon-triangle-down'"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="recorder-form-in-grid" v-if="showing == call.index">
|
||||
<div class="grid-form-heading" @click="showing = null">
|
||||
<div class="toolbar grid-header-toolbar">
|
||||
<span class="panel-title">{{ __("SQL Query") }} #<span class="grid-form-row-index">{{ call.index }}</span></span>
|
||||
<div class="btn btn-default btn-xs pull-right" style="margin-left: 7px;">
|
||||
<span class="hidden-xs octicon octicon-triangle-up"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid-form-body">
|
||||
|
|
@ -116,7 +113,7 @@
|
|||
</div>
|
||||
<div class="frappe-control">
|
||||
<div class="form-group">
|
||||
<div class="clearfix"><label class="control-label"{{ __("Stack Trace") }}</label></div>
|
||||
<div class="clearfix"><label class="control-label">{{ __("Stack Trace") }}</label></div>
|
||||
<div class="control-value like-disabled-input for-description" style="overflow:auto">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ $('body').on('click', 'a', function(e) {
|
|||
return override('/app');
|
||||
}
|
||||
|
||||
if (href.startsWith('#')) {
|
||||
if (href && href.startsWith('#')) {
|
||||
// target startswith "#", this is a v1 style route, so remake it.
|
||||
return override(e.currentTarget.hash);
|
||||
}
|
||||
|
|
@ -169,10 +169,8 @@ frappe.router = {
|
|||
standard_route = ['Tree', doctype_route.doctype];
|
||||
} else {
|
||||
standard_route = ['List', doctype_route.doctype, frappe.utils.to_title_case(route[2])];
|
||||
if (route[3]) {
|
||||
// calendar / kanban / dashboard / folder name
|
||||
standard_route.push([...route].splice(3, route.length));
|
||||
}
|
||||
// calendar / kanban / dashboard / folder
|
||||
if (route[3]) standard_route.push(...route.slice(3, route.length));
|
||||
}
|
||||
return standard_route;
|
||||
},
|
||||
|
|
@ -245,7 +243,7 @@ frappe.router = {
|
|||
// example 1: frappe.set_route('a', 'b', 'c');
|
||||
// example 2: frappe.set_route(['a', 'b', 'c']);
|
||||
// example 3: frappe.set_route('a/b/c');
|
||||
let route = arguments;
|
||||
let route = Array.from(arguments);
|
||||
|
||||
return new Promise(resolve => {
|
||||
route = this.get_route_from_arguments(route);
|
||||
|
|
@ -297,7 +295,7 @@ frappe.router = {
|
|||
new_route = [this.slug(route[1]), 'view', route[2].toLowerCase()];
|
||||
|
||||
// calendar / inbox / file folder
|
||||
if (route[3]) new_route.push([...route].slice(3, route.length));
|
||||
if (route[3]) new_route.push(...route.slice(3, route.length));
|
||||
} else {
|
||||
if ($.isPlainObject(route[2])) {
|
||||
frappe.route_options = route[2];
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@
|
|||
}
|
||||
|
||||
.list-row {
|
||||
padding: 15px;
|
||||
padding: 15px 15px 15px 0px;
|
||||
height: 45px;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
|
|
@ -130,10 +130,15 @@
|
|||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.select-like {
|
||||
padding: 15px 0px 15px 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.list-row-head {
|
||||
@extend .list-row;
|
||||
padding: 15px;
|
||||
cursor: default;
|
||||
|
||||
.list-subject {
|
||||
|
|
@ -200,6 +205,10 @@ input.list-check-all, input.list-row-checkbox {
|
|||
--checkbox-right-margin: calc(var(--checkbox-size) / 2 + #{$level-margin-right});
|
||||
}
|
||||
|
||||
.render-list-checkbox {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.filterable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,19 +90,22 @@ class WebsiteSearch(FullTextSearch):
|
|||
def slugs_with_web_view(_items_to_index):
|
||||
all_routes = []
|
||||
filters = { "has_web_view": 1, "allow_guest_to_view": 1, "index_web_pages_for_search": 1}
|
||||
fields = ["name", "is_published_field", 'website_search_field']
|
||||
fields = ["name", "is_published_field", "website_search_field"]
|
||||
doctype_with_web_views = frappe.get_all("DocType", filters=filters, fields=fields)
|
||||
|
||||
for doctype in doctype_with_web_views:
|
||||
if doctype.is_published_field:
|
||||
docs = frappe.get_all(doctype.name, filters={doctype.is_published_field: 1}, fields=["route", doctype.website_search_field, 'title'])
|
||||
fields=["route", doctype.website_search_field]
|
||||
filters={doctype.is_published_field: 1},
|
||||
if doctype.website_search_field:
|
||||
docs = frappe.get_all(doctype.name, filters=filters, fields=fields.append("title"))
|
||||
for doc in docs:
|
||||
content = frappe.utils.md_to_html(getattr(doc, doctype.website_search_field))
|
||||
soup = BeautifulSoup(content, "html.parser")
|
||||
text_content = soup.text if soup else ""
|
||||
_items_to_index += [frappe._dict(title=doc.title, content=text_content, path=doc.route)]
|
||||
else:
|
||||
docs = frappe.get_all(doctype.name, filters=filters, fields=fields)
|
||||
all_routes += [route.route for route in docs]
|
||||
|
||||
return all_routes
|
||||
|
|
|
|||
|
|
@ -18,8 +18,19 @@ first_lang, second_lang, third_lang, fourth_lang, fifth_lang = choices(
|
|||
)
|
||||
|
||||
class TestTranslate(unittest.TestCase):
|
||||
guest_sessions_required = [
|
||||
"test_guest_request_language_resolution_with_cookie",
|
||||
"test_guest_request_language_resolution_with_request_header"
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
if self._testMethodName in self.guest_sessions_required:
|
||||
frappe.set_user("Guest")
|
||||
|
||||
def tearDown(self):
|
||||
frappe.form_dict.pop("_lang", None)
|
||||
if self._testMethodName in self.guest_sessions_required:
|
||||
frappe.set_user("Administrator")
|
||||
|
||||
def test_extract_message_from_file(self):
|
||||
data = frappe.translate.get_messages_from_file(translation_string_file)
|
||||
|
|
@ -52,20 +63,44 @@ class TestTranslate(unittest.TestCase):
|
|||
Case 2: frappe.form_dict._lang is not set, but preferred_language cookie is
|
||||
"""
|
||||
|
||||
with patch.object(frappe.translate, "get_preferred_language_cookie", return_value=second_lang):
|
||||
set_request(method="POST", path="/", headers=[("Accept-Language", third_lang)])
|
||||
return_val = get_language()
|
||||
|
||||
self.assertNotIn(return_val, [second_lang, get_parent_language(second_lang)])
|
||||
|
||||
def test_guest_request_language_resolution_with_cookie(self):
|
||||
"""Test for frappe.translate.get_language
|
||||
|
||||
Case 3: frappe.form_dict._lang is not set, but preferred_language cookie is [Guest User]
|
||||
"""
|
||||
|
||||
with patch.object(frappe.translate, "get_preferred_language_cookie", return_value=second_lang):
|
||||
set_request(method="POST", path="/", headers=[("Accept-Language", third_lang)])
|
||||
return_val = get_language()
|
||||
|
||||
self.assertIn(return_val, [second_lang, get_parent_language(second_lang)])
|
||||
|
||||
|
||||
def test_guest_request_language_resolution_with_request_header(self):
|
||||
"""Test for frappe.translate.get_language
|
||||
|
||||
Case 4: frappe.form_dict._lang & preferred_language cookie is not set, but Accept-Language header is [Guest User]
|
||||
"""
|
||||
|
||||
set_request(method="POST", path="/", headers=[("Accept-Language", third_lang)])
|
||||
return_val = get_language()
|
||||
self.assertIn(return_val, [third_lang, get_parent_language(third_lang)])
|
||||
|
||||
def test_request_language_resolution_with_request_header(self):
|
||||
"""Test for frappe.translate.get_language
|
||||
|
||||
Case 3: frappe.form_dict._lang & preferred_language cookie is not set, but Accept-Language header is
|
||||
Case 5: frappe.form_dict._lang & preferred_language cookie is not set, but Accept-Language header is
|
||||
"""
|
||||
|
||||
set_request(method="POST", path="/", headers=[("Accept-Language", third_lang)])
|
||||
return_val = get_language()
|
||||
self.assertIn(return_val, [third_lang, get_parent_language(third_lang)])
|
||||
self.assertNotIn(return_val, [third_lang, get_parent_language(third_lang)])
|
||||
|
||||
|
||||
expected_output = [
|
||||
|
|
|
|||
|
|
@ -27,11 +27,12 @@ def get_language(lang_list: List = None) -> str:
|
|||
|
||||
Order of priority for setting language:
|
||||
1. Form Dict => _lang
|
||||
2. Cookie => preferred_language
|
||||
3. Request Header => Accept-Language
|
||||
2. Cookie => preferred_language (Non authorized user)
|
||||
3. Request Header => Accept-Language (Non authorized user)
|
||||
4. User document => language
|
||||
5. System Settings => language
|
||||
"""
|
||||
is_logged_in = frappe.session.user != "Guest"
|
||||
|
||||
# fetch language from form_dict
|
||||
if frappe.form_dict._lang:
|
||||
|
|
@ -41,6 +42,10 @@ def get_language(lang_list: List = None) -> str:
|
|||
if language:
|
||||
return language
|
||||
|
||||
# use language set in User or System Settings if user is logged in
|
||||
if is_logged_in:
|
||||
return frappe.local.lang
|
||||
|
||||
lang_set = set(lang_list or get_all_languages() or [])
|
||||
|
||||
# fetch language from cookie
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ from frappe.utils.commands import log
|
|||
|
||||
default_timeout = 300
|
||||
queue_timeout = {
|
||||
'background': 2500,
|
||||
'long': 1500,
|
||||
'default': 300,
|
||||
'short': 300
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ def update_add_node(doc, parent, parent_field):
|
|||
|
||||
# get the last sibling of the parent
|
||||
if parent:
|
||||
left, right = frappe.db.sql("select lft, rgt from `tab{0}` where name=%s"
|
||||
left, right = frappe.db.sql("select lft, rgt from `tab{0}` where name=%s for update"
|
||||
.format(doctype), parent)[0]
|
||||
validate_loop(doc.doctype, doc.name, left, right)
|
||||
else: # root
|
||||
|
|
@ -89,7 +89,7 @@ def update_move_node(doc, parent_field):
|
|||
|
||||
if parent:
|
||||
new_parent = frappe.db.sql("""select lft, rgt from `tab{0}`
|
||||
where name = %s""".format(doc.doctype), parent, as_dict=1)[0]
|
||||
where name = %s for update""".format(doc.doctype), parent, as_dict=1)[0]
|
||||
|
||||
validate_loop(doc.doctype, doc.name, new_parent.lft, new_parent.rgt)
|
||||
|
||||
|
|
@ -108,7 +108,7 @@ def update_move_node(doc, parent_field):
|
|||
|
||||
if parent:
|
||||
new_parent = frappe.db.sql("""select lft, rgt from `tab%s`
|
||||
where name = %s""" % (doc.doctype, '%s'), parent, as_dict=1)[0]
|
||||
where name = %s for update""" % (doc.doctype, '%s'), parent, as_dict=1)[0]
|
||||
|
||||
|
||||
# set parent lft, rgt
|
||||
|
|
|
|||
|
|
@ -488,11 +488,12 @@ def set_content_type(response, data, path):
|
|||
return data
|
||||
|
||||
def add_preload_headers(response):
|
||||
from bs4 import BeautifulSoup
|
||||
from bs4 import BeautifulSoup, SoupStrainer
|
||||
|
||||
try:
|
||||
preload = []
|
||||
soup = BeautifulSoup(response.data, "lxml")
|
||||
strainer = SoupStrainer(re.compile("script|link"))
|
||||
soup = BeautifulSoup(response.data, "lxml", parse_only=strainer)
|
||||
for elem in soup.find_all('script', src=re.compile(".*")):
|
||||
preload.append(("script", elem.get("src")))
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
"qz-tray": "^2.0.8",
|
||||
"redis": "^3.1.1",
|
||||
"showdown": "^1.9.1",
|
||||
"snyk": "^1.518.0",
|
||||
"snyk": "^1.667.0",
|
||||
"socket.io": "^2.4.0",
|
||||
"superagent": "^3.8.2",
|
||||
"touch": "^3.1.0",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue