def post(self, data_source_id): req = request.get_json(True) if req: if not req.has_key("type"): abort(400) if req["type"] == "column": data_source = get_object_or_404(models.DataSourceColumn.get_by_id, data_source_id) elif req["type"] == "table": data_source = get_object_or_404(models.DataSourceTable.get_by_id, data_source_id) else: abort(400) if req["type"] == "column" and req.has_key("joins"): data_source.joins = req["joins"] if req.has_key("description"): data_source.description = req["description"] if req.has_key("tags"): data_source.tags = req["tags"] data_source.save() return data_source.to_dict(all=True) else: abort(400)
def get(self, query_id=None, query_result_id=None, filetype='json'): # TODO: # This method handles two cases: retrieving result by id & retrieving result by query id. # They need to be split, as they have different logic (for example, retrieving by query id # should check for query parameters and shouldn't cache the result). should_cache = query_result_id is not None if query_result_id is None and query_id is not None: query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) if query: query_result_id = query._data['latest_query_data'] if query_result_id: query_result = get_object_or_404(models.QueryResult.get_by_id_and_org, query_result_id, self.current_org) else: query_result = None if query_result: require_access(query_result.data_source.groups, self.current_user, view_only) if isinstance(self.current_user, models.ApiUser): event = { 'user_id': None, 'org_id': self.current_org.id, 'action': 'api_get', 'timestamp': int(time.time()), 'api_key': self.current_user.name, 'file_type': filetype, 'user_agent': request.user_agent.string, 'ip': request.remote_addr } if query_id: event['object_type'] = 'query' event['object_id'] = query_id else: event['object_type'] = 'query_result' event['object_id'] = query_result_id record_event.delay(event) if filetype == 'json': response = self.make_json_response(query_result) elif filetype == 'xlsx': response = self.make_excel_response(query_result) else: response = self.make_csv_response(query_result) if len(settings.ACCESS_CONTROL_ALLOW_ORIGIN) > 0: self.add_cors_headers(response.headers) if should_cache: response.headers.add_header('Cache-Control', 'max-age=%d' % ONE_YEAR) return response else: abort(404, message='No cached result found for this query.')
def get(self, query_id, dropdown_query_id): query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) require_access(query, current_user, view_only) related_queries_ids = [p['queryId'] for p in query.parameters if p['type'] == 'query'] if int(dropdown_query_id) not in related_queries_ids: dropdown_query = get_object_or_404(models.Query.get_by_id_and_org, dropdown_query_id, self.current_org) require_access(dropdown_query.data_source, current_user, view_only) return dropdown_values(dropdown_query_id)
def post(self, object_type, object_id): model = get_model_from_type(object_type) obj = get_object_or_404(model.get_by_id_and_org, object_id, self.current_org) require_admin_or_owner(obj.user_id) req = request.get_json(True) access_type = req['access_type'] if access_type not in ACCESS_TYPES: abort(400, message='Unknown access type.') try: grantee = User.get_by_id_and_org(req['user_id'], self.current_org) except User.DoesNotExist: abort(400, message='User not found.') permission = AccessPermission.grant(obj, access_type, grantee, self.current_user) self.record_event({ 'action': 'grant_permission', 'object_id': object_id, 'object_type': object_type, 'access_type': access_type, 'grantee': grantee.id }) return permission.to_dict()
def post(self, query_id): query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) query_def = request.get_json(force=True) require_object_modify_permission(query, self.current_user) for field in ['id', 'created_at', 'api_key', 'visualizations', 'latest_query_data', 'user', 'last_modified_by', 'org']: query_def.pop(field, None) if 'latest_query_data_id' in query_def: query_def['latest_query_data'] = query_def.pop('latest_query_data_id') if 'data_source_id' in query_def: query_def['data_source'] = query_def.pop('data_source_id') query_def['last_modified_by'] = self.current_user query_def['changed_by'] = self.current_user try: query.update_instance(**query_def) except models.ConflictDetectedError: abort(409) # old_query = copy.deepcopy(query.to_dict()) # new_change = query.update_instance_tracked(changing_user=self.current_user, old_object=old_query, **query_def) # abort(409) # HTTP 'Conflict' status code result = query.to_dict(with_visualizations=True) return result
def public_dashboard(token, org_slug=None): # TODO: verify object is a dashboard? if not isinstance(current_user, models.ApiUser): api_key = get_object_or_404(models.ApiKey.get_by_api_key, token) dashboard = api_key.object else: dashboard = current_user.object user = { 'permissions': [], 'apiKey': current_user.id } headers = { 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate' } record_event(current_org, current_user, { 'action': 'view', 'object_id': dashboard.id, 'object_type': 'dashboard', 'public': True, 'headless': 'embed' in request.args, 'referer': request.headers.get('Referer') }) response = render_template("public.html", headless='embed' in request.args, user=json.dumps(user), seed_data=json_dumps({ 'dashboard': serializers.public_dashboard(dashboard) }), client_config=json.dumps(settings.COMMON_CLIENT_CONFIG)) return response, 200, headers
def get(self, data_source_id): data_source = get_object_or_404(models.DataSource.get_by_id_and_org, data_source_id, self.current_org) require_access(data_source.groups, self.current_user, view_only) refresh = request.args.get('refresh') is not None schema = data_source.get_schema(refresh) return schema
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 get(self, object_type, object_id, access_type): model = get_model_from_type(object_type) obj = get_object_or_404(model.get_by_id_and_org, object_id, self.current_org) has_access = AccessPermission.exists(obj, access_type, self.current_user) return {'response': has_access}
def get(self, query_id): q = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) require_access(q.groups, self.current_user, view_only) result = q.to_dict(with_visualizations=True) result['can_edit'] = can_modify(q, self.current_user) return result
def post(self, query_id): query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) require_access(query.groups, self.current_user, not_view_only) parameter_values = collect_parameters_from_request(request.args) return run_query(query.data_source, parameter_values, query.query, query.id)
def get(self, query_id=None, query_result_id=None, filetype='json'): should_cache = query_result_id is not None if query_result_id is None and query_id is not None: query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) if query: query_result_id = query._data['latest_query_data'] if query_result_id: query_result = get_object_or_404(models.QueryResult.get_by_id_and_org, query_result_id, self.current_org) if query_result: if isinstance(self.current_user, models.ApiUser): event = { 'user_id': None, 'org_id': self.current_org.id, 'action': 'api_get', 'timestamp': int(time.time()), 'api_key': self.current_user.id, 'file_type': filetype } if query_id: event['object_type'] = 'query' event['object_id'] = query_id else: event['object_type'] = 'query_result' event['object_id'] = query_result_id record_event.delay(event) if filetype == 'json': response = self.make_json_response(query_result) elif filetype == 'xlsx': response = self.make_excel_response(query_result) else: response = self.make_csv_response(query_result) if len(settings.ACCESS_CONTROL_ALLOW_ORIGIN) > 0: self.add_cors_headers(response.headers) if should_cache: response.headers.add_header('Cache-Control', 'max-age=%d' % ONE_YEAR) return response else: abort(404)
def get(self, query_id, dropdown_query_id): query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) related_queries_ids = [p['queryId'] for p in query.parameters if p['type'] == 'query'] if int(dropdown_query_id) not in related_queries_ids: abort(403) return dropdown_values(dropdown_query_id, should_require_access=False)
def get(self, query_id): q = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) require_access(q.groups, self.current_user, view_only) if q: return q.to_dict(with_visualizations=True) else: abort(404, message="Query not found.")
def post(self, join_id): join = get_object_or_404(models.DataSourceJoin.get_by_id, join_id) kwargs = request.get_json(True) join.update_instance(**kwargs) return join.to_dict(all=True)
def get(self, group_id): group = get_object_or_404(models.Group.get_by_id_and_org, group_id, self.current_org) # TOOD: move to models data_sources = models.DataSource.select(models.DataSource, models.DataSourceGroup.view_only)\ .join(models.DataSourceGroup)\ .where(models.DataSourceGroup.group == group) return [ds.to_dict(with_permissions=True) for ds in data_sources]
def delete(self, object_id): dashboard = get_object_or_404(models.Dashboard.get_by_slug_and_org, object_id, self.current_org) models.Favorite.query.filter(models.Favorite.object==dashboard, models.Favorite.user==self.current_user).delete() models.db.session.commit() self.record_event({ 'action': 'unfavorite', 'object_id': dashboard.id, 'object_type': 'dashboard' })
def post(self, data_source_id): data_source = get_object_or_404(models.DataSource.get_by_id_and_org, data_source_id, self.current_org) try: data_source.query_runner.test_connection() except Exception as e: return {"message": unicode(e), "ok": False} else: return {"message": "success", "ok": True}
def delete(self, snippet_id): snippet = get_object_or_404(models.QuerySnippet.get_by_id_and_org, snippet_id, self.current_org) require_admin_or_owner(snippet.user.id) snippet.delete_instance() self.record_event({ 'action': 'delete', 'object_id': snippet.id, 'object_type': 'query_snippet' })
def delete(self, visualization_id): vis = get_object_or_404(models.Visualization.get_by_id_and_org, visualization_id, self.current_org) require_object_modify_permission(vis.query_rel, self.current_user) self.record_event({ 'action': 'delete', 'object_id': visualization_id, 'object_type': 'Visualization' }) models.db.session.delete(vis) models.db.session.commit()
def delete(self, data_source_id): data_source = get_object_or_404(models.DataSource.get_by_id_and_org, data_source_id, self.current_org) data_source.resume() self.record_event({ 'action': 'resume', 'object_id': data_source.id, 'object_type': 'datasource' }) return data_source.to_dict()
def get(self, dashboard_slug=None): dashboard = get_object_or_404(models.Dashboard.get_by_slug_and_org, dashboard_slug, self.current_org) response = dashboard.to_dict(with_widgets=True, user=self.current_user) api_key = models.ApiKey.get_by_object(dashboard) if api_key: response['public_url'] = url_for('redash.public_dashboard', token=api_key.api_key, org_slug=self.current_org.slug, _external=True) response['api_key'] = api_key.api_key return response
def get(self, group_id): group = get_object_or_404(models.Group.get_by_id_and_org, group_id, self.current_org) # TOOD: move to models data_sources = (models.DataSource.query .join(models.DataSourceGroup) .filter(models.DataSourceGroup.group == group)) return [ds.to_dict(with_permissions_for=group) for ds in data_sources]
def delete(self, query_id): """ Archives a query. :param query_id: ID of query to archive """ query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) require_admin_or_owner(query.user_id) query.archive(self.current_user) models.db.session.commit()
def get(self, user_id): require_permission_or_owner('list_users', user_id) user = get_object_or_404(models.User.get_by_id_and_org, user_id, self.current_org) self.record_event({ 'action': 'view', 'object_id': user_id, 'object_type': 'user', }) return user.to_dict(with_api_key=is_admin_or_owner(user_id))
def get(self, snippet_id): snippet = get_object_or_404(models.QuerySnippet.get_by_id_and_org, snippet_id, self.current_org) self.record_event({ 'action': 'view', 'object_id': snippet_id, 'object_type': 'query_snippet', }) return snippet.to_dict()
def post(self, query_id): """ Creates a new query, copying the query text from an existing one. :param query_id: ID of query to fork Responds with created :ref:`query <query-response-label>` object. """ query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) forked_query = query.fork(self.current_user) models.db.session.commit() return forked_query.to_dict(with_visualizations=True)
def delete(self, alert_id, subscriber_id): subscription = get_object_or_404(models.AlertSubscription.get_by_id, subscriber_id) require_admin_or_owner(subscription.user.id) subscription.delete_instance() self.record_event({ 'action': 'unsubscribe', 'timestamp': int(time.time()), 'object_id': alert_id, 'object_type': 'alert' })
def post(self): kwargs = request.get_json(force=True) query = get_object_or_404(models.Query.get_by_id_and_org, kwargs.pop('query_id'), self.current_org) require_admin_or_owner(query.user_id) kwargs['options'] = json.dumps(kwargs['options']) kwargs['query'] = query vis = models.Visualization.create(**kwargs) return vis.to_dict(with_query=False)
def post(self): kwargs = request.get_json(force=True) query = get_object_or_404(models.Query.get_by_id_and_org, kwargs.pop('query_id'), self.current_org) require_object_modify_permission(query, self.current_user) kwargs['options'] = json_dumps(kwargs['options']) kwargs['query_rel'] = query vis = models.Visualization(**kwargs) models.db.session.add(vis) models.db.session.commit() return serialize_visualization(vis, with_query=False)
def get(self, dashboard_id=None): """ Retrieves a dashboard. :qparam number id: Id of dashboard to retrieve. .. _dashboard-response-label: :>json number id: Dashboard ID :>json string name: :>json string slug: :>json number user_id: ID of the dashboard creator :>json string created_at: ISO format timestamp for dashboard creation :>json string updated_at: ISO format timestamp for last dashboard modification :>json number version: Revision number of dashboard :>json boolean dashboard_filters_enabled: Whether filters are enabled or not :>json boolean is_archived: Whether this dashboard has been removed from the index or not :>json boolean is_draft: Whether this dashboard is a draft or not. :>json array layout: Array of arrays containing widget IDs, corresponding to the rows and columns the widgets are displayed in :>json array widgets: Array of arrays containing :ref:`widget <widget-response-label>` data .. _widget-response-label: Widget structure: :>json number widget.id: Widget ID :>json number widget.width: Widget size :>json object widget.options: Widget options :>json number widget.dashboard_id: ID of dashboard containing this widget :>json string widget.text: Widget contents, if this is a text-box widget :>json object widget.visualization: Widget contents, if this is a visualization widget :>json string widget.created_at: ISO format timestamp for widget creation :>json string widget.updated_at: ISO format timestamp for last widget modification """ if request.args.get("legacy") is not None: fn = models.Dashboard.get_by_slug_and_org else: fn = models.Dashboard.get_by_id_and_org dashboard = get_object_or_404(fn, dashboard_id, self.current_org) response = DashboardSerializer( dashboard, with_widgets=True, user=self.current_user ).serialize() api_key = models.ApiKey.get_by_object(dashboard) if api_key: response["public_url"] = url_for( "redash.public_dashboard", token=api_key.api_key, org_slug=self.current_org.slug, _external=True, ) response["api_key"] = api_key.api_key response["can_edit"] = can_modify(dashboard, self.current_user) self.record_event( {"action": "view", "object_id": dashboard.id, "object_type": "dashboard"} ) return response
def delete(self, visualization_id): vis = get_object_or_404(models.Visualization.get_by_id_and_org, visualization_id, self.current_org) require_admin_or_owner(vis.query_rel.user_id) models.db.session.delete(vis) models.db.session.commit()
def post(self): """ Create a new query. :<json number data_source_id: The ID of the data source this query will run on :<json string query: Query text :<json string name: :<json string description: :<json string schedule: Schedule interval, in seconds, for repeated execution of this query :<json object options: Query options .. _query-response-label: :>json number id: Query ID :>json number latest_query_data_id: ID for latest output data from this query :>json string name: :>json string description: :>json string query: Query text :>json string query_hash: Hash of query text :>json string schedule: Schedule interval, in seconds, for repeated execution of this query :>json string api_key: Key for public access to this query's results. :>json boolean is_archived: Whether this query is displayed in indexes and search results or not. :>json boolean is_draft: Whether this query is a draft or not :>json string updated_at: Time of last modification, in ISO format :>json string created_at: Time of creation, in ISO format :>json number data_source_id: ID of the data source this query will run on :>json object options: Query options :>json number version: Revision version (for update conflict avoidance) :>json number user_id: ID of query creator :>json number last_modified_by_id: ID of user who last modified this query :>json string retrieved_at: Time when query results were last retrieved, in ISO format (may be null) :>json number runtime: Runtime of last query execution, in seconds (may be null) """ query_def = request.get_json(force=True) LOG.info('** receive queries create param: %s' % query_def) group = query_def.pop('group') group_ref = models.Group.query\ .filter(models.Group.name == group)\ .first() query_obj = None query_id = query_def.pop('query_id', None) if query_id: query_obj = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) data_source = models.DataSource.get_by_id_and_org( query_def.pop("data_source_id"), self.current_org) require_access(data_source, self.current_user, not_view_only) require_access_to_dropdown_queries(self.current_user, query_def) for field in [ "id", "created_at", "api_key", "visualizations", "latest_query_data", "last_modified_by", ]: query_def.pop(field, None) if query_obj: for field in ["user", "org"]: query_def.pop(field, None) if "query" in query_def: query_def["query_text"] = query_def.pop("query") if "tags" in query_def: query_def["tags"] = [tag for tag in query_def["tags"] if tag] query_def["last_modified_by"] = self.current_user query_def["changed_by"] = self.current_user if "version" in query_def and query_def[ "version"] != query_obj.version: abort(409) try: self.update_model(query_obj, query_def) query_obj.group_id = group_ref.id models.db.session.commit() except StaleDataError: abort(409) query = query_obj else: query_def["query_text"] = query_def.pop("query") query_def["user"] = self.current_user query_def["data_source"] = data_source query_def["org"] = self.current_org query_def["is_draft"] = True query_def["group_id"] = group_ref.id LOG.info('** handle queries query ref data: %s' % query_def) query = models.Query.create(**query_def) models.db.session.add(query) models.db.session.commit() self.record_event({ "action": "create", "object_id": query.id, "object_type": "query" }) return QuerySerializer(query, with_visualizations=True).serialize()
def delete(self, alert_id): alert = get_object_or_404(models.Alert.get_by_id_and_org, alert_id, self.current_org) require_admin_or_owner(alert.user_id) models.db.session.delete(alert) models.db.session.commit()
def get(self, user_id): require_permission_or_owner('list_users', user_id) user = get_object_or_404(models.User.get_by_id_and_org, user_id, self.current_org) return user.to_dict(with_api_key=is_admin_or_owner(user_id))
def get(self, query_id=None, query_result_id=None, filetype='json'): """ Retrieve query results. :param number query_id: The ID of the query whose results should be fetched :param number query_result_id: the ID of the query result to fetch :param string filetype: Format to return. One of 'json', 'xlsx', or 'csv'. Defaults to 'json'. :<json number id: Query result ID :<json string query: Query that produced this result :<json string query_hash: Hash code for query text :<json object data: Query output :<json number data_source_id: ID of data source that produced this result :<json number runtime: Length of execution time in seconds :<json string retrieved_at: Query retrieval date/time, in ISO format """ # TODO: # This method handles two cases: retrieving result by id & retrieving result by query id. # They need to be split, as they have different logic (for example, retrieving by query id # should check for query parameters and shouldn't cache the result). should_cache = query_result_id is not None parameter_values = collect_parameters_from_request(request.args) max_age = int(request.args.get('maxAge', 0)) query_result = None query = None if query_result_id: query_result = get_object_or_404( models.QueryResult.get_by_id_and_org, query_result_id, self.current_org) if query_id is not None: query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) if query_result is None and query is not None and query.latest_query_data_id is not None: query_result = get_object_or_404( models.QueryResult.get_by_id_and_org, query.latest_query_data_id, self.current_org) if query is not None and query_result is not None and self.current_user.is_api_user( ): if query.query_hash != query_result.query_hash: abort(404, message='No cached result found for this query.') if query_result: require_access(query_result.data_source, self.current_user, view_only) if isinstance(self.current_user, models.ApiUser): event = { 'user_id': None, 'org_id': self.current_org.id, 'action': 'api_get', 'api_key': self.current_user.name, 'file_type': filetype, 'user_agent': request.user_agent.string, 'ip': request.remote_addr } if query_id: event['object_type'] = 'query' event['object_id'] = query_id else: event['object_type'] = 'query_result' event['object_id'] = query_result_id self.record_event(event) if filetype == 'json': response = self.make_json_response(query_result) elif filetype == 'xlsx': response = self.make_excel_response(query_result) else: response = self.make_csv_response(query_result) if len(settings.ACCESS_CONTROL_ALLOW_ORIGIN) > 0: self.add_cors_headers(response.headers) if should_cache: response.headers.add_header('Cache-Control', 'private,max-age=%d' % ONE_YEAR) filename = get_download_filename(query_result, query, filetype) response.headers.add_header( "Content-Disposition", 'attachment; filename="{}"'.format(filename.encode("utf-8"))) return response else: abort(404, message='No cached result found for this query.')
def get(self, data_source_id): data_source = get_object_or_404(models.DataSource.get_by_id_and_org, data_source_id, self.current_org) schema = data_source.get_schema() return schema
def get(self, alert_id): alert = get_object_or_404(models.Alert.get_by_id_and_org, alert_id, self.current_org) require_access(alert.groups, self.current_user, view_only) return alert.to_dict()
def get(self, snippet_id): snippet = get_object_or_404(models.QuerySnippet.get_by_id_and_org, snippet_id, self.current_org) return snippet.to_dict()
def get(self, query_id=None, query_result_id=None, filetype="json"): """ Retrieve query results. :param number query_id: The ID of the query whose results should be fetched :param number query_result_id: the ID of the query result to fetch :param string filetype: Format to return. One of 'json', 'xlsx', or 'csv'. Defaults to 'json'. :<json number id: Query result ID :<json string query: Query that produced this result :<json string query_hash: Hash code for query text :<json object data: Query output :<json number data_source_id: ID of data source that produced this result :<json number runtime: Length of execution time in seconds :<json string retrieved_at: Query retrieval date/time, in ISO format """ # TODO: # This method handles two cases: retrieving result by id & retrieving result by query id. # They need to be split, as they have different logic (for example, retrieving by query id # should check for query parameters and shouldn't cache the result). should_cache = query_result_id is not None query_result = None query = None if query_result_id: query_result = get_object_or_404( models.QueryResult.get_by_id_and_org, query_result_id, self.current_org) if query_id is not None: query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) if (query_result is None and query is not None and query.latest_query_data_id is not None): query_result = get_object_or_404( models.QueryResult.get_by_id_and_org, query.latest_query_data_id, self.current_org, ) if (query is not None and query_result is not None and self.current_user.is_api_user()): if query.query_hash != query_result.query_hash: abort(404, message="No cached result found for this query.") if query_result: require_access(query_result.data_source, self.current_user, view_only) if isinstance(self.current_user, models.ApiUser): event = { "user_id": None, "org_id": self.current_org.id, "action": "api_get", "api_key": self.current_user.name, "file_type": filetype, "user_agent": request.user_agent.string, "ip": request.remote_addr, } if query_id: event["object_type"] = "query" event["object_id"] = query_id else: event["object_type"] = "query_result" event["object_id"] = query_result_id self.record_event(event) response_builders = { "json": self.make_json_response, "xlsx": self.make_excel_response, "csv": self.make_csv_response, "tsv": self.make_tsv_response, } response = response_builders[filetype](query_result) if len(settings.ACCESS_CONTROL_ALLOW_ORIGIN) > 0: self.add_cors_headers(response.headers) if should_cache: response.headers.add_header("Cache-Control", "private,max-age=%d" % ONE_YEAR) filename = get_download_filename(query_result, query, filetype) filenames = content_disposition_filenames(filename) response.headers.add("Content-Disposition", "attachment", **filenames) return response else: abort(404, message="No cached result found for this query.")
def delete(self, visualization_id): vis = get_object_or_404(models.Visualization.get_by_id_and_org, visualization_id, self.current_org) require_object_modify_permission(vis.query_rel, self.current_user) models.db.session.delete(vis) models.db.session.commit()
def delete(self, query_id): query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) require_admin_or_owner(query.user_id) query.archive(self.current_user)