Merge branch 'master' into develop
This commit is contained in:
commit
17b20b22a3
27 changed files with 560 additions and 109 deletions
|
|
@ -23,7 +23,7 @@ if sys.version[0] == '2':
|
|||
reload(sys)
|
||||
sys.setdefaultencoding("utf-8")
|
||||
|
||||
__version__ = '11.1.4'
|
||||
__version__ = '11.1.5'
|
||||
__title__ = "Frappe Framework"
|
||||
|
||||
local = Local()
|
||||
|
|
@ -501,6 +501,7 @@ def read_only():
|
|||
retval = fn(*args, **get_newargs(fn, kwargs))
|
||||
|
||||
if local and hasattr(local, 'master_db'):
|
||||
local.db.close()
|
||||
local.db = local.master_db
|
||||
|
||||
return retval
|
||||
|
|
|
|||
|
|
@ -2,9 +2,84 @@
|
|||
# Copyright (c) 2017, Frappe Technologies and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
from frappe.core.doctype.user_permission.user_permission import add_user_permissions
|
||||
|
||||
#import frappe
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
class TestUserPermission(unittest.TestCase):
|
||||
pass
|
||||
def test_apply_to_all(self):
|
||||
''' Create User permission for User having access to all applicable Doctypes'''
|
||||
user = get_user()
|
||||
param = get_params(user, apply = 1)
|
||||
created = add_user_permissions(param)
|
||||
self.assertEquals(created, 1)
|
||||
|
||||
def test_for_applicable_on_update_from_apply_to_all(self):
|
||||
''' Update User Permission from all to some applicable Doctypes'''
|
||||
user = get_user()
|
||||
param = get_params(user, applicable = ["Chat Room", "Chat Message"])
|
||||
create = add_user_permissions(param)
|
||||
frappe.db.commit()
|
||||
|
||||
removed_apply_to_all = frappe.db.exists("User Permission", get_exists_param(user))
|
||||
created_applicable_first = frappe.db.exists("User Permission", get_exists_param(user, applicable = "Chat Room"))
|
||||
created_applicable_second = frappe.db.exists("User Permission", get_exists_param(user, applicable = "Chat Message"))
|
||||
|
||||
self.assertIsNone(removed_apply_to_all)
|
||||
self.assertIsNotNone(created_applicable_first)
|
||||
self.assertIsNotNone(created_applicable_second)
|
||||
self.assertEquals(create, 1)
|
||||
|
||||
def test_for_apply_to_all_on_update_from_applicable(self):
|
||||
''' Update User Permission from some to all applicable Doctypes'''
|
||||
user = get_user()
|
||||
param = get_params(user, apply = 1)
|
||||
created = add_user_permissions(param)
|
||||
created_apply_to_all = frappe.db.exists("User Permission", get_exists_param(user))
|
||||
removed_applicable_first = frappe.db.exists("User Permission", get_exists_param(user, applicable = "Chat Room"))
|
||||
removed_applicable_second = frappe.db.exists("User Permission", get_exists_param(user, applicable = "Chat Message"))
|
||||
|
||||
|
||||
self.assertIsNotNone(created_apply_to_all)
|
||||
self.assertIsNone(removed_applicable_first)
|
||||
self.assertIsNone(removed_applicable_second)
|
||||
self.assertEquals(created, 1)
|
||||
|
||||
def get_user():
|
||||
if frappe.db.exists('User', 'test_bulk_creation_update@example.com'):
|
||||
return frappe.get_doc('User', 'test_bulk_creation_update@example.com')
|
||||
else:
|
||||
user = frappe.new_doc('User')
|
||||
user.email = 'test_bulk_creation_update@example.com'
|
||||
user.first_name = 'Test_Bulk_Creation'
|
||||
user.add_roles("System Manager")
|
||||
return user
|
||||
|
||||
def get_params(user, apply = None , applicable = None):
|
||||
''' Return param to insert '''
|
||||
param = {
|
||||
"user": user.name,
|
||||
"doctype":"User",
|
||||
"docname":user.name
|
||||
}
|
||||
if apply:
|
||||
param.update({"apply_to_all_doctypes": 1})
|
||||
param.update({"applicable_doctypes": []})
|
||||
if applicable:
|
||||
param.update({"apply_to_all_doctypes": 0})
|
||||
param.update({"applicable_doctypes": applicable})
|
||||
return param
|
||||
|
||||
def get_exists_param(user, applicable = None):
|
||||
''' param to check existing Document '''
|
||||
param = {
|
||||
"user": user.name,
|
||||
"allow": "User",
|
||||
"for_value": user.name,
|
||||
}
|
||||
if applicable:
|
||||
param.update({"applicable_for": applicable})
|
||||
else:
|
||||
param.update({"apply_to_all_doctypes": 1})
|
||||
return param
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ def get_user_permissions(user=None):
|
|||
if not user:
|
||||
user = frappe.session.user
|
||||
|
||||
if user == "Administrator":
|
||||
return {}
|
||||
|
||||
cached_user_permissions = frappe.cache().hget("user_permissions", user)
|
||||
|
||||
if cached_user_permissions is not None:
|
||||
|
|
@ -111,12 +114,100 @@ def get_permitted_documents(doctype):
|
|||
return [d.get('doc') for d in get_user_permissions().get(doctype, []) \
|
||||
if d.get('doc')]
|
||||
|
||||
@frappe.whitelist()
|
||||
def check_applicable_doc_perm(user, doctype, docname):
|
||||
frappe.only_for('System Manager')
|
||||
applicable = []
|
||||
doc_exists = frappe.get_all('User Permission',
|
||||
fields=['name'],
|
||||
filters={"user": user,
|
||||
"allow": doctype,
|
||||
"for_value": docname,
|
||||
"apply_to_all_doctypes":1,
|
||||
}, limit=1)
|
||||
if doc_exists:
|
||||
applicable = get_linked_doctypes(doctype).keys()
|
||||
else:
|
||||
data = frappe.get_all('User Permission',
|
||||
fields=['applicable_for'],
|
||||
filters={"user": user,
|
||||
"allow": doctype,
|
||||
"for_value":docname,
|
||||
})
|
||||
for d in data:
|
||||
applicable.append(d.applicable_for)
|
||||
return applicable
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def clear_user_permissions(user, for_doctype):
|
||||
frappe.only_for('System Manager')
|
||||
|
||||
total = frappe.db.count('User Permission', filters = dict(user=user, allow=for_doctype))
|
||||
if total:
|
||||
frappe.db.sql('DELETE FROM `tabUser Permission` WHERE `user`=%s AND `allow`=%s', (user, for_doctype))
|
||||
frappe.clear_cache()
|
||||
return total
|
||||
|
||||
@frappe.whitelist()
|
||||
def add_user_permissions(data):
|
||||
''' Add and update the user permissions '''
|
||||
frappe.only_for('System Manager')
|
||||
if isinstance(data, frappe.string_types):
|
||||
data = json.loads(data)
|
||||
data = frappe._dict(data)
|
||||
|
||||
d = check_applicable_doc_perm(data.user, data.doctype, data.docname)
|
||||
exists = frappe.db.exists("User Permission", {"user": data.user, "allow": data.doctype, "for_value": data.docname, "apply_to_all_doctypes": 1})
|
||||
if data.apply_to_all_doctypes == 1 and not exists:
|
||||
remove_applicable(d, data.user, data.doctype, data.docname)
|
||||
insert_user_perm(data.user, data.doctype, data.docname, apply_to_all = 1)
|
||||
return 1
|
||||
else:
|
||||
remove_apply_to_all(data.user, data.doctype, data.docname)
|
||||
update_applicable(d, data.applicable_doctypes, data.user, data.doctype, data.docname)
|
||||
for applicable in data.applicable_doctypes :
|
||||
if applicable not in d:
|
||||
insert_user_perm(data.user, data.doctype, data.docname, applicable = applicable)
|
||||
elif exists:
|
||||
insert_user_perm(data.user, data.doctype, data.docname, applicable = applicable)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def insert_user_perm(user, doctype, docname, apply_to_all=None, applicable=None):
|
||||
user_perm = frappe.new_doc("User Permission")
|
||||
user_perm.user = user
|
||||
user_perm.allow = doctype
|
||||
user_perm.for_value = docname
|
||||
if applicable:
|
||||
user_perm.applicable_for = applicable
|
||||
user_perm.apply_to_all_doctypes = 0
|
||||
else:
|
||||
user_perm.apply_to_all_doctypes = 1
|
||||
user_perm.insert()
|
||||
|
||||
def remove_applicable(d, user, doctype, docname):
|
||||
for applicable_for in d:
|
||||
frappe.db.sql("""DELETE FROM `tabUser Permission`
|
||||
WHERE `user`=%s
|
||||
AND `applicable_for`=%s
|
||||
AND `allow`=%s
|
||||
AND `for_value`=%s
|
||||
""", (user, applicable_for, doctype, docname))
|
||||
|
||||
def remove_apply_to_all(user, doctype, docname):
|
||||
frappe.db.sql("""DELETE from `tabUser Permission`
|
||||
WHERE `user`=%s
|
||||
AND `apply_to_all_doctypes`=1
|
||||
AND `allow`=%s
|
||||
AND `for_value`=%s
|
||||
""",(user, doctype, docname))
|
||||
|
||||
def update_applicable(already_applied, to_apply, user, doctype, docname):
|
||||
for applied in already_applied:
|
||||
if applied not in to_apply:
|
||||
frappe.db.sql("""DELETE FROM `tabUser Permission`
|
||||
WHERE `user`=%s
|
||||
AND `applicable_for`=%s
|
||||
AND `allow`=%s
|
||||
AND `for_value`=%s
|
||||
""",(user, applied, doctype, docname))
|
||||
|
|
@ -1,22 +1,123 @@
|
|||
frappe.listview_settings['User Permission'] = {
|
||||
|
||||
onload: function(list_view) {
|
||||
list_view.page.add_menu_item(__("Clear User Permissions"), () => {
|
||||
var me = this;
|
||||
list_view.page.add_inner_button( __("Add / Update"), function() {
|
||||
let dialog =new frappe.ui.Dialog({
|
||||
title : __('Add User Permissions'),
|
||||
fields: [
|
||||
{
|
||||
fieldname: 'user',
|
||||
label: __('For User'),
|
||||
fieldtype: 'Link',
|
||||
options: 'User',
|
||||
reqd: 1,
|
||||
onchange: function() {
|
||||
dialog.fields_dict.doctype.set_input(undefined);
|
||||
dialog.fields_dict.docname.set_input(undefined);
|
||||
dialog.set_df_property("docname", "hidden", 1);
|
||||
dialog.set_df_property("apply_to_all_doctypes", "hidden", 1);
|
||||
dialog.set_df_property("applicable_doctypes", "hidden", 1);
|
||||
}
|
||||
},
|
||||
{
|
||||
fieldname: 'doctype',
|
||||
label: __('Document Type'),
|
||||
fieldtype: 'Link',
|
||||
options: 'DocType',
|
||||
reqd: 1,
|
||||
onchange: function() {
|
||||
me.on_doctype_change(dialog);
|
||||
}
|
||||
},
|
||||
{
|
||||
fieldname: 'docname',
|
||||
label: __('Document Name'),
|
||||
fieldtype: 'Dynamic Link',
|
||||
options: 'doctype',
|
||||
hidden: 1,
|
||||
onchange: function() {
|
||||
let field = dialog.fields_dict["docname"];
|
||||
if(field.value != field.last_value) {
|
||||
if(dialog.fields_dict.doctype.value && dialog.fields_dict.docname.value && dialog.fields_dict.user.value){
|
||||
me.get_applicable_doctype(dialog).then(applicable => {
|
||||
me.get_multi_select_options(dialog, applicable).then(options => {
|
||||
me.applicable_options = options;
|
||||
me.on_docname_change(dialog, options, applicable);
|
||||
if(options.length > 5){
|
||||
dialog.fields_dict.applicable_doctypes.setup_select_all();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
fieldname: 'apply_to_all_doctypes',
|
||||
label: __('Apply to all Documents Types'),
|
||||
fieldtype: 'Check',
|
||||
checked: 1,
|
||||
hidden: 1,
|
||||
onchange: function() {
|
||||
if(dialog.fields_dict.doctype.value && dialog.fields_dict.docname.value && dialog.fields_dict.user.value){
|
||||
me.on_apply_to_all_doctypes_change(dialog, me.applicable_options);
|
||||
if(me.applicable_options.length > 5){
|
||||
dialog.fields_dict.applicable_doctypes.setup_select_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: __("Applicable Document Types"),
|
||||
fieldname: "applicable_doctypes",
|
||||
fieldtype: "MultiCheck",
|
||||
options: [],
|
||||
columns: 2,
|
||||
hidden: 1
|
||||
},
|
||||
],
|
||||
primary_action: (data) => {
|
||||
data = me.validate(dialog, data);
|
||||
frappe.call({
|
||||
async: false,
|
||||
method: "frappe.core.doctype.user_permission.user_permission.add_user_permissions",
|
||||
args: {
|
||||
data : data
|
||||
},
|
||||
callback: function(r) {
|
||||
if(r.message === 1) {
|
||||
frappe.show_alert({message:__("User Permissions created sucessfully"), indicator:'blue'});
|
||||
} else {
|
||||
frappe.show_alert({message:__("Nothing to update"), indicator:'red'});
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
dialog.hide();
|
||||
list_view.refresh();
|
||||
},
|
||||
primary_action_label: __('Submit')
|
||||
});
|
||||
dialog.show();
|
||||
});
|
||||
list_view.page.add_inner_button( __("Bulk Delete"), function() {
|
||||
const dialog = new frappe.ui.Dialog({
|
||||
title: __('Clear User Permissions'),
|
||||
fields: [
|
||||
{
|
||||
'fieldname': 'user',
|
||||
'label': __('For User'),
|
||||
'fieldtype': 'Link',
|
||||
'options': 'User',
|
||||
'reqd': 1
|
||||
fieldname: 'user',
|
||||
label: __('For User'),
|
||||
fieldtype: 'Link',
|
||||
options: 'User',
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
'fieldname': 'for_doctype',
|
||||
'label': __('For Document Type'),
|
||||
'fieldtype': 'Link',
|
||||
'options': 'DocType',
|
||||
'reqd': 1
|
||||
fieldname: 'for_doctype',
|
||||
label: __('For Document Type'),
|
||||
fieldtype: 'Link',
|
||||
options: 'DocType',
|
||||
reqd: 1
|
||||
},
|
||||
],
|
||||
primary_action: (data) => {
|
||||
|
|
@ -31,6 +132,8 @@ frappe.listview_settings['User Permission'] = {
|
|||
let message = '';
|
||||
if (data === 0) {
|
||||
message = __('No records deleted');
|
||||
} else if(data === 1) {
|
||||
message = __('{0} record deleted', [data]);
|
||||
} else {
|
||||
message = __('{0} records deleted', [data]);
|
||||
}
|
||||
|
|
@ -43,10 +146,95 @@ frappe.listview_settings['User Permission'] = {
|
|||
});
|
||||
|
||||
},
|
||||
primary_action_label: __('Clear')
|
||||
primary_action_label: __('Delete')
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
});
|
||||
},
|
||||
|
||||
validate: function(dialog, data) {
|
||||
if(dialog.fields_dict.applicable_doctypes.get_unchecked_options().length == 0) {
|
||||
data.apply_to_all_doctypes = 1;
|
||||
data.applicable_doctypes = [];
|
||||
return data;
|
||||
}
|
||||
if(data.apply_to_all_doctypes == 0 && !("applicable_doctypes" in data)) {
|
||||
frappe.throw("Please select applicable Doctypes");
|
||||
}
|
||||
return data;
|
||||
},
|
||||
|
||||
get_applicable_doctype: function(dialog) {
|
||||
return new Promise(resolve => {
|
||||
frappe.call({
|
||||
method: 'frappe.core.doctype.user_permission.user_permission.check_applicable_doc_perm',
|
||||
async: false,
|
||||
args:{
|
||||
user: dialog.fields_dict.user.value,
|
||||
doctype: dialog.fields_dict.doctype.value,
|
||||
docname: dialog.fields_dict.docname.value
|
||||
}
|
||||
}).then(r => {
|
||||
resolve(r.message);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
get_multi_select_options: function(dialog, applicable){
|
||||
return new Promise(resolve => {
|
||||
frappe.call({
|
||||
method: 'frappe.desk.form.linked_with.get_linked_doctypes',
|
||||
async: false,
|
||||
args:{
|
||||
user: dialog.fields_dict.user.value,
|
||||
doctype: dialog.fields_dict.doctype.value,
|
||||
docname: dialog.fields_dict.docname.value
|
||||
}
|
||||
}).then(r => {
|
||||
var options = [];
|
||||
for(var d in r.message){
|
||||
var checked = ($.inArray(d, applicable) != -1) ? 1 : 0;
|
||||
options.push({ "label":d, "value": d , "checked": checked});
|
||||
}
|
||||
resolve(options);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
on_doctype_change: function(dialog) {
|
||||
dialog.set_df_property("docname", "hidden", 0);
|
||||
dialog.set_df_property("docname", "reqd", 1);
|
||||
dialog.set_df_property("apply_to_all_doctypes", "hidden", 0);
|
||||
dialog.set_value("apply_to_all_doctypes","checked",1);
|
||||
},
|
||||
|
||||
on_docname_change: function(dialog, options, applicable) {
|
||||
if(applicable.length != 0 ) {
|
||||
dialog.set_primary_action("Update");
|
||||
dialog.set_title("Update User Permissions");
|
||||
dialog.set_df_property("applicable_doctypes", "options", options);
|
||||
if(dialog.fields_dict.applicable_doctypes.get_checked_options().length == options.length) {
|
||||
dialog.set_df_property("applicable_doctypes", "hidden", 1);
|
||||
} else {
|
||||
dialog.set_df_property("applicable_doctypes", "hidden", 0);
|
||||
dialog.set_df_property("apply_to_all_doctypes", "checked", 0);
|
||||
}
|
||||
} else {
|
||||
dialog.set_primary_action("Submit");
|
||||
dialog.set_title("Add User Permissions");
|
||||
dialog.set_df_property("applicable_doctypes", "options", options);
|
||||
dialog.set_df_property("applicable_doctypes", "hidden", 1);
|
||||
}
|
||||
},
|
||||
|
||||
on_apply_to_all_doctypes_change: function(dialog, options) {
|
||||
if(dialog.fields_dict.apply_to_all_doctypes.get_value() == 0) {
|
||||
dialog.set_df_property("applicable_doctypes", "hidden", 0);
|
||||
dialog.set_df_property("applicable_doctypes", "options", options);
|
||||
} else {
|
||||
dialog.set_df_property("applicable_doctypes", "options", options);
|
||||
dialog.set_df_property("applicable_doctypes", "hidden", 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -251,6 +251,11 @@ def get_open_count(doctype, name, items=[]):
|
|||
:param transactions: List of transactions (json/dict)
|
||||
:param filters: optional filters (json/list)'''
|
||||
|
||||
if frappe.flags.in_migrate or frappe.flags.in_install:
|
||||
return {
|
||||
'count': []
|
||||
}
|
||||
|
||||
frappe.has_permission(doc=frappe.get_doc(doctype, name), throw=True)
|
||||
|
||||
meta = frappe.get_meta(doctype)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,13 @@ import frappe
|
|||
from frappe.model.document import Document
|
||||
|
||||
class EmailGroupMember(Document):
|
||||
pass
|
||||
def after_delete(self):
|
||||
email_group = frappe.get_doc('Email Group', self.email_group)
|
||||
email_group.update_total_subscribers()
|
||||
|
||||
def after_insert(self):
|
||||
email_group = frappe.get_doc('Email Group', self.email_group)
|
||||
email_group.update_total_subscribers()
|
||||
|
||||
def after_doctype_insert():
|
||||
frappe.db.add_unique("Email Group Member", ("email_group", "email"))
|
||||
frappe.db.add_unique("Email Group Member", ("email_group", "email"))
|
||||
|
|
|
|||
|
|
@ -216,8 +216,15 @@ def get_context(context):
|
|||
please enable Allow Print For {0} in Print Settings""".format(status)),
|
||||
title=_("Error in Notification"))
|
||||
else:
|
||||
return [{"print_format_attachment":1, "doctype":doc.doctype, "name": doc.name,
|
||||
"print_format":self.print_format, "print_letterhead": print_settings.with_letterhead}]
|
||||
return [{
|
||||
"print_format_attachment": 1,
|
||||
"doctype": doc.doctype,
|
||||
"name": doc.name,
|
||||
"print_format": self.print_format,
|
||||
"print_letterhead": print_settings.with_letterhead,
|
||||
"lang": frappe.db.get_value('Print Format', self.print_format, 'default_print_language')
|
||||
if self.print_format else 'en'
|
||||
}]
|
||||
|
||||
|
||||
def get_template(self):
|
||||
|
|
|
|||
|
|
@ -174,7 +174,8 @@ def get_email_queue(recipients, sender, subject, **kwargs):
|
|||
if att.get('fid'):
|
||||
_attachments.append(att)
|
||||
elif att.get("print_format_attachment") == 1:
|
||||
att['lang'] = frappe.local.lang
|
||||
if not att.get('lang', None):
|
||||
att['lang'] = frappe.local.lang
|
||||
att['print_letterhead'] = kwargs.get('print_letterhead')
|
||||
_attachments.append(att)
|
||||
e.attachments = json.dumps(_attachments)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import frappe.defaults
|
|||
from frappe.model import data_fieldtypes
|
||||
from frappe.utils import nowdate, nowtime, now_datetime
|
||||
from frappe.core.doctype.user_permission.user_permission import get_user_permissions
|
||||
from frappe.permissions import get_allowed_docs_for_doctype
|
||||
|
||||
def get_new_doc(doctype, parent_doc = None, parentfield = None, as_dict=False):
|
||||
if doctype not in frappe.local.new_doc_templates:
|
||||
|
|
@ -53,36 +54,39 @@ def set_user_and_static_default_values(doc):
|
|||
|
||||
for df in doc.meta.get("fields"):
|
||||
if df.fieldtype in data_fieldtypes:
|
||||
user_default_value = get_user_default_value(df, defaults, user_permissions)
|
||||
# user permissions for link options
|
||||
doctype_user_permissions = user_permissions.get(df.options, [])
|
||||
# Allowed records for the reference doctype (link field)
|
||||
allowed_records = get_allowed_docs_for_doctype(doctype_user_permissions, df.parent)
|
||||
|
||||
user_default_value = get_user_default_value(df, defaults, doctype_user_permissions, allowed_records)
|
||||
|
||||
if user_default_value is not None:
|
||||
doc.set(df.fieldname, user_default_value)
|
||||
|
||||
else:
|
||||
if df.fieldname != doc.meta.title_field:
|
||||
static_default_value = get_static_default_value(df, user_permissions)
|
||||
static_default_value = get_static_default_value(df, doctype_user_permissions, allowed_records)
|
||||
if static_default_value is not None:
|
||||
doc.set(df.fieldname, static_default_value)
|
||||
|
||||
def get_user_default_value(df, defaults, user_permissions):
|
||||
def get_user_default_value(df, defaults, doctype_user_permissions, allowed_records):
|
||||
# don't set defaults for "User" link field using User Permissions!
|
||||
if df.fieldtype == "Link" and df.options != "User":
|
||||
# 1 - look in user permissions only for document_type==Setup
|
||||
# We don't want to include permissions of transactions to be used for defaults.
|
||||
if (frappe.get_meta(df.options).document_type=="Setup"
|
||||
and user_permissions_exist(df, user_permissions)
|
||||
and len(user_permissions.get(df.options))==1):
|
||||
return user_permissions.get(df.options)[0].get("doc")
|
||||
if frappe.get_meta(df.options).document_type=="Setup" and len(allowed_records)==1:
|
||||
return allowed_records[0]
|
||||
|
||||
# 2 - Look in user defaults
|
||||
user_default = defaults.get(df.fieldname)
|
||||
is_allowed_user_default = user_default and (not user_permissions_exist(df, user_permissions)
|
||||
or (user_default in user_permissions.get(df.options, [])))
|
||||
is_allowed_user_default = user_default and (not user_permissions_exist(df, doctype_user_permissions)
|
||||
or user_default in allowed_records)
|
||||
|
||||
# is this user default also allowed as per user permissions?
|
||||
if is_allowed_user_default:
|
||||
return user_default
|
||||
|
||||
def get_static_default_value(df, user_permissions):
|
||||
def get_static_default_value(df, doctype_user_permissions, allowed_records):
|
||||
# 3 - look in default of docfield
|
||||
if df.get("default"):
|
||||
if df.default == "__user":
|
||||
|
|
@ -93,8 +97,8 @@ def get_static_default_value(df, user_permissions):
|
|||
|
||||
elif not df.default.startswith(":"):
|
||||
# a simple default value
|
||||
is_allowed_default_value = (not user_permissions_exist(df, user_permissions)
|
||||
or (df.default in user_permissions.get(df.options, [])))
|
||||
is_allowed_default_value = (not user_permissions_exist(df, doctype_user_permissions)
|
||||
or (df.default in allowed_records))
|
||||
|
||||
if df.fieldtype!="Link" or df.options=="User" or is_allowed_default_value:
|
||||
return df.default
|
||||
|
|
@ -126,10 +130,10 @@ def set_dynamic_default_values(doc, parent_doc, parentfield):
|
|||
if parentfield:
|
||||
doc["parentfield"] = parentfield
|
||||
|
||||
def user_permissions_exist(df, user_permissions):
|
||||
def user_permissions_exist(df, doctype_user_permissions):
|
||||
return (df.fieldtype=="Link"
|
||||
and not getattr(df, "ignore_user_permissions", False)
|
||||
and df.options in (user_permissions or []))
|
||||
and doctype_user_permissions)
|
||||
|
||||
def get_default_based_on_another_field(df, user_permissions, parent_doc):
|
||||
# default value based on another document
|
||||
|
|
@ -139,7 +143,7 @@ def get_default_based_on_another_field(df, user_permissions, parent_doc):
|
|||
ref_fieldname = ref_doctype.lower().replace(" ", "_")
|
||||
reference_name = parent_doc.get(ref_fieldname) if parent_doc else frappe.db.get_default(ref_fieldname)
|
||||
default_value = frappe.db.get_value(ref_doctype, reference_name, df.fieldname)
|
||||
is_allowed_default_value = (not user_permissions_exist(df, user_permissions) or
|
||||
is_allowed_default_value = (not user_permissions_exist(df, user_permissions.get(df.options)) or
|
||||
(default_value in get_allowed_docs_for_doctype(user_permissions[df.options], df.parent)))
|
||||
|
||||
# is this allowed as per user permissions
|
||||
|
|
|
|||
|
|
@ -165,10 +165,10 @@ class Document(BaseDocument):
|
|||
self.latest = frappe.get_doc(self.doctype, self.name)
|
||||
return self.latest
|
||||
|
||||
def check_permission(self, permtype='read', permlabel=None):
|
||||
def check_permission(self, permtype='read', permlevel=None):
|
||||
"""Raise `frappe.PermissionError` if not permitted"""
|
||||
if not self.has_permission(permtype):
|
||||
self.raise_no_permission_to(permlabel or permtype)
|
||||
self.raise_no_permission_to(permlevel or permtype)
|
||||
|
||||
def has_permission(self, permtype="read", verbose=False):
|
||||
"""Call `frappe.has_permission` if `self.flags.ignore_permissions`
|
||||
|
|
@ -999,7 +999,7 @@ class Document(BaseDocument):
|
|||
frappe.db.commit()
|
||||
|
||||
def db_get(self, fieldname):
|
||||
'''get database vale for this fieldname'''
|
||||
'''get database value for this fieldname'''
|
||||
return frappe.db.get_value(self.doctype, self.name, fieldname)
|
||||
|
||||
def check_no_back_links_exist(self):
|
||||
|
|
|
|||
|
|
@ -24,8 +24,10 @@ def print_has_permission_check_logs(func):
|
|||
def inner(*args, **kwargs):
|
||||
frappe.flags['has_permission_check_logs'] = []
|
||||
result = func(*args, **kwargs)
|
||||
self_perm_check = True if not kwargs.get('user') else kwargs.get('user') == frappe.session.user
|
||||
# print only if access denied
|
||||
if not result:
|
||||
# and if user is checking his own permission
|
||||
if not result and self_perm_check:
|
||||
msgprint(('<br>').join(frappe.flags['has_permission_check_logs']))
|
||||
frappe.flags.pop('has_permission_check_logs', None)
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -232,6 +232,16 @@ frappe.dom = {
|
|||
frappe.ui.scroll(section.parent().parent());
|
||||
}
|
||||
}, 200);
|
||||
},
|
||||
pixel_to_inches(pixels) {
|
||||
const div = $('<div id="dpi" style="height: 1in; width: 1in; left: 100%; position: fixed; top: 100%;"></div>');
|
||||
div.appendTo(document.body);
|
||||
|
||||
const dpi_x = document.getElementById('dpi').offsetWidth;
|
||||
const inches = pixels / dpi_x;
|
||||
div.remove();
|
||||
|
||||
return inches;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -86,7 +86,9 @@ frappe.ui.form.ControlMultiCheck = frappe.ui.form.Control.extend({
|
|||
this.selected_options.push(option_name);
|
||||
} else {
|
||||
let index = this.selected_options.indexOf(option_name);
|
||||
this.selected_options.splice(index, 1);
|
||||
if(index > -1) {
|
||||
this.selected_options.splice(index, 1);
|
||||
}
|
||||
}
|
||||
this.df.on_change && this.df.on_change();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -136,22 +136,40 @@ frappe.ui.form.PrintPreview = Class.extend({
|
|||
preview: function () {
|
||||
var me = this;
|
||||
this.get_print_html(function (out) {
|
||||
me.wrapper.find(".print-format").html(out.html);
|
||||
const $print_format = me.wrapper.find(".print-format");
|
||||
$print_format.html(out.html);
|
||||
me.show_footer();
|
||||
me.set_style(out.style);
|
||||
|
||||
const print_height = $print_format.get(0).offsetHeight;
|
||||
const $message = me.wrapper.find(".page-break-message");
|
||||
|
||||
const print_height_inches = frappe.dom.pixel_to_inches(print_height);
|
||||
// if contents are large enough, indicate that it will get printed on multiple pages
|
||||
// Maximum height for an A4 document is 11.69 inches
|
||||
if (print_height_inches > 11.69) {
|
||||
$message.text(__('This may get printed on multiple pages'));
|
||||
} else {
|
||||
$message.text('');
|
||||
}
|
||||
});
|
||||
},
|
||||
show_footer: function() {
|
||||
// footer is hidden by default as reqd by pdf generation
|
||||
// simple hack to show it in print preview
|
||||
this.wrapper.find('.print-format').css({
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
});
|
||||
this.wrapper.find('.page-break').css({
|
||||
'display': 'flex',
|
||||
'flex-direction': 'column'
|
||||
'flex-direction': 'column',
|
||||
'flex': '1'
|
||||
});
|
||||
this.wrapper.find('#footer-html').attr('style', `
|
||||
display: block !important;
|
||||
order: 1;
|
||||
margin-top: 20px;
|
||||
margin-top: auto;
|
||||
`);
|
||||
},
|
||||
printit: function () {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
<div class="print-preview-wrapper">
|
||||
<div class="print-preview">
|
||||
<div class="print-format"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-break-message text-muted text-center text-medium margin-top"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -151,6 +151,13 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
);
|
||||
|
||||
fields.forEach(f => this._add_field(f));
|
||||
|
||||
this.fields.forEach(f => {
|
||||
const df = frappe.meta.get_docfield(f[1], f[0]);
|
||||
if (df && df.fieldtype === 'Currency' && df.options && !df.options.includes(':')) {
|
||||
this._add_field(df.options);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
patch_refresh_and_load_lib() {
|
||||
|
|
@ -611,7 +618,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
|
|||
args: {
|
||||
doctype: this.doctype,
|
||||
filters: this.get_filters_for_args(),
|
||||
fields: [`count(distinct ${frappe.model.get_full_column_name('name', this.doctype)}) as total_count`],
|
||||
fields: [`count(${frappe.model.get_full_column_name('name', this.doctype)}) as total_count`],
|
||||
}
|
||||
}).then(r => {
|
||||
this.total_count = r.message.values[0][0] || current_count;
|
||||
|
|
|
|||
|
|
@ -87,10 +87,8 @@ $.extend(frappe.model, {
|
|||
var doctype = doc.doctype;
|
||||
var docfields = frappe.meta.docfield_list[doctype] || [];
|
||||
var updated = [];
|
||||
|
||||
for(var fid=0;fid<docfields.length;fid++) {
|
||||
var f = docfields[fid];
|
||||
|
||||
if(!in_list(frappe.model.no_value_type, f.fieldtype) && doc[f.fieldname]==null) {
|
||||
var v = frappe.model.get_default_value(f, doc, parent_doc);
|
||||
if(v) {
|
||||
|
|
@ -126,25 +124,23 @@ $.extend(frappe.model, {
|
|||
get_default_value: function(df, doc, parent_doc) {
|
||||
var user_default = "";
|
||||
var user_permissions = frappe.defaults.get_user_permissions();
|
||||
let allowed_records = [];
|
||||
if(user_permissions) {
|
||||
allowed_records = frappe.perm.get_allowed_docs_for_doctype(user_permissions[df.options], doc.doctype);
|
||||
}
|
||||
var meta = frappe.get_meta(doc.doctype);
|
||||
var has_user_permissions = (df.fieldtype==="Link"
|
||||
&& user_permissions
|
||||
&& !$.isEmptyObject(user_permissions)
|
||||
&& df.ignore_user_permissions != 1
|
||||
&& user_permissions[df.options]);
|
||||
|
||||
function is_doc_allowed(doctype, docname) {
|
||||
return user_permissions[doctype].some(perm => {
|
||||
return perm.doc === docname && (perm.applicable_for === doc.doctype || !perm.applicable_for);
|
||||
});
|
||||
}
|
||||
&& allowed_records.length);
|
||||
|
||||
// don't set defaults for "User" link field using User Permissions!
|
||||
if (df.fieldtype==="Link" && df.options!=="User") {
|
||||
// 1 - look in user permissions for document_type=="Setup".
|
||||
// We don't want to include permissions of transactions to be used for defaults.
|
||||
if (df.linked_document_type==="Setup"
|
||||
&& has_user_permissions && user_permissions[df.options].length===1) {
|
||||
return user_permissions[df.options][0].doc;
|
||||
&& has_user_permissions && allowed_records.length===1) {
|
||||
return allowed_records[0];
|
||||
}
|
||||
|
||||
if(!df.ignore_user_permissions) {
|
||||
|
|
@ -165,7 +161,7 @@ $.extend(frappe.model, {
|
|||
}
|
||||
|
||||
var is_allowed_user_default = user_default &&
|
||||
(!has_user_permissions || is_doc_allowed(df.options, user_default));
|
||||
(!has_user_permissions || allowed_records.includes(user_default));
|
||||
|
||||
// is this user default also allowed as per user permissions?
|
||||
if (is_allowed_user_default) {
|
||||
|
|
@ -190,7 +186,7 @@ $.extend(frappe.model, {
|
|||
|
||||
} else if (df["default"][0]===":") {
|
||||
var boot_doc = frappe.model.get_default_from_boot_docs(df, doc, parent_doc);
|
||||
var is_allowed_boot_doc = !has_user_permissions || is_doc_allowed(df.options, boot_doc);
|
||||
var is_allowed_boot_doc = !has_user_permissions || allowed_records.includes(boot_doc);
|
||||
|
||||
if (is_allowed_boot_doc) {
|
||||
return boot_doc;
|
||||
|
|
@ -201,7 +197,7 @@ $.extend(frappe.model, {
|
|||
}
|
||||
|
||||
// is this default value is also allowed as per user permissions?
|
||||
var is_allowed_default = !has_user_permissions || is_doc_allowed(df.options, df.default);
|
||||
var is_allowed_default = !has_user_permissions || allowed_records.includes(df.default);
|
||||
if (df.fieldtype!=="Link" || df.options==="User" || is_allowed_default) {
|
||||
return df["default"];
|
||||
}
|
||||
|
|
@ -342,5 +338,3 @@ frappe.new_doc = function (doctype, opts, init_callback) {
|
|||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -151,18 +151,10 @@ $.extend(frappe.perm, {
|
|||
let rules = {};
|
||||
let fields_to_check = frappe.meta.get_fields_to_check_permissions(doctype);
|
||||
$.each(fields_to_check, (i, df) => {
|
||||
const user_permissions_for_doctype = user_permissions[df.options];
|
||||
// check if there are any user permission applicable for parent doctype
|
||||
const has_user_permission = user_permissions_for_doctype ? user_permissions_for_doctype
|
||||
.some(perm => !perm.applicable_for || perm.applicable_for === doctype) : false;
|
||||
|
||||
if (has_user_permission) {
|
||||
rules[df.label] = [];
|
||||
user_permissions_for_doctype.map(permission => {
|
||||
if (!permission.applicable_for || permission.applicable_for === doctype) {
|
||||
rules[df.label].push(permission.doc);
|
||||
}
|
||||
});
|
||||
const user_permissions_for_doctype = user_permissions[df.options] || [];
|
||||
const allowed_records = frappe.perm.get_allowed_docs_for_doctype(user_permissions_for_doctype, doctype);
|
||||
if (allowed_records.length) {
|
||||
rules[df.label] = allowed_records;
|
||||
}
|
||||
});
|
||||
if (!$.isEmptyObject(rules)) {
|
||||
|
|
@ -260,4 +252,10 @@ $.extend(frappe.perm, {
|
|||
|
||||
return status === "None" ? false : true;
|
||||
},
|
||||
|
||||
get_allowed_docs_for_doctype: (user_permissions, doctype) => {
|
||||
return (user_permissions || []).filter(perm => {
|
||||
return (perm.applicable_for === doctype || !perm.applicable_for);
|
||||
}).map(perm => perm.doc);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -117,10 +117,14 @@ frappe.ui.Filter = class {
|
|||
}
|
||||
|
||||
update_filter_tag() {
|
||||
return this._filter_value_set.then(() => {
|
||||
!this.$filter_tag ? this.make_tag() : this.set_filter_button_text();
|
||||
this.filter_edit_area.hide();
|
||||
});
|
||||
if (this._filter_value_set) {
|
||||
return this._filter_value_set.then(() => {
|
||||
!this.$filter_tag ? this.make_tag() : this.set_filter_button_text();
|
||||
this.filter_edit_area.hide();
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
remove() {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ frappe.provide("frappe.views");
|
|||
cards: cards,
|
||||
columns: columns,
|
||||
cur_list: opts.cur_list,
|
||||
empty_state: false
|
||||
empty_state: false,
|
||||
wrapper: opts.wrapper
|
||||
});
|
||||
},
|
||||
update_cards: function(updater, cards) {
|
||||
|
|
@ -97,21 +98,33 @@ frappe.provide("frappe.views");
|
|||
var doc_fields = {};
|
||||
doc_fields[field.fieldname] = card_title;
|
||||
doc_fields[this.board.field_name] = column_title;
|
||||
this.board.filters_array.forEach(function(f) {
|
||||
this.cur_list.filter_area.get().forEach(function(f) {
|
||||
if (f[2] !== "=") return;
|
||||
doc_fields[f[1]] = f[3];
|
||||
});
|
||||
|
||||
$.extend(doc, doc_fields);
|
||||
|
||||
// add the card directly
|
||||
// for better ux
|
||||
const card = prepare_card(doc, state);
|
||||
card._disable_click = true;
|
||||
const cards = [...state.cards, card];
|
||||
// remember the name which we will override later
|
||||
const old_name = doc.name;
|
||||
updater.set({ cards });
|
||||
|
||||
if (field && !quick_entry) {
|
||||
return insert_doc(doc)
|
||||
.then(function(r) {
|
||||
var updated_doc = r.message;
|
||||
var card = prepare_card(doc, state, updated_doc);
|
||||
var cards = state.cards.slice();
|
||||
cards.push(card);
|
||||
updater.set({ cards: cards });
|
||||
// update the card in place with the updated doc
|
||||
const updated_doc = r.message;
|
||||
const index = state.cards.findIndex(card => card.name === old_name);
|
||||
const card = prepare_card(updated_doc, state);
|
||||
const new_cards = state.cards.slice();
|
||||
new_cards[index] = card;
|
||||
updater.set({ cards: new_cards });
|
||||
fluxify.doAction('update_order');
|
||||
});
|
||||
} else {
|
||||
frappe.new_doc(this.doctype, doc);
|
||||
|
|
@ -142,11 +155,22 @@ frappe.provide("frappe.views");
|
|||
fluxify.doAction('update_card', updated_card);
|
||||
});
|
||||
},
|
||||
update_order: function(updater, order) {
|
||||
update_order: function(updater) {
|
||||
// cache original order
|
||||
const _cards = this.cards.slice();
|
||||
const _columns = this.columns.slice();
|
||||
|
||||
const order = {};
|
||||
this.wrapper.find('.kanban-column[data-column-value]')
|
||||
.each(function() {
|
||||
var col_name = $(this).data().columnValue;
|
||||
order[col_name] = [];
|
||||
$(this).find('.kanban-card-wrapper').each(function() {
|
||||
var card_name = $(this).data().name;
|
||||
order[col_name].push(card_name);
|
||||
});
|
||||
});
|
||||
|
||||
frappe.call({
|
||||
method: method_prefix + "update_order",
|
||||
args: {
|
||||
|
|
@ -431,17 +455,7 @@ frappe.provide("frappe.views");
|
|||
wrapper.find('.kanban-card.add-card').fadeIn(100);
|
||||
wrapper.find('.kanban-cards').height('auto');
|
||||
// update order
|
||||
var order = {};
|
||||
wrapper.find('.kanban-column[data-column-value]')
|
||||
.each(function() {
|
||||
var col_name = $(this).data().columnValue;
|
||||
order[col_name] = [];
|
||||
$(this).find('.kanban-card-wrapper').each(function() {
|
||||
var card_name = $(this).data().name;
|
||||
order[col_name].push(card_name);
|
||||
});
|
||||
});
|
||||
fluxify.doAction('update_order', order);
|
||||
fluxify.doAction('update_order');
|
||||
},
|
||||
onAdd: function() {
|
||||
},
|
||||
|
|
@ -470,11 +484,11 @@ frappe.provide("frappe.views");
|
|||
// not already working -- double entry
|
||||
e.preventDefault();
|
||||
var card_title = $textarea.val();
|
||||
$new_card_area.hide();
|
||||
$textarea.val('');
|
||||
fluxify.doAction('add_card', card_title, column.title)
|
||||
.then(() => {
|
||||
$btn_add.show();
|
||||
$new_card_area.hide();
|
||||
$textarea.val('');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -531,7 +545,8 @@ frappe.provide("frappe.views");
|
|||
function make_dom() {
|
||||
var opts = {
|
||||
name: card.name,
|
||||
title: remove_img_tags(card.title)
|
||||
title: remove_img_tags(card.title),
|
||||
disable_click: card._disable_click ? 'disable-click' : ''
|
||||
};
|
||||
self.$card = $(frappe.render_template('kanban_card', opts))
|
||||
.appendTo(wrapper);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<div class="kanban-card-wrapper" data-name="{{name}}">
|
||||
<div class="kanban-card-wrapper {{ disable_click }}" data-name="{{name}}">
|
||||
<div class="kanban-card content">
|
||||
<div class="kanban-card-title">
|
||||
{{ title }}
|
||||
|
|
|
|||
|
|
@ -639,7 +639,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
|
|||
}
|
||||
|
||||
const format_cell = (value, row, column, data) => {
|
||||
return frappe.format(value == null ? '' : value, column,
|
||||
return frappe.format(value, column,
|
||||
{for_print: false, always_show_decimals: true}, data);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -308,3 +308,7 @@ a.no-decoration& {
|
|||
.text-small {
|
||||
font-size: @text-small;
|
||||
}
|
||||
|
||||
.disable-click {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,12 +82,22 @@ class TestPermissions(unittest.TestCase):
|
|||
self.assertFalse("-test-blog-post" in names)
|
||||
|
||||
def test_default_values(self):
|
||||
doc = frappe.new_doc("Blog Post")
|
||||
self.assertFalse(doc.get("blog_category"))
|
||||
|
||||
# Fetch default based on single user permission
|
||||
add_user_permission("Blog Category", "_Test Blog Category 1", "test2@example.com")
|
||||
|
||||
frappe.set_user("test2@example.com")
|
||||
doc = frappe.new_doc("Blog Post")
|
||||
self.assertEqual(doc.get("blog_category"), "_Test Blog Category 1")
|
||||
|
||||
# Don't fetch default if user permissions is more than 1
|
||||
add_user_permission("Blog Category", "_Test Blog Category", "test2@example.com", ignore_permissions=True)
|
||||
frappe.clear_cache()
|
||||
doc = frappe.new_doc("Blog Post")
|
||||
self.assertFalse(doc.get("blog_category"))
|
||||
|
||||
def test_user_link_match_doc(self):
|
||||
blogger = frappe.get_doc("Blogger", "_Test Blogger 1")
|
||||
blogger.user = "test2@example.com"
|
||||
|
|
|
|||
|
|
@ -90,13 +90,13 @@ def download_pdf(doctype, name, format=None, doc=None, no_letterhead=0):
|
|||
html = frappe.get_print(doctype, name, format, doc=doc, no_letterhead=no_letterhead)
|
||||
frappe.local.response.filename = "{name}.pdf".format(name=name.replace(" ", "-").replace("/", "-"))
|
||||
frappe.local.response.filecontent = get_pdf(html)
|
||||
frappe.local.response.type = "download"
|
||||
frappe.local.response.type = "pdf"
|
||||
|
||||
@frappe.whitelist()
|
||||
def report_to_pdf(html, orientation="Landscape"):
|
||||
frappe.local.response.filename = "report.pdf"
|
||||
frappe.local.response.filecontent = get_pdf(html, {"orientation": orientation})
|
||||
frappe.local.response.type = "download"
|
||||
frappe.local.response.type = "pdf"
|
||||
|
||||
@frappe.whitelist()
|
||||
def print_by_server(doctype, name, print_format=None, doc=None, no_letterhead=0):
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ def build_response(response_type=None):
|
|||
'txt': as_txt,
|
||||
'download': as_raw,
|
||||
'json': as_json,
|
||||
'pdf': as_pdf,
|
||||
'page': as_page,
|
||||
'redirect': redirect,
|
||||
'binary': as_binary
|
||||
|
|
@ -83,6 +84,13 @@ def as_json():
|
|||
response.data = json.dumps(frappe.local.response, default=json_handler, separators=(',',':'))
|
||||
return response
|
||||
|
||||
def as_pdf():
|
||||
response = Response()
|
||||
response.mimetype = "application/pdf"
|
||||
response.headers["Content-Disposition"] = ("filename=\"%s\"" % frappe.response['filename'].replace(' ', '_')).encode("utf-8")
|
||||
response.data = frappe.response['filecontent']
|
||||
return response
|
||||
|
||||
def as_binary():
|
||||
response = Response()
|
||||
response.mimetype = 'application/octet-stream'
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ ndg-httpsclient
|
|||
pyasn1
|
||||
zxcvbn-python
|
||||
unittest-xml-reporting
|
||||
oauthlib==3.0.0
|
||||
requests-oauthlib==1.2.0
|
||||
oauthlib
|
||||
requests-oauthlib
|
||||
pdfkit
|
||||
PyJWT
|
||||
PyPDF2
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue