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 post(self): """ Add a widget to a dashboard. :<json number dashboard_id: The ID for the dashboard being added to :<json visualization_id: The ID of the visualization to put in this widget :<json object options: Widget options :<json string text: Text box contents :<json number width: Width for widget display :>json object widget: The created widget """ widget_properties = request.get_json(force=True) dashboard = models.Dashboard.get_by_id_and_org(widget_properties.pop('dashboard_id'), self.current_org) require_object_modify_permission(dashboard, self.current_user) widget_properties['options'] = json.dumps(widget_properties['options']) widget_properties.pop('id', None) widget_properties['dashboard'] = dashboard visualization_id = widget_properties.pop('visualization_id') if visualization_id: visualization = models.Visualization.get_by_id_and_org(visualization_id, self.current_org) require_access(visualization.query_rel.groups, self.current_user, view_only) else: visualization = None widget_properties['visualization'] = visualization widget = models.Widget(**widget_properties) models.db.session.add(widget) models.db.session.commit() models.db.session.commit() return serialize_widget(widget)
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, widget_id): """ Remove a widget from a dashboard. :param number widget_id: ID of widget to remove """ widget = models.Widget.get_by_id_and_org(widget_id, self.current_org) require_object_modify_permission(widget.dashboard, self.current_user) models.db.session.delete(widget) models.db.session.commit()
def post(self): """ Add a widget to a dashboard. :<json number dashboard_id: The ID for the dashboard being added to :<json visualization_id: The ID of the visualization to put in this widget :<json object options: Widget options :<json string text: Text box contents :<json number width: Width for widget display :>json object widget: The created widget :>json array layout: The new layout of the dashboard this widget was added to :>json boolean new_row: Whether this widget was added on a new row or not :>json number version: The revision number of the dashboard """ widget_properties = request.get_json(force=True) dashboard = models.Dashboard.get_by_id_and_org(widget_properties.pop('dashboard_id'), self.current_org) require_object_modify_permission(dashboard, self.current_user) widget_properties['options'] = json.dumps(widget_properties['options']) widget_properties.pop('id', None) widget_properties['dashboard'] = dashboard visualization_id = widget_properties.pop('visualization_id') if visualization_id: visualization = models.Visualization.get_by_id_and_org(visualization_id, self.current_org) require_access(visualization.query_rel.groups, self.current_user, view_only) else: visualization = None widget_properties['visualization'] = visualization widget = models.Widget(**widget_properties) models.db.session.add(widget) models.db.session.commit() layout = json.loads(widget.dashboard.layout) new_row = True if len(layout) == 0 or widget.width == 2: layout.append([widget.id]) elif len(layout[-1]) == 1: neighbour_widget = models.Widget.query.get(layout[-1][0]) if neighbour_widget.width == 1: layout[-1].append(widget.id) new_row = False else: layout.append([widget.id]) else: layout.append([widget.id]) widget.dashboard.layout = json.dumps(layout) models.db.session.add(widget.dashboard) models.db.session.commit() return {'widget': widget.to_dict(), 'layout': layout, 'new_row': new_row, 'version': dashboard.version}
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 post(self, dashboard_slug): """ Modifies a dashboard. :qparam string slug: Slug of dashboard to retrieve. Responds with the updated :ref:`dashboard <dashboard-response-label>`. :status 200: success :status 409: Version conflict -- dashboard modified since last read """ dashboard_properties = request.get_json(force=True) # TODO: either convert all requests to use slugs or ids dashboard = models.Dashboard.get_by_id_and_org(dashboard_slug, self.current_org) require_object_modify_permission(dashboard, self.current_user) updates = project(dashboard_properties, ('name', 'layout', 'version', 'tags', 'is_draft', 'dashboard_filters_enabled')) # SQLAlchemy handles the case where a concurrent transaction beats us # to the update. But we still have to make sure that we're not starting # out behind. if 'version' in updates and updates['version'] != dashboard.version: abort(409) updates['changed_by'] = self.current_user self.update_model(dashboard, updates) models.db.session.add(dashboard) try: models.db.session.commit() except StaleDataError: models.db.session.rollback() abort(409) except IntegrityError: models.db.session.rollback() abort(400) result = serialize_dashboard(dashboard, with_widgets=True, user=self.current_user) self.record_event({ 'action': 'edit', 'object_id': dashboard.id, 'object_type': 'dashboard', }) return result
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() d = vis.to_dict(with_query=False) return d
def delete(self, widget_id): """ Remove a widget from a dashboard. :param number widget_id: ID of widget to remove :>json array layout: New layout of dashboard this widget was removed from :>json number version: Revision number of dashboard """ widget = models.Widget.get_by_id_and_org(widget_id, self.current_org) require_object_modify_permission(widget.dashboard, self.current_user) widget.delete() models.db.session.commit() return {'layout': widget.dashboard.layout, 'version': widget.dashboard.version}
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 post(self, query_id): """ Modify a query. :param query_id: ID of query to update :<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 Responds with the updated :ref:`query <query-response-label>` object. """ 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) require_access_to_dropdown_queries(self.current_user, query_def) for field in [ 'id', 'created_at', 'api_key', 'visualizations', 'latest_query_data', 'user', 'last_modified_by', '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'] = filter(None, query_def['tags']) query_def['last_modified_by'] = self.current_user query_def['changed_by'] = self.current_user # SQLAlchemy handles the case where a concurrent transaction beats us # to the update. But we still have to make sure that we're not starting # out behind. if 'version' in query_def and query_def['version'] != query.version: abort(409) try: self.update_model(query, query_def) models.db.session.commit() except StaleDataError: abort(409) return QuerySerializer(query, with_visualizations=True).serialize()
def post(self): widget_properties = request.get_json(force=True) dashboard = models.Dashboard.get_by_id_and_org( widget_properties.pop('dashboard_id'), self.current_org) require_object_modify_permission(dashboard, self.current_user) widget_properties['options'] = json.dumps(widget_properties['options']) widget_properties.pop('id', None) widget_properties['dashboard'] = dashboard visualization_id = widget_properties.pop('visualization_id') if visualization_id: visualization = models.Visualization.get_by_id_and_org( visualization_id, self.current_org) require_access(visualization.query_rel.groups, self.current_user, view_only) else: visualization = None widget_properties['visualization'] = visualization widget = models.Widget(**widget_properties) models.db.session.add(widget) models.db.session.commit() layout = json.loads(widget.dashboard.layout) new_row = True if len(layout) == 0 or widget.width == 2: layout.append([widget.id]) elif len(layout[-1]) == 1: neighbour_widget = models.Widget.query.get(layout[-1][0]) if neighbour_widget.width == 1: layout[-1].append(widget.id) new_row = False else: layout.append([widget.id]) else: layout.append([widget.id]) widget.dashboard.layout = json.dumps(layout) models.db.session.add(widget.dashboard) return { 'widget': widget.to_dict(), 'layout': layout, 'new_row': new_row, 'version': dashboard.version }
def delete(self, widget_id): """ Remove a widget from a dashboard. :param number widget_id: ID of widget to remove """ widget = models.Widget.get_by_id_and_org(widget_id, self.current_org) require_object_modify_permission(widget.dashboard, self.current_user) self.record_event({ 'action': 'delete', 'object_id': widget_id, 'object_type': 'widget', }) models.db.session.delete(widget) models.db.session.commit()
def delete(self, widget_id): """ Remove a widget from a dashboard. :param number widget_id: ID of widget to remove """ widget = models.Widget.get_by_id_and_org(widget_id, self.current_org) require_object_modify_permission(widget.dashboard, self.current_user) models.db.session.delete(widget) models.db.session.commit() self.record_event({ 'action': 'delete', 'object_id': widget_id, 'object_type': 'widget', })
def post(self, widget_id): """ Updates a widget in a dashboard. This method currently handles Text Box widgets only. :param number widget_id: The ID of the widget to modify :<json string text: The new contents of the text box """ widget = models.Widget.get_by_id_and_org(widget_id, self.current_org) require_object_modify_permission(widget.dashboard, self.current_user) widget_properties = request.get_json(force=True) widget.text = widget_properties['text'] models.db.session.commit() return widget.to_dict()
def post(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) kwargs = request.get_json(force=True) if 'options' in kwargs: kwargs['options'] = json_dumps(kwargs['options']) kwargs.pop('id', None) kwargs.pop('query_id', None) self.update_model(vis, kwargs) d = serialize_visualization(vis, with_query=False) models.db.session.commit() return d
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 post(self, dashboard_slug): dashboard_properties = request.get_json(force=True) # TODO: either convert all requests to use slugs or ids dashboard = models.Dashboard.get_by_id_and_org(dashboard_slug, self.current_org) require_object_modify_permission(dashboard, self.current_user) updates = project(dashboard_properties, ('name', 'layout', 'version')) updates['changed_by'] = self.current_user try: dashboard.update_instance(**updates) except ConflictDetectedError: abort(409) result = dashboard.to_dict(with_widgets=True, user=self.current_user) return result
def delete(self, widget_id): """ Remove a widget from a dashboard. :param number widget_id: ID of widget to remove :>json array layout: New layout of dashboard this widget was removed from :>json number version: Revision number of dashboard """ widget = models.Widget.get_by_id_and_org(widget_id, self.current_org) require_object_modify_permission(widget.dashboard, self.current_user) widget.delete() models.db.session.commit() return { 'layout': widget.dashboard.layout, 'version': widget.dashboard.version }
def post(self, query_id): """ Modify a query. :param query_id: ID of query to update :<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 Responds with the updated :ref:`query <query-response-label>` object. """ 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) require_access_to_dropdown_queries(self.current_user, query_def) for field in ['id', 'created_at', 'api_key', 'visualizations', 'latest_query_data', 'user', 'last_modified_by', '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'] = filter(None, query_def['tags']) query_def['last_modified_by'] = self.current_user query_def['changed_by'] = self.current_user # SQLAlchemy handles the case where a concurrent transaction beats us # to the update. But we still have to make sure that we're not starting # out behind. if 'version' in query_def and query_def['version'] != query.version: abort(409) try: self.update_model(query, query_def) models.db.session.commit() except StaleDataError: abort(409) return QuerySerializer(query, with_visualizations=True).serialize()
def post(self, dashboard_slug): """ Modifies a dashboard. :qparam string slug: Slug of dashboard to retrieve. Responds with the updated :ref:`dashboard <dashboard-response-label>`. :status 200: success :status 409: Version conflict -- dashboard modified since last read """ dashboard_properties = request.get_json(force=True) # TODO: either convert all requests to use slugs or ids dashboard = models.Dashboard.get_by_id_and_org(dashboard_slug, self.current_org) require_object_modify_permission(dashboard, self.current_user) updates = project(dashboard_properties, ('name', 'layout', 'version', 'tags', 'is_draft', 'dashboard_filters_enabled')) # SQLAlchemy handles the case where a concurrent transaction beats us # to the update. But we still have to make sure that we're not starting # out behind. if 'version' in updates and updates['version'] != dashboard.version: abort(409) updates['changed_by'] = self.current_user self.update_model(dashboard, updates) models.db.session.add(dashboard) try: models.db.session.commit() except StaleDataError: abort(409) result = serialize_dashboard(dashboard, with_widgets=True, user=self.current_user) self.record_event({ 'action': 'edit', 'object_id': dashboard.id, 'object_type': 'dashboard', }) return result
def delete(self, visualization_id): """ Disable anonymous access to a visualization. :param visualization_id: The numeric ID of the visualization to unshare. """ vis = models.Visualization.get_by_id(visualization_id) require_object_modify_permission(vis.query_rel, self.current_user) api_key = models.ApiKey.get_by_object(vis) if api_key: api_key.active = False models.db.session.add(api_key) models.db.session.commit() self.record_event({ 'action': 'deactivate_api_key', 'object_id': vis.id, 'object_type': 'visualization', })
def post(self, visualization_id): """ Allow anonymous access to a visualization. :param visualization_id: The numeric ID of the visualization to share. :>json api_key: The API key to use when accessing it. """ vis = models.Visualization.get_by_id(visualization_id) require_object_modify_permission(vis.query_rel, self.current_user) api_key = models.ApiKey.create_for_object(vis, self.current_user) models.db.session.flush() models.db.session.commit() self.record_event({ 'action': 'activate_api_key', 'object_id': vis.id, 'object_type': 'visualization', }) return {'api_key': api_key.api_key}
def post(self, widget_id): """ Updates a widget in a dashboard. This method currently handles Text Box widgets only. :param number widget_id: The ID of the widget to modify :<json string text: The new contents of the text box """ widget = models.Widget.get_by_id_and_org(widget_id, self.current_org) flag = True manage_boards = models.Dashboard.queries(self.current_org, self.current_user.group_ids, self.current_user.id) for group_id in self.current_user.group_ids: group = get_object_or_404(models.Group.get_by_id_and_org, group_id, self.current_org) try: d = [ ds.to_dict(with_permissions_for=group) for ds in manage_boards ] for item in d: if item['view_only'] == False and item[ 'id'] == widget.dashboard.id: flag = False except: pass if flag: require_object_modify_permission(widget.dashboard, self.current_user) widget_properties = request.get_json(force=True) widget.text = widget_properties['text'] widget.options = json_dumps(widget_properties['options']) models.db.session.commit() return serialize_widget(widget)
def post(self): """ Add a widget to a dashboard. :<json number dashboard_id: The ID for the dashboard being added to :<json visualization_id: The ID of the visualization to put in this widget :<json object options: Widget options :<json string text: Text box contents :<json number width: Width for widget display :>json object widget: The created widget """ widget_properties = request.get_json(force=True) dashboard = models.Dashboard.get_by_id_and_org( widget_properties.pop('dashboard_id'), self.current_org) require_object_modify_permission(dashboard, self.current_user) widget_properties['options'] = json.dumps(widget_properties['options']) widget_properties.pop('id', None) widget_properties['dashboard'] = dashboard visualization_id = widget_properties.pop('visualization_id') if visualization_id: visualization = models.Visualization.get_by_id_and_org( visualization_id, self.current_org) require_access(visualization.query_rel.groups, self.current_user, view_only) else: visualization = None widget_properties['visualization'] = visualization widget = models.Widget(**widget_properties) models.db.session.add(widget) models.db.session.commit() models.db.session.commit() return widget.to_dict()
def post(self): """ Add a widget to a dashboard. :<json number dashboard_id: The ID for the dashboard being added to :<json visualization_id: The ID of the visualization to put in this widget :<json object options: Widget options :<json string text: Text box contents :<json number width: Width for widget display :>json object widget: The created widget :>json array layout: The new layout of the dashboard this widget was added to :>json boolean new_row: Whether this widget was added on a new row or not :>json number version: The revision number of the dashboard """ widget_properties = request.get_json(force=True) dashboard = models.Dashboard.get_by_id_and_org( widget_properties.pop('dashboard_id'), self.current_org) require_object_modify_permission(dashboard, self.current_user) widget_properties['options'] = json.dumps(widget_properties['options']) widget_properties.pop('id', None) widget_properties['dashboard'] = dashboard visualization_id = widget_properties.pop('visualization_id') if visualization_id: visualization = models.Visualization.get_by_id_and_org( visualization_id, self.current_org) require_access(visualization.query_rel.groups, self.current_user, view_only) else: visualization = None widget_properties['visualization'] = visualization widget = models.Widget(**widget_properties) models.db.session.add(widget) models.db.session.commit() layout = json.loads(widget.dashboard.layout) new_row = True if len(layout) == 0 or widget.width == 2: layout.append([widget.id]) elif len(layout[-1]) == 1: neighbour_widget = models.Widget.query.get(layout[-1][0]) if neighbour_widget.width == 1: layout[-1].append(widget.id) new_row = False else: layout.append([widget.id]) else: layout.append([widget.id]) widget.dashboard.layout = json.dumps(layout) models.db.session.add(widget.dashboard) models.db.session.commit() return { 'widget': widget.to_dict(), 'layout': layout, 'new_row': new_row, 'version': dashboard.version }
def post(self, query_id): """ Modify a query. :param query_id: ID of query to update :<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 Responds with the updated :ref:`query <query-response-label>` object. """ 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) require_access_to_dropdown_queries(self.current_user, query_def) for field in [ "id", "created_at", "api_key", "visualizations", "latest_query_data", "user", "last_modified_by", "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] if "data_source_id" in query_def: data_source = models.DataSource.get_by_id_and_org( query_def["data_source_id"], self.current_org ) require_access(data_source, self.current_user, not_view_only) query_def["last_modified_by"] = self.current_user query_def["changed_by"] = self.current_user # SQLAlchemy handles the case where a concurrent transaction beats us # to the update. But we still have to make sure that we're not starting # out behind. if "version" in query_def and query_def["version"] != query.version: abort(409) try: self.update_model(query, query_def) models.db.session.commit() except StaleDataError: abort(409) return QuerySerializer(query, with_visualizations=True).serialize()
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()