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

1from typing import Any 

2 

3from ckeditor.fields import RichTextFormField 

4from django import forms 

5from django.core.exceptions import ValidationError 

6from django.utils.translation import gettext_lazy as _ 

7 

8from comments_api.constants import COMMENT_STATUS_CHOICES 

9 

10 

11class CommentForm(forms.Form): 

12 """ 

13 Form for user comments. The only user input is the content of the comment. 

14 """ 

15 

16 content = RichTextFormField(required=True, label=False, config_name="comment") 

17 approval = forms.BooleanField(required=True) 

18 

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 ) 

33 

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:~:"] 

39 

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 ) 

47 

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 ) 

53 

54 return cleaned_data 

55 

56 

57class CommentFormAutogrow(CommentForm): 

58 content = RichTextFormField(required=True, label=False, config_name="comment_autogrow") 

59 approval = None 

60 

61 

62class BaseCommentStatusForm(forms.Form): 

63 """ 

64 Base comment status form. Only contains the status field. 

65 

66 Used for quick actions 

67 """ 

68 

69 post_url = "comment_status_change_light" 

70 status = forms.ChoiceField( 

71 choices=COMMENT_STATUS_CHOICES, 

72 required=True, 

73 widget=forms.HiddenInput(), 

74 ) 

75 

76 

77class DetailedCommentStatusForm(BaseCommentStatusForm): 

78 """ 

79 Form to change a comment status with additional fields available to moderators. 

80 """ 

81 

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 ) 

98 

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 

115 

116 

117def format_form_errors(form: forms.Form): 

118 """ 

119 Return the formatted list of all the form error messages, if any. 

120 

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]) 

129 

130 return errors