Skip to content

Commit dbd5719

Browse files
authored
DBC22-6067: removed legacy images pulling logic (#1275)
1 parent 6593ef1 commit dbd5719

19 files changed

Lines changed: 640 additions & 362 deletions

.env.example

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,7 @@ REACT_APP_LEGACY_URL=<legacy URL for the old DriveBC site>
6464

6565
# API
6666
DRIVEBC_INLAND_FERRY_API_BASE_URL=<inland ferry api url>
67-
DRIVEBC_IMAGE_API_BASE_URL=<image api url>
6867
DRIVEBC_IMAGE_BASE_URL=<base url for local images>
69-
DRIVEBC_IMAGE_PROXY_URL=<image proxy url>
70-
DRIVEBC_WEBCAM_API_BASE_URL=<camera api url>
7168
DRIVEBC_OPEN_511_API_BASE_URL=<open511 api url>
7269
DRIVEBC_DIT_API_BASE_URL=<CARS api url>
7370
DRIVEBC_ROUTE_PLANNER_API_BASE_URL=<route planner url>

src/backend/apps/consumer/processor.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ def process_camera_rows(rows):
307307
'update_period_stddev': 60,
308308
'dbc_mark': row.cam_internetdbc_mark if hasattr(row, 'cam_internetdbc_mark') else '',
309309
'is_on': not row.cam_controldisabled if hasattr(row, 'cam_controldisabled') else True,
310+
'cam_controldisappear': not row.cam_controldisappear if hasattr(row, 'cam_controldisappear') else True,
310311
'cam_maintenanceis_on_demand': row.cam_maintenanceis_on_demand if hasattr(row, 'cam_maintenanceis_on_demand') else False,
311312
'is_new': row.isnew if hasattr(row, 'isnew') else False,
312313
'seq': row.seq if hasattr(row, 'seq') else 0,
@@ -467,8 +468,6 @@ def save_watermarked_image_to_drivebc_pvc(camera_id: str, image_bytes: bytes, is
467468
f.write(image_bytes)
468469
if is_on:
469470
logger.info(f"Watermarked image saved to drivebc PVC at {filepath}")
470-
else:
471-
logger.info(f"Blank out image saved to drivebc PVC at {filepath}")
472471
except Exception as e:
473472
logger.error(f"Error saving image to drivebc PVC {filepath}: {e}")
474473

@@ -480,13 +479,10 @@ def delete_watermarked_image_from_pvc(camera_id: str):
480479
return
481480

482481
try:
483-
deleted_count = 0
484482
for filename in os.listdir(save_dir):
485483
filepath = os.path.join(save_dir, filename)
486484
if os.path.isfile(filepath):
487485
os.remove(filepath)
488-
deleted_count += 1
489-
logger.info(f"Deleted {deleted_count} watermarked image(s) from {save_dir}")
490486
except Exception as e:
491487
logger.error(f"Error deleting watermarked images from PVC {save_dir}: {e}")
492488

src/backend/apps/consumer/tasks.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,9 @@ def generate_offline_camera_images():
3232
watermarked = blank_out_image(camera, dummy_image_bytes, tz, timestamp)
3333

3434
if watermarked:
35-
# Convert timestamp to UTC for storage
36-
local_tz = pytz.timezone(tz)
37-
naive_dt = datetime.strptime(timestamp, "%Y%m%d%H%M%S%f")
38-
local_dt = local_tz.localize(naive_dt)
39-
utc_dt = local_dt.astimezone(pytz.utc)
40-
utc_timestamp_str = utc_dt.strftime("%Y%m%d%H%M%S")
41-
4235
# Delete all the images for replay the day
4336
delete_watermarked_image_from_pvc(camera_id)
4437
# Delete all the records from image index table for offline cams
4538
async_to_sync(delete_offline_webcam_records)(camera_id)
46-
# Save blank image for replay the day
47-
save_watermarked_image_to_pvc(camera_id, watermarked, utc_timestamp_str, False)
4839
# Save blank image for current image displaying
4940
save_watermarked_image_to_drivebc_pvc(camera_id, watermarked, False)

src/backend/apps/consumer/tests/test_processor.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def test_process_camera_rows_with_valid_data(self):
4343
cam_locationselevation=100,
4444
cam_internetdbc_mark='MARK1',
4545
cam_controldisabled=False,
46+
cam_controldisappear=False,
4647
cam_maintenanceis_on_demand=False,
4748
isnew=False,
4849
seq=1,

src/backend/apps/consumer/tests/test_tasks.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def test_generates_for_offline_cameras(self, mock_process_rows, mock_get_db):
5353

5454
generate_offline_camera_images()
5555

56-
mock_save_pvc.assert_called_once()
56+
mock_save_pvc.assert_not_called()
5757
mock_save_drivebc.assert_called_once()
5858

5959
@patch('apps.consumer.tasks.get_all_from_db')
@@ -84,7 +84,7 @@ def test_handles_watermark_failure(self, mock_process_rows, mock_get_db):
8484

8585
generate_offline_camera_images()
8686

87-
mock_save_pvc.assert_called_once()
87+
mock_save_pvc.assert_not_called()
8888
mock_save_drivebc.assert_called_once()
8989

9090
@patch('apps.consumer.tasks.get_all_from_db')
@@ -103,4 +103,4 @@ def test_handles_is_on_key_missing(self, mock_process_rows, mock_get_db):
103103
generate_offline_camera_images()
104104

105105
mock_watermark.assert_not_called()
106-
mock_save_pvc.assert_not_called()
106+
mock_save_pvc.assert_not_called()

src/backend/apps/feed/client.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
REGIONAL_WEATHER,
1919
REGIONAL_WEATHER_AREAS,
2020
REST_STOP,
21-
WEBCAM,
21+
# WEBCAM,
2222
WILDFIRE,
2323
)
2424
from apps.feed.serializers import (
@@ -40,6 +40,8 @@
4040
from django.core.cache import cache
4141
from rest_framework.exceptions import ValidationError
4242
from rest_framework.response import Response
43+
from apps.weather.models import CurrentWeather
44+
from apps.webcam.models import CameraSource, Region, RegionHighway
4345

4446
# Maps the key for our client API's serializer fields to the matching pair of
4547
# the source API's DataSetName and DisplayName fields
@@ -88,9 +90,6 @@ class FeedClient:
8890

8991
def __init__(self):
9092
self.resource_map: Dict[str, dict] = {
91-
WEBCAM: {
92-
"base_url": settings.DRIVEBC_WEBCAM_API_BASE_URL,
93-
},
9493
OPEN511: {
9594
"base_url": settings.DRIVEBC_OPEN_511_API_BASE_URL,
9695
},
@@ -264,13 +263,16 @@ def get_list_feed(self, resource_type, resource_name, serializer_cls, params=Non
264263
new_serializer.is_valid(raise_exception=True)
265264
return new_serializer.validated_data
266265

267-
# Webcam
268-
def get_webcam(self, webcam):
269-
return self.get_single_feed(webcam, WEBCAM, 'webcams/', WebcamFeedSerializer)
270266

271267
def get_webcam_list(self):
272-
return self.get_list_feed(WEBCAM, 'webcams', WebcamAPISerializer)
268+
try:
269+
cameras = list(CameraSource.objects.using("mssql").all())
270+
return cameras
273271

272+
except Exception as e:
273+
logger.error(f"Failed to query camera from Webcam database: {e}")
274+
return []
275+
274276
# Events
275277
def get_event(self, event):
276278
return self.get_single_feed(event, OPEN511, 'events/', EventFeedSerializer)

src/backend/apps/feed/tests/test_feed_client.py

Lines changed: 38 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
import pytest
44
from django.core.cache import cache
55
from httpx import HTTPStatusError
6-
from apps.feed.client import FeedClient, WEBCAM, OPEN511
6+
from apps.feed.client import FeedClient, OPEN511
77
from apps.feed.constants import REST_STOP
88
from apps.feed.serializers import WebcamAPISerializer, EventAPISerializer
99
from apps.shared.tests import BaseTest
1010
from django.conf import settings
11+
from apps.webcam.models import CameraSource
12+
from pathlib import Path
13+
import json
1114

1215
logging.getLogger().setLevel(logging.CRITICAL)
1316

@@ -27,18 +30,6 @@ def setUp(self):
2730
super().setUp()
2831
self.client = FeedClient()
2932

30-
def test_get_endpoint(self):
31-
endpoint = self.client._get_endpoint(WEBCAM, 'webcams/123')
32-
self.assertIn('webcams/123', endpoint)
33-
34-
def test_get_auth_headers_with_key(self):
35-
self.client.resource_map[WEBCAM]['auth_key'] = 'test_api_key'
36-
headers = self.client._get_auth_headers(WEBCAM)
37-
self.assertEqual(headers, {'apiKey': 'test_api_key'})
38-
39-
def test_get_auth_headers_without_key(self):
40-
headers = self.client._get_auth_headers(WEBCAM)
41-
self.assertEqual(headers, {})
4233

4334
def test_get_response_data_or_raise_success(self):
4435
mock_response = create_mock_response(200, {'key': 'value'})
@@ -174,49 +165,6 @@ def setUp(self):
174165
}
175166
}
176167

177-
@patch('apps.feed.client.httpx.get')
178-
@patch('apps.feed.serializers.WebcamFeedSerializer')
179-
def test_get_single_feed(self, mock_serializer_cls, mock_get):
180-
mock_response = create_mock_response(200, self.valid_webcam_data)
181-
mock_get.return_value = mock_response
182-
183-
mock_serializer = MagicMock()
184-
mock_serializer.is_valid = MagicMock(return_value=True)
185-
mock_serializer.validated_data = {'id': 123}
186-
mock_serializer_cls.return_value = mock_serializer
187-
188-
from apps.feed.serializers import WebcamFeedSerializer
189-
result = self.client.get_single_feed('123', WEBCAM, 'webcams/', WebcamFeedSerializer)
190-
self.assertIsNotNone(result)
191-
192-
@patch('apps.feed.client.httpx.get')
193-
@patch('apps.feed.serializers.WebcamFeedSerializer')
194-
def test_get_single_feed_returns_list(self, mock_serializer_cls, mock_get):
195-
mock_response = create_mock_response(200, [self.valid_webcam_data])
196-
mock_get.return_value = mock_response
197-
198-
mock_serializer = MagicMock()
199-
mock_serializer.is_valid = MagicMock(return_value=True)
200-
mock_serializer.validated_data = {'id': 123}
201-
mock_serializer_cls.return_value = mock_serializer
202-
203-
from apps.feed.serializers import WebcamFeedSerializer
204-
result = self.client.get_single_feed('123', WEBCAM, 'webcams/', WebcamFeedSerializer)
205-
self.assertIsNotNone(result)
206-
207-
@patch('apps.feed.client.httpx.get')
208-
@patch('apps.feed.client.WebcamFeedSerializer')
209-
def test_get_single_feed_as_serializer(self, mock_serializer_cls, mock_get):
210-
mock_response = create_mock_response(200, {'id': '123', 'name': 'Test'})
211-
mock_get.return_value = mock_response
212-
213-
mock_serializer = MagicMock()
214-
mock_serializer_cls.return_value = mock_serializer
215-
mock_serializer.is_valid = MagicMock()
216-
mock_serializer.save = MagicMock()
217-
218-
result = self.client.get_single_feed('123', WEBCAM, 'webcams/', mock_serializer_cls, as_serializer=True)
219-
self.assertEqual(result, mock_serializer)
220168

221169

222170
class TestFeedClientGetListFeed(BaseTest):
@@ -226,13 +174,6 @@ def setUp(self):
226174
super().setUp()
227175
self.client = FeedClient()
228176

229-
@patch('apps.feed.client.httpx.get')
230-
def test_get_list_feed_success(self, mock_get):
231-
mock_response = create_mock_response(200, {'webcams': []})
232-
mock_get.return_value = mock_response
233-
234-
result = self.client.get_list_feed(WEBCAM, 'webcams', WebcamAPISerializer)
235-
self.assertIn('webcams', result)
236177

237178
@patch('apps.feed.client.httpx.get')
238179
def test_get_list_feed_with_params(self, mock_get):
@@ -245,28 +186,47 @@ def test_get_list_feed_with_params(self, mock_get):
245186

246187
class TestFeedClientWebcam(BaseTest):
247188
"""Test webcam feed methods."""
189+
190+
def populate_webcam_data(self, mock_data=None):
191+
for cam in mock_data['webcams']:
192+
CameraSource.objects.using('mssql').create(
193+
id=cam['id'],
194+
cam_internetname=cam['cam_internetname'],
195+
cam_internetcaption=cam['cam_internetcaption'],
196+
cam_internetcredit=cam['cam_internetcredit'],
197+
cam_internetdbc_mark=cam['cam_internetdbc_mark'],
198+
cam_locationsregion=cam['cam_locationsregion'],
199+
cam_locationshighway=cam['cam_locationshighway'],
200+
cam_controldisabled=cam['cam_controldisabled'],
201+
cam_controldisappear=cam['cam_controldisappear'],
202+
isnew=cam['isnew'],
203+
cam_maintenanceis_on_demand=cam['cam_maintenanceis_on_demand'],
204+
seq=cam['seq']
205+
)
248206

249207
def setUp(self):
250208
super().setUp()
251209
self.client = FeedClient()
252210

253-
@patch('apps.feed.client.httpx.get')
254-
def test_get_webcam_list(self, mock_get):
255-
mock_response = create_mock_response(200, {'webcams': []})
256-
mock_get.return_value = mock_response
257-
258-
result = self.client.get_webcam_list()
259-
self.assertIn('webcams', result)
260-
261-
@patch('apps.feed.client.FeedClient.get_single_feed')
262-
def test_get_webcam(self, mock_get_single):
263-
mock_get_single.return_value = {'id': 123, 'name': 'Test'}
211+
def test_get_webcam_list(self):
212+
fake_cam = MagicMock()
213+
fake_cam.cam_internetname = "TestWebCam New"
214+
with patch("apps.webcam.models.CameraSource.objects.using") as mock_using:
215+
mock_qs = MagicMock()
216+
mock_qs.all.return_value = [fake_cam]
217+
mock_using.return_value = mock_qs
218+
result = self.client.get_webcam_list()
219+
self.assertEqual(len(result), 1)
220+
self.assertEqual(result[0].cam_internetname, "TestWebCam New")
221+
222+
def test_get_webcam_list_exception(self):
223+
with patch("apps.webcam.models.CameraSource.objects.using") as mock_using:
224+
mock_using.side_effect = Exception("DB error")
264225

265-
class MockWebcam:
266-
id = 123
226+
result = self.client.get_webcam_list()
267227

268-
result = self.client.get_webcam(MockWebcam())
269-
self.assertEqual(result, {'id': 123, 'name': 'Test'})
228+
assert result == []
229+
270230

271231

272232
class TestFeedClientEvent(BaseTest):
@@ -324,15 +284,6 @@ def setUp(self):
324284
super().setUp()
325285
self.client = FeedClient()
326286

327-
@patch('apps.feed.client.httpx.get')
328-
def test_get_list_feed_empty_response(self, mock_get):
329-
from apps.feed.serializers import WebcamAPISerializer
330-
331-
mock_response = create_mock_response(200, {'webcams': []})
332-
mock_get.return_value = mock_response
333-
334-
result = self.client.get_list_feed(WEBCAM, 'webcams', WebcamAPISerializer)
335-
self.assertIn('webcams', result)
336287

337288

338289
class TestFeedClientFerry(BaseTest):

src/backend/apps/webcam/enums.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22
CAMERA_DIFF_FIELDS = [
33
'name',
44
'caption',
5-
'last_update_modified',
65
'is_on',
76
'should_appear',
8-
'marked_stale',
9-
'marked_delayed',
107
]
8+
9+
CAMERA_FIELD_MAPPING = {
10+
'name': 'cam_internetname',
11+
'caption': 'cam_internetcaption',
12+
'is_on': 'isOn',
13+
'should_appear': 'should_appear',
14+
}

src/backend/apps/webcam/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ class CameraSource(models.Model):
161161
cam_locationsupdated_by = models.CharField(max_length=255, blank=True, null=True)
162162
cam_locationslast_updated = models.DateTimeField(blank=True, null=True)
163163
cam_controldisabled = models.BooleanField(default=False)
164+
cam_controldisappear = models.BooleanField(default=False)
164165
isnew = models.BooleanField(default=False)
165166
cam_maintenanceis_on_demand = models.BooleanField(default=False)
166167
seq = models.IntegerField(blank=True, null=True)

src/backend/apps/webcam/serializers.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,12 @@ def get_caption(self, obj):
3939

4040
def get_links(self, obj):
4141
local_root = settings.DRIVEBC_IMAGE_BASE_URL
42-
proxy_root = settings.DRIVEBC_IMAGE_PROXY_URL
4342
webcam_id = obj.id
4443

4544
timestamp = int(time.time())
46-
if obj.https_cam:
47-
links = {
45+
links = {
4846
"imageDisplay": f"{local_root}images/{webcam_id}.jpg?t={timestamp}",
49-
"replayTheDay": f"{local_root}api/webcams/{webcam_id}/replayTheDay/",
50-
}
51-
52-
else:
53-
links = {
54-
"imageDisplay": f"{local_root}images/{webcam_id}.jpg",
55-
"replayTheDay": f"{proxy_root}ReplayTheDay/json/{webcam_id}.json",
47+
"replayTheDay": f"{local_root}api/webcams/{webcam_id}/replayTheDay/",
5648
}
5749

5850
return links

0 commit comments

Comments
 (0)