aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Lemon <y@yulqen.org>2024-12-09 17:16:41 +0000
committerMatthew Lemon <y@yulqen.org>2024-12-09 17:16:41 +0000
commitb481069d9444cc0756bd9f6780e7700dcf4903f5 (patch)
tree5cba9e3d501f79747c8af22bd1b0fd7d783e7ded
parentd3dda8c0bd194c28cf11c189c150c00bdc3e8a83 (diff)
wip: moving home page to home app and implementing reCAPTCHA
-rw-r--r--alphabetlearning/pages/__init__.py0
-rw-r--r--alphabetlearning/pages/admin.py3
-rw-r--r--alphabetlearning/pages/apps.py6
-rw-r--r--alphabetlearning/pages/migrations/__init__.py0
-rw-r--r--alphabetlearning/pages/models.py3
-rw-r--r--alphabetlearning/pages/tests.py3
-rw-r--r--alphabetlearning/pages/urls.py8
-rw-r--r--alphabetlearning/pages/views.py5
-rw-r--r--alphabetlearning/payments/forms.py5
-rw-r--r--alphabetlearning/payments/views.py2
-rw-r--r--alphabetlearning/templates/base.html2
-rw-r--r--alphabetlearning/templates/pages/home.html3
-rw-r--r--alphabetlearning/templates/payments/rate_limited.html11
-rw-r--r--config/settings/base.py5
-rw-r--r--config/settings/production.py1
-rw-r--r--config/urls.py5
-rw-r--r--cookies.txt5
-rw-r--r--pyproject.toml3
-rw-r--r--uv.lock14
19 files changed, 80 insertions, 4 deletions
diff --git a/alphabetlearning/pages/__init__.py b/alphabetlearning/pages/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/alphabetlearning/pages/__init__.py
diff --git a/alphabetlearning/pages/admin.py b/alphabetlearning/pages/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/alphabetlearning/pages/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/alphabetlearning/pages/apps.py b/alphabetlearning/pages/apps.py
new file mode 100644
index 0000000..cdd024b
--- /dev/null
+++ b/alphabetlearning/pages/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class PagesConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'pages'
diff --git a/alphabetlearning/pages/migrations/__init__.py b/alphabetlearning/pages/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/alphabetlearning/pages/migrations/__init__.py
diff --git a/alphabetlearning/pages/models.py b/alphabetlearning/pages/models.py
new file mode 100644
index 0000000..71a8362
--- /dev/null
+++ b/alphabetlearning/pages/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/alphabetlearning/pages/tests.py b/alphabetlearning/pages/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/alphabetlearning/pages/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/alphabetlearning/pages/urls.py b/alphabetlearning/pages/urls.py
new file mode 100644
index 0000000..f8c5b15
--- /dev/null
+++ b/alphabetlearning/pages/urls.py
@@ -0,0 +1,8 @@
+from django.urls import path
+
+from . import views
+
+app_name = "pages"
+urlpatterns = [
+ path("", views.HomePageView.as_view(), name="home"),
+]
diff --git a/alphabetlearning/pages/views.py b/alphabetlearning/pages/views.py
new file mode 100644
index 0000000..81d4392
--- /dev/null
+++ b/alphabetlearning/pages/views.py
@@ -0,0 +1,5 @@
+from django.views.generic import TemplateView
+
+
+class HomePageView(TemplateView):
+ template_name = "pages/home.html"
diff --git a/alphabetlearning/payments/forms.py b/alphabetlearning/payments/forms.py
index 3aa2d95..68acfee 100644
--- a/alphabetlearning/payments/forms.py
+++ b/alphabetlearning/payments/forms.py
@@ -1,8 +1,13 @@
from django import forms
+from django_recaptcha.fields import ReCaptchaField
+from django_recaptcha.widgets import ReCaptchaV2Checkbox
+
from .models import EmailVerification
class EmailVerificationForm(forms.ModelForm):
+ captcha = ReCaptchaField(widget=ReCaptchaV2Checkbox)
+
class Meta:
model = EmailVerification
fields = ["email"]
diff --git a/alphabetlearning/payments/views.py b/alphabetlearning/payments/views.py
index 2be5344..7682c35 100644
--- a/alphabetlearning/payments/views.py
+++ b/alphabetlearning/payments/views.py
@@ -61,6 +61,8 @@ class SuccessEmailSignupView(TemplateView):
@ratelimit(key="ip", rate="2/m", block=True)
def email_signup_verification(request):
if request.method == "POST":
+ if getattr(request, "limited", False):
+ return render(request, "payments/rate_limited.html", status=429)
form = EmailVerificationForm(request.POST)
if form.is_valid():
# Create pending verification
diff --git a/alphabetlearning/templates/base.html b/alphabetlearning/templates/base.html
index 5aa2193..f26fb72 100644
--- a/alphabetlearning/templates/base.html
+++ b/alphabetlearning/templates/base.html
@@ -59,7 +59,7 @@
<header>
<nav class="navbar navbar-expand-lg navbar-light bg-white">
<div class="container-fluid">
- <a class="navbar-brand" href="{% url "home" %}">
+ <a class="navbar-brand" href="{% url "pages:home" %}">
<img style="margin-left: 2rem; margin-top: 20px;" src="{% static "images/AL_long_logo_black_grey.png" %}" width=300px alt="Alphabet Learning Logo">
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
diff --git a/alphabetlearning/templates/pages/home.html b/alphabetlearning/templates/pages/home.html
index 6261524..0d00042 100644
--- a/alphabetlearning/templates/pages/home.html
+++ b/alphabetlearning/templates/pages/home.html
@@ -65,6 +65,9 @@
placeholder="Your email address..."
/>
</div>
+ <div>
+ {{ form.captcha }}
+ </div>
<button
type="submit"
style="
diff --git a/alphabetlearning/templates/payments/rate_limited.html b/alphabetlearning/templates/payments/rate_limited.html
new file mode 100644
index 0000000..c75e474
--- /dev/null
+++ b/alphabetlearning/templates/payments/rate_limited.html
@@ -0,0 +1,11 @@
+{% extends "base.html" %}
+
+{% load static %}
+
+{% block content %}
+ <div class="container my-5">
+ <div class="row">
+ <h2>You have made to many submissions</h2>
+ <p>Please try again later.</p>
+ </div>
+{% endblock content %}
diff --git a/config/settings/base.py b/config/settings/base.py
index 157926b..991605c 100644
--- a/config/settings/base.py
+++ b/config/settings/base.py
@@ -77,6 +77,7 @@ THIRD_PARTY_APPS = [
"allauth.mfa",
"allauth.socialaccount",
"django_celery_beat",
+ "django_recaptcha",
]
STRIPE_SECRET_KEY = env("STRIPE_SECRET_KEY")
@@ -88,6 +89,7 @@ LOCAL_APPS = [
"alphabetlearning.users",
"alphabetlearning.resources",
"alphabetlearning.payments",
+ "alphabetlearning.pages",
# Your stuff: custom apps go here
]
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
@@ -366,3 +368,6 @@ CACHES = {
"LOCATION": "rate_limit_cache",
},
}
+
+RECAPTCHA_PUBLIC_KEY = env("RECAPTCHA_PUBLIC_KEY")
+RECAPTCHA_PRIVATE_KEY = env("RECAPTCHA_PRIVATE_KEY")
diff --git a/config/settings/production.py b/config/settings/production.py
index 374be33..ff9e475 100644
--- a/config/settings/production.py
+++ b/config/settings/production.py
@@ -233,3 +233,4 @@ MAILGUN_API_URL = env("MAILGUN_API_URL", default="https://api.eu.mailgun.net/v3"
USE_X_FORWARDED_HOST = True
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
+RECAPTCHA_USE_SSL = True # Use HTTPS for requests
diff --git a/config/urls.py b/config/urls.py
index e213522..554d227 100644
--- a/config/urls.py
+++ b/config/urls.py
@@ -12,10 +12,11 @@ from django.views.generic import TemplateView
# import debug_toolbar
-admin.site.site_header = "Blackbird Admin Panel"
+admin.site.site_header = "Alphabet Learning Admin Panel"
urlpatterns = [
- path("", TemplateView.as_view(template_name="pages/home.html"), name="home"),
+ # path("", TemplateView.as_view(template_name="pages/home.html"), name="home"),
+ path("", include("alphabetlearning.pages.urls", namespace="pages")),
path(
"about/",
TemplateView.as_view(template_name="pages/about.html"),
diff --git a/cookies.txt b/cookies.txt
new file mode 100644
index 0000000..6bef457
--- /dev/null
+++ b/cookies.txt
@@ -0,0 +1,5 @@
+# Netscape HTTP Cookie File
+# https://curl.se/docs/http-cookies.html
+# This file was generated by libcurl! Edit at your own risk.
+
+#HttpOnly_127.0.0.1 FALSE / FALSE 1765141225 csrftoken ZvMDpDcXBf12tnCdJGlR0i8AcBUnh0rX
diff --git a/pyproject.toml b/pyproject.toml
index b2d4262..d09d98b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -55,7 +55,8 @@ dependencies = [
# https://github.com/samuelcolvin/watchfiles
"stripe==11.1.0",
"django-stubs[compatible-mypy]>=5.0.4",
- "django-ratelimit==4.1.0"
+ "django-ratelimit==4.1.0",
+ "django-recaptcha==4.0.0"
]
[tool.uv] # https://docs.astral.sh/uv/concepts/dependencies/#development-dependencies
dev-dependencies = [
diff --git a/uv.lock b/uv.lock
index 14a3fc0..43f4a55 100644
--- a/uv.lock
+++ b/uv.lock
@@ -18,6 +18,7 @@ dependencies = [
{ name = "django-environ" },
{ name = "django-model-utils" },
{ name = "django-ratelimit" },
+ { name = "django-recaptcha" },
{ name = "django-redis" },
{ name = "django-storages" },
{ name = "django-stubs", extra = ["compatible-mypy"] },
@@ -66,6 +67,7 @@ requires-dist = [
{ name = "django-environ", specifier = "==0.11.2" },
{ name = "django-model-utils", specifier = "==4.5.1" },
{ name = "django-ratelimit", specifier = "==4.1.0" },
+ { name = "django-recaptcha", specifier = "==4.0.0" },
{ name = "django-redis", specifier = "==5.4.0" },
{ name = "django-storages", specifier = "==1.14.3" },
{ name = "django-stubs", extras = ["compatible-mypy"], specifier = ">=5.0.4" },
@@ -540,6 +542,18 @@ wheels = [
]
[[package]]
+name = "django-recaptcha"
+version = "4.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "django" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/d4/6b/6edf89da076b2d1ea042e14f116de80be18d25b17af158038d5fc14c00bb/django-recaptcha-4.0.0.tar.gz", hash = "sha256:5316438f97700c431d65351470d1255047e3f2cd9af0f2f13592b637dad9213e", size = 22907 }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/28/d7/09cefb2b4a7dc9ed8a6aabb176ea86eb904a8f73671358436e4b0aa81b93/django_recaptcha-4.0.0-py3-none-any.whl", hash = "sha256:0d912d5c7c009df4e47accd25029133d47a74342dbd2a8edc2877b6bffa971a3", size = 21915 },
+]
+
+[[package]]
name = "django-redis"
version = "5.4.0"
source = { registry = "https://pypi.org/simple" }