def record_event(self, options): options.update({ 'user_id': self.current_user.id, 'org_id': self.current_org.id }) record_event.delay(options)
def post(self): req = request.get_json(True) required_fields = ("options", "name", "query_id") for f in required_fields: if f not in req: abort(400) alert = models.Alert.create( name=req["name"], query=req["query_id"], user=self.current_user, options=req["options"] ) record_event.delay( { "user_id": self.current_user.id, "action": "create", "timestamp": int(time.time()), "object_id": alert.id, "object_type": "alert", } ) # TODO: should be in model? models.AlertSubscription.create(alert=alert, user=self.current_user) record_event.delay( { "user_id": self.current_user.id, "action": "subscribe", "timestamp": int(time.time()), "object_id": alert.id, "object_type": "alert", } ) return alert.to_dict()
def record_event(org, user, options): if user.is_api_user(): options.update({ 'api_key': user.name, 'org_id': org.id }) else: if isinstance(user.id, int): user_id = user.id else: user_id = 1 options.update({ 'user_id': user_id, 'org_id': org.id }) options.update({ 'user_agent': request.user_agent.string, 'ip': request.remote_addr }) if 'timestamp' not in options: options['timestamp'] = int(time.time()) record_event_task.delay(options)
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) 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)
def post(self): req = request.get_json(True) require_fields(req, ('options', 'name', 'query_id')) alert = models.Alert.create( name=req['name'], query=req['query_id'], user=self.current_user, options=req['options'] ) record_event.delay({ 'user_id': self.current_user.id, 'action': 'create', 'timestamp': int(time.time()), 'object_id': alert.id, 'object_type': 'alert' }) # TODO: should be in model? models.AlertSubscription.create(alert=alert, user=self.current_user) record_event.delay({ 'user_id': self.current_user.id, 'action': 'subscribe', 'timestamp': int(time.time()), 'object_id': alert.id, 'object_type': 'alert' }) return alert.to_dict()
def post(self): req = request.get_json(True) require_fields(req, ('options', 'name', 'query_id')) alert = models.Alert.create(name=req['name'], query=req['query_id'], user=self.current_user, options=req['options']) record_event.delay({ 'user_id': self.current_user.id, 'action': 'create', 'timestamp': int(time.time()), 'object_id': alert.id, 'object_type': 'alert' }) # TODO: should be in model? models.AlertSubscription.create(alert=alert, user=self.current_user) record_event.delay({ 'user_id': self.current_user.id, 'action': 'subscribe', 'timestamp': int(time.time()), 'object_id': alert.id, 'object_type': 'alert' }) return alert.to_dict()
def post(self): # TODO: send invite. req = request.get_json(force=True) require_fields(req, ("name", "email", "password")) user = models.User(name=req["name"], email=req["email"]) user.hash_password(req["password"]) try: user.save() except IntegrityError as e: if "email" in e.message: abort(400, message="Email already taken.") abort(500) record_event.delay( { "user_id": self.current_user.id, "action": "create", "timestamp": int(time.time()), "object_id": user.id, "object_type": "user", } ) return user.to_dict()
def log_user_logged_in(app, user): event = { 'user_id': user.id, 'action': 'login', 'object_type': 'redash', 'timestamp': int(time.time()), } record_event.delay(event)
def delete(self, alert_id, subscriber_id): models.AlertSubscription.unsubscribe(alert_id, subscriber_id) record_event.delay({ 'user_id': self.current_user.id, 'action': 'unsubscribe', 'timestamp': int(time.time()), 'object_id': alert_id, 'object_type': 'alert' })
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 post(self, alert_id): subscription = models.AlertSubscription.create(alert=alert_id, user=self.current_user) record_event.delay({ 'user_id': self.current_user.id, 'action': 'subscribe', 'timestamp': int(time.time()), 'object_id': alert_id, 'object_type': 'alert' }) return subscription.to_dict()
def delete(self, alert_id, subscriber_id): models.AlertSubscription.unsubscribe(alert_id, subscriber_id) record_event.delay( { "user_id": self.current_user.id, "action": "unsubscribe", "timestamp": int(time.time()), "object_id": alert_id, "object_type": "alert", } )
def log_user_logged_in(app, user): event = { "org_id": user.org_id, "user_id": user.id, "action": "login", "object_type": "redash", "timestamp": int(time.time()), "user_agent": request.user_agent.string, "ip": request.remote_addr, } record_event.delay(event)
def record_event(org, user, options): if isinstance(user, ApiUser): options.update({"api_key": user.name, "org_id": org.id}) else: options.update({"user_id": user.id, "org_id": org.id}) options.update({"user_agent": request.user_agent.string, "ip": request.remote_addr}) if "timestamp" not in options: options["timestamp"] = int(time.time()) record_event_task.delay(options)
def log_user_logged_in(app, user): event = { 'org_id': current_org.id, 'user_id': user.id, 'action': 'login', 'object_type': 'redash', 'timestamp': int(time.time()), 'user_agent': request.user_agent.string, 'ip': request.remote_addr } record_event.delay(event)
def record_event(org, user, options): if user.is_api_user(): options.update({"api_key": user.name, "org_id": org.id}) else: options.update({"user_id": user.id, "user_name": user.name, "org_id": org.id}) options.update({"user_agent": request.user_agent.string, "ip": request.remote_addr}) if "timestamp" not in options: options["timestamp"] = int(time.time()) record_event_task.delay(options)
def log_user_logged_in(app, user): event = { 'org_id': user.org_id, 'user_id': user.id, 'action': 'login', 'object_type': 'redash', 'timestamp': int(time.time()), 'user_agent': request.user_agent.string, 'ip': request.remote_addr } record_event.delay(event)
def post(self, alert_id): subscription = models.AlertSubscription.create(alert=alert_id, user=self.current_user) record_event.delay( { "user_id": self.current_user.id, "action": "subscribe", "timestamp": int(time.time()), "object_id": alert_id, "object_type": "alert", } ) return subscription.to_dict()
def record_event(self, options): if isinstance(self.current_user, ApiUser): options.update({ 'api_key': self.current_user.id, 'org_id': self.current_org.id }) else: options.update({ 'user_id': self.current_user.id, 'org_id': self.current_org.id }) record_event.delay(options)
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=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 log_user_logged_in(app, user): event = { 'org_id': current_org.id, 'user_id': user.id, 'action': 'login', 'object_type': 'redash', 'timestamp': int(time.time()), 'user_agent': request.user_agent.string, 'ip': request.remote_addr } logging.debug("Old value of last_logged_at %s", user.last_logged_at) logging.debug("New value of last_logged_at %s", datetime.now(pytz.UTC)) user.last_logged_at = datetime.now(pytz.UTC) models.db.session.add(user) models.db.session.commit() record_event.delay(event)
def post(self, alert_id): req = request.get_json(True) params = project(req, ('options', 'name', 'query_id')) alert = models.Alert.get_by_id(alert_id) if 'query_id' in params: params['query'] = params.pop('query_id') alert.update_instance(**params) record_event.delay({ 'user_id': self.current_user.id, 'action': 'edit', 'timestamp': int(time.time()), 'object_id': alert.id, 'object_type': 'alert' }) return alert.to_dict()
def post(self, user_id): require_admin_or_owner(user_id) user = models.User.get_by_id(user_id) req = request.get_json(True) params = project(req, ("email", "name", "password", "old_password", "groups")) if "password" in params and "old_password" not in params: abort(403, message="Must provide current password to update password.") if "old_password" in params and not user.verify_password(params["old_password"]): abort(403, message="Incorrect current password.") if "password" in params: user.hash_password(params.pop("password")) params.pop("old_password") if "groups" in params and not self.current_user.has_permission("admin"): abort(403, message="Must be admin to change groups membership.") try: user.update_instance(**params) except IntegrityError as e: if "email" in e.message: message = "Email already taken." else: message = "Error updating record" abort(400, message=message) record_event.delay( { "user_id": self.current_user.id, "action": "edit", "timestamp": int(time.time()), "object_id": user.id, "object_type": "user", "updated_fields": params.keys(), } ) 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'): if query_result_id is None and query_id is not None: query = models.Query.get(models.Query.id == query_id) if query: query_result_id = query._data['latest_query_data'] if query_result_id: query_result = models.QueryResult.get_by_id(query_result_id) if query_result: if isinstance(self.current_user, models.ApiUser): event = { 'user_id': None, '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) headers = {} if len(settings.ACCESS_CONTROL_ALLOW_ORIGIN) > 0: self.add_cors_headers(headers) if filetype == 'json': data = json.dumps({'query_result': query_result.to_dict()}, cls=utils.JSONEncoder) headers.update(cache_headers) return make_response(data, 200, headers) else: return self.csv_response(query_result) else: abort(404)
def get(self, query_id=None, query_result_id=None, filetype="json"): if query_result_id is None and query_id is not None: query = models.Query.get(models.Query.id == query_id) if query: query_result_id = query._data["latest_query_data"] if query_result_id: query_result = models.QueryResult.get_by_id(query_result_id) if query_result: if isinstance(self.current_user, models.ApiUser): event = { "user_id": None, "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) headers = {} if len(settings.ACCESS_CONTROL_ALLOW_ORIGIN) > 0: self.add_cors_headers(headers) if filetype == "json": data = json.dumps({"query_result": query_result.to_dict()}, cls=utils.JSONEncoder) headers.update(cache_headers) return make_response(data, 200, headers) else: return self.csv_response(query_result) else: abort(404)
def post(self, alert_id): req = request.get_json(True) params = project(req, ("options", "name", "query_id")) alert = models.Alert.get_by_id(alert_id) if "query_id" in params: params["query"] = params.pop("query_id") alert.update_instance(**params) record_event.delay( { "user_id": self.current_user.id, "action": "edit", "timestamp": int(time.time()), "object_id": alert.id, "object_type": "alert", } ) return alert.to_dict()
def post(self, user_id): require_admin_or_owner(user_id) user = models.User.get_by_id(user_id) req = request.get_json(True) params = project(req, ('email', 'name', 'password', 'old_password', 'groups')) if 'password' in params and 'old_password' not in params: abort(403, message="Must provide current password to update password.") if 'old_password' in params and not user.verify_password(params['old_password']): abort(403, message="Incorrect current password.") if 'password' in params: user.hash_password(params.pop('password')) params.pop('old_password') if 'groups' in params and not self.current_user.has_permission('admin'): abort(403, message="Must be admin to change groups membership.") try: user.update_instance(**params) except IntegrityError as e: if "email" in e.message: message = "Email already taken." else: message = "Error updating record" abort(400, message=message) record_event.delay({ 'user_id': self.current_user.id, 'action': 'edit', 'timestamp': int(time.time()), 'object_id': user.id, 'object_type': 'user', 'updated_fields': params.keys() }) return user.to_dict(with_api_key=is_admin_or_owner(user_id))
def record_event(self, options): if isinstance(self.current_user, ApiUser): options.update({ 'api_key': self.current_user.id, 'org_id': self.current_org.id }) else: options.update({ 'user_id': self.current_user.id, 'org_id': self.current_org.id }) options.update({ 'user_agent': request.user_agent.string, 'ip': request.remote_addr }) if 'timestamp' not in options: options['timestamp'] = int(time.time()) record_event.delay(options)
def record_event(org, user, options): if isinstance(user, ApiUser): options.update({ 'api_key': user.name, 'org_id': org.id }) else: options.update({ 'user_id': user.id, 'org_id': org.id }) options.update({ 'user_agent': request.user_agent.string, 'ip': request.remote_addr }) if 'timestamp' not in options: options['timestamp'] = int(time.time()) record_event_task.delay(options)
def post(self): # TODO: send invite. req = request.get_json(force=True) require_fields(req, ('name', 'email', 'password')) user = models.User(name=req['name'], email=req['email']) user.hash_password(req['password']) try: user.save() except IntegrityError as e: if "email" in e.message: abort(400, message='Email already taken.') abort(500) record_event.delay({ 'user_id': self.current_user.id, 'action': 'create', 'timestamp': int(time.time()), 'object_id': user.id, 'object_type': 'user' }) return user.to_dict()
def post(self): events_list = request.get_json(force=True) for event in events_list: record_event.delay(event)
'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) query_result_dict = query_result.to_dict() # TODO saving again even saved queries - Solved # but correct way is through frontend js ... sepearate endpoint, here same string saved again as new query won't auto visualise # another bug ? if sql directly typed again - then auto visualize wont happen mapper = get_mappings() file_name = None saved_query_id = None for k in mapper: if (mapper[k][0] == query_result_dict['query']): file_name = mapper[k][1] query_text = mapper[k][2] #query_name = None
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 if query_result_id: query_result = get_object_or_404( models.QueryResult.get_by_id_and_org, query_result_id, self.current_org) # this is the table only result - a new one every time execute button is clicked # don't update this variable - can't call another func here cause we don't have query_id to update (maybe adhoc) 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) query_result_dict = query_result.to_dict() # TODO saving again even saved queries - Solved # but correct way is through frontend js ... sepearate endpoint, here same string saved again as new query won't auto visualise # another bug ? if sql directly typed again - then auto visualize wont happen mapper = get_mappings() file_name = None saved_query_id = None for k in mapper: if (mapper[k][0] == query_result_dict['query']): file_name = mapper[k][1] query_text = mapper[k][2] #query_name = None if file_name: if (not query_result.is_same_query(query_text, query_result.data_source)): # 1. save the query 2. get predefined visual json 3. add json to query object visualizations visualization_resource = VisualizationListResource() try: saved_query_id = visualization_resource.save_and_add_visual( query_result_dict, file_name, query_text) except Exception as e: abort(500, e.message) if saved_query_id: query_result_dict['query_id'] = saved_query_id if filetype == 'json': response = self.make_json_response(query_result_dict) 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=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 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: if settings.ALLOW_PARAMETERS_IN_EMBEDS and parameter_values: query_result = run_query_sync(query.data_source, parameter_values, query.query_text, max_age=max_age) elif 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.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', 'private,max-age=%d' % ONE_YEAR) return response else: abort(404, message='No cached result found for this query.')
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 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: if settings.ALLOW_PARAMETERS_IN_EMBEDS and parameter_values: query_result = run_query_sync(query.data_source, parameter_values, query.query_text, max_age=max_age) elif 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.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', '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', 'private,max-age=%d' % ONE_YEAR) return response else: abort(404, message='No cached result found for this query.')