Skip to content

Commit 4d22263

Browse files
committed
Readd list and landing views.
1 parent 505c7d6 commit 4d22263

File tree

9 files changed

+137
-13
lines changed

9 files changed

+137
-13
lines changed

project/config/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@
161161

162162
# Login URL setting
163163
LOGIN_URL = reverse_lazy("auth_login")
164-
LOGIN_REDIRECT_URL = "/"
164+
LOGIN_REDIRECT_URL = reverse_lazy("newsletter:landing")
165165

166166
# Martor / Markdown editor
167167

project/newsletter/syndication.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from django.contrib.syndication.views import Feed
2+
from django.urls import reverse
23

34
from project.newsletter.models import Category, Post
45

@@ -46,7 +47,7 @@ def item_title(self, obj):
4647
return f"{obj.title} newsletter posts"
4748

4849
def item_link(self, obj):
49-
return "/p/" + f"?category={obj.slug}"
50+
return reverse("newsletter:list_posts") + f"?category={obj.slug}"
5051

5152
def items(self, obj):
5253
return (

project/newsletter/test_views.py

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,88 @@
1212
from project.newsletter.test import DataTestCase
1313

1414

15+
class TestLanding(DataTestCase):
16+
url = reverse("newsletter:landing")
17+
18+
def test_unauthenticated(self):
19+
response = self.client.get(self.url)
20+
self.assertTemplateUsed(response, "landing.html")
21+
self.assertEqual(
22+
list(response.context["posts"]), [self.data.career_post, self.data.all_post]
23+
)
24+
25+
def test_authenticated_no_subscription(self):
26+
self.client.force_login(User.objects.create_user(username="inline"))
27+
response = self.client.get(self.url)
28+
self.assertTemplateUsed(response, "landing.html")
29+
self.assertEqual(
30+
list(response.context["posts"]), [self.data.career_post, self.data.all_post]
31+
)
32+
# Verify the categories are rendered
33+
self.assertContains(response, self.data.career_post.categories.first().title)
34+
35+
def test_authenticated_subscriber(self):
36+
self.client.force_login(self.data.subscription.user)
37+
response = self.client.get(self.url)
38+
self.assertTemplateUsed(response, "landing.html")
39+
self.assertEqual(
40+
list(response.context["posts"]),
41+
[self.data.private_post, self.data.career_post, self.data.all_post],
42+
)
43+
44+
45+
class TestListPosts(DataTestCase):
46+
url = reverse("newsletter:list_posts")
47+
48+
@patch("project.newsletter.views.LIST_POSTS_PAGE_SIZE", 1)
49+
def test_unauthenticated(self):
50+
response = self.client.get(self.url)
51+
self.assertTemplateUsed(response, "posts/list.html")
52+
self.assertEqual(list(response.context["page"]), [self.data.career_post])
53+
54+
# Verify the pagination exists.
55+
self.assertInHTML(
56+
'<a class="item active" href="?page=1">1</a>',
57+
response.content.decode("utf-8"),
58+
)
59+
self.assertInHTML(
60+
'<a class="item" href="?page=2">2</a>', response.content.decode("utf-8")
61+
)
62+
63+
@patch("project.newsletter.views.LIST_POSTS_PAGE_SIZE", 1)
64+
def test_authenticated(self):
65+
self.client.force_login(self.data.subscription.user)
66+
response = self.client.get(self.url)
67+
self.assertTemplateUsed(response, "posts/list.html")
68+
self.assertEqual(list(response.context["page"]), [self.data.private_post])
69+
70+
# Verify the categories are rendered
71+
self.assertContains(response, self.data.private_post.categories.first().title)
72+
# Verify the pagination exists.
73+
self.assertInHTML(
74+
'<a class="item active" href="?page=1">1</a>',
75+
response.content.decode("utf-8"),
76+
)
77+
self.assertInHTML(
78+
'<a class="item" href="?page=2">2</a>', response.content.decode("utf-8")
79+
)
80+
81+
@patch("project.newsletter.views.LIST_POSTS_PAGE_SIZE", 1)
82+
def test_pagination(self):
83+
self.client.force_login(self.data.subscription.user)
84+
response = self.client.get(self.url + "?page=2")
85+
self.assertTemplateUsed(response, "posts/list.html")
86+
self.assertEqual(list(response.context["page"]), [self.data.career_post])
87+
# Verify the pagination exists.
88+
self.assertInHTML(
89+
'<a class="item" href="?page=1">1</a>', response.content.decode("utf-8")
90+
)
91+
self.assertInHTML(
92+
'<a class="item active" href="?page=2">2</a>',
93+
response.content.decode("utf-8"),
94+
)
95+
96+
1597
class TestViewPost(DataTestCase):
1698
def test_unauthenticated(self):
1799
response = self.client.get(
@@ -227,7 +309,7 @@ def test_toggle(self):
227309
)
228310
url = reverse("newsletter:toggle_post_privacy", kwargs={"slug": post.slug})
229311
response = self.client.post(url)
230-
self.assertRedirects(response, "/admin/")
312+
self.assertRedirects(response, reverse("newsletter:list_posts"))
231313
post.refresh_from_db()
232314
self.assertFalse(post.is_public)
233315

@@ -332,7 +414,10 @@ def test_invalid(self):
332414
def test_update(self):
333415
self.client.force_login(self.user)
334416
data = {"categories": [self.data.career.slug]}
335-
self.client.post(reverse("newsletter:update_subscription"), data=data)
417+
response = self.client.post(
418+
reverse("newsletter:update_subscription"), data=data
419+
)
420+
self.assertRedirects(response, reverse("newsletter:list_posts"))
336421
self.assertEqual(self.subscription.categories.get(), self.data.career)
337422

338423

project/newsletter/urls.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
app_name = "newsletter"
66
urlpatterns = [
77
path("markdown/uploader/", views.markdown_uploader, name="markdown_uploader"),
8+
path("", views.landing, name="landing"),
89
path("account/", views.update_subscription, name="update_subscription"),
910
path("analytics/", views.analytics, name="analytics"),
1011
path("post/unpublished/", views.unpublished_posts, name="unpublished_posts"),
@@ -19,6 +20,7 @@
1920
"p/",
2021
include(
2122
[
23+
path("", views.list_posts, name="list_posts"),
2224
path("<slug>/", views.view_post, name="view_post"),
2325
]
2426
),

project/newsletter/views.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,41 @@
2525
LIST_POSTS_PAGE_SIZE = 100
2626

2727

28+
@require_http_methods(["GET"])
29+
def landing(request):
30+
"""
31+
The landing page view.
32+
33+
Render the public posts or the most recent posts an authenticated
34+
user is subscribed for.
35+
"""
36+
posts = Post.objects.recent_first().published().annotate_is_unread(request.user)
37+
if request.user.is_authenticated and (
38+
subscription := Subscription.objects.for_user(request.user)
39+
):
40+
posts = posts.in_relevant_categories(subscription)
41+
else:
42+
posts = posts.public()
43+
return render(request, "landing.html", {"posts": posts[:3]})
44+
45+
46+
@require_http_methods(["GET"])
47+
def list_posts(request):
48+
"""
49+
The post lists view.
50+
"""
51+
posts = Post.objects.recent_first().published().annotate_is_unread(request.user)
52+
if not request.user.is_authenticated:
53+
posts = posts.public()
54+
paginator = Paginator(posts, LIST_POSTS_PAGE_SIZE)
55+
page_number = request.GET.get("page")
56+
page_obj = paginator.get_page(page_number)
57+
page_range = paginator.get_elided_page_range(page_obj.number)
58+
return render(
59+
request, "posts/list.html", {"page": page_obj, "page_range": page_range}
60+
)
61+
62+
2863
@require_http_methods(["GET"])
2964
def view_post(request, slug):
3065
"""
@@ -64,7 +99,7 @@ def update_subscription(request):
6499
form.instance.user = request.user
65100
form.save()
66101
messages.success(request, "Your subscription changes have been saved.")
67-
return redirect("/")
102+
return redirect("newsletter:list_posts")
68103
return render(request, "subscription/update.html", {"form": form})
69104

70105

@@ -139,7 +174,7 @@ def toggle_post_privacy(request, slug):
139174
messages.success(request, f"Post slug={slug} was updated.")
140175
if url := request.GET.get("next"):
141176
return redirect(url)
142-
return redirect("/admin/")
177+
return redirect("newsletter:list_posts")
143178

144179

145180
@staff_member_required(login_url=settings.LOGIN_URL)

project/templates/base.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,19 @@
1111
<header>
1212
<div class="ui fixed inverted menu">
1313
<div class="ui container">
14-
<a href="#" class="header item">
14+
<a href="{% url "newsletter:landing" %}" class="header item">
1515
Debug Newsletter
1616
</a>
1717
{% if not request.user.is_staff %}
18-
<a href="#" class="header item">
18+
<a href="{% url "newsletter:list_posts" %}" class="header item">
1919
Posts
20-
</a>
20+
</a>
2121
{% else %}
2222
<div class="ui dropdown item" tabindex="0">
2323
Posts
2424
<i class="dropdown icon"></i>
2525
<div class="menu transition hidden" tabindex="-1">
26+
<a href="{% url "newsletter:list_posts" %}" class="item">Published</a>
2627
<a href="{% url "newsletter:unpublished_posts" %}" class="item">Unpublished</a>
2728
<div class="divider"></div>
2829
<a href="{% url "newsletter:create_post" %}" class="item">Create</a>

project/templates/posts/detail.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
{% block content %}
1818
<div class="ui main text container">
1919
<div class="ui breadcrumb">
20-
<a href="/" class="section">Home</a>
20+
<a href="{% url "newsletter:landing" %}" class="section">Home</a>
2121
<div class="divider"> / </div>
22-
<a href="/p/" class="section">Posts</a>
22+
<a href="{% url "newsletter:list_posts" %}" class="section">Posts</a>
2323
<div class="divider"> / </div>
2424
<div class="active section">
2525
{% if is_trending %}

project/templates/posts/list.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<div class="ui vertical stripe segment">
88
<div class="ui text container">
99
<div class="ui breadcrumb">
10-
<a href="/" class="section">Home</a>
10+
<a href="{% url "newsletter:landing" %}" class="section">Home</a>
1111
<div class="divider"> / </div>
1212
<div class="active section">Posts</div>
1313
</div>

project/templates/staff/analytics.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<div class="ui vertical stripe segment">
99
<div class="ui text container">
1010
<div class="ui breadcrumb">
11-
<a href="/" class="section">Home</a>
11+
<a href="{% url "newsletter:landing" %}" class="section">Home</a>
1212
<div class="divider"> / </div>
1313
<div class="active section">Analytics</div>
1414
</div>

0 commit comments

Comments
 (0)