Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minimal posting threads views #1778

Merged
merged 24 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
807a12f
Setup empty posting app
rafalp Jul 29, 2024
a00f0c8
Empty views for starting thread
rafalp Jul 29, 2024
7cf7605
Very raw posting threads action
rafalp Jul 29, 2024
4f0b07d
Small refactor of thread start view
rafalp Jul 30, 2024
04761e6
WIP select category to start thread at
rafalp Jul 30, 2024
f90cc16
More iteration on category selector
rafalp Aug 1, 2024
26e7a02
Move posting thread logic to special state object
rafalp Aug 3, 2024
89e4a9d
Tweak design of category picker for starting thread
rafalp Aug 4, 2024
b72fc80
Further tweak category picker on thread start page
rafalp Aug 4, 2024
b26fae2
Another tweak to select category page
rafalp Aug 4, 2024
46886aa
Rename thread start check functions, move start thread category choic…
rafalp Aug 5, 2024
90036ea
Small codebase refactor, keep track of changes to models in state
rafalp Aug 5, 2024
a6c7307
Add hooks for posting in closed category and start thread permission …
rafalp Aug 6, 2024
65ada6c
Fix invalid login link
rafalp Aug 6, 2024
23e2b3a
Add private thread permissions to groups
rafalp Aug 6, 2024
aa6991a
Commit new files
rafalp Aug 6, 2024
8470f3a
Barebones start private thread form
rafalp Aug 7, 2024
237b7a7
Add some tests to thread start views
rafalp Aug 7, 2024
45bed61
Add tests for start thread views
rafalp Aug 7, 2024
3d8c220
Add tests for start thread and select category views
rafalp Aug 7, 2024
9a84c23
Default to showing start and reply buttons to guests in the UI
rafalp Aug 7, 2024
0852d5f
Generate hooks docs
rafalp Aug 7, 2024
0e359cf
Write tests for new permission checks
rafalp Aug 7, 2024
2ceb8f0
Cleanup select category component a little
rafalp Aug 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ A function implemented by a plugin that can be registered in this hook.

A standard Misago function used to check if the user has permission to browse a category. It also checks if the user can see the category. It raises Django's `Http404` if they can't see it or `PermissionDenied` with an error message if they can't browse it.

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


#### `user_permissions: UserPermissionsProxy`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# `check_post_in_closed_category_permission_hook`

This hook wraps the standard function that Misago uses to check if the user has permission to post in a closed category. It raises Django's `PermissionDenied` with an error message if category is closed and they can't post in it.


## Location

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

```python
from misago.permissions.hooks import check_post_in_closed_category_permission_hook
```


## Filter

```python
def custom_check_post_in_closed_category_permission_filter(
action: CheckPostInClosedCategoryPermissionHookAction,
permissions: 'UserPermissionsProxy',
category: Category,
) -> None:
...
```

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


### Arguments

#### `action: CheckPostInClosedCategoryPermissionHookAction`

A standard Misago function used to check if the user has permission to post in a closed category. It raises Django's `PermissionDenied` with an error message if category is closed and they can't post in it.

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


#### `user_permissions: UserPermissionsProxy`

A proxy object with the current user's permissions.


#### `category: Category`

A category to check permissions for.


## Action

```python
def check_post_in_closed_category_permission_action(
permissions: 'UserPermissionsProxy', category: Category
) -> None:
...
```

A standard Misago function used to check if the user has permission to post in a closed category. It raises Django's `PermissionDenied` with an error message if category is closed and they can't post in it.


### Arguments

#### `user_permissions: UserPermissionsProxy`

A proxy object with the current user's permissions.


#### `category: Category`

A category to check permissions for.


## Example

The code below implements a custom filter function that permits a user to post in the specific category if they have a custom flag set on their account.

```python
from misago.categories.models import Category
from misago.permissions.hooks import check_post_in_closed_category_permission_hook
from misago.permissions.proxy import UserPermissionsProxy

@check_post_in_closed_category_permission_hook.append_filter
def check_user_can_post_in_closed_category(
action,
permissions: UserPermissionsProxy,
category: Category,
) -> None:
user = permissions.user
if user.is_authenticated:
post_in_closed_categories = (
user.plugin_data.get("post_in_closed_categories") or []
)
else:
post_in_closed_categories = None

if (
not post_in_closed_categories
or category.id not in post_in_closed_categories
):
action(permissions, category)
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# `check_start_private_threads_permission_hook`

This hook wraps the standard function that Misago uses to check if the user has a permission to start bew private threads. Raises Django's `PermissionDenied` with an error message if they don't.


## Location

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

```python
from misago.permissions.hooks import check_start_private_threads_permission_hook
```


## Filter

```python
def custom_check_start_private_threads_permission_filter(
action: CheckStartPrivateThreadsPermissionHookAction,
permissions: 'UserPermissionsProxy',
) -> None:
...
```

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


### Arguments

#### `action: CheckStartPrivateThreadsPermissionHookAction`

A standard Misago function used to check if the user has a permission to start new private threads. Raises Django's `PermissionDenied` with an error message if they don't.

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


#### `user_permissions: UserPermissionsProxy`

A proxy object with the current user's permissions.


## Action

```python
def check_start_private_threads_permission_action(permissions: 'UserPermissionsProxy') -> None:
...
```

A standard Misago function used to check if the user has a permission to start new private threads. Raises Django's `PermissionDenied` with an error message if they don't.


### Arguments

#### `user_permissions: UserPermissionsProxy`

A proxy object with the current user's permissions.


## Example

The code below implements a custom filter function that blocks user from starting new private threads if there's a custom flag set on their account.

```python
from django.core.exceptions import PermissionDenied
from django.utils.translation import pgettext
from misago.permissions.hooks import check_start_private_threads_permission_hook
from misago.permissions.proxy import UserPermissionsProxy

@check_start_private_threads_permission_hook.append_filter
def check_user_is_banned_from_starting_private_threads(
action,
permissions: UserPermissionsProxy,
) -> None:
# Run standard permission checks
action(permissions)

if permissions.user.plugin_data.get("ban_start_private_threads"):
raise PermissionDenied(
pgettext(
"private threads permission error",
"Site admin has removed your option to start private threads."
)
)
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# `check_start_thread_in_category_permission_hook`

This hook wraps the standard Misago function used to check if the user has permission to start a new thread in a category. It raises Django's `PermissionDenied` with an error message if they can't start thread in a category.


## Location

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

```python
from misago.permissions.hooks import check_start_thread_in_category_permission_hook
```


## Filter

```python
def custom_check_start_thread_in_category_permission_filter(
action: CheckStartThreadInCategoryPermissionHookAction,
permissions: 'UserPermissionsProxy',
category: Category,
) -> None:
...
```

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


### Arguments

#### `action: CheckStartThreadInCategoryPermissionHookAction`

A standard Misago function used to check if the user has permission to start a new thread in a category. It raises Django's `PermissionDenied` with an error message if they can't start thread in a category.

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


#### `user_permissions: UserPermissionsProxy`

A proxy object with the current user's permissions.


#### `category: Category`

A category to check permissions for.


## Action

```python
def check_start_thread_in_category_permission_action(
permissions: 'UserPermissionsProxy', category: Category
) -> None:
...
```

A standard Misago function used to check if the user has permission to start a new thread in a category. It raises Django's `PermissionDenied` with an error message if they can't start thread in a category.


### Arguments

#### `user_permissions: UserPermissionsProxy`

A proxy object with the current user's permissions.


#### `category: Category`

A category to check permissions for.


## Example

The code below implements a custom filter function that prevents the user from starting a thread in category if their account is newer than 7 days.

```python
from datetime import timedelta

from django.core.exceptions import PermissionDenied
from django.utils import timezone
from misago.categories.models import Category
from misago.permissions.hooks import check_start_thread_in_category_permission_hook
from misago.permissions.proxy import UserPermissionsProxy

@check_start_thread_in_category_permission_hook.append_filter
def check_user_can_start_thread(
action,
permissions: UserPermissionsProxy,
category: Category,
) -> None:
action(permissions, category)

user = permissions.user
if (
user.is_authenticated
and user.joined_on > timezone.now() - timedelta(days=7):
):
raise PermissionDenied(
"Your account was created less than 7 days ago. "
"You can't start threads yet."
)
```
3 changes: 3 additions & 0 deletions dev-docs/plugins/hooks/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,11 @@ Hooks instances are importable from the following Python modules:
- [`build_user_category_permissions_hook`](./build-user-category-permissions-hook.md)
- [`build_user_permissions_hook`](./build-user-permissions-hook.md)
- [`check_browse_category_permission_hook`](./check-browse-category-permission-hook.md)
- [`check_post_in_closed_category_permission_hook`](./check-post-in-closed-category-permission-hook.md)
- [`check_private_threads_permission_hook`](./check-private-threads-permission-hook.md)
- [`check_see_category_permission_hook`](./check-see-category-permission-hook.md)
- [`check_start_private_threads_permission_hook`](./check-start-private-threads-permission-hook.md)
- [`check_start_thread_in_category_permission_hook`](./check-start-thread-in-category-permission-hook.md)
- [`copy_category_permissions_hook`](./copy-category-permissions-hook.md)
- [`copy_group_permissions_hook`](./copy-group-permissions-hook.md)
- [`filter_private_threads_queryset_hook`](./filter-private-threads-queryset-hook.md)
Expand Down
18 changes: 14 additions & 4 deletions dev-docs/plugins/template-outlets-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ On the admin dashboard page, above all other content.

## `CATEGORIES_LIST_END`

On the categories page, under the list.
On the categories page, below the list.


## `CATEGORIES_LIST_START`
Expand All @@ -35,7 +35,7 @@ On the categories page, above the list.

## `CATEGORY_THREADS_LIST_END`

On the category threads page, under the list.
On the category threads page, below the list.


## `CATEGORY_THREADS_LIST_MIDDLE`
Expand All @@ -48,9 +48,19 @@ On the category threads page, between the subcategories and the list.
On the category threads page, above the list.


## `LOGIN_PAGE_END`

On the sign in page, below the form.


## `LOGIN_PAGE_START`

On the sign in page, above the form.


## `PRIVATE_THREADS_LIST_END`

On the private threads page, under the list.
On the private threads page, below the list.


## `PRIVATE_THREADS_LIST_START`
Expand All @@ -65,7 +75,7 @@ Used in some tests.

## `THREADS_LIST_END`

On the threads page, under the list.
On the threads page, below the list.


## `THREADS_LIST_MIDDLE`
Expand Down
6 changes: 1 addition & 5 deletions frontend/src/components/Timestamp/Timestamp.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import React from "react"
import {
dateRelative,
dateRelativeShort,
fullDateTime,
} from "../../formats"
import { dateRelative, dateRelativeShort, fullDateTime } from "../../formats"

class Timestamp extends React.Component {
constructor(props) {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/post-feed/post/body.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function (props) {
export function Default(props) {
return (
<div className="post-body">
<MisagoMarkup markup={props.post.content} />
<MisagoMarkup markup={props.post.headline || props.post.content} />
</div>
)
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/search-route/threads/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default function (props) {
<div className="post-border">
<div className="post-body">
<div className="panel panel-default panel-post">
<PostBody content={props.post.content} />
<PostBody content={props.post.headline || props.post.content} />
<PostFooter
category={props.post.category}
post={props.post}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/search/SearchResultPost.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default function SearchResultPost({ post }) {
<div className="search-result-name">{post.thread.title}</div>
<div
className="search-result-summary"
dangerouslySetInnerHTML={{ __html: post.content }}
dangerouslySetInnerHTML={{ __html: post.headline || post.content }}
/>
<ul className="search-result-details">
<li>
Expand Down
Loading
Loading