├── .env-example ├── .github └── workflows │ ├── publish.yml │ └── test.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── MANIFEST.in ├── README.md ├── codecov.yml ├── config └── database.py ├── craft ├── description ├── makefile ├── pyproject.toml ├── pytest.ini ├── requirements.txt ├── setup.cfg ├── setup.py ├── src ├── __init__.py └── filemanager │ ├── __init__.py │ ├── config │ ├── __init__.py │ └── filemanager.py │ ├── constants │ └── __init__.py │ ├── controllers │ └── filemanager_controller.py │ ├── drivers │ ├── filemanager_driver.py │ ├── local_driver.py │ └── s3_driver.py │ ├── filemanager.py │ ├── providers │ ├── __init__.py │ └── filemanager_provider.py │ ├── resources │ ├── __init__.py │ ├── dropzone.min.css │ ├── dropzone.min.js │ ├── glightbox.min.css │ ├── glightbox.min.js │ ├── picker.css │ └── picker.js │ ├── routes │ ├── __init__.py │ └── route.py │ └── templates │ ├── details.html │ ├── index.html │ ├── partials │ ├── create_form.html │ ├── dialog.html │ ├── grid.html │ ├── list.html │ ├── previews │ │ ├── audio.html │ │ ├── file.html │ │ ├── image.html │ │ ├── pdf.html │ │ └── video.html │ └── rename_form.html │ ├── picker.html │ └── sidebar.html ├── tests ├── __init__.py ├── integrations │ ├── Kernel.py │ ├── app │ │ ├── __init__.py │ │ ├── controllers │ │ │ ├── WelcomeController.py │ │ │ └── __init__.py │ │ ├── middlewares │ │ │ └── VerifyCsrfToken.py │ │ └── models │ │ │ └── User.py │ ├── config │ │ ├── __init__.py │ │ ├── application.py │ │ ├── auth.py │ │ ├── broadcast.py │ │ ├── cache.py │ │ ├── database.py │ │ ├── exceptions.py │ │ ├── filesystem.py │ │ ├── mail.py │ │ ├── notification.py │ │ ├── providers.py │ │ ├── queue.py │ │ └── session.py │ ├── databases │ │ ├── migrations │ │ │ ├── 2021_01_09_033202_create_password_reset_table.py │ │ │ └── 2021_01_09_043202_create_users_table.py │ │ └── seeds │ │ │ ├── __init__.py │ │ │ ├── database_seeder.py │ │ │ └── user_table_seeder.py │ ├── resources │ │ ├── css │ │ │ └── app.css │ │ └── js │ │ │ ├── app.js │ │ │ └── bootstrap.js │ ├── routes │ │ └── web.py │ ├── storage │ │ ├── .gitignore │ │ └── public │ │ │ ├── favicon.ico │ │ │ ├── logo.png │ │ │ └── robots.txt │ └── templates │ │ ├── __init__.py │ │ ├── base.html │ │ ├── form.html │ │ ├── maintenance.html │ │ └── welcome.html └── unit │ ├── __init__.py │ └── test_package.py └── wsgi.py /.env-example: -------------------------------------------------------------------------------- 1 | APP_DEBUG=True 2 | APP_ENV=development 3 | APP_KEY=plyUWY8iZnEH9_8WrVjl-LS3B8aRtHK9UAB35fGAq0M= 4 | DB_CONFIG_PATH=tests/integrations/config/database 5 | DB_CONNECTION=sqlite 6 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Package in PyPi 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | - name: Set up Python 13 | uses: actions/setup-python@v4 14 | with: 15 | python-version: "3.x" 16 | - name: Install dependencies 17 | run: | 18 | make init 19 | - name: Publish only packages passing test 20 | run: | 21 | make test 22 | - name: Build and publish 23 | env: 24 | TWINE_USERNAME: __token__ 25 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} 26 | run: | 27 | make publish -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: Test Package 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | python-version: ["3.7", "3.8", "3.9", "3.10"] 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | - name: Set up Python ${{ matrix.python-version }} 24 | uses: actions/setup-python@v2 25 | with: 26 | python-version: ${{ matrix.python-version }} 27 | - name: Install dependencies 28 | run: | 29 | python -m pip install --upgrade pip 30 | python -m pip install flake8 pytest 31 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 32 | - name: Lint with flake8 33 | run: | 34 | # stop the build if there are Python syntax errors or undefined names 35 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 36 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 37 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 38 | - name: Test with pytest 39 | run: | 40 | pytest 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | venv2 3 | .vscode 4 | .idea/ 5 | build/ 6 | .pypirc 7 | .coverage 8 | coverage.xml 9 | .pytest_* 10 | **/*__pycache__* 11 | **/*.DS_Store* 12 | **/*.pyc 13 | *.pyc 14 | *~ 15 | *.swp 16 | dist 17 | .env 18 | *.db 19 | src/masonite_filemanager.egg-info 20 | storage 21 | vendor -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guide 2 | 3 | ## Introduction 4 | 5 | When contributing to this repository, **please first discuss the change you wish to make via issue, email, or any other method with the owners or contributors of this repository** before making a change 😃 . Thank you ! 6 | 7 | ## Getting Started 8 | 9 | ### Get the code 10 | 11 | First you should configure your local environment to be able to make changes in this package. 12 | 13 | 1. Fork the `https://github.com/yubarajshrestha/masonite-filemanager` repo. 14 | 2. Clone that repo into your computer: `git clone http://github.com/your-username/masonite-filemanager.git`. 15 | 3. Checkout the current release branch \(example: `master`\). 16 | 4. Run `git pull origin master` to get the current release version. 17 | 18 | ### Install the environment 19 | 20 | 1. You should create a Python virtual environment with `Python >= 3.6`. 21 | 2. Then install the dependencies and setup the project, in root directory with: 22 | 23 | ``` 24 | make init 25 | ``` 26 | 27 | **Note:** 28 | 29 | - The package will be locally installed in your venv (with `pip install .`). Meaning that you will be 30 | able to import it from the project contained in the package as if you installed it from PyPi. 31 | - When making changes to your packages you will need to uninstall the package and reinstall it with 32 | `pip uninstall masonite-filemanager && pip install .` 33 | 34 | ### Contribute 35 | 36 | - From there simply create: 37 | - a feature branch `feat/my-new-feature` 38 | - a fix branch `fix/my-new-fix` 39 | - Push to your origin repository: 40 | - `git push origin feat/my-new-feature` 41 | - Open a pull request (PR) and follow the PR process below 42 | 43 | 1. You should open an issue before making any pull requests. Not all features will be added to the package and some may be better off as another third party package. It wouldn't be good if you worked on a feature for several days and the pull request gets rejected for reasons that could have been discussed in an issue for several minutes. 44 | 2. Ensure any changes are well commented and any configuration files that are added have a flagpole comment on the variables it's setting. 45 | 3. Update the README.md if installation/configuration or usage has changed. 46 | 4. It's better to add unit tests for the changes you made. 47 | 5. The PR must pass Github CI checks. The PR can be merged in once you have a successful review from a maintainer. 48 | 6. The version will be bumped by the maintainer when merging, so don't edit package version in the PR. 49 | 50 | ### Testing 51 | 52 | - To add unit tests add tests under `tests/` directory, please read about [Masonite 53 | testing](https://docs.masoniteproject.com/useful-features/testing) in the official 54 | documentation 55 | 56 | - To test your package locally in a project, a default Masonite project is available 57 | at root. Just run `python craft serve` and navigate to `localhost:8000/` and 58 | you will see `Hello Package World` in your browser. 59 | 60 | ## Dev Guidelines 61 | 62 | ### Package development 63 | 64 | You should read guidelines on package creation in the [Official Documentation](https://docs.masoniteproject.com/advanced/creating-packages) 65 | 66 | ### Comments 67 | 68 | Comments are a vital part of any repository and should be used where needed. It is important not to overcomment something. If you find you need to constantly add comments, you're code may be too complex. Code should be self documenting \(with clearly defined variable and method names\) 69 | 70 | #### Types of comments to use 71 | 72 | There are 3 main type of comments you should use when developing for Masonite: 73 | 74 | **Module Docstrings** 75 | 76 | All modules should have a docstring at the top of every module file and should look something like: 77 | 78 | ```python 79 | """ This is a module to add support for Billing users """ 80 | from masonite.request import Request 81 | ... 82 | ``` 83 | 84 | **Method and Function Docstrings** 85 | 86 | All methods and functions should also contain a docstring with a brief description of what the module does 87 | 88 | For example: 89 | 90 | ```python 91 | def some_function(self): 92 | """ 93 | This is a function that does x action. 94 | Then give an exmaple of when to use it 95 | """ 96 | ... code ... 97 | ``` 98 | 99 | **Code Comments** 100 | 101 | If you're code MUST be complex enough that future developers will not understand it, add a `#` comment above it 102 | 103 | For normal code this will look something like: 104 | 105 | ```python 106 | # This code performs a complex task that may not be understood later on 107 | # You can add a second line like this 108 | complex_code = 'value' 109 | 110 | perform_some_complex_task() 111 | ``` 112 | 113 | **Flagpole Comments** 114 | 115 | Flag pole comments are a fantastic way to give developers an inside to what is really happening and for now should only be reserved for configuration files. A flag pole comment gets its name from how the comment looks 116 | 117 | ```text 118 | """ 119 | |-------------------------------------------------------------------------- 120 | | A Heading of The Setting Being Set 121 | |-------------------------------------------------------------------------- 122 | | 123 | | A quick description 124 | | 125 | """ 126 | 127 | SETTING = "some value" 128 | ``` 129 | 130 | It's important to note that there should have exactly 75 `-` above and below the header and have a trailing `|` at the bottom of the comment. 131 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022, Yubaraj Shrestha 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-filemanager/e73a4c0e0260228d5829a9ae695a961dced76c12/MANIFEST.in -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # filemanager 2 | 3 |

4 | 5 |

6 | 7 |

8 | 9 | GitHub Workflow Status 10 | PyPI 11 | Python Version 12 | GitHub release (latest by date including pre-releases) 13 | License 14 | star 15 | Code style: black 16 |

17 | 18 | ## Introduction 19 | 20 | A simple yet powerful file management solution for your masonite application. 21 | 22 | ## Features 23 | 24 | - [x] Manager Server Files (Currently only supports local files) 25 | - [x] Upload Files 26 | - [x] Preview Files 27 | - [x] Rename Files/Folders 28 | - [x] Delete Files/Folders 29 | - [x] Download Files 30 | - [x] Move Files 31 | - [x] Search Files 32 | - [x] Protect Routes 33 | - [ ] Image Editing 34 | - [ ] Third Party Driver Support (S3, DigitalOcean Space, etc) 35 | - [x] File Picker (Form) 36 | 37 | ## Installation 38 | 39 | ```bash 40 | pip install masonite-filemanager 41 | ``` 42 | 43 | ## Configuration 44 | 45 | Add FileManagerProvider to your project in `config/providers.py`: 46 | 47 | ```python 48 | # config/providers.py 49 | # ... 50 | from filemanager.providers import FileManagerProvider 51 | 52 | # ... 53 | PROVIDERS = [ 54 | # ... 55 | # Third Party Providers 56 | FileManagerProvider, 57 | # ... 58 | ] 59 | ``` 60 | 61 | Then you can publish the package resources (if needed) by doing: 62 | 63 | ```bash 64 | python craft package:publish filemanager 65 | ``` 66 | 67 | Finally add following to `STATICFILES` section in `config/filesystem.py`: 68 | 69 | ```python 70 | # config/filesystem.py 71 | 72 | STATICFILES = { 73 | # ... 74 | # FileManager resources 75 | 'resources/vendor/filemanager': 'filemanager-assets/', 76 | "storage/framework/filesystem/filemanager": "filemanager-uploads/", 77 | } 78 | ``` 79 | 80 | ## Usage 81 | 82 | Once finishing configurations, you can access the file manager by using the following route: 83 | 84 | `http://localhost:8000/filemanager` 85 | 86 | If you want to use file picker then all you have to do is include then follow the following guidelines: 87 | 88 | 1. Add style in the header of your base template: 89 | ```html 90 | 91 | ``` 92 | 2. Add script before the `` tag of your base template: 93 | ```html 94 | 95 | ``` 96 | 3. Finally, in your form you can use selector in your form in the following way: 97 | ```html 98 |
99 | 100 |
101 | ``` 102 | or, if you want file-preview: 103 | ```html 104 |
105 | 106 |
107 | ``` 108 | 109 | The design of the file-picker is very basic so you might want to customize with your own design by modifying the stylesheet which resides in `storage/vendor/filemanager` directory. 110 | 111 | ## License 112 | 113 | masonite-filemanager is open-sourced software licensed under the [MIT license](LICENSE). 114 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | require_ci_to_pass: no 3 | 4 | github_checks: false 5 | 6 | coverage: 7 | precision: 2 8 | round: down 9 | range: "70...100" 10 | 11 | parsers: 12 | gcov: 13 | branch_detection: 14 | conditional: yes 15 | loop: yes 16 | method: no 17 | macro: no 18 | 19 | comment: 20 | layout: "footer" 21 | behavior: default 22 | require_changes: no 23 | -------------------------------------------------------------------------------- /config/database.py: -------------------------------------------------------------------------------- 1 | from masonite.environment import LoadEnvironment, env 2 | from masoniteorm.connections import ConnectionResolver 3 | 4 | # Loads in the environment variables when this page is imported. 5 | LoadEnvironment() 6 | 7 | """ 8 | The connections here don't determine the database but determine the "connection". 9 | They can be named whatever you want. 10 | """ 11 | DATABASES = { 12 | "default": env("DB_CONNECTION", "sqlite"), 13 | "sqlite": { 14 | "driver": "sqlite", 15 | "database": env("SQLITE_DB_DATABASE", "masonite.sqlite3"), 16 | "prefix": "", 17 | "log_queries": env("DB_LOG"), 18 | }, 19 | "mysql": { 20 | "driver": "mysql", 21 | "host": env("DB_HOST"), 22 | "user": env("DB_USERNAME"), 23 | "password": env("DB_PASSWORD"), 24 | "database": env("DB_DATABASE"), 25 | "port": env("DB_PORT"), 26 | "prefix": "", 27 | "grammar": "mysql", 28 | "options": { 29 | "charset": "utf8mb4", 30 | }, 31 | "log_queries": env("DB_LOG"), 32 | }, 33 | "postgres": { 34 | "driver": "postgres", 35 | "host": env("DB_HOST"), 36 | "user": env("DB_USERNAME"), 37 | "password": env("DB_PASSWORD"), 38 | "database": env("DB_DATABASE"), 39 | "port": env("DB_PORT"), 40 | "prefix": "", 41 | "grammar": "postgres", 42 | "log_queries": env("DB_LOG"), 43 | }, 44 | "mssql": { 45 | "driver": "mssql", 46 | "host": env("MSSQL_DATABASE_HOST"), 47 | "user": env("MSSQL_DATABASE_USER"), 48 | "password": env("MSSQL_DATABASE_PASSWORD"), 49 | "database": env("MSSQL_DATABASE_DATABASE"), 50 | "port": env("MSSQL_DATABASE_PORT"), 51 | "prefix": "", 52 | "log_queries": env("DB_LOG"), 53 | }, 54 | } 55 | 56 | DB = ConnectionResolver().set_connection_details(DATABASES) 57 | -------------------------------------------------------------------------------- /craft: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Craft Command. 3 | This module is really used for backup only if the masonite CLI cannot import this for you. 4 | This can be used by running "python craft". This module is not ran when the CLI can 5 | successfully import commands for you. 6 | """ 7 | 8 | from wsgi import application 9 | 10 | if __name__ == '__main__': 11 | application.make('commands').run() 12 | -------------------------------------------------------------------------------- /description: -------------------------------------------------------------------------------- 1 | Unnamed repository; edit this file 'description' to name the repository. 2 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | .PHONY: help 2 | help: ## Show this help 3 | @egrep -h '\s##\s' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' 4 | 5 | init: ## Install package dependencies 6 | cp .env-example .env 7 | pip install --upgrade pip 8 | # install test project and package dependencies 9 | pip install -r requirements.txt 10 | # install package and dev dependencies (see setup.py) 11 | pip install '.[dev]' 12 | test: ## Run package tests 13 | python -m pytest tests 14 | ci: ## [CI] Run package tests and lint 15 | make test 16 | make lint 17 | lint: ## Run code linting 18 | python -m flake8 . 19 | format: ## Format code with Black 20 | black src 21 | coverage: ## Run package tests and upload coverage reports 22 | python -m pytest --cov-report term --cov-report xml --cov=src/masonite/filemanager tests 23 | publish: ## Publish package to pypi 24 | python setup.py sdist bdist_wheel 25 | twine upload dist/* 26 | rm -fr build dist .egg src/masonite_filemanager.egg-info 27 | pypirc: ## Copy the template .pypirc in the repo to your home directory 28 | cp .pypirc ~/.pypirc -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length = 99 3 | target-version = ['py38'] 4 | include = '\.pyi?$' 5 | exclude = ''' 6 | /( 7 | \.git 8 | \.github 9 | \.vscode 10 | | \.venv 11 | | docs 12 | | node_modules 13 | | tests/integrations/templates 14 | )/ 15 | ''' 16 | 17 | [tool.isort] 18 | profile = "black" 19 | multi_line_output = 3 20 | include_trailing_comma = true -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | filterwarnings = 3 | ignore::DeprecationWarning 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | masonite>=4,<5 2 | masonite-orm>=2,<3 3 | pdf2image==1.16.0 4 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | exclude = 3 | .git, 4 | .github, 5 | .vscode, 6 | __pycache__, 7 | templates, 8 | node_modules, 9 | venv 10 | max-complexity = 10 11 | max-line-length = 99 12 | 13 | omit = 14 | */config/* 15 | setup.py 16 | */stubs/* 17 | wsgi.py 18 | tests/ -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | with open("README.md", "r") as fh: 4 | long_description = fh.read() 5 | 6 | setup( 7 | name="masonite-filemanager", 8 | # Versions should comply with PEP440. For a discussion on single-sourcing 9 | # the version across setup.py and the project code, see 10 | # https://packaging.python.org/en/latest/single_source_version.html 11 | version="0.1.3", 12 | packages=[ 13 | "filemanager", 14 | "filemanager.config", 15 | "filemanager.constants", 16 | "filemanager.controllers", 17 | "filemanager.drivers", 18 | "filemanager.providers", 19 | "filemanager.routes", 20 | "filemanager.resources", 21 | "filemanager.templates", 22 | "filemanager.templates.partials", 23 | "filemanager.templates.partials.previews", 24 | ], 25 | package_dir={"": "src"}, 26 | description="File management solution for Masonite", 27 | long_description=long_description, 28 | long_description_content_type="text/markdown", 29 | # The project's main homepage. 30 | url="https://github.com/py-package/masonite-filemanager", 31 | # Author details 32 | author="Yubaraj Shrestha", 33 | author_email="yubaraj@pypackage.com", 34 | # Choose your license 35 | license="MIT license", 36 | # If your package should include things you specify in your MANIFEST.in file 37 | # Use this option if your package needs to include files that are not python files 38 | # like html templates or css files 39 | include_package_data=True, 40 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 41 | classifiers=[ 42 | # How mature is this project? Common values are 43 | # 3 - Alpha 44 | # 4 - Beta 45 | # 5 - Production/Stable 46 | "Development Status :: 4 - Beta", 47 | # Indicate who your project is intended for 48 | "Intended Audience :: Developers", 49 | "Environment :: Web Environment", 50 | # Pick your license as you wish (should match "license" above) 51 | "License :: OSI Approved :: MIT License", 52 | "Operating System :: OS Independent", 53 | # Specify the Python versions you support here. In particular, ensure 54 | # that you indicate whether you support Python 2, Python 3 or both. 55 | "Programming Language :: Python :: 3.7", 56 | "Programming Language :: Python :: 3.8", 57 | "Programming Language :: Python :: 3.9", 58 | "Programming Language :: Python :: 3.10", 59 | "Topic :: Software Development :: Libraries :: Application Frameworks", 60 | "Topic :: Software Development :: Libraries :: Python Modules", 61 | # List package on masonite packages website 62 | "Framework :: Masonite", 63 | ], 64 | # What does your project relate to? 65 | keywords="Masonite, Python, Development, Filemanager", 66 | # List run-time dependencies here. These will be installed by pip when 67 | # your project is installed. For an analysis of "install_requires" vs pip's 68 | # requirements files see: 69 | # https://packaging.python.org/en/latest/requirements.html 70 | install_requires=["masonite>=4.0<5.0"], 71 | # List additional groups of dependencies here (e.g. development 72 | # dependencies). You can install these using the following syntax, 73 | # for example: 74 | # $ pip install -e .[dev,test] 75 | # $ pip install your-package[dev,test] 76 | extras_require={ 77 | "dev": [ 78 | "black", 79 | "flake8", 80 | "coverage", 81 | "pytest", 82 | "pytest-cov", 83 | "twine>=1.5.0", 84 | "wheel", 85 | ], 86 | }, 87 | # If there are data files included in your packages that need to be 88 | # installed, specify them here. If using Python 2.6 or less, then these 89 | # have to be included in MANIFEST.in as well. 90 | package_data={ 91 | 'filemanager': [ 92 | 'templates/*.html', 93 | 'templates/partials/*.html', 94 | 'templates/partials/previews/*.html', 95 | 'resources/*.js', 96 | 'resources/*.css' 97 | ], 98 | }, 99 | ) 100 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-filemanager/e73a4c0e0260228d5829a9ae695a961dced76c12/src/__init__.py -------------------------------------------------------------------------------- /src/filemanager/__init__.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa F401 2 | from .providers.filemanager_provider import FileManagerProvider 3 | -------------------------------------------------------------------------------- /src/filemanager/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-filemanager/e73a4c0e0260228d5829a9ae695a961dced76c12/src/filemanager/config/__init__.py -------------------------------------------------------------------------------- /src/filemanager/config/filemanager.py: -------------------------------------------------------------------------------- 1 | """filemanager Settings""" 2 | 3 | """ 4 | |-------------------------------------------------------------------------- 5 | | A Heading of The Setting Being Set 6 | |-------------------------------------------------------------------------- 7 | | 8 | | A quick description 9 | | 10 | """ 11 | 12 | DRIVER = "local" # local or s3 13 | MIDDLEWARE = ["web"] 14 | -------------------------------------------------------------------------------- /src/filemanager/constants/__init__.py: -------------------------------------------------------------------------------- 1 | NOT_IMPLEMENTED_MSG = "Not implemented" 2 | -------------------------------------------------------------------------------- /src/filemanager/controllers/filemanager_controller.py: -------------------------------------------------------------------------------- 1 | from masonite.controllers import Controller 2 | from masonite.request import Request 3 | from masonite.response import Response 4 | from masonite.views import View 5 | from masonite.configuration import config 6 | from ..filemanager import FileManager 7 | import json 8 | 9 | 10 | class FileManagerController(Controller): 11 | def __init__(self, response: Response, request: Request) -> None: 12 | self.response = response 13 | self.request = request 14 | self.manager = FileManager() 15 | 16 | def index(self, view: View): 17 | return view.render("filemanager:index", {}) 18 | 19 | def file_info(self): 20 | file = self.request.input("file") 21 | return self.manager.provider().file_info(file) 22 | 23 | def all_files(self): 24 | query = self.request.input("query", "") 25 | if query: 26 | return self.manager.provider().search_files(query=query) 27 | return self.manager.provider().all_files() 28 | 29 | def upload(self): 30 | files = self.request.input("files") 31 | self.manager.provider().upload(files) 32 | 33 | if config("filemanager.generate_previews"): 34 | self.manager.provider().generate_previews(files) 35 | 36 | return self.response.json( 37 | { 38 | "message": "File uploaded!", 39 | } 40 | ) 41 | 42 | def get_preview(self, view: View): 43 | file = json.loads(self.request.input("file")) 44 | ext = file["extension"][1:] 45 | mime, type = file["mime"].split("/") 46 | if mime == "image": 47 | return { 48 | "html": view.render( 49 | "filemanager:partials.previews.image", {"file": file, "type": ext} 50 | ).rendered_template 51 | } 52 | elif mime == "audio": 53 | return { 54 | "html": view.render( 55 | "filemanager:partials.previews.audio", {"file": file, "type": ext} 56 | ).rendered_template 57 | } 58 | elif mime == "video": 59 | return { 60 | "html": view.render( 61 | "filemanager:partials.previews.video", {"file": file, "type": ext} 62 | ).rendered_template 63 | } 64 | elif mime == "application": 65 | if type == "pdf": 66 | return { 67 | "html": view.render( 68 | "filemanager:partials.previews.pdf", {"file": file} 69 | ).rendered_template 70 | } 71 | return { 72 | "html": view.render( 73 | "filemanager:partials.previews.file", {"file": file, "type": ext} 74 | ).rendered_template 75 | } 76 | 77 | def rename(self): 78 | name = self.request.input("name") 79 | path = self.request.input("path") 80 | self.manager.provider().rename(path, name) 81 | 82 | return self.response.json( 83 | { 84 | "message": "File/Folder renamed!", 85 | } 86 | ) 87 | 88 | def create_folder(self): 89 | name = self.request.input("name") 90 | 91 | if not self.manager.provider().exists(name): 92 | self.manager.provider().create_folder(name) 93 | 94 | return self.response.json( 95 | { 96 | "message": "Folder Created...", 97 | } 98 | ) 99 | 100 | return self.response.json( 101 | { 102 | "message": "Folder already exists!", 103 | } 104 | ) 105 | 106 | def delete_folder(self): 107 | path = self.request.input("path") 108 | 109 | try: 110 | self.manager.provider().delete_folder(path) 111 | 112 | return self.response.json( 113 | { 114 | "message": "Folder deleted...", 115 | } 116 | ) 117 | except Exception as e: 118 | print(e) 119 | 120 | return self.response.json( 121 | { 122 | "message": "Folder doesn't exists!", 123 | } 124 | ) 125 | 126 | def move_file(self): 127 | paths = json.loads(self.request.input("paths")) 128 | errors = [] 129 | for path in paths: 130 | try: 131 | self.manager.provider().move_file(path["from"], path["to"]) 132 | except Exception: 133 | return { 134 | "message": "Files don't" if len(errors) > 1 else "File doesn't" + " exist!", 135 | "failed": errors, 136 | } 137 | 138 | return {"message": "Files" if len(errors) > 1 else "File" + " moved!"} 139 | 140 | def delete_file(self): 141 | path = self.request.input("path") 142 | try: 143 | self.manager.provider().delete_file(path) 144 | return self.response.json( 145 | { 146 | "message": "File deleted...", 147 | } 148 | ) 149 | except Exception as e: 150 | print(e) 151 | 152 | return self.response.json( 153 | { 154 | "message": "File doesn't exists!", 155 | } 156 | ) 157 | 158 | def picker(self, view: View): 159 | return view.render("filemanager:picker", {}) 160 | -------------------------------------------------------------------------------- /src/filemanager/drivers/filemanager_driver.py: -------------------------------------------------------------------------------- 1 | import mimetypes 2 | import os 3 | from ..constants import NOT_IMPLEMENTED_MSG 4 | 5 | 6 | class FileManagerDriver: 7 | def __init__(self) -> None: 8 | from wsgi import application 9 | 10 | self.application = application 11 | self.storage = application.make("storage") 12 | self.root = self.storage.disk("local") 13 | self.root_path = self.root.get_path("filemanager") 14 | 15 | if not os.path.exists(self.root_path): 16 | os.mkdir(self.root_path) 17 | 18 | def _get_path(self, extra=None) -> str: 19 | raise NotImplementedError(NOT_IMPLEMENTED_MSG) 20 | 21 | def _get_media_type(self, file) -> str: 22 | return mimetypes.guess_type(file.name)[0] 23 | 24 | def total_size(self) -> str: 25 | raise NotImplementedError(NOT_IMPLEMENTED_MSG) 26 | 27 | def upload(self, file): 28 | raise NotImplementedError(NOT_IMPLEMENTED_MSG) 29 | 30 | def rename(self, path, name) -> bool: 31 | raise NotImplementedError(NOT_IMPLEMENTED_MSG) 32 | 33 | def search_files(self, query="") -> dict: 34 | raise NotImplementedError(NOT_IMPLEMENTED_MSG) 35 | 36 | def all_files(self) -> dict: 37 | raise NotImplementedError(NOT_IMPLEMENTED_MSG) 38 | 39 | def exists(self, name) -> bool: 40 | raise NotImplementedError(NOT_IMPLEMENTED_MSG) 41 | 42 | def create_folder(self, name) -> bool: 43 | raise NotImplementedError(NOT_IMPLEMENTED_MSG) 44 | 45 | def delete_folder(self, name) -> bool: 46 | raise NotImplementedError(NOT_IMPLEMENTED_MSG) 47 | 48 | def delete_file(self, name) -> bool: 49 | raise NotImplementedError("Not implemented") 50 | 51 | def generate_preview(self, file): 52 | raise NotImplementedError(NOT_IMPLEMENTED_MSG) 53 | 54 | def convert_bytes(self, num) -> str: 55 | """ 56 | this function will convert bytes to MB.... GB... etc 57 | """ 58 | step_unit = 1000.0 # 1024 bad the size 59 | 60 | for x in ["bytes", "KB", "MB", "GB", "TB"]: 61 | if num < step_unit: 62 | return "%3.1f %s" % (num, x) 63 | num /= step_unit 64 | 65 | def validate(self, data: dict) -> dict: 66 | try: 67 | if data.get("total_size") is None: 68 | raise ValueError("total_size key is required") 69 | 70 | if data.get("folders") is None: 71 | raise ValueError("folders key is required") 72 | 73 | if data.get("files") is None: 74 | raise ValueError("files key is required") 75 | 76 | data["folders"] = self.verify_folder_data(data["folders"]) 77 | data["files"] = self.verify_file_data(data["files"]) 78 | 79 | return data 80 | 81 | except Exception as e: 82 | raise ValueError(e) 83 | 84 | def verify_folder_data(self, folders: list) -> list: 85 | try: 86 | filtered_folders = [] 87 | 88 | for folder in folders: 89 | if all( 90 | key in folder 91 | for key in ["name", "size", "path", "created", "modified", "total_files"] 92 | ): 93 | filtered_folders.append(folder) 94 | 95 | return filtered_folders 96 | 97 | except Exception as e: 98 | raise ValueError(e) 99 | 100 | def verify_file_data(self, files: list) -> list: 101 | try: 102 | filtered_files = [] 103 | 104 | for file in files: 105 | if all( 106 | key in file 107 | for key in ["name", "size", "path", "created", "modified", "url", "mime"] 108 | ): 109 | filtered_files.append(file) 110 | return filtered_files 111 | 112 | except Exception as e: 113 | raise ValueError(e) 114 | -------------------------------------------------------------------------------- /src/filemanager/drivers/local_driver.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | import shutil 4 | import time 5 | from .filemanager_driver import FileManagerDriver 6 | from masonite.configuration import config 7 | 8 | 9 | class LocalDriver(FileManagerDriver): 10 | def _get_path(self, extra=None) -> str: 11 | """Get the path to the filemanager directory""" 12 | 13 | request = self.application.make("request") 14 | folder = request.input("folder", None) 15 | 16 | path = self.root_path 17 | if folder: 18 | folders = folder.split(",") 19 | path = os.path.join(self.root_path, *folders) 20 | 21 | if extra: 22 | path = os.path.join(path, extra) 23 | 24 | return path 25 | 26 | def total_size(self): 27 | """Get the total size of the filemanager directory""" 28 | 29 | size = sum(file.stat().st_size for file in Path(self.root_path).rglob("*")) 30 | return self.convert_bytes(size) 31 | 32 | def exists(self, name) -> bool: 33 | """Check if a file/path exists in the filemanager directory""" 34 | 35 | return os.path.exists(self._get_path(name)) 36 | 37 | def upload(self, files): 38 | """Upload a file to the filemanager directory""" 39 | request = self.application.make("request") 40 | folder = request.input("folder", None) 41 | path = "filemanager" 42 | 43 | if folder: 44 | path = "filemanager/{}".format(folder.replace(",", "/")) 45 | for key, file in files.items(): 46 | self.storage.disk("local").put_file( 47 | path, file, os.path.splitext(file.name)[0].rstrip() 48 | ) 49 | 50 | def create_folder(self, name) -> bool: 51 | """Create a folder in the filemanager directory""" 52 | 53 | try: 54 | path = self._get_path(name) 55 | if not self.exists(path): 56 | os.mkdir(self._get_path(name)) 57 | return True 58 | except Exception as e: 59 | print(e) 60 | return False 61 | 62 | def rename(self, path, name) -> bool: 63 | """Rename a file/folder in the filemanager directory""" 64 | 65 | if os.path.exists(path): 66 | # check if path is file 67 | if os.path.isfile(path): 68 | name = "{name}.{ext}".format(name=name, ext=path.split(".")[-1]) 69 | os.rename(path, self._get_path(name)) 70 | return True 71 | return False 72 | 73 | def delete_folder(self, path) -> bool: 74 | """Delete a folder in the filemanager directory""" 75 | 76 | try: 77 | if os.path.exists(path): 78 | if len(os.listdir(path)) > 0: 79 | shutil.rmtree(path) 80 | else: 81 | os.rmdir(path) 82 | return True 83 | except Exception as e: 84 | print(e) 85 | return False 86 | 87 | def move_file(self, from_path, to_path): 88 | self.storage.disk("local").move(from_path, to_path) 89 | 90 | def delete_file(self, path) -> bool: 91 | """Delete a file in the filemanager directory""" 92 | 93 | try: 94 | if os.path.exists(path): 95 | os.unlink(path) 96 | return True 97 | except Exception as e: 98 | print(e) 99 | return False 100 | 101 | def generate_previews(self, files): 102 | from pdf2image import convert_from_path 103 | 104 | for _, file in files.items(): 105 | _, ext = os.path.splitext(file.name) 106 | if ext[1:] == "pdf": 107 | preview_folder = config("filemanager.paths.previews") 108 | if not os.path.exists(preview_folder): 109 | # if the preview directory is not present then create it. 110 | os.makedirs(preview_folder) 111 | pages = convert_from_path(os.path.join(self.root_path, file.name), 100) 112 | pages[0].save(preview_folder + os.path.splitext(file.name)[0] + ".jpg", "JPEG") 113 | 114 | def file_info(self, file): 115 | if isinstance(file, str): 116 | f = open(file) 117 | f.close() 118 | return {} 119 | 120 | def all_files(self): 121 | data = { 122 | "folders": [], 123 | "files": [], 124 | "total_size": self.total_size(), 125 | } 126 | 127 | path = self._get_path() 128 | 129 | with os.scandir(path) as entries: 130 | for item in entries: 131 | name = item.name 132 | byte_size = ( 133 | item.stat().st_size 134 | if item.is_file() 135 | else sum(file.stat().st_size for file in Path(item.path).rglob("*")) 136 | ) 137 | size = self.convert_bytes(byte_size) 138 | created_at = time.ctime(item.stat().st_ctime) 139 | modified_at = time.ctime(item.stat().st_mtime) 140 | 141 | file_url = item.path.replace(self.root_path, "/filemanager-uploads") 142 | file_url = file_url.replace("\\", "/") 143 | 144 | file_item = { 145 | "name": name if item.is_dir() else os.path.splitext(item.name)[0], 146 | "extension": "dir" if item.is_dir() else os.path.splitext(item.name)[1], 147 | "size": size, 148 | "created": created_at, 149 | "modified": modified_at, 150 | "path": item.path, 151 | } 152 | 153 | if item.is_dir(): 154 | file_item["total_files"] = len(os.listdir(item.path)) 155 | data.get("folders").append(file_item) 156 | else: 157 | file_item["url"] = file_url 158 | file_item["mime"] = self._get_media_type(item) 159 | data.get("files").append(file_item) 160 | 161 | return self.validate(data) 162 | 163 | def search_files(self, query=""): 164 | data = { 165 | "folders": [], 166 | "files": [], 167 | "total_size": self.total_size(), 168 | } 169 | 170 | path = self._get_path() 171 | 172 | with os.scandir(path) as entries: 173 | for item in entries: 174 | name = item.name 175 | byte_size = ( 176 | item.stat().st_size 177 | if item.is_file() 178 | else sum(file.stat().st_size for file in Path(item.path).rglob("*")) 179 | ) 180 | size = self.convert_bytes(byte_size) 181 | created_at = time.ctime(item.stat().st_ctime) 182 | modified_at = time.ctime(item.stat().st_mtime) 183 | 184 | file_url = item.path.replace(self.root_path, "/filemanager-uploads") 185 | file_url = file_url.replace("\\", "/") 186 | 187 | file_item = { 188 | "name": name if item.is_dir() else os.path.splitext(item.name)[0], 189 | "extension": "dir" if item.is_dir() else os.path.splitext(item.name)[1], 190 | "size": size, 191 | "created": created_at, 192 | "modified": modified_at, 193 | "path": item.path, 194 | } 195 | 196 | if item.is_dir() and query == "": 197 | file_item["total_files"] = len(os.listdir(item.path)) 198 | data.get("folders", []).append(file_item) 199 | else: 200 | file_item["url"] = file_url 201 | file_item["mime"] = self._get_media_type(item) 202 | if query == "": 203 | data.get("files", []).append(file_item) 204 | elif query in file_item["name"]: 205 | data.get("files", []).append(file_item) 206 | 207 | return self.validate(data) 208 | -------------------------------------------------------------------------------- /src/filemanager/drivers/s3_driver.py: -------------------------------------------------------------------------------- 1 | from .filemanager_driver import FileManagerDriver 2 | 3 | 4 | class S3Driver(FileManagerDriver): 5 | pass 6 | -------------------------------------------------------------------------------- /src/filemanager/filemanager.py: -------------------------------------------------------------------------------- 1 | from masonite.configuration import config 2 | from .drivers.local_driver import LocalDriver 3 | from .drivers.s3_driver import S3Driver 4 | 5 | 6 | class FileManager: 7 | def __init__(self) -> None: 8 | self.conf = config("filemanager") 9 | 10 | def provider(self, driver=None): 11 | if driver is None: 12 | driver = self.conf.get("driver", "local") 13 | if driver == "local": 14 | return LocalDriver() 15 | if driver == "s3": 16 | return S3Driver() 17 | 18 | raise ModuleNotFoundError("Driver not found") 19 | -------------------------------------------------------------------------------- /src/filemanager/providers/__init__.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa: E501 2 | from .filemanager_provider import FileManagerProvider 3 | -------------------------------------------------------------------------------- /src/filemanager/providers/filemanager_provider.py: -------------------------------------------------------------------------------- 1 | """A FileManagerProvider Service Provider.""" 2 | 3 | from masonite.packages import PackageProvider 4 | 5 | 6 | class FileManagerProvider(PackageProvider): 7 | def configure(self): 8 | """Register objects into the Service Container.""" 9 | ( 10 | self.root("filemanager") 11 | .name("filemanager") 12 | .config("config/filemanager.py", publish=True) 13 | .views("templates", publish=False) 14 | .assets("resources") 15 | .routes("routes/route.py") 16 | ) 17 | 18 | def register(self): 19 | super().register() 20 | 21 | def boot(self): 22 | """Boots services required by the container.""" 23 | pass 24 | -------------------------------------------------------------------------------- /src/filemanager/resources/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-filemanager/e73a4c0e0260228d5829a9ae695a961dced76c12/src/filemanager/resources/__init__.py -------------------------------------------------------------------------------- /src/filemanager/resources/dropzone.min.css: -------------------------------------------------------------------------------- 1 | @keyframes passing-through { 2 | 0% { 3 | opacity: 0; 4 | transform: translateY(40px); 5 | } 6 | 30%, 7 | 70% { 8 | opacity: 1; 9 | transform: translateY(0px); 10 | } 11 | 100% { 12 | opacity: 0; 13 | transform: translateY(-40px); 14 | } 15 | } 16 | @keyframes slide-in { 17 | 0% { 18 | opacity: 0; 19 | transform: translateY(40px); 20 | } 21 | 30% { 22 | opacity: 1; 23 | transform: translateY(0px); 24 | } 25 | } 26 | @keyframes pulse { 27 | 0% { 28 | transform: scale(1); 29 | } 30 | 10% { 31 | transform: scale(1.1); 32 | } 33 | 20% { 34 | transform: scale(1); 35 | } 36 | } 37 | .dropzone, 38 | .dropzone * { 39 | box-sizing: border-box; 40 | } 41 | .dropzone { 42 | min-height: 150px; 43 | border: 1px solid rgba(0, 0, 0, 0.8); 44 | border-radius: 5px; 45 | padding: 20px 20px; 46 | } 47 | .dropzone.dz-clickable { 48 | cursor: pointer; 49 | } 50 | .dropzone.dz-clickable * { 51 | cursor: default; 52 | } 53 | .dropzone.dz-clickable .dz-message, 54 | .dropzone.dz-clickable .dz-message * { 55 | cursor: pointer; 56 | } 57 | .dropzone.dz-started .dz-message { 58 | display: none; 59 | } 60 | .dropzone.dz-drag-hover { 61 | border-style: solid; 62 | } 63 | .dropzone.dz-drag-hover .dz-message { 64 | opacity: 0.5; 65 | } 66 | .dropzone .dz-message { 67 | text-align: center; 68 | margin: 2em 0; 69 | } 70 | .dropzone .dz-message .dz-button { 71 | background: none; 72 | color: inherit; 73 | border: none; 74 | padding: 0; 75 | font: inherit; 76 | cursor: pointer; 77 | outline: inherit; 78 | } 79 | .dropzone .dz-preview { 80 | position: relative; 81 | display: inline-block; 82 | vertical-align: top; 83 | margin: 16px; 84 | min-height: 100px; 85 | } 86 | .dropzone .dz-preview:hover { 87 | z-index: 1000; 88 | } 89 | .dropzone .dz-preview:hover .dz-details { 90 | opacity: 1; 91 | } 92 | .dropzone .dz-preview.dz-file-preview .dz-image { 93 | border-radius: 20px; 94 | background: #999; 95 | background: linear-gradient(to bottom, #eee, #ddd); 96 | } 97 | .dropzone .dz-preview.dz-file-preview .dz-details { 98 | opacity: 1; 99 | } 100 | .dropzone .dz-preview.dz-image-preview { 101 | background: #fff; 102 | } 103 | .dropzone .dz-preview.dz-image-preview .dz-details { 104 | transition: opacity 0.2s linear; 105 | } 106 | .dropzone .dz-preview .dz-remove { 107 | font-size: 14px; 108 | text-align: center; 109 | display: block; 110 | cursor: pointer; 111 | border: none; 112 | } 113 | .dropzone .dz-preview .dz-remove:hover { 114 | text-decoration: underline; 115 | } 116 | .dropzone .dz-preview:hover .dz-details { 117 | opacity: 1; 118 | } 119 | .dropzone .dz-preview .dz-details { 120 | z-index: 20; 121 | position: absolute; 122 | top: 0; 123 | left: 0; 124 | opacity: 0; 125 | font-size: 13px; 126 | min-width: 100%; 127 | max-width: 100%; 128 | padding: 2em 1em; 129 | text-align: center; 130 | color: rgba(0, 0, 0, 0.9); 131 | line-height: 150%; 132 | } 133 | .dropzone .dz-preview .dz-details .dz-size { 134 | margin-bottom: 1em; 135 | font-size: 16px; 136 | } 137 | .dropzone .dz-preview .dz-details .dz-filename { 138 | white-space: nowrap; 139 | } 140 | .dropzone .dz-preview .dz-details .dz-filename:hover span { 141 | border: 1px solid rgba(200, 200, 200, 0.8); 142 | background-color: rgba(255, 255, 255, 0.8); 143 | } 144 | .dropzone .dz-preview .dz-details .dz-filename:not(:hover) { 145 | overflow: hidden; 146 | text-overflow: ellipsis; 147 | } 148 | .dropzone .dz-preview .dz-details .dz-filename:not(:hover) span { 149 | border: 1px solid transparent; 150 | } 151 | .dropzone .dz-preview .dz-details .dz-filename span, 152 | .dropzone .dz-preview .dz-details .dz-size span { 153 | background-color: rgba(255, 255, 255, 0.4); 154 | padding: 0 0.4em; 155 | border-radius: 3px; 156 | } 157 | .dropzone .dz-preview:hover .dz-image img { 158 | transform: scale(1.05, 1.05); 159 | filter: blur(8px); 160 | } 161 | .dropzone .dz-preview .dz-image { 162 | border-radius: 20px; 163 | overflow: hidden; 164 | width: 120px; 165 | height: 120px; 166 | position: relative; 167 | display: block; 168 | z-index: 10; 169 | } 170 | .dropzone .dz-preview .dz-image img { 171 | display: block; 172 | } 173 | .dropzone .dz-preview.dz-success .dz-success-mark { 174 | animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); 175 | } 176 | .dropzone .dz-preview.dz-error .dz-error-mark { 177 | opacity: 1; 178 | animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); 179 | } 180 | .dropzone .dz-preview .dz-success-mark, 181 | .dropzone .dz-preview .dz-error-mark { 182 | pointer-events: none; 183 | opacity: 0; 184 | z-index: 500; 185 | position: absolute; 186 | display: block; 187 | top: 50%; 188 | left: 50%; 189 | margin-left: -27px; 190 | margin-top: -27px; 191 | background: rgba(0, 0, 0, 0.8); 192 | border-radius: 50%; 193 | } 194 | .dropzone .dz-preview .dz-success-mark svg, 195 | .dropzone .dz-preview .dz-error-mark svg { 196 | display: block; 197 | width: 54px; 198 | height: 54px; 199 | fill: #fff; 200 | } 201 | .dropzone .dz-preview.dz-processing .dz-progress { 202 | opacity: 1; 203 | transition: all 0.2s linear; 204 | } 205 | .dropzone .dz-preview.dz-complete .dz-progress { 206 | opacity: 0; 207 | transition: opacity 0.4s ease-in; 208 | } 209 | .dropzone .dz-preview:not(.dz-processing) .dz-progress { 210 | animation: pulse 6s ease infinite; 211 | } 212 | .dropzone .dz-preview .dz-progress { 213 | opacity: 1; 214 | z-index: 1000; 215 | pointer-events: none; 216 | position: absolute; 217 | height: 20px; 218 | top: 50%; 219 | margin-top: -10px; 220 | left: 15%; 221 | right: 15%; 222 | border: 3px solid rgba(0, 0, 0, 0.8); 223 | background: rgba(0, 0, 0, 0.8); 224 | border-radius: 10px; 225 | overflow: hidden; 226 | } 227 | .dropzone .dz-preview .dz-progress .dz-upload { 228 | background: #fff; 229 | display: block; 230 | position: relative; 231 | height: 100%; 232 | width: 0; 233 | transition: width 300ms ease-in-out; 234 | border-radius: 17px; 235 | } 236 | .dropzone .dz-preview.dz-error .dz-error-message { 237 | display: block; 238 | } 239 | .dropzone .dz-preview.dz-error:hover .dz-error-message { 240 | opacity: 1; 241 | pointer-events: auto; 242 | } 243 | .dropzone .dz-preview .dz-error-message { 244 | pointer-events: none; 245 | z-index: 1000; 246 | position: absolute; 247 | display: block; 248 | display: none; 249 | opacity: 0; 250 | transition: opacity 0.3s ease; 251 | border-radius: 8px; 252 | font-size: 13px; 253 | top: 130px; 254 | left: -10px; 255 | width: 140px; 256 | background: #b10606; 257 | padding: 0.5em 1em; 258 | color: #fff; 259 | } 260 | .dropzone .dz-preview .dz-error-message:after { 261 | content: ""; 262 | position: absolute; 263 | top: -6px; 264 | left: 64px; 265 | width: 0; 266 | height: 0; 267 | border-left: 6px solid transparent; 268 | border-right: 6px solid transparent; 269 | border-bottom: 6px solid #b10606; 270 | } 271 | -------------------------------------------------------------------------------- /src/filemanager/resources/dropzone.min.js: -------------------------------------------------------------------------------- 1 | !function () { function e(e) { return e && e.__esModule ? e.default : e } function t(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e } function i(e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") } function n(e, t) { for (var i = 0; i < t.length; i++) { var n = t[i]; n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, n.key, n) } } function r(e, t, i) { return t && n(e.prototype, t), i && n(e, i), e } function a(e) { return a = Object.setPrototypeOf ? Object.getPrototypeOf : function (e) { return e.__proto__ || Object.getPrototypeOf(e) }, a(e) } function o(e, t) { return o = Object.setPrototypeOf || function (e, t) { return e.__proto__ = t, e }, o(e, t) } function l(e, t) { if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function"); e.prototype = Object.create(t && t.prototype, { constructor: { value: e, writable: !0, configurable: !0 } }), t && o(e, t) } function s(e, i) { return !i || "object" != ((n = i) && n.constructor === Symbol ? "symbol" : typeof n) && "function" != typeof i ? t(e) : i; var n } var u; function c(e) { return Array.isArray(e) || "[object Object]" == {}.toString.call(e) } function d(e) { return !e || "object" != typeof e && "function" != typeof e } u = function e() { var t = [].slice.call(arguments), i = !1; "boolean" == typeof t[0] && (i = t.shift()); var n = t[0]; if (d(n)) throw new Error("extendee must be an object"); for (var r = t.slice(1), a = r.length, o = 0; o < a; o++) { var l = r[o]; for (var s in l) if (Object.prototype.hasOwnProperty.call(l, s)) { var u = l[s]; if (i && c(u)) { var h = Array.isArray(u) ? [] : {}; n[s] = e(!0, Object.prototype.hasOwnProperty.call(n, s) && !d(n[s]) ? n[s] : h, u) } else n[s] = u } } return n }; var h = function () { "use strict"; function e() { i(this, e) } return r(e, [{ key: "on", value: function (e, t) { return this._callbacks = this._callbacks || {}, this._callbacks[e] || (this._callbacks[e] = []), this._callbacks[e].push(t), this } }, { key: "emit", value: function (e) { for (var t = arguments.length, i = new Array(t > 1 ? t - 1 : 0), n = 1; n < t; n++)i[n - 1] = arguments[n]; this._callbacks = this._callbacks || {}; var r = this._callbacks[e], a = !0, o = !1, l = void 0; if (r) try { for (var s, u = r[Symbol.iterator](); !(a = (s = u.next()).done); a = !0) { var c = s.value; c.apply(this, i) } } catch (e) { o = !0, l = e } finally { try { a || null == u.return || u.return() } finally { if (o) throw l } } return this.element && this.element.dispatchEvent(this.makeEvent("dropzone:" + e, { args: i })), this } }, { key: "makeEvent", value: function (e, t) { var i = { bubbles: !0, cancelable: !0, detail: t }; if ("function" == typeof window.CustomEvent) return new CustomEvent(e, i); var n = document.createEvent("CustomEvent"); return n.initCustomEvent(e, i.bubbles, i.cancelable, i.detail), n } }, { key: "off", value: function (e, t) { if (!this._callbacks || 0 === arguments.length) return this._callbacks = {}, this; var i = this._callbacks[e]; if (!i) return this; if (1 === arguments.length) return delete this._callbacks[e], this; for (var n = 0; n < i.length; n++) { var r = i[n]; if (r === t) { i.splice(n, 1); break } } return this } }]), e }(); var p = { url: null, method: "post", withCredentials: !1, timeout: null, parallelUploads: 2, uploadMultiple: !1, chunking: !1, forceChunking: !1, chunkSize: 2e6, parallelChunkUploads: !1, retryChunks: !1, retryChunksLimit: 3, maxFilesize: 256, paramName: "file", createImageThumbnails: !0, maxThumbnailFilesize: 10, thumbnailWidth: 120, thumbnailHeight: 120, thumbnailMethod: "crop", resizeWidth: null, resizeHeight: null, resizeMimeType: null, resizeQuality: .8, resizeMethod: "contain", filesizeBase: 1e3, maxFiles: null, headers: null, clickable: !0, ignoreHiddenFiles: !0, acceptedFiles: null, acceptedMimeTypes: null, autoProcessQueue: !0, autoQueue: !0, addRemoveLinks: !1, previewsContainer: null, disablePreviews: !1, hiddenInputContainer: "body", capture: null, renameFilename: null, renameFile: null, forceFallback: !1, dictDefaultMessage: "Drop files here to upload", dictFallbackMessage: "Your browser does not support drag'n'drop file uploads.", dictFallbackText: "Please use the fallback form below to upload your files like in the olden days.", dictFileTooBig: "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.", dictInvalidFileType: "You can't upload files of this type.", dictResponseError: "Server responded with {{statusCode}} code.", dictCancelUpload: "Cancel upload", dictUploadCanceled: "Upload canceled.", dictCancelUploadConfirmation: "Are you sure you want to cancel this upload?", dictRemoveFile: "Remove file", dictRemoveFileConfirmation: null, dictMaxFilesExceeded: "You can not upload any more files.", dictFileSizeUnits: { tb: "TB", gb: "GB", mb: "MB", kb: "KB", b: "b" }, init: function () { }, params: function (e, t, i) { if (i) return { dzuuid: i.file.upload.uuid, dzchunkindex: i.index, dztotalfilesize: i.file.size, dzchunksize: this.options.chunkSize, dztotalchunkcount: i.file.upload.totalChunkCount, dzchunkbyteoffset: i.index * this.options.chunkSize } }, accept: function (e, t) { return t() }, chunksUploaded: function (e, t) { t() }, fallback: function () { var e; this.element.className = "".concat(this.element.className, " dz-browser-not-supported"); var t = !0, i = !1, n = void 0; try { for (var r, a = this.element.getElementsByTagName("div")[Symbol.iterator](); !(t = (r = a.next()).done); t = !0) { var o = r.value; if (/(^| )dz-message($| )/.test(o.className)) { e = o, o.className = "dz-message"; break } } } catch (e) { i = !0, n = e } finally { try { t || null == a.return || a.return() } finally { if (i) throw n } } e || (e = f.createElement('
'), this.element.appendChild(e)); var l = e.getElementsByTagName("span")[0]; return l && (null != l.textContent ? l.textContent = this.options.dictFallbackMessage : null != l.innerText && (l.innerText = this.options.dictFallbackMessage)), this.element.appendChild(this.getFallbackForm()) }, resize: function (e, t, i, n) { var r = { srcX: 0, srcY: 0, srcWidth: e.width, srcHeight: e.height }, a = e.width / e.height; null == t && null == i ? (t = r.srcWidth, i = r.srcHeight) : null == t ? t = i * a : null == i && (i = t / a); var o = (t = Math.min(t, r.srcWidth)) / (i = Math.min(i, r.srcHeight)); if (r.srcWidth > t || r.srcHeight > i) if ("crop" === n) a > o ? (r.srcHeight = e.height, r.srcWidth = r.srcHeight * o) : (r.srcWidth = e.width, r.srcHeight = r.srcWidth / o); else { if ("contain" !== n) throw new Error("Unknown resizeMethod '".concat(n, "'")); a > o ? i = t / a : t = i * a } return r.srcX = (e.width - r.srcWidth) / 2, r.srcY = (e.height - r.srcHeight) / 2, r.trgWidth = t, r.trgHeight = i, r }, transformFile: function (e, t) { return (this.options.resizeWidth || this.options.resizeHeight) && e.type.match(/image.*/) ? this.resizeImage(e, this.options.resizeWidth, this.options.resizeHeight, this.options.resizeMethod, t) : t(e) }, previewTemplate: e('
'), drop: function (e) { return this.element.classList.remove("dz-drag-hover") }, dragstart: function (e) { }, dragend: function (e) { return this.element.classList.remove("dz-drag-hover") }, dragenter: function (e) { return this.element.classList.add("dz-drag-hover") }, dragover: function (e) { return this.element.classList.add("dz-drag-hover") }, dragleave: function (e) { return this.element.classList.remove("dz-drag-hover") }, paste: function (e) { }, reset: function () { return this.element.classList.remove("dz-started") }, addedfile: function (e) { if (this.element === this.previewsContainer && this.element.classList.add("dz-started"), this.previewsContainer && !this.options.disablePreviews) { var t = this; e.previewElement = f.createElement(this.options.previewTemplate.trim()), e.previewTemplate = e.previewElement, this.previewsContainer.appendChild(e.previewElement); var i = !0, n = !1, r = void 0; try { for (var a, o = e.previewElement.querySelectorAll("[data-dz-name]")[Symbol.iterator](); !(i = (a = o.next()).done); i = !0) { var l = a.value; l.textContent = e.name } } catch (e) { n = !0, r = e } finally { try { i || null == o.return || o.return() } finally { if (n) throw r } } var s = !0, u = !1, c = void 0; try { for (var d, h = e.previewElement.querySelectorAll("[data-dz-size]")[Symbol.iterator](); !(s = (d = h.next()).done); s = !0)(l = d.value).innerHTML = this.filesize(e.size) } catch (e) { u = !0, c = e } finally { try { s || null == h.return || h.return() } finally { if (u) throw c } } this.options.addRemoveLinks && (e._removeLink = f.createElement(''.concat(this.options.dictRemoveFile, "")), e.previewElement.appendChild(e._removeLink)); var p = function (i) { var n = t; if (i.preventDefault(), i.stopPropagation(), e.status === f.UPLOADING) return f.confirm(t.options.dictCancelUploadConfirmation, (function () { return n.removeFile(e) })); var r = t; return t.options.dictRemoveFileConfirmation ? f.confirm(t.options.dictRemoveFileConfirmation, (function () { return r.removeFile(e) })) : t.removeFile(e) }, m = !0, v = !1, y = void 0; try { for (var g, b = e.previewElement.querySelectorAll("[data-dz-remove]")[Symbol.iterator](); !(m = (g = b.next()).done); m = !0) { g.value.addEventListener("click", p) } } catch (e) { v = !0, y = e } finally { try { m || null == b.return || b.return() } finally { if (v) throw y } } } }, removedfile: function (e) { return null != e.previewElement && null != e.previewElement.parentNode && e.previewElement.parentNode.removeChild(e.previewElement), this._updateMaxFilesReachedClass() }, thumbnail: function (e, t) { if (e.previewElement) { e.previewElement.classList.remove("dz-file-preview"); var i = !0, n = !1, r = void 0; try { for (var a, o = e.previewElement.querySelectorAll("[data-dz-thumbnail]")[Symbol.iterator](); !(i = (a = o.next()).done); i = !0) { var l = a.value; l.alt = e.name, l.src = t } } catch (e) { n = !0, r = e } finally { try { i || null == o.return || o.return() } finally { if (n) throw r } } return setTimeout((function () { return e.previewElement.classList.add("dz-image-preview") }), 1) } }, error: function (e, t) { if (e.previewElement) { e.previewElement.classList.add("dz-error"), "string" != typeof t && t.error && (t = t.error); var i = !0, n = !1, r = void 0; try { for (var a, o = e.previewElement.querySelectorAll("[data-dz-errormessage]")[Symbol.iterator](); !(i = (a = o.next()).done); i = !0) { a.value.textContent = t } } catch (e) { n = !0, r = e } finally { try { i || null == o.return || o.return() } finally { if (n) throw r } } } }, errormultiple: function () { }, processing: function (e) { if (e.previewElement && (e.previewElement.classList.add("dz-processing"), e._removeLink)) return e._removeLink.innerHTML = this.options.dictCancelUpload }, processingmultiple: function () { }, uploadprogress: function (e, t, i) { var n = !0, r = !1, a = void 0; if (e.previewElement) try { for (var o, l = e.previewElement.querySelectorAll("[data-dz-uploadprogress]")[Symbol.iterator](); !(n = (o = l.next()).done); n = !0) { var s = o.value; "PROGRESS" === s.nodeName ? s.value = t : s.style.width = "".concat(t, "%") } } catch (e) { r = !0, a = e } finally { try { n || null == l.return || l.return() } finally { if (r) throw a } } }, totaluploadprogress: function () { }, sending: function () { }, sendingmultiple: function () { }, success: function (e) { if (e.previewElement) return e.previewElement.classList.add("dz-success") }, successmultiple: function () { }, canceled: function (e) { return this.emit("error", e, this.options.dictUploadCanceled) }, canceledmultiple: function () { }, complete: function (e) { if (e._removeLink && (e._removeLink.innerHTML = this.options.dictRemoveFile), e.previewElement) return e.previewElement.classList.add("dz-complete") }, completemultiple: function () { }, maxfilesexceeded: function () { }, maxfilesreached: function () { }, queuecomplete: function () { }, addedfiles: function () { } }, f = function (n) { "use strict"; function o(n, r) { var l, c, d, h; if (i(this, o), (l = s(this, (c = o, a(c)).call(this))).element = n, l.clickableElements = [], l.listeners = [], l.files = [], "string" == typeof l.element && (l.element = document.querySelector(l.element)), !l.element || null == l.element.nodeType) throw new Error("Invalid dropzone element."); if (l.element.dropzone) throw new Error("Dropzone already attached."); o.instances.push(t(l)), l.element.dropzone = t(l); var f = null != (h = o.optionsForElement(l.element)) ? h : {}; if (l.options = e(u)(!0, {}, p, f, null != r ? r : {}), l.options.previewTemplate = l.options.previewTemplate.replace(/\n*/g, ""), l.options.forceFallback || !o.isBrowserSupported()) return s(l, l.options.fallback.call(t(l))); if (null == l.options.url && (l.options.url = l.element.getAttribute("action")), !l.options.url) throw new Error("No URL provided."); if (l.options.acceptedFiles && l.options.acceptedMimeTypes) throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated."); if (l.options.uploadMultiple && l.options.chunking) throw new Error("You cannot set both: uploadMultiple and chunking."); return l.options.acceptedMimeTypes && (l.options.acceptedFiles = l.options.acceptedMimeTypes, delete l.options.acceptedMimeTypes), null != l.options.renameFilename && (l.options.renameFile = function (e) { return l.options.renameFilename.call(t(l), e.name, e) }), "string" == typeof l.options.method && (l.options.method = l.options.method.toUpperCase()), (d = l.getExistingFallback()) && d.parentNode && d.parentNode.removeChild(d), !1 !== l.options.previewsContainer && (l.options.previewsContainer ? l.previewsContainer = o.getElement(l.options.previewsContainer, "previewsContainer") : l.previewsContainer = l.element), l.options.clickable && (!0 === l.options.clickable ? l.clickableElements = [l.element] : l.clickableElements = o.getElements(l.options.clickable, "clickable")), l.init(), l } return l(o, n), r(o, [{ key: "getAcceptedFiles", value: function () { return this.files.filter((function (e) { return e.accepted })).map((function (e) { return e })) } }, { key: "getRejectedFiles", value: function () { return this.files.filter((function (e) { return !e.accepted })).map((function (e) { return e })) } }, { key: "getFilesWithStatus", value: function (e) { return this.files.filter((function (t) { return t.status === e })).map((function (e) { return e })) } }, { key: "getQueuedFiles", value: function () { return this.getFilesWithStatus(o.QUEUED) } }, { key: "getUploadingFiles", value: function () { return this.getFilesWithStatus(o.UPLOADING) } }, { key: "getAddedFiles", value: function () { return this.getFilesWithStatus(o.ADDED) } }, { key: "getActiveFiles", value: function () { return this.files.filter((function (e) { return e.status === o.UPLOADING || e.status === o.QUEUED })).map((function (e) { return e })) } }, { key: "init", value: function () { var e = this, t = this, i = this, n = this, r = this, a = this, l = this, s = this, u = this, c = this, d = this; if ("form" === this.element.tagName && this.element.setAttribute("enctype", "multipart/form-data"), this.element.classList.contains("dropzone") && !this.element.querySelector(".dz-message") && this.element.appendChild(o.createElement('
"))), this.clickableElements.length) { var h = this, p = function () { var e = h; h.hiddenFileInput && h.hiddenFileInput.parentNode.removeChild(h.hiddenFileInput), h.hiddenFileInput = document.createElement("input"), h.hiddenFileInput.setAttribute("type", "file"), (null === h.options.maxFiles || h.options.maxFiles > 1) && h.hiddenFileInput.setAttribute("multiple", "multiple"), h.hiddenFileInput.className = "dz-hidden-input", null !== h.options.acceptedFiles && h.hiddenFileInput.setAttribute("accept", h.options.acceptedFiles), null !== h.options.capture && h.hiddenFileInput.setAttribute("capture", h.options.capture), h.hiddenFileInput.setAttribute("tabindex", "-1"), h.hiddenFileInput.style.visibility = "hidden", h.hiddenFileInput.style.position = "absolute", h.hiddenFileInput.style.top = "0", h.hiddenFileInput.style.left = "0", h.hiddenFileInput.style.height = "0", h.hiddenFileInput.style.width = "0", o.getElement(h.options.hiddenInputContainer, "hiddenInputContainer").appendChild(h.hiddenFileInput), h.hiddenFileInput.addEventListener("change", (function () { var t = e.hiddenFileInput.files, i = !0, n = !1, r = void 0; if (t.length) try { for (var a, o = t[Symbol.iterator](); !(i = (a = o.next()).done); i = !0) { var l = a.value; e.addFile(l) } } catch (e) { n = !0, r = e } finally { try { i || null == o.return || o.return() } finally { if (n) throw r } } e.emit("addedfiles", t), p() })) }; p() } this.URL = null !== window.URL ? window.URL : window.webkitURL; var f = !0, m = !1, v = void 0; try { for (var y, g = this.events[Symbol.iterator](); !(f = (y = g.next()).done); f = !0) { var b = y.value; this.on(b, this.options[b]) } } catch (e) { m = !0, v = e } finally { try { f || null == g.return || g.return() } finally { if (m) throw v } } this.on("uploadprogress", (function () { return e.updateTotalUploadProgress() })), this.on("removedfile", (function () { return t.updateTotalUploadProgress() })), this.on("canceled", (function (e) { return i.emit("complete", e) })), this.on("complete", (function (e) { var t = n; if (0 === n.getAddedFiles().length && 0 === n.getUploadingFiles().length && 0 === n.getQueuedFiles().length) return setTimeout((function () { return t.emit("queuecomplete") }), 0) })); var k = function (e) { if (function (e) { if (e.dataTransfer.types) for (var t = 0; t < e.dataTransfer.types.length; t++)if ("Files" === e.dataTransfer.types[t]) return !0; return !1 }(e)) return e.stopPropagation(), e.preventDefault ? e.preventDefault() : e.returnValue = !1 }; return this.listeners = [{ element: this.element, events: { dragstart: function (e) { return r.emit("dragstart", e) }, dragenter: function (e) { return k(e), a.emit("dragenter", e) }, dragover: function (e) { var t; try { t = e.dataTransfer.effectAllowed } catch (e) { } return e.dataTransfer.dropEffect = "move" === t || "linkMove" === t ? "move" : "copy", k(e), l.emit("dragover", e) }, dragleave: function (e) { return s.emit("dragleave", e) }, drop: function (e) { return k(e), u.drop(e) }, dragend: function (e) { return c.emit("dragend", e) } } }], this.clickableElements.forEach((function (e) { var t = d; return d.listeners.push({ element: e, events: { click: function (i) { return (e !== t.element || i.target === t.element || o.elementInside(i.target, t.element.querySelector(".dz-message"))) && t.hiddenFileInput.click(), !0 } } }) })), this.enable(), this.options.init.call(this) } }, { key: "destroy", value: function () { return this.disable(), this.removeAllFiles(!0), (null != this.hiddenFileInput ? this.hiddenFileInput.parentNode : void 0) && (this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput), this.hiddenFileInput = null), delete this.element.dropzone, o.instances.splice(o.instances.indexOf(this), 1) } }, { key: "updateTotalUploadProgress", value: function () { var e, t = 0, i = 0; if (this.getActiveFiles().length) { var n = !0, r = !1, a = void 0; try { for (var o, l = this.getActiveFiles()[Symbol.iterator](); !(n = (o = l.next()).done); n = !0) { var s = o.value; t += s.upload.bytesSent, i += s.upload.total } } catch (e) { r = !0, a = e } finally { try { n || null == l.return || l.return() } finally { if (r) throw a } } e = 100 * t / i } else e = 100; return this.emit("totaluploadprogress", e, i, t) } }, { key: "_getParamName", value: function (e) { return "function" == typeof this.options.paramName ? this.options.paramName(e) : "".concat(this.options.paramName).concat(this.options.uploadMultiple ? "[".concat(e, "]") : "") } }, { key: "_renameFile", value: function (e) { return "function" != typeof this.options.renameFile ? e.name : this.options.renameFile(e) } }, { key: "getFallbackForm", value: function () { var e, t; if (e = this.getExistingFallback()) return e; var i = '
'; this.options.dictFallbackText && (i += "

".concat(this.options.dictFallbackText, "

")), i += '
'); var n = o.createElement(i); return "FORM" !== this.element.tagName ? (t = o.createElement('
'))).appendChild(n) : (this.element.setAttribute("enctype", "multipart/form-data"), this.element.setAttribute("method", this.options.method)), null != t ? t : n } }, { key: "getExistingFallback", value: function () { var e = function (e) { var t = !0, i = !1, n = void 0; try { for (var r, a = e[Symbol.iterator](); !(t = (r = a.next()).done); t = !0) { var o = r.value; if (/(^| )fallback($| )/.test(o.className)) return o } } catch (e) { i = !0, n = e } finally { try { t || null == a.return || a.return() } finally { if (i) throw n } } }, t = !0, i = !1, n = void 0; try { for (var r, a = ["div", "form"][Symbol.iterator](); !(t = (r = a.next()).done); t = !0) { var o, l = r.value; if (o = e(this.element.getElementsByTagName(l))) return o } } catch (e) { i = !0, n = e } finally { try { t || null == a.return || a.return() } finally { if (i) throw n } } } }, { key: "setupEventListeners", value: function () { return this.listeners.map((function (e) { return function () { var t = []; for (var i in e.events) { var n = e.events[i]; t.push(e.element.addEventListener(i, n, !1)) } return t }() })) } }, { key: "removeEventListeners", value: function () { return this.listeners.map((function (e) { return function () { var t = []; for (var i in e.events) { var n = e.events[i]; t.push(e.element.removeEventListener(i, n, !1)) } return t }() })) } }, { key: "disable", value: function () { var e = this; return this.clickableElements.forEach((function (e) { return e.classList.remove("dz-clickable") })), this.removeEventListeners(), this.disabled = !0, this.files.map((function (t) { return e.cancelUpload(t) })) } }, { key: "enable", value: function () { return delete this.disabled, this.clickableElements.forEach((function (e) { return e.classList.add("dz-clickable") })), this.setupEventListeners() } }, { key: "filesize", value: function (e) { var t = 0, i = "b"; if (e > 0) { for (var n = ["tb", "gb", "mb", "kb", "b"], r = 0; r < n.length; r++) { var a = n[r]; if (e >= Math.pow(this.options.filesizeBase, 4 - r) / 10) { t = e / Math.pow(this.options.filesizeBase, 4 - r), i = a; break } } t = Math.round(10 * t) / 10 } return "".concat(t, " ").concat(this.options.dictFileSizeUnits[i]) } }, { key: "_updateMaxFilesReachedClass", value: function () { return null != this.options.maxFiles && this.getAcceptedFiles().length >= this.options.maxFiles ? (this.getAcceptedFiles().length === this.options.maxFiles && this.emit("maxfilesreached", this.files), this.element.classList.add("dz-max-files-reached")) : this.element.classList.remove("dz-max-files-reached") } }, { key: "drop", value: function (e) { if (e.dataTransfer) { this.emit("drop", e); for (var t = [], i = 0; i < e.dataTransfer.files.length; i++)t[i] = e.dataTransfer.files[i]; if (t.length) { var n = e.dataTransfer.items; n && n.length && null != n[0].webkitGetAsEntry ? this._addFilesFromItems(n) : this.handleFiles(t) } this.emit("addedfiles", t) } } }, { key: "paste", value: function (e) { if (null != (t = null != e ? e.clipboardData : void 0, i = function (e) { return e.items }, null != t ? i(t) : void 0)) { var t, i; this.emit("paste", e); var n = e.clipboardData.items; return n.length ? this._addFilesFromItems(n) : void 0 } } }, { key: "handleFiles", value: function (e) { var t = !0, i = !1, n = void 0; try { for (var r, a = e[Symbol.iterator](); !(t = (r = a.next()).done); t = !0) { var o = r.value; this.addFile(o) } } catch (e) { i = !0, n = e } finally { try { t || null == a.return || a.return() } finally { if (i) throw n } } } }, { key: "_addFilesFromItems", value: function (e) { var t = this; return function () { var i = [], n = !0, r = !1, a = void 0; try { for (var o, l = e[Symbol.iterator](); !(n = (o = l.next()).done); n = !0) { var s, u = o.value; null != u.webkitGetAsEntry && (s = u.webkitGetAsEntry()) ? s.isFile ? i.push(t.addFile(u.getAsFile())) : s.isDirectory ? i.push(t._addFilesFromDirectory(s, s.name)) : i.push(void 0) : null != u.getAsFile && (null == u.kind || "file" === u.kind) ? i.push(t.addFile(u.getAsFile())) : i.push(void 0) } } catch (e) { r = !0, a = e } finally { try { n || null == l.return || l.return() } finally { if (r) throw a } } return i }() } }, { key: "_addFilesFromDirectory", value: function (e, t) { var i = this, n = e.createReader(), r = function (e) { return t = console, i = "log", n = function (t) { return t.log(e) }, null != t && "function" == typeof t[i] ? n(t, i) : void 0; var t, i, n }, a = function () { var e = i; return n.readEntries((function (i) { if (i.length > 0) { var n = !0, r = !1, o = void 0; try { for (var l, s = i[Symbol.iterator](); !(n = (l = s.next()).done); n = !0) { var u = l.value, c = e; u.isFile ? u.file((function (e) { if (!c.options.ignoreHiddenFiles || "." !== e.name.substring(0, 1)) return e.fullPath = "".concat(t, "/").concat(e.name), c.addFile(e) })) : u.isDirectory && e._addFilesFromDirectory(u, "".concat(t, "/").concat(u.name)) } } catch (e) { r = !0, o = e } finally { try { n || null == s.return || s.return() } finally { if (r) throw o } } a() } return null }), r) }; return a() } }, { key: "accept", value: function (e, t) { this.options.maxFilesize && e.size > 1048576 * this.options.maxFilesize ? t(this.options.dictFileTooBig.replace("{{filesize}}", Math.round(e.size / 1024 / 10.24) / 100).replace("{{maxFilesize}}", this.options.maxFilesize)) : o.isValidFile(e, this.options.acceptedFiles) ? null != this.options.maxFiles && this.getAcceptedFiles().length >= this.options.maxFiles ? (t(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}", this.options.maxFiles)), this.emit("maxfilesexceeded", e)) : this.options.accept.call(this, e, t) : t(this.options.dictInvalidFileType) } }, { key: "addFile", value: function (e) { var t = this; e.upload = { uuid: o.uuidv4(), progress: 0, total: e.size, bytesSent: 0, filename: this._renameFile(e) }, this.files.push(e), e.status = o.ADDED, this.emit("addedfile", e), this._enqueueThumbnail(e), this.accept(e, (function (i) { i ? (e.accepted = !1, t._errorProcessing([e], i)) : (e.accepted = !0, t.options.autoQueue && t.enqueueFile(e)), t._updateMaxFilesReachedClass() })) } }, { key: "enqueueFiles", value: function (e) { var t = !0, i = !1, n = void 0; try { for (var r, a = e[Symbol.iterator](); !(t = (r = a.next()).done); t = !0) { var o = r.value; this.enqueueFile(o) } } catch (e) { i = !0, n = e } finally { try { t || null == a.return || a.return() } finally { if (i) throw n } } return null } }, { key: "enqueueFile", value: function (e) { if (e.status !== o.ADDED || !0 !== e.accepted) throw new Error("This file can't be queued because it has already been processed or was rejected."); var t = this; if (e.status = o.QUEUED, this.options.autoProcessQueue) return setTimeout((function () { return t.processQueue() }), 0) } }, { key: "_enqueueThumbnail", value: function (e) { if (this.options.createImageThumbnails && e.type.match(/image.*/) && e.size <= 1048576 * this.options.maxThumbnailFilesize) { var t = this; return this._thumbnailQueue.push(e), setTimeout((function () { return t._processThumbnailQueue() }), 0) } } }, { key: "_processThumbnailQueue", value: function () { var e = this; if (!this._processingThumbnail && 0 !== this._thumbnailQueue.length) { this._processingThumbnail = !0; var t = this._thumbnailQueue.shift(); return this.createThumbnail(t, this.options.thumbnailWidth, this.options.thumbnailHeight, this.options.thumbnailMethod, !0, (function (i) { return e.emit("thumbnail", t, i), e._processingThumbnail = !1, e._processThumbnailQueue() })) } } }, { key: "removeFile", value: function (e) { if (e.status === o.UPLOADING && this.cancelUpload(e), this.files = m(this.files, e), this.emit("removedfile", e), 0 === this.files.length) return this.emit("reset") } }, { key: "removeAllFiles", value: function (e) { null == e && (e = !1); var t = !0, i = !1, n = void 0; try { for (var r, a = this.files.slice()[Symbol.iterator](); !(t = (r = a.next()).done); t = !0) { var l = r.value; (l.status !== o.UPLOADING || e) && this.removeFile(l) } } catch (e) { i = !0, n = e } finally { try { t || null == a.return || a.return() } finally { if (i) throw n } } return null } }, { key: "resizeImage", value: function (e, t, i, n, r) { var a = this; return this.createThumbnail(e, t, i, n, !0, (function (t, i) { if (null == i) return r(e); var n = a.options.resizeMimeType; null == n && (n = e.type); var l = i.toDataURL(n, a.options.resizeQuality); return "image/jpeg" !== n && "image/jpg" !== n || (l = g.restore(e.dataURL, l)), r(o.dataURItoBlob(l)) })) } }, { key: "createThumbnail", value: function (e, t, i, n, r, a) { var o = this, l = new FileReader; l.onload = function () { e.dataURL = l.result, "image/svg+xml" !== e.type ? o.createThumbnailFromUrl(e, t, i, n, r, a) : null != a && a(l.result) }, l.readAsDataURL(e) } }, { key: "displayExistingFile", value: function (e, t, i, n, r) { var a = void 0 === r || r; if (this.emit("addedfile", e), this.emit("complete", e), a) { var o = this; e.dataURL = t, this.createThumbnailFromUrl(e, this.options.thumbnailWidth, this.options.thumbnailHeight, this.options.thumbnailMethod, this.options.fixOrientation, (function (t) { o.emit("thumbnail", e, t), i && i() }), n) } else this.emit("thumbnail", e, t), i && i() } }, { key: "createThumbnailFromUrl", value: function (e, t, i, n, r, a, o) { var l = this, s = document.createElement("img"); return o && (s.crossOrigin = o), r = "from-image" != getComputedStyle(document.body).imageOrientation && r, s.onload = function () { var o = l, u = function (e) { return e(1) }; return "undefined" != typeof EXIF && null !== EXIF && r && (u = function (e) { return EXIF.getData(s, (function () { return e(EXIF.getTag(this, "Orientation")) })) }), u((function (r) { e.width = s.width, e.height = s.height; var l = o.options.resize.call(o, e, t, i, n), u = document.createElement("canvas"), c = u.getContext("2d"); switch (u.width = l.trgWidth, u.height = l.trgHeight, r > 4 && (u.width = l.trgHeight, u.height = l.trgWidth), r) { case 2: c.translate(u.width, 0), c.scale(-1, 1); break; case 3: c.translate(u.width, u.height), c.rotate(Math.PI); break; case 4: c.translate(0, u.height), c.scale(1, -1); break; case 5: c.rotate(.5 * Math.PI), c.scale(1, -1); break; case 6: c.rotate(.5 * Math.PI), c.translate(0, -u.width); break; case 7: c.rotate(.5 * Math.PI), c.translate(u.height, -u.width), c.scale(-1, 1); break; case 8: c.rotate(-.5 * Math.PI), c.translate(-u.height, 0) }y(c, s, null != l.srcX ? l.srcX : 0, null != l.srcY ? l.srcY : 0, l.srcWidth, l.srcHeight, null != l.trgX ? l.trgX : 0, null != l.trgY ? l.trgY : 0, l.trgWidth, l.trgHeight); var d = u.toDataURL("image/png"); if (null != a) return a(d, u) })) }, null != a && (s.onerror = a), s.src = e.dataURL } }, { key: "processQueue", value: function () { var e = this.options.parallelUploads, t = this.getUploadingFiles().length, i = t; if (!(t >= e)) { var n = this.getQueuedFiles(); if (n.length > 0) { if (this.options.uploadMultiple) return this.processFiles(n.slice(0, e - t)); for (; i < e;) { if (!n.length) return; this.processFile(n.shift()), i++ } } } } }, { key: "processFile", value: function (e) { return this.processFiles([e]) } }, { key: "processFiles", value: function (e) { var t = !0, i = !1, n = void 0; try { for (var r, a = e[Symbol.iterator](); !(t = (r = a.next()).done); t = !0) { var l = r.value; l.processing = !0, l.status = o.UPLOADING, this.emit("processing", l) } } catch (e) { i = !0, n = e } finally { try { t || null == a.return || a.return() } finally { if (i) throw n } } return this.options.uploadMultiple && this.emit("processingmultiple", e), this.uploadFiles(e) } }, { key: "_getFilesWithXhr", value: function (e) { return this.files.filter((function (t) { return t.xhr === e })).map((function (e) { return e })) } }, { key: "cancelUpload", value: function (e) { if (e.status === o.UPLOADING) { var t = this._getFilesWithXhr(e.xhr), i = !0, n = !1, r = void 0; try { for (var a, l = t[Symbol.iterator](); !(i = (a = l.next()).done); i = !0) { (p = a.value).status = o.CANCELED } } catch (e) { n = !0, r = e } finally { try { i || null == l.return || l.return() } finally { if (n) throw r } } void 0 !== e.xhr && e.xhr.abort(); var s = !0, u = !1, c = void 0; try { for (var d, h = t[Symbol.iterator](); !(s = (d = h.next()).done); s = !0) { var p = d.value; this.emit("canceled", p) } } catch (e) { u = !0, c = e } finally { try { s || null == h.return || h.return() } finally { if (u) throw c } } this.options.uploadMultiple && this.emit("canceledmultiple", t) } else e.status !== o.ADDED && e.status !== o.QUEUED || (e.status = o.CANCELED, this.emit("canceled", e), this.options.uploadMultiple && this.emit("canceledmultiple", [e])); if (this.options.autoProcessQueue) return this.processQueue() } }, { key: "resolveOption", value: function (e) { for (var t = arguments.length, i = new Array(t > 1 ? t - 1 : 0), n = 1; n < t; n++)i[n - 1] = arguments[n]; return "function" == typeof e ? e.apply(this, i) : e } }, { key: "uploadFile", value: function (e) { return this.uploadFiles([e]) } }, { key: "uploadFiles", value: function (e) { var t = this; this._transformFiles(e, (function (i) { if (t.options.chunking) { var n = i[0]; e[0].upload.chunked = t.options.chunking && (t.options.forceChunking || n.size > t.options.chunkSize), e[0].upload.totalChunkCount = Math.ceil(n.size / t.options.chunkSize) } if (e[0].upload.chunked) { var r = t, a = t, l = e[0]; n = i[0]; l.upload.chunks = []; var s = function () { for (var t = 0; void 0 !== l.upload.chunks[t];)t++; if (!(t >= l.upload.totalChunkCount)) { 0; var i = t * r.options.chunkSize, a = Math.min(i + r.options.chunkSize, n.size), s = { name: r._getParamName(0), data: n.webkitSlice ? n.webkitSlice(i, a) : n.slice(i, a), filename: l.upload.filename, chunkIndex: t }; l.upload.chunks[t] = { file: l, index: t, dataBlock: s, status: o.UPLOADING, progress: 0, retries: 0 }, r._uploadData(e, [s]) } }; if (l.upload.finishedChunkUpload = function (t, i) { var n = a, r = !0; t.status = o.SUCCESS, t.dataBlock = null, t.xhr = null; for (var u = 0; u < l.upload.totalChunkCount; u++) { if (void 0 === l.upload.chunks[u]) return s(); l.upload.chunks[u].status !== o.SUCCESS && (r = !1) } r && a.options.chunksUploaded(l, (function () { n._finished(e, i, null) })) }, t.options.parallelChunkUploads) for (var u = 0; u < l.upload.totalChunkCount; u++)s(); else s() } else { var c = []; for (u = 0; u < e.length; u++)c[u] = { name: t._getParamName(u), data: i[u], filename: e[u].upload.filename }; t._uploadData(e, c) } })) } }, { key: "_getChunk", value: function (e, t) { for (var i = 0; i < e.upload.totalChunkCount; i++)if (void 0 !== e.upload.chunks[i] && e.upload.chunks[i].xhr === t) return e.upload.chunks[i] } }, { key: "_uploadData", value: function (t, i) { var n = this, r = this, a = this, o = this, l = new XMLHttpRequest, s = !0, c = !1, d = void 0; try { for (var h, p = t[Symbol.iterator](); !(s = (h = p.next()).done); s = !0) { (_ = h.value).xhr = l } } catch (e) { c = !0, d = e } finally { try { s || null == p.return || p.return() } finally { if (c) throw d } } t[0].upload.chunked && (t[0].upload.chunks[i[0].chunkIndex].xhr = l); var f = this.resolveOption(this.options.method, t), m = this.resolveOption(this.options.url, t); l.open(f, m, !0), this.resolveOption(this.options.timeout, t) && (l.timeout = this.resolveOption(this.options.timeout, t)), l.withCredentials = !!this.options.withCredentials, l.onload = function (e) { n._finishedUploading(t, l, e) }, l.ontimeout = function () { r._handleUploadError(t, l, "Request timedout after ".concat(r.options.timeout / 1e3, " seconds")) }, l.onerror = function () { a._handleUploadError(t, l) }, (null != l.upload ? l.upload : l).onprogress = function (e) { return o._updateFilesUploadProgress(t, l, e) }; var v = { Accept: "application/json", "Cache-Control": "no-cache", "X-Requested-With": "XMLHttpRequest" }; for (var y in this.options.headers && e(u)(v, this.options.headers), v) { var g = v[y]; g && l.setRequestHeader(y, g) } var b = new FormData; if (this.options.params) { var k = this.options.params; for (var w in "function" == typeof k && (k = k.call(this, t, l, t[0].upload.chunked ? this._getChunk(t[0], l) : null)), k) { var F = k[w]; if (Array.isArray(F)) for (var E = 0; E < F.length; E++)b.append(w, F[E]); else b.append(w, F) } } var x = !0, z = !1, C = void 0; try { for (var S, A = t[Symbol.iterator](); !(x = (S = A.next()).done); x = !0) { var _ = S.value; this.emit("sending", _, l, b) } } catch (e) { z = !0, C = e } finally { try { x || null == A.return || A.return() } finally { if (z) throw C } } this.options.uploadMultiple && this.emit("sendingmultiple", t, l, b), this._addFormElementData(b); for (E = 0; E < i.length; E++) { var T = i[E]; b.append(T.name, T.data, T.filename) } this.submitRequest(l, b, t) } }, { key: "_transformFiles", value: function (e, t) { for (var i = this, n = function (n) { i.options.transformFile.call(i, e[n], (function (i) { r[n] = i, ++a === e.length && t(r) })) }, r = [], a = 0, o = 0; o < e.length; o++)n(o) } }, { key: "_addFormElementData", value: function (e) { var t = !0, i = !1, n = void 0; if ("FORM" === this.element.tagName) try { for (var r = this.element.querySelectorAll("input, textarea, select, button")[Symbol.iterator](); !(t = (s = r.next()).done); t = !0) { var a = s.value, o = a.getAttribute("name"), l = a.getAttribute("type"); if (l && (l = l.toLowerCase()), null != o) if ("SELECT" === a.tagName && a.hasAttribute("multiple")) { t = !0, i = !1, n = void 0; try { var s; for (r = a.options[Symbol.iterator](); !(t = (s = r.next()).done); t = !0) { var u = s.value; u.selected && e.append(o, u.value) } } catch (e) { i = !0, n = e } finally { try { t || null == r.return || r.return() } finally { if (i) throw n } } } else (!l || "checkbox" !== l && "radio" !== l || a.checked) && e.append(o, a.value) } } catch (e) { i = !0, n = e } finally { try { t || null == r.return || r.return() } finally { if (i) throw n } } } }, { key: "_updateFilesUploadProgress", value: function (e, t, i) { var n = !0, r = !1, a = void 0; if (e[0].upload.chunked) { c = e[0]; var o = this._getChunk(c, t); i ? (o.progress = 100 * i.loaded / i.total, o.total = i.total, o.bytesSent = i.loaded) : (o.progress = 100, o.bytesSent = o.total), c.upload.progress = 0, c.upload.total = 0, c.upload.bytesSent = 0; for (var l = 0; l < c.upload.totalChunkCount; l++)c.upload.chunks[l] && void 0 !== c.upload.chunks[l].progress && (c.upload.progress += c.upload.chunks[l].progress, c.upload.total += c.upload.chunks[l].total, c.upload.bytesSent += c.upload.chunks[l].bytesSent); c.upload.progress = c.upload.progress / c.upload.totalChunkCount, this.emit("uploadprogress", c, c.upload.progress, c.upload.bytesSent) } else try { for (var s, u = e[Symbol.iterator](); !(n = (s = u.next()).done); n = !0) { var c; (c = s.value).upload.total && c.upload.bytesSent && c.upload.bytesSent == c.upload.total || (i ? (c.upload.progress = 100 * i.loaded / i.total, c.upload.total = i.total, c.upload.bytesSent = i.loaded) : (c.upload.progress = 100, c.upload.bytesSent = c.upload.total), this.emit("uploadprogress", c, c.upload.progress, c.upload.bytesSent)) } } catch (e) { r = !0, a = e } finally { try { n || null == u.return || u.return() } finally { if (r) throw a } } } }, { key: "_finishedUploading", value: function (e, t, i) { var n; if (e[0].status !== o.CANCELED && 4 === t.readyState) { if ("arraybuffer" !== t.responseType && "blob" !== t.responseType && (n = t.responseText, t.getResponseHeader("content-type") && ~t.getResponseHeader("content-type").indexOf("application/json"))) try { n = JSON.parse(n) } catch (e) { i = e, n = "Invalid JSON response from server." } this._updateFilesUploadProgress(e, t), 200 <= t.status && t.status < 300 ? e[0].upload.chunked ? e[0].upload.finishedChunkUpload(this._getChunk(e[0], t), n) : this._finished(e, n, i) : this._handleUploadError(e, t, n) } } }, { key: "_handleUploadError", value: function (e, t, i) { if (e[0].status !== o.CANCELED) { if (e[0].upload.chunked && this.options.retryChunks) { var n = this._getChunk(e[0], t); if (n.retries++ < this.options.retryChunksLimit) return void this._uploadData(e, [n.dataBlock]); console.warn("Retried this chunk too often. Giving up.") } this._errorProcessing(e, i || this.options.dictResponseError.replace("{{statusCode}}", t.status), t) } } }, { key: "submitRequest", value: function (e, t, i) { 1 == e.readyState ? e.send(t) : console.warn("Cannot send this request because the XMLHttpRequest.readyState is not OPENED.") } }, { key: "_finished", value: function (e, t, i) { var n = !0, r = !1, a = void 0; try { for (var l, s = e[Symbol.iterator](); !(n = (l = s.next()).done); n = !0) { var u = l.value; u.status = o.SUCCESS, this.emit("success", u, t, i), this.emit("complete", u) } } catch (e) { r = !0, a = e } finally { try { n || null == s.return || s.return() } finally { if (r) throw a } } if (this.options.uploadMultiple && (this.emit("successmultiple", e, t, i), this.emit("completemultiple", e)), this.options.autoProcessQueue) return this.processQueue() } }, { key: "_errorProcessing", value: function (e, t, i) { var n = !0, r = !1, a = void 0; try { for (var l, s = e[Symbol.iterator](); !(n = (l = s.next()).done); n = !0) { var u = l.value; u.status = o.ERROR, this.emit("error", u, t, i), this.emit("complete", u) } } catch (e) { r = !0, a = e } finally { try { n || null == s.return || s.return() } finally { if (r) throw a } } if (this.options.uploadMultiple && (this.emit("errormultiple", e, t, i), this.emit("completemultiple", e)), this.options.autoProcessQueue) return this.processQueue() } }], [{ key: "initClass", value: function () { this.prototype.Emitter = h, this.prototype.events = ["drop", "dragstart", "dragend", "dragenter", "dragover", "dragleave", "addedfile", "addedfiles", "removedfile", "thumbnail", "error", "errormultiple", "processing", "processingmultiple", "uploadprogress", "totaluploadprogress", "sending", "sendingmultiple", "success", "successmultiple", "canceled", "canceledmultiple", "complete", "completemultiple", "reset", "maxfilesexceeded", "maxfilesreached", "queuecomplete"], this.prototype._thumbnailQueue = [], this.prototype._processingThumbnail = !1 } }, { key: "uuidv4", value: function () { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (function (e) { var t = 16 * Math.random() | 0; return ("x" === e ? t : 3 & t | 8).toString(16) })) } }]), o }(h); f.initClass(), f.options = {}, f.optionsForElement = function (e) { return e.getAttribute("id") ? f.options[v(e.getAttribute("id"))] : void 0 }, f.instances = [], f.forElement = function (e) { if ("string" == typeof e && (e = document.querySelector(e)), null == (null != e ? e.dropzone : void 0)) throw new Error("No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone."); return e.dropzone }, f.discover = function () { var e; if (document.querySelectorAll) e = document.querySelectorAll(".dropzone"); else { e = []; var t = function (t) { return function () { var i = [], n = !0, r = !1, a = void 0; try { for (var o, l = t[Symbol.iterator](); !(n = (o = l.next()).done); n = !0) { var s = o.value; /(^| )dropzone($| )/.test(s.className) ? i.push(e.push(s)) : i.push(void 0) } } catch (e) { r = !0, a = e } finally { try { n || null == l.return || l.return() } finally { if (r) throw a } } return i }() }; t(document.getElementsByTagName("div")), t(document.getElementsByTagName("form")) } return function () { var t = [], i = !0, n = !1, r = void 0; try { for (var a, o = e[Symbol.iterator](); !(i = (a = o.next()).done); i = !0) { var l = a.value; !1 !== f.optionsForElement(l) ? t.push(new f(l)) : t.push(void 0) } } catch (e) { n = !0, r = e } finally { try { i || null == o.return || o.return() } finally { if (n) throw r } } return t }() }, f.blockedBrowsers = [/opera.*(Macintosh|Windows Phone).*version\/12/i], f.isBrowserSupported = function () { var e = !0; if (window.File && window.FileReader && window.FileList && window.Blob && window.FormData && document.querySelector) if ("classList" in document.createElement("a")) { void 0 !== f.blacklistedBrowsers && (f.blockedBrowsers = f.blacklistedBrowsers); var t = !0, i = !1, n = void 0; try { for (var r, a = f.blockedBrowsers[Symbol.iterator](); !(t = (r = a.next()).done); t = !0) { r.value.test(navigator.userAgent) && (e = !1) } } catch (e) { i = !0, n = e } finally { try { t || null == a.return || a.return() } finally { if (i) throw n } } } else e = !1; else e = !1; return e }, f.dataURItoBlob = function (e) { for (var t = atob(e.split(",")[1]), i = e.split(",")[0].split(":")[1].split(";")[0], n = new ArrayBuffer(t.length), r = new Uint8Array(n), a = 0, o = t.length, l = 0 <= o; l ? a <= o : a >= o; l ? a++ : a--)r[a] = t.charCodeAt(a); return new Blob([n], { type: i }) }; var m = function (e, t) { return e.filter((function (e) { return e !== t })).map((function (e) { return e })) }, v = function (e) { return e.replace(/[\-_](\w)/g, (function (e) { return e.charAt(1).toUpperCase() })) }; f.createElement = function (e) { var t = document.createElement("div"); return t.innerHTML = e, t.childNodes[0] }, f.elementInside = function (e, t) { if (e === t) return !0; for (; e = e.parentNode;)if (e === t) return !0; return !1 }, f.getElement = function (e, t) { var i; if ("string" == typeof e ? i = document.querySelector(e) : null != e.nodeType && (i = e), null == i) throw new Error("Invalid `".concat(t, "` option provided. Please provide a CSS selector or a plain HTML element.")); return i }, f.getElements = function (e, t) { var i, n; if (e instanceof Array) { n = []; try { var r = !0, a = !1, o = void 0; try { for (var l = e[Symbol.iterator](); !(r = (s = l.next()).done); r = !0)i = s.value, n.push(this.getElement(i, t)) } catch (e) { a = !0, o = e } finally { try { r || null == l.return || l.return() } finally { if (a) throw o } } } catch (e) { n = null } } else if ("string" == typeof e) { n = []; r = !0, a = !1, o = void 0; try { var s; for (l = document.querySelectorAll(e)[Symbol.iterator](); !(r = (s = l.next()).done); r = !0)i = s.value, n.push(i) } catch (e) { a = !0, o = e } finally { try { r || null == l.return || l.return() } finally { if (a) throw o } } } else null != e.nodeType && (n = [e]); if (null == n || !n.length) throw new Error("Invalid `".concat(t, "` option provided. Please provide a CSS selector, a plain HTML element or a list of those.")); return n }, f.confirm = function (e, t, i) { return window.confirm(e) ? t() : null != i ? i() : void 0 }, f.isValidFile = function (e, t) { if (!t) return !0; t = t.split(","); var i = e.type, n = i.replace(/\/.*$/, ""), r = !0, a = !1, o = void 0; try { for (var l, s = t[Symbol.iterator](); !(r = (l = s.next()).done); r = !0) { var u = l.value; if ("." === (u = u.trim()).charAt(0)) { if (-1 !== e.name.toLowerCase().indexOf(u.toLowerCase(), e.name.length - u.length)) return !0 } else if (/\/\*$/.test(u)) { if (n === u.replace(/\/.*$/, "")) return !0 } else if (i === u) return !0 } } catch (e) { a = !0, o = e } finally { try { r || null == s.return || s.return() } finally { if (a) throw o } } return !1 }, "undefined" != typeof jQuery && null !== jQuery && (jQuery.fn.dropzone = function (e) { return this.each((function () { return new f(this, e) })) }), f.ADDED = "added", f.QUEUED = "queued", f.ACCEPTED = f.QUEUED, f.UPLOADING = "uploading", f.PROCESSING = f.UPLOADING, f.CANCELED = "canceled", f.ERROR = "error", f.SUCCESS = "success"; var y = function (e, t, i, n, r, a, o, l, s, u) { var c = function (e) { e.naturalWidth; var t = e.naturalHeight, i = document.createElement("canvas"); i.width = 1, i.height = t; var n = i.getContext("2d"); n.drawImage(e, 0, 0); for (var r = n.getImageData(1, 0, 1, t).data, a = 0, o = t, l = t; l > a;)0 === r[4 * (l - 1) + 3] ? o = l : a = l, l = o + a >> 1; var s = l / t; return 0 === s ? 1 : s }(t); return e.drawImage(t, i, n, r, a, o, l, s, u / c) }, g = function () { "use strict"; function e() { i(this, e) } return r(e, null, [{ key: "initClass", value: function () { this.KEY_STR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" } }, { key: "encode64", value: function (e) { for (var t = "", i = void 0, n = void 0, r = "", a = void 0, o = void 0, l = void 0, s = "", u = 0; a = (i = e[u++]) >> 2, o = (3 & i) << 4 | (n = e[u++]) >> 4, l = (15 & n) << 2 | (r = e[u++]) >> 6, s = 63 & r, isNaN(n) ? l = s = 64 : isNaN(r) && (s = 64), t = t + this.KEY_STR.charAt(a) + this.KEY_STR.charAt(o) + this.KEY_STR.charAt(l) + this.KEY_STR.charAt(s), i = n = r = "", a = o = l = s = "", u < e.length;); return t } }, { key: "restore", value: function (e, t) { if (!e.match("data:image/jpeg;base64,")) return t; var i = this.decode64(e.replace("data:image/jpeg;base64,", "")), n = this.slice2Segments(i), r = this.exifManipulation(t, n); return "data:image/jpeg;base64,".concat(this.encode64(r)) } }, { key: "exifManipulation", value: function (e, t) { var i = this.getExifArray(t), n = this.insertExif(e, i); return new Uint8Array(n) } }, { key: "getExifArray", value: function (e) { for (var t = void 0, i = 0; i < e.length;) { if (255 === (t = e[i])[0] & 225 === t[1]) return t; i++ } return [] } }, { key: "insertExif", value: function (e, t) { var i = e.replace("data:image/jpeg;base64,", ""), n = this.decode64(i), r = n.indexOf(255, 3), a = n.slice(0, r), o = n.slice(r), l = a; return l = (l = l.concat(t)).concat(o) } }, { key: "slice2Segments", value: function (e) { for (var t = 0, i = []; ;) { if (255 === e[t] & 218 === e[t + 1]) break; if (255 === e[t] & 216 === e[t + 1]) t += 2; else { var n = t + (256 * e[t + 2] + e[t + 3]) + 2, r = e.slice(t, n); i.push(r), t = n } if (t > e.length) break } return i } }, { key: "decode64", value: function (e) { var t = void 0, i = void 0, n = "", r = void 0, a = void 0, o = "", l = 0, s = []; for (/[^A-Za-z0-9\+\/\=]/g.exec(e) && console.warn("There were invalid base64 characters in the input text.\nValid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\nExpect errors in decoding."), e = e.replace(/[^A-Za-z0-9\+\/\=]/g, ""); t = this.KEY_STR.indexOf(e.charAt(l++)) << 2 | (r = this.KEY_STR.indexOf(e.charAt(l++))) >> 4, i = (15 & r) << 4 | (a = this.KEY_STR.indexOf(e.charAt(l++))) >> 2, n = (3 & a) << 6 | (o = this.KEY_STR.indexOf(e.charAt(l++))), s.push(t), 64 !== a && s.push(i), 64 !== o && s.push(n), t = i = n = "", r = a = o = "", l < e.length;); return s } }]), e }(); g.initClass(); window.Dropzone = f }(); -------------------------------------------------------------------------------- /src/filemanager/resources/glightbox.min.css: -------------------------------------------------------------------------------- 1 | .glightbox-container{width:100%;height:100%;position:fixed;top:0;left:0;z-index:999999!important;overflow:hidden;-ms-touch-action:none;touch-action:none;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;-ms-text-size-adjust:100%;text-size-adjust:100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;outline:0;overflow:hidden}.glightbox-container.inactive{display:none}.glightbox-container .gcontainer{position:relative;width:100%;height:100%;z-index:9999;overflow:hidden}.glightbox-container .gslider{-webkit-transition:-webkit-transform .4s ease;transition:-webkit-transform .4s ease;transition:transform .4s ease;transition:transform .4s ease,-webkit-transform .4s ease;height:100%;left:0;top:0;width:100%;position:relative;overflow:hidden;display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.glightbox-container .gslide{width:100%;position:absolute;opacity:1;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;opacity:0}.glightbox-container .gslide.current{opacity:1;z-index:99999;position:relative}.glightbox-container .gslide.prev{opacity:1;z-index:9999}.glightbox-container .gslide-inner-content{width:100%}.glightbox-container .ginner-container{position:relative;width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;max-width:100%;margin:auto;height:100vh}.glightbox-container .ginner-container.gvideo-container{width:100%}.glightbox-container .ginner-container.desc-bottom,.glightbox-container .ginner-container.desc-top{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.glightbox-container .ginner-container.desc-left,.glightbox-container .ginner-container.desc-right{max-width:100%!important}.gslide iframe,.gslide video{outline:0!important;border:none;min-height:165px;-webkit-overflow-scrolling:touch;-ms-touch-action:auto;touch-action:auto}.gslide:not(.current){pointer-events:none}.gslide-image{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.gslide-image img{max-height:100vh;display:block;padding:0;float:none;outline:0;border:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;max-width:100vw;width:auto;height:auto;-o-object-fit:cover;object-fit:cover;-ms-touch-action:none;touch-action:none;margin:auto;min-width:200px}.desc-bottom .gslide-image img,.desc-top .gslide-image img{width:auto}.desc-left .gslide-image img,.desc-right .gslide-image img{width:auto;max-width:100%}.gslide-image img.zoomable{position:relative}.gslide-image img.dragging{cursor:-webkit-grabbing!important;cursor:grabbing!important;-webkit-transition:none;transition:none}.gslide-video{position:relative;max-width:100vh;width:100%!important}.gslide-video .gvideo-wrapper{width:100%;margin:auto}.gslide-video::before{content:'';display:block;position:absolute;width:100%;height:100%;background:rgba(255,0,0,.34);display:none}.gslide-video.playing::before{display:none}.gslide-video.fullscreen{max-width:100%!important;min-width:100%;height:75vh}.gslide-video.fullscreen video{max-width:100%!important;width:100%!important}.gslide-inline{background:#fff;text-align:left;max-height:calc(100vh - 40px);overflow:auto;max-width:100%}.gslide-inline .ginlined-content{padding:20px;width:100%}.gslide-inline .dragging{cursor:-webkit-grabbing!important;cursor:grabbing!important;-webkit-transition:none;transition:none}.ginlined-content{overflow:auto;display:block!important;opacity:1}.gslide-external{display:-webkit-box;display:-ms-flexbox;display:flex;width:100%;min-width:100%;background:#fff;padding:0;overflow:auto;max-height:75vh;height:100%}.gslide-media{display:-webkit-box;display:-ms-flexbox;display:flex;width:auto}.zoomed .gslide-media{-webkit-box-shadow:none!important;box-shadow:none!important}.desc-bottom .gslide-media,.desc-top .gslide-media{margin:0 auto;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.gslide-description{position:relative;-webkit-box-flex:1;-ms-flex:1 0 100%;flex:1 0 100%}.gslide-description.description-left,.gslide-description.description-right{max-width:100%}.gslide-description.description-bottom,.gslide-description.description-top{margin:0 auto;width:100%}.gslide-description p{margin-bottom:12px}.gslide-description p:last-child{margin-bottom:0}.zoomed .gslide-description{display:none}.glightbox-button-hidden{display:none}.glightbox-mobile .glightbox-container .gslide-description{height:auto!important;width:100%;background:0 0;position:absolute;bottom:0;padding:19px 11px;max-width:100vw!important;-webkit-box-ordinal-group:3!important;-ms-flex-order:2!important;order:2!important;max-height:78vh;overflow:auto!important;background:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,0)),to(rgba(0,0,0,.75)));background:linear-gradient(to bottom,rgba(0,0,0,0) 0,rgba(0,0,0,.75) 100%);-webkit-transition:opacity .3s linear;transition:opacity .3s linear;padding-bottom:50px}.glightbox-mobile .glightbox-container .gslide-title{color:#fff;font-size:1em}.glightbox-mobile .glightbox-container .gslide-desc{color:#a1a1a1}.glightbox-mobile .glightbox-container .gslide-desc a{color:#fff;font-weight:700}.glightbox-mobile .glightbox-container .gslide-desc *{color:inherit}.glightbox-mobile .glightbox-container .gslide-desc string{color:#fff}.glightbox-mobile .glightbox-container .gslide-desc .desc-more{color:#fff;opacity:.4}.gdesc-open .gslide-media{-webkit-transition:opacity .5s ease;transition:opacity .5s ease;opacity:.4}.gdesc-open .gdesc-inner{padding-bottom:30px}.gdesc-closed .gslide-media{-webkit-transition:opacity .5s ease;transition:opacity .5s ease;opacity:1}.greset{-webkit-transition:all .3s ease;transition:all .3s ease}.gabsolute{position:absolute}.grelative{position:relative}.glightbox-desc{display:none!important}.glightbox-open{overflow:hidden}.gloader{height:25px;width:25px;-webkit-animation:lightboxLoader .8s infinite linear;animation:lightboxLoader .8s infinite linear;border:2px solid #fff;border-right-color:transparent;border-radius:50%;position:absolute;display:block;z-index:9999;left:0;right:0;margin:0 auto;top:47%}.goverlay{width:100%;height:calc(100vh + 1px);position:fixed;top:-1px;left:0;background:#000;will-change:opacity}.glightbox-mobile .goverlay{background:#000}.gclose,.gnext,.gprev{z-index:99999;cursor:pointer;width:26px;height:44px;border:none;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.gclose svg,.gnext svg,.gprev svg{display:block;width:25px;height:auto;margin:0;padding:0}.gclose.disabled,.gnext.disabled,.gprev.disabled{opacity:.1}.gclose .garrow,.gnext .garrow,.gprev .garrow{stroke:#fff}.gbtn.focused{outline:2px solid #0f3d81}iframe.wait-autoplay{opacity:0}.glightbox-closing .gclose,.glightbox-closing .gnext,.glightbox-closing .gprev{opacity:0!important}.glightbox-clean .gslide-description{background:#fff}.glightbox-clean .gdesc-inner{padding:22px 20px}.glightbox-clean .gslide-title{font-size:1em;font-weight:400;font-family:arial;color:#000;margin-bottom:19px;line-height:1.4em}.glightbox-clean .gslide-desc{font-size:.86em;margin-bottom:0;font-family:arial;line-height:1.4em}.glightbox-clean .gslide-video{background:#000}.glightbox-clean .gclose,.glightbox-clean .gnext,.glightbox-clean .gprev{background-color:rgba(0,0,0,.75);border-radius:4px}.glightbox-clean .gclose path,.glightbox-clean .gnext path,.glightbox-clean .gprev path{fill:#fff}.glightbox-clean .gprev{position:absolute;top:-100%;left:30px;width:40px;height:50px}.glightbox-clean .gnext{position:absolute;top:-100%;right:30px;width:40px;height:50px}.glightbox-clean .gclose{width:35px;height:35px;top:15px;right:10px;position:absolute}.glightbox-clean .gclose svg{width:18px;height:auto}.glightbox-clean .gclose:hover{opacity:1}.gfadeIn{-webkit-animation:gfadeIn .5s ease;animation:gfadeIn .5s ease}.gfadeOut{-webkit-animation:gfadeOut .5s ease;animation:gfadeOut .5s ease}.gslideOutLeft{-webkit-animation:gslideOutLeft .3s ease;animation:gslideOutLeft .3s ease}.gslideInLeft{-webkit-animation:gslideInLeft .3s ease;animation:gslideInLeft .3s ease}.gslideOutRight{-webkit-animation:gslideOutRight .3s ease;animation:gslideOutRight .3s ease}.gslideInRight{-webkit-animation:gslideInRight .3s ease;animation:gslideInRight .3s ease}.gzoomIn{-webkit-animation:gzoomIn .5s ease;animation:gzoomIn .5s ease}.gzoomOut{-webkit-animation:gzoomOut .5s ease;animation:gzoomOut .5s ease}@-webkit-keyframes lightboxLoader{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes lightboxLoader{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes gfadeIn{from{opacity:0}to{opacity:1}}@keyframes gfadeIn{from{opacity:0}to{opacity:1}}@-webkit-keyframes gfadeOut{from{opacity:1}to{opacity:0}}@keyframes gfadeOut{from{opacity:1}to{opacity:0}}@-webkit-keyframes gslideInLeft{from{opacity:0;-webkit-transform:translate3d(-60%,0,0);transform:translate3d(-60%,0,0)}to{visibility:visible;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes gslideInLeft{from{opacity:0;-webkit-transform:translate3d(-60%,0,0);transform:translate3d(-60%,0,0)}to{visibility:visible;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes gslideOutLeft{from{opacity:1;visibility:visible;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{-webkit-transform:translate3d(-60%,0,0);transform:translate3d(-60%,0,0);opacity:0;visibility:hidden}}@keyframes gslideOutLeft{from{opacity:1;visibility:visible;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{-webkit-transform:translate3d(-60%,0,0);transform:translate3d(-60%,0,0);opacity:0;visibility:hidden}}@-webkit-keyframes gslideInRight{from{opacity:0;visibility:visible;-webkit-transform:translate3d(60%,0,0);transform:translate3d(60%,0,0)}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes gslideInRight{from{opacity:0;visibility:visible;-webkit-transform:translate3d(60%,0,0);transform:translate3d(60%,0,0)}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes gslideOutRight{from{opacity:1;visibility:visible;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{-webkit-transform:translate3d(60%,0,0);transform:translate3d(60%,0,0);opacity:0}}@keyframes gslideOutRight{from{opacity:1;visibility:visible;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{-webkit-transform:translate3d(60%,0,0);transform:translate3d(60%,0,0);opacity:0}}@-webkit-keyframes gzoomIn{from{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}to{opacity:1}}@keyframes gzoomIn{from{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}to{opacity:1}}@-webkit-keyframes gzoomOut{from{opacity:1}50%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}to{opacity:0}}@keyframes gzoomOut{from{opacity:1}50%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}to{opacity:0}}@media (min-width:769px){.glightbox-container .ginner-container{width:auto;height:auto;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.glightbox-container .ginner-container.desc-top .gslide-description{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.glightbox-container .ginner-container.desc-top .gslide-image,.glightbox-container .ginner-container.desc-top .gslide-image img{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.glightbox-container .ginner-container.desc-left .gslide-description{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.glightbox-container .ginner-container.desc-left .gslide-image{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.gslide-image img{max-height:97vh;max-width:100%}.gslide-image img.zoomable{cursor:-webkit-zoom-in;cursor:zoom-in}.zoomed .gslide-image img.zoomable{cursor:-webkit-grab;cursor:grab}.gslide-inline{max-height:95vh}.gslide-external{max-height:100vh}.gslide-description.description-left,.gslide-description.description-right{max-width:275px}.glightbox-open{height:auto}.goverlay{background:rgba(0,0,0,.92)}.glightbox-clean .gslide-media{-webkit-box-shadow:1px 2px 9px 0 rgba(0,0,0,.65);box-shadow:1px 2px 9px 0 rgba(0,0,0,.65)}.glightbox-clean .description-left .gdesc-inner,.glightbox-clean .description-right .gdesc-inner{position:absolute;height:100%;overflow-y:auto}.glightbox-clean .gclose,.glightbox-clean .gnext,.glightbox-clean .gprev{background-color:rgba(0,0,0,.32)}.glightbox-clean .gclose:hover,.glightbox-clean .gnext:hover,.glightbox-clean .gprev:hover{background-color:rgba(0,0,0,.7)}.glightbox-clean .gprev{top:45%}.glightbox-clean .gnext{top:45%}}@media (min-width:992px){.glightbox-clean .gclose{opacity:.7;right:20px}}@media screen and (max-height:420px){.goverlay{background:#000}} -------------------------------------------------------------------------------- /src/filemanager/resources/picker.css: -------------------------------------------------------------------------------- 1 | .file-picker { 2 | min-width: 32px; 3 | padding: 8px; 4 | border: 1px dotted black; 5 | border-radius: 4px; 6 | position: relative; 7 | min-height: 16px; 8 | } 9 | 10 | .file-picker .preview { 11 | width: 100%; 12 | height: 100%; 13 | z-index: 1; 14 | top: 0; 15 | left: 0; 16 | position: absolute; 17 | } 18 | 19 | .file-picker .close { 20 | position: absolute; 21 | right: 2px; 22 | top: 2px; 23 | z-index: 2; 24 | background: white; 25 | padding: 0; 26 | margin: 0; 27 | width: 16px; 28 | height: 16px; 29 | display: flex; 30 | justify-content: center; 31 | line-height: 0.9; 32 | border-radius: 100%; 33 | cursor: pointer; 34 | } -------------------------------------------------------------------------------- /src/filemanager/resources/picker.js: -------------------------------------------------------------------------------- 1 | (() => { 2 | let index = 0; 3 | const FilePickers = document.querySelectorAll(".file-picker"); 4 | 5 | window.fmanager = function (element, callback) { 6 | if (!element) return; 7 | window.open('/filemanager/picker', 'File Picker', 8 | 'height=400,width=1200,toolbar=no,directories=no,status=no, linemenubar=no,scrollbars=no,resizable=no ,modal=yes'); 9 | 10 | if (!window.SetUrl) { 11 | window.SetUrl = function (url) { 12 | callback(url, element); 13 | } 14 | } 15 | } 16 | 17 | const SelectorTemplate = ` 18 | 19 | Select File 20 | 21 | `; 22 | 23 | const PreviewTemplate = ` 24 | 25 | 26 | 27 | x 28 | `; 29 | 30 | const SetPreview = (file) => { 31 | if (FilePickers[index].classList.contains('has-preview')) { 32 | const close = FilePickers[index].querySelector('.close') 33 | if (close) close.remove() 34 | const preview = FilePickers[index].querySelector('.preview') 35 | if (preview) preview.remove() 36 | const PreviewElement = PreviewTemplate.replace("IMAGE_URL", file) 37 | FilePickers[index].insertAdjacentHTML("beforeend", PreviewElement); 38 | } 39 | } 40 | 41 | const PickFile = () => { 42 | fmanager(FilePickers[index], function (file, target) { 43 | FilePickers[index].querySelector('input').value = file; 44 | SetPreview(file); 45 | }); 46 | } 47 | 48 | FilePickers.forEach(function (fp, i) { 49 | fp.insertAdjacentHTML("beforeend", SelectorTemplate) 50 | fp.addEventListener('click', function (e) { 51 | index = i; 52 | if (e.target.classList.contains('close')) { 53 | FilePickers[index].querySelector('.close').remove() 54 | FilePickers[index].querySelector('.preview').remove() 55 | FilePickers[index].querySelector('input').value = ''; 56 | } else { 57 | PickFile(FilePickers[index]) 58 | } 59 | }) 60 | }) 61 | })(); -------------------------------------------------------------------------------- /src/filemanager/routes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-filemanager/e73a4c0e0260228d5829a9ae695a961dced76c12/src/filemanager/routes/__init__.py -------------------------------------------------------------------------------- /src/filemanager/routes/route.py: -------------------------------------------------------------------------------- 1 | from masonite.routes import Route 2 | from masonite.configuration import config 3 | from ..controllers.filemanager_controller import FileManagerController 4 | 5 | middleware = config("filemanager.middleware") 6 | 7 | ROUTES = Route.group( 8 | [ 9 | Route.get("", FileManagerController.index).name("ui"), 10 | Route.post("", FileManagerController.upload).name("store"), 11 | Route.get("/all-files", FileManagerController.all_files).name("list"), 12 | Route.post("/rename", FileManagerController.rename).name("rename"), 13 | Route.post("/create-folder", FileManagerController.create_folder).name("create_folder"), 14 | Route.post("/delete-folder", FileManagerController.delete_folder).name("delete_folder"), 15 | Route.post("/move-file", FileManagerController.move_file).name("move_file"), 16 | Route.post("/file-info", FileManagerController.file_info).name("file_info"), 17 | Route.post("/get-preview", FileManagerController.get_preview).name("get_preview"), 18 | Route.post("/delete-file", FileManagerController.delete_file).name("delete_file"), 19 | Route.get("/picker", FileManagerController.picker).name("picker"), 20 | ], 21 | prefix="/filemanager", 22 | middleware=middleware, 23 | name="filemanager.", 24 | ) 25 | -------------------------------------------------------------------------------- /src/filemanager/templates/details.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/filemanager/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | FileManager 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 28 | 29 | 30 | 31 |
32 | FileManager 33 |
34 | 35 | 38 |
39 |
40 |
41 | 42 | @include 'sidebar.html' 43 |
47 |
48 |
49 |
    50 |
  • All Files
  • 51 | {% if request().input('folder') %} 52 | {% for folder in request().input('folder').split('/') %} 53 |
  • {{folder}}
  • 54 | {% endfor %} 55 | {% endif %} 56 |
57 |
58 | 62 | 66 |
67 |
68 |
69 |
70 | @include 'partials/grid.html' 71 | @include 'partials/list.html' 72 |
73 | 106 |
107 |
108 | @include 'details.html' 109 |
110 | 111 | @include 'partials/create_form.html' 112 | 113 | 114 | @include 'partials/rename_form.html' 115 | 116 |
117 | 629 | 630 | 631 | -------------------------------------------------------------------------------- /src/filemanager/templates/partials/create_form.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/filemanager/templates/partials/dialog.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/filemanager/templates/partials/grid.html: -------------------------------------------------------------------------------- 1 |
4 |
5 |
6 | Folders 7 |
8 |
9 | 52 | 55 |
56 |
57 |
58 |
59 | Files 60 |
61 |
62 | 118 | 121 |
122 |
123 |
-------------------------------------------------------------------------------- /src/filemanager/templates/partials/list.html: -------------------------------------------------------------------------------- 1 |
4 |
5 |
Name
6 | 7 | 9 |
10 |
11 |
12 | 65 |
66 |
67 |
68 |
69 | 70 | 137 |
138 |
139 |
-------------------------------------------------------------------------------- /src/filemanager/templates/partials/previews/audio.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
-------------------------------------------------------------------------------- /src/filemanager/templates/partials/previews/file.html: -------------------------------------------------------------------------------- 1 |
2 | {% if type == 'txt' %} 3 | 4 | {% else %} 5 | 6 | {% endif %} 7 |
-------------------------------------------------------------------------------- /src/filemanager/templates/partials/previews/image.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /src/filemanager/templates/partials/previews/pdf.html: -------------------------------------------------------------------------------- 1 | {% if config('filemanager.generate_previews') %} 2 |
4 | {% else %} 5 |
6 | 7 |
8 | {% endif %} -------------------------------------------------------------------------------- /src/filemanager/templates/partials/previews/video.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/filemanager/templates/partials/rename_form.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/filemanager/templates/picker.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | FileManager 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 27 | 28 | 29 | 30 |
31 | FileManager 32 |
33 |
34 | 35 | 36 | @include 'sidebar.html' 37 | 38 |
39 |
40 |
42 | 43 | 46 |
47 |
48 |
All Files
49 |
50 |
51 | Folders 52 |
53 |
54 | 55 |
56 |
57 |
58 |
59 | Files 60 |
61 |
62 | 63 |
64 |
65 |
66 |
67 | 68 | 76 | 77 |
78 | 79 | 80 | @include 'partials/create_form.html' 81 | 82 | 83 | @include 'partials/rename_form.html' 84 | 85 |
86 | 87 | 308 | 309 | 310 | -------------------------------------------------------------------------------- /src/filemanager/templates/sidebar.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-filemanager/e73a4c0e0260228d5829a9ae695a961dced76c12/tests/__init__.py -------------------------------------------------------------------------------- /tests/integrations/Kernel.py: -------------------------------------------------------------------------------- 1 | from masonite.foundation import response_handler 2 | from masonite.storage import StorageCapsule 3 | from masonite.auth import Sign 4 | from masonite.environment import LoadEnvironment 5 | from masonite.utils.structures import load 6 | from masonite.utils.location import base_path 7 | from masonite.middleware import ( 8 | SessionMiddleware, 9 | EncryptCookies, 10 | LoadUserMiddleware, 11 | MaintenanceModeMiddleware, 12 | ) 13 | from masonite.routes import Route 14 | from masonite.configuration.Configuration import Configuration 15 | from masonite.configuration import config 16 | 17 | from .app.middlewares.VerifyCsrfToken import VerifyCsrfToken 18 | 19 | 20 | class Kernel: 21 | 22 | http_middleware = [MaintenanceModeMiddleware, EncryptCookies] 23 | 24 | route_middleware = { 25 | "web": [SessionMiddleware, LoadUserMiddleware, VerifyCsrfToken], 26 | } 27 | 28 | def __init__(self, app): 29 | self.application = app 30 | 31 | def register(self): 32 | # Register routes 33 | self.load_environment() 34 | self.register_configurations() 35 | self.register_middleware() 36 | self.register_routes() 37 | self.register_database() 38 | self.register_templates() 39 | self.register_storage() 40 | 41 | def load_environment(self): 42 | LoadEnvironment() 43 | 44 | def register_configurations(self): 45 | # load configuration 46 | self.application.bind("config.location", "tests/integrations/config") 47 | configuration = Configuration(self.application) 48 | configuration.load() 49 | self.application.bind("config", configuration) 50 | key = config("application.key") 51 | self.application.bind("key", key) 52 | self.application.bind("sign", Sign(key)) 53 | # set locations 54 | self.application.bind("resources.location", "tests/integrations/resources/") 55 | self.application.bind("controllers.location", "tests/integrations/app/controllers") 56 | self.application.bind("jobs.location", "tests/integrations/jobs") 57 | self.application.bind("providers.location", "tests/integrations/providers") 58 | self.application.bind("mailables.location", "tests/integrations/mailables") 59 | self.application.bind("listeners.location", "tests/integrations/listeners") 60 | self.application.bind("validation.location", "tests/integrations/validation") 61 | self.application.bind("notifications.location", "tests/integrations/notifications") 62 | self.application.bind("events.location", "tests/integrations/events") 63 | self.application.bind("tasks.location", "tests/integrations/tasks") 64 | self.application.bind("models.location", "tests/integrations/app/models") 65 | self.application.bind("observers.location", "tests/integrations/models/observers") 66 | self.application.bind("policies.location", "tests/integrations/policies") 67 | self.application.bind("commands.location", "tests/integrations/commands") 68 | self.application.bind("middlewares.location", "tests/integrations/app/middlewares") 69 | 70 | self.application.bind("server.runner", "masonite.commands.ServeCommand.main") 71 | 72 | def register_middleware(self): 73 | self.application.make("middleware").add(self.route_middleware).add(self.http_middleware) 74 | 75 | def register_routes(self): 76 | Route.set_controller_locations(self.application.make("controllers.location")) 77 | self.application.bind("routes.location", "tests/integrations/routes/web") 78 | self.application.make("router").add( 79 | Route.group( 80 | load(self.application.make("routes.location"), "ROUTES"), middleware=["web"] 81 | ) 82 | ) 83 | 84 | def register_database(self): 85 | from masoniteorm.query import QueryBuilder 86 | 87 | self.application.bind( 88 | "builder", 89 | QueryBuilder(connection_details=config("database.databases")), 90 | ) 91 | 92 | self.application.bind("migrations.location", "tests/integrations/databases/migrations") 93 | self.application.bind("seeds.location", "tests/integrations/databases/seeds") 94 | 95 | self.application.bind("resolver", config("database.db")) 96 | 97 | def register_templates(self): 98 | self.application.bind("views.location", "tests/integrations/templates/") 99 | 100 | def register_storage(self): 101 | storage = StorageCapsule() 102 | storage.add_storage_assets(config("filesystem.staticfiles")) 103 | self.application.bind("storage_capsule", storage) 104 | 105 | self.application.set_response_handler(response_handler) 106 | self.application.use_storage_path(base_path("storage")) 107 | -------------------------------------------------------------------------------- /tests/integrations/app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-filemanager/e73a4c0e0260228d5829a9ae695a961dced76c12/tests/integrations/app/__init__.py -------------------------------------------------------------------------------- /tests/integrations/app/controllers/WelcomeController.py: -------------------------------------------------------------------------------- 1 | """A WelcomeController Module.""" 2 | from masonite.views import View 3 | from masonite.controllers import Controller 4 | 5 | 6 | class WelcomeController(Controller): 7 | """WelcomeController Controller Class.""" 8 | 9 | def show(self, view: View): 10 | return view.render("welcome") 11 | 12 | def form(self, view: View): 13 | return view.render("form") 14 | -------------------------------------------------------------------------------- /tests/integrations/app/controllers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-filemanager/e73a4c0e0260228d5829a9ae695a961dced76c12/tests/integrations/app/controllers/__init__.py -------------------------------------------------------------------------------- /tests/integrations/app/middlewares/VerifyCsrfToken.py: -------------------------------------------------------------------------------- 1 | from masonite.middleware import VerifyCsrfToken as Middleware 2 | 3 | 4 | class VerifyCsrfToken(Middleware): 5 | 6 | exempt = ["/filemanager"] 7 | -------------------------------------------------------------------------------- /tests/integrations/app/models/User.py: -------------------------------------------------------------------------------- 1 | """User Model.""" 2 | from masoniteorm.models import Model 3 | from masoniteorm.scopes import SoftDeletesMixin 4 | from masonite.authentication import Authenticates 5 | 6 | 7 | class User(Model, SoftDeletesMixin, Authenticates): 8 | """User Model.""" 9 | 10 | __fillable__ = ["name", "email", "password"] 11 | __hidden__ = ["password"] 12 | __auth__ = "email" 13 | -------------------------------------------------------------------------------- /tests/integrations/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-filemanager/e73a4c0e0260228d5829a9ae695a961dced76c12/tests/integrations/config/__init__.py -------------------------------------------------------------------------------- /tests/integrations/config/application.py: -------------------------------------------------------------------------------- 1 | from masonite.environment import env 2 | 3 | 4 | KEY = env("APP_KEY", "-RkDOqXojJIlsF_I8wWiUq_KRZ0PtGWTOZ676u5HtLg=") 5 | 6 | HASHING = { 7 | "default": env("HASHING_FUNCTION", "bcrypt"), 8 | "bcrypt": {"rounds": 10}, 9 | "argon2": {"memory": 1024, "threads": 2, "time": 2}, 10 | } 11 | 12 | APP_URL = env("APP_URL", "http://localhost:8000/") 13 | -------------------------------------------------------------------------------- /tests/integrations/config/auth.py: -------------------------------------------------------------------------------- 1 | from ..app.models.User import User 2 | 3 | GUARDS = { 4 | "default": "web", 5 | "web": {"model": User}, 6 | "password_reset_table": "password_resets", 7 | "password_reset_expiration": 1440, # in minutes. 24 hours. None if disabled 8 | } 9 | -------------------------------------------------------------------------------- /tests/integrations/config/broadcast.py: -------------------------------------------------------------------------------- 1 | from masonite.environment import env 2 | 3 | 4 | BROADCASTS = { 5 | "default": "pusher", 6 | "pusher": { 7 | "driver": "pusher", 8 | "client": env("PUSHER_CLIENT"), 9 | "app_id": env("PUSHER_APP_ID"), 10 | "secret": env("PUSHER_SECRET"), 11 | "cluster": env("PUSHER_CLUSTER"), 12 | "ssl": False, 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /tests/integrations/config/cache.py: -------------------------------------------------------------------------------- 1 | # from masonite.environment import env 2 | 3 | 4 | STORES = { 5 | "default": "local", 6 | "local": { 7 | "driver": "file", 8 | "location": "storage/framework/cache" 9 | # 10 | }, 11 | "redis": { 12 | "driver": "redis", 13 | "host": "127.0.0.1", 14 | "port": "6379", 15 | "password": "", 16 | "name": "project_name", 17 | }, 18 | "memcache": { 19 | "driver": "memcache", 20 | "host": "127.0.0.1", 21 | "port": "11211", 22 | "password": "", 23 | "name": "project_name", 24 | }, 25 | } 26 | -------------------------------------------------------------------------------- /tests/integrations/config/database.py: -------------------------------------------------------------------------------- 1 | from masonite.environment import LoadEnvironment, env 2 | from masoniteorm.connections import ConnectionResolver 3 | 4 | # Loads in the environment variables when this page is imported. 5 | LoadEnvironment() 6 | 7 | """ 8 | The connections here don't determine the database but determine the "connection". 9 | They can be named whatever you want. 10 | """ 11 | DATABASES = { 12 | "default": env("DB_CONNECTION", "sqlite"), 13 | "sqlite": { 14 | "driver": "sqlite", 15 | "database": env("SQLITE_DB_DATABASE", "masonite.sqlite3"), 16 | "prefix": "", 17 | "log_queries": env("DB_LOG"), 18 | }, 19 | "mysql": { 20 | "driver": "mysql", 21 | "host": env("DB_HOST"), 22 | "user": env("DB_USERNAME"), 23 | "password": env("DB_PASSWORD"), 24 | "database": env("DB_DATABASE"), 25 | "port": env("DB_PORT"), 26 | "prefix": "", 27 | "grammar": "mysql", 28 | "options": { 29 | "charset": "utf8mb4", 30 | }, 31 | "log_queries": env("DB_LOG"), 32 | }, 33 | "postgres": { 34 | "driver": "postgres", 35 | "host": env("DB_HOST"), 36 | "user": env("DB_USERNAME"), 37 | "password": env("DB_PASSWORD"), 38 | "database": env("DB_DATABASE"), 39 | "port": env("DB_PORT"), 40 | "prefix": "", 41 | "grammar": "postgres", 42 | "log_queries": env("DB_LOG"), 43 | }, 44 | "mssql": { 45 | "driver": "mssql", 46 | "host": env("MSSQL_DATABASE_HOST"), 47 | "user": env("MSSQL_DATABASE_USER"), 48 | "password": env("MSSQL_DATABASE_PASSWORD"), 49 | "database": env("MSSQL_DATABASE_DATABASE"), 50 | "port": env("MSSQL_DATABASE_PORT"), 51 | "prefix": "", 52 | "log_queries": env("DB_LOG"), 53 | }, 54 | } 55 | 56 | DB = ConnectionResolver().set_connection_details(DATABASES) 57 | -------------------------------------------------------------------------------- /tests/integrations/config/exceptions.py: -------------------------------------------------------------------------------- 1 | HANDLERS = {"stack_overflow": True, "solutions": True} 2 | -------------------------------------------------------------------------------- /tests/integrations/config/filesystem.py: -------------------------------------------------------------------------------- 1 | from masonite.environment import env 2 | from masonite.utils.location import base_path 3 | 4 | 5 | DISKS = { 6 | "default": "local", 7 | "local": {"driver": "file", "path": base_path("storage/framework/filesystem")}, 8 | "s3": { 9 | "driver": "s3", 10 | "client": env("AWS_CLIENT"), 11 | "secret": env("AWS_SECRET"), 12 | "bucket": env("AWS_BUCKET"), 13 | }, 14 | } 15 | 16 | STATICFILES = { 17 | # folder # template alias 18 | "storage/static": "static/", 19 | "storage/compiled": "assets/", 20 | "storage/public": "/", 21 | "storage/vendor/filemanager": "filemanager-assets/", 22 | "storage/framework/filesystem/filemanager": "filemanager-uploads/", 23 | } 24 | -------------------------------------------------------------------------------- /tests/integrations/config/mail.py: -------------------------------------------------------------------------------- 1 | from masonite.environment import env 2 | 3 | 4 | FROM_EMAIL = env("MAIL_FROM", "no-reply@masonite.com") 5 | 6 | DRIVERS = { 7 | "default": env("MAIL_DRIVER", "terminal"), 8 | "smtp": { 9 | "host": env("MAIL_HOST"), 10 | "port": env("MAIL_PORT"), 11 | "username": env("MAIL_USERNAME"), 12 | "password": env("MAIL_PASSWORD"), 13 | "from": FROM_EMAIL, 14 | }, 15 | "mailgun": { 16 | "domain": env("MAILGUN_DOMAIN"), 17 | "secret": env("MAILGUN_SECRET"), 18 | "from": FROM_EMAIL, 19 | }, 20 | "terminal": { 21 | "from": FROM_EMAIL, 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /tests/integrations/config/notification.py: -------------------------------------------------------------------------------- 1 | from masonite.environment import env 2 | 3 | 4 | DRIVERS = { 5 | "slack": { 6 | "token": env("SLACK_TOKEN", ""), # used for API mode 7 | "webhook": env("SLACK_WEBHOOK", ""), # used for webhook mode 8 | }, 9 | "vonage": { 10 | "key": env("VONAGE_KEY", ""), 11 | "secret": env("VONAGE_SECRET", ""), 12 | "sms_from": env("VONAGE_SMS_FROM", "+33000000000"), 13 | }, 14 | "database": { 15 | "connection": "sqlite", 16 | "table": "notifications", 17 | }, 18 | } 19 | 20 | DRY = False 21 | -------------------------------------------------------------------------------- /tests/integrations/config/providers.py: -------------------------------------------------------------------------------- 1 | from masonite.providers import ( 2 | RouteProvider, 3 | FrameworkProvider, 4 | ViewProvider, 5 | WhitenoiseProvider, 6 | ExceptionProvider, 7 | MailProvider, 8 | SessionProvider, 9 | QueueProvider, 10 | CacheProvider, 11 | EventProvider, 12 | StorageProvider, 13 | HelpersProvider, 14 | BroadcastProvider, 15 | AuthenticationProvider, 16 | AuthorizationProvider, 17 | HashServiceProvider, 18 | ORMProvider, 19 | ) 20 | 21 | 22 | from masonite.scheduling.providers import ScheduleProvider 23 | from masonite.notification.providers import NotificationProvider 24 | from masonite.validation.providers import ValidationProvider 25 | 26 | from src.filemanager.providers import FileManagerProvider 27 | 28 | PROVIDERS = [ 29 | FrameworkProvider, 30 | HelpersProvider, 31 | RouteProvider, 32 | ViewProvider, 33 | WhitenoiseProvider, 34 | ExceptionProvider, 35 | MailProvider, 36 | NotificationProvider, 37 | SessionProvider, 38 | CacheProvider, 39 | QueueProvider, 40 | ScheduleProvider, 41 | EventProvider, 42 | StorageProvider, 43 | BroadcastProvider, 44 | HashServiceProvider, 45 | AuthenticationProvider, 46 | ValidationProvider, 47 | AuthorizationProvider, 48 | ORMProvider, 49 | FileManagerProvider, 50 | ] 51 | -------------------------------------------------------------------------------- /tests/integrations/config/queue.py: -------------------------------------------------------------------------------- 1 | # from masonite.environment import env 2 | 3 | 4 | DRIVERS = { 5 | "default": "async", 6 | "database": { 7 | "connection": "sqlite", 8 | "table": "jobs", 9 | "failed_table": "failed_jobs", 10 | "attempts": 3, 11 | "poll": 5, 12 | }, 13 | "redis": { 14 | # 15 | }, 16 | "amqp": { 17 | "username": "guest", 18 | "password": "guest", 19 | "port": "5672", 20 | "vhost": "", 21 | "host": "localhost", 22 | "channel": "default", 23 | "queue": "masonite4", 24 | }, 25 | "async": { 26 | "blocking": True, 27 | "callback": "handle", 28 | "mode": "threading", 29 | "workers": 1, 30 | }, 31 | } 32 | -------------------------------------------------------------------------------- /tests/integrations/config/session.py: -------------------------------------------------------------------------------- 1 | # from masonite.environment import env 2 | 3 | 4 | DRIVERS = { 5 | "default": "cookie", 6 | "cookie": {}, 7 | } 8 | -------------------------------------------------------------------------------- /tests/integrations/databases/migrations/2021_01_09_033202_create_password_reset_table.py: -------------------------------------------------------------------------------- 1 | from masoniteorm.migrations import Migration 2 | 3 | 4 | class CreatePasswordResetTable(Migration): 5 | def up(self): 6 | """Run the migrations.""" 7 | with self.schema.create("password_resets") as table: 8 | table.string("email").unique() 9 | table.string("token") 10 | table.datetime("expires_at").nullable() 11 | table.datetime("created_at") 12 | 13 | def down(self): 14 | """Revert the migrations.""" 15 | self.schema.drop("password_resets") 16 | -------------------------------------------------------------------------------- /tests/integrations/databases/migrations/2021_01_09_043202_create_users_table.py: -------------------------------------------------------------------------------- 1 | from masoniteorm.migrations import Migration 2 | 3 | 4 | class CreateUsersTable(Migration): 5 | def up(self): 6 | """Run the migrations.""" 7 | with self.schema.create("users") as table: 8 | table.increments("id") 9 | table.string("name") 10 | table.string("email").unique() 11 | table.string("password") 12 | table.string("second_password").nullable() 13 | table.string("remember_token").nullable() 14 | table.string("phone").nullable() 15 | table.timestamp("verified_at").nullable() 16 | table.timestamps() 17 | table.soft_deletes() 18 | 19 | def down(self): 20 | """Revert the migrations.""" 21 | self.schema.drop("users") 22 | -------------------------------------------------------------------------------- /tests/integrations/databases/seeds/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-filemanager/e73a4c0e0260228d5829a9ae695a961dced76c12/tests/integrations/databases/seeds/__init__.py -------------------------------------------------------------------------------- /tests/integrations/databases/seeds/database_seeder.py: -------------------------------------------------------------------------------- 1 | """Base Database Seeder Module.""" 2 | from masoniteorm.seeds import Seeder 3 | 4 | from .user_table_seeder import UserTableSeeder 5 | 6 | 7 | class DatabaseSeeder(Seeder): 8 | def run(self): 9 | """Run the database seeds.""" 10 | self.call(UserTableSeeder) 11 | -------------------------------------------------------------------------------- /tests/integrations/databases/seeds/user_table_seeder.py: -------------------------------------------------------------------------------- 1 | """UserTableSeeder Seeder.""" 2 | from masoniteorm.seeds import Seeder 3 | from masonite.facades import Hash 4 | 5 | from tests.integrations.app.models.User import User 6 | 7 | 8 | class UserTableSeeder(Seeder): 9 | def run(self): 10 | """Run the database seeds.""" 11 | User.create( 12 | { 13 | "name": "Joe", 14 | "email": "user@example.com", 15 | "password": Hash.make("secret"), 16 | "phone": "+123456789", 17 | } 18 | ) 19 | -------------------------------------------------------------------------------- /tests/integrations/resources/css/app.css: -------------------------------------------------------------------------------- 1 | /* Put your CSS here */ 2 | -------------------------------------------------------------------------------- /tests/integrations/resources/js/app.js: -------------------------------------------------------------------------------- 1 | 2 | require("./bootstrap.js") 3 | -------------------------------------------------------------------------------- /tests/integrations/resources/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * We'll load the axios HTTP library which allows us to easily issue requests 3 | * to our Masonite back-end. This library automatically handles sending the 4 | * CSRF token as a header based on the value of the "XSRF" token cookie. 5 | */ 6 | 7 | window.axios = require('axios'); 8 | 9 | window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 10 | 11 | /** 12 | * Next we will register the CSRF Token as a common header with Axios so that 13 | * all outgoing HTTP requests automatically have it attached. This is just 14 | * a simple convenience so we don't have to attach every token manually. 15 | */ 16 | 17 | let token = document.head.querySelector('meta[name="csrf-token"]'); 18 | 19 | if (token) { 20 | window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content; 21 | } else { 22 | console.error('CSRF token not found: https://docs.masoniteproject.com/features/csrf#ajax-vue-axios'); 23 | } 24 | -------------------------------------------------------------------------------- /tests/integrations/routes/web.py: -------------------------------------------------------------------------------- 1 | from masonite.routes import Route 2 | 3 | ROUTES = [ 4 | Route.get("/", "WelcomeController@show"), 5 | Route.get("/form", "WelcomeController@form") 6 | ] 7 | -------------------------------------------------------------------------------- /tests/integrations/storage/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-filemanager/e73a4c0e0260228d5829a9ae695a961dced76c12/tests/integrations/storage/.gitignore -------------------------------------------------------------------------------- /tests/integrations/storage/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-filemanager/e73a4c0e0260228d5829a9ae695a961dced76c12/tests/integrations/storage/public/favicon.ico -------------------------------------------------------------------------------- /tests/integrations/storage/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-filemanager/e73a4c0e0260228d5829a9ae695a961dced76c12/tests/integrations/storage/public/logo.png -------------------------------------------------------------------------------- /tests/integrations/storage/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: -------------------------------------------------------------------------------- /tests/integrations/templates/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-filemanager/e73a4c0e0260228d5829a9ae695a961dced76c12/tests/integrations/templates/__init__.py -------------------------------------------------------------------------------- /tests/integrations/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {% block title %}Masonite 4{% endblock %} 10 | 11 | 12 | 13 | {% block head %} 14 | 15 | {% endblock %} 16 | 17 | 18 | 19 | {% block content %}{% endblock %} 20 | 21 | {% block js %} 22 | 23 | {% endblock %} 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/integrations/templates/form.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Welcome on Masonite 4{% endblock %} 3 | 4 | {% block content %} 5 |
6 | Masonite Logo 7 |
8 | Masonite 4 9 |
10 | 11 |
12 | 13 |
14 |
15 |
16 | 17 |
18 |
19 | {% endblock %} 20 | 21 | {% block js %} 22 | {% endblock %} -------------------------------------------------------------------------------- /tests/integrations/templates/maintenance.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Server Maintenance 9 | 10 | 11 | 12 | 13 | 14 |
15 |

Sorry, this site is currently down for maintenance.

16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/integrations/templates/welcome.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Welcome on Masonite 4{% endblock %} 3 | 4 | {% block content %} 5 |
6 | Masonite Logo 7 |
8 | Masonite 4 9 |
10 | 11 | 32 | 33 |
34 | {% endblock %} -------------------------------------------------------------------------------- /tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-filemanager/e73a4c0e0260228d5829a9ae695a961dced76c12/tests/unit/__init__.py -------------------------------------------------------------------------------- /tests/unit/test_package.py: -------------------------------------------------------------------------------- 1 | from masonite.tests import TestCase 2 | 3 | 4 | class Testfilemanager(TestCase): 5 | def test_example(self): 6 | self.assertTrue(True) 7 | -------------------------------------------------------------------------------- /wsgi.py: -------------------------------------------------------------------------------- 1 | from masonite.foundation import Application, Kernel 2 | from tests.integrations.config.providers import PROVIDERS 3 | from tests.integrations.Kernel import Kernel as ApplicationKernel 4 | 5 | 6 | """Start The Application Instance.""" 7 | application = Application("tests/integrations") 8 | 9 | """Now Bind important providers needed to make the framework work.""" 10 | application.register_providers(Kernel, ApplicationKernel) 11 | 12 | """Now Bind important application specific providers needed to make the application work.""" 13 | application.add_providers(*PROVIDERS) 14 | --------------------------------------------------------------------------------