Skip to content

Commit

Permalink
add email subscribe functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
sirodoht committed May 25, 2024
1 parent 9e007bb commit 521833a
Show file tree
Hide file tree
Showing 11 changed files with 163 additions and 11 deletions.
10 changes: 10 additions & 0 deletions main/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,15 @@ class ArticleAdmin(admin.ModelAdmin):
"updated_at",
)
list_display_links = ("id", "title", "slug")
ordering = ["-id"]


@admin.register(models.Subscription)
class SubscriptionAdmin(admin.ModelAdmin):
list_display = (
"id",
"email",
"created_at",
)
list_display_links = ("id", "email")
ordering = ["-id"]
9 changes: 9 additions & 0 deletions main/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django import forms

from main import models


class Subscription(forms.ModelForm):
class Meta:
model = models.Subscription
fields = ["email"]
31 changes: 31 additions & 0 deletions main/migrations/0003_subscription.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Generated by Django 5.0.6 on 2024-05-25 11:02

import uuid

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("main", "0002_article"),
]

operations = [
migrations.CreateModel(
name="Subscription",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("email", models.EmailField(max_length=254, unique=True)),
("created_at", models.DateTimeField(auto_now_add=True)),
("unsubscribe_key", models.UUIDField(default=uuid.uuid4, unique=True)),
],
),
]
17 changes: 17 additions & 0 deletions main/migrations/0004_alter_subscription_email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 5.0.6 on 2024-05-25 11:27

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("main", "0003_subscription"),
]

operations = [
migrations.AlterField(
model_name="subscription",
name="email",
field=models.EmailField(max_length=254),
),
]
15 changes: 15 additions & 0 deletions main/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import uuid

import mistune
from django.conf import settings
from django.contrib.auth.models import AbstractUser
Expand Down Expand Up @@ -49,3 +51,16 @@ def get_absolute_url(self):

def __str__(self):
return f"{self.id}: {self.title}"


class Subscription(models.Model):
email = models.EmailField()
created_at = models.DateTimeField(auto_now_add=True)
unsubscribe_key = models.UUIDField(default=uuid.uuid4, unique=True)

def get_unsubscribe_url(self):
path = reverse("unsubscribe_key", args={self.unsubscribe_key})
return f"{settings.CANONICAL_URL}{path}"

def __str__(self):
return f"{self.id}: {self.email}"
24 changes: 24 additions & 0 deletions main/templates/assets/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
html, body { margin: 0; }
body { font-family: InterVariable, sans-serif; line-height: 1.3; }
a { color: black; }
aside {
text-align: center;
padding-top: 24px;
text-transform: none;
color: salmon;
}

/* all pages */
section { max-width: 640px; margin: 0 auto 64px; font-size: 20px; }
Expand All @@ -59,6 +65,24 @@ section blockquote {
}
section blockquote p { padding: 0; }

/* all pages: forms */
form { max-width: 300px; margin: 0 auto; }
label { display: block; margin-bottom: 8px; user-select: none; }
input[type="email"] { box-sizing: border-box; display: block; width: 100%; }
input[type="submit"] {
cursor: pointer;
display: block;
width: 100%;
background: white;
border: 1px solid black;
padding: 8px 0;
}
input[type="submit"]:hover {
background: black;
color: white;
}
.errorlist { font-size: 18px; }

/* articles / news / ideas / blog sections */
#articles .article-list-title {
font-family: 'Grenette Variable Pro';
Expand Down
4 changes: 2 additions & 2 deletions main/templates/main/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ <h2>

<div id="newsletter">
<h2>Stay In Touch</h2>
<form method="post">
<form method="post" action="{% url 'subscribe' %}">
{% csrf_token %}
<input type="email" title="email" placeholder="email">
<input type="email" name="email" placeholder="email">
</form>
</div>

Expand Down
17 changes: 9 additions & 8 deletions main/templates/main/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,22 @@
</head>

<body>
{% if messages %}
<aside>
{% for message in messages %}
<div {% if message.tags %}class="alert-{{ message.tags }}"{% endif %}>{{ message|safe }}</div>
{% endfor %}
</aside>
{% endif %}

<nav>
<a href="{% url 'index' %}" style="color: #3D6D75;">Shoshin College</a>
<a href="{% url 'index' %}">Home</a>
<a href="{% url 'about' %}">About</a>
<a target="_blank" href="https://shoshincollege.notion.site/Classes-Fall-2024-72c20e12164e4f13b4c3d6182fe74f0d">Classes ↗</a>
<a href="{% url 'news_list' %}">News</a>

{% if messages %}
<aside>
{% for message in messages %}
<div {% if message.tags %}class="alert-{{ message.tags }}"{% endif %}>{{ message|safe }}</div>
{% endfor %}
</aside>
{% endif %}
</nav>

{% block content %}
{% endblock %}
</body>
Expand Down
22 changes: 22 additions & 0 deletions main/templates/main/subscribe.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{% extends 'main/layout.html' %}

{% block content %}
<div id="section-title">
<h1>Stay In Touch</h1>
</div>

<section>
<form method="post" action="{% url 'subscribe' %}">
<p>
<label for="email">Email:</label>
{{ form.email.errors }}
<input type="email" id="email" name="email" required>
</p>

{% csrf_token %}

<input type="submit" value="Submit">
</form>
</section>

{% endblock %}
1 change: 1 addition & 0 deletions main/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
urlpatterns = [
path("", views.index, name="index"),
path("about/", views.about, name="about"),
path("subscribe/", views.Subscribe.as_view(), name="subscribe"),
path("news/", views.NewsList.as_view(), name="news_list"),
path("news/<slug:slug>/", views.NewsDetail.as_view(), name="news_detail"),
]
24 changes: 23 additions & 1 deletion main/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from django.contrib.messages.views import SuccessMessageMixin
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import DetailView, ListView
from django.views.generic.edit import FormView

from main import models
from main import forms, models


def index(request):
Expand All @@ -23,3 +26,22 @@ def get_queryset(self):

class NewsDetail(DetailView):
model = models.Article


class Subscribe(SuccessMessageMixin, FormView):
form_class = forms.Subscription
template_name = "main/subscribe.html"
success_url = reverse_lazy("index")
success_message = "thanks! we've noted down your email address"

def form_valid(self, form):
# Handle case: already subscribed
if models.Subscription.objects.filter(
email=form.cleaned_data.get("email")
).exists():
self.success_message = "thanks! you are already subscribed but whatever"
return super().form_valid(form)

# Handle happy path: email is new
self.object = form.save()
return super().form_valid(form)

0 comments on commit 521833a

Please sign in to comment.