Skip to content

Commit

Permalink
Merge pull request #90 from stuartmaxwell:test-paths
Browse files Browse the repository at this point in the history
Test-paths
  • Loading branch information
stuartmaxwell authored Nov 29, 2024
2 parents 5dc36d3 + a9e4d13 commit 7edcf5c
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 24 deletions.
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "djpress"
version = "0.14.0"
version = "0.14.1"
description = "A blog application for Django sites, inspired by classic WordPress."
readme = "README.md"
requires-python = ">=3.10"
Expand Down Expand Up @@ -97,7 +97,7 @@ include = ["src/djpress/*"]
omit = ["*/tests/*", "*/migrations/*"]

[tool.bumpver]
current_version = "0.14.0"
current_version = "0.14.1"
version_pattern = "MAJOR.MINOR.PATCH"
commit_message = "👍 bump version {old_version} -> {new_version}"
commit = true
Expand Down
2 changes: 1 addition & 1 deletion src/djpress/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""djpress module."""

__version__ = "0.14.0"
__version__ = "0.14.1"
58 changes: 41 additions & 17 deletions src/djpress/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,24 @@ def dispatcher(request: HttpRequest, path: str) -> HttpResponse | None:
if djpress_settings.RSS_ENABLED and (path in (djpress_settings.RSS_PATH, f"{djpress_settings.RSS_PATH}/")):
return PostFeed()(request)

# 2. Check if it matches the single post regex
# 2. Check if it matches the single post or the archives regex
post_match = re.fullmatch(get_path_regex("post"), path)
archives_match = re.fullmatch(get_path_regex("archives"), path)
if post_match:
# Does the post exist?
post_groups = post_match.groupdict()
return single_post(request, **post_groups)
post = get_post(**post_groups)

# If so, return the single post view
if post:
return single_post(request, post)

# If it doesn't look like an archive post, then it's a 404 - otherwise continue to the next step
if not archives_match:
msg = "Post not found"
raise Http404(msg)

# 3. Check if it matches the archives regex
archives_match = re.fullmatch(get_path_regex("archives"), path)
if archives_match:
archives_groups = archives_match.groupdict()
return archive_posts(request, **archives_groups)
Expand Down Expand Up @@ -221,38 +231,52 @@ def author_posts(request: HttpRequest, author: str) -> HttpResponse:
)


def single_post(
request: HttpRequest,
def get_post(
slug: str,
year: str | None = None,
month: str | None = None,
day: str | None = None,
) -> HttpResponse:
"""View for a single post.
) -> None | Post:
"""Try to get a post by slug and date parts.
Args:
request (HttpRequest): The request object.
slug (str): The post slug.
year (str | None): The year.
month (str | None): The month.
day (str | None): The day.
Returns:
HttpResponse: The response.
Context:
post (Post): The post object.
None | Post: The post object, or None if not found.
"""
try:
date_parts = validate_date_parts(year=year, month=month, day=day)
post = Post.post_objects.get_published_post_by_slug(slug=slug, **date_parts)
context: dict = {"post": post}
except (PostNotFoundError, ValueError) as exc:
return Post.post_objects.get_published_post_by_slug(slug=slug, **date_parts)
except (PostNotFoundError, ValueError):
# A PageNotFoundError means we were able to parse the path, but the page was not found
# A ValueError means we were not able to parse the path
msg = "Post not found"
raise Http404(msg) from exc
return None


def single_post(
request: HttpRequest,
post: Post,
) -> HttpResponse:
"""View for a single post.
The single_post view is different to the others in that it doesn't look for a post since this is done in the
dispatcher function. This view is only called if a post is found.
Args:
request (HttpRequest): The request object.
post (Post): The post object.
Returns:
HttpResponse: The response.
Context:
post (Post): The post object.
"""
context: dict = {"post": post}
template: str = get_template_name(view_name="single_post")

return render(
Expand Down
133 changes: 130 additions & 3 deletions tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from django.urls import reverse
from django.utils import timezone

from djpress.models import Post
from djpress.url_utils import get_archives_url, get_author_url, get_category_url


Expand Down Expand Up @@ -167,8 +168,21 @@ def test_category_with_category_enabled_false(client, settings):


@pytest.mark.django_db
def test_date_archives_year(client, test_post1):
def test_date_archives_year(client, settings, test_post1):
assert settings.DJPRESS_SETTINGS["ARCHIVE_PREFIX"] == "test-url-archives"
url = get_archives_url(test_post1.date.year)
assert url == f"/test-url-archives/{test_post1.date.year}/"
response = client.get(url)
assert response.status_code == 200
assert test_post1.title.encode() in response.content
assert "posts" in response.context
assert isinstance(response.context["posts"], Iterable)
assert "Test Post1" in response.content.decode()

settings.DJPRESS_SETTINGS["ARCHIVE_PREFIX"] = ""
url = get_archives_url(test_post1.date.year)
assert url == f"/{test_post1.date.year}/"

response = client.get(url)
assert response.status_code == 200
assert test_post1.title.encode() in response.content
Expand Down Expand Up @@ -196,8 +210,21 @@ def test_date_archives_year_no_posts(client, test_post1):


@pytest.mark.django_db
def test_date_archives_month(client, test_post1):
def test_date_archives_month(client, settings, test_post1):
assert settings.DJPRESS_SETTINGS["ARCHIVE_PREFIX"] == "test-url-archives"
url = get_archives_url(test_post1.date.year, test_post1.date.month)
assert url == f"/test-url-archives/{test_post1.date.year}/{test_post1.date.month}/"

response = client.get(url)
assert response.status_code == 200
assert test_post1.title.encode() in response.content
assert "posts" in response.context
assert isinstance(response.context["posts"], Iterable)

settings.DJPRESS_SETTINGS["ARCHIVE_PREFIX"] = ""
url = get_archives_url(test_post1.date.year, test_post1.date.month)
assert url == f"/{test_post1.date.year}/{test_post1.date.month}/"

response = client.get(url)
assert response.status_code == 200
assert test_post1.title.encode() in response.content
Expand Down Expand Up @@ -226,12 +253,112 @@ def test_date_archives_month_no_posts(client, test_post1):


@pytest.mark.django_db
def test_date_archives_day(client, test_post1):
def test_date_archives_day(client, settings, test_post1):
assert settings.DJPRESS_SETTINGS["ARCHIVE_PREFIX"] == "test-url-archives"
url = get_archives_url(test_post1.date.year, test_post1.date.month, test_post1.date.day)
assert url == f"/test-url-archives/{test_post1.date.year}/{test_post1.date.month}/{test_post1.date.day}/"

response = client.get(url)
assert response.status_code == 200
assert test_post1.title.encode() in response.content
assert "posts" in response.context
assert isinstance(response.context["posts"], Iterable)

settings.DJPRESS_SETTINGS["ARCHIVE_PREFIX"] = ""
url = get_archives_url(test_post1.date.year, test_post1.date.month, test_post1.date.day)
assert url == f"/{test_post1.date.year}/{test_post1.date.month}/{test_post1.date.day}/"

response = client.get(url)
assert response.status_code == 200
assert test_post1.title.encode() in response.content
assert "posts" in response.context
assert isinstance(response.context["posts"], Iterable)

assert settings.DJPRESS_SETTINGS["POST_PREFIX"] == "test-posts"
settings.DJPRESS_SETTINGS["POST_PREFIX"] = "{{ year }}/{{ month }}/{{ day }}"
url = get_archives_url(test_post1.date.year, test_post1.date.month, test_post1.date.day)
assert url == f"/{test_post1.date.year}/{test_post1.date.month}/{test_post1.date.day}/"

response = client.get(url)
assert response.status_code == 200
assert test_post1.title.encode() in response.content
assert "posts" in response.context
assert isinstance(response.context["posts"], Iterable)


@pytest.mark.django_db
def test_conflict_day_archives_and_single_post(client, settings, test_post1):
"""Change the POST_PREFIX to match the same format as the day archives.
For example, with POST_PREFIX = "{{ year }}/{{ month }}", either of the following two URLs could be valid posts:
- /2024/01/31/ - This could be a day archive, or a post with the slug "31" in the year 2024 and month 01.
- /2024/01/test-post1/
The first URL will try to get a post and if that doesn't exist, it will try to get a day archive, but only if the
POST_PREFIX matches the day archive format.
"""
settings.DJPRESS_SETTINGS["ARCHIVE_PREFIX"] = ""
settings.DJPRESS_SETTINGS["POST_PREFIX"] = "{{ year }}/{{ month }}"
url = get_archives_url(test_post1.date.year, test_post1.date.month, test_post1.date.day)
assert url == f"/{test_post1.date.year}/{test_post1.date.month}/{test_post1.date.day}/"

response = client.get(url)
assert response.status_code == 200
assert test_post1.title.encode() in response.content
assert "posts" in response.context
assert isinstance(response.context["posts"], Iterable)


@pytest.mark.django_db
def test_conflict_month_archives_and_single_post(client, settings, test_post1):
"""Similar concept to test_conflict_day_archives_and_single_post.
With POST_PREFIX = "{{ year }}", either of the following two URLs could be valid posts:
- /2024/12/ - This could be a month archive, or a post with the slug "12" in the year 2024.
- /2024/test-post1/
"""
settings.DJPRESS_SETTINGS["ARCHIVE_PREFIX"] = ""
settings.DJPRESS_SETTINGS["POST_PREFIX"] = "{{ year }}"
url = get_archives_url(test_post1.date.year, test_post1.date.month)
assert url == f"/{test_post1.date.year}/{test_post1.date.month}/"

response = client.get(url)
assert response.status_code == 200
assert test_post1.title.encode() in response.content
assert "posts" in response.context
assert isinstance(response.context["posts"], Iterable)


@pytest.mark.django_db
def test_conflict_year_archives_and_single_post(client, settings, test_post1):
"""Similar concept to test_conflict_day_archives_and_single_post and test_conflict_month_archives_and_single_post.
With POST_PREFIX = "", either of the following two URLs could be valid posts:
- /2024/ - This could be a year archive, or a post with the slug "2024".
- /test-post1/
"""
settings.DJPRESS_SETTINGS["ARCHIVE_PREFIX"] = ""
settings.DJPRESS_SETTINGS["POST_PREFIX"] = ""
url = get_archives_url(test_post1.date.year)
assert url == f"/{test_post1.date.year}/"

response = client.get(url)
assert response.status_code == 200
assert test_post1.title.encode() in response.content
assert "posts" in response.context
assert isinstance(response.context["posts"], Iterable)

# If the post slug is 2024, then the post will be returned.
test_post1.slug = str(test_post1.date.year)
test_post1.save()
response = client.get(url)
assert response.status_code == 200
assert test_post1.title.encode() in response.content
assert "post" in response.context
assert isinstance(response.context["post"], Post)


@pytest.mark.django_db
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 7edcf5c

Please sign in to comment.