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

gcivil-nyu-org / INET-Wednesday-Spring2024-Team-2 / 638

01 May 2024 07:15PM UTC coverage: 85.085% (+1.1%) from 83.958%
638

Pull #182

travis-pro

web-flow
Merge 3bef72187 into a04204438
Pull Request #182: add tests

15 of 43 new or added lines in 1 file covered. (34.88%)

530 existing lines in 18 files now uncovered.

1101 of 1294 relevant lines covered (85.09%)

1.26 hits per line

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

88.32
/users/forms.py
1
import re
2✔
2
from datetime import date, timedelta
2✔
3
from crispy_forms.helper import FormHelper
2✔
4
from crispy_forms.layout import Layout, Submit, Row, Column, Field, HTML
2✔
5
from django import forms
2✔
6
from django.contrib.auth.forms import UserCreationForm
2✔
7
from django.contrib.auth import get_user_model
2✔
8
from .models import CustomUser, Rental_Listings
2✔
9
from django.contrib.auth.forms import AuthenticationForm
2✔
10
from django.core.exceptions import ValidationError
2✔
11
from django.contrib.auth.forms import UserChangeForm
2✔
12
from django.utils import timezone
2✔
13

14
User = get_user_model()
2✔
15

16

17
class UserSignUpForm(UserCreationForm):
2✔
18
    full_name = forms.CharField(max_length=255, required=True)
2✔
19
    phone_number = forms.CharField(max_length=15, required=True)
2✔
20
    city = forms.CharField(max_length=100, required=True)
2✔
21
    email = forms.EmailField(required=True)
2✔
22

23
    class Meta:
2✔
24
        model = User
2✔
25
        fields = (
2✔
26
            "email",
27
            "full_name",
28
            "phone_number",
29
            "city",
30
            "password1",
31
            "password2",
32
        )
33

34
    def clean_email(self):
2✔
UNCOV
35
        email = self.cleaned_data["email"]
1✔
UNCOV
36
        if not email.endswith("@nyu.edu"):
1✔
UNCOV
37
            raise ValidationError("Oops! Only NYU email addresses are supported.")
1✔
UNCOV
38
        if User.objects.filter(username=self.cleaned_data["email"]).exists():
1✔
39
            raise ValidationError("Email already exists. Please use a different one.")
×
UNCOV
40
        return email
1✔
41

42
    def clean_phone_number(self):
2✔
UNCOV
43
        phone_number = self.cleaned_data.get("phone_number")
1✔
UNCOV
44
        if len(phone_number) != 10 or not phone_number.isdigit():
1✔
45
            raise ValidationError("Phone number must be 10 digits.")
×
UNCOV
46
        return phone_number
1✔
47

48

49
class LandlordSignupForm(UserCreationForm):
2✔
50
    pdf_file = forms.FileField(required=False, label="OwnerShip Document")  #
2✔
51

52
    class Meta:
2✔
53
        model = CustomUser
2✔
54
        fields = (
2✔
55
            "username",
56
            "email",
57
            "full_name",
58
            "phone_number",
59
            "city",
60
            "password1",
61
            "password2",
62
            # "user_type",
63
            "pdf_file",
64
        )
65

66
    # def _init_(self, *args, **kwargs):
67
    #     super(LandlordSignupForm, self)._init_(*args, **kwargs)
68
    #     self.fields["user_type"].initial = CustomUser.LANDLORD
69
    #     self.fields[
70
    #         "user_type"
71
    #     ].widget = forms.HiddenInput()  # Hide the user_type field
72

73
    def _init_(self, *args, **kwargs):
2✔
74
        super(LandlordSignupForm, self)._init_(*args, **kwargs)
×
75
        # No need to set user_type initial value here, as it will be set in save.
76

77
    def save(self, commit=True):
2✔
UNCOV
78
        user = super(LandlordSignupForm, self).save(commit=False)
1✔
UNCOV
79
        user.user_type = CustomUser.LANDLORD  # Set user_type to LANDLORD
1✔
80

UNCOV
81
        if commit:
1✔
UNCOV
82
            user.save()
1✔
UNCOV
83
            self.save_m2m()
1✔
84

UNCOV
85
        return user
1✔
86

87

88
class RentalListingForm(forms.ModelForm):
2✔
89
    ROOMS_CHOICES = [(i, str(i)) for i in range(1, 11)]
2✔
90
    BATHS_CHOICES = [(i * 0.5, str(i * 0.5)) for i in range(2, 21)]
2✔
91

92
    UNIT_TYPE_CHOICES = [
2✔
93
        ("Apartment", "Apartment"),
94
        ("House", "House"),
95
        ("Multi-family", "Multi-family"),
96
        ("Condo", "Condo"),
97
        ("Rental Unit", "Rental Unit"),
98
        ("Building", "Building"),
99
        ("Townhouse", "Townhouse"),
100
        ("Co-op", "Co-op"),
101
    ]
102
    NEIGHBORHOOD_CHOICES = [
2✔
103
        ("Manhattan", "Manhattan"),
104
        ("Brooklyn", "Brooklyn"),
105
        ("Upper East Side", "Upper East Side"),
106
        ("Upper West Side", "Upper West Side"),
107
        ("Midtown", "Midtown"),
108
        ("Harlem", "Harlem"),
109
        ("Chelsea", "Chelsea"),
110
        ("Greenwich Village", "Greenwich Village"),
111
        ("Soho", "Soho"),
112
        ("East Village", "East Village"),
113
        ("Lower East Side", "Lower East Side"),
114
        ("Williamsburg", "Williamsburg"),
115
        ("Bushwick", "Bushwick"),
116
        ("Park Slope", "Park Slope"),
117
        ("Brooklyn Heights", "Brooklyn Heights"),
118
        ("Red Hook", "Red Hook"),
119
        ("Astoria", "Astoria"),
120
        ("Long Island City", "Long Island City"),
121
        ("Flushing", "Flushing"),
122
        ("Jamaica", "Jamaica"),
123
        ("Forest Hills", "Forest Hills"),
124
        ("Riverdale", "Riverdale"),
125
        ("Fordham", "Fordham"),
126
        ("Concourse", "Concourse"),
127
        ("Throgs Neck", "Throgs Neck"),
128
        ("St. George", "St. George"),
129
        ("Tottenville", "Tottenville"),
130
        ("Stapleton", "Stapleton"),
131
    ]
132

133
    BOROUGH_CHOICES = [
2✔
134
        ("Manhattan", "Manhattan"),
135
        ("Brooklyn", "Brooklyn"),
136
        ("Queens", "Queens"),
137
        ("Bronx", "Bronx"),
138
        ("Staten Island", "Staten Island"),
139
    ]
140
    address = forms.CharField(
2✔
141
        widget=forms.TextInput(
142
            attrs={
143
                "id": "id_address",
144
                "placeholder": "Enter your address",
145
                "autocomplete": "off",
146
            }
147
        )
148
    )
149
    rooms = forms.ChoiceField(choices=ROOMS_CHOICES)
2✔
150
    beds = forms.ChoiceField(choices=ROOMS_CHOICES)
2✔
151
    baths = forms.ChoiceField(choices=BATHS_CHOICES)
2✔
152
    unit_type = forms.ChoiceField(choices=UNIT_TYPE_CHOICES)
2✔
153
    neighborhood = forms.CharField(
2✔
154
        required=True, widget=forms.TextInput(attrs={"id": "id_neighborhood"})
155
    )
156
    borough = forms.ChoiceField(
2✔
157
        choices=BOROUGH_CHOICES, widget=forms.Select(attrs={"id": "id_borough"})
158
    )
159
    photo = forms.ImageField(
2✔
160
        required=False,
161
        label="Images",
162
        widget=forms.ClearableFileInput(attrs={"multiple": True}),
163
    )
164
    latitude = forms.FloatField(
2✔
165
        widget=forms.HiddenInput(attrs={"readonly": "readonly"})
166
    )
167
    longitude = forms.FloatField(
2✔
168
        widget=forms.HiddenInput(attrs={"readonly": "readonly"})
169
    )
170
    zipcode = forms.CharField(
2✔
171
        required=True,
172
        label="Zip",
173
        widget=forms.TextInput(attrs={"id": "id_zipcode", "placeholder": ""}),
174
    )
175
    sq_ft = forms.IntegerField(required=True, label="Area(sqft)")
2✔
176
    Availability_Date = forms.DateField(
2✔
177
        required=True, widget=forms.DateInput(attrs={"type": "date"})
178
    )
179
    apt_no = forms.CharField(
2✔
180
        required=False,
181
        label="Apt#",
182
        widget=forms.TextInput(attrs={"id": "id_aptNo", "placeholder": ""}),
183
    )
184

185
    def __init__(self, *args, **kwargs):
2✔
UNCOV
186
        super(RentalListingForm, self).__init__(*args, **kwargs)
1✔
UNCOV
187
        self.helper = FormHelper(self)
1✔
UNCOV
188
        self.helper.form_method = "post"
1✔
UNCOV
189
        self.helper.form_enctype = "multipart/form-data"
1✔
UNCOV
190
        self.helper.layout = Layout(
1✔
191
            Row(
192
                Column("address", css_class="form-group col-md-8 mb-0"),
193
                Column("zipcode", css_class="form-group col-md-2 mb-0"),
194
                Column("apt_no", css_class="form-group col-md-2 mb-0"),
195
                css_class="form-row",
196
            ),
197
            Row(
198
                Column("price", css_class="form-group col-md-4 mb-0"),
199
                Column("sq_ft", css_class="form-group col-md-4 mb-0"),
200
                Column("broker_fee", css_class="form-group col-md-4 mb-0"),
201
                css_class="form-row",
202
            ),
203
            Row(
204
                Column("rooms", css_class="form-group col-md-4 mb-0"),
205
                Column("beds", css_class="form-group col-md-4 mb-0"),
206
                Column("baths", css_class="form-group col-md-4 mb-0"),
207
                css_class="form-row",
208
            ),
209
            Row(
210
                Column("neighborhood", css_class="form-group col-md-4 mb-0"),
211
                Column("borough", css_class="form-group col-md-4 mb-0"),
212
                Column("unit_type", css_class="form-group col-md-4 mb-0"),
213
                css_class="form-row",
214
            ),
215
            Row(
216
                Column("dishwasher", css_class="form-group col-md-6 mb-0"),
217
                Column("doorman", css_class="form-group col-md-6 mb-0"),
218
                css_class="form-row",
219
            ),
220
            Row(
221
                Column(
222
                    "central_air_conditioning", css_class="form-group col-md-6 mb-0"
223
                ),
224
                Column("furnished", css_class="form-group col-md-6 mb-0"),
225
                css_class="form-row",
226
            ),
227
            Row(
228
                Column("parking_available", css_class="form-group col-md-6 mb-0"),
229
                Column("washer_dryer_in_unit", css_class="form-group col-md-6 mb-0"),
230
                css_class="form-row",
231
            ),
232
            Column("elevator", css_class="form-group col-md-4 mb-0"),
233
            "Availability_Date",
234
            Row(
235
                Column(
236
                    "latitude", css_class="form-group col-md-4 mb-0 align-self-end"
237
                ),  # Add 'align-self-end' class
238
                Column(
239
                    "longitude", css_class="form-group col-md-4 mb-0 align-self-end"
240
                ),  # Add 'align-self-end' class
241
                css_class="form-row location-row",
242
            ),
243
            Field("photo", multiple=True),
244
            Submit("submit", "Submit", css_class="btn btn-primary form-button1"),
245
        )
246

247
    class Meta:
2✔
248
        model = Rental_Listings
2✔
249
        fields = [
2✔
250
            "address",
251
            "zipcode",
252
            "price",
253
            "sq_ft",
254
            "rooms",
255
            "beds",
256
            "baths",
257
            "unit_type",
258
            "neighborhood",
259
            "borough",
260
            "broker_fee",
261
            "central_air_conditioning",
262
            "dishwasher",
263
            "doorman",
264
            "elevator",
265
            "furnished",
266
            "parking_available",
267
            "washer_dryer_in_unit",
268
            "Availability_Date",
269
            "photo",
270
            "latitude",
271
            "longitude",
272
        ]
273
        widgets = {"Availability_Date": forms.DateInput(attrs={"type": "date"})}
2✔
274

275
    def clean_price(self):
2✔
UNCOV
276
        price = self.cleaned_data["price"]
1✔
UNCOV
277
        if price < 0:
1✔
UNCOV
278
            raise ValidationError("Price cannot be negative.")
1✔
UNCOV
279
        return price
1✔
280

281
    def clean_brokerfee(self):
2✔
282
        broker_fee = self.cleaned_data["broker_fee"]
×
283
        if broker_fee < 0:
×
284
            raise ValidationError("Broker Fee cannot be negative.")
×
285
        return broker_fee
×
286

287
    def clean_Availability_Date(self):
2✔
UNCOV
288
        availability_date = self.cleaned_data.get("Availability_Date")
1✔
UNCOV
289
        if availability_date and availability_date < date.today():
1✔
UNCOV
290
            raise ValidationError("The availability date cannot be in the past.")
1✔
UNCOV
291
        if availability_date and availability_date > date.today() + timedelta(days=365):
1✔
292
            raise ValidationError("The availability date is too far in the future.")
×
UNCOV
293
        return availability_date
1✔
294

295
    def clean_rooms_beds(self):
2✔
296
        rooms = self.cleaned_data.get("rooms")
×
297
        beds = self.cleaned_data.get("beds")
×
298

299
        if rooms is not None and beds is not None and rooms < beds:
×
300
            raise ValidationError(
×
301
                "Total number of rooms cannot be less than the number of bedrooms."
302
            )
303

304
    def clean_zipcode(self):
2✔
UNCOV
305
        zipcode = self.cleaned_data["zipcode"]
1✔
UNCOV
306
        if not zipcode.isdigit() or len(zipcode) != 5:
1✔
UNCOV
307
            raise forms.ValidationError("Please enter a valid 5-digit zip code.")
1✔
UNCOV
308
        return zipcode
1✔
309

310
    def clean_sq_ft(self):
2✔
UNCOV
311
        sq_ft = self.cleaned_data["sq_ft"]
1✔
UNCOV
312
        if sq_ft < 100:
1✔
313
            raise forms.ValidationError(
×
314
                "Please enter a valid square footage (100 sq ft minimum)."
315
            )
UNCOV
316
        return sq_ft
1✔
317

318
    def clean_address(self):
2✔
UNCOV
319
        address = self.cleaned_data["address"]
1✔
UNCOV
320
        if len(address) > 255:
1✔
UNCOV
321
            raise forms.ValidationError("Address is too long.")
1✔
UNCOV
322
        return address
1✔
323

324

325
class CustomLoginForm(AuthenticationForm):
2✔
326
    def __init__(self, *args, **kwargs):
2✔
UNCOV
327
        super().__init__(*args, **kwargs)
1✔
328

329

330
class CustomUserEditForm(forms.ModelForm):
2✔
331
    class Meta:
2✔
332
        model = CustomUser
2✔
333
        fields = ("full_name", "phone_number", "city")
2✔
334
        widgets = {
2✔
335
            "full_name": forms.TextInput(attrs={"class": "form-control"}),
336
            "phone_number": forms.TextInput(attrs={"class": "form-control"}),
337
            "city": forms.TextInput(attrs={"class": "form-control"}),
338
        }
339

340
    def clean_full_name(self):
2✔
UNCOV
341
        full_name = self.cleaned_data["full_name"]
1✔
UNCOV
342
        if not re.match("^[a-zA-Z\\s]*$", full_name):  # noqa: W605
1✔
343
            raise ValidationError("Name should only contain letters and spaces.")
×
UNCOV
344
        return full_name
1✔
345

346
    def clean_phone_number(self):
2✔
UNCOV
347
        phone_number = self.cleaned_data["phone_number"]
1✔
UNCOV
348
        if not phone_number.isdigit() or len(phone_number) != 10:
1✔
349
            raise ValidationError("Phone number must contain exactly 10 digits.")
×
UNCOV
350
        return phone_number
1✔
351

352
    def clean_city(self):
2✔
UNCOV
353
        city = self.cleaned_data["city"]
1✔
UNCOV
354
        if not re.match("^[a-zA-Z\\s]*$", city):  # noqa: W605
1✔
355
            raise ValidationError("City should only contain letters and spaces.")
×
UNCOV
356
        return city
1✔
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