Skip to content

Commit

Permalink
Remove file ext validation (#185)
Browse files Browse the repository at this point in the history
  • Loading branch information
Nimond committed Sep 14, 2021
1 parent 81b9701 commit 944239c
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 95 deletions.
2 changes: 1 addition & 1 deletion botx/clients/clients/processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def build_file(response: HTTPResponse) -> File:
Built file from response.
"""
mimetype = response.headers["content-type"].split(";", 1)[0]
ext = File.get_ext_by_mimetype(mimetype)
ext = File.get_ext_by_mimetype(mimetype) or ""
file_name = "document{0}".format(ext)
return File.from_file(BytesIO(response.raw_data), file_name) # type: ignore

Expand Down
151 changes: 85 additions & 66 deletions botx/models/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,58 +9,115 @@
from uuid import UUID

from base64io import Base64IO
from pydantic import validator

from botx.models.base import BotXBaseModel
from botx.models.enums import AttachmentsTypes

EXTENSIONS_TO_MIMETYPES = MappingProxyType(
{
# image_extensions
".gif": "image/gif",
".jpeg": "image/jpeg",
".jpg": "image/jpeg",
".png": "image/png",
".svg": "image/svg+xml",
".tiff": "image/tiff",
# document_extensions
".csv": "text/csv",
# application
".7z": "application/x-7z-compressed",
".abw": "application/x-abiword",
".ai": "application/postscript",
".arc": "application/x-freearc",
".azw": "application/vnd.amazon.ebook",
".bin": "application/octet-stream",
".bz": "application/x-bzip",
".bz2": "application/x-bzip2",
".cda": "application/x-cdf",
".csh": "application/x-csh",
".doc": "application/msword",
".docm": "application/vnd.ms-word.document.macroenabled.12",
".docx": (
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
),
".eot": "application/vnd.ms-fontobject",
".eps": "application/postscript",
".epub": "application/epub+zip",
".gz": "application/gzip",
".html": "text/html",
".jar": "application/java-archive",
".json-api": "application/vnd.api+json",
".json-patch": "application/json-patch+json",
".json": "application/json",
".mp3": "audio/mpeg",
".mp4": "video/mp4",
".jsonld": "application/ld+json",
".mdb": "application/x-msaccess",
".mpkg": "application/vnd.apple.installer+xml",
".odp": "application/vnd.oasis.opendocument.presentation",
".ods": "application/vnd.oasis.opendocument.spreadsheet",
".odt": "application/vnd.oasis.opendocument.text",
".ogx": "application/ogg",
".pdf": "application/pdf",
".php": "application/x-httpd-php",
".ppt": "application/vnd.ms-powerpoint",
".pptm": "application/vnd.ms-powerpoint.presentation.macroenabled.12",
".pptx": (
"application/vnd.openxmlformats-officedocument.presentationml.presentation"
),
".psd": "image/vnd.adobe.photoshop",
".ps": "application/postscript",
".rar": "application/vnd.rar",
".rtf": "application/rtf",
".sig": "application/pgp-signature",
".tgz": "application/gzip",
".txt": "text/plain",
".sh": "application/x-sh",
".swf": "application/x-shockwave-flash",
".tar": "application/x-tar",
".vsd": "application/vnd.visio",
".vsdx": "application/octet-stream",
".wasm": "application/wasm",
".webmanifest": "application/manifest+json",
".xhtml": "application/xhtml+xml",
".xls": "application/vnd.ms-excel",
".xlsm": "application/vnd.ms-excel.sheet.macroenabled.12",
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
".xml": "text/xml",
".xul": "application/vnd.mozilla.xul+xml",
".zip": "application/zip",
# audio
".aac": "audio/aac",
".mid": "audio/midi",
".midi": "audio/midi",
".mp3": "audio/mpeg",
".oga": "audio/ogg",
".opus": "audio/opus",
".wav": "audio/wav",
".weba": "audio/webm",
# font
".otf": "font/otf",
".ttf": "font/ttf",
".woff": "font/woff",
".woff2": "font/woff2",
# image
".avif": "image/avif",
".bmp": "image/bmp",
".gif": "image/gif",
".ico": "image/vnd.microsoft.icon",
".jpeg": "image/jpeg",
".jpg": "image/jpeg",
".png": "image/png",
".svg": "image/svg+xml",
".svgz": "image/svg+xml",
".tif": "image/tiff",
".tiff": "image/tiff",
".webp": "image/webp",
# text
".css": "text/css",
".csv": "text/csv",
".htm": "text/html",
".html": "text/html",
".ics": "text/calendar",
".js": "text/javascript",
".mjs": "text/javascript",
".txt": "text/plain",
".text": "text/plain",
".xml": "text/xml",
# video
".3g2": "video/3gpp2",
".3gp": "video/3gpp",
".avi": "video/x-msvideo",
".mov": "video/quicktime",
".mp4": "video/mp4",
".mpeg": "video/mpeg",
".mpg": "video/mpeg",
".ogv": "video/ogg",
".ts": "video/mp2t",
".webm": "video/webm",
".wmv": "video/x-ms-wmv",
},
)
#: file extensions that can be proceed by BotX API.
BOTX_API_ACCEPTED_EXTENSIONS = EXTENSIONS_TO_MIMETYPES.keys()
DEFAULT_MIMETYPE = "application/octet-stream"


class NamedAsyncIterable(AsyncIterable):
Expand All @@ -81,28 +138,6 @@ class File(BotXBaseModel): # noqa: WPS214
#: text under file.
caption: Optional[str] = None

@validator("file_name", always=True)
def check_file_extension(cls, name: str) -> str: # noqa: N805
"""Check that file extension can be handled by BotX API.
Arguments:
name: file name which will be checked for matching extensions.
Returns:
Passed name if matching was successful.
Raises:
ValueError: raised if extension is not supported.
"""
if not cls.has_supported_extension(name):
raise ValueError(
"file {0} has an extensions that is not supported by BotX API".format(
name,
),
)

return name

@classmethod
def from_file( # noqa: WPS210
cls,
Expand Down Expand Up @@ -229,36 +264,20 @@ def media_type(self) -> str:
return self._get_mimetype(self.file_name)

@classmethod
def has_supported_extension(cls, filename: str) -> bool:
"""Check that file extension can be handled by BotX API.
Arguments:
filename: file name to check.
Returns:
Matching result.
"""
file_extension = Path(filename).suffix.lower()
return file_extension in BOTX_API_ACCEPTED_EXTENSIONS

@classmethod
def get_ext_by_mimetype(cls, mimetype: str) -> str:
def get_ext_by_mimetype(cls, mimetype: str) -> Optional[str]:
"""Get extension by mimetype.
Arguments:
mimetype: mimetype of file.
Returns:
file extension.
Raises:
ValueError: when mimetype is unsupported.
file extension or none if mimetype not found.
"""
for ext, m_type in EXTENSIONS_TO_MIMETYPES.items():
if m_type == mimetype:
return ext

raise ValueError("`{0}` is unsupported mimetype.".format(mimetype))
return None

@classmethod
def _to_rfc2397(cls, media_type: str, encoded_data: str) -> str:
Expand All @@ -284,7 +303,7 @@ def _get_mimetype(cls, filename: str) -> str:
File mimetype.
"""
file_extension = Path(filename).suffix.lower()
return EXTENSIONS_TO_MIMETYPES[file_extension]
return EXTENSIONS_TO_MIMETYPES.get(file_extension, DEFAULT_MIMETYPE)


class MetaFile(BotXBaseModel):
Expand Down
16 changes: 16 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
## 0.24.0 (Sep 14, 2021)

### Removed

* File extensions validation.
* `File.has_supported_extension` classmethod.

### Added

* Multiple mime-types.

### Changed

* `File.get_ext_by_mimetype` now don't raise `ValueError` and returns `None` if mimetype not found.


## 0.23.2 (Sep 09, 2021)

### Added
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "botx"
version = "0.23.2"
version = "0.24.0"
description = "A little python framework for building bots for eXpress"
license = "MIT"
authors = [
Expand Down
18 changes: 1 addition & 17 deletions tests/test_models/test_files/test_attributes.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import pytest

from botx import File


Expand All @@ -23,19 +21,5 @@ def test_retrieving_file_size():
assert File.from_string(b"file\ncontents", filename="test.txt").size_in_bytes == 13


@pytest.mark.parametrize("extension", [".txt", ".TXT"])
def test_accept_has_supported_extension(extension):
filename = f"test{extension}"

assert File.has_supported_extension(filename)


def test_decline_has_supported_extension():
bad_filename = "test.bad"

assert not File.has_supported_extension(bad_filename)


def test_get_ext_by_unsupported_mimetype():
with pytest.raises(ValueError):
File.get_ext_by_mimetype("application/javascript")
assert File.get_ext_by_mimetype("application/javascript") is None
10 changes: 0 additions & 10 deletions tests/test_models/test_files/test_errors.py

This file was deleted.

1 comment on commit 944239c

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 Published on https://pybotx.netlify.app as production
🚀 Deployed on https://6140793a37b75e15dc7e0435--pybotx.netlify.app

Please sign in to comment.