diff --git a/requirements/base.txt b/requirements/base.txt index 4b7363ca18c67..9a007094b1e7c 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -100,7 +100,7 @@ flask-sqlalchemy==2.5.1 # flask-migrate flask-talisman==0.8.1 # via apache-superset -flask-wtf==0.14.3 +flask-wtf==1.0.1 # via # apache-superset # flask-appbuilder diff --git a/superset/config.py b/superset/config.py index 6760a0af72909..b16f759e28863 100644 --- a/superset/config.py +++ b/superset/config.py @@ -735,6 +735,9 @@ def _try_json_readsha(filepath: str, length: int) -> Optional[str]: CSV_EXTENSIONS = {"csv", "tsv", "txt"} COLUMNAR_EXTENSIONS = {"parquet", "zip"} ALLOWED_EXTENSIONS = {*EXCEL_EXTENSIONS, *CSV_EXTENSIONS, *COLUMNAR_EXTENSIONS} +CSV_MAX_SIZES = 1 * 1024 * 1024 +CSV_MAX_ROWS = 1000 +CSV_MIN_ROWS = 1 # CSV Options: key/value pairs that will be passed as argument to DataFrame.to_csv # method. diff --git a/superset/views/base.py b/superset/views/base.py index 74a2e2a2d7e64..afc66453032fd 100644 --- a/superset/views/base.py +++ b/superset/views/base.py @@ -79,8 +79,7 @@ from superset.translations.utils import get_language_pack from superset.utils import core as utils from superset.utils.core import get_user_id - -from .utils import bootstrap_user_data +from superset.views.utils import bootstrap_user_data FRONTEND_CONF_KEYS = ( "SUPERSET_WEBSERVER_TIMEOUT", @@ -110,6 +109,9 @@ "CSV_EXTENSIONS", "COLUMNAR_EXTENSIONS", "ALLOWED_EXTENSIONS", + "CSV_MAX_SIZES", + "CSV_MAX_ROWS", + "CSV_MIN_ROWS", "SAMPLES_ROW_LIMIT", "DEFAULT_TIME_FILTER", "HTML_SANITIZATION", diff --git a/superset/views/database/forms.py b/superset/views/database/forms.py index 91ab38dc2fe5e..612574f71f13c 100644 --- a/superset/views/database/forms.py +++ b/superset/views/database/forms.py @@ -20,7 +20,7 @@ from flask_appbuilder.fieldwidgets import BS3TextFieldWidget from flask_appbuilder.forms import DynamicForm from flask_babel import lazy_gettext as _ -from flask_wtf.file import FileAllowed, FileField, FileRequired +from flask_wtf.file import FileAllowed, FileField, FileRequired, FileSize from wtforms import ( BooleanField, IntegerField, @@ -107,9 +107,23 @@ def is_engine_allowed_to_file_upl(database: Database) -> bool: class CsvToDatabaseForm(UploadToDatabaseForm): csv_file = FileField( _("CSV Upload"), - description=_("Select a file to be uploaded to the database"), + description=_( + "Select a file to be uploaded to a database. Max Size of the file should be " + + str(config["CSV_MAX_SIZES"] / 1048576) + + " MB and the accepted extensions are: " + "%(allowed_extensions)s", + allowed_extensions=", ".join( + config["ALLOWED_EXTENSIONS"].intersection(config["CSV_EXTENSIONS"]) + ), + ), validators=[ FileRequired(), + FileSize( + config["CSV_MAX_SIZES"], + message="File size must not exceed the limit: " + + str(config["CSV_MAX_SIZES"] / 1048576) + + "MB", + ), FileAllowed( config["ALLOWED_EXTENSIONS"].intersection(config["CSV_EXTENSIONS"]), _( @@ -252,8 +266,18 @@ class CsvToDatabaseForm(UploadToDatabaseForm): ) nrows = IntegerField( _("Rows to Read"), - description=_("Number of rows of file to read"), - validators=[Optional(), NumberRange(min=0)], + description=_( + "Number of rows of file to read. Minimum " + + str(config["CSV_MIN_ROWS"]) + + " and Maximum " + + str(config["CSV_MAX_ROWS"]) + + " rows are allowed" + ), + validators=[ + Optional(), + NumberRange(min=config["CSV_MIN_ROWS"]), + NumberRange(max=config["CSV_MAX_ROWS"]), + ], widget=BS3TextFieldWidget(), ) skiprows = IntegerField(