| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 | from collections import abcfrom werkzeug.datastructures import FileStoragefrom wtforms import FileField as _FileFieldfrom wtforms import MultipleFileField as _MultipleFileFieldfrom wtforms.validators import DataRequiredfrom wtforms.validators import StopValidationfrom wtforms.validators import ValidationErrorclass FileField(_FileField):    """Werkzeug-aware subclass of :class:`wtforms.fields.FileField`."""    def process_formdata(self, valuelist):        valuelist = (x for x in valuelist if isinstance(x, FileStorage) and x)        data = next(valuelist, None)        if data is not None:            self.data = data        else:            self.raw_data = ()class MultipleFileField(_MultipleFileField):    """Werkzeug-aware subclass of :class:`wtforms.fields.MultipleFileField`.    .. versionadded:: 1.2.0    """    def process_formdata(self, valuelist):        valuelist = (x for x in valuelist if isinstance(x, FileStorage) and x)        data = list(valuelist) or None        if data is not None:            self.data = data        else:            self.raw_data = ()class FileRequired(DataRequired):    """Validates that the uploaded files(s) is a Werkzeug    :class:`~werkzeug.datastructures.FileStorage` object.    :param message: error message    You can also use the synonym ``file_required``.    """    def __call__(self, form, field):        field_data = [field.data] if not isinstance(field.data, list) else field.data        if not (            all(isinstance(x, FileStorage) and x for x in field_data) and field_data        ):            raise StopValidation(                self.message or field.gettext("This field is required.")            )file_required = FileRequiredclass FileAllowed:    """Validates that the uploaded file(s) is allowed by a given list of    extensions or a Flask-Uploads :class:`~flaskext.uploads.UploadSet`.    :param upload_set: A list of extensions or an        :class:`~flaskext.uploads.UploadSet`    :param message: error message    You can also use the synonym ``file_allowed``.    """    def __init__(self, upload_set, message=None):        self.upload_set = upload_set        self.message = message    def __call__(self, form, field):        field_data = [field.data] if not isinstance(field.data, list) else field.data        if not (            all(isinstance(x, FileStorage) and x for x in field_data) and field_data        ):            return        filenames = [f.filename.lower() for f in field_data]        for filename in filenames:            if isinstance(self.upload_set, abc.Iterable):                if any(filename.endswith("." + x) for x in self.upload_set):                    continue                raise StopValidation(                    self.message                    or field.gettext(                        "File does not have an approved extension: {extensions}"                    ).format(extensions=", ".join(self.upload_set))                )            if not self.upload_set.file_allowed(field_data, filename):                raise StopValidation(                    self.message                    or field.gettext("File does not have an approved extension.")                )file_allowed = FileAllowedclass FileSize:    """Validates that the uploaded file(s) is within a minimum and maximum    file size (set in bytes).    :param min_size: minimum allowed file size (in bytes). Defaults to 0 bytes.    :param max_size: maximum allowed file size (in bytes).    :param message: error message    You can also use the synonym ``file_size``.    """    def __init__(self, max_size, min_size=0, message=None):        self.min_size = min_size        self.max_size = max_size        self.message = message    def __call__(self, form, field):        field_data = [field.data] if not isinstance(field.data, list) else field.data        if not (            all(isinstance(x, FileStorage) and x for x in field_data) and field_data        ):            return        for f in field_data:            file_size = len(f.read())            f.seek(0)  # reset cursor position to beginning of file            if (file_size < self.min_size) or (file_size > self.max_size):                # the file is too small or too big => validation failure                raise ValidationError(                    self.message                    or field.gettext(                        "File must be between {min_size} and {max_size} bytes.".format(                            min_size=self.min_size, max_size=self.max_size                        )                    )                )file_size = FileSize
 |