Exemple #1
0
 def _get_url(
     self, user_friendly: bool = False, csv: bool = False, **kwargs: Any
 ) -> str:
     """
     Get the url for this report schedule: chart or dashboard
     """
     if self._report_schedule.chart:
         if csv:
             return get_url_path(
                 "Superset.explore_json",
                 csv="true",
                 form_data=json.dumps({"slice_id": self._report_schedule.chart_id}),
             )
         return get_url_path(
             "Superset.slice",
             user_friendly=user_friendly,
             slice_id=self._report_schedule.chart_id,
             **kwargs,
         )
     return get_url_path(
         "Superset.dashboard",
         user_friendly=user_friendly,
         dashboard_id_or_slug=self._report_schedule.dashboard_id,
         **kwargs,
     )
Exemple #2
0
 def _get_url(self,
              user_friendly: bool = False,
              csv: bool = False,
              **kwargs: Any) -> str:
     """
     Get the url for this report schedule: chart or dashboard
     """
     if self._report_schedule.chart:
         if csv:
             return get_url_path(
                 "ChartRestApi.get_data",
                 pk=self._report_schedule.chart_id,
                 format=ChartDataResultFormat.CSV.value,
                 type=ChartDataResultType.POST_PROCESSED.value,
             )
         return get_url_path(
             "Superset.slice",
             user_friendly=user_friendly,
             slice_id=self._report_schedule.chart_id,
             **kwargs,
         )
     return get_url_path(
         "Superset.dashboard",
         user_friendly=user_friendly,
         dashboard_id_or_slug=self._report_schedule.dashboard_id,
         **kwargs,
     )
Exemple #3
0
 def compute_generic_thumbnail(
     friendly_type: str,
     model_cls: Union[Type[Dashboard], Type[Slice]],
     model_id: int,
     compute_func: CallableTask,
 ) -> None:
     query = db.session.query(model_cls)
     if model_id:
         query = query.filter(model_cls.id.in_(model_id))
     dashboards = query.all()
     count = len(dashboards)
     for i, model in enumerate(dashboards):
         if asynchronous:
             func = compute_func.delay
             action = "Triggering"
         else:
             func = compute_func
             action = "Processing"
         msg = f'{action} {friendly_type} "{model}" ({i+1}/{count})'
         click.secho(msg, fg="green")
         if friendly_type == "chart":
             url = get_url_path("Superset.slice",
                                slice_id=model.id,
                                standalone="true")
         else:
             url = get_url_path("Superset.dashboard",
                                dashboard_id_or_slug=model.id)
         func(url, model.digest, force=force)
    def _get_url(
        self,
        user_friendly: bool = False,
        result_format: Optional[ChartDataResultFormat] = None,
        **kwargs: Any,
    ) -> str:
        """
        Get the url for this report schedule: chart or dashboard
        """
        force = "true" if self._report_schedule.force_screenshot else "false"
        if self._report_schedule.chart:
            if result_format in {
                    ChartDataResultFormat.CSV,
                    ChartDataResultFormat.JSON,
            }:
                return get_url_path(
                    "ChartDataRestApi.get_data",
                    pk=self._report_schedule.chart_id,
                    format=result_format.value,
                    type=ChartDataResultType.POST_PROCESSED.value,
                    force=force,
                )
            return get_url_path(
                "ExploreView.root",
                user_friendly=user_friendly,
                form_data=json.dumps(
                    {"slice_id": self._report_schedule.chart_id}),
                standalone="true",
                force=force,
                **kwargs,
            )

        # If we need to render dashboard in a specific sate, use stateful permalink
        dashboard_state = self._report_schedule.extra.get("dashboard")
        if dashboard_state:
            permalink_key = CreateDashboardPermalinkCommand(
                dashboard_id=self._report_schedule.dashboard_id,
                state=dashboard_state,
            ).run()
            return get_url_path("Superset.dashboard_permalink",
                                key=permalink_key)

        return get_url_path(
            "Superset.dashboard",
            user_friendly=user_friendly,
            dashboard_id_or_slug=self._report_schedule.dashboard_id,
            standalone=DashboardStandaloneMode.REPORT.value,
            force=force,
            **kwargs,
        )
Exemple #5
0
 def _get_url(report_schedule: ReportSchedule, user_friendly: bool = False) -> str:
     """
     Get the url for this report schedule: chart or dashboard
     """
     if report_schedule.chart:
         return get_url_path(
             "Superset.slice",
             user_friendly=user_friendly,
             slice_id=report_schedule.chart_id,
             standalone="true",
         )
     return get_url_path(
         "Superset.dashboard",
         user_friendly=user_friendly,
         dashboard_id_or_slug=report_schedule.dashboard_id,
     )
Exemple #6
0
 def _get_url(self, user_friendly: bool = False, **kwargs: Any) -> str:
     """
     Get the url for this report schedule: chart or dashboard
     """
     if self._report_schedule.chart:
         return get_url_path(
             "Superset.slice",
             user_friendly=user_friendly,
             slice_id=self._report_schedule.chart_id,
             **kwargs,
         )
     return get_url_path(
         "Superset.dashboard",
         user_friendly=user_friendly,
         dashboard_id_or_slug=self._report_schedule.dashboard_id,
         **kwargs,
     )
Exemple #7
0
 def test_screenshot_selenium_load_wait(self, mock_webdriver,
                                        mock_webdriver_wait):
     app.config["SCREENSHOT_LOAD_WAIT"] = 15
     webdriver = WebDriverProxy("firefox")
     user = security_manager.get_user_by_username(
         app.config["THUMBNAIL_SELENIUM_USER"])
     url = get_url_path("Superset.slice", slice_id=1, standalone="true")
     webdriver.get_screenshot(url, "chart-container", user=user)
     assert mock_webdriver_wait.call_args_list[1] == call(ANY, 15)
Exemple #8
0
 def test_screenshot_selenium_headstart(self, mock_sleep, mock_webdriver,
                                        mock_webdriver_wait):
     webdriver = WebDriverProxy("firefox")
     user = security_manager.get_user_by_username(
         app.config["THUMBNAIL_SELENIUM_USER"])
     url = get_url_path("Superset.slice", slice_id=1, standalone="true")
     app.config["SCREENSHOT_SELENIUM_HEADSTART"] = 5
     webdriver.get_screenshot(url, "chart-container", user=user)
     assert mock_sleep.call_args_list[0] == call(5)
def deliver_alert(alert: Alert, recipients: Optional[str] = None) -> None:
    logging.info("Triggering alert: %s", alert)
    img_data = None
    images = {}
    recipients = recipients or alert.recipients

    if alert.slice:

        chart_url = get_url_path("Superset.slice",
                                 slice_id=alert.slice.id,
                                 standalone="true")
        screenshot = ChartScreenshot(chart_url, alert.slice.digest)
        cache_key = screenshot.cache_key()
        image_url = get_url_path("ChartRestApi.screenshot",
                                 pk=alert.slice.id,
                                 digest=cache_key)

        user = security_manager.find_user(
            current_app.config["THUMBNAIL_SELENIUM_USER"])
        img_data = screenshot.compute_and_cache(
            user=user,
            cache=thumbnail_cache,
            force=True,
        )
    else:
        # TODO: dashboard delivery!
        image_url = "https://media.giphy.com/media/dzaUX7CAG0Ihi/giphy.gif"

    # generate the email
    subject = f"[Superset] Triggered alert: {alert.label}"
    deliver_as_group = False
    data = None
    if img_data:
        images = {"screenshot": img_data}
    body = __(
        textwrap.dedent("""\
            <h2>Alert: %(label)s</h2>
            <img src="cid:screenshot" alt="%(label)s" />
        """),
        label=alert.label,
        image_url=image_url,
    )

    _deliver_email(recipients, deliver_as_group, subject, body, data, images)
def deliver_alert(alert_id: int, recipients: Optional[str] = None) -> None:
    alert = db.session.query(Alert).get(alert_id)

    logging.info("Triggering alert: %s", alert)
    img_data = None
    images = {}
    recipients = recipients or alert.recipients

    if alert.slice:

        chart_url = get_url_path("Superset.slice",
                                 slice_id=alert.slice.id,
                                 standalone="true")
        screenshot = ChartScreenshot(chart_url, alert.slice.digest)
        image_url = _get_url_path(
            "Superset.slice",
            user_friendly=True,
            slice_id=alert.slice.id,
            standalone="true",
        )
        standalone_index = image_url.find("/?standalone=true")
        if standalone_index != -1:
            image_url = image_url[:standalone_index]

        user = security_manager.find_user(
            current_app.config["THUMBNAIL_SELENIUM_USER"])
        img_data = screenshot.compute_and_cache(
            user=user,
            cache=thumbnail_cache,
            force=True,
        )
    else:
        # TODO: dashboard delivery!
        image_url = "https://media.giphy.com/media/dzaUX7CAG0Ihi/giphy.gif"

    # generate the email
    # TODO add sql query results to email
    subject = f"[Superset] Triggered alert: {alert.label}"
    deliver_as_group = False
    data = None
    if img_data:
        images = {"screenshot": img_data}
    body = render_template(
        "email/alert.txt",
        alert_url=_get_url_path("AlertModelView.show",
                                user_friendly=True,
                                pk=alert.id),
        label=alert.label,
        sql=alert.sql,
        image_url=image_url,
    )

    _deliver_email(recipients, deliver_as_group, subject, body, data, images)
Exemple #11
0
    def _get_url(
        self,
        user_friendly: bool = False,
        result_format: Optional[ChartDataResultFormat] = None,
        **kwargs: Any,
    ) -> str:
        """
        Get the url for this report schedule: chart or dashboard
        """
        force = "true" if self._report_schedule.force_screenshot else "false"

        if self._report_schedule.chart:
            if result_format in {
                    ChartDataResultFormat.CSV,
                    ChartDataResultFormat.JSON,
            }:
                return get_url_path(
                    "ChartDataRestApi.get_data",
                    pk=self._report_schedule.chart_id,
                    format=result_format.value,
                    type=ChartDataResultType.POST_PROCESSED.value,
                    force=force,
                )
            return get_url_path(
                "Superset.explore",
                user_friendly=user_friendly,
                form_data=json.dumps(
                    {"slice_id": self._report_schedule.chart_id}),
                standalone="true",
                force=force,
                **kwargs,
            )
        return get_url_path(
            "Superset.dashboard",
            user_friendly=user_friendly,
            dashboard_id_or_slug=self._report_schedule.dashboard_id,
            standalone=DashboardStandaloneMode.REPORT.value,
            # force=force,  TODO (betodealmeida) implement this
            **kwargs,
        )
Exemple #12
0
 def test_get_cached_chart_screenshot(self):
     """
         Thumbnails: Simple get cached chart screenshot
     """
     chart = db.session.query(Slice).all()[0]
     chart_url = get_url_path("Superset.slice", slice_id=chart.id, standalone="true")
     # Cache a test "image"
     screenshot = ChartScreenshot(chart_url, chart.digest)
     thumbnail_cache.set(screenshot.cache_key, self.mock_image)
     self.login(username="******")
     uri = f"api/v1/chart/{chart.id}/thumbnail/{chart.digest}/"
     rv = self.client.get(uri)
     self.assertEqual(rv.status_code, 200)
     self.assertEqual(rv.data, self.mock_image)
Exemple #13
0
 def test_get_cached_dashboard_screenshot(self):
     """
         Thumbnails: Simple get cached dashboard screenshot
     """
     dashboard = db.session.query(Dashboard).all()[0]
     dashboard_url = get_url_path("Superset.dashboard", dashboard_id=dashboard.id)
     # Cache a test "image"
     screenshot = DashboardScreenshot(dashboard_url, dashboard.digest)
     thumbnail_cache.set(screenshot.cache_key, self.mock_image)
     self.login(username="******")
     uri = f"api/v1/dashboard/{dashboard.id}/thumbnail/{dashboard.digest}/"
     rv = self.client.get(uri)
     self.assertEqual(rv.status_code, 200)
     self.assertEqual(rv.data, self.mock_image)
def _get_slice_screenshot(slice_id: int, session: Session) -> ScreenshotData:
    slice_obj = session.query(Slice).get(slice_id)

    chart_url = get_url_path("Superset.slice", slice_id=slice_obj.id, standalone="true")
    screenshot = ChartScreenshot(chart_url, slice_obj.digest)
    image_url = _get_url_path(
        "Superset.slice", user_friendly=True, slice_id=slice_obj.id,
    )

    user = security_manager.find_user(current_app.config["THUMBNAIL_SELENIUM_USER"])
    image_data = screenshot.compute_and_cache(
        user=user, cache=thumbnail_cache, force=True,
    )

    session.commit()
    return ScreenshotData(image_url, image_data)
Exemple #15
0
    def cache_screenshot(self, pk: int,
                         **kwargs: Dict[str, bool]) -> WerkzeugResponse:
        """
        ---
        get:
          description: Compute and cache a screenshot.
          parameters:
          - in: path
            schema:
              type: integer
            name: pk
          - in: query
            name: q
            content:
              application/json:
                schema:
                  $ref: '#/components/schemas/screenshot_query_schema'
          responses:
            200:
              description: Chart async result
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/ChartCacheScreenshotResponseSchema"
            302:
              description: Redirects to the current digest
            400:
              $ref: '#/components/responses/400'
            401:
              $ref: '#/components/responses/401'
            404:
              $ref: '#/components/responses/404'
            500:
              $ref: '#/components/responses/500'
        """
        rison_dict = kwargs["rison"]
        window_size = rison_dict.get("window_size") or (800, 600)

        # Don't shrink the image if thumb_size is not specified
        thumb_size = rison_dict.get("thumb_size") or window_size

        chart = self.datamodel.get(pk, self._base_filters)
        if not chart:
            return self.response_404()

        chart_url = get_url_path("Superset.slice",
                                 slice_id=chart.id,
                                 standalone="true")
        screenshot_obj = ChartScreenshot(chart_url, chart.digest)
        cache_key = screenshot_obj.cache_key(window_size, thumb_size)
        image_url = get_url_path("ChartRestApi.screenshot",
                                 pk=chart.id,
                                 digest=cache_key)

        def trigger_celery() -> WerkzeugResponse:
            logger.info("Triggering screenshot ASYNC")
            kwargs = {
                "url": chart_url,
                "digest": chart.digest,
                "force": True,
                "window_size": window_size,
                "thumb_size": thumb_size,
            }
            cache_chart_thumbnail.delay(**kwargs)
            return self.response(
                202,
                cache_key=cache_key,
                chart_url=chart_url,
                image_url=image_url,
            )

        return trigger_celery()
Exemple #16
0
    def thumbnail(self, pk: int, digest: str,
                  **kwargs: Any) -> WerkzeugResponse:
        """Get Dashboard thumbnail
        ---
        get:
          description: >-
            Compute async or get already computed dashboard thumbnail from cache.
          parameters:
          - in: path
            schema:
              type: integer
            name: pk
          - in: path
            name: digest
            description: A hex digest that makes this dashboard unique
            schema:
              type: string
          - in: query
            name: q
            content:
              application/json:
                schema:
                  $ref: '#/components/schemas/thumbnail_query_schema'
          responses:
            200:
              description: Dashboard thumbnail image
              content:
               image/*:
                 schema:
                   type: string
                   format: binary
            202:
              description: Thumbnail does not exist on cache, fired async to compute
              content:
                application/json:
                  schema:
                    type: object
                    properties:
                      message:
                        type: string
            302:
              description: Redirects to the current digest
            401:
              $ref: '#/components/responses/401'
            404:
              $ref: '#/components/responses/404'
            422:
              $ref: '#/components/responses/422'
            500:
              $ref: '#/components/responses/500'
        """
        dashboard = self.datamodel.get(pk, self._base_filters)
        if not dashboard:
            return self.response_404()

        dashboard_url = get_url_path("Superset.dashboard",
                                     dashboard_id_or_slug=dashboard.id)
        # If force, request a screenshot from the workers
        if kwargs["rison"].get("force", False):
            cache_dashboard_thumbnail.delay(dashboard_url,
                                            dashboard.digest,
                                            force=True)
            return self.response(202, message="OK Async")
        # fetch the dashboard screenshot using the current user and cache if set
        screenshot = DashboardScreenshot(
            dashboard_url,
            dashboard.digest).get_from_cache(cache=thumbnail_cache)
        # If the screenshot does not exist, request one from the workers
        if not screenshot:
            self.incr_stats("async", self.thumbnail.__name__)
            cache_dashboard_thumbnail.delay(dashboard_url,
                                            dashboard.digest,
                                            force=True)
            return self.response(202, message="OK Async")
        # If digests
        if dashboard.digest != digest:
            self.incr_stats("redirect", self.thumbnail.__name__)
            return redirect(
                url_for(
                    f"{self.__class__.__name__}.thumbnail",
                    pk=pk,
                    digest=dashboard.digest,
                ))
        self.incr_stats("from_cache", self.thumbnail.__name__)
        return Response(FileWrapper(screenshot),
                        mimetype="image/png",
                        direct_passthrough=True)
def event_after_dashboard_changed(  # pylint: disable=unused-argument
    mapper: Mapper, connection: Connection, target: Dashboard
) -> None:
    url = get_url_path("Superset.dashboard", dashboard_id=target.id)
    cache_dashboard_thumbnail.delay(url, target.digest, force=True)
Exemple #18
0
    def thumbnail(self, pk: int, digest: str,
                  **kwargs: Dict[str, bool]) -> WerkzeugResponse:
        """Get Chart thumbnail
        ---
        get:
          description: Compute or get already computed chart thumbnail from cache.
          parameters:
          - in: path
            schema:
              type: integer
            name: pk
          - in: path
            schema:
              type: string
            name: digest
          responses:
            200:
              description: Chart thumbnail image
              content:
               image/*:
                 schema:
                   type: string
                   format: binary
            302:
              description: Redirects to the current digest
            400:
              $ref: '#/components/responses/400'
            401:
              $ref: '#/components/responses/401'
            404:
              $ref: '#/components/responses/404'
            500:
              $ref: '#/components/responses/500'
        """
        chart = self.datamodel.get(pk, self._base_filters)
        if not chart:
            return self.response_404()

        url = get_url_path("Superset.slice",
                           slice_id=chart.id,
                           standalone="true")
        if kwargs["rison"].get("force", False):
            logger.info("Triggering thumbnail compute (chart id: %s) ASYNC",
                        str(chart.id))
            cache_chart_thumbnail.delay(url, chart.digest, force=True)
            return self.response(202, message="OK Async")
        # fetch the chart screenshot using the current user and cache if set
        screenshot = ChartScreenshot(
            url, chart.digest).get_from_cache(cache=thumbnail_cache)
        # If not screenshot then send request to compute thumb to celery
        if not screenshot:
            logger.info("Triggering thumbnail compute (chart id: %s) ASYNC",
                        str(chart.id))
            cache_chart_thumbnail.delay(url, chart.digest, force=True)
            return self.response(202, message="OK Async")
        # If digests
        if chart.digest != digest:
            return redirect(
                url_for(f"{self.__class__.__name__}.thumbnail",
                        pk=pk,
                        digest=chart.digest))
        return Response(FileWrapper(screenshot),
                        mimetype="image/png",
                        direct_passthrough=True)
def event_after_dashboard_changed(
    _mapper: Mapper, _connection: Connection, target: Dashboard
) -> None:
    url = get_url_path("Superset.dashboard", dashboard_id_or_slug=target.id)
    cache_dashboard_thumbnail.delay(url, target.digest, force=True)
Exemple #20
0
def event_after_chart_changed(_mapper: Mapper, _connection: Connection,
                              target: Slice) -> None:
    url = get_url_path("Superset.slice", slice_id=target.id, standalone="true")
    cache_chart_thumbnail.delay(url, target.digest, force=True)
 def update_thumbnail(self) -> None:
     url = get_url_path("Superset.dashboard", dashboard_id_or_slug=self.id)
     cache_dashboard_thumbnail.delay(url, self.digest, force=True)