@@ -14,7 +14,7 @@ import os, sys, importlib, inspect, json | |||
from .exceptions import * | |||
from .utils.jinja import get_jenv, get_template, render_template, get_email_from_template | |||
__version__ = '8.9.3' | |||
__version__ = '8.9.4' | |||
__title__ = "Frappe Framework" | |||
local = Local() | |||
@@ -609,10 +609,11 @@ frappe.ui.form.Grid = Class.extend({ | |||
}, | |||
setup_download: function() { | |||
var me = this; | |||
let title = me.df.label || frappe.model.unscrub(me.df.fieldname); | |||
$(this.wrapper).find(".grid-download").removeClass("hide").on("click", function() { | |||
var data = []; | |||
var docfields = []; | |||
data.push([__("Bulk Edit {0}", [me.df.label])]); | |||
data.push([__("Bulk Edit {0}", [title])]); | |||
data.push([]); | |||
data.push([]); | |||
data.push([]); | |||
@@ -642,7 +643,7 @@ frappe.ui.form.Grid = Class.extend({ | |||
data.push(row); | |||
}); | |||
frappe.tools.downloadify(data, null, me.df.label); | |||
frappe.tools.downloadify(data, null, title); | |||
return false; | |||
}); | |||
}, | |||
@@ -534,11 +534,11 @@ frappe.views.QueryReport = Class.extend({ | |||
col.field = df.fieldname || df.label; | |||
df.label = __(df.label); | |||
col.name = col.id = col.label = df.label; | |||
if(df.width < 0) { | |||
col.hidden = true; | |||
} | |||
return col | |||
})); | |||
}, | |||
@@ -590,6 +590,9 @@ frappe.views.QueryReport = Class.extend({ | |||
newrow.id = newrow.name ? newrow.name : ("_" + newrow._id); | |||
this.data.push(newrow); | |||
} | |||
if(this.report_doc.add_total_row) { | |||
this.total_row_id = this.data[this.data.length - 1].id; | |||
} | |||
}, | |||
make_dataview: function() { | |||
// initialize the model | |||
@@ -621,20 +624,18 @@ frappe.views.QueryReport = Class.extend({ | |||
update_totals_row: function() { | |||
if(!this.report_doc.add_total_row) return; | |||
const data_length = this.dataView.getLength(); | |||
const last_index = data_length - 1; | |||
const number_fields = ['Currency', 'Float', 'Int']; | |||
const fields = this.columns | |||
.filter(col => number_fields.includes(col.fieldtype)) | |||
.map(col => col.field); | |||
// reset numeric fields | |||
let updated_totals = Object.assign({}, this.dataView.getItem(last_index)); | |||
let updated_totals = Object.assign({}, this.dataView.getItemById(this.total_row_id)); | |||
fields.map(field => { | |||
updated_totals[field] = 0.0; | |||
}); | |||
const data_length = this.dataView.getLength(); | |||
// loop all the rows except the last Total row | |||
for (let i = 0; i < data_length - 1; i++) { | |||
const item = this.dataView.getItem(i); | |||
@@ -648,7 +649,7 @@ frappe.views.QueryReport = Class.extend({ | |||
var me = frappe.container.page.query_report; | |||
if(me.report_doc.add_total_row) { | |||
// always show totals row | |||
if(Object.values(item).includes("'Total'")) return true; | |||
if(item.id === me.total_row_id) return true; | |||
} | |||
for (var columnId in me.columnFilters) { | |||
if (columnId !== undefined && me.columnFilters[columnId] !== "") { | |||
@@ -821,10 +822,10 @@ frappe.views.QueryReport = Class.extend({ | |||
me.data.sort(function (dataRow1, dataRow2) { | |||
// Totals row should always be last | |||
if(me.report_doc.add_total_row) { | |||
if(Object.values(dataRow1).includes("'Total'")) { | |||
if(dataRow1.id === me.total_row_id) { | |||
return 1; | |||
} | |||
if(Object.values(dataRow2).includes("'Total'")) { | |||
if(dataRow2.id === me.total_row_id) { | |||
return -1; | |||
} | |||
} | |||
@@ -81,8 +81,8 @@ def two_factor_is_enabled_for_(user): | |||
roles.append('All') | |||
query = """select name from `tabRole` where two_factor_auth=1 | |||
and name in ({0}) limit 1""".format(', '.join('\"{}\"'.format(i) for \ | |||
i in roles)) | |||
and name in ({0}) limit 1""".format(', '.join('\"{}\"'.format(i) for i in roles)) | |||
if len(frappe.db.sql(query)) > 0: | |||
return True | |||
@@ -149,7 +149,6 @@ def get_verification_obj(user, token, otp_secret): | |||
verification_obj = process_2fa_for_email(user, token, otp_secret, otp_issuer) | |||
return verification_obj | |||
def process_2fa_for_sms(user, token, otp_secret): | |||
'''Process sms method for 2fa.''' | |||
phone = frappe.db.get_value('User', user, ['phone', 'mobile_no'], as_dict=1) | |||
@@ -262,14 +261,22 @@ def send_token_via_sms(otpsecret, token=None, phone_no=None): | |||
return False | |||
hotp = pyotp.HOTP(otpsecret) | |||
args = {ss.message_parameter: 'Your verification code is {}'.format(hotp.at(int(token))), ss.sms_sender_name: otp_issuer} | |||
args = { | |||
ss.sms_sender_name: otp_issuer, | |||
ss.message_parameter: 'Your verification code is {}'.format(hotp.at(int(token))) | |||
} | |||
for d in ss.get("parameters"): | |||
args[d.parameter] = d.value | |||
args[ss.receiver_parameter] = phone_no | |||
sms_args = {'gateway_url': ss.sms_gateway_url, 'params': args} | |||
enqueue(method=send_request, queue='short', timeout=300, event=None, async=True, job_name=None, now=False, **sms_args) | |||
sms_args = { | |||
'params': args, | |||
'gateway_url': ss.sms_gateway_url | |||
} | |||
enqueue(method=send_request, queue='short', timeout=300, event=None, | |||
async=True, job_name=None, now=False, **sms_args) | |||
return True | |||
def send_token_via_email(user, token, otp_secret, otp_issuer, subject=None, message=None): | |||
@@ -295,8 +302,8 @@ def send_token_via_email(user, token, otp_secret, otp_issuer, subject=None, mess | |||
'retry':3 | |||
} | |||
enqueue(method=frappe.sendmail, queue='short', | |||
timeout=300, event=None, async=True, job_name=None, now=False, **email_args) | |||
enqueue(method=frappe.sendmail, queue='short', timeout=300, event=None, | |||
async=True, job_name=None, now=False, **email_args) | |||
return True | |||
def get_qr_svg_code(totp_uri): | |||
@@ -344,9 +351,11 @@ def create_barcode_folder(): | |||
def delete_qrimage(user, check_expiry=False): | |||
'''Delete Qrimage when user logs in.''' | |||
user_barcodes = frappe.get_all('File', {'attached_to_doctype': 'User', | |||
'attached_to_name': user, 'folder': 'Home/Barcodes'}) | |||
'attached_to_name': user, 'folder': 'Home/Barcodes'}) | |||
for barcode in user_barcodes: | |||
if check_expiry and not should_remove_barcode_image(barcode): continue | |||
if check_expiry and not should_remove_barcode_image(barcode): | |||
continue | |||
barcode = frappe.get_doc('File', barcode.name) | |||
frappe.delete_doc('File', barcode.name, ignore_permissions=True) | |||
@@ -354,6 +363,7 @@ def delete_all_barcodes_for_users(): | |||
'''Task to delete all barcodes for user.''' | |||
if not two_factor_is_enabled(): | |||
return | |||
users = frappe.get_all('User', {'enabled':1}) | |||
for user in users: | |||
delete_qrimage(user.name, check_expiry=True) | |||
@@ -368,5 +378,4 @@ def should_remove_barcode_image(barcode): | |||
return False | |||
def disable(): | |||
frappe.db.set_value('System Settings', None, 'enable_two_factor_auth', 0) | |||
frappe.db.set_value('System Settings', None, 'enable_two_factor_auth', 0) |