def run(self): self.validate() try: dashboard = DashboardDAO.create(self._properties) except DAOCreateFailedError as e: logger.exception(e.exception) raise DashboardCreateFailedError() return dashboard
def run(self) -> Model: self.validate() try: dashboard = DashboardDAO.delete(self._model) except DAODeleteFailedError as e: logger.exception(e.exception) raise DashboardDeleteFailedError() return dashboard
def wraps(self: BaseSupersetModelRestApi, id_or_slug: str) -> Response: try: dash = DashboardDAO.get_by_id_or_slug(id_or_slug) return f(self, dash) except DashboardAccessDeniedError: return self.response_403() except DashboardNotFoundError: return self.response_404()
def test_get_dashboard_changed_on(self): session = db.session() dashboard = session.query(Dashboard).filter_by( slug="world_health").first() assert dashboard.changed_on == DashboardDAO.get_dashboard_changed_on( dashboard) assert dashboard.changed_on == DashboardDAO.get_dashboard_changed_on( "world_health") old_changed_on = dashboard.changed_on # freezegun doesn't work for some reason, so we need to sleep here :( time.sleep(1) data = dashboard.data positions = data["position_json"] data.update({"positions": positions}) original_data = copy.deepcopy(data) data.update({"foo": "bar"}) DashboardDAO.set_dash_metadata(dashboard, data) session.merge(dashboard) session.commit() assert old_changed_on < DashboardDAO.get_dashboard_changed_on( dashboard) DashboardDAO.set_dash_metadata(dashboard, original_data) session.merge(dashboard) session.commit()
def validate(self) -> None: exceptions: List[ValidationError] = [] owners_ids: Optional[List[int]] = self._properties.get("owners") roles_ids: Optional[List[int]] = self._properties.get("roles") slug: Optional[str] = self._properties.get("slug") # Validate/populate model exists self._model = DashboardDAO.find_by_id(self._model_id) if not self._model: raise DashboardNotFoundError() # Check ownership try: security_manager.raise_for_ownership(self._model) except SupersetSecurityException as ex: raise DashboardForbiddenError() from ex # Validate slug uniqueness if not DashboardDAO.validate_update_slug_uniqueness(self._model_id, slug): exceptions.append(DashboardSlugExistsValidationError()) # Validate/Populate owner if owners_ids is None: owners_ids = [owner.id for owner in self._model.owners] try: owners = self.populate_owners(owners_ids) self._properties["owners"] = owners except ValidationError as ex: exceptions.append(ex) if exceptions: exception = DashboardInvalidError() exception.add_list(exceptions) raise exception # Validate/Populate role if roles_ids is None: roles_ids = [role.id for role in self._model.roles] try: roles = populate_roles(roles_ids) self._properties["roles"] = roles except ValidationError as ex: exceptions.append(ex) if exceptions: exception = DashboardInvalidError() exception.add_list(exceptions) raise exception
def get(self, resource_id: int, key: str, refresh_timeout: bool) -> Optional[str]: dashboard = DashboardDAO.get_by_id_or_slug(str(resource_id)) if dashboard: entry: Entry = cache_manager.filter_state_cache.get( cache_key(resource_id, key)) if refresh_timeout: cache_manager.filter_state_cache.set(key, entry) return entry["value"] return None
def create(self, cmd_params: CommandParameters) -> bool: resource_id = cmd_params.resource_id actor = cmd_params.actor key = cache_key(resource_id, cmd_params.key) value = cmd_params.value dashboard = DashboardDAO.get_by_id_or_slug(str(resource_id)) if dashboard and value: entry: Entry = {"owner": actor.get_user_id(), "value": value} return cache_manager.filter_state_cache.set(key, entry) return False
def validate(self) -> None: # Validate/populate model exists self._model = DashboardDAO.find_by_id(self._model_id) if not self._model: raise DashboardNotFoundError() # Check ownership try: check_ownership(self._model) except SupersetSecurityException: raise DashboardForbiddenError()
def run(self) -> Optional[DashboardPermalinkValue]: self.validate() try: key = decode_permalink_id(self.key, salt=self.salt) command = GetKeyValueCommand(resource=self.resource, key=key) value: Optional[DashboardPermalinkValue] = command.run() if value: DashboardDAO.get_by_id_or_slug(value["dashboardId"]) return value return None except ( DashboardNotFoundError, KeyValueGetFailedError, KeyValueParseKeyError, ) as ex: raise DashboardPermalinkGetFailedError(message=ex.message) from ex except SQLAlchemyError as ex: logger.exception("Error running get command") raise DashboardPermalinkGetFailedError() from ex
def run(self) -> str: self.validate() try: DashboardDAO.get_by_id_or_slug(self.dashboard_id) value = { "dashboardId": self.dashboard_id, "state": self.state, } key = CreateKeyValueCommand( actor=self.actor, resource=self.resource, value=value, ).run() if key.id is None: raise DashboardPermalinkCreateFailedError("Unexpected missing key id") return encode_permalink_key(key=key.id, salt=self.salt) except SQLAlchemyError as ex: logger.exception("Error running create command") raise DashboardPermalinkCreateFailedError() from ex
def run(self) -> str: self.validate() try: DashboardDAO.get_by_id_or_slug(self.dashboard_id) value = { "dashboardId": self.dashboard_id, "state": self.state, } user_id = get_user_id() key = UpsertKeyValueCommand( resource=self.resource, key=get_deterministic_uuid(self.salt, (user_id, value)), value=value, ).run() assert key.id # for type checks return encode_permalink_key(key=key.id, salt=self.salt) except SQLAlchemyError as ex: logger.exception("Error running create command") raise DashboardPermalinkCreateFailedError() from ex
def validate(self) -> None: # Validate/populate model exists self._models = DashboardDAO.find_by_ids(self._model_ids) if not self._models or len(self._models) != len(self._model_ids): raise DashboardNotFoundError() # Check ownership for model in self._models: try: check_ownership(model) except SupersetSecurityException: raise DashboardForbiddenError()
def run(self) -> Model: self.validate() try: dashboard = DashboardDAO.update(self._model, self._properties, commit=False) dashboard = DashboardDAO.update_charts_owners(dashboard, commit=False) if self._properties.get("json_metadata"): dashboard = DashboardDAO.set_dash_metadata( dashboard, data=json.loads(self._properties.get( "json_metadata", "{}")), commit=False, ) db.session.commit() except DAOUpdateFailedError as ex: logger.exception(ex.exception) raise DashboardUpdateFailedError() from ex return dashboard
def favorite_status(self, **kwargs: Any) -> Response: """Favorite Stars for Dashboards --- get: description: >- Check favorited dashboards for current user parameters: - in: query name: q content: application/json: schema: $ref: '#/components/schemas/get_fav_star_ids_schema' responses: 200: description: content: application/json: schema: $ref: "#/components/schemas/GetFavStarIdsSchema" 400: $ref: '#/components/responses/400' 401: $ref: '#/components/responses/401' 404: $ref: '#/components/responses/404' 500: $ref: '#/components/responses/500' """ requested_ids = kwargs["rison"] dashboards = DashboardDAO.find_by_ids(requested_ids) if not dashboards: return self.response_404() favorited_dashboard_ids = DashboardDAO.favorited_ids( dashboards, g.user.get_id() ) res = [ {"id": request_id, "value": request_id in favorited_dashboard_ids} for request_id in requested_ids ] return self.response(200, result=res)
def get_charts(self, id_or_slug: str) -> Response: """Gets the chart definitions for a given dashboard --- get: description: >- Get the chart definitions for a given dashboard parameters: - in: path schema: type: string name: id_or_slug responses: 200: description: Dashboard chart definitions content: application/json: schema: type: object properties: result: type: array items: $ref: '#/components/schemas/ChartEntityResponseSchema' 302: description: Redirects to the current digest 400: $ref: '#/components/responses/400' 401: $ref: '#/components/responses/401' 403: $ref: '#/components/responses/403' 404: $ref: '#/components/responses/404' """ try: charts = DashboardDAO.get_charts_for_dashboard(id_or_slug) result = [ self.chart_entity_response_schema.dump(chart) for chart in charts ] if is_feature_enabled("REMOVE_SLICE_LEVEL_LABEL_COLORS"): # dashboard metadata has dashboard-level label_colors, # so remove slice-level label_colors from its form_data for chart in result: form_data = chart.get("form_data") form_data.pop("label_colors", None) return self.response(200, result=result) except DashboardAccessDeniedError: return self.response_403() except DashboardNotFoundError: return self.response_404()
def delete(self, cmd_params: CommandParameters) -> bool: resource_id = cmd_params.resource_id actor = cmd_params.actor key = cache_key(resource_id, cmd_params.key) dashboard = DashboardDAO.get_by_id_or_slug(str(resource_id)) if dashboard: entry: Entry = cache_manager.filter_state_cache.get(key) if entry: if entry["owner"] != actor.get_user_id(): raise KeyValueAccessDeniedError() return cache_manager.filter_state_cache.delete(key) return False
def delete(self, actor: User, resource_id: int, key: str) -> Optional[bool]: dashboard = DashboardDAO.get_by_id_or_slug(str(resource_id)) if dashboard: entry: Entry = cache_manager.filter_state_cache.get( cache_key(resource_id, key)) if entry: if entry["owner"] != actor.get_user_id(): raise KeyValueAccessDeniedError() return cache_manager.filter_state_cache.delete( cache_key(resource_id, key)) return False
def validate(self) -> None: exceptions: List[ValidationError] = [] dashboard_ids = self._properties.get("dashboards") owner_ids: Optional[List[int]] = self._properties.get("owners") # Validate if datasource_id is provided datasource_type is required datasource_id = self._properties.get("datasource_id") if datasource_id is not None: datasource_type = self._properties.get("datasource_type", "") if not datasource_type: exceptions.append( DatasourceTypeUpdateRequiredValidationError()) # Validate/populate model exists self._model = ChartDAO.find_by_id(self._model_id) if not self._model: raise ChartNotFoundError() # Check and update ownership; when only updating query context we ignore # ownership so the update can be performed by report workers if not is_query_context_update(self._properties): try: check_ownership(self._model) owners = self.populate_owners(self._actor, owner_ids) self._properties["owners"] = owners except SupersetSecurityException as ex: raise ChartForbiddenError() from ex except ValidationError as ex: exceptions.append(ex) # Validate/Populate datasource if datasource_id is not None: try: datasource = get_datasource_by_id(datasource_id, datasource_type) self._properties["datasource_name"] = datasource.name except ValidationError as ex: exceptions.append(ex) # Validate/Populate dashboards only if it's a list if dashboard_ids is not None: dashboards = DashboardDAO.find_by_ids(dashboard_ids) if len(dashboards) != len(dashboard_ids): exceptions.append(DashboardsNotFoundValidationError()) self._properties["dashboards"] = dashboards if exceptions: exception = ChartInvalidError() exception.add_list(exceptions) raise exception
def get_datasets(self, id_or_slug: str) -> Response: """Gets a dashboard's datasets --- get: description: >- Returns a list of a dashboard's datasets. Each dataset includes only the information necessary to render the dashboard's charts. parameters: - in: path schema: type: string name: id_or_slug description: Either the id of the dashboard, or its slug responses: 200: description: Dashboard dataset definitions content: application/json: schema: type: object properties: result: type: array items: $ref: '#/components/schemas/DashboardDatasetSchema' 400: $ref: '#/components/responses/400' 401: $ref: '#/components/responses/401' 403: $ref: '#/components/responses/403' 404: $ref: '#/components/responses/404' """ try: datasets = DashboardDAO.get_datasets_for_dashboard(id_or_slug) result = [ self.dashboard_dataset_schema.dump(dataset) for dataset in datasets ] return self.response(200, result=result) except (TypeError, ValueError) as err: return self.response_400(message=gettext( "Dataset schema is invalid, caused by: %(error)s", error=str(err))) except DashboardAccessDeniedError: return self.response_403() except DashboardNotFoundError: return self.response_404()
def validate(self) -> None: exceptions: List[ValidationError] = list() dashboard_ids = self._properties.get("dashboards") owner_ids: Optional[List[int]] = self._properties.get("owners") # Validate if datasource_id is provided datasource_type is required datasource_id = self._properties.get("datasource_id") if datasource_id is not None: datasource_type = self._properties.get("datasource_type", "") if not datasource_type: exceptions.append( DatasourceTypeUpdateRequiredValidationError()) # Validate/populate model exists self._model = ChartDAO.find_by_id(self._model_id) if not self._model: raise ChartNotFoundError() # Check ownership try: check_ownership(self._model) except SupersetSecurityException: raise ChartForbiddenError() # Validate/Populate datasource if datasource_id is not None: try: datasource = get_datasource_by_id(datasource_id, datasource_type) self._properties["datasource_name"] = datasource.name except ValidationError as ex: exceptions.append(ex) # Validate/Populate dashboards only if it's a list if dashboard_ids is not None: dashboards = DashboardDAO.find_by_ids(dashboard_ids) if len(dashboards) != len(dashboard_ids): exceptions.append(DashboardsNotFoundValidationError()) self._properties["dashboards"] = dashboards # Validate/Populate owner try: owners = populate_owners(self._actor, owner_ids) self._properties["owners"] = owners except ValidationError as ex: exceptions.append(ex) if exceptions: exception = ChartInvalidError() exception.add_list(exceptions) raise exception
def create(self, cmd_params: CommandParameters) -> str: resource_id = cmd_params.resource_id actor = cmd_params.actor tab_id = cmd_params.tab_id contextual_key = cache_key(session.get("_id"), tab_id, resource_id) key = cache_manager.filter_state_cache.get(contextual_key) if not key or not tab_id: key = random_key() value = cmd_params.value dashboard = DashboardDAO.get_by_id_or_slug(str(resource_id)) if dashboard and value: entry: Entry = {"owner": actor.get_user_id(), "value": value} cache_manager.filter_state_cache.set(cache_key(resource_id, key), entry) cache_manager.filter_state_cache.set(contextual_key, key) return key
def delete(self, cmd_params: CommandParameters) -> bool: resource_id = cmd_params.resource_id actor = cmd_params.actor key = cache_key(resource_id, cmd_params.key) dashboard = DashboardDAO.get_by_id_or_slug(str(resource_id)) if dashboard: entry: Entry = cache_manager.filter_state_cache.get(key) if entry: if entry["owner"] != actor.get_user_id(): raise TemporaryCacheAccessDeniedError() tab_id = cmd_params.tab_id contextual_key = cache_key(session.get("_id"), tab_id, resource_id) cache_manager.filter_state_cache.delete(contextual_key) return cache_manager.filter_state_cache.delete(key) return False
def update(self, actor: User, resource_id: int, key: str, value: str) -> Optional[bool]: dashboard = DashboardDAO.get_by_id_or_slug(str(resource_id)) if dashboard: entry: Entry = cache_manager.filter_state_cache.get( cache_key(resource_id, key)) if entry: user_id = actor.get_user_id() if entry["owner"] != user_id: raise KeyValueAccessDeniedError() new_entry: Entry = { "owner": actor.get_user_id(), "value": value } return cache_manager.filter_state_cache.set( cache_key(resource_id, key), new_entry) return False
def validate(self) -> None: # Validate/populate model exists self._model = DashboardDAO.find_by_id(self._model_id) if not self._model: raise DashboardNotFoundError() # Check there are no associated ReportSchedules reports = ReportScheduleDAO.find_by_dashboard_id(self._model_id) if reports: report_names = [report.name for report in reports] raise DashboardDeleteFailedReportsExistError( _("There are associated alerts or reports: %s" % ",".join(report_names))) # Check ownership try: check_ownership(self._model) except SupersetSecurityException as ex: raise DashboardForbiddenError() from ex
def update(self, cmd_params: CommandParameters) -> bool: resource_id = cmd_params.resource_id actor = cmd_params.actor key = cache_key(resource_id, cmd_params.key) value = cmd_params.value dashboard = DashboardDAO.get_by_id_or_slug(str(resource_id)) if dashboard and value: entry: Entry = cache_manager.filter_state_cache.get(key) if entry: user_id = actor.get_user_id() if entry["owner"] != user_id: raise KeyValueAccessDeniedError() new_entry: Entry = { "owner": actor.get_user_id(), "value": value } return cache_manager.filter_state_cache.set(key, new_entry) return False
def test_set_dash_metadata(self): dash: Dashboard = ( db.session.query(Dashboard).filter_by(slug="world_health").first() ) data = dash.data positions = data["position_json"] data.update({"positions": positions}) original_data = copy.deepcopy(data) # add filter scopes filter_slice = next(slc for slc in dash.slices if slc.viz_type == "filter_box") immune_slices = [slc for slc in dash.slices if slc != filter_slice] filter_scopes = { str(filter_slice.id): { "region": { "scope": ["ROOT_ID"], "immune": [slc.id for slc in immune_slices], } } } data.update({"filter_scopes": json.dumps(filter_scopes)}) DashboardDAO.set_dash_metadata(dash, data) updated_metadata = json.loads(dash.json_metadata) self.assertEqual(updated_metadata["filter_scopes"], filter_scopes) # remove a slice and change slice ids (as copy slices) removed_slice = immune_slices.pop() removed_components = [ key for (key, value) in positions.items() if isinstance(value, dict) and value.get("type") == "CHART" and value["meta"]["chartId"] == removed_slice.id ] for component_id in removed_components: del positions[component_id] data.update({"positions": positions}) DashboardDAO.set_dash_metadata(dash, data) updated_metadata = json.loads(dash.json_metadata) expected_filter_scopes = { str(filter_slice.id): { "region": { "scope": ["ROOT_ID"], "immune": [slc.id for slc in immune_slices], } } } self.assertEqual(updated_metadata["filter_scopes"], expected_filter_scopes) # reset dash to original data DashboardDAO.set_dash_metadata(dash, original_data)
def validate(self) -> None: exceptions = list() owner_ids: Optional[List[int]] = self._properties.get("owners") slug: str = self._properties.get("slug", "") # Validate slug uniqueness if not DashboardDAO.validate_slug_uniqueness(slug): exceptions.append(DashboardSlugExistsValidationError()) try: owners = populate_owners(self._actor, owner_ids) self._properties["owners"] = owners except ValidationError as ex: exceptions.append(ex) if exceptions: exception = DashboardInvalidError() exception.add_list(exceptions) raise exception
def validate(self) -> None: # Validate/populate model exists self._models = DashboardDAO.find_by_ids(self._model_ids) if not self._models or len(self._models) != len(self._model_ids): raise DashboardNotFoundError() # Check there are no associated ReportSchedules reports = ReportScheduleDAO.find_by_dashboard_ids(self._model_ids) if reports: report_names = [report.name for report in reports] raise DashboardBulkDeleteFailedReportsExistError( _("There are associated alerts or reports: %s" % ",".join(report_names)) ) # Check ownership for model in self._models: try: security_manager.raise_for_ownership(model) except SupersetSecurityException as ex: raise DashboardForbiddenError() from ex
def get_datasets(self, id_or_slug: str) -> Response: """Gets a dashboard's datasets --- get: description: >- Returns a list of a dashboard's datasets. Each dataset includes only the information necessary to render the dashboard's charts. parameters: - in: path schema: type: string name: id_or_slug description: Either the id of the dashboard, or its slug responses: 200: description: Dashboard dataset definitions content: application/json: schema: type: object properties: result: type: array items: $ref: '#/components/schemas/DashboardDatasetSchema' 302: description: Redirects to the current digest 400: $ref: '#/components/responses/400' 401: $ref: '#/components/responses/401' 404: $ref: '#/components/responses/404' """ try: datasets = DashboardDAO.get_datasets_for_dashboard(id_or_slug) result = [ self.dashboard_dataset_schema.dump(dataset) for dataset in datasets ] return self.response(200, result=result) except DashboardNotFoundError: return self.response_404()
def get(self, id_or_slug: str) -> Response: """Gets a dashboard --- get: description: >- Get a dashboard parameters: - in: path schema: type: string name: id_or_slug description: Either the id of the dashboard, or its slug responses: 200: description: Dashboard content: application/json: schema: type: object properties: result: $ref: '#/components/schemas/DashboardGetResponseSchema' 302: description: Redirects to the current digest 400: $ref: '#/components/responses/400' 401: $ref: '#/components/responses/401' 403: $ref: '#/components/responses/403' 404: $ref: '#/components/responses/404' """ # pylint: disable=arguments-differ try: dash = DashboardDAO.get_by_id_or_slug(id_or_slug) result = self.dashboard_get_response_schema.dump(dash) return self.response(200, result=result) except DashboardAccessDeniedError: return self.response_403() except DashboardNotFoundError: return self.response_404()