def test_not_allows_if_not_enough_permission(self): user = MockUser([], [1]) self.assertFalse(has_access({1: view_only}, user, not view_only)) self.assertFalse(has_access({2: view_only}, user, not view_only)) self.assertFalse(has_access({2: view_only}, user, view_only)) self.assertFalse(has_access({2: not view_only, 1: view_only}, user, not view_only))
def test_allows_if_user_member_in_multiple_groups(self): user = MockUser([], [1, 2, 3]) self.assertTrue(has_access({1: not view_only, 2: view_only}, user, not view_only)) self.assertFalse(has_access({1: view_only, 2: view_only}, user, not view_only)) self.assertTrue(has_access({1: view_only, 2: view_only}, user, view_only)) self.assertTrue(has_access({1: not view_only, 2: not view_only}, user, view_only))
def post(self): """ Execute a query (or retrieve recent results). :qparam string query: The query text to execute :qparam number query_id: The query object to update with the result (optional) :qparam number max_age: If query results less than `max_age` seconds old are available, return them, otherwise execute the query; if omitted or -1, returns any cached result, or executes if not available. Set to zero to always execute. :qparam number data_source_id: ID of data source to query :qparam object parameters: A set of parameter values to apply to the query. """ params = request.get_json(force=True) query = params['query'] max_age = params.get('max_age', -1) # max_age might have the value of None, in which case calling int(None) will fail if max_age is None: max_age = -1 max_age = int(max_age) query_id = params.get('query_id', 'adhoc') parameters = params.get('parameters', collect_parameters_from_request(request.args)) parameterized_query = ParameterizedQuery(query, org=self.current_org) data_source_id = params.get('data_source_id') if data_source_id: data_source = models.DataSource.get_by_id_and_org( params.get('data_source_id'), self.current_org) else: return error_messages['select_data_source'] if query_id: query = models.Query.get_by_id_and_org(params.get('query_id'), self.current_org) else: return error_messages['select_query'] if not has_access(data_source, self.current_user, not_view_only): return error_messages['no_permission'] if not has_access(query, self.current_user, not_view_only): return error_messages['no_permission'] return run_query(parameterized_query, parameters, data_source, query_id, max_age)
def post(self): params = request.get_json(force=True) data_source = models.DataSource.get_by_id_and_org(params.get('data_source_id'), self.current_org) if not has_access(data_source.groups, self.current_user, not_view_only): return {'job': {'status': 4, 'error': 'You do not have permission to run queries with this data source.'}}, 403 self.record_event({ 'action': 'execute_query', 'timestamp': int(time.time()), 'object_id': data_source.id, 'object_type': 'data_source', 'query': params['query'] }) max_age = int(params.get('max_age', -1)) if max_age == 0: query_result = None else: query_result = models.QueryResult.get_latest(data_source, params['query'], max_age) if query_result: return {'query_result': query_result.to_dict()} else: query_id = params.get('query_id', 'adhoc') job = QueryTask.add_task(params['query'], data_source, metadata={"Username": self.current_user.name, "Query ID": query_id}) return {'job': job.to_dict()}
def post(self): params = request.get_json(force=True) parameter_values = collect_parameters_from_request(request.args) query = params['query'] max_age = int(params.get('max_age', -1)) query_id = params.get('query_id', 'adhoc') data_source = models.DataSource.get_by_id_and_org( params.get('data_source_id'), self.current_org) if not has_access(data_source.groups, self.current_user, not_view_only): return { 'job': { 'status': 4, 'error': 'You do not have permission to run queries with this data source.' } }, 403 self.record_event({ 'action': 'execute_query', 'timestamp': int(time.time()), 'object_id': data_source.id, 'object_type': 'data_source', 'query': query }) return run_query(data_source, parameter_values, query, query_id, max_age)
def post(self): """ Execute a query (or retrieve recent results). :qparam string query: The query text to execute :qparam number query_id: The query object to update with the result (optional) :qparam number max_age: If query results less than `max_age` seconds old are available, return them, otherwise execute the query; if omitted or -1, returns any cached result, or executes if not available. Set to zero to always execute. :qparam number data_source_id: ID of data source to query """ params = request.get_json(force=True) parameter_values = collect_parameters_from_request(request.args) query = params['query'] max_age = int(params.get('max_age', -1)) query_id = params.get('query_id', 'adhoc') data_source = models.DataSource.get_by_id_and_org(params.get('data_source_id'), self.current_org) if not has_access(data_source.groups, self.current_user, not_view_only): return {'job': {'status': 4, 'error': 'You do not have permission to run queries with this data source.'}}, 403 self.record_event({ 'action': 'execute_query', 'object_id': data_source.id, 'object_type': 'data_source', 'query': query }) return run_query(data_source, parameter_values, query, query_id, max_age)
def post(self, data_source_id): params = request.get_json(force=True) parameter_values = collect_parameters_from_request(request.args) query = mustache_render(params['query'], parameter_values) data_source = get_object_or_404( models.DataSource.get_by_id_and_org, data_source_id, self.current_org, ) # get the validator method validator = self.get_validator(data_source.query_runner) if (validator is None or not has_access(data_source.groups, self.current_user, not_view_only)): return { 'valid': False, 'report': 'You do not have permission to run queries with this data source.' }, 403 try: valid, report = validator(data_source.query_runner, query) return {'valid': valid, 'report': report}, 200 except apiclient.errors.HttpError as e: if e.resp.status == 400: error = json_loads(e.content)['error']['message'] else: error = e.content return {'valid': False, 'report': error}, 200 except Exception as e: return {'valid': False, 'report': str(e)}, 500
def post(self, query_id): """ Execute a saved query. :param number query_id: The ID of the query whose results should be fetched. :param object parameters: The parameter values to apply to the query. :qparam number max_age: If query results less than `max_age` seconds old are available, return them, otherwise execute the query; if omitted or -1, returns any cached result, or executes if not available. Set to zero to always execute. """ params = request.get_json(force=True) parameter_values = params.get('parameters') max_age = params.get('max_age', -1) # max_age might have the value of None, in which case calling int(None) will fail if max_age is None: max_age = -1 max_age = int(max_age) query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) allow_executing_with_view_only_permissions = query.parameterized.is_safe if has_access(query, self.current_user, allow_executing_with_view_only_permissions): return run_query(query.parameterized, parameter_values, query.data_source, query_id, max_age) else: return {'job': {'status': 4, 'error': 'You do not have permission to run queries with this data source.'}}, 403
def post(self, query_id): """ Execute a saved query. :param number query_id: The ID of the query whose results should be fetched. :param object parameters: The parameter values to apply to the query. :qparam number max_age: If query results less than `max_age` seconds old are available, return them, otherwise execute the query; if omitted or -1, returns any cached result, or executes if not available. Set to zero to always execute. """ params = request.get_json(force=True) parameters = params.get('parameters', {}) max_age = int(params.get('max_age', 0)) query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) if not has_access(query.data_source.groups, self.current_user, not_view_only): return { 'job': { 'status': 4, 'error': 'You do not have permission to run queries with this data source.' } }, 403 else: return run_query(query.data_source, parameters, query.query_text, query_id, max_age)
def post(self, query_id): """ Execute a saved query. :param number query_id: The ID of the query whose results should be fetched. :param object parameters: The parameter values to apply to the query. :qparam number max_age: If query results less than `max_age` seconds old are available, return them, otherwise execute the query; if omitted or -1, returns any cached result, or executes if not available. Set to zero to always execute. """ params = request.get_json(force=True, silent=True) or {} parameter_values = params.get('parameters', {}) max_age = params.get('max_age', -1) # max_age might have the value of None, in which case calling int(None) will fail if max_age is None: max_age = -1 max_age = int(max_age) query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) allow_executing_with_view_only_permissions = query.parameterized.is_safe if has_access(query, self.current_user, allow_executing_with_view_only_permissions): return run_query(query.parameterized, parameter_values, query.data_source, query_id, max_age) else: if not query.parameterized.is_safe: if current_user.is_api_user(): return error_messages['unsafe_when_shared'] else: return error_messages['unsafe_on_view_only'] else: return error_messages['no_permission']
def post(self): """ Execute a query (or retrieve recent results). :qparam string query: The query text to execute :qparam number query_id: The query object to update with the result (optional) :qparam number max_age: If query results less than `max_age` seconds old are available, return them, otherwise execute the query; if omitted, always execute :qparam number data_source_id: ID of data source to query """ params = request.get_json(force=True) parameter_values = collect_parameters_from_request(request.args) query = params['query'] max_age = int(params.get('max_age', -1)) query_id = params.get('query_id', 'adhoc') data_source = models.DataSource.get_by_id_and_org(params.get('data_source_id'), self.current_org) if not has_access(data_source.groups, self.current_user, not_view_only): return {'job': {'status': 4, 'error': 'You do not have permission to run queries with this data source.'}}, 403 self.record_event({ 'action': 'execute_query', 'timestamp': int(time.time()), 'object_id': data_source.id, 'object_type': 'data_source', 'query': query }) return run_query(data_source, parameter_values, query, query_id, max_age)
def post(self): """ Execute a query (or retrieve recent results). :qparam string query: The query text to execute :qparam number query_id: The query object to update with the result (optional) :qparam number max_age: If query results less than `max_age` seconds old are available, return them, otherwise execute the query; if omitted or -1, returns any cached result, or executes if not available. Set to zero to always execute. :qparam number data_source_id: ID of data source to query :qparam object parameters: A set of parameter values to apply to the query. """ params = request.get_json(force=True) query = params['query'] max_age = params.get('max_age', -1) # max_age might have the value of None, in which case calling int(None) will fail if max_age is None: max_age = -1 max_age = int(max_age) query_id = params.get('query_id', 'adhoc') parameters = params.get('parameters', collect_parameters_from_request(request.args)) parameterized_query = ParameterizedQuery(query) data_source_id = params.get('data_source_id') if data_source_id: data_source = models.DataSource.get_by_id_and_org( params.get('data_source_id'), self.current_org) else: return { 'job': { 'status': 4, 'error': 'Please select data source to run this query.' } }, 401 if not has_access(data_source, self.current_user, not_view_only): return { 'job': { 'status': 4, 'error': 'You do not have permission to run queries with this data source.' } }, 403 self.record_event({ 'action': 'execute_query', 'object_id': data_source.id, 'object_type': 'data_source', 'query': query, 'query_id': query_id, 'parameters': parameters }) return run_query(parameterized_query, parameters, data_source, query_id, max_age)
def serialize_dashboard(obj, with_widgets=False, user=None, with_favorite_state=True): layout = json_loads(obj.layout) widgets = [] if with_widgets: for w in obj.widgets: if w.visualization_id is None: widgets.append(serialize_widget(w)) elif user and has_access(w.visualization.query_rel, user, view_only): widgets.append(serialize_widget(w)) else: widget = project(serialize_widget(w), ('id', 'width', 'dashboard_id', 'options', 'created_at', 'updated_at')) widget['restricted'] = True widgets.append(widget) else: widgets = None if obj.user is not None: _user = obj.user.to_dict() else: assets = app.extensions['webpack']['assets'] or {} path = 'images/avatar.svg' profile_image_url = url_for('static', filename=assets.get(path, path)) _user = { 'name': 'user', 'profile_image_url': profile_image_url, } d = { 'id': obj.id, 'slug': obj.slug, 'name': obj.name, 'user_id': obj.user_id, # TODO: we should properly load the users 'user': _user, 'layout': layout, 'dashboard_filters_enabled': obj.dashboard_filters_enabled, 'widgets': widgets, 'is_archived': obj.is_archived, 'is_draft': obj.is_draft, 'tags': obj.tags or [], # TODO: bulk load favorites 'updated_at': obj.updated_at, 'created_at': obj.created_at, 'version': obj.version } if with_favorite_state: d['is_favorite'] = models.Favorite.is_favorite(current_user.id, obj) return d
def serialize_dashboard(obj, with_widgets=False, user=None, with_favorite_state=True): layout = json_loads(obj.layout) widgets = [] if with_widgets: for w in obj.widgets: if w.visualization_id is None: widgets.append(serialize_widget(w)) elif user and has_access(w.visualization.query_rel, user, view_only): widgets.append(serialize_widget(w)) else: widget = project( serialize_widget(w), ( "id", "width", "dashboard_id", "options", "created_at", "updated_at", ), ) widget["restricted"] = True widgets.append(widget) else: widgets = None d = { "id": obj.id, "slug": obj.name_as_slug, "name": obj.name, "user_id": obj.user_id, "user": { "id": obj.user.id, "name": obj.user.name, "email": obj.user.email, "profile_image_url": obj.user.profile_image_url, }, "layout": layout, "dashboard_filters_enabled": obj.dashboard_filters_enabled, "widgets": widgets, "options": obj.options, "is_archived": obj.is_archived, "is_draft": obj.is_draft, "tags": obj.tags or [], "updated_at": obj.updated_at, "created_at": obj.created_at, "version": obj.version, } return d
def test_allows_access_to_query_by_dashboard_api_key(self): dashboard = self.factory.create_dashboard() visualization = self.factory.create_visualization() self.factory.create_widget(dashboard=dashboard, visualization=visualization) query = self.factory.create_query(visualizations=[visualization]) api_key = self.factory.create_api_key(object=dashboard).api_key user = models.ApiUser(api_key, None, []) self.assertTrue(has_access(query, user, view_only))
def serialize_dashboard(obj, with_widgets=False, user=None, with_favorite_state=True): layout = json_loads(obj.layout) widgets = [] if with_widgets: for w in obj.widgets: if w.visualization_id is None: widgets.append(serialize_widget(w)) elif user and has_access(w.visualization.query_rel, user, view_only): widgets.append(serialize_widget(w)) else: widget = project( serialize_widget(w), ( "id", "width", "dashboard_id", "options", "created_at", "updated_at", ), ) widget["restricted"] = True widgets.append(widget) else: widgets = None d = { "id": obj.id, "slug": obj.slug, "name": obj.name, "user_id": obj.user_id, # TODO: we should properly load the users "user": obj.user.to_dict(), "layout": layout, "dashboard_filters_enabled": obj.dashboard_filters_enabled, "widgets": widgets, "is_archived": obj.is_archived, "is_draft": obj.is_draft, "tags": obj.tags or [], # TODO: bulk load favorites "updated_at": obj.updated_at, "created_at": obj.created_at, "version": obj.version, } if with_favorite_state: d["is_favorite"] = models.Favorite.is_favorite(current_user.id, obj) return d
def _load_query(user, query_id): query = models.Query.get_by_id(query_id) if user.org_id != query.org_id: raise PermissionError("Query id {} not found.".format(query.id)) if not has_access(query.data_source, user, not_view_only): raise PermissionError(u"You are not allowed to execute queries on {} data source (used for query id {}).".format( query.data_source.name, query.id)) return query
def _load_query(user, query_id): query = models.Query.get_by_id(query_id) if user.org_id != query.org_id: raise PermissionError("Query id {} not found.".format(query.id)) # TODO: this duplicates some of the logic we already have in the redash.handlers.query_results. # We should merge it so it's consistent. if not has_access(query.data_source, user, view_only): raise PermissionError("You do not have access to query id {}.".format(query.id)) return query
def serialize_dashboard(obj, with_widgets=False, user=None, with_favorite_state=True): layout = json_loads(obj.layout) widgets = [] if with_widgets: for w in obj.widgets: if w.visualization_id is None: widgets.append(serialize_widget(w)) elif user and has_access(w.visualization.query_rel, user, view_only): widgets.append(serialize_widget(w)) else: widget = project(serialize_widget(w), ('id', 'width', 'dashboard_id', 'options', 'created_at', 'updated_at')) widget['restricted'] = True widgets.append(widget) else: widgets = None d = { 'id': obj.id, 'slug': obj.slug, 'name': obj.name, 'user_id': current_user.id, 'created_by': obj.user.to_dict(), 'user': current_user.to_dict(), 'layout': layout, 'dashboard_filters_enabled': obj.dashboard_filters_enabled, 'widgets': widgets, 'is_archived': obj.is_archived, 'is_draft': obj.is_draft, 'tags': obj.tags or [], 'updated_at': obj.updated_at, 'created_at': obj.created_at, 'version': obj.version, 'background_image': obj.background_image, 'description': obj.description, 'type': obj.type or 'dashboard', 'folder_id': obj.folder_id } d['groups'] = [ g.to_dict(with_permissions_for=True) for g in models.DashboardGroup.get_by_dashboard(obj) ] return d
def serialize_dashboard(obj, with_widgets=False, user=None, with_favorite_state=True): layout = json_loads(obj.layout) widgets = [] if with_widgets: for w in obj.widgets: if w.visualization_id is None: widgets.append(serialize_widget(w)) elif user and has_access(w.visualization.query_rel, user, view_only): widgets.append(serialize_widget(w)) else: widget = project(serialize_widget(w), ('id', 'width', 'dashboard_id', 'options', 'created_at', 'updated_at')) widget['restricted'] = True widgets.append(widget) else: widgets = None d = { 'id': obj.id, 'slug': obj.slug, 'name': obj.name, 'user_id': obj.user_id, # TODO: we should properly load the users 'user': obj.user.to_dict(), 'layout': layout, 'dashboard_filters_enabled': obj.dashboard_filters_enabled, 'widgets': widgets, 'is_archived': obj.is_archived, 'is_draft': obj.is_draft, 'tags': obj.tags or [], # TODO: bulk load favorites 'updated_at': obj.updated_at, 'created_at': obj.created_at, 'version': obj.version } if with_favorite_state: d['is_favorite'] = models.Favorite.is_favorite(current_user.id, obj) return d
def _load_query(user, q): try: query = models.Query.get_by_id(q.id) except NoResultFound: query = None location = '(at line {} column {})'.format(q.line, q.column) if not query or user.org_id != query.org_id: raise PermissionError(u"Query id {} not found. {}".format( query_id, location)) if not has_access(query.data_source.groups, user, not_view_only): raise PermissionError( u"You are not allowed to execute queries on {} data source (used for query id {}). {}" .format(query.data_source.name, query.id, location)) return query
def serialize_dashboard_overview(obj, user=None): layout = json_loads(obj.layout) visualizations = [] for w in obj.widgets: if w.visualization_id is not None: if user and has_access(w.visualization.query_rel, user, view_only): visualizations.append(w.visualization_id) d = { 'id': obj.id, 'slug': obj.slug, 'name': obj.name, 'visualizations': visualizations, 'updated_at': obj.updated_at, 'created_at': obj.created_at, 'type': obj.type or 'dashboard' } return d
def post(self): """ Execute a query (or retrieve recent results). :qparam string query: The query text to execute :qparam number query_id: The query object to update with the result (optional) :qparam number max_age: If query results less than `max_age` seconds old are available, return them, otherwise execute the query; if omitted or -1, returns any cached result, or executes if not available. Set to zero to always execute. :qparam number data_source_id: ID of data source to query :qparam object parameters: A set of parameter values to apply to the query. """ params = request.get_json(force=True) query = params['query'] max_age = params.get('max_age', -1) # max_age might have the value of None, in which case calling int(None) will fail if max_age is None: max_age = -1 max_age = int(max_age) query_id = params.get('query_id', 'adhoc') parameters = params.get('parameters', collect_parameters_from_request(request.args)) parameterized_query = ParameterizedQuery(query) data_source = models.DataSource.get_by_id_and_org(params.get('data_source_id'), self.current_org) if not has_access(data_source, self.current_user, not_view_only): return {'job': {'status': 4, 'error': 'You do not have permission to run queries with this data source.'}}, 403 self.record_event({ 'action': 'execute_query', 'object_id': data_source.id, 'object_type': 'data_source', 'query': query, 'query_id': query_id, 'parameters': parameters }) return run_query(parameterized_query, parameters, data_source, query_id, max_age)
def post(self): params = request.get_json(force=True) parameter_values = collect_parameters_from_request(request.args) query = params['query'] max_age = int(params.get('max_age', -1)) query_id = params.get('query_id', 'adhoc') data_source = models.DataSource.get_by_id_and_org(params.get('data_source_id'), self.current_org) if not has_access(data_source.groups, self.current_user, not_view_only): return {'job': {'status': 4, 'error': 'You do not have permission to run queries with this data source.'}}, 403 self.record_event({ 'action': 'execute_query', 'timestamp': int(time.time()), 'object_id': data_source.id, 'object_type': 'data_source', 'query': query }) return run_query(data_source, parameter_values, query, query_id, max_age)
def post(self, query_id): """ Execute a saved query. :param number query_id: The ID of the query whose results should be fetched. :param object parameters: The parameter values to apply to the query. :qparam number max_age: If query results less than `max_age` seconds old are available, return them, otherwise execute the query; if omitted or -1, returns any cached result, or executes if not available. Set to zero to always execute. """ params = request.get_json(force=True) parameters = params.get('parameters', {}) max_age = params.get('max_age', -1) # max_age might have the value of None, in which case calling int(None) will fail if max_age is None: max_age = -1 max_age = int(max_age) query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) allow_executing_with_view_only_permissions = query.parameterized.is_safe if has_access(query.data_source.groups, self.current_user, allow_executing_with_view_only_permissions): return run_query(query.parameterized, parameters, query.data_source, query_id, max_age) else: return { 'job': { 'status': 4, 'error': 'You do not have permission to run queries with this data source.' } }, 403
def post(self): """ Execute a query (or retrieve recent results). :qparam string query: The query text to execute :qparam number query_id: The query object to update with the result (optional) :qparam number max_age: If query results less than `max_age` seconds old are available, return them, otherwise execute the query; if omitted, always execute :qparam number data_source_id: ID of data source to query """ params = request.get_json(force=True) parameter_values = collect_parameters_from_request(request.args) query = params['query'] max_age = int(params.get('max_age', -1)) query_id = params.get('query_id', 'adhoc') data_source = models.DataSource.get_by_id_and_org( params.get('data_source_id'), self.current_org) if not has_access(data_source.groups, self.current_user, not_view_only): return { 'job': { 'status': 4, 'error': 'You do not have permission to run queries with this data source.' } }, 403 if settings.REMOTE_RESOURCE_RESTRICTION_ENABLED and remote_resource_restriction( parameter_values, self.current_user, request): return { 'job': { 'status': 4, 'error': 'You have a remote resource restriction on the provided parameters.' } }, 403 self.record_event({ 'action': 'execute_query', 'timestamp': int(time.time()), 'object_id': data_source.id, 'object_type': 'data_source', 'query': query }) try: return run_query(data_source, parameter_values, query, query_id, max_age) except jwt.ExpiredSignatureError: return { 'job': { 'status': 4, 'error': 'Your authentication credentials have expired, please re-login.', 'provider': settings.REMOTE_JWT_EXPIRED_ENDPOINT + urllib.quote_plus(request.referrer or settings.ROOT_UI_URL) } }, 401
def test_allows_if_user_member_in_group_with_view_access(self): user = MockUser([], [1], False) self.assertTrue(has_access({1: view_only}, user, view_only))
def test_allows_if_user_member_in_group_with_full_access(self): user = MockUser([], [1]) self.assertTrue(has_access({1: not view_only}, user, not view_only))
def test_allows_admin_regardless_of_groups(self): user = MockUser(['admin'], []) self.assertTrue(has_access({}, user, view_only)) self.assertTrue(has_access({}, user, not view_only))
def test_allows_embed_with_view_access(self): user = MockUser([], [], True) self.assertTrue(has_access({}, user, view_only))
def serialize_dashboard(obj, with_widgets=False, user=None, with_favorite_state=True): layout = json_loads(obj.layout) widgets = [] if with_widgets: for w in obj.widgets: if w.visualization_id is None: widgets.append(serialize_widget(w)) elif user and has_access(w.visualization.query_rel, user, view_only): widgets.append(serialize_widget(w)) # NOTE(jinlong): 判断当前分享的dashboard的组是否在当前访问用户所在的组里. user_groups = user.group_ids dash_group = obj.group_id if dash_group not in user_groups: widget = project( serialize_widget(w), ( "id", "width", "dashboard_id", "options", "created_at", "updated_at", ), ) widget["restricted"] = True widget["err_infos"] = "没有dashboard所在组权限, 无法查看!" widgets.append(widget) else: widgets.append(serialize_widget(w)) else: widget = project( serialize_widget(w), ( "id", "width", "dashboard_id", "options", "created_at", "updated_at", ), ) widget["restricted"] = True widgets.append(widget) else: widgets = None d = { "id": obj.id, "slug": obj.slug, "name": obj.name, "user_id": obj.user_id, # TODO: we should properly load the users "user": obj.user.to_dict(), "layout": layout, "dashboard_filters_enabled": obj.dashboard_filters_enabled, "widgets": widgets, "is_archived": obj.is_archived, "is_draft": obj.is_draft, "tags": obj.tags or [], # TODO: bulk load favorites "updated_at": obj.updated_at, "created_at": obj.created_at, "version": obj.version, "group_name": "", "creator": obj.user.to_dict().get("name"), } # NOTE(jinlong): dashboard展示列表时添加group_name和crator group_id = obj.group_id if group_id: group_obj = models.Group.query.get(group_id) d['group_name'] = group_obj.name if with_favorite_state: d["is_favorite"] = models.Favorite.is_favorite(current_user.id, obj) return d
def test_doesnt_allow_access_to_query_by_different_api_key(self): query = self.factory.create_query() other_query = self.factory.create_query() user = models.ApiUser(other_query.api_key, None, []) self.assertFalse(has_access(query, user, view_only))
def test_allows_access_to_query_by_query_api_key(self): query = self.factory.create_query() user = models.ApiUser(query.api_key, None, []) self.assertTrue(has_access(query, user, view_only))