Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
    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)
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
    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
Ejemplo n.º 8
0
    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
Ejemplo n.º 9
0
    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
Ejemplo n.º 10
0
    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)
Ejemplo n.º 11
0
    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)
Ejemplo n.º 12
0
    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
Ejemplo n.º 13
0
    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
Ejemplo n.º 14
0
    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)