86 lines
2.9 KiB
PL/PgSQL
86 lines
2.9 KiB
PL/PgSQL
-- Live position tracking for whereabouts map
|
|
CREATE TABLE IF NOT EXISTS live_positions (
|
|
user_id uuid PRIMARY KEY REFERENCES auth.users(id),
|
|
lat double precision NOT NULL,
|
|
lng double precision NOT NULL,
|
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
in_premise boolean NOT NULL DEFAULT false
|
|
);
|
|
|
|
-- Enable realtime
|
|
ALTER PUBLICATION supabase_realtime ADD TABLE live_positions;
|
|
|
|
-- RLS
|
|
ALTER TABLE live_positions ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- All authenticated users can read live positions
|
|
CREATE POLICY "live_positions_select" ON live_positions FOR SELECT TO authenticated
|
|
USING (true);
|
|
|
|
-- Users can only upsert their own position
|
|
CREATE POLICY "live_positions_insert" ON live_positions FOR INSERT TO authenticated
|
|
WITH CHECK (user_id = auth.uid());
|
|
|
|
CREATE POLICY "live_positions_update" ON live_positions FOR UPDATE TO authenticated
|
|
USING (user_id = auth.uid());
|
|
|
|
-- RPC: update_live_position — upserts position, computes in_premise via geofence
|
|
CREATE OR REPLACE FUNCTION public.update_live_position(
|
|
p_lat double precision,
|
|
p_lng double precision
|
|
) RETURNS boolean
|
|
LANGUAGE plpgsql SECURITY DEFINER
|
|
AS $$
|
|
DECLARE
|
|
v_geofence jsonb;
|
|
v_in_premise boolean := false;
|
|
v_polygon jsonb;
|
|
v_point_count int;
|
|
v_i int;
|
|
v_j int;
|
|
v_xi double precision;
|
|
v_yi double precision;
|
|
v_xj double precision;
|
|
v_yj double precision;
|
|
v_inside boolean := false;
|
|
BEGIN
|
|
-- Fetch geofence config
|
|
SELECT value INTO v_geofence FROM app_settings WHERE key = 'geofence';
|
|
|
|
IF v_geofence IS NOT NULL THEN
|
|
v_polygon := COALESCE(v_geofence->'polygon', v_geofence->'points');
|
|
IF v_polygon IS NOT NULL AND jsonb_array_length(v_polygon) > 2 THEN
|
|
-- Ray-casting point-in-polygon
|
|
v_point_count := jsonb_array_length(v_polygon);
|
|
v_j := v_point_count - 1;
|
|
FOR v_i IN 0..(v_point_count - 1) LOOP
|
|
v_xi := (v_polygon->v_i->>'lng')::double precision;
|
|
v_yi := (v_polygon->v_i->>'lat')::double precision;
|
|
v_xj := (v_polygon->v_j->>'lng')::double precision;
|
|
v_yj := (v_polygon->v_j->>'lat')::double precision;
|
|
|
|
IF ((v_yi > p_lat) != (v_yj > p_lat)) AND
|
|
(p_lng < (v_xj - v_xi) * (p_lat - v_yi) / (v_yj - v_yi) + v_xi) THEN
|
|
v_inside := NOT v_inside;
|
|
END IF;
|
|
v_j := v_i;
|
|
END LOOP;
|
|
v_in_premise := v_inside;
|
|
END IF;
|
|
END IF;
|
|
|
|
INSERT INTO live_positions (user_id, lat, lng, updated_at, in_premise)
|
|
VALUES (auth.uid(), p_lat, p_lng, now(), v_in_premise)
|
|
ON CONFLICT (user_id)
|
|
DO UPDATE SET lat = p_lat, lng = p_lng, updated_at = now(), in_premise = v_in_premise;
|
|
|
|
RETURN v_in_premise;
|
|
END;
|
|
$$;
|
|
|
|
-- Update the duty_schedules RLS to allow all authenticated users to SELECT
|
|
-- (previously only admin/dispatcher could see all; now all roles can see all schedules)
|
|
DROP POLICY IF EXISTS "duty_schedules_select" ON duty_schedules;
|
|
CREATE POLICY "duty_schedules_select" ON duty_schedules FOR SELECT TO authenticated
|
|
USING (true);
|