diff --git a/april/__init__.py b/april/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/april/apps.py b/april/apps.py new file mode 100644 index 00000000..6bef3518 --- /dev/null +++ b/april/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AprilConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "april" diff --git a/april/middleware.py b/april/middleware.py new file mode 100644 index 00000000..ae98dc44 --- /dev/null +++ b/april/middleware.py @@ -0,0 +1,34 @@ +import os +from urllib.parse import urlparse + +from django.conf import settings +from django.http import HttpRequest + +from april import views + + +class AprilFoolMiddleware: + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request: HttpRequest): + if request.user.is_authenticated and request.user.id == os.environ.get( + "SLI_ID" + ): + # Sli deserves a special one :) + return views.april_fool_sli(request) + if self._prank_user(request): + return views.april_fool(request) + return self.get_response(request) + + @classmethod + def _prank_user(cls, request): + if request.user.is_anonymous or not request.user.was_subscribed: + return False + # fool users only if the request isn't originated from the sith itself + referer = request.META.get("HTTP_REFERER", None) + if referer is not None or urlparse(referer).netloc == settings.SITH_URL: + return False + # don't fool a user too often, or his UX will become miserable + already_pranked = request.COOKIES.get("prankDone") + return not already_pranked diff --git a/april/migrations/__init__.py b/april/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/april/static/april/age_confirm.scss b/april/static/april/age_confirm.scss new file mode 100644 index 00000000..262c05c3 --- /dev/null +++ b/april/static/april/age_confirm.scss @@ -0,0 +1,165 @@ +a, body, div, h3, img, li, p, small, span, ul { + margin: 0; + padding: 0; + border: 0; + vertical-align: baseline; +} + +body { + line-height: 1; +} + +ul { + list-style: none; +} + +body { + font-size: 14px; + color: var(--main-text); + font-family: Arial, Helvetica, sans-serif; +} + +a { + text-decoration: none; + color: var(--main-theme); + cursor: pointer; + outline: 0; +} + +p { + margin-bottom: 10px; + line-height: 21px; +} + +h3 { + font-weight: 700; + margin-bottom: 10px; + font-size: 1.4em; +} + +.button { + display: inline-block; + padding: 7px; + border: 0; + border-radius: 3px; + color: var(--main-text); + font-size: 1em; + text-align: center; + text-decoration: none; + cursor: pointer; + outline: 0; +} + +button.button { + border: 0; +} + +.button.button-pink { + background-color: var(--main-theme); +} + +.button.button-close { + background-color: var(--gray); + color: var(--light-gray); + padding-top: 8px; + padding-bottom: 8px; +} + +#ageDisclaimerWrapper { + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; + z-index: 20240; + width: 100%; + height: 100%; + display: block; + background-color: var(--main-background); +} + +#ageDisclaimerWrapper .age-disclaimer-modal { + max-width: 850px; + width: 100%; + max-height: 100%; + overflow: auto; + box-sizing: border-box; + position: absolute; + left: 50%; + top: 30%; + -webkit-transform: translate(-50%, -30%); + transform: translate(-50%, -30%); + background: var(--darkest-gray); + border: 1px solid var(--gray); + padding: 50px; + text-align: center; +} + +#ageDisclaimerWrapper .age-disclaimer-modal .logo-wrapper { + margin-bottom: 20px; +} + +#ageDisclaimerWrapper .age-disclaimer-modal .content { + font-size: 1.2em; + margin: 30px 0; +} + +#ageDisclaimerWrapper .age-disclaimer-modal .buttons-wrapper { + display: flex; + justify-content: center; +} + +#ageDisclaimerWrapper .age-disclaimer-modal .buttons-wrapper .button-close, #ageDisclaimerWrapper .age-disclaimer-modal .buttons-wrapper .button-pink { + font-size: 1.3em; + padding: 15px 10px; + -webkit-transition: all .2s; + transition: all .2s; + flex-basis: 40%; + max-width: 350px; +} + +#ageDisclaimerWrapper .age-disclaimer-modal .buttons-wrapper .button-pink:hover { + background-color: var(--main-theme-hover); +} + +#ageDisclaimerWrapper .age-disclaimer-modal .buttons-wrapper .button-close { + margin-left: 10px; +} + +#ageDisclaimerWrapper .age-disclaimer-modal .buttons-wrapper .button-close:hover { + background-color: var(--mid-gray); +} + +#ageDisclaimerWrapper .age-disclaimer-modal .parental-control-message { + margin-top: 30px; + line-height: 18px; +} + +#ageDisclaimerWrapper .age-disclaimer-modal .parental-control-message .block-copyright { + position: relative; + bottom: 10px; + color: var(--shadow-dark-gray); +} + +#ageDisclaimerWrapper .age-disclaimer-modal .parental-control-message a { + display: inline-block; +} + +#ageDisclaimerWrapper .age-disclaimer-modal .parental-control-message a:hover { + color: var(--main-theme-hover); +} + +#ageDisclaimerWrapper .age-disclaimer-modal .age_verification_title { + font-size: 2em; + font-weight: 700; + margin-bottom: 10px; +} + +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} \ No newline at end of file diff --git a/april/templates/april/age_confirm.jinja b/april/templates/april/age_confirm.jinja new file mode 100644 index 00000000..2c405196 --- /dev/null +++ b/april/templates/april/age_confirm.jinja @@ -0,0 +1,98 @@ + + + + AE UTBM + + + + + + + + + + + + +
+ +
+
+
+ +
+

+ {% trans %}Age Verification{% endtrans %} +

+
+

+ {% trans trimmed %} + This website contains age-restricted materials including blousards + and explicit depictions of student activity. + By entering, you affirm that you are at least 18 years of age + or the age of majority in the campus you are accessing the website from + and you consent to viewing explicit student content. + {% endtrans %} +

+
+
+ + +
+
+

+ {% trans trimmed %} + Our + parental controls page explains if you can access this website + {% endtrans %} +

+ AE UTBM 2025 +
+
+
+ + + diff --git a/april/templates/april/sli.jinja b/april/templates/april/sli.jinja new file mode 100644 index 00000000..7541ab4a --- /dev/null +++ b/april/templates/april/sli.jinja @@ -0,0 +1,4 @@ +

Service unavailable

+
+

HTTP Error 503 : the service is unavailable

+Review mes PRs, wesh \ No newline at end of file diff --git a/april/views.py b/april/views.py new file mode 100644 index 00000000..b45967e0 --- /dev/null +++ b/april/views.py @@ -0,0 +1,9 @@ +from django.shortcuts import render + + +def april_fool(request): + return render(request, "april/age_confirm.jinja") + + +def april_fool_sli(request): + return render(request, "april/sli.jinja") diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index a7d0c1ab..4748fd3e 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-03-28 13:51+0100\n" +"POT-Creation-Date: 2025-04-01 01:33+0200\n" "PO-Revision-Date: 2016-07-18\n" "Last-Translator: Maréchal \n" @@ -796,6 +796,42 @@ msgstr "" "True si gardé à jour par le biais d'un fournisseur externe de domains " "toxics, False sinon" +#: april/templates/april/age_confirm.jinja +msgid "Age Verification" +msgstr "Vérification de l'âge" + +#: april/templates/april/age_confirm.jinja +msgid "" +"This website contains age-restricted materials including blousards and " +"explicit depictions of student activity. By entering, you affirm that you " +"are at least 18 years of age or the age of majority in the campus you are " +"accessing the website from and you consent to viewing explicit student " +"content." +msgstr "" +"Ce site possède du contenu dont l'accès est limité à un certain âge, " +"incluant des blousards et des représentations explicites d'activités " +"étudiantes. En rentrant sur le site, vous affirmez que vous avez au moins 18 " +"ans ou l'âge de la majorité dans le campus depuis lequel vous accédez au " +"site et vous acceptez de voir du contenu explicite étudiant." + +#: april/templates/april/age_confirm.jinja +msgid "I am 18 or older" +msgstr "J'ai 18 ans ou plus" + +#: april/templates/april/age_confirm.jinja +msgid "I am under 18" +msgstr "J'ai moins de 18 ans" + +#: april/templates/april/age_confirm.jinja +msgid "" +"Our parental controls page explains if you can " +"access this website" +msgstr "" +"Notre page de contrôle parental explique si vous " +"pouvez accéder à ce site." + #: club/forms.py msgid "Users to add" msgstr "Utilisateurs à ajouter" @@ -935,6 +971,10 @@ msgstr "rôle" msgid "description" msgstr "description" +#: club/models.py +msgid "past member" +msgstr "ancien membre" + #: club/models.py msgid "Email address" msgstr "Adresse email" @@ -3335,8 +3375,8 @@ msgstr "Nom d'utilisateur, email, ou numéro de compte AE" #: core/views/forms.py msgid "" -"Profile: you need to be visible on the picture, in order to be recognized (e." -"g. by the barmen)" +"Profile: you need to be visible on the picture, in order to be recognized " +"(e.g. by the barmen)" msgstr "" "Photo de profil: vous devez être visible sur la photo afin d'être reconnu " "(par exemple par les barmen)" @@ -3409,10 +3449,6 @@ msgstr "Famille" msgid "Pictures" msgstr "Photos" -#: core/views/user.py -msgid "Galaxy" -msgstr "Galaxie" - #: counter/apps.py sith/settings.py msgid "Check" msgstr "Chèque" @@ -3946,8 +3982,8 @@ msgstr "" #: counter/templates/counter/mails/account_dump.jinja msgid "If you think this was a mistake, please mail us at ae@utbm.fr." msgstr "" -"Si vous pensez qu'il s'agit d'une erreur, veuillez envoyer un mail à ae@utbm." -"fr." +"Si vous pensez qu'il s'agit d'une erreur, veuillez envoyer un mail à " +"ae@utbm.fr." #: counter/templates/counter/mails/account_dump.jinja msgid "" @@ -6043,6 +6079,3 @@ msgstr "Vous ne pouvez plus écrire de commentaires, la date est passée." #, python-format msgid "Maximum characters: %(max_length)s" msgstr "Nombre de caractères max: %(max_length)s" - -#~ msgid "past member" -#~ msgstr "ancien membre" diff --git a/sith/settings.py b/sith/settings.py index ab16e7d5..11c973c0 100644 --- a/sith/settings.py +++ b/sith/settings.py @@ -98,6 +98,7 @@ INSTALLED_APPS = ( "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", + "april", "staticfiles", "django.contrib.sites", "honeypot", @@ -135,6 +136,7 @@ MIDDLEWARE = ( "django.middleware.security.SecurityMiddleware", "core.middleware.AuthenticationMiddleware", "core.middleware.SignalRequestMiddleware", + "april.middleware.AprilFoolMiddleware", ) ROOT_URLCONF = "sith.urls"