Merge branch 'master' into staging-fixes

This commit is contained in:
Ameya Shenoy 2018-11-23 08:07:36 +00:00
commit d1d0edc636
No known key found for this signature in database
GPG key ID: AC016A555657D0A3
6 changed files with 43 additions and 23 deletions

View file

@ -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()

View file

@ -29,7 +29,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)
@ -46,7 +46,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))
@ -67,7 +67,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)
@ -359,8 +359,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!

View file

@ -14,6 +14,7 @@ import frappe.permissions
from frappe.utils import flt, cint, getdate, get_datetime, get_time, make_filter_tuple, get_filter, add_to_date
from frappe import _
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 datetime import datetime
@ -659,6 +660,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):

View file

@ -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

View file

@ -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) {

View file

@ -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))