Coverage for src/comments_views/core/forms.py: 46%
51 statements
« prev ^ index » next coverage.py v7.7.0, created at 2025-04-09 14:49 +0000
« prev ^ index » next coverage.py v7.7.0, created at 2025-04-09 14:49 +0000
1from typing import Any
3from ckeditor.fields import RichTextFormField
4from django import forms
5from django.core.exceptions import ValidationError
6from django.utils.translation import gettext_lazy as _
8from comments_api.constants import COMMENT_STATUS_CHOICES
11class CommentForm(forms.Form):
12 """
13 Form for user comments. The only user input is the content of the comment.
14 """
16 content = RichTextFormField(required=True, label=False, config_name="comment")
17 approval = forms.BooleanField(required=True)
19 # Hidden inputs
20 doi = forms.CharField(required=True, widget=forms.HiddenInput())
21 id = forms.IntegerField(required=False, widget=forms.HiddenInput)
22 parent = forms.IntegerField(required=False, widget=forms.HiddenInput())
23 parent_author_name = forms.CharField(
24 max_length=128, required=False, widget=forms.HiddenInput()
25 )
26 #### TODO: Is `date_submitted` really used ????
27 date_submitted = forms.CharField(required=False, widget=forms.HiddenInput())
28 status = forms.ChoiceField(
29 choices=COMMENT_STATUS_CHOICES,
30 required=False,
31 widget=forms.HiddenInput(),
32 )
34 def clean(self):
35 cleaned_data = super().clean()
36 parent = cleaned_data.get("parent")
37 parent_author_name = cleaned_data.get("parent_author_name")
38 null_values = [None, 0, "", ":~:init:~:"]
40 if (parent in null_values and parent_author_name not in null_values) or (
41 parent not in null_values and parent_author_name in null_values
42 ):
43 raise forms.ValidationError(
44 _("Both Parent ID and Parent author name must be null or non-null."),
45 code="invalid",
46 )
48 if self.prefix == "reply" and (parent in null_values or parent_author_name in null_values):
49 raise forms.ValidationError(
50 _("Both Parent ID and Parent author name must be non-null for a reply comment."),
51 code="invalid",
52 )
54 return cleaned_data
57class CommentFormAutogrow(CommentForm):
58 content = RichTextFormField(required=True, label=False, config_name="comment_autogrow")
59 approval = None
62class BaseCommentStatusForm(forms.Form):
63 """
64 Base comment status form. Only contains the status field.
66 Used for quick actions
67 """
69 post_url = "comment_status_change_light"
70 status = forms.ChoiceField(
71 choices=COMMENT_STATUS_CHOICES,
72 required=True,
73 widget=forms.HiddenInput(),
74 )
77class DetailedCommentStatusForm(BaseCommentStatusForm):
78 """
79 Form to change a comment status with additional fields available to moderators.
80 """
82 post_url = "comment_status_change"
83 article_author_comment = forms.BooleanField(
84 label="Article's author",
85 required=False,
86 help_text="Check this box if the comment is from an author of the article.",
87 )
88 editorial_team_comment = forms.BooleanField(
89 label="Editorial team",
90 required=False,
91 help_text="Check this box if the comment is from someone of the editorial team.",
92 )
93 hide_author_name = forms.BooleanField(
94 label="Hide author name",
95 required=False,
96 help_text="Check this box to hide the name of the comment's author.",
97 )
99 def clean(self) -> dict[str, Any]:
100 cleaned_data = super().clean()
101 if (
102 cleaned_data["hide_author_name"]
103 and not cleaned_data["article_author_comment"]
104 and not cleaned_data["editorial_team_comment"]
105 ):
106 raise ValidationError(
107 "'Article's author' or 'Editorial team' must be checked"
108 " when 'Hide author name' is checked."
109 )
110 if cleaned_data["article_author_comment"] and cleaned_data["editorial_team_comment"]:
111 raise ValidationError(
112 "'Article's author' and 'Editorial team' can't be checked together."
113 )
114 return cleaned_data
117def format_form_errors(form: forms.Form):
118 """
119 Return the formatted list of all the form error messages, if any.
121 Field error messages are prefixed with the field name.
122 """
123 errors = []
124 for field, error_list in form.errors.items():
125 if field == "__all__":
126 errors.extend(error_list)
127 continue
128 errors.extend([f"{field} - {err}" for err in error_list])
130 return errors