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

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

09 Apr 2025 09:44PM UTC coverage: 96.016% (-1.3%) from 97.348%
415

Pull #223

travis-pro

web-flow
Merge 641d3dcfc into 81c89d2d6
Pull Request #223: Fixing URLS

964 of 1004 relevant lines covered (96.02%)

0.96 hits per line

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

78.91
/parks/views.py
1
from django.shortcuts import render, get_object_or_404, redirect
1✔
2
from django.http import (  # noqa: F401  # Ignore "imported but unused"
1✔
3
    HttpResponseForbidden,
4
    HttpResponse,
5
)
6
from django.db.models import OuterRef, Subquery, CharField, Q, Avg, Count
1✔
7
from django.db.models.functions import Cast
1✔
8
from .models import DogRunNew, Review, ParkImage, ReviewReport, ImageReport
1✔
9
from django.forms.models import model_to_dict
1✔
10
from django.contrib.auth import login
1✔
11
from django.contrib.auth.decorators import login_required
1✔
12

13
import folium
1✔
14
from folium.plugins import MarkerCluster
1✔
15

16
from .utilities import folium_cluster_styling
1✔
17
from .forms import RegisterForm
1✔
18

19
import json
1✔
20
from django.contrib import messages
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", "")
×
46
    parks = DogRunNew.objects.all()  # Fetch all dog runs from the database
×
47

48
    if query:
×
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})
×
56

57

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

61

62
def map(request):
1✔
63

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

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

70
    marker_cluster = MarkerCluster(icon_create_function=icon_create_function).add_to(m)
×
71

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

75
    # Mark every park on the map
76
    for park in parks:
×
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_()}
×
87
    return render(request, "parks/map.html", context)
×
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(
105
            thumbnail_url=Cast(Subquery(thumbnail), output_field=CharField()),
106
            average_rating=Avg("reviews__rating"),
107
            review_count=Count("reviews"),
108
        )
109
    )
110

111
    # Search by ZIP, name, or Google name
112
    if query:
1✔
113
        parks = parks.filter(
×
114
            Q(name__icontains=query)
115
            | Q(google_name__icontains=query)
116
            | Q(zip_code__icontains=query)
117
        )
118

119
    # Filter by park type (e.g., "Off-Leash")
120
    if filter_value:
1✔
121
        parks = parks.filter(dogruns_type__iexact=filter_value)
×
122

123
    # Filter by accessibility only if explicitly set to "True" or "False"
124
    if accessible_value == "True":
1✔
125
        parks = parks.filter(accessible=True)
×
126
    elif accessible_value == "False":
1✔
127
        parks = parks.filter(accessible=False)
×
128

129
    if borough_value:
1✔
130
        parks = parks.filter(borough=borough_value)
1✔
131

132
    # Convert parks to JSON (for JS use)
133
    parks_json = json.dumps(list(parks.values()))
1✔
134

135
    # Render the template
136
    return render(
1✔
137
        request,
138
        "parks/combined_view.html",
139
        {
140
            "parks": parks,
141
            "parks_json": parks_json,
142
            "query": query,
143
            "selected_type": filter_value,
144
            "selected_accessible": accessible_value,
145
            "selected_borough": borough_value,
146
        },
147
    )
148

149

150
def park_detail(request, slug, id):
1✔
151
    park = get_object_or_404(DogRunNew, id=id)
1✔
152
    images = ParkImage.objects.filter(park=park)
1✔
153
    reviews = park.reviews.all()
1✔
154
    average_rating = reviews.aggregate(Avg("rating"))["rating__avg"]
1✔
155

156
    if request.user.is_authenticated and request.method == "POST":
1✔
157
        form_type = request.POST.get("form_type")
1✔
158

159
        if 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
                messages.error(request, "Please select a rating before submitting.")
×
165
                return redirect("park_detail", slug=park.slug, id=park.id)
×
166

167
            rating = int(rating_value)
1✔
168
            if rating < 1 or rating > 5:
1✔
169
                return render(
×
170
                    request,
171
                    "parks/park_detail.html",
172
                    {
173
                        "park": park,
174
                        "images": images,
175
                        "reviews": reviews,
176
                        "error_message": "Rating must be between 1 and 5 stars!",
177
                        "average_rating": average_rating,
178
                    },
179
                )
180

181
            review = Review.objects.create(
1✔
182
                park=park,
183
                text=review_text if review_text else "",
184
                rating=rating,
185
                user=request.user,
186
            )
187

188
            images = request.FILES.getlist("images")
1✔
189

190
            if images:
1✔
191
                for image in images:
×
192
                    ParkImage.objects.create(
×
193
                        park=park, image=image, review=review, user=request.user
194
                    )
195

196
            messages.success(request, "Your review was submitted successfully!")
1✔
197
            return redirect("park_detail", slug=park.slug, id=park.id)
1✔
198
        # report reviews
199
        elif form_type == "report_review":
1✔
200
            if request.user.is_authenticated:
1✔
201
                review_id = request.POST.get("review_id")
1✔
202
                reason = request.POST.get("reason", "").strip()
1✔
203
            if review_id and reason:
1✔
204
                review = get_object_or_404(Review, id=review_id)
1✔
205
                ReviewReport.objects.create(
1✔
206
                    review=review, reported_by=request.user, reason=reason
207
                )
208
                messages.success(
1✔
209
                    request, "Your review report was submitted successfully."
210
                )
211
                return redirect("park_detail", slug=park.slug, id=park.id)
1✔
212

213
    park_json = json.dumps(model_to_dict(park))
1✔
214

215
    return render(
1✔
216
        request,
217
        "parks/park_detail.html",
218
        {
219
            "park": park,
220
            "images": images,
221
            "reviews": reviews,
222
            "park_json": park_json,
223
            "average_rating": average_rating,
224
        },
225
    )
226

227

228
@login_required
1✔
229
def delete_review(request, review_id):
1✔
230
    review = get_object_or_404(Review, id=review_id)
1✔
231
    if request.user == review.user:
1✔
232
        review.delete()
1✔
233
        messages.success(request, "You have successfully deleted the review!")
1✔
234
        return redirect("park_detail", slug=review.park.slug, id=review.park.id)
1✔
235
    else:
236
        return HttpResponseForbidden("You are not allowed to delete this review.")
×
237

238

239
@login_required
1✔
240
def delete_image(request, image_id):
1✔
241
    image = get_object_or_404(ParkImage, id=image_id)
1✔
242
    if image.user == request.user:
1✔
243
        park_id = image.park.id
1✔
244
        image.delete()
1✔
245
        messages.success(request, "You have successfully deleted the image!")
1✔
246
        return redirect("park_detail", slug=image.park.slug, id=park_id)
1✔
247
    return HttpResponseForbidden("You are not allowed to delete this image.")
×
248

249

250
def contact_view(request):
1✔
251
    return render(request, "parks/contact.html")
1✔
252

253

254
@login_required
1✔
255
def report_image(request, image_id):
1✔
256
    image = get_object_or_404(ParkImage, id=image_id)
1✔
257
    if request.method == "POST":
1✔
258
        reason = request.POST.get("reason", "").strip()
1✔
259
        if reason:
1✔
260
            ImageReport.objects.create(user=request.user, image=image, reason=reason)
1✔
261
            messages.success(request, "You have successfully reported the image!")
1✔
262
            return redirect("park_detail", slug=image.park.slug, id=image.park.id)
1✔
263
    return redirect("park_detail", slug=image.park.slug, 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