3 | Site administration 4 |
5 |8 | You don’t have permission to view or edit anything. 9 |
10 | 11 |26 |
This is is a test mail. 6 | It used the django template: {{ foo }}, {{ bar }}
7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /django_tools_project/django_tools_test_app/templates/mail_test.txt: -------------------------------------------------------------------------------- 1 | This is is a test mail. 2 | It used the django template: {{ foo }}, {{ bar }} 3 | -------------------------------------------------------------------------------- /django_tools_project/django_tools_test_app/templates/test_template.html: -------------------------------------------------------------------------------- 1 | Hello {{ foo }} ! 2 | -------------------------------------------------------------------------------- /django_tools_project/django_tools_test_app/views.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dynamic SITE ID unittests 3 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | 5 | :copyleft: 2012-2018 by the django-tools team, see AUTHORS for more details. 6 | :license: GNU GPL v3 or above, see LICENSE for more details. 7 | """ 8 | 9 | import json 10 | import logging 11 | 12 | from django.conf import settings 13 | from django.contrib import messages 14 | from django.contrib.sites.models import Site 15 | from django.http import HttpResponse, HttpResponseRedirect 16 | from django.views.decorators.cache import never_cache 17 | from django.views.generic import TemplateView 18 | 19 | # https://github.com/jedie/django-tools 20 | from django_tools.debug.delay import SessionDelay 21 | from django_tools.middlewares.ThreadLocal import get_current_request 22 | 23 | 24 | log = logging.getLogger(__name__) 25 | 26 | 27 | @never_cache 28 | def display_site(request): 29 | settings_id = settings.SITE_ID 30 | current_site = Site.objects.get_current() 31 | current_id = current_site.id 32 | 33 | txt = f"ID from settings: {settings_id!r} - id from get_current(): {current_id!r}" 34 | log.debug("display_site(): %s", txt) 35 | return HttpResponse(txt) 36 | 37 | 38 | class ExampleException(Exception): 39 | pass 40 | 41 | 42 | def raise_exception(request, msg=""): 43 | """ 44 | This view just raises an exception as a way to test middleware exception 45 | handling. 46 | """ 47 | raise ExampleException(msg) 48 | 49 | 50 | def get_current_get_parameters(request): 51 | """ 52 | Returns a JSON version of request.GET from the current request 53 | """ 54 | return HttpResponse(json.dumps(get_current_request().GET)) 55 | 56 | 57 | class TemplateDoesNotExists(TemplateView): 58 | template_name = "/template/does/not/exists.html" 59 | 60 | 61 | def create_message_normal_response(request, msg): 62 | messages.info(request, msg) 63 | return HttpResponse("django_tools_project.django_tools_test_app.views.create_message_normal_response") 64 | 65 | 66 | def create_message_redirect_response(request, msg): 67 | messages.info(request, msg) 68 | return HttpResponseRedirect("/create_message_redirect_response/") 69 | 70 | 71 | def delay_view(request): 72 | """ 73 | Used in django_tools_tests.test_debug_delay.SessionDelayTests 74 | """ 75 | SessionDelay(request, key="delay_view", only_debug=False).load(request, query_string="sec", default=5) 76 | 77 | SessionDelay(request, key="delay_view").sleep() 78 | 79 | return HttpResponse("django_tools_project.django_tools_test_app.views.delay_view") 80 | -------------------------------------------------------------------------------- /django_tools_project/middlewares.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from pathlib import Path 3 | 4 | from debug_toolbar.middleware import show_toolbar 5 | from django.conf import settings 6 | 7 | 8 | logger = logging.getLogger(__name__) 9 | 10 | 11 | def djdt_show(request): 12 | """ 13 | Determining whether the Django Debug Toolbar should show or not. 14 | """ 15 | if not settings.DEBUG: 16 | return False 17 | 18 | if Path('/.dockerenv').exists(): 19 | # We run in a docker container 20 | # skip the `request.META['REMOTE_ADDR'] in settings.INTERNAL_IPS` check. 21 | return True 22 | 23 | return show_toolbar(request) 24 | -------------------------------------------------------------------------------- /django_tools_project/settings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jedie/django-tools/62cac0dd5c0baf7728e091bd8ce17f04ed82cecd/django_tools_project/settings/__init__.py -------------------------------------------------------------------------------- /django_tools_project/settings/local.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa: E405 2 | 3 | """ 4 | Django settings for local development 5 | """ 6 | 7 | import os as __os 8 | import sys as __sys 9 | 10 | from django_tools_project.settings.prod import * # noqa 11 | 12 | 13 | # SECURITY WARNING: don't run with debug turned on in production! 14 | DEBUG = True 15 | 16 | 17 | # Serve static/media files for local development: 18 | SERVE_FILES = True 19 | 20 | 21 | # Disable caches: 22 | CACHES = {'default': {'BACKEND': 'django.core.cache.backends.dummy.DummyCache'}} 23 | 24 | # Required for the debug toolbar to be displayed: 25 | INTERNAL_IPS = ('127.0.0.1', '0.0.0.0', 'localhost') 26 | 27 | ALLOWED_HOSTS = INTERNAL_IPS 28 | 29 | DATABASES = { 30 | 'default': { 31 | 'ENGINE': 'django.db.backends.sqlite3', 32 | 'NAME': str(BASE_PATH / 'django_tools-database.sqlite3'), 33 | # https://docs.djangoproject.com/en/dev/ref/databases/#database-is-locked-errors 34 | 'timeout': 30, 35 | } 36 | } 37 | print(f'Use Database: {DATABASES["default"]["NAME"]!r}', file=__sys.stderr) 38 | 39 | # _____________________________________________________________________________ 40 | 41 | if __os.environ.get('AUTOLOGIN') != '0': 42 | # Auto login for dev. server: 43 | MIDDLEWARE = MIDDLEWARE.copy() 44 | MIDDLEWARE += ['django_tools.middlewares.local_auto_login.AlwaysLoggedInAsSuperUserMiddleware'] 45 | 46 | # _____________________________________________________________________________ 47 | # Manage Django Project 48 | 49 | INSTALLED_APPS.append('manage_django_project') 50 | 51 | # _____________________________________________________________________________ 52 | # Django-Debug-Toolbar 53 | 54 | 55 | INSTALLED_APPS.append('debug_toolbar') 56 | MIDDLEWARE.append('debug_toolbar.middleware.DebugToolbarMiddleware') 57 | 58 | DEBUG_TOOLBAR_PATCH_SETTINGS = True 59 | from debug_toolbar.settings import CONFIG_DEFAULTS as DEBUG_TOOLBAR_CONFIG # noqa 60 | 61 | 62 | # Disable some more panels that will slow down the page: 63 | DEBUG_TOOLBAR_CONFIG['DISABLE_PANELS'].add('debug_toolbar.panels.sql.SQLPanel') 64 | DEBUG_TOOLBAR_CONFIG['DISABLE_PANELS'].add('debug_toolbar.panels.cache.CachePanel') 65 | 66 | # don't load jquery from ajax.googleapis.com, just use django's version: 67 | DEBUG_TOOLBAR_CONFIG['JQUERY_URL'] = STATIC_URL + 'admin/js/vendor/jquery/jquery.min.js' 68 | 69 | DEBUG_TOOLBAR_CONFIG['SHOW_TEMPLATE_CONTEXT'] = True 70 | DEBUG_TOOLBAR_CONFIG['SHOW_COLLAPSED'] = True # Show toolbar collapsed by default. 71 | DEBUG_TOOLBAR_CONFIG['SHOW_TOOLBAR_CALLBACK'] = 'django_tools_project.middlewares.djdt_show' 72 | -------------------------------------------------------------------------------- /django_tools_project/settings/tests.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa: E405 2 | """ 3 | Settings used to run tests 4 | """ 5 | from django_tools_project.settings.prod import * # noqa 6 | 7 | 8 | ALLOWED_HOSTS = ['testserver'] 9 | 10 | 11 | # _____________________________________________________________________________ 12 | # Manage Django Project 13 | 14 | INSTALLED_APPS.append('manage_django_project') 15 | 16 | # _____________________________________________________________________________ 17 | 18 | 19 | DATABASES = { 20 | 'default': { 21 | 'ENGINE': 'django.db.backends.sqlite3', 22 | 'NAME': ':memory:', 23 | } 24 | } 25 | 26 | SECRET_KEY = 'No individual secret for tests ;)' 27 | 28 | DEBUG = True 29 | 30 | # Speedup tests by change the Password hasher: 31 | PASSWORD_HASHERS = ('django.contrib.auth.hashers.MD5PasswordHasher',) 32 | 33 | # _____________________________________________________________________________ 34 | 35 | # All tests should use django-override-storage! 36 | # Set root to not existing path, so that wrong tests will fail: 37 | STATIC_ROOT = '/not/exists/static/' 38 | MEDIA_ROOT = '/not/exists/media/' 39 | -------------------------------------------------------------------------------- /django_tools_project/templates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jedie/django-tools/62cac0dd5c0baf7728e091bd8ce17f04ed82cecd/django_tools_project/templates/.gitkeep -------------------------------------------------------------------------------- /django_tools_project/tests/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest.util 3 | from pathlib import Path 4 | 5 | from bx_py_utils.test_utils.deny_requests import deny_any_real_request 6 | from typeguard import install_import_hook 7 | 8 | 9 | # Check type annotations via typeguard in all tests: 10 | install_import_hook(packages=('django_tools', 'django_tools_project')) 11 | 12 | 13 | def pre_configure_tests() -> None: 14 | print(f'Configure unittests via "load_tests Protocol" from {Path(__file__).relative_to(Path.cwd())}') 15 | 16 | # Hacky way to display more "assert"-Context in failing tests: 17 | _MIN_MAX_DIFF = unittest.util._MAX_LENGTH - unittest.util._MIN_DIFF_LEN 18 | unittest.util._MAX_LENGTH = int(os.environ.get('UNITTEST_MAX_LENGTH', 600)) 19 | unittest.util._MIN_DIFF_LEN = unittest.util._MAX_LENGTH - _MIN_MAX_DIFF 20 | 21 | # Deny any request via docket/urllib3 because tests they should mock all requests: 22 | deny_any_real_request() 23 | 24 | 25 | def load_tests(loader, tests, pattern): 26 | """ 27 | Use unittest "load_tests Protocol" as a hook to setup test environment before running tests. 28 | https://docs.python.org/3/library/unittest.html#load-tests-protocol 29 | """ 30 | pre_configure_tests() 31 | return loader.discover(start_dir=Path(__file__).parent, pattern=pattern) 32 | -------------------------------------------------------------------------------- /django_tools_project/tests/test_ThreadLocal_middleware.py: -------------------------------------------------------------------------------- 1 | """ 2 | :copyleft: 2017-2019 by the django-tools team, see AUTHORS for more details. 3 | :license: GNU GPL v3 or above, see LICENSE for more details. 4 | """ 5 | 6 | import json 7 | 8 | from django.test import TestCase 9 | 10 | # https://github.com/jedie/django-tools 11 | from django_tools.middlewares.ThreadLocal import get_current_request 12 | from django_tools.unittest_utils.assertments import assert_pformat_equal 13 | from django_tools_project.django_tools_test_app.views import ExampleException 14 | 15 | 16 | class TestGetCurrentRequest(TestCase): 17 | def test_current_request_receives_current_request(self): 18 | response = self.client.get("/get_current_get_parameters/?") 19 | current_get_parameters = json.loads(response.content.decode("utf-8")) 20 | assert_pformat_equal(current_get_parameters, {}) 21 | response = self.client.get("/get_current_get_parameters/?foo=bar") 22 | current_get_parameters = json.loads(response.content.decode("utf-8")) 23 | assert_pformat_equal(current_get_parameters, {"foo": "bar"}) 24 | 25 | def test_current_request_is_cleared_after_request_is_finished(self): 26 | self.client.get("/get_current_get_parameters/") 27 | assert_pformat_equal(get_current_request(), None) 28 | 29 | def test_current_request_is_cleared_when_exception_is_raised(self): 30 | with self.assertRaises(ExampleException): 31 | self.client.get("/raise_exception/TestGetCurrentRequest/") 32 | assert_pformat_equal(get_current_request(), None) 33 | -------------------------------------------------------------------------------- /django_tools_project/tests/test_TracebackLogMiddleware.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | from django_tools_project.django_tools_test_app.views import ExampleException 4 | 5 | 6 | class TestTracebackLogMiddleware(TestCase): 7 | def test_exception_logging(self): 8 | with self.assertLogs(logger=None, level=None) as logs, self.assertRaises(ExampleException): 9 | self.client.get('/raise_exception/TestTracebackLogMiddleware/') 10 | 11 | output = '\n'.join([str(entry) for entry in logs.output]) 12 | 13 | assert 'Exception on url: /raise_exception/TestTracebackLogMiddleware/' in output 14 | assert 'Traceback (most recent call last):' in output 15 | assert 'django_tools_test_app/views.py' in output 16 | assert 'Exception: TestTracebackLogMiddleware' in output 17 | -------------------------------------------------------------------------------- /django_tools_project/tests/test_admin.py: -------------------------------------------------------------------------------- 1 | from bx_django_utils.test_utils.html_assertion import ( 2 | HtmlAssertionMixin, 3 | assert_html_response_snapshot, 4 | get_django_name_suffix, 5 | ) 6 | from django.contrib.auth.models import User 7 | from django.test import TestCase 8 | from model_bakery import baker 9 | 10 | 11 | class AdminAnonymousTests(HtmlAssertionMixin, TestCase): 12 | """ 13 | Anonymous will be redirected to the login page. 14 | """ 15 | 16 | def test_login(self): 17 | response = self.client.get('/admin/') 18 | self.assertRedirects(response, expected_url='/admin/login/?next=/admin/') 19 | 20 | 21 | class AdminLoggedinTests(HtmlAssertionMixin, TestCase): 22 | """ 23 | Some basics test with the django admin 24 | """ 25 | 26 | @classmethod 27 | def setUpTestData(cls): 28 | cls.superuser = baker.make(User, username='superuser', is_staff=True, is_active=True, is_superuser=True) 29 | cls.staffuser = baker.make(User, username='staff_test_user', is_staff=True, is_active=True, is_superuser=False) 30 | 31 | def test_staff_admin_index(self): 32 | self.client.force_login(self.staffuser) 33 | 34 | response = self.client.get("/admin/") 35 | self.assert_html_parts( 36 | response, 37 | parts=( 38 | "You don’t have permission to view or edit anything.
", 41 | ), 42 | ) 43 | self.assertTemplateUsed(response, template_name="admin/index.html") 44 | assert_html_response_snapshot(response, validate=False, name_suffix=get_django_name_suffix()) 45 | 46 | def test_superuser_admin_index(self): 47 | self.client.force_login(self.superuser) 48 | response = self.client.get("/admin/") 49 | self.assert_html_parts( 50 | response, 51 | parts=( 52 | "8 | You don’t have permission to view or edit anything. 9 |
10 | 11 |8 | You don’t have permission to view or edit anything. 9 |
10 | 11 |8 | You don’t have permission to view or edit anything. 9 |
10 | 11 |This is is a test mail. 78 | It used the django template: first, second
79 | 80 | 81 | 82 | 83 | 84 | """, 85 | ) 86 | assert_pformat_equal(html_email[1], "text/html") 87 | -------------------------------------------------------------------------------- /django_tools_project/tests/test_filesystem_browser.py: -------------------------------------------------------------------------------- 1 | """ 2 | :copyleft: 2017-2019 by the django-tools team, see AUTHORS for more details. 3 | :license: GNU GPL v3 or above, see LICENSE for more details. 4 | """ 5 | 6 | import os 7 | 8 | from django.http import Http404 9 | from django.test import SimpleTestCase 10 | from django.test.utils import override_settings 11 | 12 | # https://github.com/jedie/django-tools 13 | import django_tools 14 | from django_tools.filemanager.filesystem_browser import BaseFilesystemBrowser 15 | from django_tools.unittest_utils.assertments import assert_pformat_equal 16 | 17 | 18 | @override_settings(DEBUG=False) 19 | class TestFilesystemBrowser(SimpleTestCase): 20 | """ 21 | e.g.: 22 | https://en.wikipedia.org/wiki/Directory_traversal_attack 23 | """ 24 | 25 | BASE_PATH = os.path.abspath(os.path.dirname(django_tools.__file__)) 26 | 27 | def test_directory_traversal_attack1(self): 28 | try: 29 | BaseFilesystemBrowser(request=None, absolute_path=self.BASE_PATH, base_url="bar", rest_url="../") 30 | except Http404 as err: 31 | assert_pformat_equal(str(err), "Directory doesn't exist!") 32 | 33 | @override_settings(DEBUG=True) 34 | def test_debug_message(self): 35 | sub_path = os.path.normpath(os.path.join(self.BASE_PATH, "..")) 36 | try: 37 | BaseFilesystemBrowser(request=None, absolute_path=self.BASE_PATH, base_url="bar", rest_url="../") 38 | except Http404 as err: 39 | assert_pformat_equal( 40 | err.args[0].message, f"Directory '{sub_path}' is not in base path ('{self.BASE_PATH}')" 41 | ) 42 | 43 | def test_directory_traversal_attack_encodings(self): 44 | rest_urls = ( 45 | "/etc/passwd", 46 | "..", 47 | "../", 48 | "\\\\", 49 | # URI encoded directory traversal: 50 | "%2e%2e%2f", # ../ 51 | "%2e%2e/", # ../ 52 | "..%2f", # ../ 53 | "%2e%2e%5c", # ..\ 54 | # Unicode / UTF-8 encoded directory traversal: 55 | "..%c1%1c", # ../ 56 | "..%c0%af", # ..\ 57 | "%c0%ae%c0%ae%c1%1c", # %c0%ae -> . -> ../ 58 | "%c0%ae%c0%ae%c0%af", # %c0%ae -> . -> ..\ 59 | ) 60 | for rest_url in rest_urls: 61 | # print(rest_url) 62 | try: 63 | BaseFilesystemBrowser(request=None, absolute_path=self.BASE_PATH, base_url="bar", rest_url=rest_url) 64 | except Http404 as err: 65 | assert_pformat_equal(str(err), "Directory doesn't exist!") 66 | -------------------------------------------------------------------------------- /django_tools_project/tests/test_html_utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | :copyleft: 2017-2019 by the django-tools team, see AUTHORS for more details. 3 | :license: GNU GPL v3 or above, see LICENSE for more details. 4 | """ 5 | 6 | # https://github.com/jedie/django-tools 7 | from django_tools.unittest_utils.assertments import assert_pformat_equal 8 | from django_tools.unittest_utils.unittest_base import BaseUnittestCase 9 | from django_tools.utils.html_utils import html2text 10 | 11 | 12 | class TestHtmlUtils(BaseUnittestCase): 13 | def test_none(self): 14 | assert_pformat_equal(html2text(None), None) 15 | 16 | def test_empty(self): 17 | assert_pformat_equal(html2text(""), "") 18 | 19 | def test_text_only(self): 20 | assert_pformat_equal(html2text("foo"), "foo") 21 | 22 | def test_invalid_tags(self): 23 | assert_pformat_equal(html2text("