forked from 00dani/lemoncurry
Run Black over the whole codebase
This commit is contained in:
parent
cd990e4e2f
commit
2e7d12b3e6
109 changed files with 1539 additions and 1209 deletions
|
@ -14,7 +14,7 @@ class Crumb:
|
|||
return self._label
|
||||
|
||||
def __eq__(self, other):
|
||||
if hasattr(other, 'route'):
|
||||
if hasattr(other, "route"):
|
||||
return self.route == other.route
|
||||
return self.route == other
|
||||
|
||||
|
|
|
@ -2,6 +2,6 @@ from debug_toolbar.middleware import show_toolbar as core_show_toolbar
|
|||
|
||||
|
||||
def show_toolbar(request):
|
||||
if request.path.endswith('/amp'):
|
||||
if request.path.endswith("/amp"):
|
||||
return False
|
||||
return core_show_toolbar(request)
|
||||
|
|
|
@ -22,18 +22,22 @@ def environment(**options):
|
|||
lstrip_blocks=True,
|
||||
**options
|
||||
)
|
||||
env.filters.update({
|
||||
'ago': ago,
|
||||
'friendly_url': friendly_url,
|
||||
'markdown': markdown,
|
||||
})
|
||||
env.globals.update({
|
||||
'entry_kinds': entry_kinds,
|
||||
'favicons': favicons,
|
||||
'package': load_package_json(),
|
||||
'settings': settings,
|
||||
'static': staticfiles_storage.url,
|
||||
'theme_color': theme_color,
|
||||
'url': reverse,
|
||||
})
|
||||
env.filters.update(
|
||||
{
|
||||
"ago": ago,
|
||||
"friendly_url": friendly_url,
|
||||
"markdown": markdown,
|
||||
}
|
||||
)
|
||||
env.globals.update(
|
||||
{
|
||||
"entry_kinds": entry_kinds,
|
||||
"favicons": favicons,
|
||||
"package": load_package_json(),
|
||||
"settings": settings,
|
||||
"static": staticfiles_storage.url,
|
||||
"theme_color": theme_color,
|
||||
"url": reverse,
|
||||
}
|
||||
)
|
||||
return env
|
||||
|
|
|
@ -6,4 +6,4 @@ def ago(dt: datetime) -> str:
|
|||
# We have to convert the datetime we get to local time first, because ago
|
||||
# just strips the timezone from a timezone-aware datetime.
|
||||
dt = dt.astimezone()
|
||||
return human(dt, precision=1, past_tense='{}', abbreviate=True)
|
||||
return human(dt, precision=1, past_tense="{}", abbreviate=True)
|
||||
|
|
|
@ -3,13 +3,13 @@ from bleach.linkifier import LinkifyFilter
|
|||
from jinja2 import pass_eval_context
|
||||
from markupsafe import Markup
|
||||
|
||||
TAGS = ['cite', 'code', 'details', 'p', 'pre', 'img', 'span', 'summary']
|
||||
TAGS = ["cite", "code", "details", "p", "pre", "img", "span", "summary"]
|
||||
TAGS.extend(ALLOWED_TAGS)
|
||||
ATTRIBUTES = {
|
||||
'a': ['href', 'title', 'class'],
|
||||
'details': ['open'],
|
||||
'img': ['alt', 'src', 'title'],
|
||||
'span': ['class'],
|
||||
"a": ["href", "title", "class"],
|
||||
"details": ["open"],
|
||||
"img": ["alt", "src", "title"],
|
||||
"span": ["class"],
|
||||
}
|
||||
|
||||
cleaner = Cleaner(tags=TAGS, attributes=ATTRIBUTES, filters=(LinkifyFilter,))
|
||||
|
|
|
@ -3,12 +3,14 @@ from markdown import Markdown
|
|||
|
||||
from .bleach import bleach
|
||||
|
||||
md = Markdown(extensions=(
|
||||
'extra',
|
||||
'sane_lists',
|
||||
'smarty',
|
||||
'toc',
|
||||
))
|
||||
md = Markdown(
|
||||
extensions=(
|
||||
"extra",
|
||||
"sane_lists",
|
||||
"smarty",
|
||||
"toc",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@pass_eval_context
|
||||
|
|
|
@ -8,7 +8,9 @@ class ResponseException(Exception):
|
|||
|
||||
|
||||
class ResponseExceptionMiddleware(MiddlewareMixin):
|
||||
def process_exception(self, request: HttpRequest, exception: Exception) -> HttpResponse:
|
||||
def process_exception(
|
||||
self, request: HttpRequest, exception: Exception
|
||||
) -> HttpResponse:
|
||||
if isinstance(exception, ResponseException):
|
||||
return exception.response
|
||||
raise exception
|
||||
|
|
|
@ -11,7 +11,7 @@ from mf2py import Parser
|
|||
class DjangoCache(BaseCache):
|
||||
@classmethod
|
||||
def key(cls, url):
|
||||
return 'req:' + sha256(url.encode('utf-8')).hexdigest()
|
||||
return "req:" + sha256(url.encode("utf-8")).hexdigest()
|
||||
|
||||
def get(self, url):
|
||||
key = self.key(url)
|
||||
|
@ -45,4 +45,4 @@ def get(url):
|
|||
|
||||
def mf2(url):
|
||||
r = get(url)
|
||||
return Parser(doc=r.text, url=url, html_parser='html5lib')
|
||||
return Parser(doc=r.text, url=url, html_parser="html5lib")
|
||||
|
|
|
@ -16,7 +16,7 @@ from typing import List
|
|||
APPEND_SLASH = False
|
||||
|
||||
ADMINS = [
|
||||
('dani', 'dani@00dani.me'),
|
||||
("dani", "dani@00dani.me"),
|
||||
]
|
||||
|
||||
BASE_DIR = path.dirname(path.dirname(path.dirname(path.abspath(__file__))))
|
||||
|
@ -26,13 +26,13 @@ BASE_DIR = path.dirname(path.dirname(path.dirname(path.abspath(__file__))))
|
|||
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = '6riil57g@r^wprf7mdy((+bs&(6l*phcn9&fd$l0@t-kzj+xww'
|
||||
SECRET_KEY = "6riil57g@r^wprf7mdy((+bs&(6l*phcn9&fd$l0@t-kzj+xww"
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS: List[str] = []
|
||||
INTERNAL_IPS = ['127.0.0.1', '::1']
|
||||
INTERNAL_IPS = ["127.0.0.1", "::1"]
|
||||
|
||||
# Settings to tighten up security - these can safely be on in dev mode too,
|
||||
# since I dev using a local HTTPS server.
|
||||
|
@ -50,7 +50,7 @@ CSRF_COOKIE_SECURE = True
|
|||
# Miscellanous headers to protect against attacks.
|
||||
SECURE_CONTENT_TYPE_NOSNIFF = True
|
||||
SECURE_BROWSER_XSS_FILTER = True
|
||||
X_FRAME_OPTIONS = 'DENY'
|
||||
X_FRAME_OPTIONS = "DENY"
|
||||
|
||||
# This technically isn't needed, since nginx doesn't let the app be accessed
|
||||
# over insecure HTTP anyway. Just for completeness!
|
||||
|
@ -58,109 +58,106 @@ SECURE_SSL_REDIRECT = True
|
|||
|
||||
# We run behind nginx, so we need nginx to tell us whether we're using HTTPS or
|
||||
# not.
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'lemoncurry',
|
||||
'pyup_django',
|
||||
|
||||
'django.contrib.admin',
|
||||
'django.contrib.admindocs',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.humanize',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.sitemaps',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
|
||||
'analytical',
|
||||
'annoying',
|
||||
'compressor',
|
||||
'computed_property',
|
||||
'corsheaders',
|
||||
'debug_toolbar',
|
||||
'django_activeurl',
|
||||
'django_agent_trust',
|
||||
'django_extensions',
|
||||
'django_otp',
|
||||
'django_otp.plugins.otp_static',
|
||||
'django_otp.plugins.otp_totp',
|
||||
'django_rq',
|
||||
'meta',
|
||||
|
||||
'entries',
|
||||
'home',
|
||||
'lemonauth',
|
||||
'lemonshort',
|
||||
'micropub',
|
||||
'users',
|
||||
'webmention',
|
||||
'wellknowns',
|
||||
"lemoncurry",
|
||||
"pyup_django",
|
||||
"django.contrib.admin",
|
||||
"django.contrib.admindocs",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.humanize",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.sites",
|
||||
"django.contrib.sitemaps",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"analytical",
|
||||
"annoying",
|
||||
"compressor",
|
||||
"computed_property",
|
||||
"corsheaders",
|
||||
"debug_toolbar",
|
||||
"django_activeurl",
|
||||
"django_agent_trust",
|
||||
"django_extensions",
|
||||
"django_otp",
|
||||
"django_otp.plugins.otp_static",
|
||||
"django_otp.plugins.otp_totp",
|
||||
"django_rq",
|
||||
"meta",
|
||||
"entries",
|
||||
"home",
|
||||
"lemonauth",
|
||||
"lemonshort",
|
||||
"micropub",
|
||||
"users",
|
||||
"webmention",
|
||||
"wellknowns",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||
'django.middleware.http.ConditionalGetMiddleware',
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.admindocs.middleware.XViewMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'corsheaders.middleware.CorsMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django_otp.middleware.OTPMiddleware',
|
||||
'django_agent_trust.middleware.AgentMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.contrib.sites.middleware.CurrentSiteMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'lemoncurry.middleware.ResponseExceptionMiddleware',
|
||||
"debug_toolbar.middleware.DebugToolbarMiddleware",
|
||||
"django.middleware.http.ConditionalGetMiddleware",
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"django.contrib.admindocs.middleware.XViewMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"corsheaders.middleware.CorsMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django_otp.middleware.OTPMiddleware",
|
||||
"django_agent_trust.middleware.AgentMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.contrib.sites.middleware.CurrentSiteMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
"lemoncurry.middleware.ResponseExceptionMiddleware",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'lemoncurry.urls'
|
||||
ROOT_URLCONF = "lemoncurry.urls"
|
||||
|
||||
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
|
||||
SESSION_ENGINE = "django.contrib.sessions.backends.cached_db"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.jinja2.Jinja2',
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'environment': 'lemoncurry.jinja2.environment',
|
||||
"BACKEND": "django.template.backends.jinja2.Jinja2",
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"environment": "lemoncurry.jinja2.environment",
|
||||
},
|
||||
},
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'lemoncurry.wsgi.application'
|
||||
WSGI_APPLICATION = "lemoncurry.wsgi.application"
|
||||
|
||||
# Cache
|
||||
# https://docs.djangoproject.com/en/1.11/ref/settings/#std:setting-CACHES
|
||||
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django_redis.cache.RedisCache',
|
||||
'LOCATION': 'redis://127.0.0.1:6380/0',
|
||||
'KEY_PREFIX': 'lemoncurry',
|
||||
'OPTIONS': {
|
||||
'PARSER_CLASS': 'redis.connection.HiredisParser',
|
||||
'SERIALIZER': 'lemoncurry.msgpack.MSGPackModernSerializer',
|
||||
"default": {
|
||||
"BACKEND": "django_redis.cache.RedisCache",
|
||||
"LOCATION": "redis://127.0.0.1:6380/0",
|
||||
"KEY_PREFIX": "lemoncurry",
|
||||
"OPTIONS": {
|
||||
"PARSER_CLASS": "redis.connection.HiredisParser",
|
||||
"SERIALIZER": "lemoncurry.msgpack.MSGPackModernSerializer",
|
||||
},
|
||||
'VERSION': 2,
|
||||
"VERSION": 2,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,51 +165,51 @@ CACHES = {
|
|||
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql',
|
||||
'NAME': environ.get('POSTGRES_DB', 'lemoncurry'),
|
||||
'USER': environ.get('POSTGRES_USER'),
|
||||
'PASSWORD': environ.get('POSTGRES_PASSWORD'),
|
||||
'HOST': environ.get('POSTGRES_HOST', 'localhost'),
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.postgresql",
|
||||
"NAME": environ.get("POSTGRES_DB", "lemoncurry"),
|
||||
"USER": environ.get("POSTGRES_USER"),
|
||||
"PASSWORD": environ.get("POSTGRES_PASSWORD"),
|
||||
"HOST": environ.get("POSTGRES_HOST", "localhost"),
|
||||
}
|
||||
}
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
|
||||
|
||||
AUTH_USER_MODEL = 'users.User'
|
||||
AUTH_USER_MODEL = "users.User"
|
||||
|
||||
# Password hashers
|
||||
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
|
||||
PASSWORD_HASHERS = [
|
||||
'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',
|
||||
"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",
|
||||
]
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
|
||||
|
||||
PW_VALIDATOR_MODULE = 'django.contrib.auth.password_validation'
|
||||
PW_VALIDATOR_MODULE = "django.contrib.auth.password_validation"
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{'NAME': PW_VALIDATOR_MODULE + '.UserAttributeSimilarityValidator'},
|
||||
{'NAME': PW_VALIDATOR_MODULE + '.MinimumLengthValidator'},
|
||||
{'NAME': PW_VALIDATOR_MODULE + '.CommonPasswordValidator'},
|
||||
{'NAME': PW_VALIDATOR_MODULE + '.NumericPasswordValidator'},
|
||||
{"NAME": PW_VALIDATOR_MODULE + ".UserAttributeSimilarityValidator"},
|
||||
{"NAME": PW_VALIDATOR_MODULE + ".MinimumLengthValidator"},
|
||||
{"NAME": PW_VALIDATOR_MODULE + ".CommonPasswordValidator"},
|
||||
{"NAME": PW_VALIDATOR_MODULE + ".NumericPasswordValidator"},
|
||||
]
|
||||
|
||||
LOGIN_URL = 'lemonauth:login'
|
||||
LOGIN_REDIRECT_URL = 'home:index'
|
||||
LOGIN_URL = "lemonauth:login"
|
||||
LOGIN_REDIRECT_URL = "home:index"
|
||||
LOGOUT_REDIRECT_URL = LOGIN_REDIRECT_URL
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/1.11/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-au'
|
||||
LANGUAGE_CODE = "en-au"
|
||||
|
||||
TIME_ZONE = 'Australia/Sydney'
|
||||
TIME_ZONE = "Australia/Sydney"
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
|
@ -224,23 +221,21 @@ USE_TZ = True
|
|||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/1.11/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_ROOT = path.join(BASE_DIR, 'static')
|
||||
STATIC_URL = "/static/"
|
||||
STATIC_ROOT = path.join(BASE_DIR, "static")
|
||||
STATICFILES_FINDERS = (
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
'compressor.finders.CompressorFinder',
|
||||
)
|
||||
STATICFILES_STORAGE = (
|
||||
'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
|
||||
"django.contrib.staticfiles.finders.FileSystemFinder",
|
||||
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
|
||||
"compressor.finders.CompressorFinder",
|
||||
)
|
||||
STATICFILES_STORAGE = "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
|
||||
|
||||
COMPRESS_PRECOMPILERS = (
|
||||
('text/stylus', 'npx stylus -u ./lemoncurry/static/lemoncurry/css/theme'),
|
||||
("text/stylus", "npx stylus -u ./lemoncurry/static/lemoncurry/css/theme"),
|
||||
)
|
||||
|
||||
MEDIA_URL = STATIC_URL + 'media/'
|
||||
MEDIA_ROOT = path.join(STATIC_ROOT, 'media')
|
||||
MEDIA_URL = STATIC_URL + "media/"
|
||||
MEDIA_ROOT = path.join(STATIC_ROOT, "media")
|
||||
|
||||
# django-contrib-sites
|
||||
# https://docs.djangoproject.com/en/dev/ref/contrib/sites/
|
||||
|
@ -252,25 +247,25 @@ AGENT_COOKIE_SECURE = True
|
|||
|
||||
# django-cors-headers
|
||||
CORS_ORIGIN_ALLOW_ALL = True
|
||||
CORS_URLS_REGEX = r'^/(?!admin|auth/(?:login|logout|indie)).*$'
|
||||
CORS_URLS_REGEX = r"^/(?!admin|auth/(?:login|logout|indie)).*$"
|
||||
|
||||
# lemonshort
|
||||
SHORT_BASE_URL = '/s/'
|
||||
SHORT_BASE_URL = "/s/"
|
||||
SHORTEN_MODELS = {
|
||||
'e': 'entries.entry',
|
||||
"e": "entries.entry",
|
||||
}
|
||||
|
||||
# django-meta
|
||||
# https://django-meta.readthedocs.io/en/latest/settings.html
|
||||
META_SITE_PROTOCOL = 'https'
|
||||
META_SITE_PROTOCOL = "https"
|
||||
META_USE_SITES = True
|
||||
META_USE_OG_PROPERTIES = True
|
||||
META_USE_TWITTER_PROPERTIES = True
|
||||
|
||||
# django-push
|
||||
# https://django-push.readthedocs.io/en/latest/publisher.html
|
||||
PUSH_HUB = 'https://00dani.superfeedr.com/'
|
||||
PUSH_HUB = "https://00dani.superfeedr.com/"
|
||||
|
||||
# django-rq
|
||||
# https://github.com/ui/django-rq
|
||||
RQ_QUEUES = {'default': {'USE_REDIS_CACHE': 'default'}}
|
||||
RQ_QUEUES = {"default": {"USE_REDIS_CACHE": "default"}}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from .base import *
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
META_SITE_DOMAIN = '00dani.lo'
|
||||
META_FB_APPID = '142105433189339'
|
||||
STATIC_URL = 'https://static.00dani.lo/'
|
||||
MEDIA_URL = 'https://media.00dani.lo/'
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
META_SITE_DOMAIN = "00dani.lo"
|
||||
META_FB_APPID = "142105433189339"
|
||||
STATIC_URL = "https://static.00dani.lo/"
|
||||
MEDIA_URL = "https://media.00dani.lo/"
|
||||
|
|
|
@ -4,19 +4,19 @@ from os.path import join
|
|||
from .base import *
|
||||
from .base import BASE_DIR, DATABASES
|
||||
|
||||
ALLOWED_HOSTS = ['00dani.me']
|
||||
ALLOWED_HOSTS = ["00dani.me"]
|
||||
DEBUG = False
|
||||
SECRET_KEY = environ['DJANGO_SECRET_KEY']
|
||||
SERVER_EMAIL = 'lemoncurry@00dani.me'
|
||||
SECRET_KEY = environ["DJANGO_SECRET_KEY"]
|
||||
SERVER_EMAIL = "lemoncurry@00dani.me"
|
||||
|
||||
# Authenticate as an app-specific Postgres user in production.
|
||||
DATABASES['default']['USER'] = 'lemoncurry'
|
||||
DATABASES["default"]["USER"] = "lemoncurry"
|
||||
|
||||
SHORT_BASE_URL = 'https://nya.as/'
|
||||
SHORT_BASE_URL = "https://nya.as/"
|
||||
|
||||
STATIC_ROOT = join(BASE_DIR, '..', 'static')
|
||||
MEDIA_ROOT = join(BASE_DIR, '..', 'media')
|
||||
STATIC_URL = 'https://cdn.00dani.me/'
|
||||
MEDIA_URL = STATIC_URL + 'm/'
|
||||
META_SITE_DOMAIN = '00dani.me'
|
||||
META_FB_APPID = '145311792869199'
|
||||
STATIC_ROOT = join(BASE_DIR, "..", "static")
|
||||
MEDIA_ROOT = join(BASE_DIR, "..", "media")
|
||||
STATIC_URL = "https://cdn.00dani.me/"
|
||||
MEDIA_URL = STATIC_URL + "m/"
|
||||
META_SITE_DOMAIN = "00dani.me"
|
||||
META_FB_APPID = "145311792869199"
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
from .base import *
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
SECURE_SSL_REDIRECT = False
|
||||
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
|
||||
STATICFILES_STORAGE = "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||
|
||||
MEDIA_URL = '/media/'
|
||||
STATIC_ROOT = path.join(BASE_DIR, 'media')
|
||||
MEDIA_URL = "/media/"
|
||||
STATIC_ROOT = path.join(BASE_DIR, "media")
|
||||
|
|
|
@ -8,5 +8,5 @@ register = template.Library()
|
|||
@register.simple_tag
|
||||
@register.filter(is_safe=True)
|
||||
def absolute_url(url):
|
||||
base = 'https://' + Site.objects.get_current().domain
|
||||
base = "https://" + Site.objects.get_current().domain
|
||||
return urljoin(base, url)
|
||||
|
|
|
@ -5,13 +5,13 @@ from django.utils.safestring import mark_safe
|
|||
from bleach.sanitizer import Cleaner, ALLOWED_TAGS
|
||||
from bleach.linkifier import LinkifyFilter
|
||||
|
||||
tags = ['cite', 'code', 'details', 'p', 'pre', 'img', 'span', 'summary']
|
||||
tags = ["cite", "code", "details", "p", "pre", "img", "span", "summary"]
|
||||
tags.extend(ALLOWED_TAGS)
|
||||
attributes = {
|
||||
'a': ['href', 'title', 'class'],
|
||||
'details': ['open'],
|
||||
'img': ['alt', 'src', 'title'],
|
||||
'span': ['class'],
|
||||
"a": ["href", "title", "class"],
|
||||
"details": ["open"],
|
||||
"img": ["alt", "src", "title"],
|
||||
"span": ["class"],
|
||||
}
|
||||
|
||||
register = template.Library()
|
||||
|
|
|
@ -11,5 +11,5 @@ register = template.Library()
|
|||
@register.filter
|
||||
def jsonify(value):
|
||||
if isinstance(value, QuerySet):
|
||||
return mark_safe(serialize('json', value))
|
||||
return mark_safe(serialize("json", value))
|
||||
return mark_safe(json.dumps(value, cls=DjangoJSONEncoder))
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.models import Site
|
||||
|
@ -40,67 +39,71 @@ def site_name():
|
|||
return Site.objects.get_current().name
|
||||
|
||||
|
||||
@register.inclusion_tag('lemoncurry/tags/nav.html')
|
||||
@register.inclusion_tag("lemoncurry/tags/nav.html")
|
||||
def nav_left(request):
|
||||
items = (MenuItem(
|
||||
label=k.plural,
|
||||
icon=k.icon,
|
||||
url=('entries:index', (k,))
|
||||
) for k in kinds.all)
|
||||
return {'items': items, 'request': request}
|
||||
items = (
|
||||
MenuItem(label=k.plural, icon=k.icon, url=("entries:index", (k,)))
|
||||
for k in kinds.all
|
||||
)
|
||||
return {"items": items, "request": request}
|
||||
|
||||
|
||||
@register.inclusion_tag('lemoncurry/tags/nav.html')
|
||||
@register.inclusion_tag("lemoncurry/tags/nav.html")
|
||||
def nav_right(request):
|
||||
if request.user.is_authenticated:
|
||||
items = (
|
||||
MenuItem(label='admin', icon='fas fa-cog', url='admin:index'),
|
||||
MenuItem(label='log out', icon='fas fa-sign-out-alt',
|
||||
url='lemonauth:logout'),
|
||||
MenuItem(label="admin", icon="fas fa-cog", url="admin:index"),
|
||||
MenuItem(
|
||||
label="log out", icon="fas fa-sign-out-alt", url="lemonauth:logout"
|
||||
),
|
||||
)
|
||||
else:
|
||||
items = (
|
||||
MenuItem(label='log in', icon='fas fa-sign-in-alt',
|
||||
url='lemonauth:login'),
|
||||
MenuItem(label="log in", icon="fas fa-sign-in-alt", url="lemonauth:login"),
|
||||
)
|
||||
return {'items': items, 'request': request}
|
||||
return {"items": items, "request": request}
|
||||
|
||||
|
||||
@register.inclusion_tag('lemoncurry/tags/breadcrumbs.html', takes_context=True)
|
||||
@register.inclusion_tag("lemoncurry/tags/breadcrumbs.html", takes_context=True)
|
||||
def nav_crumbs(context, route):
|
||||
crumbs = breadcrumbs.find(route)
|
||||
current = crumbs.pop()
|
||||
|
||||
item_list_element = [{
|
||||
'@type': 'ListItem',
|
||||
'position': i + 1,
|
||||
'item': {
|
||||
'@id': context['origin'] + crumb.url,
|
||||
'@type': 'WebPage',
|
||||
'name': crumb.label
|
||||
item_list_element = [
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": i + 1,
|
||||
"item": {
|
||||
"@id": context["origin"] + crumb.url,
|
||||
"@type": "WebPage",
|
||||
"name": crumb.label,
|
||||
},
|
||||
}
|
||||
} for i, crumb in enumerate(crumbs)]
|
||||
item_list_element.append({
|
||||
'@type': 'ListItem',
|
||||
'position': len(item_list_element) + 1,
|
||||
'item': {
|
||||
'id': context['uri'],
|
||||
'@type': 'WebPage',
|
||||
'name': current.label or context.get('title'),
|
||||
for i, crumb in enumerate(crumbs)
|
||||
]
|
||||
item_list_element.append(
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": len(item_list_element) + 1,
|
||||
"item": {
|
||||
"id": context["uri"],
|
||||
"@type": "WebPage",
|
||||
"name": current.label or context.get("title"),
|
||||
},
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
breadcrumb_list = {
|
||||
'@context': 'http://schema.org',
|
||||
'@type': 'BreadcrumbList',
|
||||
'itemListElement': item_list_element
|
||||
"@context": "http://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": item_list_element,
|
||||
}
|
||||
|
||||
return {
|
||||
'breadcrumb_list': breadcrumb_list,
|
||||
'crumbs': crumbs,
|
||||
'current': current,
|
||||
'title': context.get('title'),
|
||||
"breadcrumb_list": breadcrumb_list,
|
||||
"crumbs": crumbs,
|
||||
"current": current,
|
||||
"title": context.get("title"),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,12 +3,14 @@ from django import template
|
|||
from markdown import Markdown
|
||||
from .bleach import bleach
|
||||
|
||||
md = Markdown(extensions=(
|
||||
'extra',
|
||||
'sane_lists',
|
||||
'smarty',
|
||||
'toc',
|
||||
))
|
||||
md = Markdown(
|
||||
extensions=(
|
||||
"extra",
|
||||
"sane_lists",
|
||||
"smarty",
|
||||
"toc",
|
||||
)
|
||||
)
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
|
|
@ -6,43 +6,43 @@ from .. import breadcrumbs as b
|
|||
|
||||
@pytest.fixture
|
||||
def nested_crumbs():
|
||||
x = b.Crumb('nc.x', label='x')
|
||||
y = b.Crumb('nc.y', label='y', parent='nc.x')
|
||||
z = b.Crumb('nc.z', label='z', parent='nc.y')
|
||||
x = b.Crumb("nc.x", label="x")
|
||||
y = b.Crumb("nc.y", label="y", parent="nc.x")
|
||||
z = b.Crumb("nc.z", label="z", parent="nc.y")
|
||||
crumbs = (x, y, z)
|
||||
|
||||
for crumb in crumbs:
|
||||
b.breadcrumbs[crumb.route] = crumb
|
||||
yield namedtuple('NestedCrumbs', 'x y z')(*crumbs)
|
||||
yield namedtuple("NestedCrumbs", "x y z")(*crumbs)
|
||||
for crumb in crumbs:
|
||||
del b.breadcrumbs[crumb.route]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def crumb_match(nested_crumbs):
|
||||
return namedtuple('Match', 'view_name')(nested_crumbs.z.route)
|
||||
return namedtuple("Match", "view_name")(nested_crumbs.z.route)
|
||||
|
||||
|
||||
class TestAdd:
|
||||
def test_inserts_a_breadcrumb_without_parent(self):
|
||||
route = 'tests.add.insert'
|
||||
route = "tests.add.insert"
|
||||
assert route not in b.breadcrumbs
|
||||
b.add(route, 'some label')
|
||||
b.add(route, "some label")
|
||||
assert route in b.breadcrumbs
|
||||
assert b.breadcrumbs[route] == route
|
||||
route = b.breadcrumbs[route]
|
||||
assert route.label == 'some label'
|
||||
assert route.label == "some label"
|
||||
assert route.parent is None
|
||||
|
||||
def test_inserts_a_breadcrumb_with_parent(self):
|
||||
route = 'tests.add.with_parent'
|
||||
parent = 'tests.add.insert'
|
||||
route = "tests.add.with_parent"
|
||||
parent = "tests.add.insert"
|
||||
assert route not in b.breadcrumbs
|
||||
b.add(route, 'child label', parent)
|
||||
b.add(route, "child label", parent)
|
||||
assert route in b.breadcrumbs
|
||||
assert b.breadcrumbs[route] == route
|
||||
route = b.breadcrumbs[route]
|
||||
assert route.label == 'child label'
|
||||
assert route.label == "child label"
|
||||
assert route.parent == parent
|
||||
|
||||
|
||||
|
|
|
@ -5,22 +5,22 @@ from .. import utils
|
|||
class TestOrigin:
|
||||
def test_simple_http(self):
|
||||
"""should return the correct origin for a vanilla HTTP site"""
|
||||
req = Mock(scheme='http', site=Mock(domain='lemoncurry.test'))
|
||||
assert utils.origin(req) == 'http://lemoncurry.test'
|
||||
req = Mock(scheme="http", site=Mock(domain="lemoncurry.test"))
|
||||
assert utils.origin(req) == "http://lemoncurry.test"
|
||||
|
||||
def test_simple_https(self):
|
||||
"""should return the correct origin for a vanilla HTTPS site"""
|
||||
req = Mock(scheme='https', site=Mock(domain='secure.lemoncurry.test'))
|
||||
assert utils.origin(req) == 'https://secure.lemoncurry.test'
|
||||
req = Mock(scheme="https", site=Mock(domain="secure.lemoncurry.test"))
|
||||
assert utils.origin(req) == "https://secure.lemoncurry.test"
|
||||
|
||||
|
||||
class TestUri:
|
||||
def test_siteroot(self):
|
||||
"""should return correct full URI for requests to the site root"""
|
||||
req = Mock(scheme='https', path='/', site=Mock(domain='l.test'))
|
||||
assert utils.uri(req) == 'https://l.test/'
|
||||
req = Mock(scheme="https", path="/", site=Mock(domain="l.test"))
|
||||
assert utils.uri(req) == "https://l.test/"
|
||||
|
||||
def test_path(self):
|
||||
"""should return correct full URI for requests with a path"""
|
||||
req = Mock(scheme='https', path='/notes/23', site=Mock(domain='l.tst'))
|
||||
assert utils.uri(req) == 'https://l.tst/notes/23'
|
||||
req = Mock(scheme="https", path="/notes/23", site=Mock(domain="l.tst"))
|
||||
assert utils.uri(req) == "https://l.tst/notes/23"
|
||||
|
|
|
@ -4,12 +4,14 @@ from yaml import safe_load
|
|||
|
||||
path = join(
|
||||
settings.BASE_DIR,
|
||||
'lemoncurry', 'static',
|
||||
'base16-materialtheme-scheme', 'material-darker.yaml',
|
||||
"lemoncurry",
|
||||
"static",
|
||||
"base16-materialtheme-scheme",
|
||||
"material-darker.yaml",
|
||||
)
|
||||
with open(path, 'r') as f:
|
||||
with open(path, "r") as f:
|
||||
theme = safe_load(f)
|
||||
|
||||
|
||||
def color(i):
|
||||
return '#' + theme['base0' + format(i, '1X')]
|
||||
return "#" + theme["base0" + format(i, "1X")]
|
||||
|
|
|
@ -27,33 +27,37 @@ from entries.sitemaps import EntriesSitemap
|
|||
from home.sitemaps import HomeSitemap
|
||||
|
||||
sections = {
|
||||
'entries': EntriesSitemap,
|
||||
'home': HomeSitemap,
|
||||
"entries": EntriesSitemap,
|
||||
"home": HomeSitemap,
|
||||
}
|
||||
maps = {'sitemaps': sections}
|
||||
maps = {"sitemaps": sections}
|
||||
|
||||
urlpatterns = (
|
||||
path('', include('home.urls')),
|
||||
path('', include('entries.urls')),
|
||||
path('', include('users.urls')),
|
||||
path('.well-known/', include('wellknowns.urls')),
|
||||
path('admin/doc/', include('django.contrib.admindocs.urls')),
|
||||
path('admin/', admin.site.urls),
|
||||
path('auth/', include('lemonauth.urls')),
|
||||
path('favicon.ico', RedirectView.as_view(
|
||||
url=settings.MEDIA_URL + 'favicon/favicon.ico')),
|
||||
path('micropub', include('micropub.urls')),
|
||||
path('s/', include('lemonshort.urls')),
|
||||
path('webmention', include('webmention.urls')),
|
||||
|
||||
path('django-rq/', include('django_rq.urls')),
|
||||
path('sitemap.xml', sitemap.index, maps, name='sitemap'),
|
||||
path('sitemaps/<section>.xml', sitemap.sitemap, maps,
|
||||
name='django.contrib.sitemaps.views.sitemap'),
|
||||
path("", include("home.urls")),
|
||||
path("", include("entries.urls")),
|
||||
path("", include("users.urls")),
|
||||
path(".well-known/", include("wellknowns.urls")),
|
||||
path("admin/doc/", include("django.contrib.admindocs.urls")),
|
||||
path("admin/", admin.site.urls),
|
||||
path("auth/", include("lemonauth.urls")),
|
||||
path(
|
||||
"favicon.ico",
|
||||
RedirectView.as_view(url=settings.MEDIA_URL + "favicon/favicon.ico"),
|
||||
),
|
||||
path("micropub", include("micropub.urls")),
|
||||
path("s/", include("lemonshort.urls")),
|
||||
path("webmention", include("webmention.urls")),
|
||||
path("django-rq/", include("django_rq.urls")),
|
||||
path("sitemap.xml", sitemap.index, maps, name="sitemap"),
|
||||
path(
|
||||
"sitemaps/<section>.xml",
|
||||
sitemap.sitemap,
|
||||
maps,
|
||||
name="django.contrib.sitemaps.views.sitemap",
|
||||
),
|
||||
) # type: Tuple[URLPattern, ...]
|
||||
|
||||
if settings.DEBUG:
|
||||
import debug_toolbar
|
||||
urlpatterns += (
|
||||
path('__debug__/', include(debug_toolbar.urls)),
|
||||
)
|
||||
|
||||
urlpatterns += (path("__debug__/", include(debug_toolbar.urls)),)
|
||||
|
|
|
@ -20,7 +20,7 @@ class PackageJson:
|
|||
|
||||
def load(self) -> Dict[str, Any]:
|
||||
if self.data is None:
|
||||
with open(join(settings.BASE_DIR, 'package.json')) as f:
|
||||
with open(join(settings.BASE_DIR, "package.json")) as f:
|
||||
self.data = json.load(f)
|
||||
assert self.data is not None
|
||||
return self.data
|
||||
|
@ -30,10 +30,10 @@ PACKAGE = PackageJson()
|
|||
|
||||
|
||||
def friendly_url(url):
|
||||
if '//' not in url:
|
||||
url = '//' + url
|
||||
if "//" not in url:
|
||||
url = "//" + url
|
||||
(scheme, netloc, path, params, q, fragment) = urlparse(url)
|
||||
if path == '/':
|
||||
if path == "/":
|
||||
return netloc
|
||||
return "{}\u200B{}".format(netloc, path)
|
||||
|
||||
|
@ -43,7 +43,7 @@ def load_package_json() -> Dict[str, Any]:
|
|||
|
||||
|
||||
def origin(request):
|
||||
return '{0}://{1}'.format(request.scheme, request.site.domain)
|
||||
return "{0}://{1}".format(request.scheme, request.site.domain)
|
||||
|
||||
|
||||
def absolute_url(request, url):
|
||||
|
@ -56,19 +56,18 @@ def uri(request):
|
|||
|
||||
def form_encoded_response(content):
|
||||
return HttpResponse(
|
||||
urlencode(content),
|
||||
content_type='application/x-www-form-urlencoded'
|
||||
urlencode(content), content_type="application/x-www-form-urlencoded"
|
||||
)
|
||||
|
||||
|
||||
REPS = {
|
||||
'application/x-www-form-urlencoded': form_encoded_response,
|
||||
'application/json': JsonResponse,
|
||||
"application/x-www-form-urlencoded": form_encoded_response,
|
||||
"application/json": JsonResponse,
|
||||
}
|
||||
|
||||
|
||||
def choose_type(request, content, reps=REPS):
|
||||
accept = request.META.get('HTTP_ACCEPT', '*/*')
|
||||
accept = request.META.get("HTTP_ACCEPT", "*/*")
|
||||
type = get_best_match(accept, reps.keys())
|
||||
if type:
|
||||
return reps[type](content)
|
||||
|
@ -76,11 +75,11 @@ def choose_type(request, content, reps=REPS):
|
|||
|
||||
|
||||
def bad_req(message):
|
||||
return HttpResponseBadRequest(message, content_type='text/plain')
|
||||
return HttpResponseBadRequest(message, content_type="text/plain")
|
||||
|
||||
|
||||
def forbid(message):
|
||||
return HttpResponseForbidden(message, content_type='text/plain')
|
||||
return HttpResponseForbidden(message, content_type="text/plain")
|
||||
|
||||
|
||||
def to_plain(md):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue