def wraps( self: BaseSupersetModelRestApi, pk: int, table_name: str, schema_name: Optional[str] = None, ) -> Any: schema_name_parsed = parse_js_uri_path_item(schema_name, eval_undefined=True) table_name_parsed = parse_js_uri_path_item(table_name) if not table_name_parsed: return self.response_422(message=_("Table name undefined")) database: Database = self.datamodel.get(pk) if not database: self.stats_logger.incr( f"database_not_found_{self.__class__.__name__}.select_star") return self.response_404() if not self.appbuilder.sm.can_access_table( database, Table(table_name_parsed, schema_name_parsed)): self.stats_logger.incr( f"permisssion_denied_{self.__class__.__name__}.select_star") logger.warning( "Permission denied for user %s on table: %s schema: %s", g.user, table_name_parsed, schema_name_parsed, ) return self.response_404() return f(self, database, table_name_parsed, schema_name_parsed)
def wraps(self, pk: int, table_name: str, schema_name: Optional[str] = None): schema_name_parsed = parse_js_uri_path_item(schema_name, eval_undefined=True) table_name_parsed = parse_js_uri_path_item(table_name) if not table_name_parsed: return self.response_422(message=_("Table name undefined")) database: Database = self.datamodel.get(pk) if not database: self.stats_logger.incr( f"database_not_found_{self.__class__.__name__}.select_star") return self.response_404() # Check that the user can access the datasource if not self.appbuilder.sm.can_access_datasource( database, Table(table_name_parsed, schema_name_parsed), schema_name_parsed): self.stats_logger.incr( f"permisssion_denied_{self.__class__.__name__}.select_star") logger.warning( f"Permission denied for user {g.user} on table: {table_name_parsed} " f"schema: {schema_name_parsed}") return self.response_404() return f(self, database, table_name_parsed, schema_name_parsed)
def table_extra_metadata(self, database: Database, table_name: str, schema_name: str) -> FlaskResponse: """Table schema info --- get: summary: >- Get table extra metadata description: >- Response depends on each DB engine spec normally focused on partitions parameters: - in: path schema: type: integer name: pk description: The database id - in: path schema: type: string name: table_name description: Table name - in: path schema: type: string name: schema_name description: Table schema responses: 200: description: Table extra metadata information content: application/json: schema: $ref: "#/components/schemas/TableExtraMetadataResponseSchema" 400: $ref: '#/components/responses/400' 401: $ref: '#/components/responses/401' 404: $ref: '#/components/responses/404' 422: $ref: '#/components/responses/422' 500: $ref: '#/components/responses/500' """ self.incr_stats("init", self.table_metadata.__name__) parsed_schema = parse_js_uri_path_item(schema_name, eval_undefined=True) table_name = parse_js_uri_path_item(table_name) # type: ignore payload = database.db_engine_spec.extra_table_metadata( database, table_name, parsed_schema) return self.response(200, **payload)
def test_parse_js_uri_path_items_item_optional(self): self.assertIsNone(parse_js_uri_path_item(None)) self.assertIsNotNone(parse_js_uri_path_item("item"))
def test_parse_js_uri_path_items_unquote(self): self.assertEqual("slashed/name", parse_js_uri_path_item("slashed%2fname")) self.assertEqual( "slashed%2fname", parse_js_uri_path_item("slashed%2fname", unquote=False))
def test_parse_js_uri_path_items_eval_undefined(self): self.assertIsNone( parse_js_uri_path_item("undefined", eval_undefined=True)) self.assertIsNone(parse_js_uri_path_item("null", eval_undefined=True)) self.assertEqual("undefined", parse_js_uri_path_item("undefined")) self.assertEqual("null", parse_js_uri_path_item("null"))
def test_parse_js_uri_path_items_eval_undefined(self): self.assertIsNone(parse_js_uri_path_item('undefined', eval_undefined=True)) self.assertIsNone(parse_js_uri_path_item('null', eval_undefined=True)) self.assertEqual('undefined', parse_js_uri_path_item('undefined')) self.assertEqual('null', parse_js_uri_path_item('null'))
def table_metadata(self, pk: int, table_name: str, schema_name: str): # pylint: disable=invalid-name """ Table schema info --- get: description: Get database table metadata parameters: - in: path schema: type: integer name: pk description: The database id - in: path schema: type: string name: table_name description: Table name - in: path schema: type: string name: schema description: Table schema responses: 200: description: Table schema info content: text/plain: schema: type: object properties: columns: type: array description: Table columns info items: type: object properties: keys: type: array items: type: string longType: type: string name: type: string type: type: string foreignKeys: type: array description: Table list of foreign keys items: type: object properties: column_names: type: array items: type: string name: type: string options: type: object referred_columns: type: array items: type: string referred_schema: type: string referred_table: type: string type: type: string indexes: type: array description: Table list of indexes items: type: object properties: column_names: type: array items: type: string name: type: string options: type: object referred_columns: type: array items: type: string referred_schema: type: string referred_table: type: string type: type: string primaryKey: type: object properties: column_names: type: array items: type: string name: type: string type: type: string 400: $ref: '#/components/responses/400' 401: $ref: '#/components/responses/401' 404: $ref: '#/components/responses/404' 422: $ref: '#/components/responses/422' 500: $ref: '#/components/responses/500' """ table_name_parsed = parse_js_uri_path_item(table_name) schema_parsed = parse_js_uri_path_item(schema_name, eval_undefined=True) # schemas can be None but not tables if not table_name_parsed: return self.response_422( message=_(f"Could not parse table name or schema")) database: Database = self.datamodel.get(pk, self._base_filters) if not database: return self.response_404() try: table_info: Dict = get_table_metadata(database, table_name_parsed, schema_parsed) except SQLAlchemyError as e: return self.response_422(error_msg_from_exception(e)) return self.response(200, **table_info)