diff --git a/itassets/middleware.py b/itassets/middleware.py
index d8730da2..4dbbbf29 100644
--- a/itassets/middleware.py
+++ b/itassets/middleware.py
@@ -2,8 +2,11 @@
from django.http import HttpResponse, HttpResponseServerError
-class HealthCheckMiddleware(object):
+class HealthCheckMiddleware:
"""Middleware to provide healthcheck HTTP endpoints for the system.
+ Should be placed at the top of the MIDDLEWARE list so that requests
+ to healthcheck endpoints short-circuit and return a response without
+ passing through further middleware classes.
"""
def __init__(self, get_response):
@@ -18,8 +21,7 @@ def __call__(self, request):
return self.get_response(request)
def liveness(self, request):
- """Returns that the server is alive and able to serve HTTP responses.
- """
+ """Returns that the server is alive and able to serve HTTP responses."""
return HttpResponse("OK")
def readiness(self, request):
diff --git a/itassets/settings.py b/itassets/settings.py
index e3bb49aa..20bd2534 100644
--- a/itassets/settings.py
+++ b/itassets/settings.py
@@ -67,10 +67,12 @@
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
+ "django.middleware.cache.UpdateCacheMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
+ "django.middleware.cache.FetchFromCacheMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"dbca_utils.middleware.SSOLoginMiddleware",
]
@@ -110,7 +112,14 @@
"LOCATION": REDIS_CACHE_HOST,
}
}
+else:
+ CACHES = {
+ "default": {
+ "BACKEND": "django.core.cache.backends.dummy.DummyCache",
+ }
+ }
API_RESPONSE_CACHE_SECONDS = env("API_RESPONSE_CACHE_SECONDS", 60)
+CACHE_MIDDLEWARE_SECONDS = env("CACHE_MIDDLEWARE_SECONDS", 60)
ADMIN_EMAILS = env("ADMIN_EMAILS", "asi@dbca.wa.gov.au").split(",")
SERVICE_DESK_EMAIL = env("SERVICE_DESK_EMAIL", "oim.servicedesk@dbca.wa.gov.au")
diff --git a/kustomize/overlays/prod/cronjobs/deptusers-check-ascender/patch.yaml b/kustomize/overlays/prod/cronjobs/deptusers-check-ascender/patch.yaml
index f76e92a6..2a465c57 100644
--- a/kustomize/overlays/prod/cronjobs/deptusers-check-ascender/patch.yaml
+++ b/kustomize/overlays/prod/cronjobs/deptusers-check-ascender/patch.yaml
@@ -3,8 +3,8 @@ kind: CronJob
metadata:
name: itassets-cronjob
spec:
- # AWST: 10/40 min past the hour, 08:00-19:00, Mon-Fri
- schedule: "10,40 0-10 * * 1-5"
+ # AWST: 10/40 min past the hour, 07:00-19:00, Mon-Fri
+ schedule: "10,40 0-10,23 * * 1-5"
jobTemplate:
spec:
activeDeadlineSeconds: 600
diff --git a/kustomize/overlays/prod/deployment_patch.yaml b/kustomize/overlays/prod/deployment_patch.yaml
index 9396cd91..d381edf4 100644
--- a/kustomize/overlays/prod/deployment_patch.yaml
+++ b/kustomize/overlays/prod/deployment_patch.yaml
@@ -197,3 +197,8 @@ spec:
secretKeyRef:
name: itassets-env-prod
key: REDIS_CACHE_HOST
+ - name: API_RESPONSE_CACHE_SECONDS
+ valueFrom:
+ secretKeyRef:
+ name: itassets-env-prod
+ key: API_RESPONSE_CACHE_SECONDS
diff --git a/kustomize/overlays/prod/kustomization.yaml b/kustomize/overlays/prod/kustomization.yaml
index 4fdfd378..9d92fc59 100644
--- a/kustomize/overlays/prod/kustomization.yaml
+++ b/kustomize/overlays/prod/kustomization.yaml
@@ -35,4 +35,4 @@ patches:
- path: postgres_fdw_service_patch.yaml
images:
- name: ghcr.io/dbca-wa/it-assets
- newTag: 2.4.28
+ newTag: 2.4.29
diff --git a/kustomize/overlays/uat/deployment_patch.yaml b/kustomize/overlays/uat/deployment_patch.yaml
index 1187b2c5..a2d3859d 100644
--- a/kustomize/overlays/uat/deployment_patch.yaml
+++ b/kustomize/overlays/uat/deployment_patch.yaml
@@ -203,3 +203,8 @@ spec:
secretKeyRef:
name: itassets-env-uat
key: REDIS_CACHE_HOST
+ - name: API_RESPONSE_CACHE_SECONDS
+ valueFrom:
+ secretKeyRef:
+ name: itassets-env-uat
+ key: API_RESPONSE_CACHE_SECONDS
diff --git a/organisation/ascender.py b/organisation/ascender.py
index df27dce6..b96aa79c 100644
--- a/organisation/ascender.py
+++ b/organisation/ascender.py
@@ -466,6 +466,7 @@ def ascender_user_import_all():
user.ascender_data = job
user.ascender_data_updated = timezone.localtime()
user.update_from_ascender_data() # This method calls save()
+ LOGGER.info(f"Updated existing user {user}")
elif not DepartmentUser.objects.filter(employee_id=employee_id).exists():
# Ascender record does not exist in our database; conditionally create a new
# Azure AD account and DepartmentUser instance for them.
diff --git a/organisation/static/js/location_map.js b/organisation/static/js/location_map.js
index 02d32c8f..6e8e93c1 100644
--- a/organisation/static/js/location_map.js
+++ b/organisation/static/js/location_map.js
@@ -15,22 +15,61 @@ const mapboxStreets = L.tileLayer(
// Define overlay tile layers.
const dbcaRegions = L.tileLayer(
- geoserver_wmts_url_overlay + "&layer=cddp:dbca_regions",
+ geoserver_wmts_url_overlay + "&layer=cddp:kaartdijin-boodja-public_CPT_DBCA_REGIONS",
{
tileSize: 1024,
zoomOffset: -2,
},
);
const dbcaDistricts = L.tileLayer(
- geoserver_wmts_url_overlay + "&layer=public:dbca_districts_public",
+ geoserver_wmts_url_overlay + "&layer=cddp:kaartdijin-boodja-public_CPT_DBCA_DISTRICTS",
{
tileSize: 1024,
zoomOffset: -2,
},
);
+// Function to define hover effect for location points.
+function locationHover(feature, layer) {
+ layer.bindTooltip(
+ feature.properties.name,
+ { className: "leaflet-tooltip-wide" }
+ );
+ layer.bindPopup(`${feature.properties.name}
+${feature.properties.ascender_desc}
+${feature.properties.phone}`);
+}
+
+// Define a clustered layer for DBCA locations, and a GeoJSON layer to contain the data.
+const locationsClustered = L.markerClusterGroup();
+const dbcaLocations = L.geoJSON(
+ null, // Initially empty.
+ {
+ onEachFeature: locationHover
+ },
+);
+
+// Function to get location data and populate the layer.
+function queryLocationsData() {
+ $.ajax({
+ dataType: "json",
+ url: location_features_url,
+ data: { format: "geojson" },
+ success: function (data) {
+ // Add the device data to the GeoJSON layer.
+ dbcaLocations.addData(data);
+ // Add DBCA locations layer to the map display and zoom to their bounds.
+ locationsClustered.addLayer(dbcaLocations);
+ map.addLayer(locationsClustered);
+ map.fitBounds(dbcaLocations.getBounds());
+ },
+ });
+};
+// Immediately run the function once to get data.
+queryLocationsData();
+
// Define map.
-const map = L.map('map', {
+const map = L.map("map", {
crs: L.CRS.EPSG4326, // WGS 84
center: [-31.96, 115.87],
minZoom: 4,
@@ -54,26 +93,11 @@ L.control.layers(baseMaps, overlayMaps).addTo(map);
// Define scale bar
L.control.scale({ maxWidth: 500, imperial: false }).addTo(map);
-// Function to define hover effect for location points.
-function locationHover(feature, layer) {
- layer.bindTooltip(
- feature.properties.name,
- { className: 'leaflet-tooltip-wide' }
- );
- layer.bindPopup(`
-${feature.properties.name}
-${feature.properties.ascender_desc}
-${feature.properties.phone}`);
-}
-
-// Add locations to the map display and zoom to their bounds.
-const locationsLayer = L.geoJson(locationFeatures, {
- onEachFeature: locationHover
+// Move the map div inside the #locations-tab-pane div and redraw it.
+// https://stackoverflow.com/a/63319084/14508
+const mapDiv = document.getElementById("map");
+const mapResizeObserver = new ResizeObserver(() => {
+ map.invalidateSize();
});
-const locations = L.markerClusterGroup();
-locations.addLayer(locationsLayer);
-map.addLayer(locations);
-map.fitBounds(locations.getBounds());
-
-// Move the map div inside the #locations-tab-pane div.
-document.getElementById("locations-tab-pane").appendChild(document.getElementById("map"));
+document.getElementById("locations-tab-pane").appendChild(mapDiv);
+mapResizeObserver.observe(mapDiv);
diff --git a/organisation/templates/organisation/address_book.html b/organisation/templates/organisation/address_book.html
index 72990344..3415b843 100644
--- a/organisation/templates/organisation/address_book.html
+++ b/organisation/templates/organisation/address_book.html
@@ -31,6 +31,14 @@