├── logs
└── .gitkeep
├── config
├── __init__.py
├── settings
│ ├── __init__.py
│ ├── test.py
│ ├── test_demo_app.py
│ ├── local.py
│ └── base.py
├── wsgi.py
└── urls.py
├── docs
├── _static
│ └── .gitkeep
├── licence.rst
├── demo.rst
├── authors.rst
├── running_tests.rst
├── acknowledgements.rst
├── example_outputs.rst
├── getting_started.rst
├── index.rst
├── Makefile
├── development.rst
├── make.bat
├── api_documentation.rst
├── conf.py
├── changelog.rst
├── celery.rst
└── events.rst
├── test_app
├── tests
│ ├── __init__.py
│ ├── celery
│ │ ├── __init__.py
│ │ ├── test_steps.py
│ │ └── test_receivers.py
│ └── middlewares
│ │ ├── __init__.py
│ │ ├── test_celery.py
│ │ └── test_request.py
├── migrations
│ └── __init__.py
├── __init__.py
└── apps.py
├── .gitattributes
├── MANIFEST.in
├── django_structlog_demo_project
├── home
│ ├── __init__.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── test_api_views.py
│ │ └── test_views.py
│ ├── api_views.py
│ └── views.py
├── users
│ ├── __init__.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── test_models.py
│ │ ├── test_adapters.py
│ │ ├── factories.py
│ │ ├── test_urls.py
│ │ ├── test_forms.py
│ │ └── test_views.py
│ ├── migrations
│ │ ├── __init__.py
│ │ └── 0001_initial.py
│ ├── apps.py
│ ├── models.py
│ ├── urls.py
│ ├── admin.py
│ ├── adapters.py
│ ├── forms.py
│ └── views.py
├── static
│ ├── fonts
│ │ └── .gitkeep
│ ├── sass
│ │ ├── custom_bootstrap_vars.scss
│ │ └── project.scss
│ ├── js
│ │ └── project.js
│ ├── images
│ │ └── favicons
│ │ │ └── favicon.ico
│ └── css
│ │ └── project.css
├── taskapp
│ ├── __init__.py
│ ├── tests
│ │ ├── __init__.py
│ │ └── test_celery.py
│ └── celery.py
├── templates
│ ├── pages
│ │ ├── about.html
│ │ └── home.html
│ ├── 404.html
│ ├── 403_csrf.html
│ ├── account
│ │ ├── base.html
│ │ ├── account_inactive.html
│ │ ├── password_reset_from_key_done.html
│ │ ├── signup_closed.html
│ │ ├── verification_sent.html
│ │ ├── password_set.html
│ │ ├── password_reset_done.html
│ │ ├── password_change.html
│ │ ├── logout.html
│ │ ├── signup.html
│ │ ├── verified_email_required.html
│ │ ├── password_reset.html
│ │ ├── password_reset_from_key.html
│ │ ├── email_confirm.html
│ │ ├── login.html
│ │ └── email.html
│ ├── 500.html
│ ├── users
│ │ ├── user_list.html
│ │ ├── user_form.html
│ │ └── user_detail.html
│ └── base.html
├── __init__.py
├── contrib
│ ├── __init__.py
│ └── sites
│ │ ├── __init__.py
│ │ └── migrations
│ │ ├── __init__.py
│ │ ├── 0002_alter_domain_unique.py
│ │ ├── 0003_set_site_domain_and_name.py
│ │ └── 0001_initial.py
└── conftest.py
├── requirements.txt
├── .dockerignore
├── pytest.ini
├── django_structlog
├── celery
│ ├── __init__.py
│ ├── signals.py
│ ├── middlewares.py
│ ├── steps.py
│ └── receivers.py
├── apps.py
├── middlewares
│ ├── __init__.py
│ └── request.py
├── __init__.py
└── signals.py
├── setup.cfg
├── requirements
├── doc.txt
├── ci.txt
└── local.txt
├── compose
└── local
│ ├── postgres
│ ├── maintenance
│ │ ├── _sourced
│ │ │ ├── constants.sh
│ │ │ ├── yes_no.sh
│ │ │ ├── countdown.sh
│ │ │ └── messages.sh
│ │ ├── backups
│ │ ├── backup
│ │ └── restore
│ └── Dockerfile
│ ├── django
│ ├── celery
│ │ ├── worker
│ │ │ └── start
│ │ ├── beat
│ │ │ └── start
│ │ └── flower
│ │ │ └── start
│ ├── start
│ ├── entrypoint
│ └── Dockerfile
│ └── docs
│ ├── Dockerfile
│ └── start
├── .idea
├── encodings.xml
├── vcs.xml
├── modules.xml
├── misc.xml
├── django-structlog.iml
└── inspectionProfiles
│ └── Project_Default.xml
├── .envs
└── .local
│ ├── .postgres
│ └── .django
├── .coveragerc
├── .pre-commit-config.yaml
├── pyproject.toml
├── docker-compose.docs.yml
├── tox.ini
├── LICENSE.rst
├── manage.py
├── setup.py
├── docker-compose.yml
├── .travis.yml
├── .gitignore
└── README.rst
/logs/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/config/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/_static/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/config/settings/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test_app/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/test_app/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test_app/tests/celery/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include LICENSE.rst
2 |
--------------------------------------------------------------------------------
/test_app/tests/middlewares/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/django_structlog_demo_project/home/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/django_structlog_demo_project/users/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | -r requirements/local.txt
2 |
--------------------------------------------------------------------------------
/django_structlog_demo_project/home/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/django_structlog_demo_project/static/fonts/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/django_structlog_demo_project/taskapp/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/django_structlog_demo_project/users/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/django_structlog_demo_project/taskapp/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/django_structlog_demo_project/users/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | .*
2 | !.coveragerc
3 | !.env
4 | !.pylintrc
5 |
--------------------------------------------------------------------------------
/django_structlog_demo_project/static/sass/custom_bootstrap_vars.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | DJANGO_SETTINGS_MODULE=config.settings.test
3 |
--------------------------------------------------------------------------------
/docs/licence.rst:
--------------------------------------------------------------------------------
1 | Licence
2 | =======
3 |
4 | .. include:: ../LICENSE.rst
5 |
--------------------------------------------------------------------------------
/test_app/__init__.py:
--------------------------------------------------------------------------------
1 | default_app_config = "test_app.apps.TestAppConfig"
2 |
--------------------------------------------------------------------------------
/django_structlog_demo_project/templates/pages/about.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
--------------------------------------------------------------------------------
/django_structlog/celery/__init__.py:
--------------------------------------------------------------------------------
1 | """ ``celery`` integration for ``django_structlog``.
2 | """
3 |
--------------------------------------------------------------------------------
/django_structlog_demo_project/static/js/project.js:
--------------------------------------------------------------------------------
1 | /* Project specific Javascript goes here. */
2 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [flake8]
2 | exclude = .tox,.git,docs,venv,build,.pytest_cache,.idea,logs
3 | ignore = E501
4 |
--------------------------------------------------------------------------------
/test_app/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class TestAppConfig(AppConfig):
5 | name = "test_app"
6 |
--------------------------------------------------------------------------------
/requirements/doc.txt:
--------------------------------------------------------------------------------
1 | sphinx<2
2 | sphinx_rtd_theme
3 | celery==4.3.0
4 | django>=2.2,<3
5 | structlog
6 | sphinx-autobuild>=0.7.1
7 |
--------------------------------------------------------------------------------
/docs/demo.rst:
--------------------------------------------------------------------------------
1 | .. include:: ../README.rst
2 | :start-after: inclusion-marker-demo-begin
3 | :end-before: inclusion-marker-demo-end
4 |
--------------------------------------------------------------------------------
/docs/authors.rst:
--------------------------------------------------------------------------------
1 | .. include:: ../README.rst
2 | :start-after: inclusion-marker-authors-begin
3 | :end-before: inclusion-marker-authors-end
4 |
--------------------------------------------------------------------------------
/compose/local/postgres/maintenance/_sourced/constants.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 |
4 | BACKUP_DIR_PATH='/backups'
5 | BACKUP_FILE_PREFIX='backup'
6 |
--------------------------------------------------------------------------------
/django_structlog/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class DjangoStructLogConfig(AppConfig):
5 | name = "django_structlog"
6 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
This is not the page you were looking for.
9 | {% endblock content %} 10 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [report] 2 | include = 3 | ./django_structlog/* 4 | ./django_structlog_demo_project/* 5 | ./test_app/* 6 | exclude_lines = 7 | pragma: no cover 8 | raise NotImplementedError 9 | 10 | fail_under = 100 11 | skip_covered = True 12 | show_missing = True -------------------------------------------------------------------------------- /django_structlog_demo_project/templates/403_csrf.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Forbidden (403){% endblock %} 4 | 5 | {% block content %} 6 |CSRF verification failed. Request aborted.
9 | {% endblock content %} 10 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/ambv/black 3 | rev: stable 4 | hooks: 5 | - id: black 6 | language_version: python3 7 | - repo: https://gitlab.com/pycqa/flake8 8 | rev: 3.7.8 9 | hooks: 10 | - id: flake8 11 | -------------------------------------------------------------------------------- /compose/local/django/celery/flower/start: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -o errexit 4 | set -o nounset 5 | 6 | 7 | celery flower \ 8 | --app=django_structlog_demo_project.taskapp \ 9 | --broker="${CELERY_BROKER_URL}" \ 10 | --basic_auth="${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}" 11 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 |{% trans "This account is inactive." %}
11 | {% endblock %} 12 | 13 | -------------------------------------------------------------------------------- /django_structlog_demo_project/templates/account/password_reset_from_key_done.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | 3 | {% load i18n %} 4 | {% block head_title %}{% trans "Change Password" %}{% endblock %} 5 | 6 | {% block inner %} 7 |{% trans 'Your password is now changed.' %}
9 | {% endblock %} 10 | 11 | -------------------------------------------------------------------------------- /django_structlog_demo_project/users/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class UsersAppConfig(AppConfig): 5 | 6 | name = "django_structlog_demo_project.users" 7 | verbose_name = "Users" 8 | 9 | def ready(self): 10 | try: 11 | import users.signals # noqa F401 12 | except ImportError: 13 | pass 14 | -------------------------------------------------------------------------------- /django_structlog_demo_project/templates/account/signup_closed.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block head_title %}{% trans "Sign Up Closed" %}{% endblock %} 6 | 7 | {% block inner %} 8 |{% trans "We are sorry, but the sign up is currently closed." %}
11 | {% endblock %} 12 | 13 | -------------------------------------------------------------------------------- /django_structlog_demo_project/home/api_views.py: -------------------------------------------------------------------------------- 1 | from rest_framework.decorators import api_view 2 | from rest_framework.response import Response 3 | import structlog 4 | 5 | logger = structlog.get_logger(__name__) 6 | 7 | 8 | @api_view() 9 | def home_api_view(request): 10 | logger.info("This is a rest-framework structured log") 11 | return Response({"message": "Hello, world!"}) 12 | -------------------------------------------------------------------------------- /compose/local/postgres/maintenance/_sourced/yes_no.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | yes_no() { 5 | declare desc="Prompt for confirmation. \$\"\{1\}\": confirmation message." 6 | local arg1="${1}" 7 | 8 | local response= 9 | read -r -p "${arg1} (y/[n])? " response 10 | if [[ "${response}" =~ ^[Yy]$ ]] 11 | then 12 | exit 0 13 | else 14 | exit 1 15 | fi 16 | } 17 | -------------------------------------------------------------------------------- /django_structlog_demo_project/templates/500.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Server Error{% endblock %} 4 | 5 | {% block content %} 6 |We track these errors automatically, but if the problem persists feel free to contact us. In the meantime, try refreshing.
11 | {% endblock content %} 12 | 13 | 14 | -------------------------------------------------------------------------------- /compose/local/postgres/maintenance/_sourced/countdown.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | countdown() { 5 | declare desc="A simple countdown. Source: https://superuser.com/a/611582" 6 | local seconds="${1}" 7 | local d=$(($(date +%s) + "${seconds}")) 8 | while [ "$d" -ge `date +%s` ]; do 9 | echo -ne "$(date -u --date @$(($d - `date +%s`)) +%H:%M:%S)\r"; 10 | sleep 0.1 11 | done 12 | } 13 | -------------------------------------------------------------------------------- /compose/local/docs/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7-alpine 2 | 3 | ENV PYTHONUNBUFFERED 1 4 | 5 | RUN apk update \ 6 | && apk add --virtual build-dependencies \ 7 | build-base 8 | 9 | WORKDIR /app 10 | 11 | # Requirements are installed here to ensure they will be cached. 12 | COPY ./requirements /requirements 13 | RUN pip install -r /requirements/doc.txt 14 | 15 | COPY ./compose/local/docs/start /start 16 | RUN sed -i 's/\r//' /start 17 | RUN chmod +x /start 18 | -------------------------------------------------------------------------------- /.envs/.local/.django: -------------------------------------------------------------------------------- 1 | # General 2 | # ------------------------------------------------------------------------------ 3 | USE_DOCKER=yes 4 | IPYTHONDIR=/app/.ipython 5 | # Redis 6 | # ------------------------------------------------------------------------------ 7 | REDIS_URL=redis://redis:6379/0 8 | 9 | # Celery 10 | # ------------------------------------------------------------------------------ 11 | 12 | # Flower 13 | CELERY_FLOWER_USER=debug 14 | CELERY_FLOWER_PASSWORD=debug 15 | 16 | -------------------------------------------------------------------------------- /django_structlog_demo_project/users/tests/test_adapters.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from django_structlog_demo_project.users.adapters import ( 4 | SocialAccountAdapter, 5 | AccountAdapter, 6 | ) 7 | 8 | pytestmark = pytest.mark.django_db 9 | 10 | 11 | class TestUserCreationForm: 12 | def test_account_adapter(self): 13 | assert AccountAdapter().is_open_for_signup(None) 14 | 15 | def test_social_account_adapter(self): 16 | assert SocialAccountAdapter().is_open_for_signup(None, None) 17 | -------------------------------------------------------------------------------- /django_structlog_demo_project/home/tests/test_api_views.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from .. import api_views 4 | 5 | pytestmark = pytest.mark.django_db 6 | 7 | 8 | class TestApiView: 9 | def test(self, caplog, request_factory): 10 | response = api_views.home_api_view(request_factory.get("/")) 11 | assert response.status_code == 200 12 | assert len(caplog.records) == 1 13 | record = caplog.records[0] 14 | assert record.msg["event"] == "This is a rest-framework structured log" 15 | -------------------------------------------------------------------------------- /compose/local/postgres/maintenance/backups: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | ### View backups. 5 | ### 6 | ### Usage: 7 | ### $ docker-compose -f{% blocktrans %}We have sent an e-mail to you for verification. Follow the link provided to finalize the signup process. Please contact us if you do not receive it within a few minutes.{% endblocktrans %}
11 | 12 | {% endblock %} 13 | 14 | -------------------------------------------------------------------------------- /django_structlog_demo_project/templates/users/user_list.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load static i18n %} 3 | {% block title %}Members{% endblock %} 4 | 5 | {% block content %} 6 |{% blocktrans %}We have sent you an e-mail. Please contact us if you do not receive it within a few minutes.{% endblocktrans %}
16 | {% endblock %} 17 | 18 | -------------------------------------------------------------------------------- /django_structlog_demo_project/templates/account/password_change.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | 3 | {% load i18n %} 4 | {% load crispy_forms_tags %} 5 | 6 | {% block head_title %}{% trans "Change Password" %}{% endblock %} 7 | 8 | {% block inner %} 9 |{% trans 'Are you sure you want to sign out?' %}
11 | 12 | 19 | 20 | 21 | {% endblock %} 22 | 23 | -------------------------------------------------------------------------------- /django_structlog_demo_project/contrib/sites/migrations/0002_alter_domain_unique.py: -------------------------------------------------------------------------------- 1 | import django.contrib.sites.models 2 | from django.db import migrations, models 3 | 4 | 5 | class Migration(migrations.Migration): 6 | 7 | dependencies = [("sites", "0001_initial")] 8 | 9 | operations = [ 10 | migrations.AlterField( 11 | model_name="site", 12 | name="domain", 13 | field=models.CharField( 14 | max_length=100, 15 | unique=True, 16 | validators=[django.contrib.sites.models._simple_domain_name_validator], 17 | verbose_name="domain name", 18 | ), 19 | ) 20 | ] 21 | -------------------------------------------------------------------------------- /compose/local/postgres/maintenance/_sourced/messages.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | message_newline() { 5 | echo 6 | } 7 | 8 | message_debug() 9 | { 10 | echo -e "DEBUG: ${@}" 11 | } 12 | 13 | message_welcome() 14 | { 15 | echo -e "\e[1m${@}\e[0m" 16 | } 17 | 18 | message_warning() 19 | { 20 | echo -e "\e[33mWARNING\e[0m: ${@}" 21 | } 22 | 23 | message_error() 24 | { 25 | echo -e "\e[31mERROR\e[0m: ${@}" 26 | } 27 | 28 | message_info() 29 | { 30 | echo -e "\e[37mINFO\e[0m: ${@}" 31 | } 32 | 33 | message_suggestion() 34 | { 35 | echo -e "\e[33mSUGGESTION\e[0m: ${@}" 36 | } 37 | 38 | message_success() 39 | { 40 | echo -e "\e[32mSUCCESS\e[0m: ${@}" 41 | } 42 | -------------------------------------------------------------------------------- /django_structlog_demo_project/users/adapters.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from allauth.account.adapter import DefaultAccountAdapter 4 | from allauth.socialaccount.adapter import DefaultSocialAccountAdapter 5 | from django.conf import settings 6 | from django.http import HttpRequest 7 | 8 | 9 | class AccountAdapter(DefaultAccountAdapter): 10 | def is_open_for_signup(self, request: HttpRequest): 11 | return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True) 12 | 13 | 14 | class SocialAccountAdapter(DefaultSocialAccountAdapter): 15 | def is_open_for_signup(self, request: HttpRequest, sociallogin: Any): 16 | return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True) 17 | -------------------------------------------------------------------------------- /docs/development.rst: -------------------------------------------------------------------------------- 1 | Development 2 | =========== 3 | 4 | Prerequisites 5 | ------------- 6 | 7 | - `docker{% blocktrans %}Already have an account? Then please sign in.{% endblocktrans %}
12 | 13 | 21 | 22 | {% endblock %} 23 | 24 | -------------------------------------------------------------------------------- /compose/local/docs/start: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -o errexit 4 | set -o pipefail 5 | set -o nounset 6 | 7 | # Basically we watch only README.rst, LICENCE.rst and everything under django_structlog 8 | sphinx-autobuild docs /docs/_build/html \ 9 | -b ${SPHINX_COMMAND} \ 10 | -p 5000 \ 11 | -H 0.0.0.0 \ 12 | --watch . \ 13 | --ignore "*___jb_*" \ 14 | --ignore ".*/*" \ 15 | --ignore ".*" \ 16 | --ignore "build/*" \ 17 | --ignore "compose/*" \ 18 | --ignore "config/*" \ 19 | --ignore "dist/*" \ 20 | --ignore "django_structlog.egg-info/*" \ 21 | --ignore "django_structlog_demo_project/*" \ 22 | --ignore "logs/*" \ 23 | --ignore "requirements/*" \ 24 | --ignore "requirements.txt" \ 25 | --ignore "docker*.yml" \ 26 | --ignore "manage.py" \ 27 | --ignore "MANIFEST.in" \ 28 | --ignore "*.toml" \ 29 | --ignore "setup.py" \ 30 | --ignore "*.log" \ 31 | --ignore "*.ini" 32 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | # Test against latest supported version of each of python 2 and 3 for 3 | # each Django version. 4 | # 5 | # Also, make sure that all python versions used here are included in .travis.yml 6 | envlist = 7 | py{35,36,37}-django111-celery43, 8 | py{35,36,37}-django2{0,1,2}-celery43, 9 | py{36,37,38}-django3{0}-celery44, 10 | 11 | [testenv] 12 | setenv = 13 | PYTHONPATH={toxinidir} 14 | CELERY_BROKER_URL=redis://0.0.0.0:6379 15 | DJANGO_SETTINGS_MODULE=config.settings.test 16 | deps = 17 | celery43: Celery >=4.3, <4.4 18 | celery44: Celery >=4.4, <4.5 19 | django111: Django >=1.11, <2.0 20 | django20: Django >=2.0, <2.1 21 | django21: Django >=2.1, <2.2 22 | django22: Django >=2.2, <2.3 23 | -r{toxinidir}/requirements/ci.txt 24 | 25 | commands = pytest --cov=./test_app --cov=./django_structlog --cov-append test_app 26 | -------------------------------------------------------------------------------- /django_structlog_demo_project/users/tests/factories.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Sequence 2 | 3 | from django.contrib.auth import get_user_model 4 | from factory import DjangoModelFactory, Faker, post_generation 5 | 6 | 7 | class UserFactory(DjangoModelFactory): 8 | 9 | username = Faker("user_name") 10 | email = Faker("email") 11 | name = Faker("name") 12 | 13 | @post_generation 14 | def password(self, create: bool, extracted: Sequence[Any], **kwargs): 15 | password = Faker( 16 | "password", 17 | length=42, 18 | special_chars=True, 19 | digits=True, 20 | upper_case=True, 21 | lower_case=True, 22 | ).generate(extra_kwargs={}) 23 | self.set_password(password) 24 | 25 | class Meta: 26 | model = get_user_model() 27 | django_get_or_create = ["username"] 28 | -------------------------------------------------------------------------------- /django_structlog_demo_project/home/tests/test_views.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from .. import views 4 | 5 | pytestmark = pytest.mark.django_db 6 | 7 | 8 | class TestEnqueueSuccessfulTask: 9 | def test(self): 10 | response = views.enqueue_successful_task(None) 11 | assert response.status_code == 201 12 | 13 | 14 | class TestEnqueueFailingTask: 15 | def test(self): 16 | response = views.enqueue_failing_task(None) 17 | assert response.status_code == 201 18 | 19 | 20 | class TestEnqueueNestingTask: 21 | def test(self): 22 | response = views.enqueue_nesting_task(None) 23 | assert response.status_code == 201 24 | 25 | 26 | class TestRaiseException: 27 | def test(self): 28 | with pytest.raises(Exception) as e: 29 | views.raise_exception(None) 30 | assert str(e.value) == "This is a view raising an exception." 31 | -------------------------------------------------------------------------------- /django_structlog_demo_project/contrib/sites/migrations/0003_set_site_domain_and_name.py: -------------------------------------------------------------------------------- 1 | """ 2 | To understand why this file is here, please read: 3 | 4 | http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django 5 | """ 6 | from django.conf import settings 7 | from django.db import migrations 8 | 9 | 10 | def update_site_forward(apps, schema_editor): 11 | """Set site domain and name.""" 12 | site_model = apps.get_model("sites", "Site") 13 | site_model.objects.update_or_create( 14 | id=settings.SITE_ID, 15 | defaults={"domain": "example.com", "name": "django_structlog_demo_project"}, 16 | ) 17 | 18 | 19 | class Migration(migrations.Migration): 20 | 21 | dependencies = [("sites", "0002_alter_domain_unique")] 22 | 23 | operations = [migrations.RunPython(update_site_forward, migrations.RunPython.noop)] 24 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /django_structlog_demo_project/home/views.py: -------------------------------------------------------------------------------- 1 | import structlog 2 | from django.http import HttpResponse 3 | from django_structlog_demo_project.taskapp.celery import ( 4 | successful_task, 5 | failing_task, 6 | nesting_task, 7 | ) 8 | 9 | logger = structlog.get_logger(__name__) 10 | 11 | 12 | def enqueue_successful_task(request): 13 | logger.info("Enqueuing successful task") 14 | successful_task.delay(foo="bar") 15 | return HttpResponse(status=201) 16 | 17 | 18 | def enqueue_failing_task(request): 19 | logger.info("Enqueuing failing task") 20 | failing_task.delay(foo="bar") 21 | return HttpResponse(status=201) 22 | 23 | 24 | def enqueue_nesting_task(request): 25 | logger.info("Enqueuing nesting task") 26 | nesting_task.delay() 27 | return HttpResponse(status=201) 28 | 29 | 30 | def raise_exception(request): 31 | raise Exception("This is a view raising an exception.") 32 | -------------------------------------------------------------------------------- /django_structlog/celery/middlewares.py: -------------------------------------------------------------------------------- 1 | from ..celery.receivers import receiver_before_task_publish, receiver_after_task_publish 2 | 3 | 4 | class CeleryMiddleware: 5 | """ 6 | ``CeleryMiddleware`` initializes ``celery`` signals to pass ``django``'s request information to ``celery`` worker's logger. 7 | 8 | >>> MIDDLEWARE = [ 9 | ... # ... 10 | ... 'django_structlog.middlewares.RequestMiddleware', 11 | ... 'django_structlog.middlewares.CeleryMiddleware', 12 | ... ] 13 | 14 | """ 15 | 16 | def __init__(self, get_response=None): 17 | self.get_response = get_response 18 | from celery.signals import before_task_publish, after_task_publish 19 | 20 | before_task_publish.connect(receiver_before_task_publish) 21 | after_task_publish.connect(receiver_after_task_publish) 22 | 23 | def __call__(self, request): 24 | return self.get_response(request) 25 | -------------------------------------------------------------------------------- /django_structlog_demo_project/users/tests/test_urls.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from django.conf import settings 3 | from django.urls import reverse, resolve 4 | 5 | pytestmark = pytest.mark.django_db 6 | 7 | 8 | def test_detail(user: settings.AUTH_USER_MODEL): 9 | route = "/users/{username}/".format(username=user.username) 10 | assert reverse("users:detail", kwargs={"username": user.username}) == route 11 | assert resolve(route).view_name == "users:detail" 12 | 13 | 14 | def test_list(): 15 | assert reverse("users:list") == "/users/" 16 | assert resolve("/users/").view_name == "users:list" 17 | 18 | 19 | def test_update(): 20 | assert reverse("users:update") == "/users/~update/" 21 | assert resolve("/users/~update/").view_name == "users:update" 22 | 23 | 24 | def test_redirect(): 25 | assert reverse("users:redirect") == "/users/~redirect/" 26 | assert resolve("/users/~redirect/").view_name == "users:redirect" 27 | -------------------------------------------------------------------------------- /django_structlog_demo_project/templates/account/verified_email_required.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block head_title %}{% trans "Verify Your E-mail Address" %}{% endblock %} 6 | 7 | {% block inner %} 8 |{% blocktrans %}This part of the site requires us to verify that 13 | you are who you claim to be. For this purpose, we require that you 14 | verify ownership of your e-mail address. {% endblocktrans %}
15 | 16 |{% blocktrans %}We have sent an e-mail to you for 17 | verification. Please click on the link inside this e-mail. Please 18 | contact us if you do not receive it within a few minutes.{% endblocktrans %}
19 | 20 |{% blocktrans %}Note: you can still change your e-mail address.{% endblocktrans %}
21 | 22 | 23 | {% endblock %} 24 | 25 | -------------------------------------------------------------------------------- /django_structlog_demo_project/templates/users/user_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load static %} 3 | 4 | {% block title %}User: {{ object.username }}{% endblock %} 5 | 6 | {% block content %} 7 |{{ object.name }}
15 | {% endif %} 16 |{% trans "Forgotten your password? Enter your e-mail address below, and we'll send you an e-mail allowing you to reset it." %}
17 | 18 | 23 | 24 |{% blocktrans %}Please contact us if you have any trouble resetting your password.{% endblocktrans %}
25 | {% endblock %} 26 | 27 | -------------------------------------------------------------------------------- /docs/api_documentation.rst: -------------------------------------------------------------------------------- 1 | API documentation 2 | ================= 3 | 4 | django_structlog 5 | ^^^^^^^^^^^^^^^^ 6 | 7 | .. automodule:: django_structlog 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | 12 | .. automodule:: django_structlog.middlewares 13 | :members: RequestMiddleware 14 | :undoc-members: 15 | :show-inheritance: 16 | 17 | .. automodule:: django_structlog.signals 18 | :members: bind_extra_request_metadata 19 | 20 | 21 | django_structlog.celery 22 | ^^^^^^^^^^^^^^^^^^^^^^^ 23 | 24 | .. automodule:: django_structlog.celery 25 | :members: 26 | :undoc-members: 27 | :show-inheritance: 28 | 29 | .. automodule:: django_structlog.celery.middlewares 30 | :members: CeleryMiddleware 31 | :undoc-members: 32 | :show-inheritance: 33 | 34 | .. automodule:: django_structlog.celery.steps 35 | :members: DjangoStructLogInitStep 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | .. automodule:: django_structlog.celery.signals 40 | :members: bind_extra_task_metadata 41 | -------------------------------------------------------------------------------- /.idea/django-structlog.iml: -------------------------------------------------------------------------------- 1 | 2 |{% blocktrans %}The password reset link was invalid, possibly because it has already been used. Please request a new password reset.{% endblocktrans %}
13 | {% else %} 14 | {% if form %} 15 | 20 | {% else %} 21 |{% trans 'Your password is now changed.' %}
22 | {% endif %} 23 | {% endif %} 24 | {% endblock %} 25 | 26 | -------------------------------------------------------------------------------- /compose/local/django/entrypoint: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -o errexit 4 | set -o pipefail 5 | set -o nounset 6 | 7 | 8 | 9 | # N.B. If only .env files supported variable expansion... 10 | export CELERY_BROKER_URL="${REDIS_URL}" 11 | 12 | 13 | if [ -z "${POSTGRES_USER}" ]; then 14 | base_postgres_image_default_user='postgres' 15 | export POSTGRES_USER="${base_postgres_image_default_user}" 16 | fi 17 | export DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}" 18 | 19 | postgres_ready() { 20 | python << END 21 | import sys 22 | 23 | import psycopg2 24 | 25 | try: 26 | psycopg2.connect( 27 | dbname="${POSTGRES_DB}", 28 | user="${POSTGRES_USER}", 29 | password="${POSTGRES_PASSWORD}", 30 | host="${POSTGRES_HOST}", 31 | port="${POSTGRES_PORT}", 32 | ) 33 | except psycopg2.OperationalError: 34 | sys.exit(-1) 35 | sys.exit(0) 36 | 37 | END 38 | } 39 | until postgres_ready; do 40 | >&2 echo 'Waiting for PostgreSQL to become available...' 41 | sleep 1 42 | done 43 | >&2 echo 'PostgreSQL is available' 44 | 45 | exec "$@" 46 | -------------------------------------------------------------------------------- /django_structlog_demo_project/taskapp/tests/test_celery.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from .. import celery 4 | 5 | pytestmark = pytest.mark.django_db 6 | 7 | 8 | class TestSuccessfulTask: 9 | def test(self, caplog): 10 | celery.successful_task(foo="bar") 11 | assert len(caplog.records) == 1 12 | record = caplog.records[0] 13 | assert record.msg["event"] == "This is a successful task" 14 | 15 | 16 | class TestFailingTask: 17 | def test(self): 18 | with pytest.raises(Exception) as e: 19 | celery.failing_task(foo="bar") 20 | assert str(e.value) == "This is a failed task" 21 | 22 | 23 | class TestNestingTask: 24 | def test(self, caplog): 25 | celery.nesting_task() 26 | assert len(caplog.records) == 1 27 | record = caplog.records[0] 28 | assert record.msg["event"] == "This is a nesting task" 29 | 30 | 31 | class TestNestedTask: 32 | def test(self, caplog): 33 | celery.nested_task() 34 | assert len(caplog.records) == 1 35 | record = caplog.records[0] 36 | assert record.msg["event"] == "This is a nested task" 37 | -------------------------------------------------------------------------------- /django_structlog_demo_project/templates/account/email_confirm.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | 3 | {% load i18n %} 4 | {% load account %} 5 | 6 | {% block head_title %}{% trans "Confirm E-mail Address" %}{% endblock %} 7 | 8 | 9 | {% block inner %} 10 |{% blocktrans with confirmation.email_address.email as email %}Please confirm that {{ email }} is an e-mail address for user {{ user_display }}.{% endblocktrans %}
17 | 18 | 22 | 23 | {% else %} 24 | 25 | {% url 'account_email' as email_url %} 26 | 27 |{% blocktrans %}This e-mail confirmation link expired or is invalid. Please issue a new e-mail confirmation request.{% endblocktrans %}
28 | 29 | {% endif %} 30 | 31 | {% endblock %} 32 | 33 | -------------------------------------------------------------------------------- /test_app/tests/middlewares/test_celery.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import Mock, patch, call 2 | from django.test import TestCase 3 | 4 | from django_structlog import middlewares 5 | 6 | 7 | class TestCeleryMiddleware(TestCase): 8 | def test_call(self): 9 | from celery.signals import before_task_publish, after_task_publish 10 | from django_structlog.celery.receivers import ( 11 | receiver_before_task_publish, 12 | receiver_after_task_publish, 13 | ) 14 | 15 | mock_get_response = Mock() 16 | mock_request = Mock() 17 | with patch( 18 | "celery.utils.dispatch.signal.Signal.connect", autospec=True 19 | ) as mock_connect: 20 | middleware = middlewares.CeleryMiddleware(mock_get_response) 21 | 22 | middleware(mock_request) 23 | mock_get_response.assert_called_once_with(mock_request) 24 | 25 | mock_connect.assert_has_calls( 26 | [ 27 | call(before_task_publish, receiver_before_task_publish), 28 | call(after_task_publish, receiver_after_task_publish), 29 | ] 30 | ) 31 | -------------------------------------------------------------------------------- /LICENSE.rst: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Jules Robichaud-Gagnon 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 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local") 7 | 8 | try: 9 | from django.core.management import execute_from_command_line 10 | except ImportError: 11 | # The above import may fail for some other reason. Ensure that the 12 | # issue is really that Django is missing to avoid masking other 13 | # exceptions on Python 2. 14 | try: 15 | import django # noqa 16 | except ImportError: 17 | raise ImportError( 18 | "Couldn't import Django. Are you sure it's installed and " 19 | "available on your PYTHONPATH environment variable? Did you " 20 | "forget to activate a virtual environment?" 21 | ) 22 | 23 | raise 24 | 25 | # This allows easy placement of apps within the interior 26 | # django_structlog_demo_project directory. 27 | current_path = os.path.dirname(os.path.abspath(__file__)) 28 | sys.path.append(os.path.join(current_path, "django_structlog_demo_project")) 29 | 30 | execute_from_command_line(sys.argv) 31 | -------------------------------------------------------------------------------- /compose/local/postgres/maintenance/backup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | ### Create a database backup. 5 | ### 6 | ### Usage: 7 | ### $ docker-compose -f{% blocktrans with site.name as site_name %}Please sign in with one 17 | of your existing third party accounts. Or, sign up 18 | for a {{ site_name }} account and sign in below:{% endblocktrans %}
19 | 20 | 29 | 30 | {% include "socialaccount/snippets/login_extra.html" %} 31 | 32 | {% else %} 33 |{% blocktrans %}If you have not created an account yet, then please 34 | sign up first.{% endblocktrans %}
35 | {% endif %} 36 | 37 | 46 | 47 | {% endblock %} 48 | 49 | -------------------------------------------------------------------------------- /compose/local/postgres/maintenance/restore: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | ### Restore database from a backup. 5 | ### 6 | ### Parameters: 7 | ### <1> filename of an existing backup. 8 | ### 9 | ### Usage: 10 | ### $ docker-compose -f{% trans 'The following e-mail addresses are associated with your account:' %}
14 | 15 | 44 | 45 | {% else %} 46 |{% trans 'Warning:'%} {% trans "You currently do not have any e-mail address set up. You should really add an e-mail address so you can receive notifications, reset your password, etc." %}
47 | 48 | {% endif %} 49 | 50 | 51 |Use this document as a way to quick start any new project.
87 | {% endblock content %} 88 | 89 |