xtablo-source/supabase/migrations/20251116175557_update_notif_trigger.sql
2025-11-16 20:34:33 +01:00

262 lines
No EOL
9.2 KiB
PL/PgSQL

CREATE OR REPLACE FUNCTION public.notify_users()
RETURNS TRIGGER AS $$
DECLARE
affected_users UUID[];
affected_user UUID;
actor UUID;
action TEXT;
msg TEXT;
meta JSONB;
entity_type_name TEXT;
entity_identifier TEXT;
BEGIN
-- Determine if this is an INSERT or UPDATE
IF TG_OP = 'INSERT' THEN
action := 'created';
ELSE
action := 'updated';
-- Skip if soft delete happened (only for tables with deleted_at column)
IF TG_TABLE_NAME IN ('tablos', 'events', 'notes', 'event_types') THEN
IF NEW.deleted_at IS NOT NULL AND OLD.deleted_at IS NULL THEN
RETURN NEW;
END IF;
END IF;
END IF;
-- Get the actor (current user)
actor := auth.uid();
-- Set entity type and ID based on the table
entity_type_name := TG_TABLE_NAME;
-- Determine entity ID and affected users based on table
CASE TG_TABLE_NAME
WHEN 'tablos' THEN
entity_identifier := NEW.id;
IF TG_OP = 'INSERT' THEN
msg := 'New tablo "' || NEW.name || '" was created';
-- Notify owner (but not if they are the creator)
IF NEW.owner_id != actor THEN
affected_users := ARRAY[NEW.owner_id];
END IF;
ELSE
msg := 'Tablo "' || NEW.name || '" was updated';
-- Notify owner and all collaborators
affected_users := ARRAY(
SELECT DISTINCT user_id
FROM public.tablo_access
WHERE tablo_id = NEW.id
AND is_active = true
AND user_id != actor
UNION
SELECT NEW.owner_id
WHERE NEW.owner_id != actor
);
END IF;
meta := jsonb_build_object(
'tablo_name', NEW.name,
'status', NEW.status,
'color', NEW.color
);
WHEN 'tasks' THEN
entity_identifier := NEW.id;
IF TG_OP = 'INSERT' THEN
msg := 'New task "' || NEW.title || '" was created';
ELSE
IF OLD.status != NEW.status THEN
msg := 'Task "' || NEW.title || '" status changed to ' || NEW.status;
ELSIF OLD.assignee_id != NEW.assignee_id OR (OLD.assignee_id IS NULL AND NEW.assignee_id IS NOT NULL) THEN
msg := 'You were assigned to task "' || NEW.title || '"';
ELSE
msg := 'Task "' || NEW.title || '" was updated';
END IF;
END IF;
-- Notify tablo collaborators and assignee
affected_users := ARRAY(
SELECT DISTINCT user_id
FROM public.tablo_access
WHERE tablo_id = NEW.tablo_id
AND is_active = true
AND user_id != actor
UNION
SELECT t.owner_id
FROM public.tablos t
WHERE t.id = NEW.tablo_id
AND t.owner_id != actor
UNION
SELECT NEW.assignee_id
WHERE NEW.assignee_id IS NOT NULL
AND NEW.assignee_id != actor
);
meta := jsonb_build_object(
'task_title', NEW.title,
'status', NEW.status,
'tablo_id', NEW.tablo_id,
'assignee_id', NEW.assignee_id
);
WHEN 'events' THEN
entity_identifier := NEW.id;
IF TG_OP = 'INSERT' THEN
msg := 'New event "' || NEW.title || '" was created';
ELSE
msg := 'Event "' || NEW.title || '" was updated';
END IF;
-- Notify tablo collaborators
affected_users := ARRAY(
SELECT DISTINCT user_id
FROM public.tablo_access
WHERE tablo_id = NEW.tablo_id
AND is_active = true
AND user_id != actor
UNION
SELECT t.owner_id
FROM public.tablos t
WHERE t.id = NEW.tablo_id
AND t.owner_id != actor
UNION
SELECT NEW.created_by
WHERE NEW.created_by != actor
);
meta := jsonb_build_object(
'event_title', NEW.title,
'start_date', NEW.start_date,
'start_time', NEW.start_time,
'tablo_id', NEW.tablo_id
);
WHEN 'notes' THEN
entity_identifier := NEW.id;
IF TG_OP = 'INSERT' THEN
msg := 'New note "' || NEW.title || '" was created';
ELSE
msg := 'Note "' || NEW.title || '" was updated';
END IF;
-- Notify note owner and users with access
affected_users := ARRAY(
SELECT DISTINCT user_id
FROM public.note_access
WHERE note_id = NEW.id
AND is_active = true
AND user_id != actor
UNION
SELECT NEW.user_id
WHERE NEW.user_id != actor
);
meta := jsonb_build_object(
'note_title', NEW.title,
'note_owner', NEW.user_id
);
WHEN 'tablo_access' THEN
entity_identifier := NEW.id::TEXT;
IF TG_OP = 'INSERT' THEN
msg := 'You were granted access to a tablo';
ELSE
IF OLD.is_admin != NEW.is_admin AND NEW.is_admin = true THEN
msg := 'You were promoted to admin on a tablo';
ELSIF OLD.is_active != NEW.is_active AND NEW.is_active = false THEN
msg := 'Your access to a tablo was revoked';
ELSE
msg := 'Your tablo access was updated';
END IF;
END IF;
-- Notify the user being granted/modified access
IF NEW.user_id != actor THEN
affected_users := ARRAY[NEW.user_id];
END IF;
meta := jsonb_build_object(
'tablo_id', NEW.tablo_id,
'is_admin', NEW.is_admin,
'is_active', NEW.is_active,
'granted_by', NEW.granted_by
);
WHEN 'tablo_invites' THEN
entity_identifier := NEW.id::TEXT;
RAISE LOG 'notify_users: Processing tablo_invites, TG_OP=%, email=%', TG_OP, NEW.invited_email;
IF TG_OP = 'INSERT' THEN
msg := 'You were invited to collaborate on a tablo';
ELSE
IF OLD.is_pending != NEW.is_pending AND NEW.is_pending = false THEN
msg := 'Your tablo invitation status changed';
ELSE
msg := 'Your tablo invitation was updated';
END IF;
END IF;
RAISE LOG 'notify_users: Looking for user with email=%, actor=%', NEW.invited_email, actor;
-- Find the user by email and notify them (case-insensitive)
-- Only notify if user exists in the system
affected_users := ARRAY(
SELECT id
FROM auth.users
WHERE LOWER(email) = LOWER(NEW.invited_email)
AND id != actor
);
RAISE LOG 'notify_users: Found % affected users for invite', COALESCE(array_length(affected_users, 1), 0);
meta := jsonb_build_object(
'tablo_id', NEW.tablo_id,
'invited_email', NEW.invited_email,
'invited_by', NEW.invited_by,
'is_pending', NEW.is_pending
);
ELSE
-- Unknown table, skip
RETURN NEW;
END CASE;
-- Insert notifications for all affected users
RAISE LOG 'notify_users: About to insert notifications for % users, entity_type=%', COALESCE(array_length(affected_users, 1), 0), entity_type_name;
IF affected_users IS NOT NULL AND array_length(affected_users, 1) > 0 THEN
FOREACH affected_user IN ARRAY affected_users
LOOP
RAISE LOG 'notify_users: Inserting notification for user_id=%, entity_type=%, message=%', affected_user, entity_type_name, msg;
INSERT INTO public.notifications (
user_id,
actor_id,
entity_type,
entity_id,
action_type,
message,
metadata
) VALUES (
affected_user,
actor,
entity_type_name,
entity_identifier,
action,
msg,
meta
);
END LOOP;
ELSE
RAISE LOG 'notify_users: No affected users to notify';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;