Skip to content

Commit

Permalink
Redirect to post views (#1802)
Browse files Browse the repository at this point in the history
  • Loading branch information
rafalp authored Sep 4, 2024
1 parent ee00407 commit 323bfff
Show file tree
Hide file tree
Showing 31 changed files with 1,633 additions and 718 deletions.
107 changes: 107 additions & 0 deletions dev-docs/plugins/hooks/get-redirect-to-post-response-hook.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# `get_redirect_to_post_response_hook`

This hook wraps the standard function that Misago uses to get a HTTP redirect response to a post.


## Location

This hook can be imported from `misago.threads.hooks`:

```python
from misago.threads.hooks import get_redirect_to_post_response_hook
```


## Filter

```python
def custom_get_redirect_to_post_response_filter(
action: GetRedirectToPostResponseHookAction,
request: HttpRequest,
post: Post,
) -> HttpResponse:
...
```

A function implemented by a plugin that can be registered in this hook.


### Arguments

#### `action: GetRedirectToPostResponseHookAction`

A standard Misago function used to get a HTTP redirect response to a post.

See the [action](#action) section for details.


#### `request: HttpRequest`

The request object.


#### `post: Post`

A post to redirect to. It's `category` attribute is already populated.


### Return value

Django's `HttpResponse` with redirect to a post.


## Action

```python
def get_redirect_to_post_response_action(request: HttpRequest, post: Post) -> HttpResponse:
...
```

A standard Misago function used to get a HTTP redirect response to a post.


### Arguments

#### `request: HttpRequest`

The request object.


#### `post: Post`

A post to redirect to. It's `category` attribute is already populated.


### Return value

Django's `HttpResponse` with redirect to a post.


## Example

The code below implements a custom filter function that creates custom redirect response for posts in non-standard category type:

```python
from django.http import HttpRequest
from django.shortcuts import redirect
from django.urls import reverse

from misago.threads.hooks import get_redirect_to_post_response_hook
from misago.threads.models import Post

BLOG_CATEGORY_TREE = 500

@get_redirect_to_post_response_hook.append_filter
def redirect_to_blog_comment(
action, request: HttpRequest, post: Post
) -> HttpResponse:
if post.category.tree_id == BLOG_CATEGORY_TREE:
return redirect(
reverse(
"blog:story",
kwargs={"id": post.thread_id},
) + f"#comment-{post.id}"
)

return action(request, post)
```
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ from misago.threads.hooks import get_thread_posts_feed_item_user_ids_hook

```python
def custom_get_thread_posts_feed_item_user_ids_filter(
request: HttpRequest, thread: Thread, page: int | None=None
request: HttpRequest, item: dict, user_ids: set[int]
):
...
```
Expand Down
101 changes: 101 additions & 0 deletions dev-docs/plugins/hooks/get-thread-url-hook.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# `get_thread_url_hook`

This hook wraps the standard function that Misago useds to retrieve a thread URL based on its category type.


## Location

This hook can be imported from `misago.threads.hooks`:

```python
from misago.threads.hooks import get_thread_url_hook
```


## Filter

```python
def custom_get_thread_url_filter(
action: GetThreadUrlHookAction,
thread: Thread,
category: Category | None=None,
) -> QuerySet:
...
```

A function implemented by a plugin that can be registered in this hook.


### Arguments

#### `action: GetThreadUrlHookAction`

A standard Misago function used to retrieve a thread URL based on its category type.

See the [action](#action) section for details.


#### `thread: Thread`

A `Thread` instance.


#### `category: Category`

A `Category` instance, if `thread.category` was not populated using `select_related` or `prefetch_related`. Otherwise it's `None` and `thread.category` should be used instead.


### Return value

An `str` with URL.


## Action

```python
def get_thread_url_action(thread: Thread, category: Category | None=None) -> QuerySet:
...
```

A standard Misago function used to retrieve a thread URL based on its category type.


### Arguments

#### `thread: Thread`

A `Thread` instance.


#### `category: Category`

A `Category` instance, if `thread.category` was not populated using `select_related` or `prefetch_related`. Otherwise it's `None` and `thread.category` should be used instead.


### Return value

An `str` with URL.


## Example

The code below implements a custom filter function that returns thread's URL for custom category type:

```python
from django.urls import reverse
from misago.categories.models import Category
from misago.threads.hooks import get_thread_url_hook
from misago.threads.models import Thread


@get_thread_url_hook.append_filter
def get_thread_blog_url(
action, thread: Thread, category: Category | None = None
):
if (category or thread.category).plugin_data.get("is_blog"):
return reverse(
"blog", kwargs={"id": thread.id, "slug": thread.slug}
)

return = action(thread, category)
```
2 changes: 2 additions & 0 deletions dev-docs/plugins/hooks/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,13 @@ Hooks instances are importable from the following Python modules:
- [`get_private_threads_page_filters_hook`](./get-private-threads-page-filters-hook.md)
- [`get_private_threads_page_queryset_hook`](./get-private-threads-page-queryset-hook.md)
- [`get_private_threads_page_threads_hook`](./get-private-threads-page-threads-hook.md)
- [`get_redirect_to_post_response_hook`](./get-redirect-to-post-response-hook.md)
- [`get_thread_posts_feed_item_user_ids_hook`](./get-thread-posts-feed-item-user-ids-hook.md)
- [`get_thread_posts_feed_users_hook`](./get-thread-posts-feed-users-hook.md)
- [`get_thread_replies_page_context_data_hook`](./get-thread-replies-page-context-data-hook.md)
- [`get_thread_replies_page_posts_queryset_hook`](./get-thread-replies-page-posts-queryset-hook.md)
- [`get_thread_replies_page_thread_queryset_hook`](./get-thread-replies-page-thread-queryset-hook.md)
- [`get_thread_url_hook`](./get-thread-url-hook.md)
- [`get_threads_page_context_data_hook`](./get-threads-page-context-data-hook.md)
- [`get_threads_page_filters_hook`](./get-threads-page-filters-hook.md)
- [`get_threads_page_moderation_actions_hook`](./get-threads-page-moderation-actions-hook.md)
Expand Down
6 changes: 4 additions & 2 deletions misago/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ def private_thread_user_reply(private_thread, user):


@pytest.fixture
def user_private_thread(private_threads_category, user, other_user):
def user_private_thread(private_threads_category, user, other_user, moderator):
thread = post_thread(
private_threads_category,
"User Private Thread",
Expand All @@ -448,12 +448,13 @@ def user_private_thread(private_threads_category, user, other_user):

ThreadParticipant.objects.create(thread=thread, user=user, is_owner=True)
ThreadParticipant.objects.create(thread=thread, user=other_user, is_owner=False)
ThreadParticipant.objects.create(thread=thread, user=moderator, is_owner=False)

return thread


@pytest.fixture
def other_user_private_thread(private_threads_category, user, other_user):
def other_user_private_thread(private_threads_category, user, other_user, moderator):
thread = post_thread(
private_threads_category,
"Other User Private Thread",
Expand All @@ -462,6 +463,7 @@ def other_user_private_thread(private_threads_category, user, other_user):

ThreadParticipant.objects.create(thread=thread, user=other_user, is_owner=True)
ThreadParticipant.objects.create(thread=thread, user=user, is_owner=False)
ThreadParticipant.objects.create(thread=thread, user=moderator, is_owner=False)

return thread

Expand Down
23 changes: 6 additions & 17 deletions misago/notifications/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from django.utils.translation import pgettext

from ..categories.enums import CategoryTree
from ..threads.views.goto import PrivateThreadGotoPostView, ThreadGotoPostView
from ..threads.views.redirect import get_redirect_to_post_response
from .verbs import NotificationVerb
from .exceptions import NotificationVerbError

Expand Down Expand Up @@ -158,27 +158,16 @@ def get_replied_notification_message(notification: "Notification") -> str:
}


go_to_thread_post = ThreadGotoPostView.as_view()
go_to_private_thread_post = PrivateThreadGotoPostView.as_view()


@registry.redirect(NotificationVerb.REPLIED)
def get_replied_notification_url(
request: HttpRequest, notification: "Notification"
) -> str:
if notification.category.tree_id == CategoryTree.PRIVATE_THREADS:
view = go_to_private_thread_post
else:
view = go_to_thread_post

redirect = view(
request,
notification.thread_id,
notification.thread.slug,
post=notification.post_id,
)
post = notification.post
post.category = notification.category

response = get_redirect_to_post_response(request, post)

return redirect.headers["location"]
return response.headers["location"]


# INVITED: invited to private thread
Expand Down
7 changes: 7 additions & 0 deletions misago/notifications/threads.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from typing import TYPE_CHECKING, Dict, Iterable, Optional

from django.db.models import IntegerChoices
from django.urls import reverse
from django.utils.translation import pgettext, pgettext_lazy

from ..acl.useracl import get_user_acl
Expand All @@ -18,6 +19,7 @@
can_see_thread,
exclude_invisible_posts,
)
from ..threads.threadurl import get_thread_url
from .verbs import NotificationVerb
from .models import Notification, WatchedThread
from .users import notify_user
Expand Down Expand Up @@ -154,6 +156,7 @@ def email_watcher_on_new_thread_reply(
"settings": settings,
"watched_thread": watched_thread,
"thread": post.thread,
"thread_url": get_thread_url(post.thread),
"post": post,
},
)
Expand Down Expand Up @@ -278,6 +281,10 @@ def email_participant_on_new_private_thread(
"settings": settings,
"watched_thread": watched_thread,
"thread": thread,
"thread_url": reverse(
"misago:private-thread",
kwargs={"id": thread.id, "slug": thread.slug},
),
},
)

Expand Down
2 changes: 1 addition & 1 deletion misago/readtracker/tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def get_thread_read_time(request: HttpRequest, thread: Thread) -> datetime:
def mark_thread_read(user: "User", thread: Thread, read_time: datetime):
create_row = True

if thread.read_time:
if getattr(thread, "read_time", None):
create_row = not ReadThread.objects.filter(
user=user,
thread=thread,
Expand Down
2 changes: 1 addition & 1 deletion misago/templates/misago/emails/privatethread/added.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@
{% endblocktrans %}
<br>
<br>
<a href="{% absoluteurl thread.get_absolute_url %}">{{ thread.title }}</a>
<a href="{% absoluteurl thread_url %}">{{ thread.title }}</a>
<br>
{% endblock content %}
2 changes: 1 addition & 1 deletion misago/templates/misago/emails/privatethread/added.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
{% blocktrans trimmed context "new private thread email" %}
To read this thread click the link below:
{% endblocktrans %}
{% absoluteurl thread.get_absolute_url %}
{% absoluteurl thread_url %}
{% endblock content %}
2 changes: 1 addition & 1 deletion misago/templates/misago/emails/thread/reply.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

{% block content %}
{% capture trimmed as thread_link %}
<a href="{% absoluteurl thread.get_absolute_url %}">{{ thread }}</a>
<a href="{% absoluteurl thread_url %}">{{ thread }}</a>
{% endcapture %}
{% blocktrans trimmed with sender=sender thread=thread_link|safe context "new thread reply email" %}
{{ sender }} has posted a new reply to the {{ thread }} thread that you are watching.
Expand Down
Loading

0 comments on commit 323bfff

Please sign in to comment.