Merge branch 'develop' of https://github.com/frappe/frappe into pref_global_search

This commit is contained in:
Himanshu Warekar 2019-11-10 09:48:29 +05:30
commit 00df2ddbad
20 changed files with 94 additions and 54 deletions

View file

@ -219,6 +219,10 @@ class LoginManager:
if not self.user:
return
from frappe.core.doctype.user.user import STANDARD_USERS
if self.user in STANDARD_USERS:
return False
reset_pwd_after_days = cint(frappe.db.get_single_value("System Settings",
"force_user_to_reset_password"))

View file

@ -381,7 +381,7 @@ def parse_email(communication, email_strings):
a doctype and docname ie in the format `admin+doctype+docname@example.com`,
the email is parsed and doctype and docname is extracted and timeline link is added.
"""
if not frappe.get_list("Email Account", filters={"enable_automatic_linking": 1}):
if not frappe.get_all("Email Account", filters={"enable_automatic_linking": 1}):
return
delimiter = "+"
@ -406,7 +406,7 @@ def get_email_without_link(email):
returns email address without doctype links
returns admin@example.com for email admin+doctype+docname@example.com
"""
if not frappe.get_list("Email Account", filters={"enable_automatic_linking": 1}):
if not frappe.get_all("Email Account", filters={"enable_automatic_linking": 1}):
return email
email_id = email.split("@")[0].split("+")[0]

View file

@ -31,6 +31,9 @@ def run_server_script_for_doc_event(doc, event):
if frappe.flags.in_install:
return
if frappe.flags.in_migrate:
return
scripts = get_server_script_map().get(doc.doctype, {}).get(EVENT_MAP[event], None)
if scripts:
# run all scripts for this doctype + event

View file

@ -41,7 +41,7 @@ def find(list_of_dict, match_function):
Usage:
list_of_dict = [{'name': 'Suraj'}, {'name': 'Aditya'}]
required_dict = find(list_of_dict, lamda d: d['name'] == 'Aditya')
required_dict = find(list_of_dict, lambda d: d['name'] == 'Aditya')
'''
for entry in list_of_dict:
@ -60,10 +60,10 @@ def find_all(list_of_dict, match_function):
{'color': 'blue', 'shape': 'triangle'}
]
red_shapes = find_all(colored_shapes, lamda d: d['color'] == 'red')
red_shapes = find_all(colored_shapes, lambda d: d['color'] == 'red')
'''
found = []
for entry in list_of_dict:
if match_function(entry):
found.append(entry)
return found
return found

View file

@ -174,6 +174,7 @@ class Database(object):
self.log_touched_tables(query)
if debug:
frappe.errprint(self._cursor.mogrify(query, values))
time_end = time()
frappe.errprint(("Execution time: {0} sec").format(round(time_end - time_start, 2)))

View file

@ -25,6 +25,16 @@ def get_permission_query_conditions(for_user):
return '''(`tabNotification Log`.for_user = '{user}')'''.format(user=for_user)
def get_title(doctype, docname, title_field=None):
if not title_field:
title_field = frappe.get_meta(doctype).get_title_field()
title = docname if title_field == "name" else \
frappe.db.get_value(doctype, docname, title_field)
return title
def get_title_html(title):
return '<b class="subject-title">{0}</b>'.format(title)
def enqueue_create_notification(users, doc):
'''
During installation of new site, enqueue_create_notification tries to connect to Redis.
@ -101,16 +111,6 @@ def get_email_header(doc):
}[doc.type or 'Default']
def get_title(doctype, docname, title_field=None):
if not title_field:
title_field = frappe.get_meta(doctype).get_title_field()
title = docname if title_field == "name" else \
frappe.db.get_value(doctype, docname, title_field)
return title
def get_title_html(title):
return '<b class="subject-title">{0}</b>'.format(title)
@frappe.whitelist()
def mark_as_seen(docname):
if docname:

View file

@ -28,7 +28,7 @@ class TestNotificationLog(unittest.TestCase):
todo = get_todo()
user = get_user()
frappe.share.add('ToDo', todo.name, user)
frappe.share.add('ToDo', todo.name, user, notify=1)
log_type = frappe.db.get_value('Notification Log', {
'document_type': 'ToDo',
'document_name': todo.name

View file

@ -45,7 +45,7 @@ def get_group_by_count(doctype, current_filters, field):
order by
count desc
limit 50""".format(subquery_condition = subquery_condition), as_dict=True)
else :
else:
return frappe.db.get_list(doctype,
filters=current_filters,
group_by=field,

View file

@ -284,10 +284,14 @@ class DatabaseQuery(object):
def set_field_tables(self):
'''If there are more than one table, the fieldname must not be ambiguous.
If the fieldname is not explicitly mentioned, set the default table'''
def _in_standard_sql_methods(field):
methods = ('count(', 'avg(', 'sum(')
return field.lower().startswith(methods)
if len(self.tables) > 1:
for i, f in enumerate(self.fields):
if '.' not in f:
self.fields[i] = '{0}.{1}'.format(self.tables[0], f)
for idx, field in enumerate(self.fields):
if '.' not in field and not _in_standard_sql_methods(field):
self.fields[idx] = '{0}.{1}'.format(self.tables[0], field)
def set_optional_columns(self):
"""Removes optional columns like `_user_tags`, `_comments` etc. if not in table"""

View file

@ -43,13 +43,13 @@ def set_new_name(doc):
# if the autoname option is 'field:' and no name was derived, we need to
# notify
if autoname.startswith('field:') and not doc.name:
if autoname.startswith("field:") and not doc.name:
fieldname = autoname[6:]
frappe.throw(_("{0} is required").format(doc.meta.get_label(fieldname)))
# at this point, we fall back to name generation with the hash option
if not doc.name or autoname == 'hash':
doc.name = make_autoname('hash', doc.doctype)
if not doc.name or autoname == "hash":
doc.name = make_autoname("hash", doc.doctype)
doc.name = validate_name(
doc.doctype,
@ -65,15 +65,15 @@ def set_name_from_naming_options(autoname, doc):
_autoname = autoname.lower()
if _autoname.startswith('field:'):
if _autoname.startswith("field:"):
doc.name = _field_autoname(autoname, doc)
elif _autoname.startswith('naming_series:'):
elif _autoname.startswith("naming_series:"):
set_name_by_naming_series(doc)
elif _autoname.startswith('prompt'):
elif _autoname.startswith("prompt"):
_prompt_autoname(autoname, doc)
elif _autoname.startswith('format:'):
elif _autoname.startswith("format:"):
doc.name = _format_autoname(autoname, doc)
elif '#' in autoname:
elif "#" in autoname:
doc.name = make_autoname(autoname, doc=doc)
def set_name_by_naming_series(doc):
@ -84,9 +84,9 @@ def set_name_by_naming_series(doc):
if not doc.naming_series:
frappe.throw(frappe._("Naming Series mandatory"))
doc.name = make_autoname(doc.naming_series+'.#####', '', doc)
doc.name = make_autoname(doc.naming_series+".#####", "", doc)
def make_autoname(key='', doctype='', doc=''):
def make_autoname(key="", doctype="", doc=""):
"""
Creates an autoname from the given key:
@ -199,12 +199,12 @@ def get_default_naming_series(doctype):
def validate_name(doctype, name, case=None, merge=False):
if not name:
return 'No Name Specified for %s' % doctype
if name.startswith('New '+doctype):
frappe.throw(_('There were some errors setting the name, please contact the administrator'), frappe.NameError)
if case == 'Title Case':
frappe.throw(_("No Name Specified for {0}").format(doctype))
if name.startswith("New "+doctype):
frappe.throw(_("There were some errors setting the name, please contact the administrator"), frappe.NameError)
if case == "Title Case":
name = name.title()
if case == 'UPPER CASE':
if case == "UPPER CASE":
name = name.upper()
name = name.strip()
@ -219,13 +219,13 @@ def validate_name(doctype, name, case=None, merge=False):
return name
def append_number_if_name_exists(doctype, value, fieldname='name', separator='-', filters=None):
def append_number_if_name_exists(doctype, value, fieldname="name", separator="-", filters=None):
if not filters:
filters = dict()
filters.update({fieldname: value})
exists = frappe.db.exists(doctype, filters)
regex = '^{value}{separator}\d+$'.format(value=re.escape(value), separator=separator)
regex = "^{value}{separator}\d+$".format(value=re.escape(value), separator=separator)
if exists:
last = frappe.db.sql("""SELECT `{fieldname}` FROM `tab{doctype}`
@ -251,10 +251,10 @@ def _set_amended_name(doc):
am_id = 1
am_prefix = doc.amended_from
if frappe.db.get_value(doc.doctype, doc.amended_from, "amended_from"):
am_id = cint(doc.amended_from.split('-')[-1]) + 1
am_prefix = '-'.join(doc.amended_from.split('-')[:-1]) # except the last hyphen
am_id = cint(doc.amended_from.split("-")[-1]) + 1
am_prefix = "-".join(doc.amended_from.split("-")[:-1]) # except the last hyphen
doc.name = am_prefix + '-' + str(am_id)
doc.name = am_prefix + "-" + str(am_id)
return doc.name
@ -264,7 +264,7 @@ def _field_autoname(autoname, doc, skip_slicing=None):
`autoname` field starts with 'field:'
"""
fieldname = autoname if skip_slicing else autoname[6:]
name = (cstr(doc.get(fieldname)) or '').strip()
name = (cstr(doc.get(fieldname)) or "").strip()
return name
@ -285,7 +285,7 @@ def _format_autoname(autoname, doc):
Example pattern: 'format:LOG-{MM}-{fieldname1}-{fieldname2}-{#####}'
"""
first_colon_index = autoname.find(':')
first_colon_index = autoname.find(":")
autoname_value = autoname[first_colon_index + 1:]
def get_param_value_for_match(match):
@ -295,6 +295,6 @@ def _format_autoname(autoname, doc):
return parse_naming_series([trimmed_param], doc=doc)
# Replace braced params with their parsed value
name = re.sub(r'(\{[\w | #]+\})', get_param_value_for_match, autoname_value)
name = re.sub(r"(\{[\w | #]+\})", get_param_value_for_match, autoname_value)
return name

View file

@ -256,3 +256,4 @@ frappe.patches.v12_0.update_global_search
execute:frappe.reload_doc('desk', 'doctype', 'notification_settings')
frappe.patches.v12_0.setup_tags
frappe.patches.v12_0.update_auto_repeat_status_and_not_submittable
frappe.patches.v12_0.copy_to_parent_for_tags

View file

@ -0,0 +1,6 @@
import frappe
def execute():
frappe.db.sql("UPDATE `tabTag Link` SET parenttype=document_type")
frappe.db.sql("UPDATE `tabTag Link` SET parent=document_name")

View file

@ -101,6 +101,9 @@ frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
validate(value) {
let valid_values = this.awesomplete._list.map(d => d.value);
if (!valid_values.length) {
return value;
}
if (valid_values.includes(value)) {
return value;
} else {

View file

@ -119,9 +119,12 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
} else {
value = this.value || value;
}
this.disp_area && $(this.disp_area)
.html(frappe.format(value, this.df, {no_icon:true, inline:true},
this.doc || (this.frm && this.frm.doc)));
if (this.df.fieldtype === 'Data') {
value = frappe.utils.escape_html(value);
}
let doc = this.doc || (this.frm && this.frm.doc);
let display_value = frappe.format(value, this.df, { no_icon: true, inline: true }, doc);
this.disp_area && $(this.disp_area).html(display_value);
},
bind_change_event: function() {
@ -184,4 +187,4 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
$(this.disp_area).toggleClass("bold", !!(this.df.bold || this.df.reqd));
}
}
});
});

View file

@ -141,6 +141,7 @@ frappe.ui.form.Share = Class.extend({
read: $(d.body).find(".add-share-read").prop("checked") ? 1 : 0,
write: $(d.body).find(".add-share-write").prop("checked") ? 1 : 0,
share: $(d.body).find(".add-share-share").prop("checked") ? 1 : 0,
notify: 1,
},
btn: this,
callback: function(r) {

View file

@ -177,7 +177,6 @@ frappe.ui.Filter = class {
if (doctype === "Tag Link" || fieldname === "_user_tags") {
original_docfield = {fieldname: "tag", fieldtype: "Data", label: "Tags", parent: "Tag Link"};
doctype = "Tag Link";
condition = "=";
}
if(!original_docfield) {

View file

@ -299,7 +299,7 @@ frappe.ui.Notifications = class Notifications {
<div class="notification-timestamp text-muted">
${timestamp}
</div>
<span class="mark-read text-muted" data-action="explicitly_mark_as_seen">
<span class="mark-read text-muted hidden-xs" data-action="explicitly_mark_as_seen">
${__('Mark as Read')}
</span>
</a>`;

View file

@ -10,7 +10,7 @@ from frappe.desk.doctype.notification_log.notification_log import enqueue_create
from frappe.utils import cint
@frappe.whitelist()
def add(doctype, name, user=None, read=1, write=0, share=0, everyone=0, flags=None):
def add(doctype, name, user=None, read=1, write=0, share=0, everyone=0, flags=None, notify=0):
"""Share the given document with a user."""
if not user:
user = frappe.session.user
@ -42,7 +42,7 @@ def add(doctype, name, user=None, read=1, write=0, share=0, everyone=0, flags=No
})
doc.save(ignore_permissions=True)
notify_assignment(user, doctype, name, everyone)
notify_assignment(user, doctype, name, everyone, notify=notify)
follow_document(doctype, name, user)
@ -147,9 +147,10 @@ def check_share_permission(doctype, name):
if not frappe.has_permission(doctype, ptype="share", doc=name):
frappe.throw(_("No permission to {0} {1} {2}".format("share", doctype, name)), frappe.PermissionError)
def notify_assignment(shared_by, doctype, doc_name, everyone):
def notify_assignment(shared_by, doctype, doc_name, everyone, notify=0):
if not (shared_by and doctype and doc_name) or everyone: return
if not (shared_by and doctype and doc_name) or everyone or not notify:
return
from frappe.utils import get_fullname

View file

@ -82,7 +82,10 @@ class EnergyPointRule(Document):
def process_energy_points(doc, state):
if (frappe.flags.in_patch
or frappe.flags.in_install
or not is_energy_point_enabled()):
or frappe.flags.in_migrate):
return
if not is_energy_point_enabled():
return
old_doc = doc.get_doc_before_save()

View file

@ -6,6 +6,7 @@ import frappe, unittest
from frappe.model.db_query import DatabaseQuery
from frappe.desk.reportview import get_filters_cond
from frappe.permissions import add_user_permission, clear_user_permissions_for_doctype
test_dependencies = ['User', 'Blog Post']
@ -332,6 +333,16 @@ class TestReportview(unittest.TestCase):
self.assertTrue({'name': 'Prepared Report'} in res)
self.assertFalse({'name': 'Property Setter'} in res)
def test_set_field_tables(self):
# Tests _in_standard_sql_methods method in test_set_field_tables
# The following query will break if the above method is broken
data = frappe.db.get_list("Web Form",
filters=[['Web Form Field', 'reqd', '=', 1]],
group_by='amount_field',
fields=['count(*) as count', '`amount_field` as name'],
order_by='count desc',
limit=50,
)
def create_event(subject="_Test Event", starts_on=None):
""" create a test event """