From b96c131c92fd50b173450735f8677b47245c8d55 Mon Sep 17 00:00:00 2001 From: MerlinB Date: Fri, 28 Dec 2018 23:43:56 +0100 Subject: [PATCH] Initial project setup --- .coveragerc | 5 + .gitignore | 287 ++++++++++++++++++ .travis.yml | 19 ++ config/__init__.py | 0 config/settings/__init__.py | 0 config/settings/base.py | 220 ++++++++++++++ config/settings/local.py | 55 ++++ config/settings/production.py | 134 ++++++++ config/settings/test.py | 52 ++++ config/urls.py | 32 ++ config/wsgi.py | 21 ++ manage.py | 21 ++ mpicms/__init__.py | 0 mpicms/contrib/__init__.py | 5 + mpicms/contrib/sites/__init__.py | 5 + .../contrib/sites/migrations/0001_initial.py | 42 +++ .../migrations/0002_alter_domain_unique.py | 20 ++ .../0003_set_site_domain_and_name.py | 34 +++ mpicms/contrib/sites/migrations/__init__.py | 5 + pytest.ini | 2 + requirements/base.txt | 4 + requirements/local.txt | 21 ++ requirements/production.txt | 1 + setup.cfg | 7 + 24 files changed, 992 insertions(+) create mode 100644 .coveragerc create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 config/__init__.py create mode 100644 config/settings/__init__.py create mode 100644 config/settings/base.py create mode 100644 config/settings/local.py create mode 100644 config/settings/production.py create mode 100644 config/settings/test.py create mode 100644 config/urls.py create mode 100644 config/wsgi.py create mode 100755 manage.py create mode 100644 mpicms/__init__.py create mode 100644 mpicms/contrib/__init__.py create mode 100644 mpicms/contrib/sites/__init__.py create mode 100644 mpicms/contrib/sites/migrations/0001_initial.py create mode 100644 mpicms/contrib/sites/migrations/0002_alter_domain_unique.py create mode 100644 mpicms/contrib/sites/migrations/0003_set_site_domain_and_name.py create mode 100644 mpicms/contrib/sites/migrations/__init__.py create mode 100644 pytest.ini create mode 100644 requirements/base.txt create mode 100644 requirements/local.txt create mode 100644 requirements/production.txt create mode 100644 setup.cfg diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..d72b2c7 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,5 @@ +[run] +include = mpicms/* +omit = *migrations*, *tests* +plugins = + django_coverage_plugin diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f5b733 --- /dev/null +++ b/.gitignore @@ -0,0 +1,287 @@ +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +staticfiles/ + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# pyenv +.python-version + + + +# Environments +.venv +venv/ +ENV/ + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + + +### Node template +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Typescript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + + +### Linux template +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + + +### VisualStudioCode template +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + + + + + +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +### macOS template +# General +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + + +### SublimeText template +# Cache files for Sublime Text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# Workspace files are user-specific +*.sublime-workspace + +# Project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using Sublime Text +# *.sublime-project + +# SFTP configuration file +sftp-config.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + + +### Vim template +# Swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-v][a-z] +[._]sw[a-p] + +# Session +Session.vim + +# Temporary +.netrwhist + +# Auto-generated tag files +tags + + +### VirtualEnv template +# Virtualenv +# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ +[Bb]in +[Ii]nclude +[Ll]ib +[Ll]ib64 +[Ss]cripts +pyvenv.cfg +pip-selfcheck.json +.env + + +### Project template + +mpicms/media/ + +.pytest_cache/ + + diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..2673491 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,19 @@ +sudo: true +before_install: + - psql -c 'create database travis_ci_test;' -U postgres +language: python +services: + - postgresql +env: + - DJANGO_SETTINGS_MODULE=config.settings.test +install: + - pip install -r requirements/local.txt +script: + - coverage run manage.py test +after_success: + - coveralls +notifications: + email: + - merlin.buczek@gmail.com +python: + - "3.7" diff --git a/config/__init__.py b/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/config/settings/__init__.py b/config/settings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/config/settings/base.py b/config/settings/base.py new file mode 100644 index 0000000..ca0eea5 --- /dev/null +++ b/config/settings/base.py @@ -0,0 +1,220 @@ +""" +Base settings for mpicms project. +""" + +import environ + +ROOT_DIR = environ.Path(__file__) - 3 # (mpicms/config/settings/base.py - 3 = mpicms/) +APPS_DIR = ROOT_DIR.path('mpicms') + +env = environ.Env() + +READ_DOT_ENV_FILE = env.bool('DJANGO_READ_DOT_ENV_FILE', default=False) +if READ_DOT_ENV_FILE: + # OS environment variables take precedence over variables from .env + env.read_env(str(ROOT_DIR.path('.env'))) + +# GENERAL +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#debug +DEBUG = env.bool('DJANGO_DEBUG', False) +# Time zone configuration +TIME_ZONE = 'Europe/Berlin' +# https://docs.djangoproject.com/en/dev/ref/settings/#language-code +LANGUAGE_CODE = 'en-us' +# https://docs.djangoproject.com/en/dev/ref/settings/#site-id +SITE_ID = 1 +# https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n +USE_I18N = True +# https://docs.djangoproject.com/en/dev/ref/settings/#use-l10n +USE_L10N = True +# https://docs.djangoproject.com/en/dev/ref/settings/#use-tz +USE_TZ = True + +# DATABASES +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#databases + +DATABASES = { + 'default': env.db('DATABASE_URL', default='postgres:///mpicms'), +} +DATABASES['default']['ATOMIC_REQUESTS'] = True + +# URLS +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#root-urlconf +ROOT_URLCONF = 'config.urls' +# https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application +WSGI_APPLICATION = 'config.wsgi.application' + +# APPS +# ------------------------------------------------------------------------------ +DJANGO_APPS = [ + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django.contrib.humanize', + 'django.contrib.admin', +] +THIRD_PARTY_APPS = [ +] +LOCAL_APPS = [ +] +# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps +INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS + +# MIGRATIONS +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#migration-modules +MIGRATION_MODULES = { + 'sites': 'mpicms.contrib.sites.migrations' +} + +# AUTHENTICATION +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#authentication-backends +AUTHENTICATION_BACKENDS = [ + # 'django_auth_ldap.backend.LDAPBackend', + 'django.contrib.auth.backends.ModelBackend', +] +# https://docs.djangoproject.com/en/dev/ref/settings/#auth-user-model +# AUTH_USER_MODEL = 'users.User' +# https://docs.djangoproject.com/en/dev/ref/settings/#login-redirect-url +# LOGIN_REDIRECT_URL = 'users:redirect' +# https://docs.djangoproject.com/en/dev/ref/settings/#login-url +# LOGIN_URL = 'account_login' + +# PASSWORDS +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers +# PASSWORD_HASHERS = [ +# # https://docs.djangoproject.com/en/dev/topics/auth/passwords/#using-argon2-with-django +# 'django.contrib.auth.hashers.Argon2PasswordHasher', +# 'django.contrib.auth.hashers.PBKDF2PasswordHasher', +# 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', +# 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', +# 'django.contrib.auth.hashers.BCryptPasswordHasher', +# ] +# https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + +# MIDDLEWARE +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#middleware +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +# STATIC +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#static-root +STATIC_ROOT = str(ROOT_DIR('staticfiles')) +# https://docs.djangoproject.com/en/dev/ref/settings/#static-url +STATIC_URL = '/static/' +# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS +STATICFILES_DIRS = [ + str(APPS_DIR.path('static')), +] +# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders +STATICFILES_FINDERS = [ + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', +] + +# MEDIA +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#media-root +MEDIA_ROOT = str(APPS_DIR('media')) +# https://docs.djangoproject.com/en/dev/ref/settings/#media-url +MEDIA_URL = '/media/' + +# TEMPLATES +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#templates +TEMPLATES = [ + { + # https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TEMPLATES-BACKEND + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + # https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs + 'DIRS': [ + str(APPS_DIR.path('templates')), + ], + 'OPTIONS': { + # https://docs.djangoproject.com/en/dev/ref/settings/#template-debug + 'debug': DEBUG, + # https://docs.djangoproject.com/en/dev/ref/settings/#template-loaders + # https://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types + 'loaders': [ + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + ], + # https://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.template.context_processors.i18n', + 'django.template.context_processors.media', + 'django.template.context_processors.static', + 'django.template.context_processors.tz', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +# FIXTURES +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#fixture-dirs +FIXTURE_DIRS = ( + str(APPS_DIR.path('fixtures')), +) + +# SECURITY +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-httponly +SESSION_COOKIE_HTTPONLY = True +# https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-httponly +CSRF_COOKIE_HTTPONLY = True +# https://docs.djangoproject.com/en/dev/ref/settings/#secure-browser-xss-filter +SECURE_BROWSER_XSS_FILTER = True +# https://docs.djangoproject.com/en/dev/ref/settings/#x-frame-options +X_FRAME_OPTIONS = 'DENY' + +# EMAIL +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend +EMAIL_BACKEND = env('DJANGO_EMAIL_BACKEND', default='django.core.mail.backends.smtp.EmailBackend') + +# ADMIN +# ------------------------------------------------------------------------------ +# Django Admin URL. +ADMIN_URL = 'admin/' +# https://docs.djangoproject.com/en/dev/ref/settings/#admins +ADMINS = [ + ("""Merlin Buczek""", 'merlin.buczek@gmail.com'), +] +# https://docs.djangoproject.com/en/dev/ref/settings/#managers +MANAGERS = ADMINS diff --git a/config/settings/local.py b/config/settings/local.py new file mode 100644 index 0000000..4e6d25a --- /dev/null +++ b/config/settings/local.py @@ -0,0 +1,55 @@ +from .base import * # noqa +from .base import env + +# GENERAL +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#debug +DEBUG = True +# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key +SECRET_KEY = env('DJANGO_SECRET_KEY', default='XBlibrFtVb24Dig6CCMAw7Kv3FpXpJYmEZMdpRlnRdTzQpNdTPZ1TtvqKiQu9caf') +# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts +ALLOWED_HOSTS = [ + "localhost", + "0.0.0.0", + "127.0.0.1", +] + +# CACHES +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#caches +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', + 'LOCATION': '' + } +} + +# TEMPLATES +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#templates +TEMPLATES[0]['OPTIONS']['debug'] = DEBUG # noqa F405 + +# EMAIL +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend +EMAIL_BACKEND = env('DJANGO_EMAIL_BACKEND', default='django.core.mail.backends.console.EmailBackend') +# https://docs.djangoproject.com/en/dev/ref/settings/#email-host +EMAIL_HOST = 'localhost' +# https://docs.djangoproject.com/en/dev/ref/settings/#email-port +EMAIL_PORT = 1025 + +# django-debug-toolbar +# ------------------------------------------------------------------------------ +# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#prerequisites +INSTALLED_APPS += ['debug_toolbar'] # noqa F405 +# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#middleware +MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware'] # noqa F405 +# https://django-debug-toolbar.readthedocs.io/en/latest/configuration.html#debug-toolbar-config +DEBUG_TOOLBAR_CONFIG = { + 'DISABLE_PANELS': [ + 'debug_toolbar.panels.redirects.RedirectsPanel', + ], + 'SHOW_TEMPLATE_CONTEXT': True, +} +# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#internal-ips +INTERNAL_IPS = ['127.0.0.1', '10.0.2.2'] diff --git a/config/settings/production.py b/config/settings/production.py new file mode 100644 index 0000000..b71f582 --- /dev/null +++ b/config/settings/production.py @@ -0,0 +1,134 @@ +from .base import * # noqa +from .base import env + +# GENERAL +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key +SECRET_KEY = env('DJANGO_SECRET_KEY') +# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts +ALLOWED_HOSTS = env.list('DJANGO_ALLOWED_HOSTS', default=['twiki.molgen.mpg.de']) + +# DATABASES +# ------------------------------------------------------------------------------ +DATABASES['default'] = env.db('DATABASE_URL') # noqa F405 +DATABASES['default']['ATOMIC_REQUESTS'] = True # noqa F405 +DATABASES['default']['CONN_MAX_AGE'] = env.int('CONN_MAX_AGE', default=60) # noqa F405 + +# CACHES +# ------------------------------------------------------------------------------ +CACHES = { + 'default': { + 'BACKEND': 'django_redis.cache.RedisCache', + 'LOCATION': env('REDIS_URL'), + 'OPTIONS': { + 'CLIENT_CLASS': 'django_redis.client.DefaultClient', + # Mimicing memcache behavior. + # http://niwinz.github.io/django-redis/latest/#_memcached_exceptions_behavior + 'IGNORE_EXCEPTIONS': True, + } + } +} + +# SECURITY +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header +SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') +# https://docs.djangoproject.com/en/dev/ref/settings/#secure-ssl-redirect +SECURE_SSL_REDIRECT = env.bool('DJANGO_SECURE_SSL_REDIRECT', default=True) +# https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-secure +SESSION_COOKIE_SECURE = True +# https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-secure +CSRF_COOKIE_SECURE = True +# https://docs.djangoproject.com/en/dev/topics/security/#ssl-https +# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-seconds +# TODO: set this to 60 seconds first and then to 518400 once you prove the former works +SECURE_HSTS_SECONDS = 60 +# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-include-subdomains +SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool('DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS', default=True) +# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-preload +SECURE_HSTS_PRELOAD = env.bool('DJANGO_SECURE_HSTS_PRELOAD', default=True) +# https://docs.djangoproject.com/en/dev/ref/middleware/#x-content-type-options-nosniff +SECURE_CONTENT_TYPE_NOSNIFF = env.bool('DJANGO_SECURE_CONTENT_TYPE_NOSNIFF', default=True) + +# TEMPLATES +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#templates +TEMPLATES[0]['OPTIONS']['loaders'] = [ # noqa F405 + ( + 'django.template.loaders.cached.Loader', + [ + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + ] + ), +] + +# EMAIL +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email +DEFAULT_FROM_EMAIL = env( + 'DJANGO_DEFAULT_FROM_EMAIL', + default='MPI ' +) +# https://docs.djangoproject.com/en/dev/ref/settings/#server-email +SERVER_EMAIL = env('DJANGO_SERVER_EMAIL', default=DEFAULT_FROM_EMAIL) +# https://docs.djangoproject.com/en/dev/ref/settings/#email-subject-prefix +EMAIL_SUBJECT_PREFIX = env('DJANGO_EMAIL_SUBJECT_PREFIX', default='[MPI CMS]') + +# ADMIN +# ------------------------------------------------------------------------------ +# Django Admin URL regex. +ADMIN_URL = env('DJANGO_ADMIN_URL') + +# Anymail (Mailgun) +# ------------------------------------------------------------------------------ +# https://anymail.readthedocs.io/en/stable/installation/#installing-anymail +INSTALLED_APPS += ['anymail'] # noqa F405 +EMAIL_BACKEND = 'anymail.backends.mailgun.EmailBackend' +# https://anymail.readthedocs.io/en/stable/installation/#anymail-settings-reference +ANYMAIL = { + 'MAILGUN_API_KEY': env('MAILGUN_API_KEY'), + 'MAILGUN_SENDER_DOMAIN': env('MAILGUN_DOMAIN') +} + +# LOGGING +# ------------------------------------------------------------------------------ +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse' + } + }, + 'formatters': { + 'verbose': { + 'format': '%(levelname)s %(asctime)s %(module)s ' + '%(process)d %(thread)d %(message)s' + }, + }, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler' + }, + 'console': { + 'level': 'DEBUG', + 'class': 'logging.StreamHandler', + 'formatter': 'verbose', + }, + }, + 'loggers': { + 'django.request': { + 'handlers': ['mail_admins'], + 'level': 'ERROR', + 'propagate': True + }, + 'django.security.DisallowedHost': { + 'level': 'ERROR', + 'handlers': ['console', 'mail_admins'], + 'propagate': True + } + } +} diff --git a/config/settings/test.py b/config/settings/test.py new file mode 100644 index 0000000..993be9b --- /dev/null +++ b/config/settings/test.py @@ -0,0 +1,52 @@ +""" +With these settings, tests run faster. +""" + +from .base import * # noqa +from .base import env + +# GENERAL +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#debug +DEBUG = False +# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key +SECRET_KEY = env("DJANGO_SECRET_KEY", default="0QnR12nkPQODr0GtLeIaTlt3PWaxYSd6WPQl5USDULW9Q3ArzCqOJRjzsrGUpg96") +# https://docs.djangoproject.com/en/dev/ref/settings/#test-runner +TEST_RUNNER = "django.test.runner.DiscoverRunner" + +# CACHES +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#caches +CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.locmem.LocMemCache", "LOCATION": "" + } +} + +# PASSWORDS +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers +PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"] + +# TEMPLATES +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#templates +TEMPLATES[0]["OPTIONS"]["debug"] = DEBUG # noqa F405 +TEMPLATES[0]["OPTIONS"]["loaders"] = [ # noqa F405 + ( + "django.template.loaders.cached.Loader", + [ + "django.template.loaders.filesystem.Loader", + "django.template.loaders.app_directories.Loader", + ], + ) +] + +# EMAIL +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend +EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" +# https://docs.djangoproject.com/en/dev/ref/settings/#email-host +EMAIL_HOST = "localhost" +# https://docs.djangoproject.com/en/dev/ref/settings/#email-port +EMAIL_PORT = 1025 diff --git a/config/urls.py b/config/urls.py new file mode 100644 index 0000000..4847c8c --- /dev/null +++ b/config/urls.py @@ -0,0 +1,32 @@ +from django.conf import settings +from django.contrib import admin +from django.urls import include, path +from django.views import defaults as default_views + +urlpatterns = [ + path(settings.ADMIN_URL, admin.site.urls), +] + +if settings.DEBUG: + urlpatterns += [ + path( + "400/", + default_views.bad_request, + kwargs={"exception": Exception("Bad Request!")}, + ), + path( + "403/", + default_views.permission_denied, + kwargs={"exception": Exception("Permission Denied")}, + ), + path( + "404/", + default_views.page_not_found, + kwargs={"exception": Exception("Page not Found")}, + ), + path("500/", default_views.server_error), + ] + if "debug_toolbar" in settings.INSTALLED_APPS: + import debug_toolbar + + urlpatterns = [path("__debug__/", include(debug_toolbar.urls))] + urlpatterns diff --git a/config/wsgi.py b/config/wsgi.py new file mode 100644 index 0000000..56de1ac --- /dev/null +++ b/config/wsgi.py @@ -0,0 +1,21 @@ +""" +WSGI config for mpicms project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/ +""" + +import os +import sys + +from django.core.wsgi import get_wsgi_application + +app_path = os.path.abspath(os.path.join( + os.path.dirname(os.path.abspath(__file__)), os.pardir)) +sys.path.append(os.path.join(app_path, 'mpicms')) + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.production') + +application = get_wsgi_application() diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..a8e37fb --- /dev/null +++ b/manage.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == '__main__': + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.local') + + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + + # This allows easy placement of apps within the interior project directory. + current_path = os.path.dirname(os.path.abspath(__file__)) + sys.path.append(os.path.join(current_path, "mpicms")) + + execute_from_command_line(sys.argv) diff --git a/mpicms/__init__.py b/mpicms/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mpicms/contrib/__init__.py b/mpicms/contrib/__init__.py new file mode 100644 index 0000000..1c7ecc8 --- /dev/null +++ b/mpicms/contrib/__init__.py @@ -0,0 +1,5 @@ +""" +To understand why this file is here, please read: + +http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django +""" diff --git a/mpicms/contrib/sites/__init__.py b/mpicms/contrib/sites/__init__.py new file mode 100644 index 0000000..1c7ecc8 --- /dev/null +++ b/mpicms/contrib/sites/__init__.py @@ -0,0 +1,5 @@ +""" +To understand why this file is here, please read: + +http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django +""" diff --git a/mpicms/contrib/sites/migrations/0001_initial.py b/mpicms/contrib/sites/migrations/0001_initial.py new file mode 100644 index 0000000..304cd6d --- /dev/null +++ b/mpicms/contrib/sites/migrations/0001_initial.py @@ -0,0 +1,42 @@ +import django.contrib.sites.models +from django.contrib.sites.models import _simple_domain_name_validator +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="Site", + fields=[ + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "domain", + models.CharField( + max_length=100, + verbose_name="domain name", + validators=[_simple_domain_name_validator], + ), + ), + ("name", models.CharField(max_length=50, verbose_name="display name")), + ], + options={ + "ordering": ("domain",), + "db_table": "django_site", + "verbose_name": "site", + "verbose_name_plural": "sites", + }, + bases=(models.Model,), + managers=[("objects", django.contrib.sites.models.SiteManager())], + ) + ] diff --git a/mpicms/contrib/sites/migrations/0002_alter_domain_unique.py b/mpicms/contrib/sites/migrations/0002_alter_domain_unique.py new file mode 100644 index 0000000..2c8d6da --- /dev/null +++ b/mpicms/contrib/sites/migrations/0002_alter_domain_unique.py @@ -0,0 +1,20 @@ +import django.contrib.sites.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [("sites", "0001_initial")] + + operations = [ + migrations.AlterField( + model_name="site", + name="domain", + field=models.CharField( + max_length=100, + unique=True, + validators=[django.contrib.sites.models._simple_domain_name_validator], + verbose_name="domain name", + ), + ) + ] diff --git a/mpicms/contrib/sites/migrations/0003_set_site_domain_and_name.py b/mpicms/contrib/sites/migrations/0003_set_site_domain_and_name.py new file mode 100644 index 0000000..c59e091 --- /dev/null +++ b/mpicms/contrib/sites/migrations/0003_set_site_domain_and_name.py @@ -0,0 +1,34 @@ +""" +To understand why this file is here, please read: + +http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django +""" +from django.conf import settings +from django.db import migrations + + +def update_site_forward(apps, schema_editor): + """Set site domain and name.""" + Site = apps.get_model("sites", "Site") + Site.objects.update_or_create( + id=settings.SITE_ID, + defaults={ + "domain": "twiki.molgen.mpg.de", + "name": "MPI CMS", + }, + ) + + +def update_site_backward(apps, schema_editor): + """Revert site domain and name to default.""" + Site = apps.get_model("sites", "Site") + Site.objects.update_or_create( + id=settings.SITE_ID, defaults={"domain": "example.com", "name": "example.com"} + ) + + +class Migration(migrations.Migration): + + dependencies = [("sites", "0002_alter_domain_unique")] + + operations = [migrations.RunPython(update_site_forward, update_site_backward)] diff --git a/mpicms/contrib/sites/migrations/__init__.py b/mpicms/contrib/sites/migrations/__init__.py new file mode 100644 index 0000000..1c7ecc8 --- /dev/null +++ b/mpicms/contrib/sites/migrations/__init__.py @@ -0,0 +1,5 @@ +""" +To understand why this file is here, please read: + +http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django +""" diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..5b4369b --- /dev/null +++ b/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +DJANGO_SETTINGS_MODULE=config.settings.test diff --git a/requirements/base.txt b/requirements/base.txt new file mode 100644 index 0000000..38a9d05 --- /dev/null +++ b/requirements/base.txt @@ -0,0 +1,4 @@ +# Django +#------------------------------------------------------------------------------- +Django==2.1.4 +django-environ==0.4.5 diff --git a/requirements/local.txt b/requirements/local.txt new file mode 100644 index 0000000..6754832 --- /dev/null +++ b/requirements/local.txt @@ -0,0 +1,21 @@ +-r ./base.txt + +ipdb==0.11 # https://github.com/gotcha/ipdb +psycopg2-binary==2.7.6.1 # https://github.com/psycopg/psycopg2 + +# Testing +# ------------------------------------------------------------------------------ +pytest==4.0.2 # https://github.com/pytest-dev/pytest + +# Code quality +# ------------------------------------------------------------------------------ +flake8==3.6.0 # https://github.com/PyCQA/flake8 +coverage==4.5.2 # https://github.com/nedbat/coveragepy + +# Django +# ------------------------------------------------------------------------------ +factory-boy==2.11.1 # https://github.com/FactoryBoy/factory_boy + +django-debug-toolbar==1.11 # https://github.com/jazzband/django-debug-toolbar +django-coverage-plugin==1.6.0 # https://github.com/nedbat/django_coverage_plugin +pytest-django==3.4.4 # https://github.com/pytest-dev/pytest-django diff --git a/requirements/production.txt b/requirements/production.txt new file mode 100644 index 0000000..bdedda3 --- /dev/null +++ b/requirements/production.txt @@ -0,0 +1 @@ +-r ./base.txt diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..1ec89c7 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,7 @@ +[flake8] +max-line-length = 120 +exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules + +[pycodestyle] +max-line-length = 120 +exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules