owpengram-server/deploy/migrations/20260901000022_channel_active_monoforum_invalidation.up.sql
2026-09-01 12:06:31 +03:00

194 lines
6 KiB
PL/PgSQL

-- Extend the owner-scoped channel_active_memberships generation to every
-- durable predicate used by ListActiveChannelIDsForUser. Ordinary memberships
-- are covered by user_channel_member_index; these triggers cover monoforum
-- subscriber message visibility, manager rights, and parent/mono enablement.
CREATE OR REPLACE FUNCTION public.telesrv_bump_channel_active_membership_owner(p_user_id bigint)
RETURNS void
LANGUAGE plpgsql
AS $$
BEGIN
IF COALESCE(p_user_id, 0) <= 0 THEN
RETURN;
END IF;
PERFORM public.telesrv_bump_read_model_version(
'channel_active_memberships', p_user_id, 'user', p_user_id
);
END;
$$;
CREATE OR REPLACE FUNCTION public.telesrv_notify_monoforum_message_visibility_read_model()
RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
old_owner bigint := 0;
new_owner bigint := 0;
BEGIN
IF TG_OP <> 'INSERT'
AND OLD.saved_peer_type = 'user'
AND OLD.saved_peer_id > 0
AND NOT OLD.deleted
THEN
old_owner := OLD.saved_peer_id;
END IF;
IF TG_OP <> 'DELETE'
AND NEW.saved_peer_type = 'user'
AND NEW.saved_peer_id > 0
AND NOT NEW.deleted
THEN
new_owner := NEW.saved_peer_id;
END IF;
IF old_owner > 0 THEN
PERFORM public.telesrv_bump_channel_active_membership_owner(old_owner);
END IF;
IF new_owner > 0 AND new_owner IS DISTINCT FROM old_owner THEN
PERFORM public.telesrv_bump_channel_active_membership_owner(new_owner);
END IF;
RETURN NULL;
END;
$$;
CREATE TRIGGER channel_messages_monoforum_active_membership_changed
AFTER INSERT OR DELETE OR UPDATE OF channel_id, saved_peer_type, saved_peer_id, deleted
ON public.channel_messages
FOR EACH ROW EXECUTE FUNCTION public.telesrv_notify_monoforum_message_visibility_read_model();
CREATE OR REPLACE FUNCTION public.telesrv_notify_monoforum_manager_visibility_read_model()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF OLD.role IS NOT DISTINCT FROM NEW.role
AND OLD.admin_rights IS NOT DISTINCT FROM NEW.admin_rights
THEN
RETURN NULL;
END IF;
IF EXISTS (
SELECT 1
FROM public.channels AS parent
WHERE parent.id = NEW.channel_id
AND parent.linked_monoforum_id <> 0
AND parent.broadcast_messages_allowed
AND NOT parent.deleted
) THEN
PERFORM public.telesrv_bump_channel_active_membership_owner(NEW.user_id);
END IF;
RETURN NULL;
END;
$$;
CREATE TRIGGER channel_members_monoforum_manager_visibility_changed
AFTER UPDATE OF role, admin_rights ON public.channel_members
FOR EACH ROW EXECUTE FUNCTION public.telesrv_notify_monoforum_manager_visibility_read_model();
CREATE OR REPLACE FUNCTION public.telesrv_bump_monoforum_visibility_owners(
p_parent_id bigint,
p_monoforum_id bigint
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
affected record;
BEGIN
IF COALESCE(p_parent_id, 0) <= 0 OR COALESCE(p_monoforum_id, 0) <= 0 THEN
RETURN;
END IF;
FOR affected IN
SELECT DISTINCT owner_id
FROM (
SELECT member.user_id AS owner_id
FROM public.user_channel_member_index AS member
WHERE member.channel_id = p_parent_id
AND member.status = 'active'
AND NOT member.deleted
AND member.role IN ('creator', 'admin')
UNION
SELECT message.saved_peer_id AS owner_id
FROM public.channel_messages AS message
WHERE message.channel_id = p_monoforum_id
AND message.saved_peer_type = 'user'
AND message.saved_peer_id > 0
AND NOT message.deleted
) AS owners
WHERE owner_id > 0
ORDER BY owner_id
LOOP
PERFORM public.telesrv_bump_channel_active_membership_owner(affected.owner_id);
END LOOP;
END;
$$;
CREATE OR REPLACE FUNCTION public.telesrv_notify_monoforum_channel_visibility_read_model()
RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
old_parent_id bigint := 0;
old_monoforum_id bigint := 0;
new_parent_id bigint := 0;
new_monoforum_id bigint := 0;
BEGIN
IF (OLD.broadcast_messages_allowed, OLD.linked_monoforum_id, OLD.deleted, OLD.monoforum)
IS NOT DISTINCT FROM
(NEW.broadcast_messages_allowed, NEW.linked_monoforum_id, NEW.deleted, NEW.monoforum)
THEN
RETURN NULL;
END IF;
IF OLD.linked_monoforum_id > 0 THEN
IF OLD.monoforum THEN
old_parent_id := OLD.linked_monoforum_id;
old_monoforum_id := OLD.id;
ELSE
old_parent_id := OLD.id;
old_monoforum_id := OLD.linked_monoforum_id;
END IF;
END IF;
IF NEW.linked_monoforum_id > 0 THEN
IF NEW.monoforum THEN
new_parent_id := NEW.linked_monoforum_id;
new_monoforum_id := NEW.id;
ELSE
new_parent_id := NEW.id;
new_monoforum_id := NEW.linked_monoforum_id;
END IF;
END IF;
IF old_parent_id > 0 THEN
PERFORM public.telesrv_bump_monoforum_visibility_owners(old_parent_id, old_monoforum_id);
END IF;
IF new_parent_id > 0
AND (new_parent_id, new_monoforum_id)
IS DISTINCT FROM (old_parent_id, old_monoforum_id)
THEN
PERFORM public.telesrv_bump_monoforum_visibility_owners(new_parent_id, new_monoforum_id);
END IF;
RETURN NULL;
END;
$$;
CREATE TRIGGER channels_monoforum_active_membership_changed
AFTER UPDATE OF broadcast_messages_allowed, linked_monoforum_id, deleted, monoforum
ON public.channels
FOR EACH ROW EXECUTE FUNCTION public.telesrv_notify_monoforum_channel_visibility_read_model();
-- Existing monoforum owners need a fresh generation before any shared page can
-- be populated under the expanded dependency contract.
DO $$
DECLARE
linked record;
BEGIN
FOR linked IN
SELECT parent.id AS parent_id, parent.linked_monoforum_id AS monoforum_id
FROM public.channels AS parent
WHERE parent.linked_monoforum_id > 0
LOOP
PERFORM public.telesrv_bump_monoforum_visibility_owners(
linked.parent_id, linked.monoforum_id
);
END LOOP;
END;
$$;