Run Black over the whole codebase

This commit is contained in:
Danielle McLean 2023-08-10 16:52:37 +10:00
parent cd990e4e2f
commit 2e7d12b3e6
Signed by untrusted user: 00dani
GPG key ID: 52C059C3B22A753E
109 changed files with 1539 additions and 1209 deletions

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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,))

View file

@ -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

View file

@ -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

View file

@ -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")

View file

@ -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"}}

View file

@ -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/"

View file

@ -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"

View file

@ -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")

View file

@ -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)

View file

@ -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()

View file

@ -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))

View file

@ -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"),
}

View file

@ -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()

View file

@ -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

View file

@ -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"

View file

@ -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")]

View file

@ -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)),)

View file

@ -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):