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

gcivil-nyu-org / Wednesday-Fall2023-Team-2 / #6

29 Nov 2023 09:43PM UTC coverage: 85.196% (-2.9%) from 88.099%
#6

push

travis-ci

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

Nov 29 Merge to Production

87 of 123 new or added lines in 11 files covered. (70.73%)

58 existing lines in 5 files now uncovered.

915 of 1074 relevant lines covered (85.2%)

0.85 hits per line

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

57.3
/api/views.py
1
from rest_framework import status
1✔
2
from django.utils import timezone
1✔
3
from django.http import HttpRequest
1✔
4
from django.shortcuts import get_object_or_404
1✔
5
from rest_framework import generics
1✔
6
from haversine import haversine, Unit
1✔
7
from rest_framework.views import APIView
1✔
8
from rest_framework.response import Response
1✔
9
from rest_framework.permissions import IsAuthenticated
1✔
10
from rest_framework.authentication import SessionAuthentication
×
11

12
from map.models import ParkingSpace, OccupancyHistory
1✔
13
from users.models import Post, Comment
1✔
14
from .serializers import ParkingSpaceSerializer, PostSerializer
×
15

16
from better_profanity import profanity
×
17

18
profanity.load_censor_words()
×
19
# Custom swear words can be added to this array
20
custom_badwords = ["bullshittery", "bitchy"]
×
21

22

23
class ParkingSpaceNearCenterAPIView(generics.ListAPIView):
1✔
24
    """API endpoint
25
    /api/spots/?lat=LATITUDE&lon=LONGITUDE
26
    """
27

28
    queryset = ParkingSpace.objects.all()
1✔
29
    serializer_class = ParkingSpaceSerializer
×
30

31
    def get(self, request: HttpRequest) -> Response:
×
32
        """handles get requests to API endpoint above
33

34
        Args:
35
            request (HttpRequest): http request object
36

37
        Returns:
38
            Response: JSON Object with either message requesting
39
            lat and lon as query parameters OR on success
40
            the parking spots within distance
41
            (specified in __is_within_dist method)
42
        """
43
        lat = request.GET.get("lat")
1✔
44
        lon = request.GET.get("lon")
×
45

46
        if not (lat and lon):
1✔
47
            response_data = {"message": "Bad Request: Missing lat and lon parameters"}
1✔
48
            return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
×
49

50
        center_point = (float(lat), float(lon))
1✔
51
        filtered_spots = [
1✔
52
            spot
53
            for spot in self.queryset.all()
54
            if self.__is_within_dist(
55
                center_point, (float(spot.latitude), float(spot.longitude))
56
            )
57
        ]
58

59
        for spot in filtered_spots:
1✔
NEW
60
            if spot.occupancy_percent:
×
NEW
61
                spot.occupancy_percent = round(spot.occupancy_percent / 10) * 10
×
62

63
        serializer = self.serializer_class(filtered_spots, many=True)
×
64

65
        return Response(serializer.data, status=status.HTTP_200_OK)
×
66

67
    def __is_within_dist(self, p1, p2):
×
68
        """method to create a normal user
69

70
        Returns:
71
            Boolean: p1 is within max_dist of p2
72
        """
73
        max_dist = 1
1✔
74
        return haversine(p1, p2, unit=Unit.MILES) < max_dist
×
75

76

77
class ParkingSpaceChangeOccupancyAPIView(APIView):
1✔
78
    """API endpoint
79
    /api/spot/occupancy/?percent=PERCENT&id=PARKING_SPACE_ID
80

81
    Changes the Occupancy Percent of Parking Space (ID)
82
    """
83

84
    permission_classes = [IsAuthenticated]
1✔
85
    authentication_classes = [SessionAuthentication]
×
86

87
    def post(self, request: HttpRequest) -> Response:
×
88
        """handles post requests to API endpoint above
89

90
        Args:
91
            request (HttpRequest): http request object
92

93
        Returns:
94
            Response: JSON Object with either parking_spot_id
95
            sent on success OR
96
            fail message to update front end
97
        """
98
        occupancy_percent = request.data.get("percent")
1✔
99
        parking_spot_id = request.data.get("id")
1✔
100
        if not ((occupancy_percent is not None) and parking_spot_id):
1✔
101
            response_data = {"message": "Bad Request: Missing percent or id parameters"}
1✔
102
            return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
×
103

104
        if isinstance(occupancy_percent, str) and not occupancy_percent.isdigit():
1✔
105
            response_data = {"message": "Bad Request: Percent can only have digits"}
1✔
NEW
106
            return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
×
107

108
        occupancy_percent = int(occupancy_percent)
1✔
109
        if occupancy_percent > 100:
1✔
110
            response_data = {"message": "Bad Request: Percent is >100"}
1✔
111
            return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
1✔
112
        if occupancy_percent % 10 != 0:
1✔
113
            response_data = {"message": "Bad Request: Percent is not a multiple of 10"}
1✔
NEW
114
            return Response(response_data, status=status.HTTP_400_BAD_REQUEST)
×
115

116
        try:
×
117
            # * Retrieve the ParkingSpace instance
118
            parking_space = ParkingSpace.objects.get(parking_spot_id=parking_spot_id)
×
119

120
            # Update the occupancy_percent field
121
            parking_space.occupancy_percent = occupancy_percent
1✔
122

123
            # Create New Occupancy History
124
            history = OccupancyHistory()
1✔
125
            history.user = request.user
1✔
126
            history.parking_space = get_object_or_404(
1✔
127
                ParkingSpace, parking_spot_id=parking_spot_id
128
            )
129
            history.updated_at = timezone.now()
1✔
130
            history.occupancy_percent = occupancy_percent
1✔
131

132
            parking_space.save()
×
NEW
133
            history.save()
×
134

135
            return Response(
×
136
                {"message": "Occupancy percent updated successfully."},
137
                status=status.HTTP_200_OK,
138
            )
139

140
        except ParkingSpace.DoesNotExist:
×
141
            return Response(
1✔
142
                {"message": "ParkingSpace with the specified id does not exist."},
143
                status=status.HTTP_400_BAD_REQUEST,
144
            )
145

146
        except Exception as e:
×
147
            return Response(
1✔
148
                {"message": f"An error occurred: {str(e)}"},
149
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
150
            )
151

152

153
class ParkingSpacePostsAPIView(generics.ListAPIView):
×
154
    """GET API endpoint
155
    /api/spot/posts/<str:spotId>
156

157
    get a list of all the posts associated with a spot
158
    """
159

160
    serializer_class = PostSerializer
×
161

162
    def get_queryset(self):
1✔
163
        parking_space_id = self.kwargs["spotId"]
1✔
164
        return Post.objects.filter(parking_space__parking_spot_id=parking_space_id)
×
165

166

167
class ParkingSpaceAddCommentAPIView(APIView):
1✔
168
    """POST API endpoint
169
    /api/spot/posts/add-comment/<int:postId>
170

171
    get a list of all the posts associated with a spot
172
    """
173

174
    permission_classes = [IsAuthenticated]
×
175
    authentication_classes = [SessionAuthentication]
1✔
176

177
    def post(self, request: HttpRequest, postId: int) -> Response:
1✔
178
        profanity.add_censor_words(custom_badwords)
1✔
179
        comment_content = profanity.censor(request.data["commentContent"])
1✔
180
        if not comment_content:
×
181
            return Response("Error: empty comment content", 400)
1✔
182
        try:
×
183
            post = Post.objects.get(id=postId)
1✔
184
        except Post.DoesNotExist:
×
185
            return Response(f"No post with post id {postId}", 400)
×
186

187
        new_comment = Comment(
×
188
            content=comment_content,
189
            author=request.user,
190
            post=post,
191
            created_at=timezone.now(),
192
        )
193
        new_comment.save()
×
194

195
        return Response("Comment created!", 200)
×
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