From 5bc3a54e71b6d7dc7e253df57191fef126f0d97d Mon Sep 17 00:00:00 2001 From: Klaas van Schelven Date: Thu, 16 May 2024 10:09:55 +0200 Subject: [PATCH] Documentation Driven Development: getting started guide excluding static files --- bugsink/app_settings.py | 2 +- bugsink/conf_templates/default.py.template | 64 +++++++++++++++++ bugsink/conf_templates/local.py.template | 61 ++++++++++++++++ ...{create_example_conf.py => create_conf.py} | 71 ++++--------------- bugsink/settings/default.py | 4 ++ bugsink/wsgi.py | 2 +- docs/tutorials/local-install.md | 10 ++- pyproject.toml | 2 +- 8 files changed, 154 insertions(+), 62 deletions(-) create mode 100644 bugsink/conf_templates/default.py.template create mode 100644 bugsink/conf_templates/local.py.template rename bugsink/scripts/{create_example_conf.py => create_conf.py} (56%) diff --git a/bugsink/app_settings.py b/bugsink/app_settings.py index 967ea86..3baa0a9 100644 --- a/bugsink/app_settings.py +++ b/bugsink/app_settings.py @@ -11,7 +11,7 @@ _MEBIBYTE = 1024 * _KIBIBYTE DEFAULTS = { - "BASE_URL": "http://bugsink:9000", # no trailing slash + "BASE_URL": "http://127.0.0.1:9000", # no trailing slash "SITE_TITLE": "Bugsink", # you can customize this as e.g. "My Bugsink" or "Bugsink for My Company" "DIGEST_IMMEDIATELY": True, diff --git a/bugsink/conf_templates/default.py.template b/bugsink/conf_templates/default.py.template new file mode 100644 index 0000000..28933bb --- /dev/null +++ b/bugsink/conf_templates/default.py.template @@ -0,0 +1,64 @@ +# Generated using bugsink-create-conf --template=default + +from bugsink.settings.default import * # noqa + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = "{{ secret_key }}" + +# Alternatively, pass the SECRET_KEY as an environment variable. (although that has security implications too, i.e. +# those may leak in shared server setups) +# +# SECRET_KEY = os.environ["SECRET_KEY"] # use dictionary lookup rather than .getenv to ensure the variable is set. + + +# Replacing "*" with your actual hostname forms an extra layer of security if your proxy/webserver is misconfigured. +# Doing so is recommended in production. +ALLOWED_HOSTS = ["*"] + + +# Configure the paths to the database. If you do not set these, the databases will be created in the current directory. +# (in production, being explicit about a full path is _strongly_ recommended) + +# DATABASES["default"]["NAME"] = 'db.sqlite3' +# DATABASES["default"]["TEST"]["NAME"] = 'test.sqlite3' +# DATABASES["snappea"]["NAME"] = 'snappea.sqlite3' + + +# The time-zone here is the default for display purposes (when no project/user configuration is used). +# You can change this at any time since datetime information is stored as UTC in the database. +# https://docs.djangoproject.com/en/4.2/ref/settings/#std-setting-TIME_ZONE +TIME_ZONE = 'UTC' # alternatively, e.g. 'Europe/Amsterdam' + + +# See TODO in the docs +SNAPPEA = { + "TASK_ALWAYS_EAGER": False, + "NUM_WORKERS": 1, +} + + +# See TODO in docs +# +# EMAIL_HOST = ... +# EMAIL_HOST_USER = ... +# EMAIL_HOST_PASSWORD = ... +# EMAIL_PORT = ... +# EMAIL_USE_TLS = ... + +SERVER_EMAIL = DEFAULT_FROM_EMAIL = "Bugsink " + +BUGSINK = { + # The URL where the Bugsink instance is hosted. This is used in the email notifications and to construct DSNs. + "BASE_URL": "http://127.0.0.1:{{ port }}", # no trailing slash + + # you can customize this as e.g. "My Bugsink" or "Bugsink for My Company" + # "SITE_TITLE": "Bugsink", + + # See TODO in the docs + # "DIGEST_IMMEDIATELY": False, + + # "MAX_EVENT_SIZE": _MEBIBYTE, + # "MAX_EVENT_COMPRESSED_SIZE": 200 * _KIBIBYTE, + # "MAX_ENVELOPE_SIZE": 100 * _MEBIBYTE, + # "MAX_ENVELOPE_COMPRESSED_SIZE": 20 * _MEBIBYTE, +} diff --git a/bugsink/conf_templates/local.py.template b/bugsink/conf_templates/local.py.template new file mode 100644 index 0000000..650bb26 --- /dev/null +++ b/bugsink/conf_templates/local.py.template @@ -0,0 +1,61 @@ +# Generated using bugsink-create-conf --template=local +# +# This is the default configuration when running Bugsink for local development. (i.e. using Bugsink to support the +# software development of other programs on your local machine, _not_ to develop Bugsink itself locally). +# +# SECURITY WARNING: this file should not be used in production; for production, use a configuration file generated by +# bugsink-create-conf --template=default + +from bugsink.settings.default import * # noqa + +SECRET_KEY = "{{ secret_key }}" + + +# Configure the paths to the database. If you do not set these, the databases will be created in the current directory. + +# DATABASES["default"]["NAME"] = 'db.sqlite3' +# DATABASES["default"]["TEST"]["NAME"] = 'test.sqlite3' +# DATABASES["snappea"]["NAME"] = 'snappea.sqlite3' + + +# The time-zone here is the default for display purposes (when no project/user configuration is used). +# You can change this at any time since datetime information is stored as UTC in the database. +# https://docs.djangoproject.com/en/4.2/ref/settings/#std-setting-TIME_ZONE +TIME_ZONE = 'UTC' # alternatively, e.g. 'Europe/Amsterdam' + + +# See TODO in the docs +# When running locally, it is recommended to configure SNAPPEA to always run eagerly, i.e. to run tasks synchronously. +# This avoids the need to run a separate "snappea server" process to run the workers, and the performance impact is +# negligible for local development. +SNAPPEA = { + "TASK_ALWAYS_EAGER": True, +} + + +# See TODO in docs +# When running locally, it is recommended to configure the email backend to use the console backend, which prints the +# email to the console instead of sending it. The assumption is basically that you don't want to send emails to yourself +# while developing locally, because the errors that you do trigger will already obvious. +# +EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' +# EMAIL_HOST = ... +# EMAIL_HOST_USER = ... +# EMAIL_HOST_PASSWORD = ... +# EMAIL_PORT = ... +# EMAIL_USE_TLS = ... +# SERVER_EMAIL = DEFAULT_FROM_EMAIL = "Bugsink " + +BUGSINK = { + # The URL where the Bugsink instance is hosted. This is used in the email notifications and to construct DSNs. + "BASE_URL": "http://127.0.0.1:{{ port }}", # no trailing slash + + # you can customize this as e.g. "My Bugsink" or "Bugsink for My Company" + # "SITE_TITLE": "Bugsink", + + # See TODO in the docs + # When running locally, it is recommended to configure the Bugsink to digest events immediately. (This is basically + # implied by the "TASK_ALWAYS_EAGER" setting above, but setting DIGEST_IMMEDIATELY to True removes one more step + # from the process.) + "DIGEST_IMMEDIATELY": True, +} diff --git a/bugsink/scripts/create_example_conf.py b/bugsink/scripts/create_conf.py similarity index 56% rename from bugsink/scripts/create_example_conf.py rename to bugsink/scripts/create_conf.py index c70816c..26456e3 100644 --- a/bugsink/scripts/create_example_conf.py +++ b/bugsink/scripts/create_conf.py @@ -1,13 +1,17 @@ import argparse import os import sys +from pathlib import Path from django.core.management.utils import get_random_secret_key def main(): - parser = argparse.ArgumentParser(description="Create a configuration file for the example") + parser = argparse.ArgumentParser(description="Create a configuration file.") parser.add_argument("--output-file", "-o", help="Output file", default="bugsink_conf.py") + parser.add_argument( + "--template", help="Template to use; default or local", choices=["default", "local"], default="default") + parser.add_argument("--port", help="Port to use in SITE_TITLE ; default is 9000", type=int, default=9000) args = parser.parse_args() if os.path.exists(args.output_file): @@ -15,63 +19,18 @@ def main(): sys.exit(1) secret_key = get_random_secret_key() + port = str(args.port) + + conf_template_dir = Path(__file__).resolve().parent.parent / "conf_templates" + with open(conf_template_dir / (args.template + ".py.template"), "r") as f: + template = f.read() + + body = template.\ + replace("{{ secret_key }}", secret_key). \ + replace("{{ port }}", port) with open(args.output_file, "w") as f: - f.write('''from bugsink.settings.default import * # noqa - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "''' + secret_key + '''" - -# Alternatively, pass the SECRET_KEY as an environment variable. (although that has security implications too!) -# i.e. those may leak in shared server setups. -# -# SECRET_KEY = os.environ["SECRET_KEY"] # use dictionary lookup rather than .getenv to ensure the variable is set. - - -ALLOWED_HOSTS = ["bugsink.example.org"] # set this to match your host (TODO: check what happens in forwarded configs?) - - -# Configure the paths to the database. If you do not set these, the databases will be created in the current directory. -# (being explicit about a full path is _strongly_ recommended) - -# DATABASES["default"]["NAME"] = 'db.sqlite3' -# DATABASES["default"]["TEST"]["NAME"] = 'test.sqlite3' -# DATABASES["snappea"]["NAME"] = 'snappea.sqlite3' - - -# The time-zone here is the default for display purposes (when no project/user configuration is used). -# https://docs.djangoproject.com/en/4.2/ref/settings/#std-setting-TIME_ZONE -TIME_ZONE = 'Europe/Amsterdam' - - -# See TODO in the docs -SNAPPEA = { - "TASK_ALWAYS_EAGER": True, - "NUM_WORKERS": 1, -} - - -# EMAIL_HOST = ... -# EMAIL_HOST_USER = ... -# EMAIL_HOST_PASSWORD = ... -# EMAIL_PORT = ... -# EMAIL_USE_TLS = ... - -SERVER_EMAIL = DEFAULT_FROM_EMAIL = "Bugsink " - -BUGSINK = { - # See TODO in the docs - # "DIGEST_IMMEDIATELY": False, - - # "MAX_EVENT_SIZE": _MEBIBYTE, - # "MAX_EVENT_COMPRESSED_SIZE": 200 * _KIBIBYTE, - # "MAX_ENVELOPE_SIZE": 100 * _MEBIBYTE, - # "MAX_ENVELOPE_COMPRESSED_SIZE": 20 * _MEBIBYTE, - - # "BASE_URL": "http://bugsink:9000", # no trailing slash - # "SITE_TITLE": "Bugsink", # you can customize this as e.g. "My Bugsink" or "Bugsink for My Company" -} -''') + f.write(body) print("Configuration file created at", args.output_file) print("Edit this file to match your setup") diff --git a/bugsink/settings/default.py b/bugsink/settings/default.py index a500830..423f108 100644 --- a/bugsink/settings/default.py +++ b/bugsink/settings/default.py @@ -34,6 +34,10 @@ SECRET_KEY = os.getenv("SECRET_KEY", "") DEBUG = False +# Replacing "*" with your actual hostname forms an extra layer of security if your proxy/webserver is misconfigured. +# The default (production) create-conf template adds a line for ALLOWED_HOSTS to point this out. +ALLOWED_HOSTS = ["*"] + INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', diff --git a/bugsink/wsgi.py b/bugsink/wsgi.py index d8dddc8..ca2b7bc 100644 --- a/bugsink/wsgi.py +++ b/bugsink/wsgi.py @@ -11,6 +11,6 @@ import os from django.core.wsgi import get_wsgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'bugsink.settings') +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'bugsink_conf') application = get_wsgi_application() diff --git a/docs/tutorials/local-install.md b/docs/tutorials/local-install.md index b82b29f..4326ab3 100644 --- a/docs/tutorials/local-install.md +++ b/docs/tutorials/local-install.md @@ -52,7 +52,7 @@ in your shell prompt. You can install Bugsink using `pip`: ```bash -pip install bugsink +python -m pip install bugsink ``` You should see output indicating that Bugsink and its dependencies are being @@ -71,7 +71,7 @@ You can create a configuration file that's suitable for local development by running: ```bash -bugsink-create-conf --local-development --port=9000 +bugsink-create-conf --template=local --port=9000 ``` This will create a file `bugsink_conf.py` in the current directory. You may @@ -89,7 +89,11 @@ bugsink-manage migrate ``` This will create a new SQLite database in the current directory and set up the -necessary tables. +necessary tables. You may verify the presence of the databse by running + +```bash +ls db.sqlite3 +``` ## Create a superuser diff --git a/pyproject.toml b/pyproject.toml index 9cacc7c..e0f14dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ dynamic = ["version", "dependencies"] [project.scripts] bugsink-show-version = "bugsink.scripts.show_version:main" bugsink-manage = "bugsink.scripts.manage:main" -bugsink-create-example-conf = "bugsink.scripts.create_example_conf:main" +bugsink-create-conf = "bugsink.scripts.create_conf:main" [tool.setuptools] include-package-data = true # this is the default, but explicit is better than implicit