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

gcivil-nyu-org / team4-wed-spring25 / 372

07 Apr 2025 11:16PM UTC coverage: 96.879% (+1.3%) from 95.573%
372

push

travis-pro

divya603
Fix flake8 issues: remove trailing whitespace in tests

838 of 865 relevant lines covered (96.88%)

0.97 hits per line

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

88.71
/parks/views.py
1
from django.shortcuts import render, get_object_or_404, redirect
1✔
2
from django.http import HttpResponse  # noqa: F401  # Ignore "imported but unused"
1✔
3
from django.db.models import OuterRef, Subquery, CharField
1✔
4
from django.db.models.functions import Cast
1✔
5
from .models import DogRunNew, Review, ParkImage, ReviewReport, ImageReport
1✔
6
from django.forms.models import model_to_dict
1✔
7

8
import folium
1✔
9
from folium.plugins import MarkerCluster
1✔
10

11
from .utilities import folium_cluster_styling
1✔
12

13
from django.contrib.auth import login
1✔
14
from .forms import RegisterForm
1✔
15
import json
1✔
16
from django.db.models import Q  # Import Q for complex queries
1✔
17

18
from django.contrib.auth.decorators import login_required
1✔
19
from django.db.models import Avg
1✔
20
from django.http import HttpResponseForbidden
1✔
21

22

23
def register_view(request):
1✔
24
    if request.method == "POST":
1✔
25
        form = RegisterForm(request.POST)
1✔
26
        if form.is_valid():
1✔
27
            # Save but don't commit yet
28
            user = form.save(commit=False)
1✔
29
            # If they chose Admin, mark them as staff
30
            if form.cleaned_data["role"] == "admin":
1✔
31
                user.is_staff = True
1✔
32
            user.save()
1✔
33

34
            # Log the user in immediately
35
            login(request, user)
1✔
36
            request.session.save()
1✔
37
            return redirect("home")
1✔
38
    else:
39
        form = RegisterForm()
1✔
40

41
    return render(request, "parks/register.html", {"form": form})
1✔
42

43

44
def park_list(request):
1✔
45
    query = request.GET.get("query", "")
1✔
46
    parks = DogRunNew.objects.all()  # Fetch all dog runs from the database
1✔
47

48
    if query:
1✔
49
        parks = parks.filter(
×
50
            Q(name__icontains=query)
51
            | Q(google_name__icontains=query)
52
            | Q(zip_code__icontains=query)
53
        )
54

55
    return render(request, "parks/park_list.html", {"parks": parks, "query": query})
1✔
56

57

58
def home_view(request):
1✔
59
    return render(request, "parks/home.html")
1✔
60

61

62
def map(request):
1✔
63

64
    NYC_LAT_AND_LONG = (40.730610, -73.935242)
1✔
65
    # Create map centered on NYC
66
    m = folium.Map(location=NYC_LAT_AND_LONG, zoom_start=11)
1✔
67

68
    icon_create_function = folium_cluster_styling("rgb(0, 128, 0)")
1✔
69

70
    marker_cluster = MarkerCluster(icon_create_function=icon_create_function).add_to(m)
1✔
71

72
    # Fetch all dog runs from the database
73
    parks = DogRunNew.objects.all()
1✔
74

75
    # Mark every park on the map
76
    for park in parks:
1✔
77
        park_name = park.name
×
78

79
        folium.Marker(
×
80
            location=(park.latitude, park.longitude),
81
            icon=folium.Icon(icon="dog", prefix="fa", color="green"),
82
            popup=folium.Popup(park_name, max_width=200),
83
        ).add_to(marker_cluster)
84

85
    # represent map as html
86
    context = {"map": m._repr_html_()}
1✔
87
    return render(request, "parks/map.html", context)
1✔
88

89

90
def park_and_map(request):
1✔
91
    # Get filter values from GET request
92
    query = request.GET.get("query", "").strip()
1✔
93
    filter_value = request.GET.get("filter", "").strip()
1✔
94
    accessible_value = request.GET.get("accessible", "").strip()
1✔
95
    borough_value = request.GET.get("borough", "").strip().upper()
1✔
96

97
    thumbnail = ParkImage.objects.filter(park_id=OuterRef("pk")).values("image")[:1]
1✔
98

99
    # Fetch all dog runs from the database
100
    parks = (
1✔
101
        DogRunNew.objects.all()
102
        .order_by("id")
103
        .prefetch_related("images")
104
        .annotate(thumbnail_url=Cast(Subquery(thumbnail), output_field=CharField()))
105
    )
106

107
    # Search by ZIP, name, or Google name
108
    if query:
1✔
109
        parks = parks.filter(
×
110
            Q(name__icontains=query)
111
            | Q(google_name__icontains=query)
112
            | Q(zip_code__icontains=query)
113
        )
114

115
    # Filter by park type (e.g., "Off-Leash")
116
    if filter_value:
1✔
117
        parks = parks.filter(dogruns_type__iexact=filter_value)
×
118

119
    # Filter by accessibility only if explicitly set to "True" or "False"
120
    if accessible_value == "True":
1✔
121
        parks = parks.filter(accessible=True)
×
122
    elif accessible_value == "False":
1✔
123
        parks = parks.filter(accessible=False)
×
124

125
    if borough_value:
1✔
126
        parks = parks.filter(borough=borough_value)
1✔
127
    # Convert parks to JSON (for JS use)
128
    parks_json = json.dumps(list(parks.values()))
1✔
129

130
    # Render the template
131
    return render(
1✔
132
        request,
133
        "parks/combined_view.html",
134
        {
135
            "parks": parks,
136
            "parks_json": parks_json,
137
            "query": query,
138
            "selected_type": filter_value,
139
            "selected_accessible": accessible_value,
140
            "selected_borough": borough_value,
141
        },
142
    )
143

144

145
def park_detail(request, id):
1✔
146
    park = get_object_or_404(DogRunNew, id=id)
1✔
147
    images = ParkImage.objects.filter(park=park)
1✔
148
    reviews = park.reviews.all()
1✔
149
    average_rating = reviews.aggregate(Avg("rating"))["rating__avg"]
1✔
150

151
    if request.user.is_authenticated and request.method == "POST":
1✔
152
        form_type = request.POST.get("form_type")
1✔
153

154
        if form_type == "upload_image" and request.FILES.getlist("images"):
1✔
155
            for image in request.FILES.getlist("images"):
×
156
                ParkImage.objects.create(park=park, image=image, user=request.user)
×
157
            return redirect("park_detail", id=park.id)
×
158

159
        elif form_type == "submit_review":
1✔
160
            review_text = request.POST.get("text", "").strip()
1✔
161
            rating_value = request.POST.get("rating", "").strip()
1✔
162

163
            if not rating_value.isdigit():
1✔
164
                return render(
×
165
                    request,
166
                    "parks/park_detail.html",
167
                    {
168
                        "park": park,
169
                        "images": images,
170
                        "reviews": reviews,
171
                        "error_message": "Please select a valid rating!",
172
                        "average_rating": average_rating,
173
                    },
174
                )
175

176
            rating = int(rating_value)
1✔
177
            if rating < 1 or rating > 5:
1✔
178
                return render(
×
179
                    request,
180
                    "parks/park_detail.html",
181
                    {
182
                        "park": park,
183
                        "images": images,
184
                        "reviews": reviews,
185
                        "error_message": "Rating must be between 1 and 5 stars!",
186
                        "average_rating": average_rating,
187
                    },
188
                )
189

190
            Review.objects.create(
1✔
191
                park=park, text=review_text, rating=rating, user=request.user
192
            )
193
            return redirect("park_detail", id=park.id)
1✔
194
        # report reviews
195
        elif form_type == "report_review":
1✔
196
            if request.user.is_authenticated:
1✔
197
                review_id = request.POST.get("review_id")
1✔
198
                reason = request.POST.get("reason", "").strip()
1✔
199
            if review_id and reason:
1✔
200
                review = get_object_or_404(Review, id=review_id)
1✔
201
                ReviewReport.objects.create(
1✔
202
                    review=review, reported_by=request.user, reason=reason
203
                )
204
                return redirect("park_detail", id=park.id)
1✔
205

206
    park_json = json.dumps(model_to_dict(park))
1✔
207

208
    return render(
1✔
209
        request,
210
        "parks/park_detail.html",
211
        {
212
            "park": park,
213
            "images": images,
214
            "reviews": reviews,
215
            "park_json": park_json,
216
            "average_rating": average_rating,
217
        },
218
    )
219

220

221
@login_required
1✔
222
def delete_review(request, review_id):
1✔
223
    review = get_object_or_404(Review, id=review_id)
1✔
224
    if request.user == review.user:
1✔
225
        review.delete()
1✔
226
        return redirect("park_detail", id=review.park.id)
1✔
227
    else:
228
        return HttpResponseForbidden("You are not allowed to delete this review.")
×
229

230

231
@login_required
1✔
232
def delete_image(request, image_id):
1✔
233
    image = get_object_or_404(ParkImage, id=image_id)
1✔
234
    if image.user == request.user:
1✔
235
        park_id = image.park.id
1✔
236
        image.delete()
1✔
237
        return redirect("park_detail", id=park_id)
1✔
238
    return HttpResponseForbidden("You are not allowed to delete this image.")
×
239

240

241
def contact_view(request):
1✔
242
    return render(request, "parks/contact.html")
1✔
243

244

245
@login_required
1✔
246
def report_image(request, image_id):
1✔
247
    image = get_object_or_404(ParkImage, id=image_id)
1✔
248
    if request.method == "POST":
1✔
249
        reason = request.POST.get("reason", "").strip()
1✔
250
        if reason:
1✔
251
            ImageReport.objects.create(user=request.user, image=image, reason=reason)
1✔
252
            return redirect("park_detail", id=image.park.id)
1✔
253
    return redirect("park_detail", id=image.park.id)
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