diff --git a/README.md b/README.md index e5751b5..dd9625c 100644 --- a/README.md +++ b/README.md @@ -55,3 +55,5 @@ You can set the following variables in the `.env` file: * `KHAGANAT_FORCE_HTTPS`: If True, enable the use of `KHAGANAT_HTTPS_HEADER_NAME` and `KHAGANAT_HTTPS_HEADER_VALUE` to set the `SECURE_PROXY_SSL_HEADER` configuration option. Default is `False`. * `KHAGANAT_HTTPS_HEADER_NAME`: Header name for `SECURE_PROXY_SSL_HEADER`, default is `HTTP_X_FORWARDED_PROTO`. * `KHAGANAT_HTTPS_HEADER_VALUE`: Header value for `SECURE_PROXY_SSL_HEADER`, default is `https`. +* `KHAGANAT_NSFW_TAGS`: Coma-separated list of words that triggers the content warning in logs, default is `\#nsfw`. +* `KHAGANAT_NSFW_NAME`: Name of the cookie holding the NSFW allowance, default is `nsfw_allowed`. diff --git a/khaganat/settings.py b/khaganat/settings.py index 53171b7..fadc1ad 100644 --- a/khaganat/settings.py +++ b/khaganat/settings.py @@ -183,3 +183,10 @@ if config('KHAGANAT_FORCE_HTTPS', default=False, cast=bool): config('KHAGANAT_HTTPS_HEADER_NAME', default='HTTP_X_FORWARDED_PROTO'), config('KHAGANAT_HTTPS_HEADER_VALUE', default='https') ) + + +# NSFW + +KHAGANAT_NSFW_TAGS = config('KHAGANAT_NSFW_TAGS', default='\\#nsfw', cast=Csv()) +KHAGANAT_NSFW_NAME = config('KHAGANAT_NSFW_NAME', default='nsfw_allowed') +KHAGANAT_NSFW_OK = ('y', 'yes', 't', 'true', '1') diff --git a/logs/views.py b/logs/views.py index f8e3304..0ec5023 100644 --- a/logs/views.py +++ b/logs/views.py @@ -6,6 +6,7 @@ from django.views import generic from django.conf import settings from django.urls import reverse from django.http import Http404 +from neluser import nsfw from .models import Source, Entry from .forms import SearchForm import datetime @@ -102,6 +103,19 @@ class EntriesView(generic.ListView): template_name = 'logs/entries.html' allow_empty = False + def is_nsfw(self): + for e in self.get_queryset(): + for tag in settings.KHAGANAT_NSFW_TAGS: + if tag.lower() in e.content.lower(): + return True + return False + + def dispatch(self, request, *args, **kwargs): + if not nsfw.is_nsfw_allowed(request): + if self.is_nsfw(): + return nsfw.redirect(request) + return super().dispatch(request, *args, **kwargs) + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['date'] = datetime.date( diff --git a/neluser/locale/en/LC_MESSAGES/django.po b/neluser/locale/en/LC_MESSAGES/django.po index c8b57eb..2df83b5 100644 --- a/neluser/locale/en/LC_MESSAGES/django.po +++ b/neluser/locale/en/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: 1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-02-04 15:56+0100\n" +"POT-Creation-Date: 2018-05-27 18:28+0200\n" "PO-Revision-Date: 2018-02-04 01:03+0100\n" "Last-Translator: Khaganat \n" "Language-Team: Khaganat \n" @@ -38,11 +38,19 @@ msgstr "" msgid "date joined" msgstr "" -#: models.py:65 +#: models.py:58 +msgid "NSFW flag" +msgstr "" + +#: models.py:61 +msgid "Indicate whether or not adult or sensitive content should be displayed." +msgstr "" + +#: models.py:73 msgid "user" msgstr "" -#: models.py:66 +#: models.py:74 msgid "users" msgstr "" @@ -58,6 +66,7 @@ msgstr "Your account has been activated." #: templates/neluser/activate_done.html:10 templates/neluser/login.html:4 #: templates/neluser/login.html:12 +#: templates/neluser/password_reset_done.html:10 msgid "login" msgstr "" @@ -97,6 +106,40 @@ msgstr "" msgid "forgotten_password" msgstr "forgotten password" +#: templates/neluser/nsfw.html:4 templates/neluser/nsfw.html:8 +msgid "NSFW content" +msgstr "" + +#: templates/neluser/nsfw.html:9 +msgid "" +"The content you were about to see is flagged as sensitive and therefore " +"cannot be seen while the safe mode is activated." +msgstr "" + +#: templates/neluser/nsfw.html:11 +msgid "Go back home" +msgstr "" + +#: templates/neluser/nsfw.html:12 +msgid "Permanently disable safe mode" +msgstr "" + +#: templates/neluser/nsfw.html:14 +msgid "Or disable safe mode for:" +msgstr "" + +#: templates/neluser/nsfw.html:15 +msgid "5 minutes" +msgstr "" + +#: templates/neluser/nsfw.html:16 +msgid "1 hour" +msgstr "" + +#: templates/neluser/nsfw.html:17 +msgid "1 day" +msgstr "" + #: templates/neluser/password_reset.html:4 #: templates/neluser/password_reset_confirm.html:4 #: templates/neluser/password_reset_done.html:4 @@ -120,7 +163,7 @@ msgstr "change my password" msgid "reset_password_invalid_link" msgstr "Sorry, we are unable to reset your password." -#: templates/neluser/password_reset_done.html:8 +#: templates/neluser/password_reset_done.html:9 msgid "password_reset_success" msgstr "Your password has been changed." @@ -139,8 +182,9 @@ msgstr "" #: templates/neluser/password_reset_email_sent.html:8 msgid "password_reset_success_email" -msgstr "An email has been sent to your address. Please follow the link given " -"in this email to reset your password." +msgstr "" +"An email has been sent to your address. Please follow the link given in this " +"email to reset your password." #: templates/neluser/password_reset_email_subject.txt:2 #, python-format diff --git a/neluser/locale/fr/LC_MESSAGES/django.po b/neluser/locale/fr/LC_MESSAGES/django.po index b92ad87..be6ecf0 100644 --- a/neluser/locale/fr/LC_MESSAGES/django.po +++ b/neluser/locale/fr/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: 1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-02-04 15:56+0100\n" +"POT-Creation-Date: 2018-05-27 18:28+0200\n" "PO-Revision-Date: 2018-02-04 01:03+0100\n" "Last-Translator: Khaganat \n" "Language-Team: Khaganat \n" @@ -40,11 +40,19 @@ msgstr "" msgid "date joined" msgstr "date d'inscription" -#: models.py:65 +#: models.py:58 +msgid "NSFW flag" +msgstr "Affichage du contenu sensible" + +#: models.py:61 +msgid "Indicate whether or not adult or sensitive content should be displayed." +msgstr "Indique si le contenu adulte ou choquant doit être ou non affiché." + +#: models.py:73 msgid "user" msgstr "utilisateur" -#: models.py:66 +#: models.py:74 msgid "users" msgstr "utilisateurs" @@ -60,6 +68,7 @@ msgstr "compte activé" #: templates/neluser/activate_done.html:10 templates/neluser/login.html:4 #: templates/neluser/login.html:12 +#: templates/neluser/password_reset_done.html:10 msgid "login" msgstr "connexion" @@ -99,6 +108,43 @@ msgstr "Activation de compte sur %(site_name)s" msgid "forgotten_password" msgstr "mot de passe oublié" +#: templates/neluser/nsfw.html:4 templates/neluser/nsfw.html:8 +msgid "NSFW content" +msgstr "Contenu sensible" + +#: templates/neluser/nsfw.html:9 +msgid "" +"The content you were about to see is flagged as sensitive and therefore " +"cannot be seen while the safe mode is activated." +msgstr "" +"Le contenu que vous vous apprêtiez à consulter est indiqué comme pouvant " +"choquer la sensibilité et ne peut donc pas être affiché tant que la " +"navigation filtrée est activée." + +#: templates/neluser/nsfw.html:11 +msgid "Go back home" +msgstr "Retourner à l'accueil" + +#: templates/neluser/nsfw.html:12 +msgid "Permanently disable safe mode" +msgstr "Définitivement désactiver la navigation filtrée" + +#: templates/neluser/nsfw.html:14 +msgid "Or disable safe mode for:" +msgstr "Ou désactiver la navigation filtrée pour :" + +#: templates/neluser/nsfw.html:15 +msgid "5 minutes" +msgstr "5 minutes" + +#: templates/neluser/nsfw.html:16 +msgid "1 hour" +msgstr "1 heure" + +#: templates/neluser/nsfw.html:17 +msgid "1 day" +msgstr "1 jour" + #: templates/neluser/password_reset.html:4 #: templates/neluser/password_reset_confirm.html:4 #: templates/neluser/password_reset_done.html:4 @@ -122,7 +168,7 @@ msgstr "Modifier mon mot de passe" msgid "reset_password_invalid_link" msgstr "Désolé, nous ne sommes pas en mesure de modifier votre mot de passe." -#: templates/neluser/password_reset_done.html:8 +#: templates/neluser/password_reset_done.html:9 msgid "password_reset_success" msgstr "Votre mot de passe a été modifié." @@ -144,8 +190,9 @@ msgstr "" #: templates/neluser/password_reset_email_sent.html:8 msgid "password_reset_success_email" -msgstr "Un message a été envoyé sur votre messagerie électronique. Veuillez " -"suivre le lien donné dans ce message afin de réinitialiser votre mot de passe." +msgstr "" +"Un message a été envoyé sur votre messagerie électronique. Veuillez suivre " +"le lien donné dans ce message afin de réinitialiser votre mot de passe." #: templates/neluser/password_reset_email_subject.txt:2 #, python-format diff --git a/neluser/migrations/0003_neluser_nsfw_allowed.py b/neluser/migrations/0003_neluser_nsfw_allowed.py new file mode 100644 index 0000000..be0e2ef --- /dev/null +++ b/neluser/migrations/0003_neluser_nsfw_allowed.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.2 on 2018-05-27 10:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('neluser', '0002_auto_20180204_2035'), + ] + + operations = [ + migrations.AddField( + model_name='neluser', + name='nsfw_allowed', + field=models.BooleanField(default=False, help_text='Indicate whether or not adult or sensitive content should be displayed.', verbose_name='NSFW flag'), + ), + ] diff --git a/neluser/models.py b/neluser/models.py index f60111e..e795546 100644 --- a/neluser/models.py +++ b/neluser/models.py @@ -54,6 +54,14 @@ class NelUser(AbstractBaseUser, PermissionsMixin): ), ) date_joined = models.DateTimeField(_('date joined'), default=timezone.now) + nsfw_allowed = models.BooleanField( + _('NSFW flag'), + default=False, + help_text=_( + 'Indicate whether or not adult or sensitive content should ' + 'be displayed.' + ) + ) objects = NelUserManager() diff --git a/neluser/nsfw.py b/neluser/nsfw.py new file mode 100644 index 0000000..abb8c73 --- /dev/null +++ b/neluser/nsfw.py @@ -0,0 +1,62 @@ +from django.http import HttpResponseRedirect, QueryDict +from django.urls.exceptions import Resolver404 +from django.shortcuts import render +from neluser.models import NelUser +from django.urls import reverse, resolve +from django.conf import settings + + +def is_link_legit(url): + try: + resolve(url) + except Resolver404: + return False + return True + + +def is_nsfw_allowed(request): + if isinstance(request.user, NelUser): + if request.user.nsfw_allowed: + return True + s = request.COOKIES.get(settings.KHAGANAT_NSFW_NAME) or '' + return s.lower() in settings.KHAGANAT_NSFW_OK + + +def disable_view(request, max_age): + try: + max_age = int(max_age) or None + except ValueError: + max_age = None + next_url = QueryDict(request.META.get('QUERY_STRING')).get('next') or '/' + if not is_link_legit(next_url): + next_url = '/' + response = HttpResponseRedirect(next_url) + if isinstance(request.user, NelUser) and not max_age: + request.user.nsfw_allowed = True + request.user.save() + else: + response.set_cookie( + settings.KHAGANAT_NSFW_NAME, + 'true', + max_age=max_age + ) + return response + + +def warn_view(request): + next_url = QueryDict(request.META.get('QUERY_STRING')).get('next') or '/' + if not is_link_legit(next_url): + next_url = '/' + context = { + 'next_url': next_url, + 'is_authenticated': request.user.is_authenticated, + } + return render(request, 'neluser/nsfw.html', context=context) + + +def redirect(request): + dest = '{to_url}?next={next_url}'.format( + to_url=reverse(warn_view), + next_url=request.get_full_path() + ) + return HttpResponseRedirect(dest) diff --git a/neluser/templates/neluser/nsfw.html b/neluser/templates/neluser/nsfw.html new file mode 100644 index 0000000..6752bdb --- /dev/null +++ b/neluser/templates/neluser/nsfw.html @@ -0,0 +1,20 @@ +{% extends "khaganat/base.html" %} +{% load i18n %} + +{% block title %}{% trans "NSFW content" %}{% endblock %} + +{% block content %} +
+

{% trans "NSFW content" %}

+

{% trans "The content you were about to see is flagged as sensitive and therefore cannot be seen while the safe mode is activated." %}

+ +
+{% endblock %} diff --git a/neluser/urls.py b/neluser/urls.py index c53989e..8b49f26 100644 --- a/neluser/urls.py +++ b/neluser/urls.py @@ -1,6 +1,7 @@ from django.contrib.auth import views as auth_views from django.urls import reverse_lazy, path from . import views +from . import nsfw urlpatterns = [ @@ -61,4 +62,8 @@ urlpatterns = [ ), name='password_reset_complete' ), + + # NSFW + path('nsfw/', nsfw.warn_view, name='nsfw'), + path('nsfw/disable//', nsfw.disable_view, name='disable_nsfw'), ]