Merge branch 'staging' into develop
This commit is contained in:
commit
d5fdc670f7
14 changed files with 92 additions and 71 deletions
|
|
@ -8,7 +8,6 @@ import json
|
|||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from six import iteritems
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
|
||||
|
||||
|
||||
class KanbanBoard(Document):
|
||||
|
|
@ -130,17 +129,8 @@ def update_order(board_name, order):
|
|||
@frappe.whitelist()
|
||||
def quick_kanban_board(doctype, board_name, field_name, project=None):
|
||||
'''Create new KanbanBoard quickly with default options'''
|
||||
|
||||
doc = frappe.new_doc('Kanban Board')
|
||||
|
||||
if field_name == 'kanban_column':
|
||||
create_custom_field(doctype, {
|
||||
'label': 'Kanban Column',
|
||||
'fieldname': 'kanban_column',
|
||||
'fieldtype': 'Select',
|
||||
'hidden': 1,
|
||||
'owner': 'Administrator'
|
||||
})
|
||||
|
||||
meta = frappe.get_meta(doctype)
|
||||
|
||||
options = ''
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ source_link = "https://github.com/frappe/frappe"
|
|||
app_license = "MIT"
|
||||
|
||||
develop_version = '12.x.x-develop'
|
||||
staging_version = '11.0.3-beta.45'
|
||||
staging_version = '11.0.3-beta.46'
|
||||
|
||||
app_email = "info@frappe.io"
|
||||
|
||||
|
|
|
|||
|
|
@ -573,6 +573,7 @@ class DatabaseQuery(object):
|
|||
)
|
||||
|
||||
match_conditions.append("({condition})".format(condition=condition))
|
||||
match_filters[df.get('options')] = docs
|
||||
|
||||
if match_conditions:
|
||||
self.match_conditions.append(" and ".join(match_conditions))
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ def check_if_doc_is_linked(doc, method="Delete"):
|
|||
def check_if_doc_is_dynamically_linked(doc, method="Delete"):
|
||||
'''Raise `frappe.LinkExistsError` if the document is dynamically linked'''
|
||||
for df in get_dynamic_link_map().get(doc.doctype, []):
|
||||
if df.parent in ("Communication", "ToDo", "DocShare", "Email Unsubscribe", "Activity Log", 'File', 'Version'):
|
||||
if df.parent in ("Communication", "ToDo", "DocShare", "Email Unsubscribe", "Activity Log", 'File', 'Version', 'View log'):
|
||||
# don't check for communication and todo!
|
||||
continue
|
||||
|
||||
|
|
@ -286,6 +286,10 @@ def delete_dynamic_links(doctype, name):
|
|||
communication_type = 'Comment'
|
||||
and reference_doctype=%s and reference_name=%s""", (doctype, name))
|
||||
|
||||
# delete view logs
|
||||
frappe.db.sql("""delete from `tabView log`
|
||||
where reference_doctype=%s and reference_name=%s""", (doctype, name))
|
||||
|
||||
# unlink communications
|
||||
frappe.db.sql("""update `tabCommunication`
|
||||
set reference_doctype=null, reference_name=null
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@ frappe.defaults = {
|
|||
if(!d && frappe.defaults.is_a_user_permission_key(key))
|
||||
d = defaults[frappe.model.scrub(key)];
|
||||
if($.isArray(d)) d = d[0];
|
||||
if(frappe.defaults.not_in_user_permission(key, d)) {
|
||||
|
||||
if(!frappe.defaults.in_user_permission(key, d)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return d;
|
||||
},
|
||||
get_user_defaults: function(key) {
|
||||
|
|
@ -29,7 +31,7 @@ frappe.defaults = {
|
|||
|
||||
// filter out values which are not permitted to the user
|
||||
d.filter(item => {
|
||||
if(!frappe.defaults.not_in_user_permission(key, item)) {
|
||||
if(frappe.defaults.in_user_permission(key, item)) {
|
||||
return item;
|
||||
}
|
||||
});
|
||||
|
|
@ -73,7 +75,7 @@ frappe.defaults = {
|
|||
}
|
||||
}
|
||||
|
||||
if(frappe.defaults.not_in_user_permission(key, value)) {
|
||||
if(!frappe.defaults.in_user_permission(key, value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -90,14 +92,22 @@ frappe.defaults = {
|
|||
return key.indexOf(":")===-1 && key !== frappe.model.scrub(key);
|
||||
},
|
||||
|
||||
not_in_user_permission: function(key, value) {
|
||||
let user_permission = this.get_user_permissions()[frappe.model.unscrub(key)] || [];
|
||||
in_user_permission: function(key, value) {
|
||||
let user_permission = this.get_user_permissions()[frappe.model.unscrub(key)];
|
||||
|
||||
let doc_found = user_permission.some(perm => {
|
||||
return perm.doc === value;
|
||||
});
|
||||
if (user_permission && user_permission.length) {
|
||||
|
||||
let doc_found = user_permission.some(perm => {
|
||||
return perm.doc === value;
|
||||
});
|
||||
return doc_found;
|
||||
|
||||
} else {
|
||||
// there is no user permission for this doctype
|
||||
// so we can allow this doc i.e., value
|
||||
return true;
|
||||
}
|
||||
|
||||
return !doc_found;
|
||||
},
|
||||
|
||||
get_user_permissions: function() {
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ frappe.ui.form.AssignToDialog = Class.extend({
|
|||
{value:'High', label:__('High')}],
|
||||
'default':'Medium'},
|
||||
],
|
||||
primary_action: function() { frappe.ui.add_assignment(opts, me) },
|
||||
primary_action: function() { frappe.ui.add_assignment(opts, this) },
|
||||
primary_action_label: __("Add")
|
||||
})
|
||||
$.extend(me, dialog);
|
||||
|
|
|
|||
|
|
@ -225,21 +225,18 @@ frappe.views.KanbanView.setup_dropdown_in_sidebar = function(doctype, $dropdown)
|
|||
|
||||
const fields = get_fields_for_dialog();
|
||||
|
||||
let primary_action_label = fields.length > 1 ? __('Save') : '';
|
||||
let primary_action = fields.length > 1 ?
|
||||
({ board_name, field_name, project }) => {
|
||||
make_kanban_board(board_name, field_name, project)
|
||||
.then(() => dialog.hide(), (err) => frappe.msgprint(err));
|
||||
} : null;
|
||||
|
||||
dialog = new frappe.ui.Dialog({
|
||||
title: __('New Kanban Board'),
|
||||
fields: fields,
|
||||
|
||||
primary_action_label: __('Save'),
|
||||
primary_action(values) {
|
||||
const custom_column =
|
||||
values.custom_column !== undefined ?
|
||||
values.custom_column : 1;
|
||||
|
||||
let field_name = custom_column ? 'kanban_column' : values.field_name;
|
||||
|
||||
make_kanban_board(values.board_name, field_name, values.project)
|
||||
.then(() => dialog.hide(), (err) => frappe.msgprint(err));
|
||||
}
|
||||
fields,
|
||||
primary_action_label,
|
||||
primary_action
|
||||
});
|
||||
return dialog;
|
||||
}
|
||||
|
|
@ -272,26 +269,28 @@ frappe.views.KanbanView.setup_dropdown_in_sidebar = function(doctype, $dropdown)
|
|||
});
|
||||
|
||||
if (select_fields.length > 0) {
|
||||
fields = fields.concat([{
|
||||
fields.push({
|
||||
fieldtype: 'Select',
|
||||
fieldname: 'field_name',
|
||||
label: __('Columns based on'),
|
||||
options: select_fields.map(df => ({label: df.label, value: df.fieldname})),
|
||||
default: select_fields[0],
|
||||
depends_on: 'eval:doc.custom_column===0',
|
||||
reqd: 1
|
||||
},
|
||||
|
||||
{
|
||||
fieldtype: 'Check',
|
||||
fieldname: 'custom_column',
|
||||
label: __('Custom Column'),
|
||||
default: 0,
|
||||
onchange() {
|
||||
const value = this.get_value();
|
||||
this.layout.set_df_property('field_name', 'reqd', !value);
|
||||
}
|
||||
}]);
|
||||
reqd: 1,
|
||||
});
|
||||
} else {
|
||||
fields = [{
|
||||
fieldtype: 'HTML',
|
||||
options: `
|
||||
<div>
|
||||
<p class="text-medium">
|
||||
${__('No fields found that can be used as a Kanban Column. Use the Customize Form to add a Custom Field of type "Select".')}
|
||||
</p>
|
||||
<a class="btn btn-xs btn-default" href="#Form/Customize Form?doc_type=${doctype}">
|
||||
${__('Customize Form')}
|
||||
</a>
|
||||
</div>
|
||||
`
|
||||
}];
|
||||
}
|
||||
|
||||
return fields;
|
||||
|
|
|
|||
|
|
@ -833,7 +833,13 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
|
|||
editable,
|
||||
align,
|
||||
format: (value, row, column, data) => {
|
||||
return frappe.format(value, column.docfield, { always_show_decimals: true }, data);
|
||||
const d = row.reduce((acc, curr) => {
|
||||
if (!curr.column.docfield) return acc;
|
||||
acc[curr.column.docfield.fieldname] = curr.content;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
return frappe.format(value, column.docfield, { always_show_decimals: true }, d);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1055,7 +1061,7 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
|
|||
for (let cdt in values) {
|
||||
fields = fields.concat(values[cdt].map(f => [f, cdt]));
|
||||
}
|
||||
|
||||
|
||||
// always keep name (ID) column
|
||||
this.fields = [["name", this.doctype], ...fields];
|
||||
|
||||
|
|
|
|||
|
|
@ -13,45 +13,47 @@ def set_request(**kwargs):
|
|||
class TestWebsite(unittest.TestCase):
|
||||
|
||||
def test_page_load(self):
|
||||
frappe.set_user('Guest')
|
||||
set_request(method='POST', path='login')
|
||||
response = render.render()
|
||||
|
||||
self.assertTrue(response.status_code, 200)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
html = frappe.safe_decode(response.get_data())
|
||||
|
||||
self.assertTrue('/* login-css */' in html)
|
||||
self.assertTrue('// login.js' in html)
|
||||
self.assertTrue('<!-- login.html -->' in html)
|
||||
frappe.set_user('Administrator')
|
||||
|
||||
def test_redirect(self):
|
||||
import frappe.hooks
|
||||
frappe.hooks.website_redirects = [
|
||||
dict(source='/testfrom', target='://testto1'),
|
||||
dict(source='/testfromregex.*', target='://testto2'),
|
||||
dict(source='/testsub/(.*)', target='://testto3/\1')
|
||||
dict(source=r'/testfrom', target=r'://testto1'),
|
||||
dict(source=r'/testfromregex.*', target=r'://testto2'),
|
||||
dict(source=r'/testsub/(.*)', target=r'://testto3/\1')
|
||||
]
|
||||
frappe.cache().delete_key('app_hooks')
|
||||
frappe.cache().delete_key('website_redirects')
|
||||
|
||||
set_request(method='GET', path='/testfrom')
|
||||
response = render.render()
|
||||
self.assertTrue(response.status_code, 301)
|
||||
self.assertTrue(response.headers.get('Location'), '://testto1')
|
||||
self.assertEquals(response.status_code, 301)
|
||||
self.assertEquals(response.headers.get('Location'), r'://testto1')
|
||||
|
||||
set_request(method='GET', path='/testfromregex/test')
|
||||
response = render.render()
|
||||
self.assertTrue(response.status_code, 301)
|
||||
self.assertTrue(response.headers.get('Location'), '://testto2')
|
||||
self.assertEquals(response.status_code, 301)
|
||||
self.assertEquals(response.headers.get('Location'), r'://testto2')
|
||||
|
||||
set_request(method='GET', path='/testsub/me')
|
||||
response = render.render()
|
||||
self.assertTrue(response.status_code, 301)
|
||||
self.assertTrue(response.headers.get('Location'), '://testto3/me')
|
||||
self.assertEquals(response.status_code, 301)
|
||||
self.assertEquals(response.headers.get('Location'), r'://testto3/me')
|
||||
|
||||
set_request(method='GET', path='/test404')
|
||||
response = render.render()
|
||||
self.assertTrue(response.status_code, 404)
|
||||
self.assertEquals(response.status_code, 404)
|
||||
|
||||
delattr(frappe.hooks, 'website_redirects')
|
||||
frappe.cache().delete_key('app_hooks')
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ def update_controller_context(context, controller):
|
|||
ret = module.get_context(context)
|
||||
if ret:
|
||||
context.update(ret)
|
||||
except (frappe.PermissionError, frappe.DoesNotExistError):
|
||||
except (frappe.PermissionError, frappe.DoesNotExistError, frappe.Redirect):
|
||||
raise
|
||||
except:
|
||||
if not frappe.flags.in_migrate:
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ def resolve_redirect(path):
|
|||
{"source": "/from", "target": "/main"},
|
||||
|
||||
# use regex
|
||||
{"source": "/from/(.*)", "target": "/main/\1"}
|
||||
{"source": r"/from/(.*)", "target": r"/main/\1"}
|
||||
# use r as a string prefix if you use regex groups or want to escape any string literal
|
||||
]
|
||||
'''
|
||||
redirects = frappe.get_hooks('website_redirects')
|
||||
|
|
@ -31,7 +32,7 @@ def resolve_redirect(path):
|
|||
for rule in redirects:
|
||||
pattern = rule['source'].strip('/ ') + '$'
|
||||
if re.match(pattern, path):
|
||||
redirect_to = re.sub(pattern, rule['target'].replace('\\', '\\\\'), path)
|
||||
redirect_to = re.sub(pattern, rule['target'], path)
|
||||
frappe.flags.redirect_location = redirect_to
|
||||
frappe.cache().hset('website_redirects', path, redirect_to)
|
||||
raise frappe.Redirect
|
||||
|
|
|
|||
|
|
@ -67,6 +67,9 @@ def render(path=None, http_status_code=None):
|
|||
except frappe.PermissionError as e:
|
||||
data, http_status_code = render_403(e, path)
|
||||
|
||||
except frappe.Redirect as e:
|
||||
raise e
|
||||
|
||||
except Exception:
|
||||
path = "error"
|
||||
data = render_page(path)
|
||||
|
|
|
|||
|
|
@ -70,8 +70,13 @@ def get_desk_assets(build_version):
|
|||
pass
|
||||
|
||||
for path in data["include_css"]:
|
||||
with open(os.path.join(frappe.local.sites_path, path) ,"r") as f:
|
||||
assets[1]["data"] = assets[1]["data"] + "\n" + frappe.safe_decode(f.read(), "utf-8")
|
||||
if path.startswith('/assets/'):
|
||||
path = path.replace('/assets/', 'assets/')
|
||||
try:
|
||||
with open(os.path.join(frappe.local.sites_path, path) ,"r") as f:
|
||||
assets[1]["data"] = assets[1]["data"] + "\n" + frappe.safe_decode(f.read(), "utf-8")
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
return {
|
||||
"build_version": data["build_version"],
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ from frappe.utils.html_utils import get_icon_html
|
|||
no_cache = True
|
||||
|
||||
def get_context(context):
|
||||
if frappe.session.user != "Guest" and frappe.session.data.user_type=="System User":
|
||||
frappe.local.flags.redirect_location = "/desk"
|
||||
if frappe.session.user != "Guest":
|
||||
frappe.local.flags.redirect_location = "/" if frappe.session.data.user_type=="Website User" else "/desk"
|
||||
raise frappe.Redirect
|
||||
|
||||
# get settings from site config
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue