Format code using black

This commit is contained in:
Rodolphe Breard 2019-07-24 19:07:41 +02:00
parent 7f1e07503a
commit c15512e799
29 changed files with 412 additions and 475 deletions

View file

@ -1,7 +1,9 @@
from django.contrib import admin from django.contrib import admin
from .models import LogSource from .models import LogSource
class LogSourceAdmin(admin.ModelAdmin): class LogSourceAdmin(admin.ModelAdmin):
list_display = ('name', 'slug', 'hidden') list_display = ("name", "slug", "hidden")
admin.site.register(LogSource, LogSourceAdmin) admin.site.register(LogSource, LogSourceAdmin)

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class LogsConfig(AppConfig): class LogsConfig(AppConfig):
name = 'chat' name = "chat"

View file

@ -7,8 +7,8 @@ import datetime
class SearchForm(forms.Form): class SearchForm(forms.Form):
source = forms.CharField(max_length=128) source = forms.CharField(max_length=128)
date = forms.DateField( date = forms.DateField(
label=_('date'), label=_("date"),
initial=datetime.date.today(), initial=datetime.date.today(),
widget=DateInput(format='%Y-%m-%d'), widget=DateInput(format="%Y-%m-%d"),
input_formats=['%Y-%m-%d'], input_formats=["%Y-%m-%d"],
) )

View file

@ -3,7 +3,7 @@ from chat.models import Entry
class Command(BaseCommand): class Command(BaseCommand):
help = 'Generates the CSS files used by Pygments' help = "Generates the CSS files used by Pygments"
def handle(self, *args, **options): def handle(self, *args, **options):
for e in Entry.objects.all(): for e in Entry.objects.all():

View file

@ -3,22 +3,20 @@ from . import views
urlpatterns = [ urlpatterns = [
path('', views.chat_view, name='chat'), path("", views.chat_view, name="chat"),
path('logs/', views.LogEntriesView.as_view(), name='log_index'), path("logs/", views.LogEntriesView.as_view(), name="log_index"),
path( path(
'logs/<slug:source>/<int:year>/<int:month>/<int:day>/', "logs/<slug:source>/<int:year>/<int:month>/<int:day>/",
views.LogEntriesView.as_view(), views.LogEntriesView.as_view(),
name='log_day' name="log_day",
), ),
path( path(
'logs/switch/source/<int:pk>/', "logs/switch/source/<int:pk>/",
views.switch_log_source, views.switch_log_source,
name='log_switch_source' name="log_switch_source",
), ),
path( path(
'logs/switch/entry/<int:pk>/', "logs/switch/entry/<int:pk>/", views.switch_log_entry, name="log_switch_entry"
views.switch_log_entry,
name='log_switch_entry'
), ),
path('logs/search/', views.log_search_view, name='log_search'), path("logs/search/", views.log_search_view, name="log_search"),
] ]

View file

@ -15,22 +15,19 @@ import datetime
def chat_view(request): def chat_view(request):
ctx = { ctx = {
'debug': settings.DEBUG, "debug": settings.DEBUG,
'bosh_url': settings.KHAGANAT_XMPP_BOSH_URL, "bosh_url": settings.KHAGANAT_XMPP_BOSH_URL,
'jid': settings.KHAGANAT_XMPP_JID, "jid": settings.KHAGANAT_XMPP_JID,
'rooms': settings.KHAGANAT_XMPP_ROOMS, "rooms": settings.KHAGANAT_XMPP_ROOMS,
'websocket_url': settings.KHAGANAT_XMPP_WEBSOCKET_URL, "websocket_url": settings.KHAGANAT_XMPP_WEBSOCKET_URL,
} }
return render(request, 'chat/chat_conversejs.html', ctx) return render(request, "chat/chat_conversejs.html", ctx)
def _get_dates(): def _get_dates():
now = datetime.date.today() now = datetime.date.today()
start_date = now - datetime.timedelta( start_date = now - datetime.timedelta(days=settings.KHAGANAT_LOGS_MAX_DAYS)
days=settings.KHAGANAT_LOGS_MAX_DAYS end_date = now - datetime.timedelta(days=settings.KHAGANAT_LOGS_MIN_DAYS - 1)
)
end_date = now - datetime.timedelta(
days=settings.KHAGANAT_LOGS_MIN_DAYS - 1
)
return (now, start_date, end_date) return (now, start_date, end_date)
@ -39,9 +36,9 @@ def _switch_hidden(request, obj, pk):
e.hidden = not e.hidden e.hidden = not e.hidden
e.save() e.save()
next_page = request.GET.get('next', '/') next_page = request.GET.get("next", "/")
if not is_link_legit(next_page): if not is_link_legit(next_page):
next_page = reverse('log_index') next_page = reverse("log_index")
return redirect(next_page) return redirect(next_page)
@ -56,22 +53,27 @@ def switch_log_entry(request, pk):
def log_search_view(request): def log_search_view(request):
if request.method == 'POST': if request.method == "POST":
form = SearchForm(request.POST) form = SearchForm(request.POST)
if form.is_valid(): if form.is_valid():
date = form.cleaned_data['date'] date = form.cleaned_data["date"]
return redirect(reverse('log_day', kwargs={ return redirect(
'source': form.cleaned_data['source'], reverse(
'year': date.year, "log_day",
'month': date.month, kwargs={
'day': date.day, "source": form.cleaned_data["source"],
})) "year": date.year,
raise Http404('No search parameters.') "month": date.month,
"day": date.day,
},
)
)
raise Http404("No search parameters.")
class LogEntriesView(generic.ListView): class LogEntriesView(generic.ListView):
template_name = 'chat/entries.html' template_name = "chat/entries.html"
context_object_name = 'entries' context_object_name = "entries"
filter_nsfw = False filter_nsfw = False
def is_nsfw(self): def is_nsfw(self):
@ -93,17 +95,17 @@ class LogEntriesView(generic.ListView):
"""Return the date object corresponding to the URL parameters """Return the date object corresponding to the URL parameters
or None if missing. or None if missing.
""" """
has_date = all([ has_date = all(
self.kwargs.get('year') is not None, [
self.kwargs.get('month') is not None, self.kwargs.get("year") is not None,
self.kwargs.get('day') is not None, self.kwargs.get("month") is not None,
]) self.kwargs.get("day") is not None,
]
)
if not has_date: if not has_date:
return None return None
return datetime.date( return datetime.date(
self.kwargs['year'], self.kwargs["year"], self.kwargs["month"], self.kwargs["day"]
self.kwargs['month'],
self.kwargs['day']
) )
def get_dates(self, source): def get_dates(self, source):
@ -114,26 +116,22 @@ class LogEntriesView(generic.ListView):
nb_max = settings.KHAGANAT_LOGS_MAX_DAYS nb_max = settings.KHAGANAT_LOGS_MAX_DAYS
nb_max -= settings.KHAGANAT_LOGS_MIN_DAYS nb_max -= settings.KHAGANAT_LOGS_MIN_DAYS
lst = LogEntry.objects.filter( lst = LogEntry.objects.filter(source=source)
source=source,
)
if not self.request.user.is_staff: if not self.request.user.is_staff:
lst = lst.filter( lst = lst.filter(hidden=False, created__range=(start_date, end_date))
hidden=False, lst = (
created__range=(start_date, end_date) lst.annotate(date=TruncDate("created"))
) .values("date")
lst = lst.annotate( .annotate(nb=Count("date"))
date=TruncDate('created') .order_by("-date")[:nb_max]
).values('date').annotate( )
nb=Count('date') return [o["date"] for o in lst]
).order_by('-date')[:nb_max]
return [o['date'] for o in lst]
def get_source(self): def get_source(self):
"""Return the current source.""" """Return the current source."""
if self.kwargs.get('source') is None: if self.kwargs.get("source") is None:
return None return None
return LogSource.objects.get(slug=self.kwargs['source']) return LogSource.objects.get(slug=self.kwargs["source"])
def get_sources(self): def get_sources(self):
"""Return available sources.""" """Return available sources."""
@ -144,32 +142,29 @@ class LogEntriesView(generic.ListView):
qs = qs.filter( qs = qs.filter(
hidden=False, hidden=False,
source__hidden=False, source__hidden=False,
created__range=(start_date, end_date) created__range=(start_date, end_date),
) )
qs = qs.values( qs = qs.values(
'source', 'source__name', 'source__slug', "source", "source__name", "source__slug", "source__id", "source__hidden"
'source__id', 'source__hidden' ).annotate(nb=Count("id"))
).annotate(
nb=Count('id')
)
out = [] out = []
for src in qs: for src in qs:
dts = self.get_dates(src['source']) dts = self.get_dates(src["source"])
src['first_date'] = dts[0] if dts else None src["first_date"] = dts[0] if dts else None
out.append(src) out.append(src)
return out return out
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['form'] = SearchForm() context["form"] = SearchForm()
context['sources'] = self.get_sources() context["sources"] = self.get_sources()
context['current_source'] = self.get_source() context["current_source"] = self.get_source()
context['dates'] = self.get_dates(context['current_source']) context["dates"] = self.get_dates(context["current_source"])
context['current_date'] = self.get_date() context["current_date"] = self.get_date()
context['filter_nsfw'] = self.filter_nsfw context["filter_nsfw"] = self.filter_nsfw
context['current_url'] = self.request.get_full_path() context["current_url"] = self.request.get_full_path()
return context return context
def get_queryset(self): def get_queryset(self):
@ -180,10 +175,12 @@ class LogEntriesView(generic.ListView):
is_staff = self.request.user.is_staff is_staff = self.request.user.is_staff
now = datetime.date.today() now = datetime.date.today()
out_of_bounds = any(( out_of_bounds = any(
(now - dt).days > settings.KHAGANAT_LOGS_MAX_DAYS, (
(now - dt).days < settings.KHAGANAT_LOGS_MIN_DAYS, (now - dt).days > settings.KHAGANAT_LOGS_MAX_DAYS,
)) (now - dt).days < settings.KHAGANAT_LOGS_MIN_DAYS,
)
)
if out_of_bounds and not is_staff: if out_of_bounds and not is_staff:
return LogEntry.objects.none() return LogEntry.objects.none()
src = self.get_source() src = self.get_source()
@ -191,14 +188,11 @@ class LogEntriesView(generic.ListView):
return LogEntry.objects.none() return LogEntry.objects.none()
if src.hidden and not is_staff: if src.hidden and not is_staff:
return LogEntry.objects.none() return LogEntry.objects.none()
qs = LogEntry.objects.filter( qs = (
source=src, LogEntry.objects.filter(source=src, created__year=dt.year)
created__year=dt.year .filter(created__month=dt.month)
).filter( .filter(created__day=dt.day)
created__month=dt.month,
).filter(
created__day=dt.day
) )
if not is_staff: if not is_staff:
qs = qs.filter(hidden=False) qs = qs.filter(hidden=False)
return qs.order_by('created') return qs.order_by("created")

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class KhaganatConfig(AppConfig): class KhaganatConfig(AppConfig):
name = 'khaganat' name = "khaganat"

View file

@ -24,73 +24,73 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret! # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = config('KHAGANAT_SECRET_KEY') SECRET_KEY = config("KHAGANAT_SECRET_KEY")
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = config('KHAGANAT_DEBUG', default=False, cast=bool) DEBUG = config("KHAGANAT_DEBUG", default=False, cast=bool)
ALLOWED_HOSTS = config('KHAGANAT_HOSTNAMES', default='', cast=Csv()) ALLOWED_HOSTS = config("KHAGANAT_HOSTNAMES", default="", cast=Csv())
INTERNAL_IPS = config('KHAGANAT_INTERNAL_IPS', default='127.0.0.1,::1', cast=Csv()) INTERNAL_IPS = config("KHAGANAT_INTERNAL_IPS", default="127.0.0.1,::1", cast=Csv())
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
'django.contrib.admin', "django.contrib.admin",
'django.contrib.auth', "django.contrib.auth",
'django.contrib.contenttypes', "django.contrib.contenttypes",
'django.contrib.sessions', "django.contrib.sessions",
'django.contrib.messages', "django.contrib.messages",
'bulma', "bulma",
'chat.apps.LogsConfig', "chat.apps.LogsConfig",
'khaganat.apps.KhaganatConfig', "khaganat.apps.KhaganatConfig",
'navbar.apps.NavbarConfig', "navbar.apps.NavbarConfig",
'neluser.apps.NeluserConfig', "neluser.apps.NeluserConfig",
'npb.apps.NpbConfig', "npb.apps.NpbConfig",
'nsfw.apps.NsfwConfig', "nsfw.apps.NsfwConfig",
'pages.apps.PagesConfig', "pages.apps.PagesConfig",
'static_extra.apps.KhaganatStaticFilesConfig', "static_extra.apps.KhaganatStaticFilesConfig",
] ]
MIDDLEWARE = [ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', "django.middleware.security.SecurityMiddleware",
'django.contrib.sessions.middleware.SessionMiddleware', "django.contrib.sessions.middleware.SessionMiddleware",
'django.middleware.locale.LocaleMiddleware', "django.middleware.locale.LocaleMiddleware",
'django.middleware.common.CommonMiddleware', "django.middleware.common.CommonMiddleware",
'django.middleware.csrf.CsrfViewMiddleware', "django.middleware.csrf.CsrfViewMiddleware",
'django.contrib.auth.middleware.AuthenticationMiddleware', "django.contrib.auth.middleware.AuthenticationMiddleware",
'django.contrib.messages.middleware.MessageMiddleware', "django.contrib.messages.middleware.MessageMiddleware",
'django.middleware.clickjacking.XFrameOptionsMiddleware', "django.middleware.clickjacking.XFrameOptionsMiddleware",
] ]
ROOT_URLCONF = 'khaganat.urls' ROOT_URLCONF = "khaganat.urls"
TEMPLATES = [ TEMPLATES = [
{ {
'BACKEND': 'django.template.backends.django.DjangoTemplates', "BACKEND": "django.template.backends.django.DjangoTemplates",
'DIRS': [], "DIRS": [],
'APP_DIRS': True, "APP_DIRS": True,
'OPTIONS': { "OPTIONS": {
'context_processors': [ "context_processors": [
'django.template.context_processors.debug', "django.template.context_processors.debug",
'django.template.context_processors.request', "django.template.context_processors.request",
'django.contrib.auth.context_processors.auth', "django.contrib.auth.context_processors.auth",
'django.contrib.messages.context_processors.messages', "django.contrib.messages.context_processors.messages",
], ]
}, },
}, }
] ]
WSGI_APPLICATION = 'khaganat.wsgi.application' WSGI_APPLICATION = "khaganat.wsgi.application"
# Database # Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases # https://docs.djangoproject.com/en/2.0/ref/settings/#databases
DATABASES = { DATABASES = {
'default': { "default": {
'ENGINE': 'django.db.backends.sqlite3', "ENGINE": "django.db.backends.sqlite3",
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), "NAME": os.path.join(BASE_DIR, "db.sqlite3"),
} }
} }
@ -98,32 +98,27 @@ DATABASES = {
# Emailing # Emailing
# https://docs.djangoproject.com/fr/2.0/topics/email/ # https://docs.djangoproject.com/fr/2.0/topics/email/
EMAIL_HOST = config('KHAGANAT_EMAIL_HOST', default='localhost') EMAIL_HOST = config("KHAGANAT_EMAIL_HOST", default="localhost")
EMAIL_PORT = config('KHAGANAT_EMAIL_PORT', default=25, cast=int) EMAIL_PORT = config("KHAGANAT_EMAIL_PORT", default=25, cast=int)
EMAIL_HOST_USER = config('KHAGANAT_EMAIL_HOST_USER', default='') EMAIL_HOST_USER = config("KHAGANAT_EMAIL_HOST_USER", default="")
EMAIL_HOST_PASSWORD = config('KHAGANAT_EMAIL_HOST_PASSWORD', default='') EMAIL_HOST_PASSWORD = config("KHAGANAT_EMAIL_HOST_PASSWORD", default="")
EMAIL_USE_TLS = config('KHAGANAT_EMAIL_USE_STARTTLS', default=False, cast=bool) EMAIL_USE_TLS = config("KHAGANAT_EMAIL_USE_STARTTLS", default=False, cast=bool)
EMAIL_USE_SSL = config('KHAGANAT_EMAIL_USE_TLS', default=False, cast=bool) EMAIL_USE_SSL = config("KHAGANAT_EMAIL_USE_TLS", default=False, cast=bool)
EMAIL_SUBJECT_PREFIX = config('KHAGANAT_EMAIL_SUBJECT_PREFIX', default='') EMAIL_SUBJECT_PREFIX = config("KHAGANAT_EMAIL_SUBJECT_PREFIX", default="")
DEFAULT_FROM_EMAIL = config( DEFAULT_FROM_EMAIL = config("KHAGANAT_DEFAULT_FROM_EMAIL", default="no-reply@localhost")
'KHAGANAT_DEFAULT_FROM_EMAIL',
default='no-reply@localhost'
)
# User model # User model
# https://docs.djangoproject.com/en/2.0/topics/auth/customizing/ # https://docs.djangoproject.com/en/2.0/topics/auth/customizing/
AUTH_USER_MODEL = 'neluser.NelUser' AUTH_USER_MODEL = "neluser.NelUser"
LOGIN_URL = reverse_lazy('login') LOGIN_URL = reverse_lazy("login")
LOGIN_REDIRECT_URL = reverse_lazy( LOGIN_REDIRECT_URL = reverse_lazy(
config('KHAGANAT_LOGIN_REDIRECT_URL', default='index') config("KHAGANAT_LOGIN_REDIRECT_URL", default="index")
) )
REGISTER_REQUIRE_VALIDATION = config( REGISTER_REQUIRE_VALIDATION = config(
'KHAGANAT_REGISTER_REQUIRE_VALIDATION', "KHAGANAT_REGISTER_REQUIRE_VALIDATION", default=True, cast=bool
default=True,
cast=bool
) )
@ -132,33 +127,24 @@ REGISTER_REQUIRE_VALIDATION = config(
AUTH_PASSWORD_VALIDATORS = [ AUTH_PASSWORD_VALIDATORS = [
{ {
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', "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',
}, },
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
] ]
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/ # https://docs.djangoproject.com/en/2.0/topics/i18n/
LANGUAGE_CODE = config('KHAGANAT_LANGUAGE_CODE', default='fr') LANGUAGE_CODE = config("KHAGANAT_LANGUAGE_CODE", default="fr")
# https://github.com/django/django/blob/master/django/conf/global_settings.py # https://github.com/django/django/blob/master/django/conf/global_settings.py
LANGUAGES = [ LANGUAGES = [("en", _("English")), ("fr", _("French"))]
('en', _('English')),
('fr', _('French')),
]
TIME_ZONE = config('KHAGANAT_TIME_ZONE', default='Europe/Paris') TIME_ZONE = config("KHAGANAT_TIME_ZONE", default="Europe/Paris")
USE_I18N = True USE_I18N = True
@ -170,36 +156,36 @@ USE_TZ = True
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/ # https://docs.djangoproject.com/en/2.0/howto/static-files/
STATIC_URL = config('KHAGANAT_STATIC_URL', default='/static/') STATIC_URL = config("KHAGANAT_STATIC_URL", default="/static/")
STATIC_ROOT = config('KHAGANAT_STATIC_ROOT', default='') or None STATIC_ROOT = config("KHAGANAT_STATIC_ROOT", default="") or None
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static_extra')] STATICFILES_DIRS = [os.path.join(BASE_DIR, "static_extra")]
STATICFILES_DIRS += config('KHAGANAT_STATIC_DIRS', default='', cast=Csv()) or [] STATICFILES_DIRS += config("KHAGANAT_STATIC_DIRS", default="", cast=Csv()) or []
# Logs configuration # Logs configuration
KHAGANAT_LOGS_MIN_DAYS = config('KHAGANAT_LOGS_MIN_DAYS', default=0, cast=int) KHAGANAT_LOGS_MIN_DAYS = config("KHAGANAT_LOGS_MIN_DAYS", default=0, cast=int)
KHAGANAT_LOGS_MAX_DAYS = config('KHAGANAT_LOGS_MAX_DAYS', default=7, cast=int) KHAGANAT_LOGS_MAX_DAYS = config("KHAGANAT_LOGS_MAX_DAYS", default=7, cast=int)
# TLS # TLS
# https://docs.djangoproject.com/fr/2.0/ref/settings/#std:setting-SECURE_PROXY_SSL_HEADER # https://docs.djangoproject.com/fr/2.0/ref/settings/#std:setting-SECURE_PROXY_SSL_HEADER
if config('KHAGANAT_FORCE_HTTPS', default=False, cast=bool): if config("KHAGANAT_FORCE_HTTPS", default=False, cast=bool):
SECURE_PROXY_SSL_HEADER = ( SECURE_PROXY_SSL_HEADER = (
config('KHAGANAT_HTTPS_HEADER_NAME', default='HTTP_X_FORWARDED_PROTO'), config("KHAGANAT_HTTPS_HEADER_NAME", default="HTTP_X_FORWARDED_PROTO"),
config('KHAGANAT_HTTPS_HEADER_VALUE', default='https') config("KHAGANAT_HTTPS_HEADER_VALUE", default="https"),
) )
# NSFW # NSFW
KHAGANAT_NSFW_TAGS = config('KHAGANAT_NSFW_TAGS', default='\\#nsfw', cast=Csv()) KHAGANAT_NSFW_TAGS = config("KHAGANAT_NSFW_TAGS", default="\\#nsfw", cast=Csv())
KHAGANAT_NSFW_NAME = config('KHAGANAT_NSFW_NAME', default='nsfw_allowed') KHAGANAT_NSFW_NAME = config("KHAGANAT_NSFW_NAME", default="nsfw_allowed")
KHAGANAT_NSFW_OK = ('y', 'yes', 't', 'true', '1') KHAGANAT_NSFW_OK = ("y", "yes", "t", "true", "1")
# Converse.js # Converse.js
KHAGANAT_XMPP_BOSH_URL = config('KHAGANAT_XMPP_BOSH_URL', default='') or None KHAGANAT_XMPP_BOSH_URL = config("KHAGANAT_XMPP_BOSH_URL", default="") or None
KHAGANAT_XMPP_JID = config('KHAGANAT_XMPP_JID', default='') or None KHAGANAT_XMPP_JID = config("KHAGANAT_XMPP_JID", default="") or None
KHAGANAT_XMPP_ROOMS = config('KHAGANAT_XMPP_ROOMS', default='', cast=Csv()) or [] KHAGANAT_XMPP_ROOMS = config("KHAGANAT_XMPP_ROOMS", default="", cast=Csv()) or []
KHAGANAT_XMPP_WEBSOCKET_URL = config('KHAGANAT_XMPP_WEBSOCKET_URL', default='') or None KHAGANAT_XMPP_WEBSOCKET_URL = config("KHAGANAT_XMPP_WEBSOCKET_URL", default="") or None

View file

@ -19,16 +19,14 @@ from django.contrib import admin
from django.urls import include, path from django.urls import include, path
from pages.views import index from pages.views import index
urlpatterns = [ urlpatterns = [path("", index)]
path('', index),
]
urlpatterns += i18n_patterns( urlpatterns += i18n_patterns(
path('', index), path("", index),
path('admin/', admin.site.urls), path("admin/", admin.site.urls),
path('account/', include('neluser.urls')), path("account/", include("neluser.urls")),
path('page/', include('pages.urls')), path("page/", include("pages.urls")),
path('paste/', include('npb.urls', namespace='npb')), path("paste/", include("npb.urls", namespace="npb")),
path('chat/', include('chat.urls')), path("chat/", include("chat.urls")),
path('nsfw/', include('nsfw.urls')), path("nsfw/", include("nsfw.urls")),
) )

View file

@ -6,10 +6,8 @@ from .models import Element, ElementDescription, ElementSeparator
class ElementDescriptionAdminForm(forms.ModelForm): class ElementDescriptionAdminForm(forms.ModelForm):
class Meta: class Meta:
model = ElementDescription model = ElementDescription
widgets = { widgets = {"description": forms.widgets.Textarea}
'description': forms.widgets.Textarea, fields = "__all__"
}
fields = '__all__'
class ElementDescriptionInline(admin.StackedInline): class ElementDescriptionInline(admin.StackedInline):
@ -19,8 +17,8 @@ class ElementDescriptionInline(admin.StackedInline):
class ElementAdmin(admin.ModelAdmin): class ElementAdmin(admin.ModelAdmin):
list_display = ('__str__', 'parent', 'link', 'weight') list_display = ("__str__", "parent", "link", "weight")
ordering = ('parent', 'weight') ordering = ("parent", "weight")
inlines = [ElementDescriptionInline] inlines = [ElementDescriptionInline]

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class NavbarConfig(AppConfig): class NavbarConfig(AppConfig):
name = 'navbar' name = "navbar"

View file

@ -6,72 +6,70 @@ import os
class Command(BaseCommand): class Command(BaseCommand):
help = 'Generates the CSS files used by Pygments' help = "Generates the CSS files used by Pygments"
def export_static(self, curr_lang): def export_static(self, curr_lang):
self.stdout.write('Plain HTML export for language %s' % curr_lang) self.stdout.write("Plain HTML export for language %s" % curr_lang)
output_dir = os.path.join(self.export_dir, 'html') output_dir = os.path.join(self.export_dir, "html")
output_file = 'khanav_%s.html' % curr_lang output_file = "khanav_%s.html" % curr_lang
os.makedirs(output_dir, mode=0o755, exist_ok=True) os.makedirs(output_dir, mode=0o755, exist_ok=True)
with open(os.path.join(output_dir, output_file), 'w') as f: with open(os.path.join(output_dir, output_file), "w") as f:
ctx = get_base_context(curr_lang, '/') ctx = get_base_context(curr_lang, "/")
html = render_to_string('navbar/navbar.html', ctx) html = render_to_string("navbar/navbar.html", ctx)
f.write(html) f.write(html)
def export_docuwiki(self, langs): def export_docuwiki(self, langs):
self.stdout.write( self.stdout.write("Docuwiki export for languages %s" % ", ".join(langs))
'Docuwiki export for languages %s' % ', '.join(langs)
)
output_langs = [] output_langs = []
for lang in langs: for lang in langs:
ctx = get_base_context(lang, '/') ctx = get_base_context(lang, "/")
output_langs.append({ output_langs.append(
'name': lang, {"name": lang, "html": render_to_string("navbar/navbar.html", ctx)}
'html': render_to_string('navbar/navbar.html', ctx) )
}) output_dir = os.path.join(self.export_dir, "docuwiki")
output_dir = os.path.join(self.export_dir, 'docuwiki')
os.makedirs(output_dir, mode=0o755, exist_ok=True) os.makedirs(output_dir, mode=0o755, exist_ok=True)
with open(os.path.join(output_dir, 'khanav.php'), 'w') as f: with open(os.path.join(output_dir, "khanav.php"), "w") as f:
f.write(render_to_string('navbar/export_docuwiki.html', { f.write(
'output_langs': output_langs render_to_string(
})) "navbar/export_docuwiki.html", {"output_langs": output_langs}
)
)
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument( parser.add_argument(
'--dir', '-d', "--dir",
help='Export directory.', "-d",
default=os.path.join(settings.BASE_DIR, 'build/navbar'), help="Export directory.",
dest='export_dir' default=os.path.join(settings.BASE_DIR, "build/navbar"),
dest="export_dir",
) )
parser.add_argument( parser.add_argument(
'--lang', '-l', "--lang", "-l", help="Language to export.", action="append", dest="langs"
help='Language to export.',
action='append',
dest='langs'
) )
parser.add_argument( parser.add_argument(
'--plain', '--html', "--plain",
help='Export for plain HTML.', "--html",
action='store_true', help="Export for plain HTML.",
dest='static' action="store_true",
dest="static",
) )
parser.add_argument( parser.add_argument(
'--docuwiki', "--docuwiki",
help='Export for docuwiki.', help="Export for docuwiki.",
action='store_true', action="store_true",
dest='docuwiki' dest="docuwiki",
) )
def handle(self, *args, **options): def handle(self, *args, **options):
if options['langs'] is None: if options["langs"] is None:
raise CommandError('No language specified.') raise CommandError("No language specified.")
if 'all' in options['langs']: if "all" in options["langs"]:
options['langs'] = [name for name, _ in settings.LANGUAGES] options["langs"] = [name for name, _ in settings.LANGUAGES]
self.export_dir = options['export_dir'] self.export_dir = options["export_dir"]
if options['static']: if options["static"]:
for lang in options['langs']: for lang in options["langs"]:
self.export_static(lang) self.export_static(lang)
if options['docuwiki']: if options["docuwiki"]:
self.export_docuwiki(options['langs']) self.export_docuwiki(options["langs"])
self.stdout.write(self.style.SUCCESS('Ok.')) self.stdout.write(self.style.SUCCESS("Ok."))

View file

@ -6,44 +6,35 @@ import os
class Element(models.Model): class Element(models.Model):
parent = models.ForeignKey( parent = models.ForeignKey(
'Element', "Element",
on_delete=models.CASCADE, on_delete=models.CASCADE,
null=True, null=True,
blank=True, blank=True,
limit_choices_to={'parent': None} limit_choices_to={"parent": None},
) )
link = models.CharField(max_length=512, blank=True) link = models.CharField(max_length=512, blank=True)
new_window = models.BooleanField(default=False) new_window = models.BooleanField(default=False)
add_locale = models.BooleanField(default=False) add_locale = models.BooleanField(default=False)
icon = models.FilePathField( icon = models.FilePathField(
path='navbar/static/navbar/icons', path="navbar/static/navbar/icons", match=".png", null=True, blank=True
match=".png",
null=True,
blank=True
) )
weight = models.PositiveSmallIntegerField() weight = models.PositiveSmallIntegerField()
def icon_path(self): def icon_path(self):
return os.path.join('navbar/icons', os.path.basename(self.icon)) return os.path.join("navbar/icons", os.path.basename(self.icon))
def children(self): def children(self):
return sorted( return sorted(
list(Element.objects.filter(parent=self.id).order_by('weight')) + list(Element.objects.filter(parent=self.id).order_by("weight"))
list( + list(ElementSeparator.objects.filter(parent=self.id).order_by("weight")),
ElementSeparator.objects.filter(parent=self.id) key=lambda c: c.weight,
.order_by('weight')
),
key=lambda c: c.weight
) )
def description(self): def description(self):
lang = get_language() lang = get_language()
if lang is None: if lang is None:
lang = settings.LANGUAGE_CODE lang = settings.LANGUAGE_CODE
return ElementDescription.objects.filter( return ElementDescription.objects.filter(element=self.id, language=lang).first()
element=self.id,
language=lang
).first()
def localized_link(self): def localized_link(self):
link = self.link link = self.link
@ -71,9 +62,7 @@ class ElementDescription(models.Model):
class ElementSeparator(models.Model): class ElementSeparator(models.Model):
parent = models.ForeignKey( parent = models.ForeignKey(
Element, Element, on_delete=models.CASCADE, limit_choices_to={"parent": None}
on_delete=models.CASCADE,
limit_choices_to={'parent': None}
) )
weight = models.PositiveSmallIntegerField() weight = models.PositiveSmallIntegerField()
@ -81,4 +70,4 @@ class ElementSeparator(models.Model):
return True return True
def __str__(self): def __str__(self):
return '{} ({})'.format(self.parent, self.weight) return "{} ({})".format(self.parent, self.weight)

View file

@ -13,46 +13,39 @@ import re
register = template.Library() register = template.Library()
path_re = re.compile('^(/[a-z]+)/(.*)') path_re = re.compile("^(/[a-z]+)/(.*)")
def get_lang_name(lang_code): def get_lang_name(lang_code):
li = get_language_info(lang_code) li = get_language_info(lang_code)
return li['name_local'] return li["name_local"]
def get_lang_data(path_info, lang_code, curr_lang): def get_lang_data(path_info, lang_code, curr_lang):
lang_name = get_lang_name(lang_code) lang_name = get_lang_name(lang_code)
rm = resolve(path_info) rm = resolve(path_info)
activate_lang(lang_code) activate_lang(lang_code)
lang_url = reverse( lang_url = reverse(rm.view_name, current_app="npb", args=rm.args, kwargs=rm.kwargs)
rm.view_name,
current_app='npb',
args=rm.args,
kwargs=rm.kwargs
)
activate_lang(curr_lang) activate_lang(curr_lang)
return (lang_code, lang_name, lang_url) return (lang_code, lang_name, lang_url)
def get_base_context(lang, url): def get_base_context(lang, url):
return { return {
'user': None, "user": None,
'current_url': url, "current_url": url,
'elems': Element.objects.filter(parent=None).order_by('weight'), "elems": Element.objects.filter(parent=None).order_by("weight"),
'current_lang_code': lang, "current_lang_code": lang,
'current_lang_name': get_lang_name(lang), "current_lang_name": get_lang_name(lang),
'all_langs': [ "all_langs": [get_lang_data(url, l[0], lang) for l in settings.LANGUAGES],
get_lang_data(url, l[0], lang) for l in settings.LANGUAGES
],
} }
@register.simple_tag(takes_context=True) @register.simple_tag(takes_context=True)
def navbar(context): def navbar(context):
request = context['request'] request = context["request"]
curr_lang = get_language() curr_lang = get_language()
ctx = get_base_context(curr_lang, request.path_info) ctx = get_base_context(curr_lang, request.path_info)
ctx['user'] = request.user ctx["user"] = request.user
tpl = TemplateResponse(request, 'navbar/navbar.html', context=ctx).render() tpl = TemplateResponse(request, "navbar/navbar.html", context=ctx).render()
return mark_safe(tpl.rendered_content) return mark_safe(tpl.rendered_content)

View file

@ -5,16 +5,26 @@ from .views import send_activation_email
class NelUserAdmin(admin.ModelAdmin): class NelUserAdmin(admin.ModelAdmin):
list_display = ('email', 'date_joined', 'last_login', 'is_active', 'is_staff', 'is_superuser') list_display = (
readonly_fields = ('date_joined', 'last_login') "email",
list_filter = ('is_active', 'is_staff', 'is_superuser') "date_joined",
search_fields = ('email', ) "last_login",
"is_active",
"is_staff",
"is_superuser",
)
readonly_fields = ("date_joined", "last_login")
list_filter = ("is_active", "is_staff", "is_superuser")
search_fields = ("email",)
fieldsets = [ fieldsets = [
(_('info'), {'fields': ['is_active', 'email', 'date_joined', 'last_login']}), (_("info"), {"fields": ["is_active", "email", "date_joined", "last_login"]}),
(_('user_permissions'), {'fields': ['is_staff', 'is_superuser', 'groups', 'user_permissions']}), (
(_('misc'), {'fields': ['nsfw_allowed']}), _("user_permissions"),
{"fields": ["is_staff", "is_superuser", "groups", "user_permissions"]},
),
(_("misc"), {"fields": ["nsfw_allowed"]}),
] ]
actions = ['resend_activation_link'] actions = ["resend_activation_link"]
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):
super().save_model(request, obj, form, change) super().save_model(request, obj, form, change)
@ -24,6 +34,8 @@ class NelUserAdmin(admin.ModelAdmin):
for user in queryset: for user in queryset:
if not user.is_active: if not user.is_active:
send_activation_email(request, user) send_activation_email(request, user)
resend_activation_link.short_description = _('resend_activation_link')
resend_activation_link.short_description = _("resend_activation_link")
admin.site.register(NelUser, NelUserAdmin) admin.site.register(NelUser, NelUserAdmin)

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class NeluserConfig(AppConfig): class NeluserConfig(AppConfig):
name = 'neluser' name = "neluser"

View file

@ -15,54 +15,48 @@ class RegistrationForm(UserCreationForm):
class ChangePasswordForm(forms.Form): class ChangePasswordForm(forms.Form):
current_password = forms.CharField( current_password = forms.CharField(
label=_('current_password'), label=_("current_password"), widget=forms.PasswordInput
widget=forms.PasswordInput
)
new_password = forms.CharField(
label=_('new_password'),
widget=forms.PasswordInput
) )
new_password = forms.CharField(label=_("new_password"), widget=forms.PasswordInput)
new_password_confirm = forms.CharField( new_password_confirm = forms.CharField(
label=_('new_password_confirm'), label=_("new_password_confirm"), widget=forms.PasswordInput
widget=forms.PasswordInput
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request') self.request = kwargs.pop("request")
return super().__init__(*args, **kwargs) return super().__init__(*args, **kwargs)
def clean(self): def clean(self):
cleaned_data = super().clean() cleaned_data = super().clean()
old_pass = cleaned_data.get('current_password') old_pass = cleaned_data.get("current_password")
new_pass = cleaned_data.get('new_password') new_pass = cleaned_data.get("new_password")
new_pass_confirm = cleaned_data.get('new_password_confirm') new_pass_confirm = cleaned_data.get("new_password_confirm")
user = self.request.user user = self.request.user
if new_pass != new_pass_confirm: if new_pass != new_pass_confirm:
msg = _('The new password does not match its confirmation.') msg = _("The new password does not match its confirmation.")
raise forms.ValidationError(msg) raise forms.ValidationError(msg)
try: try:
validate_password(new_pass, user=user) validate_password(new_pass, user=user)
except ValidationError as error: except ValidationError as error:
raise forms.ValidationError(error) raise forms.ValidationError(error)
if not user.check_password(old_pass): if not user.check_password(old_pass):
msg = _('The current password is incorrect.') msg = _("The current password is incorrect.")
raise forms.ValidationError(msg) raise forms.ValidationError(msg)
class DeleteAccountForm(forms.Form): class DeleteAccountForm(forms.Form):
current_password = forms.CharField( current_password = forms.CharField(
label=_('current_password'), label=_("current_password"), widget=forms.PasswordInput
widget=forms.PasswordInput
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request') self.request = kwargs.pop("request")
return super().__init__(*args, **kwargs) return super().__init__(*args, **kwargs)
def clean(self): def clean(self):
cleaned_data = super().clean() cleaned_data = super().clean()
password = cleaned_data.get('current_password') password = cleaned_data.get("current_password")
user = self.request.user user = self.request.user
if not user.check_password(password): if not user.check_password(password):
msg = _('The current password is incorrect.') msg = _("The current password is incorrect.")
raise forms.ValidationError(msg) raise forms.ValidationError(msg)

View file

@ -11,7 +11,7 @@ class NelUserManager(BaseUserManager):
def _create_user(self, email, password, **extra_fields): def _create_user(self, email, password, **extra_fields):
if not email: if not email:
raise ValueError('The given email must be set') raise ValueError("The given email must be set")
email = self.normalize_email(email) email = self.normalize_email(email)
user = self.model(email=email, **extra_fields) user = self.model(email=email, **extra_fields)
user.set_password(password) user.set_password(password)
@ -19,59 +19,56 @@ class NelUserManager(BaseUserManager):
return user return user
def create_user(self, email, password=None, **extra_fields): def create_user(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_staff', False) extra_fields.setdefault("is_staff", False)
extra_fields.setdefault('is_superuser', False) extra_fields.setdefault("is_superuser", False)
return self._create_user(email, password, **extra_fields) return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password, **extra_fields): def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True) extra_fields.setdefault("is_staff", True)
extra_fields.setdefault('is_superuser', True) extra_fields.setdefault("is_superuser", True)
extra_fields.setdefault('is_active', True) extra_fields.setdefault("is_active", True)
if extra_fields.get('is_staff') is not True: if extra_fields.get("is_staff") is not True:
raise ValueError('Superuser must have is_staff=True.') raise ValueError("Superuser must have is_staff=True.")
if extra_fields.get('is_superuser') is not True: if extra_fields.get("is_superuser") is not True:
raise ValueError('Superuser must have is_superuser=True.') raise ValueError("Superuser must have is_superuser=True.")
return self._create_user(email, password, **extra_fields) return self._create_user(email, password, **extra_fields)
class NelUser(AbstractBaseUser, PermissionsMixin): class NelUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email'), unique=True, null=True) email = models.EmailField(_("email"), unique=True, null=True)
is_staff = models.BooleanField( is_staff = models.BooleanField(
_('staff status'), _("staff status"),
default=False, default=False,
help_text=_( help_text=_("Designates whether the user can log into this admin site."),
'Designates whether the user can log into this admin site.'
),
) )
is_active = models.BooleanField( is_active = models.BooleanField(
_('active'), _("active"),
default=False, default=False,
help_text=_( help_text=_(
'Designates whether this user should be treated as active. ' "Designates whether this user should be treated as active. "
'Unselect this instead of deleting accounts.' "Unselect this instead of deleting accounts."
), ),
) )
date_joined = models.DateTimeField(_('date joined'), default=timezone.now) date_joined = models.DateTimeField(_("date joined"), default=timezone.now)
nsfw_allowed = models.BooleanField( nsfw_allowed = models.BooleanField(
_('NSFW flag'), _("NSFW flag"),
default=False, default=False,
help_text=_( help_text=_(
'Indicate whether or not adult or sensitive content should ' "Indicate whether or not adult or sensitive content should " "be displayed."
'be displayed.' ),
)
) )
objects = NelUserManager() objects = NelUserManager()
EMAIL_FIELD = 'email' EMAIL_FIELD = "email"
USERNAME_FIELD = 'email' USERNAME_FIELD = "email"
REQUIRED_FIELDS = [] REQUIRED_FIELDS = []
class Meta: class Meta:
verbose_name = _('user') verbose_name = _("user")
verbose_name_plural = _('users') verbose_name_plural = _("users")
def __str__(self): def __str__(self):
return self.email.strip() return self.email.strip()

View file

@ -6,70 +6,65 @@ from . import views
urlpatterns = [ urlpatterns = [
# Login and logout # Login and logout
path( path(
'login/', "login/",
auth_views.LoginView.as_view(template_name='neluser/login.html'), auth_views.LoginView.as_view(template_name="neluser/login.html"),
name='login' name="login",
), ),
path( path(
'logout/', "logout/",
auth_views.LogoutView.as_view(next_page=reverse_lazy('index')), auth_views.LogoutView.as_view(next_page=reverse_lazy("index")),
name='logout' name="logout",
), ),
# Account activation # Account activation
path('register/', views.register, name='register'), path("register/", views.register, name="register"),
path('activate/<uidb64>/<token>/', views.activate, name='activate'), path("activate/<uidb64>/<token>/", views.activate, name="activate"),
# Forgotten password # Forgotten password
path( path(
'forgotten_password/', "forgotten_password/",
auth_views.PasswordResetView.as_view( auth_views.PasswordResetView.as_view(
template_name='neluser/password_reset.html', template_name="neluser/password_reset.html",
email_template_name='neluser/password_reset_email.txt', email_template_name="neluser/password_reset_email.txt",
html_email_template_name='neluser/password_reset_email.html', html_email_template_name="neluser/password_reset_email.html",
subject_template_name='neluser/password_reset_email_subject.txt' subject_template_name="neluser/password_reset_email_subject.txt",
), ),
name='password_reset' name="password_reset",
), ),
path( path(
'forgotten_password/done/', "forgotten_password/done/",
auth_views.PasswordResetDoneView.as_view( auth_views.PasswordResetDoneView.as_view(
template_name='neluser/password_reset_email_sent.html' template_name="neluser/password_reset_email_sent.html"
), ),
name='password_reset_done' name="password_reset_done",
), ),
path( path(
'password/reset/<uidb64>/<token>/', "password/reset/<uidb64>/<token>/",
auth_views.PasswordResetConfirmView.as_view( auth_views.PasswordResetConfirmView.as_view(
template_name='neluser/password_reset_confirm.html' template_name="neluser/password_reset_confirm.html"
), ),
name='password_reset_confirm' name="password_reset_confirm",
), ),
path( path(
'password/reset/done/', "password/reset/done/",
auth_views.PasswordResetCompleteView.as_view( auth_views.PasswordResetCompleteView.as_view(
template_name='neluser/password_reset_done.html' template_name="neluser/password_reset_done.html"
), ),
name='password_reset_complete' name="password_reset_complete",
), ),
# -------- # --------
# Settings # Settings
# -------- # --------
path('settings/', views.settings_default, name='settings'), path("settings/", views.settings_default, name="settings"),
# Preferences # Preferences
path('settings/preferences/nsfw/', views.set_nsfw, name='set_nsfw'), path("settings/preferences/nsfw/", views.set_nsfw, name="set_nsfw"),
# Security # Security
path( path(
'settings/security/password/', "settings/security/password/",
views.ChangePasswordView.as_view(), views.ChangePasswordView.as_view(),
name='password_change' name="password_change",
), ),
path( path(
'settings/security/delete_account/', "settings/security/delete_account/",
views.DeleteAccountView.as_view(), views.DeleteAccountView.as_view(),
name='delete_account' name="delete_account",
), ),
] ]

View file

@ -21,39 +21,39 @@ from .models import NelUser
@login_required @login_required
def settings_default(request): def settings_default(request):
next_page = reverse_lazy('set_nsfw') next_page = reverse_lazy("set_nsfw")
return redirect(next_page) return redirect(next_page)
@login_required @login_required
def set_nsfw(request): def set_nsfw(request):
ctx = { ctx = {
'nsfw_allowed': is_nsfw_allowed(request), "nsfw_allowed": is_nsfw_allowed(request),
'current_url': reverse_lazy('set_nsfw'), "current_url": reverse_lazy("set_nsfw"),
'tab': 'preferences', "tab": "preferences",
'active_block': 'nsfw_filter' "active_block": "nsfw_filter",
} }
return render(request, 'neluser/settings/preferences/nsfw.html', ctx) return render(request, "neluser/settings/preferences/nsfw.html", ctx)
class ChangePasswordView(LoginRequiredMixin, FormView): class ChangePasswordView(LoginRequiredMixin, FormView):
template_name = 'neluser/settings/security/password.html' template_name = "neluser/settings/security/password.html"
form_class = ChangePasswordForm form_class = ChangePasswordForm
success_url = reverse_lazy('password_change') success_url = reverse_lazy("password_change")
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['tab'] = 'security' context["tab"] = "security"
context['active_block'] = 'password' context["active_block"] = "password"
return context return context
def get_form_kwargs(self): def get_form_kwargs(self):
kw = super().get_form_kwargs() kw = super().get_form_kwargs()
kw['request'] = self.request kw["request"] = self.request
return kw return kw
def form_valid(self, form): def form_valid(self, form):
new_password = form.cleaned_data['new_password'] new_password = form.cleaned_data["new_password"]
user = self.request.user user = self.request.user
user.set_password(new_password) user.set_password(new_password)
user.save() user.save()
@ -61,50 +61,49 @@ class ChangePasswordView(LoginRequiredMixin, FormView):
class DeleteAccountView(LoginRequiredMixin, FormView): class DeleteAccountView(LoginRequiredMixin, FormView):
template_name = 'neluser/settings/security/delete_account.html' template_name = "neluser/settings/security/delete_account.html"
form_class = DeleteAccountForm form_class = DeleteAccountForm
success_url = reverse_lazy('delete_account') success_url = reverse_lazy("delete_account")
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['tab'] = 'security' context["tab"] = "security"
context['active_block'] = 'delete_account' context["active_block"] = "delete_account"
return context return context
def get_form_kwargs(self): def get_form_kwargs(self):
kw = super().get_form_kwargs() kw = super().get_form_kwargs()
kw['request'] = self.request kw["request"] = self.request
return kw return kw
def form_valid(self, form): def form_valid(self, form):
self.request.user.delete() self.request.user.delete()
logout(self.request) logout(self.request)
messages.info(self.request, _('Your account has been deleted.')) messages.info(self.request, _("Your account has been deleted."))
return super().form_valid(form) return super().form_valid(form)
def send_activation_email(request, user): def send_activation_email(request, user):
current_site = get_current_site(request) current_site = get_current_site(request)
context = { context = {
'email': user.email, "email": user.email,
'domain': current_site.domain, "domain": current_site.domain,
'site_name': current_site.name, "site_name": current_site.name,
'uid': urlsafe_base64_encode(force_bytes(user.pk)), "uid": urlsafe_base64_encode(force_bytes(user.pk)),
'user': user, "user": user,
'token': default_token_generator.make_token(user), "token": default_token_generator.make_token(user),
'protocol': 'https' if request.is_secure() else 'http', "protocol": "https" if request.is_secure() else "http",
} }
subject = render_to_string('neluser/activate_email_subject.txt', context) subject = render_to_string("neluser/activate_email_subject.txt", context)
subject = ''.join(subject.splitlines()) subject = "".join(subject.splitlines())
email_message = EmailMultiAlternatives( email_message = EmailMultiAlternatives(
subject, subject,
render_to_string('neluser/activate_email.txt', context), render_to_string("neluser/activate_email.txt", context),
settings.DEFAULT_FROM_EMAIL, settings.DEFAULT_FROM_EMAIL,
[user.email] [user.email],
) )
email_message.attach_alternative( email_message.attach_alternative(
render_to_string('neluser/activate_email.html', context), render_to_string("neluser/activate_email.html", context), "text/html"
'text/html'
) )
email_message.send() email_message.send()
@ -115,24 +114,21 @@ def activate(request, uidb64, token):
if default_token_generator.check_token(user, token): if default_token_generator.check_token(user, token):
user.is_active = True user.is_active = True
user.save() user.save()
return render( return render(request, "neluser/activate_done.html")
request,
'neluser/activate_done.html'
)
raise Http404("Unable to activate user %d with token %s." % (uid, token)) raise Http404("Unable to activate user %d with token %s." % (uid, token))
def register(request): def register(request):
if request.method == 'GET': if request.method == "GET":
form = RegistrationForm() form = RegistrationForm()
elif request.method == 'POST': elif request.method == "POST":
form = RegistrationForm(data=request.POST) form = RegistrationForm(data=request.POST)
if form.is_valid(): if form.is_valid():
user = form.save(commit=False) user = form.save(commit=False)
user.set_password(form.cleaned_data.get('password1')) user.set_password(form.cleaned_data.get("password1"))
user.is_active = not settings.REGISTER_REQUIRE_VALIDATION user.is_active = not settings.REGISTER_REQUIRE_VALIDATION
user.save() user.save()
if settings.REGISTER_REQUIRE_VALIDATION: if settings.REGISTER_REQUIRE_VALIDATION:
send_activation_email(request, user) send_activation_email(request, user)
return render(request, 'neluser/register_done.html') return render(request, "neluser/register_done.html")
return render(request, 'neluser/register.html', {'form': form}) return render(request, "neluser/register.html", {"form": form})

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class NsfwConfig(AppConfig): class NsfwConfig(AppConfig):
name = 'nsfw' name = "nsfw"

View file

@ -4,7 +4,7 @@ from . import views
urlpatterns = [ urlpatterns = [
path('', views.warn_view, name='nsfw'), path("", views.warn_view, name="nsfw"),
path('enable/<max_age>/', views.enable_view, name='enable_nsfw'), path("enable/<max_age>/", views.enable_view, name="enable_nsfw"),
path('disable/', views.disable_view, name='disable_nsfw'), path("disable/", views.disable_view, name="disable_nsfw"),
] ]

View file

@ -13,7 +13,7 @@ def is_nsfw_allowed(request):
if isinstance(request.user, NelUser): if isinstance(request.user, NelUser):
if request.user.nsfw_allowed: if request.user.nsfw_allowed:
return True return True
s = request.COOKIES.get(settings.KHAGANAT_NSFW_NAME) or '' s = request.COOKIES.get(settings.KHAGANAT_NSFW_NAME) or ""
return s.lower() in settings.KHAGANAT_NSFW_OK return s.lower() in settings.KHAGANAT_NSFW_OK
@ -21,9 +21,9 @@ def disable_view(request):
if isinstance(request.user, NelUser): if isinstance(request.user, NelUser):
request.user.nsfw_allowed = False request.user.nsfw_allowed = False
request.user.save() request.user.save()
next_url = QueryDict(request.META.get('QUERY_STRING')).get('next') next_url = QueryDict(request.META.get("QUERY_STRING")).get("next")
if not is_link_legit(next_url): if not is_link_legit(next_url):
next_url = reverse('index') next_url = reverse("index")
response = HttpResponseRedirect(next_url) response = HttpResponseRedirect(next_url)
response.delete_cookie(settings.KHAGANAT_NSFW_NAME) response.delete_cookie(settings.KHAGANAT_NSFW_NAME)
return response return response
@ -34,64 +34,55 @@ def enable_view(request, max_age):
max_age = int(max_age) or None max_age = int(max_age) or None
except ValueError: except ValueError:
max_age = None max_age = None
next_url = QueryDict(request.META.get('QUERY_STRING')).get('next') next_url = QueryDict(request.META.get("QUERY_STRING")).get("next")
if not is_link_legit(next_url): if not is_link_legit(next_url):
next_url = reverse('index') next_url = reverse("index")
response = HttpResponseRedirect(next_url) response = HttpResponseRedirect(next_url)
if isinstance(request.user, NelUser) and not max_age: if isinstance(request.user, NelUser) and not max_age:
request.user.nsfw_allowed = True request.user.nsfw_allowed = True
request.user.save() request.user.save()
else: else:
response.set_cookie( response.set_cookie(
settings.KHAGANAT_NSFW_NAME, settings.KHAGANAT_NSFW_NAME, settings.KHAGANAT_NSFW_OK[0], max_age=max_age
settings.KHAGANAT_NSFW_OK[0],
max_age=max_age
) )
return response return response
def warn_view(request): def warn_view(request):
next_url = QueryDict(request.META.get('QUERY_STRING')).get('next') or '/' next_url = QueryDict(request.META.get("QUERY_STRING")).get("next") or "/"
if not is_link_legit(next_url): if not is_link_legit(next_url):
next_url = '/' next_url = "/"
prev_url = QueryDict(request.META.get('QUERY_STRING')).get('prev') prev_url = QueryDict(request.META.get("QUERY_STRING")).get("prev")
if not is_link_legit(prev_url): if not is_link_legit(prev_url):
prev_url = None prev_url = None
context = { context = {
'prev_url': prev_url, "prev_url": prev_url,
'go_home': True, "go_home": True,
'next_url': next_url, "next_url": next_url,
'is_authenticated': request.user.is_authenticated, "is_authenticated": request.user.is_authenticated,
} }
return render(request, 'nsfw/redirect_page.html', context=context) return render(request, "nsfw/redirect_page.html", context=context)
def warn_msg(request, next_url=None): def warn_msg(request, next_url=None):
context = { context = {
'prev_url': None, "prev_url": None,
'go_home': False, "go_home": False,
'next_url': next_url, "next_url": next_url,
'is_authenticated': request.user.is_authenticated, "is_authenticated": request.user.is_authenticated,
} }
ret = render_to_string( ret = render_to_string(request, "nsfw/redirect_page.html", context=context)
request,
'nsfw/redirect_page.html',
context=context
)
return ret return ret
def redirect(request): def redirect(request):
dest = '{to_url}?next={next_url}'.format( dest = "{to_url}?next={next_url}".format(
to_url=reverse(warn_view), to_url=reverse(warn_view), next_url=request.get_full_path()
next_url=request.get_full_path()
) )
return HttpResponseRedirect(dest) return HttpResponseRedirect(dest)
def alert(request, next_url=None): def alert(request, next_url=None):
context = { context = {"next_url": next_url}
'next_url': next_url, msg = render_to_string("nsfw/disabled_alert.html", context=context)
} messages.info(request, msg, extra_tags="safe")
msg = render_to_string('nsfw/disabled_alert.html', context=context)
messages.info(request, msg, extra_tags='safe')

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class PagesConfig(AppConfig): class PagesConfig(AppConfig):
name = 'pages' name = "pages"

View file

@ -24,14 +24,14 @@ class PageContent(models.Model):
return markdown.markdown( return markdown.markdown(
self.content, self.content,
extensions=[ extensions=[
'markdown.extensions.extra', "markdown.extensions.extra",
'markdown.extensions.admonition', "markdown.extensions.admonition",
'markdown.extensions.nl2br', "markdown.extensions.nl2br",
'markdown.extensions.sane_lists', "markdown.extensions.sane_lists",
'markdown.extensions.smarty', "markdown.extensions.smarty",
'markdown.extensions.toc', "markdown.extensions.toc",
], ],
output_format='html5', output_format="html5",
) )
def __str__(self): def __str__(self):

View file

@ -7,9 +7,6 @@ register = template.Library()
@register.simple_tag(takes_context=True) @register.simple_tag(takes_context=True)
def get_page(context, slug): def get_page(context, slug):
request = context['request'] request = context["request"]
obj = PageContent.objects.filter( obj = PageContent.objects.filter(language=get_language(), page__slug=slug).first
language=get_language(),
page__slug=slug
).first
return obj return obj

View file

@ -3,6 +3,6 @@ from . import views
urlpatterns = [ urlpatterns = [
path('<slug:slug>/', views.PageView.as_view(), name='page'), path("<slug:slug>/", views.PageView.as_view(), name="page"),
path('', views.index, name='index'), path("", views.index, name="index"),
] ]

View file

@ -8,13 +8,13 @@ from .models import Page, PageContent
def index(request): def index(request):
default_page = Page.objects.filter(default=True).first() default_page = Page.objects.filter(default=True).first()
return HttpResponseRedirect(reverse('page', args=(default_page.slug, ))) return HttpResponseRedirect(reverse("page", args=(default_page.slug,)))
class PageView(generic.DetailView): class PageView(generic.DetailView):
model = PageContent model = PageContent
context_object_name = 'page' context_object_name = "page"
template_name = 'pages/page.html' template_name = "pages/page.html"
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
if self.get_object().page.is_nsfw: if self.get_object().page.is_nsfw:
@ -26,9 +26,8 @@ class PageView(generic.DetailView):
def get_object(self): def get_object(self):
obj = PageContent.objects.filter( obj = PageContent.objects.filter(
language=get_language(), language=get_language(), page__slug=self.kwargs["slug"]
page__slug=self.kwargs['slug']
).first() ).first()
if obj is None: if obj is None:
raise Http404('Page not found: %s' % self.kwargs['slug']) raise Http404("Page not found: %s" % self.kwargs["slug"])
return obj return obj

View file

@ -2,4 +2,4 @@ from django.contrib.staticfiles.apps import StaticFilesConfig
class KhaganatStaticFilesConfig(StaticFilesConfig): class KhaganatStaticFilesConfig(StaticFilesConfig):
ignore_patterns = ['CVS', '.*', '*~', 'sass'] ignore_patterns = ["CVS", ".*", "*~", "sass"]