262 lines
No EOL
9.2 KiB
PL/PgSQL
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; |