├── .env-example
├── .flake8
├── .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
├── description
├── makefile
├── masonite.sqlite3
├── pyproject.toml
├── pytest.ini
├── requirements.txt
├── setup.cfg
├── setup.py
├── src
├── __init__.py
└── masonite_audit
│ ├── __init__.py
│ ├── config
│ └── masonite_audit.py
│ ├── masonite_audit.py
│ ├── migrations
│ └── create_audit_logs_table.py
│ ├── mixins
│ ├── __init__.py
│ └── audit.py
│ ├── models
│ └── audit_log.py
│ ├── observer
│ ├── __init__.py
│ └── audit_observer.py
│ └── providers
│ ├── AuditProvider.py
│ └── __init__.py
├── 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
│ │ ├── masonite-audit.py
│ │ ├── masonite_audit.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
│ │ │ └── 2022_04_21_110158_create_audit_logs_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
│ │ ├── maintenance.html
│ │ └── welcome.html
└── unit
│ ├── __init__.py
│ └── test_audit.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 |
--------------------------------------------------------------------------------
/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | per-file-ignores = __init__.py:F401
--------------------------------------------------------------------------------
/.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 |
7 | jobs:
8 | build:
9 | runs-on: ubuntu-latest
10 | strategy:
11 | matrix:
12 | python-version: ["3.7", "3.8", "3.9", "3.10"]
13 | name: Python ${{ matrix.python-version }}
14 | steps:
15 | - uses: actions/checkout@v3
16 | - name: Set up Python ${{ matrix.python-version }}
17 | uses: actions/setup-python@v4
18 | with:
19 | python-version: ${{ matrix.python-version }}
20 | - name: Install dependencies
21 | run: |
22 | make init
23 | - name: Test with pytest and Build coverage
24 | run: |
25 | make coverage
26 | - name: Upload coverage
27 | uses: codecov/codecov-action@v3
28 | with:
29 | token: ${{ secrets.CODECOV_TOKEN }}
30 | fail_ci_if_error: false
31 |
32 | lint:
33 | runs-on: ubuntu-latest
34 | name: Lint
35 | steps:
36 | - uses: actions/checkout@v3
37 | - name: Set up Python 3.8
38 | uses: actions/setup-python@v4
39 | with:
40 | python-version: 3.8
41 | - name: Intall Flake8
42 | run: |
43 | pip install flake8
44 | - name: Lint
45 | run: make lint
46 |
--------------------------------------------------------------------------------
/.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@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: meyubaraj
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_masonite_permission.egg-info
--------------------------------------------------------------------------------
/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-audit/f3243c2a6af99bd007293c3662c6eeb9418a01b2/MANIFEST.in
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Masonite Audit
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | ## Introduction
20 |
21 | Keep track of all your model changes with ease.
22 |
23 | ## Getting Started
24 |
25 | Install the package using pip:
26 |
27 | ```bash
28 | pip install masonite-audit
29 | ```
30 |
31 | Add AuditProvider to your project in `config/providers.py`:
32 |
33 | ```python
34 | # config/providers.py
35 | # ...
36 | from masonite_audit import AuditProvider
37 |
38 | # ...
39 | PROVIDERS = [
40 | # ...
41 | # Third Party Providers
42 | AuditProvider,
43 | # ...
44 | ]
45 | ```
46 |
47 | Publish the package configuration files.
48 |
49 | ```bash
50 | python craft package:publish masonite-audit
51 | ```
52 |
53 | This will add migrations and other `masonite-audit` related configuration to your project. Run your migrations to create the related database tables.
54 |
55 | ```bash
56 | python craft migrate
57 | ```
58 |
59 | Finally, inherit `Audit` mixin into all the models for which you need audit logging.
60 |
61 | ```python
62 | from masonite_audit.mixins import Audit
63 | class YourModel(Audit):
64 | pass
65 | ```
66 |
67 | If you want to get the audit history for a model, you can use the `history` method:
68 |
69 | ```python
70 | user = User.find(1)
71 | user.history()
72 | ```
73 |
74 | In order to rollback to previous versions of a model, you can use the `rollback` method:
75 |
76 | ```python
77 | user = User.find(1)
78 | user.rollback() # to rollback to previous version
79 | # or
80 | user.rollback(step=4) # to rollback to version 4
81 | ```
82 |
83 |
84 |
85 | ## License
86 |
87 | Masonite Audit is open-sourced software licensed under the [MIT license](LICENSE).
88 |
89 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | black tests
22 | coverage: ## Run package tests and upload coverage reports
23 | python -m pytest --cov-report term --cov-report xml --cov=src/masonite/masonite_audit tests
24 | publish: ## Publish package to pypi
25 | python setup.py sdist bdist_wheel
26 | twine upload dist/* --verbose
27 | rm -fr build dist .egg src/masonite_audit.egg-info
28 | pypirc: ## Copy the template .pypirc in the repo to your home directory
29 | cp .pypirc ~/.pypirc
--------------------------------------------------------------------------------
/masonite.sqlite3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-package/masonite-audit/f3243c2a6af99bd007293c3662c6eeb9418a01b2/masonite.sqlite3
--------------------------------------------------------------------------------
/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 | psycopg2-binary==2.9.5
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-audit",
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.6",
12 | packages=[
13 | "masonite_audit",
14 | "masonite_audit.config",
15 | "masonite_audit.migrations",
16 | "masonite_audit.mixins",
17 | "masonite_audit.models",
18 | "masonite_audit.observer",
19 | "masonite_audit.providers"
20 | ],
21 | package_dir={"": "src"},
22 | description="Keep track of all your model changes with ease.",
23 | long_description=long_description,
24 | long_description_content_type="text/markdown",
25 | # The project's main homepage.
26 | url="https://github.com/py-package/masonite-audit",
27 | # Author details
28 | author="Yubaraj Shrestha",
29 | author_email="yubaraj@pypackage.com",
30 | # Choose your license
31 | license="MIT license",
32 | # If your package should include things you specify in your MANIFEST.in file
33 | # Use this option if your package needs to include files that are not python files
34 | # like html templates or css files
35 | include_package_data=True,
36 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers
37 | classifiers=[
38 | # How mature is this project? Common values are
39 | # 3 - Alpha
40 | # 4 - Beta
41 | # 5 - Production/Stable
42 | "Development Status :: 5 - Production/Stable",
43 | # Indicate who your project is intended for
44 | "Intended Audience :: Developers",
45 | "Environment :: Web Environment",
46 | # Pick your license as you wish (should match "license" above)
47 | "License :: OSI Approved :: MIT License",
48 | "Operating System :: OS Independent",
49 | # Specify the Python versions you support here. In particular, ensure
50 | # that you indicate whether you support Python 2, Python 3 or both.
51 | "Programming Language :: Python :: 3.7",
52 | "Programming Language :: Python :: 3.8",
53 | "Programming Language :: Python :: 3.9",
54 | "Topic :: Software Development :: Libraries :: Application Frameworks",
55 | "Topic :: Software Development :: Libraries :: Python Modules",
56 | # List package on masonite packages website
57 | "Framework :: Masonite",
58 | ],
59 | # What does your project relate to?
60 | keywords="Masonite, Python, Development, Audit, Audit Log",
61 | # List run-time dependencies here. These will be installed by pip when
62 | # your project is installed. For an analysis of "install_requires" vs pip's
63 | # requirements files see:
64 | # https://packaging.python.org/en/latest/requirements.html
65 | install_requires=["masonite>=4.0<5.0"],
66 | # List additional groups of dependencies here (e.g. development
67 | # dependencies). You can install these using the following syntax,
68 | # for example:
69 | # $ pip install -e .[dev,test]
70 | # $ pip install your-package[dev,test]
71 | extras_require={
72 | "dev": [
73 | "black",
74 | "flake8",
75 | "coverage",
76 | "pytest",
77 | "pytest-cov",
78 | "twine>=1.5.0",
79 | "wheel",
80 | ],
81 | },
82 | # If there are data files included in your packages that need to be
83 | # installed, specify them here. If using Python 2.6 or less, then these
84 | # have to be included in MANIFEST.in as well.
85 | package_data={
86 | 'templates/index.html': [],
87 | },
88 | )
89 |
--------------------------------------------------------------------------------
/src/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-package/masonite-audit/f3243c2a6af99bd007293c3662c6eeb9418a01b2/src/__init__.py
--------------------------------------------------------------------------------
/src/masonite_audit/__init__.py:
--------------------------------------------------------------------------------
1 | # flake8: noqa F401
2 | from .providers.AuditProvider import AuditProvider
3 |
--------------------------------------------------------------------------------
/src/masonite_audit/config/masonite_audit.py:
--------------------------------------------------------------------------------
1 | """Masonite Audit Settings"""
2 |
3 | """
4 | |--------------------------------------------------------------------------
5 | | A Heading of The Setting Being Set
6 | |--------------------------------------------------------------------------
7 | |
8 | | A quick description
9 | |
10 | """
11 |
--------------------------------------------------------------------------------
/src/masonite_audit/masonite_audit.py:
--------------------------------------------------------------------------------
1 | from .observer.audit_observer import AuditObserver
2 |
3 |
4 | class MasoniteAudit:
5 | def observe(self):
6 | from .mixins import Audit
7 |
8 | for model in Audit.__subclasses__():
9 | model.observe(AuditObserver())
10 |
--------------------------------------------------------------------------------
/src/masonite_audit/migrations/create_audit_logs_table.py:
--------------------------------------------------------------------------------
1 | from masoniteorm.migrations import Migration
2 |
3 |
4 | class CreateAuditLogsTable(Migration):
5 | def up(self):
6 | """Run the migrations."""
7 |
8 | with self.schema.create("audit_logs") as table:
9 | table.increments("id")
10 | table.integer("editor_id").unsigned().nullable()
11 | table.integer("model_id").unsigned()
12 | table.string("model_name")
13 | table.string("action")
14 | table.json("columns").default("{}")
15 | table.json("old_value").default("{}")
16 | table.json("new_value").default("{}")
17 | table.timestamps()
18 |
19 | def down(self):
20 | """Revert the migrations."""
21 |
22 | self.schema.drop("audit_logs")
23 |
--------------------------------------------------------------------------------
/src/masonite_audit/mixins/__init__.py:
--------------------------------------------------------------------------------
1 | # flake8: noqa: E501
2 | from .audit import Audit as Audit
3 |
--------------------------------------------------------------------------------
/src/masonite_audit/mixins/audit.py:
--------------------------------------------------------------------------------
1 | from ..models.audit_log import AuditLog
2 |
3 |
4 | class Audit(object):
5 | def history(self):
6 | """Returns a list of logs for the model."""
7 | return (
8 | AuditLog.where("model_name", self.__class__.get_table_name())
9 | .where("model_id", self.id)
10 | .order_by("created_at", "desc")
11 | .get()
12 | )
13 |
14 | def rollback(self, step=1):
15 | """Rolls back a log to the model."""
16 | logs = self.history()
17 | if len(logs) >= step:
18 | log = logs[step - 1] # because step is index+1
19 |
20 | if log.old_value is not None and "updated_at" in log.old_value:
21 | log.old_value.pop("updated_at")
22 |
23 | self.update(log.old_value)
24 | self.save()
25 |
--------------------------------------------------------------------------------
/src/masonite_audit/models/audit_log.py:
--------------------------------------------------------------------------------
1 | from masoniteorm.models import Model
2 |
3 |
4 | class AuditLog(Model):
5 |
6 | __fillable__ = [
7 | "editor_id",
8 | "model_id",
9 | "model_name",
10 | "action",
11 | "columns",
12 | "old_value",
13 | "new_value",
14 | "created_at",
15 | "updated_at",
16 | ]
17 |
18 | __casts__ = {
19 | "columns": "json",
20 | "old_value": "json",
21 | "new_value": "json",
22 | }
23 |
--------------------------------------------------------------------------------
/src/masonite_audit/observer/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-package/masonite-audit/f3243c2a6af99bd007293c3662c6eeb9418a01b2/src/masonite_audit/observer/__init__.py
--------------------------------------------------------------------------------
/src/masonite_audit/observer/audit_observer.py:
--------------------------------------------------------------------------------
1 | import json
2 | from ..models.audit_log import AuditLog
3 | from datetime import datetime
4 |
5 |
6 | class AuditObserver:
7 | def _parse_model(self, model, action):
8 | """Parse the model to get the table name and primary key.
9 | Args:
10 | model (masoniteorm.models.Model): model model.
11 | """
12 | new_value = model.__attributes__
13 | old_value = model.__original_attributes__
14 |
15 | for key in new_value:
16 | if isinstance(new_value.get(key), datetime):
17 | new_value[key] = new_value.get(key).to_datetime_string()
18 | if isinstance(old_value.get(key), datetime):
19 | old_value[key] = old_value.get(key).to_datetime_string()
20 |
21 | data = {
22 | "action": action,
23 | "model_id": model.id,
24 | "model_name": model.get_table_name(),
25 | "columns": json.dumps(model.get_columns()),
26 | "new_value": json.dumps(new_value),
27 | "old_value": json.dumps(old_value),
28 | }
29 |
30 | AuditLog.create(data)
31 |
32 | def created(self, model):
33 | """Handle the model "created" event.
34 | Args:
35 | model (masoniteorm.models.Model): model model.
36 | """
37 | self._parse_model(model, "CREATED")
38 |
39 | def saved(self, model):
40 | """Handle the model "saved" event.
41 | Args:
42 | model (masoniteorm.models.Model): model model.
43 | """
44 | self._parse_model(model, "SAVED")
45 |
46 | def updated(self, model):
47 | """Handle the model "updated" event.
48 | Args:
49 | model (masoniteorm.models.Model): model model.
50 | """
51 | self._parse_model(model, "UPDATED")
52 |
53 | def deleted(self, model):
54 | """Handle the model "deleted" event.
55 | Args:
56 | model (masoniteorm.models.Model): model model.
57 | """
58 | self._parse_model(model, "DELETED")
59 |
--------------------------------------------------------------------------------
/src/masonite_audit/providers/AuditProvider.py:
--------------------------------------------------------------------------------
1 | """A AuditProvider Service Provider."""
2 |
3 | from masonite.packages import PackageProvider
4 |
5 | from ..masonite_audit import MasoniteAudit
6 |
7 |
8 | class AuditProvider(PackageProvider, MasoniteAudit):
9 | def configure(self):
10 | """Register objects into the Service Container."""
11 | (
12 | self.root("masonite_audit")
13 | .name("masonite-audit")
14 | .config("config/masonite_audit.py", publish=True)
15 | .migrations("migrations/create_audit_logs_table.py")
16 | )
17 |
18 | def register(self):
19 | super().register()
20 | self.observe()
21 |
22 | def boot(self):
23 | """Boots services required by the container."""
24 | pass
25 |
--------------------------------------------------------------------------------
/src/masonite_audit/providers/__init__.py:
--------------------------------------------------------------------------------
1 | # flake8: noqa: E501
2 | from .AuditProvider import AuditProvider
3 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-package/masonite-audit/f3243c2a6af99bd007293c3662c6eeb9418a01b2/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-audit/f3243c2a6af99bd007293c3662c6eeb9418a01b2/tests/integrations/app/__init__.py
--------------------------------------------------------------------------------
/tests/integrations/app/controllers/WelcomeController.py:
--------------------------------------------------------------------------------
1 | """A WelcomeController Module."""
2 | import random
3 | from masonite.views import View
4 | from masonite.controllers import Controller
5 |
6 | from tests.integrations.app.models.User import User
7 |
8 |
9 | class WelcomeController(Controller):
10 | """WelcomeController Controller Class."""
11 |
12 | def show(self, view: View):
13 | user = User.first()
14 | user.update({"name": f"John {random.randint(100, 900)}"})
15 | user.rollback()
16 | return user
17 |
18 | def test(self):
19 | user = User.first()
20 |
21 | return user
22 |
--------------------------------------------------------------------------------
/tests/integrations/app/controllers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-package/masonite-audit/f3243c2a6af99bd007293c3662c6eeb9418a01b2/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 = []
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 | from src.masonite_audit.mixins import Audit
6 |
7 |
8 | class User(Model, SoftDeletesMixin, Authenticates, Audit):
9 | """User Model."""
10 |
11 | __fillable__ = ["name", "email", "password"]
12 | __hidden__ = ["password"]
13 | __auth__ = "email"
14 |
--------------------------------------------------------------------------------
/tests/integrations/config/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-package/masonite-audit/f3243c2a6af99bd007293c3662c6eeb9418a01b2/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 | "host": "127.0.0.1",
21 | "driver": "mysql",
22 | "database": "masonite_permission",
23 | "user": "meyubaraj",
24 | "password": "MDB@123#go",
25 | "port": 3306,
26 | "prefix": "",
27 | "grammar": "mysql",
28 | "options": {
29 | "charset": "utf8mb4",
30 | },
31 | "log_queries": env("DB_LOG"),
32 | },
33 | "postgres": {
34 | "host": "127.0.0.1",
35 | "driver": "postgres",
36 | "database": "masonite_permission",
37 | "user": "meyubaraj",
38 | "password": "MDB@123#go",
39 | "port": 5432,
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 | "tests/integrations/storage/static": "static/",
18 | "tests/integrations/storage/compiled": "assets/",
19 | "tests/integrations/storage/public": "/",
20 | }
21 |
--------------------------------------------------------------------------------
/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/masonite-audit.py:
--------------------------------------------------------------------------------
1 | """Masonite Audit Settings"""
2 |
3 | """
4 | |--------------------------------------------------------------------------
5 | | A Heading of The Setting Being Set
6 | |--------------------------------------------------------------------------
7 | |
8 | | A quick description
9 | |
10 | """
11 |
--------------------------------------------------------------------------------
/tests/integrations/config/masonite_audit.py:
--------------------------------------------------------------------------------
1 | """Masonite Audit Settings"""
2 |
3 | """
4 | |--------------------------------------------------------------------------
5 | | A Heading of The Setting Being Set
6 | |--------------------------------------------------------------------------
7 | |
8 | | A quick description
9 | |
10 | """
11 |
--------------------------------------------------------------------------------
/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.masonite_audit.providers import AuditProvider
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 | AuditProvider,
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/migrations/2022_04_21_110158_create_audit_logs_table.py:
--------------------------------------------------------------------------------
1 | """CreateAuditLogsTable Migration."""
2 |
3 | from masoniteorm.migrations import Migration
4 |
5 |
6 | class CreateAuditLogsTable(Migration):
7 | def up(self):
8 | """
9 | Run the migrations.
10 | """
11 | with self.schema.create("audit_logs") as table:
12 | table.increments("id")
13 | table.integer("editor_id").unsigned().nullable()
14 | table.integer("model_id").unsigned()
15 | table.string("model_name")
16 | table.string("action")
17 | table.json("columns").default("{}")
18 | table.json("old_value").default("{}")
19 | table.json("new_value").default("{}")
20 | table.timestamps()
21 |
22 | def down(self):
23 | """
24 | Revert the migrations.
25 | """
26 | self.schema.drop("audit_logs")
27 |
--------------------------------------------------------------------------------
/tests/integrations/databases/seeds/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-package/masonite-audit/f3243c2a6af99bd007293c3662c6eeb9418a01b2/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("/test", "WelcomeController@test"),
6 | ]
7 |
--------------------------------------------------------------------------------
/tests/integrations/storage/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-package/masonite-audit/f3243c2a6af99bd007293c3662c6eeb9418a01b2/tests/integrations/storage/.gitignore
--------------------------------------------------------------------------------
/tests/integrations/storage/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-package/masonite-audit/f3243c2a6af99bd007293c3662c6eeb9418a01b2/tests/integrations/storage/public/favicon.ico
--------------------------------------------------------------------------------
/tests/integrations/storage/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-package/masonite-audit/f3243c2a6af99bd007293c3662c6eeb9418a01b2/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-audit/f3243c2a6af99bd007293c3662c6eeb9418a01b2/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 | {% block head %}
13 |
14 | {% endblock %}
15 |
16 |
17 |
18 | {% block content %}{% endblock %}
19 | {% block js %}
20 |
21 | {% endblock %}
22 |
23 |
24 |
--------------------------------------------------------------------------------
/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 |
31 | {% endblock %}
--------------------------------------------------------------------------------
/tests/unit/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-package/masonite-audit/f3243c2a6af99bd007293c3662c6eeb9418a01b2/tests/unit/__init__.py
--------------------------------------------------------------------------------
/tests/unit/test_audit.py:
--------------------------------------------------------------------------------
1 | from masonite.tests import TestCase
2 | from masoniteorm.query import QueryBuilder
3 | from tests.integrations.app.models.User import User
4 | from masonite.facades import Hash
5 |
6 |
7 | class TestAudit(TestCase):
8 | @classmethod
9 | def setUpClass(cls):
10 | QueryBuilder().table("audit_logs").truncate(True)
11 | QueryBuilder().table("users").truncate(True)
12 |
13 | def tearDown(self):
14 | super().tearDown()
15 | QueryBuilder().table("audit_logs").truncate(True)
16 | QueryBuilder().table("users").truncate(True)
17 |
18 | def test_audit_created(self):
19 | user = User.create(
20 | {
21 | "name": "Yubaraj",
22 | "email": "user@example.com",
23 | "password": Hash.make("secret"),
24 | "phone": "+123456789",
25 | }
26 | )
27 |
28 | self.assertDatabaseHas(
29 | "users",
30 | {
31 | "email": "user@example.com",
32 | },
33 | )
34 |
35 | self.assertDatabaseHas(
36 | "audit_logs",
37 | {
38 | "model_id": user.id,
39 | "model_name": "users",
40 | "action": "CREATED",
41 | },
42 | )
43 |
44 | def test_audit_history(self):
45 | user = User.create(
46 | {
47 | "name": "Yubaraj",
48 | "email": "user@example.com",
49 | "password": Hash.make("secret"),
50 | "phone": "+123456789",
51 | }
52 | )
53 |
54 | self.assertTrue(user.history().count() == 1)
55 |
56 | user.update({"name": "UB"})
57 |
58 | self.assertTrue(user.history().count() == 2)
59 |
60 | def test_audit_rollback(self):
61 | user = User.create(
62 | {
63 | "name": "Yubaraj",
64 | "email": "user@example.com",
65 | "password": Hash.make("secret"),
66 | "phone": "+123456789",
67 | }
68 | )
69 |
70 | self.assertDatabaseHas(
71 | "users",
72 | {
73 | "name": "Yubaraj",
74 | },
75 | )
76 |
77 | user.update({"name": "UB"})
78 |
79 | self.assertDatabaseHas(
80 | "users",
81 | {
82 | "name": "UB",
83 | },
84 | )
85 |
86 | user.rollback()
87 |
88 | self.assertDatabaseHas(
89 | "users",
90 | {
91 | "name": "Yubaraj",
92 | },
93 | )
94 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------