You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by di...@apache.org on 2024/02/21 10:13:26 UTC
(superset) 04/10: Validate inputs
This is an automated email from the ASF dual-hosted git repository.
diegopucci pushed a commit to branch diego/ch78628/fix-disabled-ssh-toggle
in repository https://gitbox.apache.org/repos/asf/superset.git
commit a17aac711998b1227d72ba7cda36da1fa2dc4912
Author: geido <di...@gmail.com>
AuthorDate: Mon Feb 19 17:02:50 2024 +0200
Validate inputs
---
.../databases/DatabaseModal/SSHTunnelForm.tsx | 12 ++++-----
.../src/features/databases/DatabaseModal/index.tsx | 21 +++++++--------
superset-frontend/src/features/databases/types.ts | 30 +++++++++++++++++-----
superset/commands/database/ssh_tunnel/create.py | 3 +++
superset/commands/database/ssh_tunnel/update.py | 9 +++++++
5 files changed, 49 insertions(+), 26 deletions(-)
diff --git a/superset-frontend/src/features/databases/DatabaseModal/SSHTunnelForm.tsx b/superset-frontend/src/features/databases/DatabaseModal/SSHTunnelForm.tsx
index 7823d82faf..e0d1b16ff2 100644
--- a/superset-frontend/src/features/databases/DatabaseModal/SSHTunnelForm.tsx
+++ b/superset-frontend/src/features/databases/DatabaseModal/SSHTunnelForm.tsx
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import React, { EventHandler, ChangeEvent, useState } from 'react';
+import React, { useState } from 'react';
import { t, styled } from '@superset-ui/core';
import { AntdForm, Col, Row } from 'src/components';
import { Form, FormLabel } from 'src/components/Form';
@@ -24,7 +24,7 @@ import { Radio } from 'src/components/Radio';
import { Input, TextArea } from 'src/components/Input';
import { Input as AntdInput, Tooltip } from 'antd';
import { EyeInvisibleOutlined, EyeOutlined } from '@ant-design/icons';
-import { DatabaseObject } from '../types';
+import { DatabaseObject, FieldPropTypes } from '../types';
import { AuthType } from '.';
const StyledDiv = styled.div`
@@ -54,9 +54,7 @@ const SSHTunnelForm = ({
setSSHTunnelLoginMethod,
}: {
db: DatabaseObject | null;
- onSSHTunnelParametersChange: EventHandler<
- ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
- >;
+ onSSHTunnelParametersChange: FieldPropTypes['changeMethods']['onSSHTunnelParametersChange'];
setSSHTunnelLoginMethod: (method: AuthType) => void;
}) => {
const [usePassword, setUsePassword] = useState<AuthType>(AuthType.Password);
@@ -86,9 +84,9 @@ const SSHTunnelForm = ({
</FormLabel>
<Input
name="server_port"
- type="text"
placeholder={t('22')}
- value={db?.ssh_tunnel?.server_port || ''}
+ type="number"
+ value={db?.ssh_tunnel?.server_port}
onChange={onSSHTunnelParametersChange}
data-test="ssh-tunnel-server_port-input"
/>
diff --git a/superset-frontend/src/features/databases/DatabaseModal/index.tsx b/superset-frontend/src/features/databases/DatabaseModal/index.tsx
index a4a7ddad4a..3607e5e400 100644
--- a/superset-frontend/src/features/databases/DatabaseModal/index.tsx
+++ b/superset-frontend/src/features/databases/DatabaseModal/index.tsx
@@ -662,7 +662,12 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
masked_encrypted_extra: db?.masked_encrypted_extra || '',
server_cert: db?.server_cert || undefined,
ssh_tunnel:
- !isEmpty(db?.ssh_tunnel) && useSSHTunneling ? db.ssh_tunnel : undefined,
+ !isEmpty(db?.ssh_tunnel) && useSSHTunneling
+ ? {
+ ...db.ssh_tunnel,
+ server_port: Number(db.ssh_tunnel!.server_port),
+ }
+ : undefined,
};
setTestInProgress(true);
testDatabaseConnection(
@@ -694,10 +699,6 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
setValidationErrors(null);
};
- const handleClearSSHTunnelConfig = () => {
- setDB({ type: ActionType.RemoveSSHTunnelConfig });
- };
-
const handleParametersChange = ({ target }: { target: HTMLInputElement }) => {
onChange(ActionType.ParametersChange, {
type: target.type,
@@ -1541,8 +1542,8 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
typeof dbErrors === 'object'
? Object.values(dbErrors)
: typeof dbErrors === 'string'
- ? [dbErrors]
- : [];
+ ? [dbErrors]
+ : [];
} else if (
!isEmpty(validationErrors) &&
validationErrors?.error_type === 'GENERIC_DB_ENGINE_ERROR'
@@ -1578,11 +1579,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
const renderSSHTunnelForm = () => (
<SSHTunnelForm
db={db as DatabaseObject}
- onSSHTunnelParametersChange={({
- target,
- }: {
- target: HTMLInputElement | HTMLTextAreaElement;
- }) =>
+ onSSHTunnelParametersChange={({ target }) =>
onChange(ActionType.ParametersSSHTunnelChange, {
type: target.type,
name: target.name,
diff --git a/superset-frontend/src/features/databases/types.ts b/superset-frontend/src/features/databases/types.ts
index 2f481d8315..1ae4a7f715 100644
--- a/superset-frontend/src/features/databases/types.ts
+++ b/superset-frontend/src/features/databases/types.ts
@@ -1,6 +1,6 @@
import { JsonObject } from '@superset-ui/core';
import { InputProps } from 'antd/lib/input';
-import { FormEvent } from 'react';
+import { ChangeEvent, EventHandler, FormEvent } from 'react';
/**
* Licensed to the Apache Software Foundation (ASF) under one
@@ -236,23 +236,39 @@ export interface ExtraJson {
version?: string;
}
-type ParametersChangeValueType = Partial<Omit<HTMLInputElement, 'value'>> & {
- value?: string | boolean;
+type CustomTextType = {
+ value?: string | boolean | number;
+ type?: string | null;
+ name?: string;
+ checked?: boolean;
};
-type ParametersChangeType<T = ParametersChangeValueType> =
+type CustomHTMLInputElement = Omit<Partial<CustomTextType>, 'value' | 'type'> &
+ CustomTextType;
+
+type CustomHTMLTextAreaElement = Omit<
+ Partial<CustomTextType>,
+ 'value' | 'type'
+> &
+ CustomTextType;
+
+export type CustomParametersChangeType<T = CustomTextType> =
| FormEvent<InputProps>
| { target: T };
+export type CustomEventHandlerType = EventHandler<
+ ChangeEvent<CustomHTMLInputElement | CustomHTMLTextAreaElement>
+>;
+
export interface FieldPropTypes {
required: boolean;
hasTooltip?: boolean;
tooltipText?: (value: any) => string;
placeholder?: string;
- onParametersChange: (event: ParametersChangeType) => void;
+ onParametersChange: (event: CustomParametersChangeType) => void;
onParametersUploadFileChange: (value: any) => string;
changeMethods: {
- onParametersChange: (event: ParametersChangeType) => void;
+ onParametersChange: (event: CustomParametersChangeType) => void;
} & {
onChange: (value: any) => string;
} & {
@@ -262,7 +278,7 @@ export interface FieldPropTypes {
onRemoveTableCatalog: (idx: number) => void;
} & {
onExtraInputChange: (value: any) => void;
- onSSHTunnelParametersChange: (value: any) => string;
+ onSSHTunnelParametersChange: CustomEventHandlerType;
};
validationErrors: JsonObject | null;
getValidation: () => void;
diff --git a/superset/commands/database/ssh_tunnel/create.py b/superset/commands/database/ssh_tunnel/create.py
index cbfee3ce2a..59e083d4d8 100644
--- a/superset/commands/database/ssh_tunnel/create.py
+++ b/superset/commands/database/ssh_tunnel/create.py
@@ -57,6 +57,7 @@ class CreateSSHTunnelCommand(BaseCommand):
server_address: Optional[str] = self._properties.get("server_address")
server_port: Optional[int] = self._properties.get("server_port")
username: Optional[str] = self._properties.get("username")
+ password: Optional[str] = self._properties.get("password")
private_key: Optional[str] = self._properties.get("private_key")
private_key_password: Optional[str] = self._properties.get(
"private_key_password"
@@ -67,6 +68,8 @@ class CreateSSHTunnelCommand(BaseCommand):
exceptions.append(SSHTunnelRequiredFieldValidationError("server_port"))
if not username:
exceptions.append(SSHTunnelRequiredFieldValidationError("username"))
+ if not private_key and not password:
+ exceptions.append(SSHTunnelRequiredFieldValidationError("password"))
if private_key_password and private_key is None:
exceptions.append(SSHTunnelRequiredFieldValidationError("private_key"))
if exceptions:
diff --git a/superset/commands/database/ssh_tunnel/update.py b/superset/commands/database/ssh_tunnel/update.py
index ae7ee78afe..47f7d4947a 100644
--- a/superset/commands/database/ssh_tunnel/update.py
+++ b/superset/commands/database/ssh_tunnel/update.py
@@ -43,6 +43,15 @@ class UpdateSSHTunnelCommand(BaseCommand):
self.validate()
try:
if self._model is not None: # So we dont get incompatible types error
+ # unset password if private key is provided
+ if self._properties.get("private_key"):
+ self._properties["password"] = None
+
+ # unset private key and password if password is provided
+ if self._properties.get("password"):
+ self._properties["private_key"] = None
+ self._properties["private_key_password"] = None
+
tunnel = SSHTunnelDAO.update(self._model, self._properties)
except DAOUpdateFailedError as ex:
raise SSHTunnelUpdateFailedError() from ex