• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gcivil-nyu-org / wed-fall24-team1 / #75

04 Dec 2024 11:37PM UTC coverage: 87.19% (-3.8%) from 90.958%
#75

push

coveralls-python

web-flow
#181 enforce character limits on input fields

3444 of 3950 relevant lines covered (87.19%)

0.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.14
/src/services/forms.py
1
# services/forms.py
2
from decimal import Decimal
1✔
3

4
from better_profanity import profanity
1✔
5
from django import forms
1✔
6
from django.forms import formset_factory
1✔
7
from geopy import Nominatim
1✔
8
from geopy.exc import GeocoderTimedOut, GeocoderServiceError
1✔
9
from django.forms import BaseFormSet
1✔
10

11

12
class ServiceForm(forms.Form):
1✔
13
    CATEGORY_CHOICES = [
1✔
14
        ("Mental Health Center", "Mental Health Center"),
15
        ("Homeless Shelter", "Homeless Shelter"),
16
        ("Food Pantry", "Food Pantry"),
17
        ("Restroom", "Restroom"),
18
    ]
19

20
    name = forms.CharField(max_length=255)
1✔
21
    address = forms.CharField(widget=forms.Textarea)
1✔
22
    category = forms.ChoiceField(choices=CATEGORY_CHOICES)
1✔
23
    is_active = forms.BooleanField(
1✔
24
        required=False, initial=True, label="Is the service currently available?"
25
    )
26
    announcement = forms.CharField(  # Add this field
1✔
27
        widget=forms.Textarea(
28
            attrs={"rows": 3, "placeholder": "Enter your announcement here"}
29
        ),
30
        required=False,
31
        max_length=500,
32
        help_text="Use this space to inform users about temporary changes or important updates.",
33
    )
34
    image = forms.ImageField(
1✔
35
        required=False, help_text="Optional. Upload an image for the service."
36
    )
37

38
    # Add remove_image field
39
    remove_image = forms.BooleanField(
1✔
40
        required=False,
41
        initial=False,
42
        label="Remove current image",
43
        help_text="Check this box to remove the current image.",
44
    )
45

46
    def clean(self):
1✔
47
        cleaned_data = super().clean()
1✔
48
        address = cleaned_data.get("address")
1✔
49

50
        if address:
1✔
51
            geolocator = Nominatim(user_agent="public_service_finder")
1✔
52
            try:
1✔
53
                location = geolocator.geocode(address)
1✔
54
                if location:
1✔
55
                    cleaned_data["latitude"] = Decimal(str(location.latitude))
1✔
56
                    cleaned_data["longitude"] = Decimal(str(location.longitude))
1✔
57
                else:
58
                    self.add_error(
×
59
                        "address",
60
                        "Unable to geocode the given address. Please check if the address is correct.",
61
                    )
62
            except (GeocoderTimedOut, GeocoderServiceError):
×
63
                self.add_error(
×
64
                    "address",
65
                    "Error occurred while geocoding the address. Please try again later.",
66
                )
67

68
        # Translate category to backend value
69
        category_translation = {
1✔
70
            "Mental Health Center": "MENTAL",
71
            "Homeless Shelter": "SHELTER",
72
            "Food Pantry": "FOOD",
73
            "Restroom": "RESTROOM",
74
        }
75
        cleaned_data["category"] = category_translation[cleaned_data["category"]]
1✔
76
        if "announcement" in cleaned_data:
1✔
77
            announcement = cleaned_data["announcement"]
1✔
78
            if announcement:
1✔
79
                profanity.load_censor_words()
×
80
                cleaned_data["announcement"] = profanity.censor(announcement)
×
81

82
        return cleaned_data
1✔
83

84

85
class DescriptionItemForm(forms.Form):
1✔
86
    key = forms.CharField(
1✔
87
        max_length=100,
88
        widget=forms.TextInput(
89
            attrs={
90
                "class": "w-full p-2 rounded bg-gray-600 text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 h-12 border border-gray-600",
91
                "maxlength": "256",
92
            }
93
        ),
94
    )
95
    value = forms.CharField(
1✔
96
        widget=forms.Textarea(
97
            attrs={
98
                "rows": 3,
99
                "class": "w-full p-2 rounded bg-gray-600 text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 border border-gray-600",
100
            }
101
        )
102
    )
103

104

105
class CustomDescriptionFormSet(BaseFormSet):
1✔
106
    def clean(self):
1✔
107
        """
108
        Adds validation to check for duplicate keys in the formset.
109
        """
110
        if any(self.errors):
1✔
111
            return
×
112

113
        keys = []
1✔
114
        duplicate_keys = set()
1✔
115

116
        # First pass: collect all keys and identify duplicates
117
        for form in self.forms:
1✔
118
            if self.can_delete and self._should_delete_form(form):
1✔
119
                continue
×
120

121
            if form.cleaned_data:
1✔
122
                key = form.cleaned_data.get("key")
1✔
123
                if key:
1✔
124
                    print(f"Processing key: {key}")  # Debug print
1✔
125
                    if key in keys:
1✔
126
                        duplicate_keys.add(key)
×
127
                    keys.append(key)
1✔
128

129
        # Second pass: add errors to all forms with duplicate keys
130
        if duplicate_keys:
1✔
131
            for form in self.forms:
×
132
                if self.can_delete and self._should_delete_form(form):
×
133
                    continue
×
134

135
                if form.cleaned_data:
×
136
                    key = form.cleaned_data.get("key")
×
137
                    if key in duplicate_keys:
×
138
                        form.add_error(
×
139
                            "key",
140
                            f"Duplicate key detected: '{key}'. Each key must be unique.",
141
                        )
142

143
            # Raise the validation error with all duplicate keys listed
144
            raise forms.ValidationError(
×
145
                f"Duplicate keys found: {', '.join(duplicate_keys)}. Each key must be unique."
146
            )
147

148
        print(f"All keys found: {keys}")  # Debug print for all keys
1✔
149
        return self.cleaned_data
1✔
150

151

152
DescriptionFormSet = formset_factory(
1✔
153
    DescriptionItemForm,
154
    formset=CustomDescriptionFormSet,
155
    extra=0,
156
    can_delete=True,
157
)
158

159

160
class ReviewResponseForm(forms.Form):
1✔
161
    responseText = forms.CharField(  # Changed from 'response' to 'responseText'
1✔
162
        widget=forms.Textarea(
163
            attrs={
164
                "class": "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500",
165
                "rows": "4",
166
                "placeholder": "Enter your response to this review...",
167
            }
168
        ),
169
        required=True,
170
    )
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc