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

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

09 Apr 2025 11:04PM UTC coverage: 97.595% (+0.9%) from 96.678%
425

push

travis-pro

web-flow
Merge pull request #226 from gcivil-nyu-org/develop

Develop

202 of 208 new or added lines in 16 files covered. (97.12%)

1 existing line in 1 file now uncovered.

974 of 998 relevant lines covered (97.6%)

0.98 hits per line

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

88.89
/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
from .forms import RegisterForm
1✔
14

15
import json
1✔
16
from django.contrib import messages
1✔
17

18

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

30
            # Log the user in immediately
31
            login(request, user)
1✔
32
            request.session.save()
1✔
33
            return redirect("home")
1✔
34
    else:
35
        form = RegisterForm()
1✔
36

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

39

40
def home_view(request):
1✔
UNCOV
41
    return render(request, "parks/home.html")
×
42

43

44
def park_and_map(request):
1✔
45
    # Get filter values from GET request
46
    query = request.GET.get("query", "").strip()
1✔
47
    filter_value = request.GET.get("filter", "").strip()
1✔
48
    accessible_value = request.GET.get("accessible", "").strip()
1✔
49
    borough_value = request.GET.get("borough", "").strip().upper()
1✔
50

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

53
    # Fetch all dog runs from the database
54
    parks = (
1✔
55
        DogRunNew.objects.all()
56
        .order_by("id")
57
        .prefetch_related("images")
58
        .annotate(
59
            thumbnail_url=Cast(Subquery(thumbnail), output_field=CharField()),
60
            average_rating=Avg("reviews__rating"),
61
            review_count=Count("reviews"),
62
        )
63
    )
64

65
    # Search by ZIP, name, or Google name
66
    if query:
1✔
67
        parks = parks.filter(
×
68
            Q(name__icontains=query)
69
            | Q(google_name__icontains=query)
70
            | Q(zip_code__icontains=query)
71
        )
72

73
    # Filter by park type (e.g., "Off-Leash")
74
    if filter_value:
1✔
75
        parks = parks.filter(dogruns_type__iexact=filter_value)
×
76

77
    # Filter by accessibility only if explicitly set to "True" or "False"
78
    if accessible_value == "True":
1✔
79
        parks = parks.filter(accessible=True)
×
80
    elif accessible_value == "False":
1✔
81
        parks = parks.filter(accessible=False)
×
82

83
    if borough_value:
1✔
84
        parks = parks.filter(borough=borough_value)
1✔
85

86
    # Convert parks to JSON (for JS use)
87
    parks_json = json.dumps(list(parks.values()))
1✔
88

89
    # Render the template
90
    return render(
1✔
91
        request,
92
        "parks/combined_view.html",
93
        {
94
            "parks": parks,
95
            "parks_json": parks_json,
96
            "query": query,
97
            "selected_type": filter_value,
98
            "selected_accessible": accessible_value,
99
            "selected_borough": borough_value,
100
        },
101
    )
102

103

104
def park_detail(request, slug, id):
1✔
105
    park = get_object_or_404(DogRunNew, id=id)
1✔
106
    images = ParkImage.objects.filter(park=park)
1✔
107
    reviews = park.reviews.all()
1✔
108
    average_rating = reviews.aggregate(Avg("rating"))["rating__avg"]
1✔
109

110
    if request.user.is_authenticated and request.method == "POST":
1✔
111
        form_type = request.POST.get("form_type")
1✔
112

113
        if form_type == "submit_review":
1✔
114
            review_text = request.POST.get("text", "").strip()
1✔
115
            rating_value = request.POST.get("rating", "").strip()
1✔
116

117
            if not rating_value.isdigit():
1✔
NEW
118
                messages.error(request, "Please select a rating before submitting.")
×
NEW
119
                return redirect("park_detail", slug=park.slug, id=park.id)
×
120

121
            rating = int(rating_value)
1✔
122
            if rating < 1 or rating > 5:
1✔
123
                return render(
×
124
                    request,
125
                    "parks/park_detail.html",
126
                    {
127
                        "park": park,
128
                        "images": images,
129
                        "reviews": reviews,
130
                        "error_message": "Rating must be between 1 and 5 stars!",
131
                        "average_rating": average_rating,
132
                    },
133
                )
134

135
            review = Review.objects.create(
1✔
136
                park=park,
137
                text=review_text if review_text else "",
138
                rating=rating,
139
                user=request.user,
140
            )
141

142
            images = request.FILES.getlist("images")
1✔
143

144
            if images:
1✔
NEW
145
                for image in images:
×
NEW
146
                    ParkImage.objects.create(
×
147
                        park=park, image=image, review=review, user=request.user
148
                    )
149

150
            messages.success(request, "Your review was submitted successfully!")
1✔
151
            return redirect("park_detail", slug=park.slug, id=park.id)
1✔
152
        # report reviews
153
        elif form_type == "report_review":
1✔
154
            if request.user.is_authenticated:
1✔
155
                review_id = request.POST.get("review_id")
1✔
156
                reason = request.POST.get("reason", "").strip()
1✔
157
            if review_id and reason:
1✔
158
                review = get_object_or_404(Review, id=review_id)
1✔
159
                ReviewReport.objects.create(
1✔
160
                    review=review, reported_by=request.user, reason=reason
161
                )
162
                messages.success(
1✔
163
                    request, "Your review report was submitted successfully."
164
                )
165
                return redirect("park_detail", slug=park.slug, id=park.id)
1✔
166

167
    park_json = json.dumps(model_to_dict(park))
1✔
168

169
    return render(
1✔
170
        request,
171
        "parks/park_detail.html",
172
        {
173
            "park": park,
174
            "images": images,
175
            "reviews": reviews,
176
            "park_json": park_json,
177
            "average_rating": average_rating,
178
        },
179
    )
180

181

182
@login_required
1✔
183
def delete_review(request, review_id):
1✔
184
    review = get_object_or_404(Review, id=review_id)
1✔
185
    if request.user == review.user:
1✔
186
        review.delete()
1✔
187
        messages.success(request, "You have successfully deleted the review!")
1✔
188
        return redirect("park_detail", slug=review.park.slug, id=review.park.id)
1✔
189
    else:
190
        return HttpResponseForbidden("You are not allowed to delete this review.")
×
191

192

193
@login_required
1✔
194
def delete_image(request, image_id):
1✔
195
    image = get_object_or_404(ParkImage, id=image_id)
1✔
196
    if image.user == request.user:
1✔
197
        park_id = image.park.id
1✔
198
        image.delete()
1✔
199
        messages.success(request, "You have successfully deleted the image!")
1✔
200
        return redirect("park_detail", slug=image.park.slug, id=park_id)
1✔
201
    return HttpResponseForbidden("You are not allowed to delete this image.")
×
202

203

204
def contact_view(request):
1✔
205
    return render(request, "parks/contact.html")
1✔
206

207

208
@login_required
1✔
209
def report_image(request, image_id):
1✔
210
    image = get_object_or_404(ParkImage, id=image_id)
1✔
211
    if request.method == "POST":
1✔
212
        reason = request.POST.get("reason", "").strip()
1✔
213
        if reason:
1✔
214
            ImageReport.objects.create(user=request.user, image=image, reason=reason)
1✔
215
            messages.success(request, "You have successfully reported the image!")
1✔
216
            return redirect("park_detail", slug=image.park.slug, id=image.park.id)
1✔
217
    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