├── .env-example ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml └── workflows │ ├── pythonapp.yml │ └── pythonpublish.yml ├── .gitignore ├── LICENSE ├── MANIFEST.in ├── README.md ├── codecov.yml ├── craft ├── makefile ├── pyproject.toml ├── pytest.ini ├── requirements.txt ├── setup.cfg ├── setup.py ├── src ├── __init__.py └── backup │ ├── Backup.py │ ├── __init__.py │ ├── commands │ ├── BackupRunCommand.py │ └── __init__.py │ ├── config │ └── backup.py │ ├── mailables │ ├── Backup.py │ └── __init__.py │ └── providers │ ├── BackupProvider.py │ └── __init__.py ├── tests ├── __init__.py ├── integrations │ ├── Kernel.py │ ├── app │ │ ├── __init__.py │ │ ├── controllers │ │ │ ├── WelcomeController.py │ │ │ └── __init__.py │ │ ├── middlewares │ │ │ ├── AuthenticationMiddleware.py │ │ │ ├── VerifyCsrfToken.py │ │ │ └── __init__.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 │ │ ├── errors │ │ ├── 403.html │ │ ├── 404.html │ │ └── 500.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/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Maintain dependencies for GitHub Actions 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | 9 | # Maintain dependencies for cookiecutter repo 10 | - package-ecosystem: "pip" 11 | directory: "/" 12 | schedule: 13 | interval: "weekly" 14 | # Allow up to 10 open pull requests for pip dependencies 15 | open-pull-requests-limit: 10 16 | -------------------------------------------------------------------------------- /.github/workflows/pythonapp.yml: -------------------------------------------------------------------------------- 1 | name: Test Application 2 | 3 | on: 4 | pull_request: 5 | branches: [master] 6 | push: 7 | branches: [master] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | python-version: ["3.7", "3.8", "3.9", "3.10"] 15 | name: Python ${{ matrix.python-version }} 16 | steps: 17 | - uses: actions/checkout@v4 18 | - name: Set up Python ${{ matrix.python-version }} 19 | uses: actions/setup-python@v4 20 | with: 21 | python-version: ${{ matrix.python-version }} 22 | - name: Install dependencies 23 | run: | 24 | make init 25 | - name: Test with pytest and Build coverage 26 | run: | 27 | make coverage 28 | - name: Upload coverage 29 | uses: codecov/codecov-action@v3 30 | with: 31 | token: ${{ secrets.CODECOV_TOKEN }} 32 | fail_ci_if_error: false 33 | 34 | lint: 35 | runs-on: ubuntu-latest 36 | name: Lint 37 | steps: 38 | - uses: actions/checkout@v4 39 | - name: Set up Python 3.8 40 | uses: actions/setup-python@v4 41 | with: 42 | python-version: 3.8 43 | - name: Intall Flake8 44 | run: | 45 | pip install flake8 46 | - name: Lint 47 | run: make lint 48 | -------------------------------------------------------------------------------- /.github/workflows/pythonpublish.yml: -------------------------------------------------------------------------------- 1 | name: Upload Python Package 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 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 28 | -------------------------------------------------------------------------------- /.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 | dist 14 | .env 15 | *.db 16 | src/masonite_backup.egg-info 17 | storage 18 | *.gz 19 | *.zip -------------------------------------------------------------------------------- /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 | 23 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-backup/089031213f024093f7b117338c1fbae03a2015cb/MANIFEST.in -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

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

16 | 17 | # Masonite Backup 18 | 19 | Backup solution for Masonite. 20 | 21 | ### Features 22 | 23 | - [x] Backup Database 24 | - [x] Backup Files 25 | - [x] Store Backup Locally in the filesystem 26 | - [x] Email Backup 27 | - [x] Store Backup in other Masonite Supported Storage Drivers [s3] 28 | 29 | 30 | ### Installation 31 | 32 | ```bash 33 | pip install masonite-backup 34 | ``` 35 | 36 | ### Configuration 37 | 38 | Add BackupProvider to your project in `config/providers.py`: 39 | 40 | ```python 41 | # config/providers.py 42 | # ... 43 | from backup import BackupProvider 44 | 45 | # ... 46 | PROVIDERS = [ 47 | # ... 48 | # Third Party Providers 49 | BackupProvider, 50 | # ... 51 | ] 52 | ``` 53 | 54 | Then you can publish the package resources (if needed) by doing: 55 | 56 | ```bash 57 | python craft package:publish backup 58 | ``` 59 | 60 | ### Usage 61 | 62 | Once you publish the package resources, you can use the `backup` command to backup your database and files. Before that if you want to configure options of backup then you can do that by updating `config/backup.py` configuration file. 63 | 64 | ```python 65 | # config/backup.py 66 | 67 | FILENAME = "backup" 68 | DIRECTORY = "backup" 69 | SOURCE = { 70 | "root": base_path(), 71 | "excludes": [ 72 | ".git", 73 | "storage", 74 | "venv", 75 | "node_modules", 76 | "__pycache__", 77 | # add more... 78 | ], 79 | } 80 | 81 | S3_BACKUP = False # Whether or not to backup to S3. 82 | EMAIL_BACKUP = False # Whether or not to email the backup. 83 | EMAIL_BACKUP_TO = "" # The email address to send the backup to. 84 | EMAIL_SUBJECT = "System Backup" # The email subject. 85 | ``` 86 | > Note: Make sure you have `EMAIL_BACKUP` set to `True` and `EMAIL_BACKUP_TO` set to a valid email address, to send the backup via email. Also don't forget to setup SMTP in `config/mail.py` configuration file or in `.env` file. In case you want to backup to S3, then make sure you have `S3_BACKUP` set to `True` and S3 storage configuration. 87 | 88 | ```sh 89 | MAIL_DRIVER=smtp 90 | MAIL_FROM= 91 | MAIL_HOST= 92 | MAIL_PORT= 93 | MAIL_USERNAME= 94 | MAIL_PASSWORD= 95 | 96 | AWS_CLIENT= 97 | AWS_SECRET= 98 | AWS_BUCKET= 99 | AWS_REGION= 100 | ``` 101 | 102 | **Backup Database and Files** 103 | 104 | ```bash 105 | python craft backup:run 106 | ``` 107 | 108 | **Backup Database Only** 109 | 110 | ```bash 111 | python craft backup:run --only-db 112 | ``` 113 | 114 | **Backup Files Only** 115 | 116 | ```bash 117 | python craft backup:run --only-files 118 | ``` 119 | 120 | ## License 121 | 122 | Backup is open-sourced software licensed under the [MIT license](LICENSE). 123 | 124 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/backup 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_backup.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 | -------------------------------------------------------------------------------- /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-backup", 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.0.4", 12 | packages=[ 13 | "backup", 14 | "backup.commands", 15 | "backup.mailables", 16 | "backup.providers", 17 | "backup.config", 18 | ], 19 | package_dir={"": "src"}, 20 | description="Backup solution for Masonite.", 21 | long_description=long_description, 22 | long_description_content_type="text/markdown", 23 | # The project's main homepage. 24 | url="https://github.com/py-package/masonite-backup", 25 | # Author details 26 | author="Yubaraj Shrestha", 27 | author_email="yubaraj@pypackage.com", 28 | # Choose your license 29 | license="MIT license", 30 | # If your package should include things you specify in your MANIFEST.in file 31 | # Use this option if your package needs to include files that are not python files 32 | # like html templates or css files 33 | include_package_data=True, 34 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 35 | classifiers=[ 36 | # How mature is this project? Common values are 37 | # 3 - Alpha 38 | # 4 - Beta 39 | # 5 - Production/Stable 40 | "Development Status :: 4 - Beta", 41 | # Indicate who your project is intended for 42 | "Intended Audience :: Developers", 43 | "Topic :: Software Development :: Build Tools", 44 | "Environment :: Web Environment", 45 | # Pick your license as you wish (should match "license" above) 46 | "License :: OSI Approved :: MIT License", 47 | "Operating System :: OS Independent", 48 | # Specify the Python versions you support here. In particular, ensure 49 | # that you indicate whether you support Python 2, Python 3 or both. 50 | "Programming Language :: Python :: 3.6", 51 | "Programming Language :: Python :: 3.7", 52 | "Programming Language :: Python :: 3.8", 53 | "Programming Language :: Python :: 3.9", 54 | "Topic :: Internet :: WWW/HTTP", 55 | "Topic :: Internet :: WWW/HTTP :: Dynamic Content", 56 | "Topic :: Internet :: WWW/HTTP :: WSGI", 57 | "Topic :: Software Development :: Libraries :: Application Frameworks", 58 | "Topic :: Software Development :: Libraries :: Python Modules", 59 | # List package on masonite packages website 60 | "Framework :: Masonite", 61 | ], 62 | # What does your project relate to? 63 | keywords="Masonite, Python, Development", 64 | # List run-time dependencies here. These will be installed by pip when 65 | # your project is installed. For an analysis of "install_requires" vs pip's 66 | # requirements files see: 67 | # https://packaging.python.org/en/latest/requirements.html 68 | install_requires=["masonite>=4.0,<5.0"], 69 | # List additional groups of dependencies here (e.g. development 70 | # dependencies). You can install these using the following syntax, 71 | # for example: 72 | # $ pip install -e .[dev,test] 73 | # $ pip install your-package[dev,test] 74 | extras_require={ 75 | "dev": [ 76 | "black", 77 | "flake8", 78 | "coverage", 79 | "pytest", 80 | "pytest-cov", 81 | "twine>=1.5.0", 82 | "wheel", 83 | ], 84 | }, 85 | # If there are data files included in your packages that need to be 86 | # installed, specify them here. If using Python 2.6 or less, then these 87 | # have to be included in MANIFEST.in as well. 88 | package_data={ 89 | # 'templates/index.html': [], 90 | }, 91 | ) 92 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-backup/089031213f024093f7b117338c1fbae03a2015cb/src/__init__.py -------------------------------------------------------------------------------- /src/backup/Backup.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa F501 2 | import pathlib 3 | import shutil 4 | import tempfile 5 | from unittest.mock import patch 6 | from masonite.configuration import config 7 | from shutil import make_archive 8 | from datetime import datetime 9 | from masonite.utils.location import base_path 10 | import subprocess 11 | import gzip 12 | from masonite.facades import Mail 13 | from .mailables.Backup import Backup as BackupMailable 14 | 15 | 16 | class Backup: 17 | def __init__(self, application) -> None: 18 | self.app = application 19 | self.backup_config = config("backup") 20 | 21 | self.db_file_path = None 22 | self.archive_file_path = None 23 | 24 | def accept(self, path): 25 | for pattern in self.backup_config.get("source").get("excludes"): 26 | if pattern in path: 27 | return False 28 | return True 29 | 30 | def database(self): 31 | """ 32 | Backup the database. 33 | """ 34 | 35 | db_config = config("database.databases") 36 | default = db_config.get("default") 37 | connection = db_config.get(default) 38 | driver = connection.get("driver") 39 | 40 | self.db_file_path = base_path( 41 | "{}.gz".format("database-" + str(datetime.timestamp(datetime.now()))) 42 | ) 43 | 44 | if driver == "sqlite": 45 | pass 46 | elif driver == "mysql": 47 | command_str = f"mysqldump -u {connection.get('user')} -p{connection.get('password')} {connection.get('database')}" 48 | 49 | elif driver == "postgres": 50 | command_str = f"pg_dump -U{connection.get('user')} -h{connection.get('host')} -p{connection.get('port')} -d{connection.get('database')}" 51 | 52 | elif driver == "mssql": 53 | command_str = f"sqlcmd -S{connection.get('host')} -U{connection.get('user')} -P{connection.get('port')} -d{connection.get('database')}" 54 | 55 | elif driver == "sqlserver": 56 | command_str = f"sqlcmd -S{connection.get('host')} -U{connection.get('user')} -P{connection.get('port')} -d{connection.get('database')}" 57 | 58 | elif driver == "oracle": 59 | command_str = f"sqlplus -S{connection.get('user')}/{connection.get('password')}@{connection.get('host')}:{connection.get('port')}/{connection.get('database')}" 60 | 61 | if command_str: 62 | with gzip.open(self.db_file_path, "wb") as f: 63 | popen = subprocess.Popen( 64 | [command_str], 65 | stdout=subprocess.PIPE, 66 | shell=True, 67 | universal_newlines=True, 68 | ) 69 | for stdout_line in iter(popen.stdout.readline, ""): 70 | f.write(stdout_line.encode("utf-8")) 71 | popen.stdout.close() 72 | popen.wait() 73 | return self.db_file_path 74 | 75 | def files(self): 76 | """ 77 | Backup the files. 78 | """ 79 | filename = ( 80 | self.backup_config.get("filename", "backup") 81 | + "-" 82 | + str(datetime.timestamp(datetime.now())) 83 | ) 84 | 85 | output_dir = base_path("storage/backup") 86 | 87 | if not pathlib.Path(output_dir).exists(): 88 | pathlib.Path(output_dir).mkdir(parents=True, exist_ok=True) 89 | 90 | self.archive_file_path = pathlib.Path(output_dir).joinpath(filename) 91 | 92 | with tempfile.TemporaryDirectory() as tmp: 93 | shutil.copytree( 94 | self.backup_config.get("source").get("root"), 95 | pathlib.Path(tmp).joinpath("backup"), 96 | ignore=shutil.ignore_patterns(*self.backup_config.get("source").get("excludes")), 97 | ) 98 | 99 | with patch("os.path.isfile", side_effect=self.accept): 100 | make_archive(self.archive_file_path, "zip", tmp) 101 | 102 | return f"{self.archive_file_path}.zip" 103 | 104 | def email(self, info): 105 | """ 106 | Email the backup. 107 | """ 108 | 109 | if not self.backup_config.get("email_backup", False): 110 | return 111 | 112 | info("Sending backup to email") 113 | if ( 114 | self.archive_file_path != None 115 | and pathlib.Path(f"{self.archive_file_path}.zip").exists() 116 | ): 117 | Mail.mailable( 118 | BackupMailable().attach(f"System Backup.zip", f"{self.archive_file_path}.zip") 119 | ).send() 120 | 121 | if self.db_file_path != None and pathlib.Path(self.db_file_path).exists(): 122 | ext = self.db_file_path.split(".")[-1] 123 | Mail.mailable( 124 | BackupMailable().attach(f"Database Backup.{ext}", self.db_file_path) 125 | ).send() 126 | 127 | def s3(self, info): 128 | """ 129 | Upload the backup to S3. 130 | """ 131 | if not self.backup_config.get("s3_backup", False): 132 | return 133 | 134 | info("Uploading backup to S3") 135 | if ( 136 | self.archive_file_path != None 137 | and pathlib.Path(f"{self.archive_file_path}.zip").exists() 138 | ): 139 | self.app.make("storage").disk("s3").put( 140 | f"System Backup.zip", f"{self.archive_file_path}.zip" 141 | ) 142 | 143 | if self.db_file_path != None and pathlib.Path(self.db_file_path).exists(): 144 | ext = self.db_file_path.split(".")[-1] 145 | self.app.make("storage").disk("s3").put(f"Database Backup.{ext}", self.db_file_path) 146 | 147 | def cleanup(self): 148 | """ 149 | Cleanup the backup files. 150 | """ 151 | if self.archive_file_path != None and pathlib.Path(self.archive_file_path).exists(): 152 | pathlib.Path(self.archive_file_path).unlink() 153 | if self.db_file_path != None and pathlib.Path(self.db_file_path).exists(): 154 | pathlib.Path(self.db_file_path).unlink() 155 | -------------------------------------------------------------------------------- /src/backup/__init__.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa F401 2 | from .providers.BackupProvider import BackupProvider 3 | -------------------------------------------------------------------------------- /src/backup/commands/BackupRunCommand.py: -------------------------------------------------------------------------------- 1 | import os 2 | from masonite.commands import Command 3 | 4 | 5 | class BackupRunCommand(Command): 6 | """ 7 | Start the backup process. 8 | 9 | backup:run 10 | {--filename : Backup filename} 11 | {--only-db : Backup database only} 12 | {--only-files : Backup files only} 13 | """ 14 | 15 | def __init__(self, application): 16 | super().__init__() 17 | self.app = application 18 | self.database_file_path = None 19 | self.assets_file_path = None 20 | 21 | def handle(self): 22 | backup = self.app.make("backup") 23 | 24 | if not self.validate_options(): 25 | return 26 | 27 | self.info("============ Backup starting ============") 28 | 29 | if self.option("only-db"): 30 | self.database_file_path = backup.database() 31 | elif self.option("only-files"): 32 | self.assets_file_path = backup.files() 33 | else: 34 | self.info("Backuping database...") 35 | self.database_file_path = backup.database() 36 | self.info("Backuping files...") 37 | self.assets_file_path = backup.files() 38 | 39 | # delete the database file 40 | os.remove(self.database_file_path) 41 | self.database_file_path = None 42 | 43 | backup.email(self.info) 44 | backup.s3(self.info) 45 | backup.cleanup() 46 | 47 | self.info("============ Backup complete ============") 48 | 49 | def validate_options(self): 50 | if self.option("only-db") and self.option("only-files"): 51 | self.error("You can only pass either files or database backup option.") 52 | return False 53 | return True 54 | -------------------------------------------------------------------------------- /src/backup/commands/__init__.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa F401 2 | from .BackupRunCommand import BackupRunCommand 3 | -------------------------------------------------------------------------------- /src/backup/config/backup.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa F501 2 | """Backup Settings""" 3 | 4 | from masonite.utils.location import base_path 5 | 6 | """ 7 | |-------------------------------------------------------------------------- 8 | | Masonite Backup 9 | |-------------------------------------------------------------------------- 10 | | 11 | | This is the configuration file for the Masonite Backup package. 12 | | 13 | """ 14 | 15 | FILENAME = "backup" # The filename of the backup file. (without the extension) 16 | DIRECTORY = "backup" # storage/backup 17 | SOURCE = { 18 | "root": base_path(), 19 | "excludes": [ 20 | ".git", 21 | "storage", 22 | "venv", 23 | "node_modules", 24 | "__pycache__", 25 | ], 26 | } 27 | S3_BACKUP = False # Whether or not to backup in S3. 28 | EMAIL_BACKUP = False # Whether or not to email the backup. 29 | EMAIL_BACKUP_TO = "" # The email address to send the backup to. 30 | EMAIL_SUBJECT = "System Backup" # The email subject. 31 | -------------------------------------------------------------------------------- /src/backup/mailables/Backup.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa F501 2 | from masonite.mail import Mailable 3 | from masonite.configuration import config 4 | from masonite.environment import env 5 | 6 | 7 | class Backup(Mailable): 8 | def build(self): 9 | backup_config = config("backup") 10 | email = backup_config.get("email_backup_to") 11 | 12 | if not email: 13 | raise Exception("No email address found in backup config.") 14 | 15 | return ( 16 | self.to(email) 17 | .subject(backup_config.get("email_subject")) 18 | .from_(env("MAIL_FROM")) 19 | .html( 20 | """ 21 |
22 |

Backup Complete

23 |

24 | Your backup has been completed and is now available for download.
Please, find the file attached here within. 25 |


26 | Thanks,
Masonite Backup
27 |
28 | """ 29 | ) 30 | ) 31 | -------------------------------------------------------------------------------- /src/backup/mailables/__init__.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa F401 2 | from .Backup import Backup 3 | -------------------------------------------------------------------------------- /src/backup/providers/BackupProvider.py: -------------------------------------------------------------------------------- 1 | """A BackupProvider Service Provider.""" 2 | 3 | from masonite.packages import PackageProvider 4 | from ..Backup import Backup 5 | from ..commands import BackupRunCommand 6 | 7 | 8 | class BackupProvider(PackageProvider): 9 | def configure(self): 10 | """Register objects into the Service Container.""" 11 | (self.root("backup").name("backup").config("config/backup.py", publish=True)) 12 | 13 | def register(self): 14 | super().register() 15 | 16 | self.application.bind("backup", Backup(application=self.application)) 17 | self.application.make("commands").add(BackupRunCommand(application=self.application)) 18 | 19 | def boot(self): 20 | """Boots services required by the container.""" 21 | pass 22 | -------------------------------------------------------------------------------- /src/backup/providers/__init__.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa: E501 2 | from .BackupProvider import BackupProvider 3 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-backup/089031213f024093f7b117338c1fbae03a2015cb/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 tests.integrations.app.middlewares import VerifyCsrfToken, AuthenticationMiddleware 18 | 19 | 20 | class Kernel: 21 | 22 | http_middleware = [MaintenanceModeMiddleware, EncryptCookies] 23 | 24 | route_middleware = { 25 | "web": [SessionMiddleware, LoadUserMiddleware, VerifyCsrfToken], 26 | "auth": [AuthenticationMiddleware], 27 | } 28 | 29 | def __init__(self, app): 30 | self.application = app 31 | 32 | def register(self): 33 | # Register routes 34 | self.load_environment() 35 | self.register_configurations() 36 | self.register_middleware() 37 | self.register_routes() 38 | self.register_database() 39 | self.register_templates() 40 | self.register_storage() 41 | 42 | def load_environment(self): 43 | LoadEnvironment() 44 | 45 | def register_configurations(self): 46 | # load configuration 47 | self.application.bind("config.location", "tests/integrations/config") 48 | configuration = Configuration(self.application) 49 | configuration.load() 50 | self.application.bind("config", configuration) 51 | key = config("application.key") 52 | self.application.bind("key", key) 53 | self.application.bind("sign", Sign(key)) 54 | # set locations 55 | self.application.bind("resources.location", "tests/integrations/resources/") 56 | self.application.bind("controllers.location", "tests/integrations/app/controllers") 57 | self.application.bind("jobs.location", "tests/integrations/app/jobs") 58 | self.application.bind("providers.location", "tests/integrations/app/providers") 59 | self.application.bind("mailables.location", "tests/integrations/app/mailables") 60 | self.application.bind("listeners.location", "tests/integrations/app/listeners") 61 | self.application.bind("validation.location", "tests/integrations/app/validation") 62 | self.application.bind("notifications.location", "tests/integrations/app/notifications") 63 | self.application.bind("events.location", "tests/integrations/app/events") 64 | self.application.bind("tasks.location", "tests/integrations/app/tasks") 65 | self.application.bind("models.location", "tests/integrations/app/models") 66 | self.application.bind("observers.location", "tests/integrations/app/models/observers") 67 | self.application.bind("policies.location", "tests/integrations/app/policies") 68 | self.application.bind("commands.location", "tests/integrations/app/commands") 69 | self.application.bind("middlewares.location", "tests/integrations/app/middlewares") 70 | 71 | self.application.bind("server.runner", "masonite.commands.ServeCommand.main") 72 | 73 | def register_middleware(self): 74 | self.application.make("middleware").add(self.route_middleware).add(self.http_middleware) 75 | 76 | def register_routes(self): 77 | Route.set_controller_locations(self.application.make("controllers.location")) 78 | self.application.bind("routes.location", "tests/integrations/routes/web") 79 | self.application.make("router").add( 80 | Route.group( 81 | load(self.application.make("routes.location"), "ROUTES"), middleware=["web"] 82 | ) 83 | ) 84 | 85 | def register_database(self): 86 | from masoniteorm.query import QueryBuilder 87 | 88 | self.application.bind( 89 | "builder", 90 | QueryBuilder(connection_details=config("database.databases")), 91 | ) 92 | 93 | self.application.bind("migrations.location", "tests/integrations/databases/migrations") 94 | self.application.bind("seeds.location", "tests/integrations/databases/seeds") 95 | 96 | self.application.bind("resolver", config("database.db")) 97 | 98 | def register_templates(self): 99 | self.application.bind("views.location", "tests/integrations/templates/") 100 | 101 | def register_storage(self): 102 | storage = StorageCapsule() 103 | storage.add_storage_assets(config("filesystem.staticfiles")) 104 | self.application.bind("storage_capsule", storage) 105 | 106 | self.application.set_response_handler(response_handler) 107 | self.application.use_storage_path(base_path("storage")) 108 | -------------------------------------------------------------------------------- /tests/integrations/app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-backup/089031213f024093f7b117338c1fbae03a2015cb/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 | -------------------------------------------------------------------------------- /tests/integrations/app/controllers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-backup/089031213f024093f7b117338c1fbae03a2015cb/tests/integrations/app/controllers/__init__.py -------------------------------------------------------------------------------- /tests/integrations/app/middlewares/AuthenticationMiddleware.py: -------------------------------------------------------------------------------- 1 | from masonite.middleware import Middleware 2 | 3 | 4 | class AuthenticationMiddleware(Middleware): 5 | """Middleware to check if the user is logged in.""" 6 | 7 | def before(self, request, response): 8 | if not request.user(): 9 | return response.redirect(name="login") 10 | return request 11 | 12 | def after(self, request, response): 13 | return request 14 | -------------------------------------------------------------------------------- /tests/integrations/app/middlewares/VerifyCsrfToken.py: -------------------------------------------------------------------------------- 1 | from masonite.middleware import VerifyCsrfToken as Middleware 2 | 3 | 4 | class VerifyCsrfToken(Middleware): 5 | 6 | exempt = [] 7 | -------------------------------------------------------------------------------- /tests/integrations/app/middlewares/__init__.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa: F401 2 | from .VerifyCsrfToken import VerifyCsrfToken 3 | from .AuthenticationMiddleware import AuthenticationMiddleware 4 | -------------------------------------------------------------------------------- /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-backup/089031213f024093f7b117338c1fbae03a2015cb/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 tests.integrations.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": { 8 | "driver": "file", 9 | "path": base_path("tests/integrations/storage/framework/filesystem") 10 | }, 11 | "s3": { 12 | "driver": "s3", 13 | "client": env("AWS_CLIENT"), 14 | "secret": env("AWS_SECRET"), 15 | "bucket": env("AWS_BUCKET"), 16 | }, 17 | } 18 | 19 | STATICFILES = { 20 | # folder # template alias 21 | 'tests/integrations/storage/static': 'static/', 22 | 'tests/integrations/storage/compiled': 'assets/', 23 | 'tests/integrations/storage/public': '/', 24 | } 25 | -------------------------------------------------------------------------------- /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 | # register local package 27 | from src.backup import BackupProvider 28 | 29 | 30 | PROVIDERS = [ 31 | FrameworkProvider, 32 | HelpersProvider, 33 | RouteProvider, 34 | ViewProvider, 35 | WhitenoiseProvider, 36 | ExceptionProvider, 37 | MailProvider, 38 | NotificationProvider, 39 | SessionProvider, 40 | CacheProvider, 41 | QueueProvider, 42 | ScheduleProvider, 43 | EventProvider, 44 | StorageProvider, 45 | BroadcastProvider, 46 | HashServiceProvider, 47 | AuthenticationProvider, 48 | ValidationProvider, 49 | AuthorizationProvider, 50 | ORMProvider 51 | ] 52 | 53 | PROVIDERS += [BackupProvider] 54 | -------------------------------------------------------------------------------- /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-backup/089031213f024093f7b117338c1fbae03a2015cb/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 = [Route.get("/", "WelcomeController@show")] 4 | -------------------------------------------------------------------------------- /tests/integrations/storage/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-backup/089031213f024093f7b117338c1fbae03a2015cb/tests/integrations/storage/.gitignore -------------------------------------------------------------------------------- /tests/integrations/storage/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-backup/089031213f024093f7b117338c1fbae03a2015cb/tests/integrations/storage/public/favicon.ico -------------------------------------------------------------------------------- /tests/integrations/storage/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py-package/masonite-backup/089031213f024093f7b117338c1fbae03a2015cb/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-backup/089031213f024093f7b117338c1fbae03a2015cb/tests/integrations/templates/__init__.py -------------------------------------------------------------------------------- /tests/integrations/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {% block title %}Masonite 4{% endblock %} 9 | 10 | 14 | {% block head %} 15 | 16 | {% endblock %} 17 | 18 | 19 | {% block content %}{% endblock %} 20 | {% block js %} 21 | 22 | {% endblock %} 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/integrations/templates/errors/403.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Permission Denied 9 | 10 | 11 | 12 | 13 | {% block content %} 14 |
15 |

Oops looks like you don't have access to this page !

16 |
17 | {% endblock %} 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/integrations/templates/errors/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Page Not Found 9 | 10 | 11 | 12 | 13 | {% block content %} 14 |
15 |

Oops this page does not exist !

16 |
17 | {% endblock %} 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/integrations/templates/errors/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Error 500 9 | 10 | 11 | 12 | 13 | {% block content %} 14 |
15 |

Oops an error happened !

16 |
17 | {% endblock %} 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/integrations/templates/maintenance.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Server Maintenance 9 | 10 | 11 | 12 | 13 | {% block content %} 14 |
15 |

Sorry, this site is currently down for maintenance.

16 |
17 | {% endblock %} 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-backup/089031213f024093f7b117338c1fbae03a2015cb/tests/unit/__init__.py -------------------------------------------------------------------------------- /tests/unit/test_package.py: -------------------------------------------------------------------------------- 1 | from masonite.tests import TestCase 2 | 3 | 4 | class TestBackup(TestCase): 5 | 6 | def test_example(self): 7 | self.assertTrue(True) 8 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------