diff --git a/misago/posting/hooks/__init__.py b/misago/posting/hooks/__init__.py index e3bb0aed7..319ee3c92 100644 --- a/misago/posting/hooks/__init__.py +++ b/misago/posting/hooks/__init__.py @@ -1,12 +1,26 @@ -from .get_start_private_thread_state import get_start_private_thread_state_hook -from .get_start_thread_state import get_start_thread_state_hook +from .get_start_private_thread_page_context_data import ( + get_start_private_thread_page_context_data_hook, +) +from .get_start_private_thread_page_formset import ( + get_start_private_thread_page_formset_hook, +) +from .get_start_private_thread_page_state import ( + get_start_private_thread_page_state_hook, +) +from .get_start_thread_page_context_data import get_start_thread_page_context_data_hook +from .get_start_thread_page_formset import get_start_thread_page_formset_hook +from .get_start_thread_page_state import get_start_thread_page_state_hook from .save_start_private_thread_state import save_start_private_thread_state_hook from .save_start_thread_state import save_start_thread_state_hook __all__ = [ - "get_start_private_thread_state_hook", - "get_start_thread_state_hook", + "get_start_private_thread_page_context_data_hook", + "get_start_private_thread_page_formset_hook", + "get_start_private_thread_page_state_hook", + "get_start_thread_page_context_data_hook", + "get_start_thread_page_formset_hook", + "get_start_thread_page_state_hook", "save_start_private_thread_state_hook", "save_start_thread_state_hook", ] diff --git a/misago/posting/hooks/get_start_private_thread_page_context_data.py b/misago/posting/hooks/get_start_private_thread_page_context_data.py new file mode 100644 index 000000000..d1c9fa2dc --- /dev/null +++ b/misago/posting/hooks/get_start_private_thread_page_context_data.py @@ -0,0 +1,132 @@ +from typing import TYPE_CHECKING, Protocol + +from django.http import HttpRequest + +from ...categories.models import Category +from ...plugins.hooks import FilterHook + +if TYPE_CHECKING: + from ..forms.start import StartThreadFormset + + +class GetStartPrivateThreadPageContextDataHookAction(Protocol): + """ + A standard Misago function used to get the template context data + for the start private thread page. + + # Arguments + + ## `request: HttpRequest` + + The request object. + + ## `category: Category` + + The `Category` instance. + + ## `formset: StartThreadFormset` + + The `StartThreadFormset` instance. + + # Return value + + A Python `dict` with context data to use to `render` the start private thread page. + """ + + def __call__( + self, + request: HttpRequest, + category: Category, + formset: "StartThreadFormset", + ) -> dict: ... + + +class GetStartPrivateThreadPageContextDataHookFilter(Protocol): + """ + A function implemented by a plugin that can be registered in this hook. + + # Arguments + + ## `action: GetStartPrivateThreadPageContextDataHookAction` + + A standard Misago function used to get the template context data + for the start private thread page. + + See the [action](#action) section for details. + + ## `request: HttpRequest` + + The request object. + + ## `category: Category` + + The `Category` instance. + + ## `formset: StartThreadFormset` + + The `StartThreadFormset` instance. + + # Return value + + A Python `dict` with context data to use to `render` the start private thread page. + """ + + def __call__( + self, + action: GetStartPrivateThreadPageContextDataHookAction, + request: HttpRequest, + category: Category, + formset: "StartThreadFormset", + ) -> dict: ... + + +class GetStartPrivateThreadPageContextDataHook( + FilterHook[ + GetStartPrivateThreadPageContextDataHookAction, + GetStartPrivateThreadPageContextDataHookFilter, + ] +): + """ + This hook wraps the standard function that Misago uses to get the template + context data for the start private thread page. + + # Example + + The code below implements a custom filter function that adds extra values to + the template context data: + + ```python + from django.http import HttpRequest + from misago.categories.models import Category + from misago.posting.forms.start import StartThreadFormset + from misago.posting.hooks import get_start_private_thread_page_context_data_hook + + + @get_start_private_thread_page_context_data_hook.append_filter + def set_show_first_post_warning_in_context( + action, + request: HttpRequest, + category: Category, + formset: StartThreadFormset, + ) -> dict: + context = action(request, category, formset) + context["show_first_post_warning"] = not requser.user.posts + return context + ``` + """ + + __slots__ = FilterHook.__slots__ + + def __call__( + self, + action: GetStartPrivateThreadPageContextDataHookAction, + request: HttpRequest, + category: Category, + formset: "StartThreadFormset", + ) -> dict: + return super().__call__(action, request, category, formset) + + +get_start_private_thread_page_context_data_hook = ( + GetStartPrivateThreadPageContextDataHook(cache=False) +) diff --git a/misago/posting/hooks/get_start_private_thread_page_formset.py b/misago/posting/hooks/get_start_private_thread_page_formset.py new file mode 100644 index 000000000..0c76e6c36 --- /dev/null +++ b/misago/posting/hooks/get_start_private_thread_page_formset.py @@ -0,0 +1,128 @@ +from typing import TYPE_CHECKING, Protocol + +from django.http import HttpRequest + +from ...categories.models import Category +from ...plugins.hooks import FilterHook + +if TYPE_CHECKING: + from ..forms.start import StartThreadFormset + + +class GetStartPrivateThreadPageFormsetHookAction(Protocol): + """ + A standard function that Misago uses to create a new + `StartThreadFormset` instance for the start a new private thread page. + + # Arguments + + ## `request: HttpRequest` + + The request object. + + ## `category: Category` + + The `Category` instance. + + # Return value + + A `StartThreadFormset` instance with forms to display + on the start a new private thread page. + """ + + def __call__( + self, + request: HttpRequest, + category: Category, + ) -> "StartThreadFormset": ... + + +class GetStartPrivateThreadPageFormsetHookFilter(Protocol): + """ + A function implemented by a plugin that can be registered in this hook. + + # Arguments + + ## `action: GetStartPrivateThreadPageFormsetHookAction` + + A standard function that Misago uses to create a new + `StartThreadFormset` instance for the start a new private thread page. + + See the [action](#action) section for details. + + ## `request: HttpRequest` + + The request object. + + ## `category: Category` + + The `Category` instance. + + # Return value + + A `StartThreadFormset` instance with forms to display + on the start a new private thread page. + """ + + def __call__( + self, + action: GetStartPrivateThreadPageFormsetHookAction, + request: HttpRequest, + category: Category, + ) -> "StartThreadFormset": ... + + +class GetStartPrivateThreadPageFormsetHook( + FilterHook[ + GetStartPrivateThreadPageFormsetHookAction, + GetStartPrivateThreadPageFormsetHookFilter, + ] +): + """ + This hook wraps the standard function that Misago uses to create a new + `StartThreadFormset` instance for the start a new private thread page. + + # Example + + The code below implements a custom filter function that adds custom form to + the start a new private thread page: + + ```python + from django.http import HttpRequest + from misago.categories.models import Category + from misago.posting.hooks import get_start_private_thread_page_formset_hook + from misago.posting.forms.start import StartThreadFormset + + from .forms import SelectUserForm + + + @get_start_private_thread_page_formset_hook.append_filter + def add_select_user_form( + action, request: HttpRequest, category: Category + ) -> StartThreadFormset: + formset = action(request, category) + + if request.method == "POST": + form = SelectUserForm(request.POST, prefix="select-user") + else: + form = SelectUserForm(prefix="select-user") + + formset.add_form(form) + return formset + ``` + """ + + __slots__ = FilterHook.__slots__ + + def __call__( + self, + action: GetStartPrivateThreadPageFormsetHookAction, + request: HttpRequest, + category: Category, + ) -> "StartThreadFormset": + return super().__call__(action, request, category) + + +get_start_private_thread_page_formset_hook = GetStartPrivateThreadPageFormsetHook( + cache=False +) diff --git a/misago/posting/hooks/get_start_private_thread_page_state.py b/misago/posting/hooks/get_start_private_thread_page_state.py new file mode 100644 index 000000000..1d89a23a4 --- /dev/null +++ b/misago/posting/hooks/get_start_private_thread_page_state.py @@ -0,0 +1,119 @@ +from typing import TYPE_CHECKING, Protocol + +from django.http import HttpRequest + +from ...categories.models import Category +from ...plugins.hooks import FilterHook + +if TYPE_CHECKING: + from ..state.start import StartPrivateThreadState + + +class GetStartPrivateThreadPageStateHookAction(Protocol): + """ + A standard function that Misago uses to create a new + `StartPrivateThreadState` instance for the start a new private thread page. + + # Arguments + + ## `request: HttpRequest` + + The request object. + + ## `category: Category` + + The `Category` instance. + + # Return value + + A `StartPrivateThreadState` instance to use to save new private thread + to the database. + """ + + def __call__( + self, + request: HttpRequest, + category: Category, + ) -> "StartPrivateThreadState": ... + + +class GetStartPrivateThreadPageStateHookFilter(Protocol): + """ + A function implemented by a plugin that can be registered in this hook. + + # Arguments + + ## `action: GetStartPrivateThreadPageStateHookAction` + + A standard function that Misago uses to create a new + `StartPrivateThreadState` instance for the start a new private thread page. + + See the [action](#action) section for details. + + ## `request: HttpRequest` + + The request object. + + ## `category: Category` + + The `Category` instance. + + # Return value + + A `StartPrivateThreadState` instance to use to save new private thread + to the database. + """ + + def __call__( + self, + action: GetStartPrivateThreadPageStateHookAction, + request: HttpRequest, + category: Category, + ) -> "StartPrivateThreadState": ... + + +class GetStartPrivateThreadPageStateHook( + FilterHook[ + GetStartPrivateThreadPageStateHookAction, + GetStartPrivateThreadPageStateHookFilter, + ] +): + """ + This hook wraps the standard function that Misago uses to create a new + `StartPrivateThreadState` instance for the start a new private thread page. + # Example + + The code below implements a custom filter function that stores the user's IP + in the state. + + ```python + from django.http import HttpRequest + from misago.categories.models import Category + from misago.posting.hooks import get_start_private_thread_page_state_hook + from misago.posting.state.start import StartPrivateThreadState + + + @get_start_private_thread_page_state_hook.append_filter + def set_poster_ip_on_start_private_thread_page_state( + action, request: HttpRequest, category: Category + ) -> StartPrivateThreadState: + state = action(request, category) + state.plugin_state["user_id"] = request.user_ip + return state + ``` + """ + + __slots__ = FilterHook.__slots__ + + def __call__( + self, + action: GetStartPrivateThreadPageStateHookAction, + request: HttpRequest, + category: Category, + ) -> "StartPrivateThreadState": + return super().__call__(action, request, category) + + +get_start_private_thread_page_state_hook = GetStartPrivateThreadPageStateHook( + cache=False +) diff --git a/misago/posting/hooks/get_start_thread_page_context_data.py b/misago/posting/hooks/get_start_thread_page_context_data.py new file mode 100644 index 000000000..8196a1623 --- /dev/null +++ b/misago/posting/hooks/get_start_thread_page_context_data.py @@ -0,0 +1,129 @@ +from typing import TYPE_CHECKING, Protocol + +from django.http import HttpRequest + +from ...categories.models import Category +from ...plugins.hooks import FilterHook + +if TYPE_CHECKING: + from ..forms.start import StartThreadFormset + + +class GetStartThreadPageContextDataHookAction(Protocol): + """ + A standard Misago function used to get the template context data + for the start thread page. + + # Arguments + + ## `request: HttpRequest` + + The request object. + + ## `category: Category` + + The `Category` instance. + + ## `formset: StartThreadFormset` + + The `StartThreadFormset` instance. + + # Return value + + A Python `dict` with context data to use to `render` the start thread page. + """ + + def __call__( + self, + request: HttpRequest, + category: Category, + formset: "StartThreadFormset", + ) -> dict: ... + + +class GetStartThreadPageContextDataHookFilter(Protocol): + """ + A function implemented by a plugin that can be registered in this hook. + + # Arguments + + ## `action: GetStartThreadPageContextDataHookAction` + + A standard Misago function used to get the template context data + for the start thread page. + + See the [action](#action) section for details. + + ## `request: HttpRequest` + + The request object. + + ## `category: Category` + + The `Category` instance. + + ## `formset: StartThreadFormset` + + The `StartThreadFormset` instance. + + # Return value + + A Python `dict` with context data to use to `render` the start thread page. + """ + + def __call__( + self, + action: GetStartThreadPageContextDataHookAction, + request: HttpRequest, + category: Category, + formset: "StartThreadFormset", + ) -> dict: ... + + +class GetStartThreadPageContextDataHook( + FilterHook[ + GetStartThreadPageContextDataHookAction, GetStartThreadPageContextDataHookFilter + ] +): + """ + This hook wraps the standard function that Misago uses to get the template + context data for the start thread page. + + # Example + + The code below implements a custom filter function that adds extra values to + the template context data: + + ```python + from django.http import HttpRequest + from misago.categories.models import Category + from misago.posting.forms.start import StartThreadFormset + from misago.posting.hooks import get_start_thread_page_context_data_hook + + + @get_start_thread_page_context_data_hook.append_filter + def set_show_first_post_warning_in_context( + action, + request: HttpRequest, + category: Category, + formset: StartThreadFormset, + ) -> dict: + context = action(request, category, formset) + context["show_first_post_warning"] = not requser.user.posts + return context + ``` + """ + + __slots__ = FilterHook.__slots__ + + def __call__( + self, + action: GetStartThreadPageContextDataHookAction, + request: HttpRequest, + category: Category, + formset: "StartThreadFormset", + ) -> dict: + return super().__call__(action, request, category, formset) + + +get_start_thread_page_context_data_hook = GetStartThreadPageContextDataHook(cache=False) diff --git a/misago/posting/hooks/get_start_thread_page_formset.py b/misago/posting/hooks/get_start_thread_page_formset.py new file mode 100644 index 000000000..ee3740c20 --- /dev/null +++ b/misago/posting/hooks/get_start_thread_page_formset.py @@ -0,0 +1,123 @@ +from typing import TYPE_CHECKING, Protocol + +from django.http import HttpRequest + +from ...categories.models import Category +from ...plugins.hooks import FilterHook + +if TYPE_CHECKING: + from ..forms.start import StartThreadFormset + + +class GetStartThreadPageFormsetHookAction(Protocol): + """ + A standard function that Misago uses to create a new + `StartThreadFormset` instance for the start a new thread page. + + # Arguments + + ## `request: HttpRequest` + + The request object. + + ## `category: Category` + + The `Category` instance. + + # Return value + + A `StartThreadFormset` instance with forms to display + on the start a new thread page. + """ + + def __call__( + self, + request: HttpRequest, + category: Category, + ) -> "StartThreadFormset": ... + + +class GetStartThreadPageFormsetHookFilter(Protocol): + """ + A function implemented by a plugin that can be registered in this hook. + + # Arguments + + ## `action: GetStartThreadPageFormsetHookAction` + + A standard function that Misago uses to create a new + `StartThreadFormset` instance for the start a new thread page. + + See the [action](#action) section for details. + + ## `request: HttpRequest` + + The request object. + + ## `category: Category` + + The `Category` instance. + + # Return value + + A `StartThreadFormset` instance with forms to display + on the start a new thread page. + """ + + def __call__( + self, + action: GetStartThreadPageFormsetHookAction, + request: HttpRequest, + category: Category, + ) -> "StartThreadFormset": ... + + +class GetStartThreadPageFormsetHook( + FilterHook[GetStartThreadPageFormsetHookAction, GetStartThreadPageFormsetHookFilter] +): + """ + This hook wraps the standard function that Misago uses to create a new + `StartThreadFormset` instance for the start a new thread page. + + # Example + + The code below implements a custom filter function that adds custom form to + the start a new thread page: + + ```python + from django.http import HttpRequest + from misago.categories.models import Category + from misago.posting.hooks import get_start_thread_page_formset_hook + from misago.posting.forms.start import StartThreadFormset + + from .forms import SelectUserForm + + + @get_start_thread_page_formset_hook.append_filter + def add_select_user_form( + action, request: HttpRequest, category: Category + ) -> StartThreadFormset: + formset = action(request, category) + + if request.method == "POST": + form = SelectUserForm(request.POST, prefix="select-user") + else: + form = SelectUserForm(prefix="select-user") + + formset.add_form(form) + return formset + ``` + """ + + __slots__ = FilterHook.__slots__ + + def __call__( + self, + action: GetStartThreadPageFormsetHookAction, + request: HttpRequest, + category: Category, + ) -> "StartThreadFormset": + return super().__call__(action, request, category) + + +get_start_thread_page_formset_hook = GetStartThreadPageFormsetHook(cache=False) diff --git a/misago/posting/hooks/get_start_thread_page_state.py b/misago/posting/hooks/get_start_thread_page_state.py new file mode 100644 index 000000000..98bb4744b --- /dev/null +++ b/misago/posting/hooks/get_start_thread_page_state.py @@ -0,0 +1,113 @@ +from typing import TYPE_CHECKING, Protocol + +from django.http import HttpRequest + +from ...categories.models import Category +from ...plugins.hooks import FilterHook + +if TYPE_CHECKING: + from ..state.start import StartThreadState + + +class GetStartThreadPageStateHookAction(Protocol): + """ + A standard function that Misago uses to create a new + `StartThreadState` instance for the start a new thread page. + + # Arguments + + ## `request: HttpRequest` + + The request object. + + ## `category: Category` + + The `Category` instance. + + # Return value + + A `StartThreadState` instance to use to save new thread to the database. + """ + + def __call__( + self, + request: HttpRequest, + category: Category, + ) -> "StartThreadState": ... + + +class GetStartThreadPageStateHookFilter(Protocol): + """ + A function implemented by a plugin that can be registered in this hook. + + # Arguments + + ## `action: GetStartThreadPageStateHookAction` + + A standard function that Misago uses to create a new + `StartThreadState` instance for the start a new thread page. + + See the [action](#action) section for details. + + ## `request: HttpRequest` + + The request object. + + ## `category: Category` + + The `Category` instance. + + # Return value + + A `StartThreadState` instance to use to save new thread to the database. + """ + + def __call__( + self, + action: GetStartThreadPageStateHookAction, + request: HttpRequest, + category: Category, + ) -> "StartThreadState": ... + + +class GetStartThreadPageStateHook( + FilterHook[GetStartThreadPageStateHookAction, GetStartThreadPageStateHookFilter] +): + """ + This hook wraps the standard function that Misago uses to create a new + `StartThreadState` instance for the start a new thread page. + + # Example + + The code below implements a custom filter function that stores the user's IP + in the state. + + ```python + from django.http import HttpRequest + from misago.categories.models import Category + from misago.posting.hooks import get_start_thread_page_state_hook + from misago.posting.state.start import StartThreadState + + + @get_start_thread_page_state_hook.append_filter + def set_poster_ip_on_start_thread_state( + action, request: HttpRequest, category: Category + ) -> StartThreadState: + state = action(request, category) + state.plugin_state["user_id"] = request.user_ip + return state + ``` + """ + + __slots__ = FilterHook.__slots__ + + def __call__( + self, + action: GetStartThreadPageStateHookAction, + request: HttpRequest, + category: Category, + ) -> "StartThreadState": + return super().__call__(action, request, category) + + +get_start_thread_page_state_hook = GetStartThreadPageStateHook(cache=False) diff --git a/misago/posting/state/reply.py b/misago/posting/state/reply.py new file mode 100644 index 000000000..37ddd1816 --- /dev/null +++ b/misago/posting/state/reply.py @@ -0,0 +1,5 @@ +from .base import PostingState + + +class ReplyThreadState(PostingState): + pass diff --git a/misago/posting/views/start.py b/misago/posting/views/start.py index 51a08b33f..bc833bb14 100644 --- a/misago/posting/views/start.py +++ b/misago/posting/views/start.py @@ -21,8 +21,12 @@ StartThreadFormset, ) from ..hooks import ( - get_start_private_thread_state_hook, - get_start_thread_state_hook, + get_start_private_thread_page_context_data_hook, + get_start_private_thread_page_formset_hook, + get_start_private_thread_page_state_hook, + get_start_thread_page_context_data_hook, + get_start_thread_page_formset_hook, + get_start_thread_page_state_hook, ) from ..state.start import StartPrivateThreadState, StartThreadState @@ -96,6 +100,13 @@ def get_category(self, request: HttpRequest, kwargs: dict) -> Category: def get_formset( self, request: HttpRequest, category: Category + ) -> StartThreadFormset: + return get_start_thread_page_formset_hook( + self.get_formset_action, request, category + ) + + def get_formset_action( + self, request: HttpRequest, category: Category ) -> StartThreadFormset: formset = StartThreadFormset() formset.add_form(self.get_start_thread_form(request, category)) @@ -111,7 +122,9 @@ def get_start_thread_form( return StartThreadForm(prefix=prefix) def get_state(self, request: HttpRequest, category: Category) -> StartThreadState: - return get_start_thread_state_hook(self.get_state_action, request, category) + return get_start_thread_page_state_hook( + self.get_state_action, request, category + ) def get_state_action( self, request: HttpRequest, category: Category @@ -120,6 +133,13 @@ def get_state_action( def get_context_data( self, request: HttpRequest, category: Category, formset: StartThreadFormset + ) -> dict: + return get_start_thread_page_context_data_hook( + self.get_context_data_action, request, category, formset + ) + + def get_context_data_action( + self, request: HttpRequest, category: Category, formset: StartThreadFormset ) -> dict: return {"category": category, "formset": formset} @@ -142,7 +162,14 @@ def get_category(self, request: HttpRequest, kwargs: dict) -> Category: def get_formset( self, request: HttpRequest, category: Category ) -> StartThreadFormset: - formset = super().get_formset(request, category) + return get_start_private_thread_page_formset_hook( + self.get_formset_action, request, category + ) + + def get_formset_action( + self, request: HttpRequest, category: Category + ) -> StartThreadFormset: + formset = super().get_formset_action(request, category) formset.add_form( self.get_start_private_thread_form(request, category), append=False ) @@ -158,10 +185,17 @@ def get_start_private_thread_form( return StartPrivateThreadForm(prefix=prefix, request=request) def get_state(self, request: HttpRequest, category: Category) -> StartThreadState: - return get_start_private_thread_state_hook( + return get_start_private_thread_page_state_hook( self.get_state_action, request, category ) + def get_context_data( + self, request: HttpRequest, category: Category, formset: StartThreadFormset + ) -> dict: + return get_start_private_thread_page_context_data_hook( + self.get_context_data_action, request, category, formset + ) + def get_thread_url(self, request: HttpRequest, thread: Thread) -> str: return reverse( "misago:private-thread",