Merge branch 'staging' into develop
This commit is contained in:
commit
13524a1ad5
13 changed files with 74 additions and 30 deletions
|
|
@ -17,7 +17,7 @@ from faker import Faker
|
|||
from .exceptions import *
|
||||
from .utils.jinja import (get_jenv, get_template, render_template, get_email_from_template, get_jloader)
|
||||
|
||||
__version__ = '10.1.63'
|
||||
__version__ = '10.1.64'
|
||||
__title__ = "Frappe Framework"
|
||||
|
||||
local = Local()
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ def get_list(doctype, fields=None, filters=None, order_by=None,
|
|||
:param limit_start: Start at this index
|
||||
:param limit_page_length: Number of records to be returned (default 20)'''
|
||||
if frappe.is_table(doctype):
|
||||
check_parent_permission(parent)
|
||||
check_parent_permission(parent, doctype)
|
||||
|
||||
return frappe.get_list(doctype, fields=fields, filters=filters, order_by=order_by,
|
||||
limit_start=limit_start, limit_page_length=limit_page_length, ignore_permissions=False)
|
||||
|
|
@ -45,7 +45,7 @@ def get(doctype, name=None, filters=None, parent=None):
|
|||
:param name: return document of this `name`
|
||||
:param filters: If name is not set, filter by these values and return the first match'''
|
||||
if frappe.is_table(doctype):
|
||||
check_parent_permission(parent)
|
||||
check_parent_permission(parent, doctype)
|
||||
|
||||
if filters and not name:
|
||||
name = frappe.db.get_value(doctype, json.loads(filters))
|
||||
|
|
@ -66,7 +66,7 @@ def get_value(doctype, fieldname, filters=None, as_dict=True, debug=False, paren
|
|||
:param fieldname: Field to be returned (default `name`)
|
||||
:param filters: dict or string for identifying the record'''
|
||||
if frappe.is_table(doctype):
|
||||
check_parent_permission(parent)
|
||||
check_parent_permission(parent, doctype)
|
||||
|
||||
if not frappe.has_permission(doctype):
|
||||
frappe.throw(_("No permission for {0}".format(doctype)), frappe.PermissionError)
|
||||
|
|
@ -360,8 +360,13 @@ def attach_file(filename=None, filedata=None, doctype=None, docname=None, folder
|
|||
|
||||
return f.as_dict()
|
||||
|
||||
def check_parent_permission(parent):
|
||||
def check_parent_permission(parent, child_doctype):
|
||||
if parent:
|
||||
# User may pass fake parent and get the information from the child table
|
||||
if child_doctype and not frappe.db.exists('DocField',
|
||||
{'parent': parent, 'options': child_doctype}):
|
||||
raise frappe.PermissionError
|
||||
|
||||
if frappe.permissions.has_permission(parent):
|
||||
return
|
||||
# Either parent not passed or the user doesn't have permission on parent doctype of child table!
|
||||
|
|
|
|||
|
|
@ -177,6 +177,11 @@ def get_data():
|
|||
"name": "Auto Email Report",
|
||||
"description": _("Setup Reports to be emailed at regular intervals"),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Newsletter",
|
||||
"description": _("Create and manage newsletter")
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -94,8 +94,8 @@ class Communication(Document):
|
|||
if self.communication_type in ("Communication", "Comment"):
|
||||
# send new comment to listening clients
|
||||
frappe.publish_realtime('new_communication', self.as_dict(),
|
||||
doctype=self.reference_doctype, docname=self.reference_name,
|
||||
after_commit=True)
|
||||
doctype=self.reference_doctype, docname=self.reference_name,
|
||||
after_commit=True)
|
||||
|
||||
if self.communication_type == "Comment":
|
||||
notify_mentions(self)
|
||||
|
|
@ -108,7 +108,7 @@ class Communication(Document):
|
|||
else:
|
||||
# reference_name contains the user who is addressed in the messages' page comment
|
||||
frappe.publish_realtime('new_message', self.as_dict(),
|
||||
user=self.reference_name, after_commit=True)
|
||||
user=self.reference_name, after_commit=True)
|
||||
|
||||
def on_update(self):
|
||||
"""Update parent status as `Open` or `Replied`."""
|
||||
|
|
|
|||
|
|
@ -200,6 +200,13 @@ frappe.data_import.download_dialog = function(frm) {
|
|||
"options": "Excel\nCSV",
|
||||
"default": "Excel"
|
||||
},
|
||||
{
|
||||
"label": __("Download with Data"),
|
||||
"fieldname": "with_data",
|
||||
"fieldtype": "Check",
|
||||
"hidden": !frm.doc.overwrite,
|
||||
"default": 1
|
||||
},
|
||||
{
|
||||
"label": __("Select All"),
|
||||
"fieldname": "select_all",
|
||||
|
|
@ -270,7 +277,7 @@ frappe.data_import.download_dialog = function(frm) {
|
|||
doctype: frm.doc.reference_doctype,
|
||||
parent_doctype: frm.doc.reference_doctype,
|
||||
select_columns: JSON.stringify(columns),
|
||||
with_data: frm.doc.overwrite,
|
||||
with_data: frm.doc.overwrite && data.with_data,
|
||||
all_doctypes: true,
|
||||
file_type: data.file_type,
|
||||
template: true
|
||||
|
|
|
|||
|
|
@ -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.29'
|
||||
staging_version = '11.0.3-beta.30'
|
||||
|
||||
app_email = "info@frappe.io"
|
||||
|
||||
|
|
|
|||
|
|
@ -476,7 +476,8 @@ class BaseDocument(object):
|
|||
setattr(self, df.fieldname, values.name)
|
||||
|
||||
for _df in fields_to_fetch:
|
||||
setattr(self, _df.fieldname, values[_df.fetch_from.split('.')[-1]])
|
||||
if self.docstatus != 1 or _df.allow_on_submit:
|
||||
setattr(self, _df.fieldname, values[_df.fetch_from.split('.')[-1]])
|
||||
|
||||
notify_link_count(doctype, docname)
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import frappe.permissions
|
|||
from datetime import datetime
|
||||
import frappe, json, copy, re
|
||||
from frappe.model import optional_fields
|
||||
from frappe.client import check_parent_permission
|
||||
from frappe.model.utils.user_settings import get_user_settings, update_user_settings
|
||||
from frappe.utils import flt, cint, get_time, make_filter_tuple, get_filter, add_to_date, cstr
|
||||
|
||||
|
|
@ -680,6 +681,19 @@ def get_list(doctype, *args, **kwargs):
|
|||
'''wrapper for DatabaseQuery'''
|
||||
kwargs.pop('cmd', None)
|
||||
kwargs.pop('ignore_permissions', None)
|
||||
|
||||
# If doctype is child table
|
||||
if frappe.is_table(doctype):
|
||||
# Example frappe.db.get_list('Purchase Receipt Item', {'parent': 'Purchase Receipt'})
|
||||
# Here purchase receipt is the parent doctype of the child doctype Purchase Receipt Item
|
||||
|
||||
if not kwargs.get('parent'):
|
||||
frappe.flags.error_message = _('Parent is required to get child table data')
|
||||
raise frappe.PermissionError(doctype)
|
||||
|
||||
check_parent_permission(kwargs.get('parent'), doctype)
|
||||
del kwargs['parent']
|
||||
|
||||
return DatabaseQuery(doctype).execute(None, *args, **kwargs)
|
||||
|
||||
def is_parent_only_filter(doctype, filters):
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ def rename_doc(doctype, old, new, force=False, merge=False, ignore_permissions=F
|
|||
frappe.delete_doc(doctype, old)
|
||||
|
||||
frappe.clear_cache()
|
||||
frappe.enqueue('frappe.utils.global_search.rebuild_for_doctype', doctype=doctype)
|
||||
|
||||
return new
|
||||
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@ frappe.search.SearchDialog = Class.extend({
|
|||
no_results_status: (keyword) => __("<p>No results found for '" + keyword + "' in Global Search</p>"),
|
||||
|
||||
get_results: function(keywords, callback) {
|
||||
var start = 0, limit = 100;
|
||||
var start = 0, limit = 1000;
|
||||
var results = frappe.search.utils.get_nav_results(keywords);
|
||||
frappe.search.utils.get_global_results(keywords, start, limit)
|
||||
.then(function(global_results) {
|
||||
|
|
|
|||
|
|
@ -150,7 +150,9 @@ table td div {
|
|||
|
||||
/* hack for webkit specific browser */
|
||||
@media (-webkit-min-device-pixel-ratio:0) {
|
||||
thead, tfoot { display: table-row-group; }
|
||||
thead, tfoot {
|
||||
display: table-header-group;
|
||||
}
|
||||
}
|
||||
|
||||
[document-status] {
|
||||
|
|
|
|||
|
|
@ -121,17 +121,17 @@ class RedisWrapper(redis.Redis):
|
|||
except redis.exceptions.ConnectionError:
|
||||
pass
|
||||
|
||||
def lpush(self, key, *values):
|
||||
super(redis.Redis, self).lpush(self.make_key(key), *values)
|
||||
def lpush(self, key, value):
|
||||
super(RedisWrapper, self).lpush(self.make_key(key), value)
|
||||
|
||||
def rpush(self, key, *values):
|
||||
super(redis.Redis, self).rpush(self.make_key(key), *values)
|
||||
def rpush(self, key, value):
|
||||
super(RedisWrapper, self).rpush(self.make_key(key), value)
|
||||
|
||||
def lpop(self, key):
|
||||
return super(redis.Redis, self).lpop(self.make_key(key))
|
||||
return super(RedisWrapper, self).lpop(self.make_key(key))
|
||||
|
||||
def llen(self, key):
|
||||
return super(redis.Redis, self).llen(self.make_key(key))
|
||||
return super(RedisWrapper, self).llen(self.make_key(key))
|
||||
|
||||
def hset(self, name, key, value, shared=False):
|
||||
_name = self.make_key(name, shared=shared)
|
||||
|
|
@ -143,14 +143,14 @@ class RedisWrapper(redis.Redis):
|
|||
|
||||
# set in redis
|
||||
try:
|
||||
super(redis.Redis, self).hset(_name,
|
||||
super(RedisWrapper, self).hset(_name,
|
||||
key, pickle.dumps(value))
|
||||
except redis.exceptions.ConnectionError:
|
||||
pass
|
||||
|
||||
def hgetall(self, name):
|
||||
return {key: pickle.loads(value) for key, value in
|
||||
iteritems(super(redis.Redis, self).hgetall(self.make_key(name)))}
|
||||
iteritems(super(RedisWrapper, self).hgetall(self.make_key(name)))}
|
||||
|
||||
def hget(self, name, key, generator=None, shared=False):
|
||||
_name = self.make_key(name, shared=shared)
|
||||
|
|
@ -162,7 +162,7 @@ class RedisWrapper(redis.Redis):
|
|||
|
||||
value = None
|
||||
try:
|
||||
value = super(redis.Redis, self).hget(_name, key)
|
||||
value = super(RedisWrapper, self).hget(_name, key)
|
||||
except redis.exceptions.ConnectionError:
|
||||
pass
|
||||
|
||||
|
|
@ -184,7 +184,7 @@ class RedisWrapper(redis.Redis):
|
|||
if key in frappe.local.cache[_name]:
|
||||
del frappe.local.cache[_name][key]
|
||||
try:
|
||||
super(redis.Redis, self).hdel(_name, key)
|
||||
super(RedisWrapper, self).hdel(_name, key)
|
||||
except redis.exceptions.ConnectionError:
|
||||
pass
|
||||
|
||||
|
|
@ -196,31 +196,31 @@ class RedisWrapper(redis.Redis):
|
|||
|
||||
def hkeys(self, name):
|
||||
try:
|
||||
return super(redis.Redis, self).hkeys(self.make_key(name))
|
||||
return super(RedisWrapper, self).hkeys(self.make_key(name))
|
||||
except redis.exceptions.ConnectionError:
|
||||
return []
|
||||
|
||||
def sadd(self, name, *values):
|
||||
"""Add a member/members to a given set"""
|
||||
super(redis.Redis, self).sadd(self.make_key(name), *values)
|
||||
super(RedisWrapper, self).sadd(self.make_key(name), *values)
|
||||
|
||||
def srem(self, name, *values):
|
||||
"""Remove a specific member/list of members from the set"""
|
||||
super(redis.Redis, self).srem(self.make_key(name), *values)
|
||||
super(RedisWrapper, self).srem(self.make_key(name), *values)
|
||||
|
||||
def sismember(self, name, value):
|
||||
"""Returns True or False based on if a given value is present in the set"""
|
||||
return super(redis.Redis, self).sismember(self.make_key(name), value)
|
||||
return super(RedisWrapper, self).sismember(self.make_key(name), value)
|
||||
|
||||
def spop(self, name):
|
||||
"""Removes and returns a random member from the set"""
|
||||
return super(redis.Redis, self).spop(self.make_key(name))
|
||||
return super(RedisWrapper, self).spop(self.make_key(name))
|
||||
|
||||
def srandmember(self, name, count=None):
|
||||
"""Returns a random member from the set"""
|
||||
return super(redis.Redis, self).srandmember(self.make_key(name))
|
||||
return super(RedisWrapper, self).srandmember(self.make_key(name))
|
||||
|
||||
def smembers(self, name):
|
||||
"""Return all members of the set"""
|
||||
return super(redis.Redis, self).smembers(self.make_key(name))
|
||||
return super(RedisWrapper, self).smembers(self.make_key(name))
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ def build_response(response_type=None):
|
|||
|
||||
response_type_map = {
|
||||
'csv': as_csv,
|
||||
'txt': as_txt,
|
||||
'download': as_raw,
|
||||
'json': as_json,
|
||||
'page': as_page,
|
||||
|
|
@ -55,6 +56,14 @@ def as_csv():
|
|||
response.data = frappe.response['result']
|
||||
return response
|
||||
|
||||
def as_txt():
|
||||
response = Response()
|
||||
response.mimetype = 'text'
|
||||
response.charset = 'utf-8'
|
||||
response.headers["Content-Disposition"] = ("attachment; filename=\"%s.txt\"" % frappe.response['doctype'].replace(' ', '_')).encode("utf-8")
|
||||
response.data = frappe.response['result']
|
||||
return response
|
||||
|
||||
def as_raw():
|
||||
response = Response()
|
||||
response.mimetype = frappe.response.get("content_type") or mimetypes.guess_type(frappe.response['filename'])[0] or "application/unknown"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue