def _get_screenshots(self) -> List[bytes]:
     """
     Get chart or dashboard screenshots
     :raises: ReportScheduleScreenshotFailedError
     """
     url = self._get_url()
     user = self._get_user()
     if self._report_schedule.chart:
         screenshot: Union[
             ChartScreenshot, DashboardScreenshot] = ChartScreenshot(
                 url,
                 self._report_schedule.chart.digest,
                 window_size=app.config["WEBDRIVER_WINDOW"]["slice"],
                 thumb_size=app.config["WEBDRIVER_WINDOW"]["slice"],
             )
     else:
         screenshot = DashboardScreenshot(
             url,
             self._report_schedule.dashboard.digest,
             window_size=app.config["WEBDRIVER_WINDOW"]["dashboard"],
             thumb_size=app.config["WEBDRIVER_WINDOW"]["dashboard"],
         )
     try:
         image = screenshot.get_screenshot(user=user)
     except SoftTimeLimitExceeded as ex:
         logger.warning("A timeout occurred while taking a screenshot.")
         raise ReportScheduleScreenshotTimeout() from ex
     except Exception as ex:
         raise ReportScheduleScreenshotFailedError(
             f"Failed taking a screenshot {str(ex)}") from ex
     if not image:
         raise ReportScheduleScreenshotFailedError()
     return [image]
Exemple #2
0
def cache_dashboard_thumbnail(dashboard_id: int, force: bool = False) -> None:
    with app.app_context():  # type: ignore
        if not thumbnail_cache:
            logging.warning("No cache set, refusing to compute")
            return None
        logger.info(f"Caching dashboard {dashboard_id}")
        screenshot = DashboardScreenshot(model_id=dashboard_id)
        user = security_manager.find_user(current_app.config["THUMBNAIL_SELENIUM_USER"])
        screenshot.compute_and_cache(user=user, cache=thumbnail_cache, force=force)
Exemple #3
0
def cache_dashboard_thumbnail(
    url: str, digest: str, force: bool = False, thumb_size: Optional[WindowSize] = None
) -> None:
    with app.app_context():  # type: ignore
        if not thumbnail_cache:
            logging.warning("No cache set, refusing to compute")
            return
        logger.info("Caching dashboard: %s", url)
        screenshot = DashboardScreenshot(url, digest)
        user = security_manager.find_user(current_app.config["THUMBNAIL_SELENIUM_USER"])
        screenshot.compute_and_cache(
            user=user, cache=thumbnail_cache, force=force, thumb_size=thumb_size,
        )
Exemple #4
0
    def _get_screenshot(self) -> ScreenshotData:
        """
        Get a chart or dashboard screenshot

        :raises: ReportScheduleScreenshotFailedError
        """
        screenshot: Optional[BaseScreenshot] = None
        if self._report_schedule.chart:
            url = self._get_url(standalone="true")
            screenshot = ChartScreenshot(
                url,
                self._report_schedule.chart.digest,
                window_size=app.config["WEBDRIVER_WINDOW"]["slice"],
                thumb_size=app.config["WEBDRIVER_WINDOW"]["slice"],
            )
        else:
            url = self._get_url()
            screenshot = DashboardScreenshot(
                url,
                self._report_schedule.dashboard.digest,
                window_size=app.config["WEBDRIVER_WINDOW"]["dashboard"],
                thumb_size=app.config["WEBDRIVER_WINDOW"]["dashboard"],
            )
        image_url = self._get_url(user_friendly=True)
        user = self._get_screenshot_user()
        image_data = screenshot.compute_and_cache(
            user=user,
            cache=thumbnail_cache,
            force=True,
        )
        if not image_data:
            raise ReportScheduleScreenshotFailedError()
        return ScreenshotData(url=image_url, image=image_data)
Exemple #5
0
    def _get_screenshot(self) -> bytes:
        """
        Get a chart or dashboard screenshot

        :raises: ReportScheduleScreenshotFailedError
        """
        screenshot: Optional[BaseScreenshot] = None
        if self._report_schedule.chart:
            url = self._get_url(standalone="true")
            screenshot = ChartScreenshot(
                url,
                self._report_schedule.chart.digest,
                window_size=app.config["WEBDRIVER_WINDOW"]["slice"],
                thumb_size=app.config["WEBDRIVER_WINDOW"]["slice"],
            )
        else:
            url = self._get_url()
            screenshot = DashboardScreenshot(
                url,
                self._report_schedule.dashboard.digest,
                window_size=app.config["WEBDRIVER_WINDOW"]["dashboard"],
                thumb_size=app.config["WEBDRIVER_WINDOW"]["dashboard"],
            )
        user = self._get_screenshot_user()
        try:
            image_data = screenshot.get_screenshot(user=user)
        except SoftTimeLimitExceeded:
            raise ReportScheduleScreenshotTimeout()
        except Exception as ex:
            raise ReportScheduleScreenshotFailedError(
                f"Failed taking a screenshot {str(ex)}")
        if not image_data:
            raise ReportScheduleScreenshotFailedError()
        return image_data
Exemple #6
0
def cache_dashboard_thumbnail(url: str,
                              digest: str,
                              force: bool = False,
                              thumb_size: Optional[WindowSize] = None) -> None:
    if not thumbnail_cache:
        logging.warning("No cache set, refusing to compute")
        return
    logger.info("Caching dashboard: %s", url)
    screenshot = DashboardScreenshot(url, digest)
    with session_scope(nullpool=True) as session:
        user = security_manager.get_user_by_username(
            current_app.config["THUMBNAIL_SELENIUM_USER"], session=session)
        screenshot.compute_and_cache(
            user=user,
            cache=thumbnail_cache,
            force=force,
            thumb_size=thumb_size,
        )
 def _get_screenshots(self) -> List[bytes]:
     """
     Get chart or dashboard screenshots
     :raises: ReportScheduleScreenshotFailedError
     """
     image_data = []
     screenshots: List[BaseScreenshot] = []
     if self._report_schedule.chart:
         url = self._get_url()
         logger.info("Screenshotting chart at %s", url)
         screenshots = [
             ChartScreenshot(
                 url,
                 self._report_schedule.chart.digest,
                 window_size=app.config["WEBDRIVER_WINDOW"]["slice"],
                 thumb_size=app.config["WEBDRIVER_WINDOW"]["slice"],
             )
         ]
     else:
         tabs: Optional[List[str]] = json.loads(self._report_schedule.extra).get(
             "dashboard_tab_ids", None
         )
         dashboard_base_url = self._get_url()
         if tabs is None:
             urls = [dashboard_base_url]
         else:
             urls = [f"{dashboard_base_url}#{tab_id}" for tab_id in tabs]
         screenshots = [
             DashboardScreenshot(
                 url,
                 self._report_schedule.dashboard.digest,
                 window_size=app.config["WEBDRIVER_WINDOW"]["dashboard"],
                 thumb_size=app.config["WEBDRIVER_WINDOW"]["dashboard"],
             )
             for url in urls
         ]
     user = self._get_user()
     for screenshot in screenshots:
         try:
             image = screenshot.get_screenshot(user=user)
         except SoftTimeLimitExceeded as ex:
             logger.warning("A timeout occurred while taking a screenshot.")
             raise ReportScheduleScreenshotTimeout() from ex
         except Exception as ex:
             raise ReportScheduleScreenshotFailedError(
                 f"Failed taking a screenshot {str(ex)}"
             ) from ex
         if image is not None:
             image_data.append(image)
     if not image_data:
         raise ReportScheduleScreenshotFailedError()
     return image_data
 def test_get_cached_dashboard_screenshot(self):
     """
         Thumbnails: Simple get cached dashboard screenshot
     """
     dashboard = db.session.query(Dashboard).all()[0]
     # Cache a test "image"
     screenshot = DashboardScreenshot(model_id=dashboard.id)
     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 test_get_cached_dashboard_wrong_digest(self):
     """
         Thumbnails: Simple get dashboard with wrong digest
     """
     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/1234/"
     rv = self.client.get(uri)
     self.assertEqual(rv.status_code, 302)
     self.assertRedirects(
         rv, f"api/v1/dashboard/{dashboard.id}/thumbnail/{dashboard.digest}/"
     )
Exemple #10
0
 def _get_screenshot(self, report_schedule: ReportSchedule) -> ScreenshotData:
     """
     Get a chart or dashboard screenshot
     :raises: ReportScheduleScreenshotFailedError
     """
     url = self._get_url(report_schedule)
     screenshot: Optional[BaseScreenshot] = None
     if report_schedule.chart:
         screenshot = ChartScreenshot(url, report_schedule.chart.digest)
     else:
         screenshot = DashboardScreenshot(url, report_schedule.dashboard.digest)
     image_url = self._get_url(report_schedule, user_friendly=True)
     user = security_manager.find_user(app.config["THUMBNAIL_SELENIUM_USER"])
     image_data = screenshot.compute_and_cache(
         user=user, cache=thumbnail_cache, force=True,
     )
     if not image_data:
         raise ReportScheduleScreenshotFailedError()
     return ScreenshotData(url=image_url, image=image_data)
Exemple #11
0
 def _get_screenshot(self) -> ScreenshotData:
     """
     Get a chart or dashboard screenshot
     :raises: ReportScheduleScreenshotFailedError
     """
     url = self._get_url()
     screenshot: Optional[BaseScreenshot] = None
     if self._report_schedule.chart:
         screenshot = ChartScreenshot(url, self._report_schedule.chart.digest)
     else:
         screenshot = DashboardScreenshot(
             url, self._report_schedule.dashboard.digest
         )
     image_url = self._get_url(user_friendly=True)
     user = self._get_screenshot_user()
     image_data = screenshot.compute_and_cache(
         user=user, cache=thumbnail_cache, force=True,
     )
     if not image_data:
         raise ReportScheduleScreenshotFailedError()
     return ScreenshotData(url=image_url, image=image_data)
Exemple #12
0
    def _get_screenshot(self) -> bytes:
        """
        Get a chart or dashboard screenshot

        :raises: ReportScheduleScreenshotFailedError
        """
        screenshot: Optional[BaseScreenshot] = None
        if self._report_schedule.chart:
            url = self._get_url()
            logger.info("Screenshotting chart at %s", url)
            screenshot = ChartScreenshot(
                url,
                self._report_schedule.chart.digest,
                window_size=app.config["WEBDRIVER_WINDOW"]["slice"],
                thumb_size=app.config["WEBDRIVER_WINDOW"]["slice"],
            )
        else:
            url = self._get_url()
            logger.info("Screenshotting dashboard at %s", url)
            screenshot = DashboardScreenshot(
                url,
                self._report_schedule.dashboard.digest,
                window_size=app.config["WEBDRIVER_WINDOW"]["dashboard"],
                thumb_size=app.config["WEBDRIVER_WINDOW"]["dashboard"],
            )
        user = self._get_user()
        try:
            image_data = screenshot.get_screenshot(user=user)
        except SoftTimeLimitExceeded as ex:
            logger.warning("A timeout occurred while taking a screenshot.")
            raise ReportScheduleScreenshotTimeout() from ex
        except Exception as ex:
            raise ReportScheduleScreenshotFailedError(
                f"Failed taking a screenshot {str(ex)}"
            ) from ex
        if not image_data:
            raise ReportScheduleScreenshotFailedError()
        return image_data
Exemple #13
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)