def delete(self, dashboard_slug): """ Archives a dashboard. :qparam string slug: Slug of dashboard to retrieve. Responds with the archived :ref:`dashboard <dashboard-response-label>`. """ dashboard = models.Dashboard.get_by_slug_and_org( dashboard_slug, self.current_org) dashboard.is_archived = True dashboard.record_changes(changed_by=self.current_user) models.db.session.add(dashboard) d = serialize_dashboard(dashboard, with_widgets=True, user=self.current_user) models.db.session.commit() self.record_event({ "action": "archive", "object_id": dashboard.id, "object_type": "dashboard" }) return d
def post(self): """ Creates a new dashboard. :<json string name: Dashboard name Responds with a :ref:`dashboard <dashboard-response-label>`. """ dashboard_properties = request.get_json(force=True) LOG.info('** receive dashboard create param: %s' % dashboard_properties) dash_name = dashboard_properties.get('dashName') dash_group = dashboard_properties.get('dashGroup') group_ref = models.Group.query\ .filter(models.Group.name == dash_group)\ .first() dashboard = models.Dashboard( name=dash_name, group_id=group_ref.id, org=self.current_org, user=self.current_user, is_draft=True, layout="[]", ) models.db.session.add(dashboard) models.db.session.commit() return serialize_dashboard(dashboard)
def get(self, dashboard_slug=None): """ Retrieves a dashboard. :qparam string slug: Slug 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 """ dashboard = get_object_or_404(models.Dashboard.get_by_slug_and_org, dashboard_slug, self.current_org) response = serialize_dashboard(dashboard, 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 response["can_edit"] = can_modify(dashboard, self.current_user) self.record_event({ "action": "view", "object_id": dashboard.id, "object_type": "dashboard" }) return response
def test_get_dashboard_with_slug(self): d1 = self.factory.create_dashboard() rv = self.make_request("get", "/api/dashboards/{0}?legacy".format(d1.slug)) self.assertEqual(rv.status_code, 200) expected = serialize_dashboard(d1, with_widgets=True, with_favorite_state=False) actual = json_loads(rv.data) self.assertResponseEqual(expected, actual)
def test_get_dashboard(self): d1 = self.factory.create_dashboard() rv = self.make_request('get', '/api/dashboards/{0}'.format(d1.slug)) self.assertEquals(rv.status_code, 200) expected = serialize_dashboard(d1, with_widgets=True, with_favorite_state=False) actual = json_loads(rv.data) self.assertResponseEqual(expected, actual)
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", "is_archived", "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 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) if 'layout' in dashboard_properties: try: layout = json.loads(dashboard_properties['layout']) except ValueError: abort(400) if not isinstance(layout, list): abort(400) 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 get(self, dashboard_slug=None): """ Retrieves a dashboard. :qparam string slug: Slug 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 """ dashboard = get_object_or_404(models.Dashboard.get_by_slug_and_org, dashboard_slug, self.current_org) response = serialize_dashboard(dashboard, 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 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, dashboard_slug): """ Archives a dashboard. :qparam string slug: Slug of dashboard to retrieve. Responds with the archived :ref:`dashboard <dashboard-response-label>`. """ dashboard = models.Dashboard.get_by_slug_and_org(dashboard_slug, self.current_org) dashboard.is_archived = True dashboard.record_changes(changed_by=self.current_user) models.db.session.add(dashboard) d = serialize_dashboard(dashboard, with_widgets=True, user=self.current_user) models.db.session.commit() return d
def post(self): """ Creates a new dashboard. :<json string name: Dashboard name Responds with a :ref:`dashboard <dashboard-response-label>`. """ dashboard_properties = request.get_json(force=True) dashboard = models.Dashboard(name=dashboard_properties['name'], org=self.current_org, user=self.current_user, is_draft=True, layout='[]') models.db.session.add(dashboard) models.db.session.commit() return serialize_dashboard(dashboard)
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 get(self): """ Lists all accessible dashboards. :qparam number page_size: Number of queries to return per page :qparam number page: Page number to retrieve :qparam number order: Name of column to order by :qparam number q: Full text search term Responds with an array of :ref:`dashboard <dashboard-response-label>` objects. """ search_term = request.args.get('q') viz_id = request.args.get('vis') if has_permission('admin'): if search_term: results = models.Dashboard.search(self.current_org, self.current_user.group_ids, self.current_user.id, search_term, viz_id) else: results = models.Dashboard.all(self.current_org, self.current_user.group_ids, self.current_user.id, viz_id) else: results = models.Dashboard.get_by_dashboard_group( self.current_org, self.current_user.group_ids, self.current_user.id, viz_id) results = filter_by_tags(results, models.Dashboard.tags) # order results according to passed order parameter, # special-casing search queries where the database # provides an order by search rank ordered_results = order_results(results, fallback=not bool(search_term)) if request.args.has_key('all'): response = [ serialize_dashboard(result) for result in ordered_results ] elif request.args.has_key('overview'): response = [ serialize_dashboard_overview(result, user=self.current_user) for result in ordered_results ] else: page = request.args.get('page', 1, type=int) page_size = request.args.get('page_size', 25, type=int) response = paginate( ordered_results, page=page, page_size=page_size, serializer=serialize_dashboard, ) if search_term: self.record_event({ 'action': 'search', 'object_type': 'dashboard', 'term': search_term, }) else: self.record_event({ 'action': 'list', 'object_type': 'dashboard', }) return response
def get(self, dashboard_slug=None): """ Retrieves a dashboard. :qparam string slug: Slug 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 """ dashboard = get_object_or_404(models.Dashboard.get_by_slug_and_org, dashboard_slug, self.current_org) response = serialize_dashboard(dashboard, 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 response['can_edit'] = can_modify(dashboard, self.current_user) 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) manage_boards = (models.Dashboard.query .join(models.ManageBoardGroup) .filter(models.ManageBoardGroup.group == group)) ds_dict = [ds.to_dict(with_permissions_for=group) for ds in manage_boards] for item in ds_dict: if item['id'] == response['id']: response['can_edit'] = True self.record_event({ 'action': 'view', 'object_id': dashboard.id, 'object_type': 'dashboard', }) if response['can_edit'] == True: return response else: abort(403)