├── .flake8 ├── .github └── workflows │ └── main.yml ├── .gitignore ├── AUTHORS ├── LICENSE ├── MANIFEST.in ├── README.md ├── demo ├── README.md ├── demo │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── manage.py ├── poetry.lock ├── pyproject.toml └── templates │ └── default_urlconf.html ├── django_spam ├── __init__.py ├── apps.py ├── enums.py ├── urls.py └── utils.py ├── poetry.lock ├── pyproject.toml ├── runtests.py ├── setup.py └── tests ├── __init__.py ├── settings.py ├── test_enums.py ├── test_spam.py ├── test_utils.py └── urls.py /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length=110 3 | ignore=F403,F405,W605,W503,E203,E231 4 | exclude=setup.py,__init__.py,.eggs,runtests.py 5 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: lint and test 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - develop 8 | 9 | jobs: 10 | lint-and-test: 11 | runs-on: ubuntu-18.04 12 | strategy: 13 | # By default, GitHub will maximize the number of jobs run in parallel 14 | # depending on the available runners on GitHub-hosted virtual machines. 15 | # max-parallel: 8 16 | fail-fast: false 17 | matrix: 18 | python-version: 19 | - "3.4" 20 | - "3.5" 21 | - "3.6" 22 | - "3.7" 23 | - "3.8" 24 | - "3.9" 25 | django-version: 26 | - "2.0" 27 | - "2.1" 28 | - "2.2" # LTS 29 | - "3.0" 30 | - "3.1" 31 | - "3.2" # LTS 32 | exclude: 33 | # Python 3.4 is not compatible with Django 2.0+ 34 | - python-version: "3.4" 35 | django-version: "2.1" 36 | - python-version: "3.4" 37 | django-version: "2.2" 38 | - python-version: "3.4" 39 | django-version: "3.0" 40 | - python-version: "3.4" 41 | django-version: "3.1" 42 | - python-version: "3.4" 43 | django-version: "3.2" 44 | # Python 3.5 is not compatible with Django 2.2+ 45 | - python-version: "3.5" 46 | django-version: "3.0" 47 | - python-version: "3.5" 48 | django-version: "3.1" 49 | - python-version: "3.5" 50 | django-version: "3.2" 51 | # Python 3.8 is compatible with Django 2.2+ 52 | - python-version: "3.8" 53 | django-version: "2.0" 54 | - python-version: "3.8" 55 | django-version: "2.1" 56 | # Python 3.9 is compatible with Django 3.1+ 57 | - python-version: "3.9" 58 | django-version: "2.0" 59 | - python-version: "3.9" 60 | django-version: "2.1" 61 | - python-version: "3.9" 62 | django-version: "2.2" 63 | - python-version: "3.9" 64 | django-version: "3.0" 65 | 66 | steps: 67 | - uses: actions/checkout@v2 68 | 69 | - name: Set up Python ${{ matrix.python-version }} 70 | uses: actions/setup-python@v2 71 | with: 72 | python-version: ${{ matrix.python-version }} 73 | 74 | - name: Upgrade pip version 75 | run: | 76 | python -m pip install -U pip 77 | 78 | - name: Upgrade django version 79 | run: | 80 | python -m pip install "Django~=${{ matrix.django-version }}.0" 81 | 82 | - name: Python and Django versions 83 | run: | 84 | echo "Python ${{ matrix.python-version }} -> Django ${{ matrix.django-version }}" 85 | python --version 86 | echo "Django: `django-admin --version`" 87 | 88 | - name: run tests 89 | run: | 90 | python -m pip install coverage 91 | coverage run --source=django_spam setup.py test 92 | coverage report 93 | coverage xml -o coverage.xml 94 | 95 | - name: Codecov 96 | if: success() 97 | uses: codecov/codecov-action@v2 98 | with: 99 | file: coverage.xml 100 | flags: unittests 101 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | .coverage 5 | 6 | # Distribution / packaging 7 | .Python 8 | env/ 9 | bin/ 10 | build/ 11 | develop-eggs/ 12 | dist/ 13 | *eggs/ 14 | lib/ 15 | lib64/ 16 | parts/ 17 | sdist/ 18 | var/ 19 | *.egg-info/ 20 | .installed.cfg 21 | *.egg 22 | demo/django_spam 23 | .vscode 24 | *.sqlite3 25 | 26 | # Installer logs 27 | pip-log.txt 28 | pip-delete-this-directory.txt 29 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | http://github.com/Tivix/django-spam/contributors 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Tivix, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS 2 | include LICENSE 3 | include MANIFEST.in 4 | include README.md 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | django-spam 2 | =========== 3 | 4 |

5 | Build Status 6 | Actions Status 7 | Release Status 8 |

9 | 10 |

11 | spam 12 |

13 | 14 | Inspired by this Nick Craver tweet https://twitter.com/nick_craver/status/720062942960623616 15 | 16 | We all hate bots, lets admit it. Especially the ones that try to gain access to our most secret endpoints. Well we have an easy 17 | solution for your django application. django_spam simply adds common admin urls to url conf so when bots (or human 18 | for that matter) try and access them, they will get redirected... 19 | 20 | 21 | | | Django 2.0 | Django 2.1 | Django 2.2 | Django 3.0 | Django 3.1 | Django 3.2 | 22 | | -- | -- | -- | -- | -- | -- | -- | 23 | | Python 3.4 | :heavy_check_mark: | | | | | | 24 | | Python 3.5 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | | | 25 | | Python 3.6 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | 26 | | Python 3.7 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | 27 | | Python 3.8 | | | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | 28 | | Python 3.9 | | | | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | 29 | 30 | 31 | ## Installation / Usage 32 | ```python 33 | pip install django-spam 34 | ``` 35 | 36 | Add to apps list: 37 | ```python 38 | INSTALLED_APPS = [ 39 | '...', 40 | 'django_spam', 41 | '...' 42 | ] 43 | ``` 44 | 45 | django_spam ships with some default endpoints bots might try to hit. If you would like to add extra routes, simply add 46 | a ``SPAM_ROUTES`` variable to your settings file that contains a list of extra endpoints you would like 47 | to add. *no leading slashes* 48 | ```python 49 | SPAM_ROUTES = [ 50 | 'admin.php', 51 | 'admin/login.php', 52 | 'administrator/index.php', 53 | 'index.php', 54 | '...', 55 | ] 56 | ``` 57 | 58 | Include ``django_spam.urls`` to root url file: 59 | ```python 60 | 61 | '...' 62 | path('', include('django_spam.urls')), 63 | '...', 64 | ``` 65 | 66 | If for some odd reason you need to exclude routes, define ``EXCLUDED_ROUTES`` in settings. *no leading slashes* 67 | 68 | ```python 69 | EXCLUDED_ROUTES = [ 70 | 'admin.php', 71 | 'index.php' 72 | ] 73 | ``` 74 | 75 | ## Demo 76 | See [here](demo/README.md) 77 | 78 | ## Development 79 | This project uses [Poetry](https://python-poetry.org/docs/#osx--linux--bashonwindows-install-instructions) to manage dev environment. Once installed: 80 | 1. Clone and `cd` into repo 81 | 2. install packages with `poetry install` 82 | 3. black `poetry run black .` 83 | 4. flake8 `poetry run flake8` 84 | 5. test `poetry run coverage run --source=django_spam setup.py test` 85 | -------------------------------------------------------------------------------- /demo/README.md: -------------------------------------------------------------------------------- 1 | ## Demo using django-spam 2 | 3 | This demo is provided as a convenience feature to allow potential users to try the app straight from the app repo without having to create a django project. 4 | 5 | It can also be used to develop the app in place. 6 | 7 | To run this example, follow these instructions: 8 | 9 | 1. Navigate to the `demo` directory 10 | 11 | 2. Install required packages with Poetry. 12 | 13 | poetry install 14 | 15 | 3. Make and apply migrations 16 | 17 | poetry run python manage.py makemigrations 18 | 19 | poetry run python manage.py migrate 20 | 21 | 4. Run the server 22 | 23 | poetry run python manage.py runserver 24 | 25 | 5. Access from the browser at `http://127.0.0.1:8000` to view homepage 26 | 27 | 6. Visit a `SPAM_ROUTES` eg `http://127.0.0.1:8000/admin/login.asp` 28 | -------------------------------------------------------------------------------- /demo/demo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tivix/django-spam/c975de8777b3c8c08e63cbaeef7b84af00f10620/demo/demo/__init__.py -------------------------------------------------------------------------------- /demo/demo/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for demo project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.11.8. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.11/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = "demo-key" 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | "django.contrib.admin", 35 | "django.contrib.auth", 36 | "django.contrib.contenttypes", 37 | "django.contrib.sessions", 38 | "django.contrib.messages", 39 | "django.contrib.staticfiles", 40 | "django_spam", 41 | ] 42 | 43 | MIDDLEWARE = [ 44 | "django.middleware.security.SecurityMiddleware", 45 | "django.contrib.sessions.middleware.SessionMiddleware", 46 | "django.middleware.common.CommonMiddleware", 47 | "django.middleware.csrf.CsrfViewMiddleware", 48 | "django.contrib.auth.middleware.AuthenticationMiddleware", 49 | "django.contrib.messages.middleware.MessageMiddleware", 50 | "django.middleware.clickjacking.XFrameOptionsMiddleware", 51 | ] 52 | 53 | ROOT_URLCONF = "demo.urls" 54 | 55 | TEMPLATES = [ 56 | { 57 | "BACKEND": "django.template.backends.django.DjangoTemplates", 58 | "DIRS": ["templates"], 59 | "APP_DIRS": True, 60 | "OPTIONS": { 61 | "context_processors": [ 62 | "django.template.context_processors.debug", 63 | "django.template.context_processors.request", 64 | "django.contrib.auth.context_processors.auth", 65 | "django.contrib.messages.context_processors.messages", 66 | ], 67 | }, 68 | }, 69 | ] 70 | 71 | WSGI_APPLICATION = "demo.wsgi.application" 72 | 73 | 74 | # Database 75 | # https://docs.djangoproject.com/en/1.11/ref/settings/#databases 76 | 77 | DATABASES = { 78 | "default": { 79 | "ENGINE": "django.db.backends.sqlite3", 80 | "NAME": os.path.join(BASE_DIR, "db.sqlite3"), 81 | } 82 | } 83 | 84 | 85 | # Internationalization 86 | # https://docs.djangoproject.com/en/1.11/topics/i18n/ 87 | 88 | LANGUAGE_CODE = "en-us" 89 | 90 | TIME_ZONE = "UTC" 91 | 92 | USE_I18N = True 93 | 94 | USE_L10N = True 95 | 96 | USE_TZ = True 97 | 98 | 99 | # Static files (CSS, JavaScript, Images) 100 | # https://docs.djangoproject.com/en/1.11/howto/static-files/ 101 | 102 | STATIC_URL = "/static/" 103 | -------------------------------------------------------------------------------- /demo/demo/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path, include 2 | from django.contrib import admin 3 | from django.views.generic import TemplateView 4 | 5 | 6 | urlpatterns = [ 7 | path("admin/", admin.site.urls), 8 | path("", TemplateView.as_view(template_name="default_urlconf.html")), 9 | path("", include("django_spam.urls")), 10 | ] 11 | -------------------------------------------------------------------------------- /demo/demo/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for demo project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /demo/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | 6 | if __name__ == "__main__": 7 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo.settings") 8 | 9 | from django.core.management import execute_from_command_line 10 | 11 | execute_from_command_line(sys.argv) 12 | -------------------------------------------------------------------------------- /demo/poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "asgiref" 3 | version = "3.4.1" 4 | description = "ASGI specs, helper code, and adapters" 5 | category = "main" 6 | optional = false 7 | python-versions = ">=3.6" 8 | 9 | [package.extras] 10 | tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"] 11 | 12 | [[package]] 13 | name = "django" 14 | version = "3.2.7" 15 | description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." 16 | category = "main" 17 | optional = false 18 | python-versions = ">=3.6" 19 | 20 | [package.dependencies] 21 | asgiref = ">=3.3.2,<4" 22 | pytz = "*" 23 | sqlparse = ">=0.2.2" 24 | 25 | [package.extras] 26 | argon2 = ["argon2-cffi (>=19.1.0)"] 27 | bcrypt = ["bcrypt"] 28 | 29 | [[package]] 30 | name = "django-spam" 31 | version = "1.0.0" 32 | description = "Django application that redirects spam bots to '10 hours of' videos" 33 | category = "main" 34 | optional = false 35 | python-versions = "^3.9" 36 | develop = true 37 | 38 | [package.source] 39 | type = "directory" 40 | url = ".." 41 | 42 | [[package]] 43 | name = "pytz" 44 | version = "2021.1" 45 | description = "World timezone definitions, modern and historical" 46 | category = "main" 47 | optional = false 48 | python-versions = "*" 49 | 50 | [[package]] 51 | name = "sqlparse" 52 | version = "0.4.2" 53 | description = "A non-validating SQL parser." 54 | category = "main" 55 | optional = false 56 | python-versions = ">=3.5" 57 | 58 | [metadata] 59 | lock-version = "1.1" 60 | python-versions = "3.9" 61 | content-hash = "3465f4fa47d1362bce3242be6e480ae22de47be7239ae7cb7670dd931b0f7006" 62 | 63 | [metadata.files] 64 | asgiref = [ 65 | {file = "asgiref-3.4.1-py3-none-any.whl", hash = "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"}, 66 | {file = "asgiref-3.4.1.tar.gz", hash = "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9"}, 67 | ] 68 | django = [ 69 | {file = "Django-3.2.7-py3-none-any.whl", hash = "sha256:e93c93565005b37ddebf2396b4dc4b6913c1838baa82efdfb79acedd5816c240"}, 70 | {file = "Django-3.2.7.tar.gz", hash = "sha256:95b318319d6997bac3595517101ad9cc83fe5672ac498ba48d1a410f47afecd2"}, 71 | ] 72 | django-spam = [] 73 | pytz = [ 74 | {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"}, 75 | {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"}, 76 | ] 77 | sqlparse = [ 78 | {file = "sqlparse-0.4.2-py3-none-any.whl", hash = "sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"}, 79 | {file = "sqlparse-0.4.2.tar.gz", hash = "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae"}, 80 | ] 81 | -------------------------------------------------------------------------------- /demo/pyproject.toml: -------------------------------------------------------------------------------- 1 | 2 | [tool.poetry] 3 | name = "django-spam demo" 4 | version = "1.0.0" 5 | description = "A demo using django-spam." 6 | authors = ["nick.kelly@tivix.com"] 7 | 8 | [tool.poetry.dependencies] 9 | python = "3.9" 10 | django = "^3.0" 11 | django_spam = { path = "../", develop = true} 12 | 13 | [tool.poetry.dev-dependencies] 14 | 15 | [build-system] 16 | requires = ["poetry>=0.12"] 17 | build-backend = "poetry.masonry.api" 18 | -------------------------------------------------------------------------------- /demo/templates/default_urlconf.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | {% get_current_language as LANGUAGE_CODE %}{% get_current_language_bidi as LANGUAGE_BIDI %} 4 | 5 | 6 | 7 | {% translate "The install worked successfully! Congratulations!" %} 8 | 9 | 10 | 201 | 202 | 203 |
204 | 207 |

{% blocktranslate %}View release notes for Django {{ version }}{% endblocktranslate %}

208 |
209 |
210 | 221 |

{% translate "The install worked successfully! Congratulations!" %}

222 |

{% blocktranslate %}You are seeing this page because DEBUG=True is in your settings file and you have not configured any URLs.{% endblocktranslate %}

223 |
224 | 253 | 254 | 255 | -------------------------------------------------------------------------------- /django_spam/__init__.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | 3 | from django_spam.enums import SPAM_ENUMS 4 | 5 | from django_spam.utils import Colour 6 | 7 | 8 | # common endpoints bots like (w/o leading slash) 9 | SPAM_ROUTES = [ 10 | # asp/x 11 | "admin.aspx", 12 | "admin.asp", 13 | "admin/account.html", 14 | "admin/login.asp", 15 | "admin_login.asp", 16 | "admin_login.aspx", 17 | "administartorlogin.aspx", 18 | "administrator_login.asp", 19 | "administrator_login.aspx", 20 | "login/administrator.aspx", 21 | "login/admin.asp", 22 | # php 23 | "admin.php", 24 | "admin/login.php", 25 | "admin_area/index.php", 26 | "administrator/index.php", 27 | "index.php", 28 | "siteadmin/index.php", 29 | "siteadmin/login.php", 30 | "wp-admin/admin-ajax.php", 31 | "wp-admin/post-new.php", 32 | "wp-admin/options-link.php", 33 | "wp-admin/includes/themes.php", 34 | "wp-login.php", 35 | # html 36 | "admin/account.html", 37 | "admin/admin.html", 38 | "admin/index.html", 39 | "admin/login.html", 40 | ] 41 | 42 | # '10 hours of'... 43 | SPAM_URLS = [spam for spam in SPAM_ENUMS] 44 | 45 | # check if any settings vars have been included to add to the 46 | # list of routes or urls 47 | if hasattr(settings, "SPAM_ROUTES"): 48 | SPAM_ROUTES += settings.SPAM_ROUTES 49 | 50 | 51 | # check for excluded routes 52 | if hasattr(settings, "EXCLUDED_ROUTES"): 53 | for route in settings.EXCLUDED_ROUTES: 54 | if route in SPAM_ROUTES: 55 | SPAM_ROUTES.remove(route) 56 | else: 57 | print( 58 | Colour.text( 59 | 'Warning: "' + route + '" is not included in django_spam.SPAM_ROUTES.', 60 | "warn", 61 | ) 62 | ) 63 | 64 | # NOTE: temp disbaling custom routes 65 | # if hasattr(settings, "SPAM_URLS"): 66 | # SPAM_URLS += settings.SPAM_URLS 67 | -------------------------------------------------------------------------------- /django_spam/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class DjangoSpamConfig(AppConfig): 5 | name = "django_spam" 6 | -------------------------------------------------------------------------------- /django_spam/enums.py: -------------------------------------------------------------------------------- 1 | class SpamBase: 2 | name = "" 3 | url = "" 4 | 5 | def __init__(self): 6 | raise NotImplementedError 7 | 8 | @classmethod 9 | def to_readable(cls) -> str: 10 | return cls.name.lower().replace(" ", "_") 11 | 12 | 13 | class VaderBreathing(SpamBase): 14 | name = "Darth Vader Breathing" 15 | url = "https://www.youtube.com/watch?v=un8FAjXWOBY" 16 | 17 | 18 | class Yodelling(SpamBase): 19 | name = "Yodelling" 20 | url = "https://www.youtube.com/watch?v=Lxt0_YrQs0M" 21 | 22 | 23 | class MulletGuy(SpamBase): 24 | name = "Whistling Mullet Guy" 25 | url = "https://www.youtube.com/watch?v=Sbhoym9yzVQ" 26 | 27 | 28 | class ScreamingGuy(SpamBase): 29 | name = "Screaming Guy" 30 | url = "https://www.youtube.com/watch?v=CRcYlE3i_-4" 31 | 32 | 33 | class FaceSong(SpamBase): 34 | name = "Awesome Face Song" 35 | url = "https://www.youtube.com/watch?v=WNeni1lbzgY" 36 | 37 | 38 | class ScreamingSheep(SpamBase): 39 | name = "Screaming Sheep" 40 | url = "https://www.youtube.com/watch?v=SjHUb7NSrNk" 41 | 42 | 43 | class SaxGuy(SpamBase): 44 | name = "Epic Sax Guy" 45 | url = "https://www.youtube.com/watch?v=kxopViU98Xo" 46 | 47 | 48 | class CrabRave(SpamBase): 49 | name = "Crab Rave" 50 | url = "https://www.youtube.com/watch?v=-50NdPawLVY" 51 | 52 | 53 | class WiiMusic(SpamBase): 54 | name = "Wii Theme Music" 55 | url = "https://www.youtube.com/watch?v=Twi92KYddW4" 56 | 57 | 58 | class NyonCat(SpamBase): 59 | name = "Nyon Cat" 60 | url = "https://www.youtube.com/watch?v=wZZ7oFKsKzY" 61 | 62 | 63 | class Asmr(SpamBase): 64 | name = "ASMR" 65 | url = "https://www.youtube.com/watch?v=jbAy9MwBR-I" 66 | 67 | 68 | class HeMan(SpamBase): 69 | name = "He-man Heyeayea" 70 | url = "https://www.youtube.com/watch?v=eh7lp9umG2I" 71 | 72 | 73 | SPAM_ENUMS = [ 74 | VaderBreathing, 75 | Yodelling, 76 | MulletGuy, 77 | ScreamingGuy, 78 | FaceSong, 79 | ScreamingSheep, 80 | SaxGuy, 81 | CrabRave, 82 | WiiMusic, 83 | NyonCat, 84 | Asmr, 85 | HeMan, 86 | ] 87 | -------------------------------------------------------------------------------- /django_spam/urls.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from django.urls import path 4 | from django.views.generic.base import RedirectView 5 | 6 | from django_spam import SPAM_ROUTES 7 | from django_spam import SPAM_ENUMS 8 | 9 | 10 | urlpatterns = list() 11 | 12 | for spam_route in SPAM_ROUTES: 13 | enum = random.choice(SPAM_ENUMS) 14 | urlpatterns.append( 15 | path( 16 | spam_route, 17 | RedirectView.as_view(url=enum.url), 18 | name=enum.to_readable(), 19 | ) 20 | ) 21 | -------------------------------------------------------------------------------- /django_spam/utils.py: -------------------------------------------------------------------------------- 1 | class Colour: 2 | """ 3 | Color output in terminal so warnings/errors stick out. 4 | """ 5 | 6 | HEADER = "\033[95m" 7 | OKBLUE = "\033[94m" 8 | OKGREEN = "\033[92m" 9 | WARNING = "\033[93m" 10 | FAIL = "\033[91m" 11 | ENDC = "\033[0m" 12 | BOLD = "\033[1m" 13 | UNDERLINE = "\033[4m" 14 | 15 | def __init__(self): 16 | raise NotImplementedError 17 | 18 | @classmethod 19 | def text(cls, txt: str, status: str = None) -> str: 20 | """colorize specific text 21 | 22 | :param txt: text printed to console 23 | :param status: the type of status depends on the color 24 | 25 | :return: colorized text string 26 | """ 27 | if status == "fail": 28 | return cls.FAIL + txt + cls.ENDC 29 | elif status == "ok": 30 | return cls.OKGREEN + txt + cls.ENDC 31 | elif status == "warn": 32 | return cls.WARNING + txt + cls.ENDC 33 | else: 34 | return txt 35 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "appdirs" 3 | version = "1.4.4" 4 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 5 | category = "dev" 6 | optional = false 7 | python-versions = "*" 8 | 9 | [[package]] 10 | name = "black" 11 | version = "20.8b1" 12 | description = "The uncompromising code formatter." 13 | category = "dev" 14 | optional = false 15 | python-versions = ">=3.6" 16 | 17 | [package.dependencies] 18 | appdirs = "*" 19 | click = ">=7.1.2" 20 | mypy-extensions = ">=0.4.3" 21 | pathspec = ">=0.6,<1" 22 | regex = ">=2020.1.8" 23 | toml = ">=0.10.1" 24 | typed-ast = ">=1.4.0" 25 | typing-extensions = ">=3.7.4" 26 | 27 | [package.extras] 28 | colorama = ["colorama (>=0.4.3)"] 29 | d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] 30 | 31 | [[package]] 32 | name = "click" 33 | version = "8.0.1" 34 | description = "Composable command line interface toolkit" 35 | category = "dev" 36 | optional = false 37 | python-versions = ">=3.6" 38 | 39 | [package.dependencies] 40 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 41 | 42 | [[package]] 43 | name = "colorama" 44 | version = "0.4.4" 45 | description = "Cross-platform colored terminal text." 46 | category = "dev" 47 | optional = false 48 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 49 | 50 | [[package]] 51 | name = "coverage" 52 | version = "5.5" 53 | description = "Code coverage measurement for Python" 54 | category = "dev" 55 | optional = false 56 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" 57 | 58 | [package.extras] 59 | toml = ["toml"] 60 | 61 | [[package]] 62 | name = "flake8" 63 | version = "3.9.2" 64 | description = "the modular source code checker: pep8 pyflakes and co" 65 | category = "dev" 66 | optional = false 67 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 68 | 69 | [package.dependencies] 70 | mccabe = ">=0.6.0,<0.7.0" 71 | pycodestyle = ">=2.7.0,<2.8.0" 72 | pyflakes = ">=2.3.0,<2.4.0" 73 | 74 | [[package]] 75 | name = "mccabe" 76 | version = "0.6.1" 77 | description = "McCabe checker, plugin for flake8" 78 | category = "dev" 79 | optional = false 80 | python-versions = "*" 81 | 82 | [[package]] 83 | name = "mypy-extensions" 84 | version = "0.4.3" 85 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 86 | category = "dev" 87 | optional = false 88 | python-versions = "*" 89 | 90 | [[package]] 91 | name = "pathspec" 92 | version = "0.9.0" 93 | description = "Utility library for gitignore style pattern matching of file paths." 94 | category = "dev" 95 | optional = false 96 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 97 | 98 | [[package]] 99 | name = "pycodestyle" 100 | version = "2.7.0" 101 | description = "Python style guide checker" 102 | category = "dev" 103 | optional = false 104 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 105 | 106 | [[package]] 107 | name = "pyflakes" 108 | version = "2.3.1" 109 | description = "passive checker of Python programs" 110 | category = "dev" 111 | optional = false 112 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 113 | 114 | [[package]] 115 | name = "regex" 116 | version = "2021.9.24" 117 | description = "Alternative regular expression module, to replace re." 118 | category = "dev" 119 | optional = false 120 | python-versions = "*" 121 | 122 | [[package]] 123 | name = "toml" 124 | version = "0.10.2" 125 | description = "Python Library for Tom's Obvious, Minimal Language" 126 | category = "dev" 127 | optional = false 128 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 129 | 130 | [[package]] 131 | name = "typed-ast" 132 | version = "1.4.3" 133 | description = "a fork of Python 2 and 3 ast modules with type comment support" 134 | category = "dev" 135 | optional = false 136 | python-versions = "*" 137 | 138 | [[package]] 139 | name = "typing-extensions" 140 | version = "3.10.0.2" 141 | description = "Backported and Experimental Type Hints for Python 3.5+" 142 | category = "dev" 143 | optional = false 144 | python-versions = "*" 145 | 146 | [metadata] 147 | lock-version = "1.1" 148 | python-versions = "^3.9" 149 | content-hash = "fbb03c7e4ae3cf6d930db3363a42815e9a414055c641b7bdf239375df60bad5d" 150 | 151 | [metadata.files] 152 | appdirs = [ 153 | {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, 154 | {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, 155 | ] 156 | black = [ 157 | {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, 158 | ] 159 | click = [ 160 | {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, 161 | {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"}, 162 | ] 163 | colorama = [ 164 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, 165 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, 166 | ] 167 | coverage = [ 168 | {file = "coverage-5.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf"}, 169 | {file = "coverage-5.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b"}, 170 | {file = "coverage-5.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669"}, 171 | {file = "coverage-5.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90"}, 172 | {file = "coverage-5.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c"}, 173 | {file = "coverage-5.5-cp27-cp27m-win32.whl", hash = "sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a"}, 174 | {file = "coverage-5.5-cp27-cp27m-win_amd64.whl", hash = "sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82"}, 175 | {file = "coverage-5.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905"}, 176 | {file = "coverage-5.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083"}, 177 | {file = "coverage-5.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5"}, 178 | {file = "coverage-5.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81"}, 179 | {file = "coverage-5.5-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6"}, 180 | {file = "coverage-5.5-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0"}, 181 | {file = "coverage-5.5-cp310-cp310-win_amd64.whl", hash = "sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae"}, 182 | {file = "coverage-5.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb"}, 183 | {file = "coverage-5.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160"}, 184 | {file = "coverage-5.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6"}, 185 | {file = "coverage-5.5-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701"}, 186 | {file = "coverage-5.5-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793"}, 187 | {file = "coverage-5.5-cp35-cp35m-win32.whl", hash = "sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e"}, 188 | {file = "coverage-5.5-cp35-cp35m-win_amd64.whl", hash = "sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3"}, 189 | {file = "coverage-5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066"}, 190 | {file = "coverage-5.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a"}, 191 | {file = "coverage-5.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465"}, 192 | {file = "coverage-5.5-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb"}, 193 | {file = "coverage-5.5-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821"}, 194 | {file = "coverage-5.5-cp36-cp36m-win32.whl", hash = "sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45"}, 195 | {file = "coverage-5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184"}, 196 | {file = "coverage-5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a"}, 197 | {file = "coverage-5.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53"}, 198 | {file = "coverage-5.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d"}, 199 | {file = "coverage-5.5-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638"}, 200 | {file = "coverage-5.5-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3"}, 201 | {file = "coverage-5.5-cp37-cp37m-win32.whl", hash = "sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a"}, 202 | {file = "coverage-5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a"}, 203 | {file = "coverage-5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6"}, 204 | {file = "coverage-5.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2"}, 205 | {file = "coverage-5.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759"}, 206 | {file = "coverage-5.5-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873"}, 207 | {file = "coverage-5.5-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a"}, 208 | {file = "coverage-5.5-cp38-cp38-win32.whl", hash = "sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6"}, 209 | {file = "coverage-5.5-cp38-cp38-win_amd64.whl", hash = "sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502"}, 210 | {file = "coverage-5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b"}, 211 | {file = "coverage-5.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529"}, 212 | {file = "coverage-5.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b"}, 213 | {file = "coverage-5.5-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff"}, 214 | {file = "coverage-5.5-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b"}, 215 | {file = "coverage-5.5-cp39-cp39-win32.whl", hash = "sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6"}, 216 | {file = "coverage-5.5-cp39-cp39-win_amd64.whl", hash = "sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03"}, 217 | {file = "coverage-5.5-pp36-none-any.whl", hash = "sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079"}, 218 | {file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"}, 219 | {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, 220 | ] 221 | flake8 = [ 222 | {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, 223 | {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, 224 | ] 225 | mccabe = [ 226 | {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, 227 | {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, 228 | ] 229 | mypy-extensions = [ 230 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 231 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 232 | ] 233 | pathspec = [ 234 | {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, 235 | {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, 236 | ] 237 | pycodestyle = [ 238 | {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, 239 | {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, 240 | ] 241 | pyflakes = [ 242 | {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, 243 | {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, 244 | ] 245 | regex = [ 246 | {file = "regex-2021.9.24-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0628ed7d6334e8f896f882a5c1240de8c4d9b0dd7c7fb8e9f4692f5684b7d656"}, 247 | {file = "regex-2021.9.24-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3baf3eaa41044d4ced2463fd5d23bf7bd4b03d68739c6c99a59ce1f95599a673"}, 248 | {file = "regex-2021.9.24-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c000635fd78400a558bd7a3c2981bb2a430005ebaa909d31e6e300719739a949"}, 249 | {file = "regex-2021.9.24-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:295bc8a13554a25ad31e44c4bedabd3c3e28bba027e4feeb9bb157647a2344a7"}, 250 | {file = "regex-2021.9.24-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0e3f59d3c772f2c3baaef2db425e6fc4149d35a052d874bb95ccfca10a1b9f4"}, 251 | {file = "regex-2021.9.24-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:aea4006b73b555fc5bdb650a8b92cf486d678afa168cf9b38402bb60bf0f9c18"}, 252 | {file = "regex-2021.9.24-cp310-cp310-win32.whl", hash = "sha256:09eb62654030f39f3ba46bc6726bea464069c29d00a9709e28c9ee9623a8da4a"}, 253 | {file = "regex-2021.9.24-cp310-cp310-win_amd64.whl", hash = "sha256:8d80087320632457aefc73f686f66139801959bf5b066b4419b92be85be3543c"}, 254 | {file = "regex-2021.9.24-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:7e3536f305f42ad6d31fc86636c54c7dafce8d634e56fef790fbacb59d499dd5"}, 255 | {file = "regex-2021.9.24-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c31f35a984caffb75f00a86852951a337540b44e4a22171354fb760cefa09346"}, 256 | {file = "regex-2021.9.24-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c7cb25adba814d5f419733fe565f3289d6fa629ab9e0b78f6dff5fa94ab0456"}, 257 | {file = "regex-2021.9.24-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:85c61bee5957e2d7be390392feac7e1d7abd3a49cbaed0c8cee1541b784c8561"}, 258 | {file = "regex-2021.9.24-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c94722bf403b8da744b7d0bb87e1f2529383003ceec92e754f768ef9323f69ad"}, 259 | {file = "regex-2021.9.24-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6adc1bd68f81968c9d249aab8c09cdc2cbe384bf2d2cb7f190f56875000cdc72"}, 260 | {file = "regex-2021.9.24-cp36-cp36m-win32.whl", hash = "sha256:2054dea683f1bda3a804fcfdb0c1c74821acb968093d0be16233873190d459e3"}, 261 | {file = "regex-2021.9.24-cp36-cp36m-win_amd64.whl", hash = "sha256:7783d89bd5413d183a38761fbc68279b984b9afcfbb39fa89d91f63763fbfb90"}, 262 | {file = "regex-2021.9.24-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b15dc34273aefe522df25096d5d087abc626e388a28a28ac75a4404bb7668736"}, 263 | {file = "regex-2021.9.24-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10a7a9cbe30bd90b7d9a1b4749ef20e13a3528e4215a2852be35784b6bd070f0"}, 264 | {file = "regex-2021.9.24-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb9f5844db480e2ef9fce3a72e71122dd010ab7b2920f777966ba25f7eb63819"}, 265 | {file = "regex-2021.9.24-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:17310b181902e0bb42b29c700e2c2346b8d81f26e900b1328f642e225c88bce1"}, 266 | {file = "regex-2021.9.24-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0bba1f6df4eafe79db2ecf38835c2626dbd47911e0516f6962c806f83e7a99ae"}, 267 | {file = "regex-2021.9.24-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:821e10b73e0898544807a0692a276e539e5bafe0a055506a6882814b6a02c3ec"}, 268 | {file = "regex-2021.9.24-cp37-cp37m-win32.whl", hash = "sha256:9c371dd326289d85906c27ec2bc1dcdedd9d0be12b543d16e37bad35754bde48"}, 269 | {file = "regex-2021.9.24-cp37-cp37m-win_amd64.whl", hash = "sha256:1e8d1898d4fb817120a5f684363b30108d7b0b46c7261264b100d14ec90a70e7"}, 270 | {file = "regex-2021.9.24-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8a5c2250c0a74428fd5507ae8853706fdde0f23bfb62ee1ec9418eeacf216078"}, 271 | {file = "regex-2021.9.24-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8aec4b4da165c4a64ea80443c16e49e3b15df0f56c124ac5f2f8708a65a0eddc"}, 272 | {file = "regex-2021.9.24-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:650c4f1fc4273f4e783e1d8e8b51a3e2311c2488ba0fcae6425b1e2c248a189d"}, 273 | {file = "regex-2021.9.24-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2cdb3789736f91d0b3333ac54d12a7e4f9efbc98f53cb905d3496259a893a8b3"}, 274 | {file = "regex-2021.9.24-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e61100200fa6ab7c99b61476f9f9653962ae71b931391d0264acfb4d9527d9c"}, 275 | {file = "regex-2021.9.24-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8c268e78d175798cd71d29114b0a1f1391c7d011995267d3b62319ec1a4ecaa1"}, 276 | {file = "regex-2021.9.24-cp38-cp38-win32.whl", hash = "sha256:658e3477676009083422042c4bac2bdad77b696e932a3de001c42cc046f8eda2"}, 277 | {file = "regex-2021.9.24-cp38-cp38-win_amd64.whl", hash = "sha256:a731552729ee8ae9c546fb1c651c97bf5f759018fdd40d0e9b4d129e1e3a44c8"}, 278 | {file = "regex-2021.9.24-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:86f9931eb92e521809d4b64ec8514f18faa8e11e97d6c2d1afa1bcf6c20a8eab"}, 279 | {file = "regex-2021.9.24-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcbbc9cfa147d55a577d285fd479b43103188855074552708df7acc31a476dd9"}, 280 | {file = "regex-2021.9.24-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29385c4dbb3f8b3a55ce13de6a97a3d21bd00de66acd7cdfc0b49cb2f08c906c"}, 281 | {file = "regex-2021.9.24-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c50a6379763c733562b1fee877372234d271e5c78cd13ade5f25978aa06744db"}, 282 | {file = "regex-2021.9.24-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f74b6d8f59f3cfb8237e25c532b11f794b96f5c89a6f4a25857d85f84fbef11"}, 283 | {file = "regex-2021.9.24-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c4d83d21d23dd854ffbc8154cf293f4e43ba630aa9bd2539c899343d7f59da3"}, 284 | {file = "regex-2021.9.24-cp39-cp39-win32.whl", hash = "sha256:95e89a8558c8c48626dcffdf9c8abac26b7c251d352688e7ab9baf351e1c7da6"}, 285 | {file = "regex-2021.9.24-cp39-cp39-win_amd64.whl", hash = "sha256:835962f432bce92dc9bf22903d46c50003c8d11b1dc64084c8fae63bca98564a"}, 286 | {file = "regex-2021.9.24.tar.gz", hash = "sha256:6266fde576e12357b25096351aac2b4b880b0066263e7bc7a9a1b4307991bb0e"}, 287 | ] 288 | toml = [ 289 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 290 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 291 | ] 292 | typed-ast = [ 293 | {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, 294 | {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"}, 295 | {file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"}, 296 | {file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"}, 297 | {file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"}, 298 | {file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"}, 299 | {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"}, 300 | {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"}, 301 | {file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"}, 302 | {file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"}, 303 | {file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"}, 304 | {file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"}, 305 | {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"}, 306 | {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"}, 307 | {file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"}, 308 | {file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"}, 309 | {file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"}, 310 | {file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"}, 311 | {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"}, 312 | {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"}, 313 | {file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"}, 314 | {file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"}, 315 | {file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"}, 316 | {file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"}, 317 | {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"}, 318 | {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"}, 319 | {file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"}, 320 | {file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"}, 321 | {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"}, 322 | {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, 323 | ] 324 | typing-extensions = [ 325 | {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, 326 | {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, 327 | {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, 328 | ] 329 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "django-spam" 3 | version = "2.0.1" 4 | description = "Django application that redirects spam bots to '10 hours of' videos" 5 | authors = ["Nick Kelly "] 6 | readme = "README.md" 7 | homepage = "https://github.com/Tivix/django-spam" 8 | repository = "https://github.com/Tivix/django-spam" 9 | 10 | [tool.poetry.dependencies] 11 | python = "^3.9" 12 | 13 | [tool.poetry.dev-dependencies] 14 | flake8 = "^3.9.2" 15 | black = "20.8b1" 16 | coverage = "^5.5" 17 | 18 | [tool.black] 19 | line-length = 110 20 | include = '\.pyi?$' 21 | exclude = ''' 22 | /( 23 | \.git 24 | | \.hg 25 | | \.mypy_cache 26 | | \.tox 27 | | \.venv 28 | | _build 29 | | build 30 | | dist 31 | )/ 32 | ''' 33 | 34 | [build-system] 35 | requires = ["poetry-core>=1.0.0"] 36 | build-backend = "poetry.core.masonry.api" 37 | -------------------------------------------------------------------------------- /runtests.py: -------------------------------------------------------------------------------- 1 | # This file mainly exists to allow python setup.py test to work. 2 | import os 3 | import sys 4 | 5 | os.environ["DJANGO_SETTINGS_MODULE"] = "tests.settings" 6 | test_dir = os.path.join(os.path.dirname(__file__), "tests") 7 | sys.path.insert(0, test_dir) 8 | 9 | import django 10 | from django.test.utils import get_runner 11 | from django.conf import settings 12 | 13 | 14 | def runtests(): 15 | TestRunner = get_runner(settings) 16 | test_runner = TestRunner(verbosity=1, interactive=True) 17 | if hasattr(django, "setup"): 18 | django.setup() 19 | failures = test_runner.run_tests(["tests"]) 20 | sys.exit(bool(failures)) 21 | 22 | 23 | if __name__ == "__main__": 24 | runtests() 25 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | try: 5 | from setuptools import setup, find_packages 6 | from setuptools.command.test import test 7 | except ImportError: 8 | from ez_setup import use_setuptools 9 | 10 | use_setuptools() 11 | from setuptools import setup, find_packages 12 | from setuptools.command.test import test 13 | 14 | 15 | import os 16 | 17 | 18 | here = os.path.dirname(os.path.abspath(__file__)) 19 | f = open(os.path.join(here, "README.md")) 20 | long_description = f.read().strip() 21 | f.close() 22 | 23 | setup( 24 | name="django_spam", 25 | version="2.0.1", 26 | author="Nick Kelly", 27 | author_email="nick.kelly@tivix.com", 28 | url="http://github.com/Tivix/django-spam", 29 | description="Redirecting bots to utilize their time better...", 30 | packages=find_packages(exclude=("tests*",)), 31 | long_description=long_description, 32 | long_description_content_type="text/markdown", 33 | keywords="django spam", 34 | zip_safe=False, 35 | include_package_data=True, 36 | py_modules=["django_spam"], 37 | test_suite="runtests.runtests", 38 | install_requires=[ 39 | "Django>=2.0.0", 40 | ], 41 | classifiers=[ 42 | "Framework :: Django", 43 | "Framework :: Django :: 2.0", 44 | "Framework :: Django :: 2.1", 45 | "Framework :: Django :: 2.2", 46 | "Framework :: Django :: 3.0", 47 | "Framework :: Django :: 3.1", 48 | "Intended Audience :: Developers", 49 | "Intended Audience :: System Administrators", 50 | "Operating System :: OS Independent", 51 | "Topic :: Software Development", 52 | ], 53 | ) 54 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tivix/django-spam/c975de8777b3c8c08e63cbaeef7b84af00f10620/tests/__init__.py -------------------------------------------------------------------------------- /tests/settings.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | 3 | INSTALLED_APPS = [ 4 | "django.contrib.auth", 5 | "django.contrib.contenttypes", 6 | "django.contrib.sessions", 7 | "django.contrib.sites", 8 | # 'tests', 9 | # 'django_spam' 10 | ] 11 | 12 | MIDDLEWARE_CLASSES = ( 13 | "django.contrib.sessions.middleware.SessionMiddleware", 14 | "django.middleware.common.CommonMiddleware", 15 | "django.middleware.csrf.CsrfViewMiddleware", 16 | "django.contrib.auth.middleware.AuthenticationMiddleware", 17 | "django.contrib.messages.middleware.MessageMiddleware", 18 | "django.middleware.clickjacking.XFrameOptionsMiddleware", 19 | ) 20 | 21 | SITE_ID = 1 22 | SECRET_KEY = "fake-key" 23 | 24 | ROOT_URLCONF = "tests.urls" 25 | 26 | SPAM_ROUTES = [ 27 | "testadmin.php", 28 | ] 29 | 30 | EXCLUDED_ROUTES = [ 31 | "index.php", 32 | ] 33 | 34 | DEBUG = True 35 | 36 | STATIC_URL = "/static/" 37 | 38 | DATABASES = { 39 | "default": { 40 | "ENGINE": "django.db.backends.sqlite3", 41 | "NAME": os.path.join(os.path.dirname(__file__), "database.db"), 42 | } 43 | } 44 | 45 | TEMPLATES = [ 46 | { 47 | "BACKEND": "django.template.backends.django.DjangoTemplates", 48 | "DIRS": [], 49 | "APP_DIRS": True, 50 | "OPTIONS": { 51 | "context_processors": [ 52 | "django.template.context_processors.debug", 53 | "django.template.context_processors.request", 54 | "django.contrib.auth.context_processors.auth", 55 | "django.contrib.messages.context_processors.messages", 56 | ], 57 | }, 58 | }, 59 | ] 60 | -------------------------------------------------------------------------------- /tests/test_enums.py: -------------------------------------------------------------------------------- 1 | from django_spam.enums import SpamBase 2 | 3 | from django.test import TestCase 4 | 5 | 6 | class DjangoSpamEnumsTestCase(TestCase): 7 | def test_not_implemented_error(self): 8 | with self.assertRaises(NotImplementedError): 9 | SpamBase() 10 | -------------------------------------------------------------------------------- /tests/test_spam.py: -------------------------------------------------------------------------------- 1 | import random 2 | import sys 3 | from io import StringIO 4 | from importlib import reload 5 | 6 | from django.conf import settings 7 | from django.test import TestCase, override_settings 8 | 9 | from django_spam import SPAM_ROUTES 10 | 11 | 12 | class DjangoSpamTestCase(TestCase): 13 | def test_redirect_random_route(self): 14 | response = self.client.get("/" + random.choice(SPAM_ROUTES)) 15 | self.assertEqual(response.status_code, 302) 16 | 17 | def test_add_spam_routes_in_settings(self): 18 | spam_routes = getattr(settings, "SPAM_ROUTES", []) 19 | response = self.client.get("/" + spam_routes[-1]) 20 | self.assertEqual(response.status_code, 302) 21 | 22 | def test_excluded_routes(self): 23 | excluded_routes = getattr(settings, "EXCLUDED_ROUTES", []) 24 | response = self.client.get("/" + excluded_routes[-1]) 25 | self.assertEqual(response.status_code, 200) 26 | 27 | @override_settings( 28 | EXCLUDED_ROUTES=[ 29 | "notinlist.html", 30 | ] 31 | ) 32 | def test_excluded_routes_contains_non_existent_spam_route(self): 33 | # create string object, redirect to stdout, reload package, then reset redirect 34 | capturedOutput = StringIO() 35 | sys.stdout = capturedOutput 36 | import django_spam 37 | 38 | reload(django_spam) 39 | sys.stdout = sys.__stdout__ 40 | 41 | captured_output = capturedOutput.getvalue() 42 | self.assertIn("Warning:", captured_output) and self.assertIn( 43 | "is not included in django_spam.SPAM_ROUTES.", captured_output 44 | ) 45 | -------------------------------------------------------------------------------- /tests/test_utils.py: -------------------------------------------------------------------------------- 1 | from django_spam.utils import Colour 2 | 3 | from django.test import TestCase 4 | 5 | 6 | class DjangoSpamUtilsTestCase(TestCase): 7 | """ 8 | We use assertIn due to unicode preceding and trailing text...for 9 | visual clarity. 10 | """ 11 | 12 | def test_fail_text(self): 13 | fail_text = Colour.text("Fail text.", "fail") 14 | self.assertIn("Fail text.", fail_text) 15 | 16 | def test_ok_text(self): 17 | ok_text = Colour.text("Ok text.", "ok") 18 | self.assertIn("Ok text.", ok_text) 19 | 20 | def test_warn_text(self): 21 | warn_text = Colour.text("Warn text.", "warn") 22 | self.assertIn("Warn text.", warn_text) 23 | 24 | def test_no_status_text(self): 25 | warn_text = Colour.text("Warn text.") # pylint: disable=no-value-for-parameter 26 | self.assertIn("Warn text.", warn_text) 27 | 28 | def test_not_implemented_error(self): 29 | with self.assertRaises(NotImplementedError): 30 | Colour() 31 | -------------------------------------------------------------------------------- /tests/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path, include 2 | from django.http import HttpResponse 3 | 4 | 5 | urlpatterns = [ 6 | path("", include("django_spam.urls")), 7 | path("index.php", lambda request: HttpResponse("Hello World!")), 8 | ] 9 | --------------------------------------------------------------------------------