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

uw-it-aca / scout / 3716322095

pending completion
3716322095

push

github

GitHub
Merge pull request #430 from uw-it-aca/develop

888 of 1025 relevant lines covered (86.63%)

0.87 hits per line

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

58.1
/scout/views.py
1
# Copyright 2022 UW-IT, University of Washington
2
# SPDX-License-Identifier: Apache-2.0
3

4
from django.http import Http404, HttpResponse
1✔
5
from django.core.exceptions import ImproperlyConfigured
1✔
6
from django.conf import settings
1✔
7
from scout.dao.space import (get_spot_by_id, get_filtered_spots, get_spot_list,
1✔
8
                             get_period_filter, get_spots_by_filter,
9
                             group_spots_by_building, get_building_list,
10
                             validate_detail_info, get_random_limit_from_spots)
11
from scout.dao.image import get_spot_image, get_item_image
1✔
12
from scout.dao.item import (get_item_by_id, get_filtered_items, get_item_count)
1✔
13

14
from django.views.generic.base import TemplateView, TemplateResponse
1✔
15

16
# using red square as the default center
17
DEFAULT_LAT = 47.653811
1✔
18
DEFAULT_LON = -122.3094925
1✔
19

20
CAMPUS_LOCATIONS = {
1✔
21
    "seattle": {"latitude": 47.653811, "longitude": -122.307815},
22
    "south_lake_union": {"latitude": 47.62456939, "longitude": -122.34105337},
23
    "bothell": {"latitude": 47.75907121, "longitude": -122.19103843},
24
    "tacoma": {"latitude": 47.24458187, "longitude": -122.43763134},
25
}
26

27
TECH_CATEGORIES = {
1✔
28
    "cameras": "Cameras",
29
    "camera_accessories": "Camera Accessories",
30
    "computers": "Computers",
31
    "computer_accessories": "Computer Accessories",
32
    "audio_systems": "Audio Systems",
33
    "audio_accessories": "Audio Accessories",
34
}
35

36

37
def validate_campus_selection(function):
1✔
38
    def wrap(request, *args, **kwargs):
1✔
39
        if settings.CAMPUS_URL_LIST and isinstance(settings.CAMPUS_URL_LIST,
1✔
40
                                                   list):
41
            campuses = settings.CAMPUS_URL_LIST
1✔
42
        else:
43
            raise ImproperlyConfigured("Must define a CAMPUS_URL_LIST"
×
44
                                       "of type list in the settings")
45
        if kwargs['campus'] in campuses:
1✔
46
            return function(request, *args, **kwargs)
1✔
47
        else:
48
            raise Http404
1✔
49
    return wrap
1✔
50

51

52
# news splash
53
class NewsSplashView(TemplateView):
1✔
54
    template_name = 'newssplash.html'
1✔
55

56

57
# discover
58
class DiscoverView(TemplateView):
1✔
59
    template_name = "404.html"
1✔
60

61
    @validate_campus_selection
1✔
62
    def get_context_data(self, **kwargs):
1✔
63
        self.template_name = kwargs['template_name']
1✔
64
        context = {"campus": kwargs['campus'],
1✔
65
                   "campus_locations": CAMPUS_LOCATIONS,
66
                   "random_cards": ["studyrandom", "foodrandom"]}
67
        return context
1✔
68

69

70
class DiscoverCardView(TemplateView):
1✔
71
    template_name = "404.html"
1✔
72

73
    @validate_campus_selection
1✔
74
    def get_context_data(self, **kwargs):
1✔
75
        self.template_name = kwargs['template_name']
×
76

77
        # if h_lat and h_lng is provided, use it
78
        # otherwise, user latitude and longitude
79

80
        # handle hybridize user lat/lng requests
81
        hlat = self.request.GET.get('h_lat', None)
×
82
        hlon = self.request.GET.get('h_lng', None)
×
83

84
        # handle standard lat/lng requests for web
85
        lat = self.request.GET.get('latitude', None)
×
86
        lon = self.request.GET.get('longitude', None)
×
87

88
        # Hardcoded for food at the moment. Change it per need basis.
89
        discover_categories = {
×
90
            "safestudy": {
91
                "title": "Study Spots Open Now",
92
                "spot_type": "study",
93
                "filter_url": "open_now=true",
94
                "filter": [
95
                    ('limit', 5),
96
                    ('open_now', True),
97
                    ('center_latitude', hlat if hlat else lat if lat else
98
                        DEFAULT_LAT),
99
                    ('center_longitude', hlon if hlon else lon if lon else
100
                        DEFAULT_LON),
101
                    ('distance', 100000),
102
                ]
103
            },
104
            "safefood": {
105
                "title": "Food Spots Open Now",
106
                "spot_type": "food",
107
                "filter_url": "open_now=true",
108
                "filter": [
109
                    ('limit', 5),
110
                    ('open_now', True),
111
                    ('center_latitude', hlat if hlat else lat if lat else
112
                        DEFAULT_LAT),
113
                    ('center_longitude', hlon if hlon else lon if lon else
114
                        DEFAULT_LON),
115
                    ('distance', 100000),
116
                    ('extended_info:app_type', 'food')
117
                ]
118
            },
119
            "morning": {
120
                "title": "Open Mornings (5am - 11am)",
121
                "spot_type": "food",
122
                "filter_url": "period0=morning",
123
                "filter": [
124
                    ('limit', 5),
125
                    ('center_latitude', hlat if hlat else lat if lat else
126
                        DEFAULT_LAT),
127
                    ('center_longitude', hlon if hlon else lon if lon else
128
                        DEFAULT_LON),
129
                    ('distance', 100000),
130
                    ('extended_info:app_type', 'food')
131
                    ] + get_period_filter('morning')
132

133
            },
134
            "late": {
135
                "title": "Open Late Night (10pm - 5am)",
136
                "spot_type": "food",
137
                "filter_url": "period0=late_night",
138
                "filter": [
139
                    ('limit', 5),
140
                    ('center_latitude', hlat if hlat else lat if lat else
141
                        DEFAULT_LAT),
142
                    ('center_longitude', hlon if hlon else lon if lon else
143
                        DEFAULT_LON),
144
                    ('distance', 100000),
145
                    ('extended_info:app_type', 'food')
146
                    ] + get_period_filter('late_night')
147
            },
148
            "studyoutdoors": {
149
                "title": "Outdoor Study Areas",
150
                "spot_type": "study",
151
                "filter_url": "type0=outdoor",
152
                "filter": [
153
                    ('limit', 5),
154
                    ('center_latitude', hlat if hlat else lat if lat else
155
                        DEFAULT_LAT),
156
                    ('center_longitude', hlon if hlon else lon if lon else
157
                        DEFAULT_LON),
158
                    ('distance', 100000),
159
                    ('type', 'outdoor')
160
                    ]
161
            },
162
            "studycomputerlab": {
163
                "title": "Computer Labs",
164
                "spot_type": "study",
165
                "filter_url": "type0=computer_lab",
166
                "filter": [
167
                    ('limit', 5),
168
                    ('center_latitude', hlat if hlat else lat if lat else
169
                        DEFAULT_LAT),
170
                    ('center_longitude', hlon if hlon else lon if lon else
171
                        DEFAULT_LON),
172
                    ('distance', 100000),
173
                    ('type', 'computer_lab')
174
                ]
175
            },
176
            "studyrandom": {
177
                "title": "Places to study",
178
                "spot_type": "study",
179
                "filter_url": "",
180
                "filter": [
181
                    ('limit', 0)
182
                ]
183
            },
184
            "foodrandom": {
185
                "title": "Places to eat",
186
                "spot_type": "food",
187
                "filter_url": "",
188
                "filter": [
189
                    ('extended_info:app_type', 'food'),
190
                    ('limit', 0)
191
                ]
192
            },
193

194
        }
195

196
        try:
×
197
            discover_data = discover_categories[kwargs['discover_category']]
×
198
        except KeyError:
×
199
            raise Http404
×
200

201
        discover_data["filter"].append(('extended_info:campus',
×
202
                                        kwargs['campus']))
203

204
        spots = get_spots_by_filter(discover_data["filter"])
×
205
        if len(spots) == 0:
×
206
            raise Http404
×
207
        if kwargs['discover_category'] in ['foodrandom', 'studyrandom']:
×
208
            spots = get_random_limit_from_spots(spots, 5)
×
209

210
        context = {
×
211
            "spots": spots,
212
            "campus": kwargs['campus'],
213
            "card_title": discover_data["title"],
214
            "spot_type": discover_data["spot_type"],
215
            "card_filter_url": discover_data["filter_url"]
216
        }
217
        return context
×
218

219

220
# food
221
class PlaceHolderView(TemplateView):
1✔
222
    template_name = "404.html"
1✔
223

224
    @validate_campus_selection
1✔
225
    def get_context_data(self, **kwargs):
1✔
226
        self.template_name = kwargs['template_name']
×
227
        context = {"campus": kwargs['campus'],
×
228
                   "app_type": kwargs['app_type'],
229
                   "campus_locations": CAMPUS_LOCATIONS}
230
        return context
×
231

232

233
class FoodListView(TemplateView):
1✔
234
    template_name = "404.html"
1✔
235

236
    @validate_campus_selection
1✔
237
    def get_context_data(self, **kwargs):
1✔
238
        self.template_name = kwargs['template_name']
1✔
239
        spots = get_filtered_spots(self.request, kwargs['campus'], "food")
1✔
240
        context = {"spots": spots,
1✔
241
                   "campus": kwargs['campus'],
242
                   "count": len(spots),
243
                   "app_type": 'food',
244
                   "campus_locations": CAMPUS_LOCATIONS}
245
        return context
1✔
246

247

248
class FoodDetailView(TemplateView):
1✔
249
    template_name = "404.html"
1✔
250

251
    @validate_campus_selection
1✔
252
    def get_context_data(self, **kwargs):
1✔
253
        self.template_name = kwargs['template_name']
1✔
254
        spot = get_spot_by_id(kwargs['spot_id'])
1✔
255
        spot = validate_detail_info(spot, kwargs['campus'], "food")
1✔
256
        if not spot:
1✔
257
            raise Http404
1✔
258

259
        context = {"spot": spot,
1✔
260
                   "campus": kwargs['campus'],
261
                   "app_type": 'food',
262
                   "campus_locations": CAMPUS_LOCATIONS}
263
        return context
1✔
264

265

266
class FoodFilterView(TemplateView):
1✔
267
    template_name = "404.html"
1✔
268

269
    @validate_campus_selection
1✔
270
    def get_context_data(self, **kwargs):
1✔
271
        self.template_name = kwargs['template_name']
1✔
272

273
        # load parameters into context
274
        filter_types = ["payment", "period", "type"]
1✔
275

276
        context = _load_filter_params_checked(self.request, filter_types)
1✔
277

278
        context.update({"campus": kwargs['campus'],
1✔
279
                        "app_type": 'food',
280
                        "campus_locations": CAMPUS_LOCATIONS})
281

282
        return context
1✔
283

284

285
# study
286
class StudyListView(TemplateView):
1✔
287
    template_name = "404.html"
1✔
288

289
    @validate_campus_selection
1✔
290
    def get_context_data(self, **kwargs):
1✔
291
        self.template_name = kwargs['template_name']
1✔
292
        spots = get_filtered_spots(self.request, kwargs['campus'], "study")
1✔
293
        grouped_spots = group_spots_by_building(spots)
1✔
294
        context = {"spots": spots,
1✔
295
                   "campus": kwargs['campus'],
296
                   "grouped_spots": grouped_spots,
297
                   "count": len(spots),
298
                   "app_type": 'study',
299
                   "campus_locations": CAMPUS_LOCATIONS}
300
        return context
1✔
301

302

303
class StudyDetailView(TemplateView):
1✔
304
    template_name = "404.html"
1✔
305

306
    @validate_campus_selection
1✔
307
    def get_context_data(self, **kwargs):
1✔
308
        self.template_name = kwargs['template_name']
×
309
        spot = get_spot_by_id(kwargs['spot_id'])
×
310
        spot = validate_detail_info(spot, kwargs['campus'], "study")
×
311
        if not spot:
×
312
            raise Http404
×
313

314
        context = {"spot": spot,
×
315
                   "campus": kwargs['campus'],
316
                   "app_type": 'study',
317
                   "campus_locations": CAMPUS_LOCATIONS}
318
        return context
×
319

320

321
class StudyFilterView(TemplateView):
1✔
322
    template_name = "404.html"
1✔
323

324
    @validate_campus_selection
1✔
325
    def get_context_data(self, **kwargs):
1✔
326
        self.template_name = kwargs['template_name']
1✔
327

328
        # load parameters into context
329
        filter_types = ["type", "resources", "noise", "food", "lighting",
1✔
330
                        "reservation", "building", "capacity"]
331

332
        context = _load_filter_params_checked(self.request, filter_types)
1✔
333

334
        context.update({"campus": kwargs['campus'],
1✔
335
                        "buildings": get_building_list(kwargs['campus']),
336
                        "app_type": 'study',
337
                        "campus_locations": CAMPUS_LOCATIONS})
338

339
        return context
1✔
340

341

342
# tech
343
class TechListView(TemplateView):
1✔
344
    template_name = "404.html"
1✔
345

346
    @validate_campus_selection
1✔
347
    def get_context_data(self, **kwargs):
1✔
348
        self.template_name = kwargs['template_name']
1✔
349
        # spots = get_spots_by_filter([('has_items', 'true')])
350
        self.request.GET = self.request.GET.copy()
1✔
351
        self.request.GET['item_is_active'] = 'true'
1✔
352
        spots = get_filtered_spots(self.request, kwargs['campus'], "tech")
1✔
353
        spots = get_filtered_items(spots, self.request)
1✔
354
        count = get_item_count(spots)
1✔
355
        if count <= 0:
1✔
356
            spots = []
1✔
357

358
        context = {"spots": spots,
1✔
359
                   "campus": kwargs['campus'],
360
                   "count": count,
361
                   "app_type": 'tech',
362
                   "campus_locations": CAMPUS_LOCATIONS}
363
        return context
1✔
364

365

366
class TechDetailView(TemplateView):
1✔
367
    template_name = "404.html"
1✔
368

369
    @validate_campus_selection
1✔
370
    def get_context_data(self, **kwargs):
1✔
371
        self.template_name = kwargs['template_name']
×
372
        spot = get_item_by_id(int(kwargs['item_id']))
×
373
        spot = validate_detail_info(spot, kwargs['campus'], "tech")
×
374
        if not spot:
×
375
            raise Http404
×
376

377
        context = {"spot": spot,
×
378
                   "campus": kwargs['campus'],
379
                   "app_type": 'tech',
380
                   "campus_locations": CAMPUS_LOCATIONS}
381
        return context
×
382

383

384
class TechFilterView(TemplateView):
1✔
385
    template_name = "404.html"
1✔
386

387
    @validate_campus_selection
1✔
388
    def get_context_data(self, **kwargs):
1✔
389
        self.template_name = kwargs['template_name']
×
390

391
        # load parameters into context
392
        filter_types = ["brand", "subcategory"]
×
393
        tech_spots = get_spot_list("tech")
×
394
        info = extract_spots_item_info(tech_spots)
×
395

396
        pre = _load_filter_params_checked(self.request, filter_types)
×
397
        context = {}
×
398

399
        for obj in pre:
×
400
            new_key = obj.replace(" ", "_").replace("-", "_").replace("/",
×
401
                                                                      "_")
402
            context[new_key] = pre[obj]
×
403

404
        context.update({"campus": kwargs['campus'],
×
405
                        "app_type": 'tech',
406
                        "filters": info,
407
                        "campus_locations": CAMPUS_LOCATIONS})
408

409
        return context
×
410

411

412
def extract_spots_item_info(spots):
1✔
413
    category_list = {}
×
414
    brand_list = []
×
415
    for spot in spots:
×
416
        for item in spot.items:
×
417
            cat = item.category
×
418
            sub = item.subcategory
×
419

420
            if cat not in category_list:
×
421
                category_list[cat] = {
×
422
                    'sub': {},
423
                    'name': ''
424
                }
425

426
            if sub not in category_list[cat]['sub']:
×
427
                category_list[cat]['sub'][sub] = {'name': ''}
×
428

429
            for info in item.extended_info:
×
430
                if info.key == 'i_brand' and info.value not in brand_list:
×
431
                    brand_list.append(info.value)
×
432
                if info.key == 'i_subcat_print_name':
×
433
                    category_list[cat]['sub'][sub]['name'] = info.value
×
434

435
    for cat_name in TECH_CATEGORIES:
×
436
        if cat_name in category_list:
×
437
            category_list[cat_name]['name'] = TECH_CATEGORIES[cat_name]
×
438

439
    result = {
×
440
        "categories": category_list,
441
        "brands": brand_list
442
    }
443
    return result
×
444

445

446
# image views
447
def spot_image_view(request, image_id, spot_id):
1✔
448
    width = request.GET.get('width', None)
×
449
    try:
×
450
        resp, content = get_spot_image(spot_id, image_id, width)
×
451
        etag = resp.headers.get('etag', None)
×
452
        response = HttpResponse(content,
×
453
                                content_type=resp.headers['content-type'])
454
        response['etag'] = etag
×
455
        return response
×
456
    except Exception:
×
457
        raise Http404
×
458

459

460
def item_image_view(request, image_id, item_id):
1✔
461
    width = request.GET.get('width', None)
×
462
    try:
×
463
        resp, content = get_item_image(item_id, image_id, width)
×
464
        etag = resp.headers.get('etag', None)
×
465
        response = HttpResponse(content,
×
466
                                content_type=resp.headers['content-type'])
467
        response['etag'] = etag
×
468
        return response
×
469
    except Exception:
×
470
        raise Http404
×
471

472

473
def _load_filter_params_checked(request, filter_types):
1✔
474
    context = {}
1✔
475

476
    if "open_now" in request.GET:
1✔
477
        context["open_now"] = True
×
478

479
    for param_class in filter_types:
1✔
480
        has_type = True
1✔
481
        i = 0
1✔
482
        while has_type:
1✔
483
            if param_class + str(i) in request.GET:
1✔
484
                param = request.GET[param_class + str(i)]
×
485
                context[param] = True
×
486
            else:
487
                has_type = False
1✔
488
            i = i + 1
1✔
489

490
    return context
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

© 2025 Coveralls, Inc