diff --git a/misago/posting/forms/inviteusers.py b/misago/posting/forms/inviteusers.py index 23896660fd..4950761553 100644 --- a/misago/posting/forms/inviteusers.py +++ b/misago/posting/forms/inviteusers.py @@ -14,15 +14,14 @@ else: User = get_user_model() -PREFIX = "posting-invite-users" - class InviteUsersForm(PostingForm): + form_prefix = "posting-invite-users" + template_name = "misago/posting/invite_users_form.html" + request: HttpRequest invite_users: list["User"] - template_name = "misago/posting/invite_users_form.html" - users = forms.CharField(max_length=200) def __init__(self, *args, **kwargs): @@ -98,7 +97,7 @@ def create_invite_users_form(request: HttpRequest) -> InviteUsersForm: return InviteUsersForm( request.POST, request=request, - prefix=PREFIX, + prefix=InviteUsersForm.form_prefix, ) - return InviteUsersForm(request=request, prefix=PREFIX) + return InviteUsersForm(request=request, prefix=InviteUsersForm.form_prefix) diff --git a/misago/posting/forms/post.py b/misago/posting/forms/post.py index 1e70193a3a..209f70aee1 100644 --- a/misago/posting/forms/post.py +++ b/misago/posting/forms/post.py @@ -16,16 +16,15 @@ from .base import PostingForm from .attachments import MultipleFileField -PREFIX = "posting-post" - class PostForm(PostingForm): + form_prefix = "posting-post" + template_name = "misago/posting/post_form.html" + attachment_secret_name = "attachment_secret" + request: HttpRequest attachments: list[Attachment] attachments_permissions: AttachmentsPermissions | None - attachment_secret_name = "attachment_secret" - - template_name = "misago/posting/post_form.html" post = forms.CharField( widget=forms.Textarea, @@ -164,7 +163,7 @@ def create_post_form( "request": request, "attachments": attachments, "attachments_permissions": attachments_permissions, - "prefix": PREFIX, + "prefix": PostForm.form_prefix, } if request.method == "POST": diff --git a/misago/posting/forms/title.py b/misago/posting/forms/title.py index f989f4344d..052bbbc8d9 100644 --- a/misago/posting/forms/title.py +++ b/misago/posting/forms/title.py @@ -6,14 +6,13 @@ from ..validators import validate_thread_title from .base import PostingForm -PREFIX = "posting-title" - class TitleForm(PostingForm): - request: HttpRequest - + form_prefix = "posting-title" template_name = "misago/posting/title_form.html" + request: HttpRequest + title = forms.CharField( max_length=255, error_messages={ @@ -48,7 +47,7 @@ def create_title_form(request: HttpRequest, initial: str | None = None) -> Title return TitleForm( request.POST, request=request, - prefix=PREFIX, + prefix=TitleForm.form_prefix, ) if initial: @@ -56,4 +55,6 @@ def create_title_form(request: HttpRequest, initial: str | None = None) -> Title else: initial_data = None - return TitleForm(request=request, prefix=PREFIX, initial=initial_data) + return TitleForm( + request=request, prefix=TitleForm.form_prefix, initial=initial_data + ) diff --git a/misago/posting/formsets/formset.py b/misago/posting/formsets/formset.py index 7282eacd18..2c273dbb12 100644 --- a/misago/posting/formsets/formset.py +++ b/misago/posting/formsets/formset.py @@ -1,6 +1,7 @@ from django.core.exceptions import ValidationError from ...forms.formset import Formset +from ..forms import InviteUsersForm, PostForm, TitleForm from ..state.base import PostingState @@ -11,6 +12,18 @@ def __init__(self): super().__init__() self.errors = [] + @property + def title(self) -> TitleForm | None: + return self.forms.get(TitleForm.form_prefix) + + @property + def post(self) -> PostForm | None: + return self.forms.get(PostForm.form_prefix) + + @property + def invite_users(self) -> InviteUsersForm | None: + return self.forms.get(InviteUsersForm.form_prefix) + def update_state(self, state: PostingState): for form in self.forms.values(): if form.is_valid(): diff --git a/misago/posting/tests/test_formsets.py b/misago/posting/tests/test_formsets.py new file mode 100644 index 0000000000..25ba4fbf6d --- /dev/null +++ b/misago/posting/tests/test_formsets.py @@ -0,0 +1,167 @@ +from unittest.mock import Mock + +from ...attachments.enums import AllowedAttachments +from ...conf.test import override_dynamic_settings +from ...permissions.enums import CanUploadAttachments +from ...permissions.proxy import UserPermissionsProxy +from ..formsets import ( + get_edit_private_thread_formset, + get_edit_private_thread_post_formset, + get_edit_thread_formset, + get_edit_thread_post_formset, + get_reply_private_thread_formset, + get_reply_thread_formset, + get_start_private_thread_formset, + get_start_thread_formset, +) + + +def test_get_start_thread_formset_initializes_valid_forms( + user, cache_versions, dynamic_settings, default_category +): + request = Mock( + settings=dynamic_settings, + user=user, + user_permissions=UserPermissionsProxy(user, cache_versions), + ) + formset = get_start_thread_formset(request, default_category) + assert formset.title + assert formset.post + assert not formset.invite_users + + +def test_get_start_thread_formset_setups_post_form_with_attachment_uploads( + user, cache_versions, dynamic_settings, default_category +): + request = Mock( + settings=dynamic_settings, + user=user, + user_permissions=UserPermissionsProxy(user, cache_versions), + ) + formset = get_start_thread_formset(request, default_category) + assert formset.post.show_attachments_upload + + +def test_get_start_thread_formset_setups_post_form_with_attachment_upload_if_uploads_are_limited_to_threads( + user, members_group, cache_versions, dynamic_settings, default_category +): + members_group.can_upload_attachments = CanUploadAttachments.THREADS + members_group.save() + + request = Mock( + settings=dynamic_settings, + user=user, + user_permissions=UserPermissionsProxy(user, cache_versions), + ) + formset = get_start_thread_formset(request, default_category) + assert formset.post.show_attachments_upload + + +def test_get_start_thread_formset_setups_post_form_without_attachment_upload_if_user_has_no_permission( + user, members_group, cache_versions, dynamic_settings, default_category +): + members_group.can_upload_attachments = CanUploadAttachments.NEVER + members_group.save() + + request = Mock( + settings=dynamic_settings, + user=user, + user_permissions=UserPermissionsProxy(user, cache_versions), + ) + formset = get_start_thread_formset(request, default_category) + assert not formset.post.show_attachments_upload + + +@override_dynamic_settings(allowed_attachment_types=AllowedAttachments.NONE) +def test_get_start_thread_formset_setups_post_form_without_attachment_upload_if_uploads_are_disabled( + user, cache_versions, dynamic_settings, default_category +): + request = Mock( + settings=dynamic_settings, + user=user, + user_permissions=UserPermissionsProxy(user, cache_versions), + ) + formset = get_start_thread_formset(request, default_category) + assert not formset.post.show_attachments_upload + + +def test_get_start_private_thread_formset_initializes_valid_forms( + user, cache_versions, dynamic_settings, private_threads_category +): + request = Mock( + settings=dynamic_settings, + user=user, + user_permissions=UserPermissionsProxy(user, cache_versions), + ) + formset = get_start_private_thread_formset(request, private_threads_category) + assert formset.title + assert formset.post + assert formset.invite_users + + +def test_get_start_private_thread_formset_setups_post_form_with_attachment_uploads( + user, cache_versions, dynamic_settings, private_threads_category +): + request = Mock( + settings=dynamic_settings, + user=user, + user_permissions=UserPermissionsProxy(user, cache_versions), + ) + formset = get_start_private_thread_formset(request, private_threads_category) + assert formset.post.show_attachments_upload + + +def test_get_start_private_thread_formset_setups_post_form_without_attachment_upload_if_user_no_has_private_threads_permission( + user, members_group, cache_versions, dynamic_settings, private_threads_category +): + members_group.can_upload_attachments = CanUploadAttachments.THREADS + members_group.save() + + request = Mock( + settings=dynamic_settings, + user=user, + user_permissions=UserPermissionsProxy(user, cache_versions), + ) + formset = get_start_private_thread_formset(request, private_threads_category) + assert not formset.post.show_attachments_upload + + +def test_get_start_private_thread_formset_setups_post_form_without_attachment_upload_if_user_no_permission( + user, members_group, cache_versions, dynamic_settings, private_threads_category +): + members_group.can_upload_attachments = CanUploadAttachments.NEVER + members_group.save() + + request = Mock( + settings=dynamic_settings, + user=user, + user_permissions=UserPermissionsProxy(user, cache_versions), + ) + formset = get_start_private_thread_formset(request, private_threads_category) + assert not formset.post.show_attachments_upload + + +@override_dynamic_settings(allowed_attachment_types=AllowedAttachments.NONE) +def test_get_start_private_thread_formset_setups_post_form_without_attachment_upload_if_uploads_are_disabled( + user, cache_versions, dynamic_settings, private_threads_category +): + request = Mock( + settings=dynamic_settings, + user=user, + user_permissions=UserPermissionsProxy(user, cache_versions), + ) + formset = get_start_private_thread_formset(request, private_threads_category) + assert not formset.post.show_attachments_upload + + +@override_dynamic_settings(allow_private_threads_attachments=False) +def test_get_start_private_thread_formset_setups_post_form_without_attachment_upload_if_private_threads_uploads_are_disabled( + user, cache_versions, dynamic_settings, private_threads_category +): + request = Mock( + settings=dynamic_settings, + user=user, + user_permissions=UserPermissionsProxy(user, cache_versions), + ) + formset = get_start_private_thread_formset(request, private_threads_category) + assert not formset.post.show_attachments_upload