fix: sync StarGift private message references
This commit is contained in:
parent
1a2d03f529
commit
30774f8c39
12 changed files with 580 additions and 15 deletions
|
|
@ -0,0 +1,4 @@
|
|||
-- This migration emits durable per-user edit_message events. Reverting the
|
||||
-- repaired ids or rewinding pts would reintroduce cross-account references and
|
||||
-- create holes in updates.getDifference, so rollback intentionally preserves
|
||||
-- both the corrected snapshots and their update facts.
|
||||
186
deploy/migrations/0124_star_gift_private_box_local_refs.up.sql
Normal file
186
deploy/migrations/0124_star_gift_private_box_local_refs.up.sql
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
-- Private message box ids are account-local. Repair user-owned Star Gift
|
||||
-- service actions that copied the owner's msg_id into both participants'
|
||||
-- message boxes, and publish durable edit_message facts for already-visible
|
||||
-- incorrect projections.
|
||||
|
||||
CREATE TEMP TABLE star_gift_box_media_repairs (
|
||||
owner_user_id bigint NOT NULL,
|
||||
box_id integer NOT NULL,
|
||||
peer_type text NOT NULL,
|
||||
peer_id bigint NOT NULL,
|
||||
repaired_media jsonb NOT NULL,
|
||||
PRIMARY KEY (owner_user_id, box_id)
|
||||
) ON COMMIT DROP;
|
||||
|
||||
-- An upgrade action points back to the original ordinary gift. user saved_id
|
||||
-- is a management identity, not a conversation message link: only the current
|
||||
-- gift owner's box may carry it. The other participant must omit the field.
|
||||
INSERT INTO star_gift_box_media_repairs (
|
||||
owner_user_id, box_id, peer_type, peer_id, repaired_media
|
||||
)
|
||||
SELECT unique_box.owner_user_id,
|
||||
unique_box.box_id,
|
||||
unique_box.peer_type,
|
||||
unique_box.peer_id,
|
||||
CASE
|
||||
WHEN unique_box.owner_user_id = gift.owner_peer_id THEN jsonb_set(
|
||||
unique_box.media,
|
||||
'{service_action,star_gift_unique,saved_id}',
|
||||
to_jsonb(gift.msg_id::bigint),
|
||||
true
|
||||
)
|
||||
ELSE unique_box.media #- '{service_action,star_gift_unique,saved_id}'
|
||||
END
|
||||
FROM peer_star_gifts gift
|
||||
JOIN message_boxes upgrade_owner
|
||||
ON upgrade_owner.owner_user_id = gift.owner_peer_id
|
||||
AND upgrade_owner.box_id = gift.upgrade_msg_id
|
||||
JOIN message_boxes unique_box
|
||||
ON unique_box.message_sender_id = upgrade_owner.message_sender_id
|
||||
AND unique_box.private_message_id = upgrade_owner.private_message_id
|
||||
WHERE gift.owner_peer_type = 'user'
|
||||
AND gift.unique_gift_id IS NOT NULL
|
||||
AND gift.msg_id > 0
|
||||
AND gift.upgrade_msg_id > 0
|
||||
AND NOT unique_box.deleted
|
||||
AND unique_box.media #>> '{service_action,kind}' = 'star_gift_unique'
|
||||
AND unique_box.media #>> '{service_action,star_gift_unique,upgrade}' = 'true'
|
||||
AND unique_box.media IS DISTINCT FROM CASE
|
||||
WHEN unique_box.owner_user_id = gift.owner_peer_id THEN jsonb_set(
|
||||
unique_box.media,
|
||||
'{service_action,star_gift_unique,saved_id}',
|
||||
to_jsonb(gift.msg_id::bigint),
|
||||
true
|
||||
)
|
||||
ELSE unique_box.media #- '{service_action,star_gift_unique,saved_id}'
|
||||
END
|
||||
ON CONFLICT (owner_user_id, box_id) DO UPDATE
|
||||
SET repaired_media = EXCLUDED.repaired_media;
|
||||
|
||||
-- For every other user-target unique action (transfer, resale, offer accept,
|
||||
-- craft), the action message itself is the new user saved-gift identity.
|
||||
-- saved_id is a channel-only field there and must be absent from every box.
|
||||
INSERT INTO star_gift_box_media_repairs (
|
||||
owner_user_id, box_id, peer_type, peer_id, repaired_media
|
||||
)
|
||||
SELECT box.owner_user_id,
|
||||
box.box_id,
|
||||
box.peer_type,
|
||||
box.peer_id,
|
||||
box.media #- '{service_action,star_gift_unique,saved_id}'
|
||||
FROM message_boxes box
|
||||
WHERE NOT box.deleted
|
||||
AND box.media #>> '{service_action,kind}' = 'star_gift_unique'
|
||||
AND box.media #>> '{service_action,star_gift_unique,peer,Type}' = 'user'
|
||||
AND COALESCE((box.media #>> '{service_action,star_gift_unique,upgrade}')::boolean, false) = false
|
||||
AND box.media #> '{service_action,star_gift_unique,saved_id}' IS NOT NULL
|
||||
ON CONFLICT (owner_user_id, box_id) DO UPDATE
|
||||
SET repaired_media = EXCLUDED.repaired_media;
|
||||
|
||||
-- A separate prepaid-upgrade action points to the same ordinary gift.
|
||||
-- Telegram defines gift_msg_id as receiver-only, so retain it only in the
|
||||
-- owner's service-message box and remove it from the payer's outgoing copy.
|
||||
INSERT INTO star_gift_box_media_repairs (
|
||||
owner_user_id, box_id, peer_type, peer_id, repaired_media
|
||||
)
|
||||
SELECT prepay_box.owner_user_id,
|
||||
prepay_box.box_id,
|
||||
prepay_box.peer_type,
|
||||
prepay_box.peer_id,
|
||||
CASE
|
||||
WHEN prepay_box.owner_user_id = gift.owner_peer_id THEN jsonb_set(
|
||||
prepay_box.media,
|
||||
'{service_action,star_gift,gift_msg_id}',
|
||||
to_jsonb(gift.msg_id::bigint),
|
||||
true
|
||||
)
|
||||
ELSE prepay_box.media #- '{service_action,star_gift,gift_msg_id}'
|
||||
END
|
||||
FROM peer_star_gifts gift
|
||||
JOIN message_boxes prepay_owner
|
||||
ON prepay_owner.owner_user_id = gift.owner_peer_id
|
||||
AND prepay_owner.media #>> '{service_action,kind}' = 'star_gift'
|
||||
AND prepay_owner.media #>> '{service_action,star_gift,prepaid_upgrade}' = 'true'
|
||||
AND prepay_owner.media #>> '{service_action,star_gift,upgrade_separate}' = 'true'
|
||||
AND (prepay_owner.media #>> '{service_action,star_gift,gift_msg_id}')::integer = gift.msg_id
|
||||
AND (prepay_owner.media #>> '{service_action,star_gift,gift_id}')::bigint = gift.gift_id
|
||||
JOIN message_boxes prepay_box
|
||||
ON prepay_box.message_sender_id = prepay_owner.message_sender_id
|
||||
AND prepay_box.private_message_id = prepay_owner.private_message_id
|
||||
WHERE gift.owner_peer_type = 'user'
|
||||
AND gift.msg_id > 0
|
||||
AND NOT prepay_box.deleted
|
||||
AND prepay_box.media IS DISTINCT FROM CASE
|
||||
WHEN prepay_box.owner_user_id = gift.owner_peer_id THEN jsonb_set(
|
||||
prepay_box.media,
|
||||
'{service_action,star_gift,gift_msg_id}',
|
||||
to_jsonb(gift.msg_id::bigint),
|
||||
true
|
||||
)
|
||||
ELSE prepay_box.media #- '{service_action,star_gift,gift_msg_id}'
|
||||
END
|
||||
ON CONFLICT (owner_user_id, box_id) DO UPDATE
|
||||
SET repaired_media = EXCLUDED.repaired_media;
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
repair record;
|
||||
next_pts integer;
|
||||
event_date integer := EXTRACT(EPOCH FROM clock_timestamp())::integer;
|
||||
BEGIN
|
||||
FOR repair IN
|
||||
SELECT owner_user_id, box_id, peer_type, peer_id, repaired_media
|
||||
FROM star_gift_box_media_repairs
|
||||
ORDER BY owner_user_id, box_id
|
||||
LOOP
|
||||
INSERT INTO user_update_watermarks (user_id, contiguous_pts)
|
||||
VALUES (repair.owner_user_id, 0)
|
||||
ON CONFLICT (user_id) DO NOTHING;
|
||||
|
||||
UPDATE user_update_watermarks
|
||||
SET contiguous_pts = contiguous_pts + 1,
|
||||
updated_at = now()
|
||||
WHERE user_id = repair.owner_user_id
|
||||
RETURNING contiguous_pts INTO next_pts;
|
||||
|
||||
UPDATE message_boxes
|
||||
SET media = repair.repaired_media,
|
||||
pts = next_pts
|
||||
WHERE owner_user_id = repair.owner_user_id
|
||||
AND box_id = repair.box_id
|
||||
AND NOT deleted;
|
||||
|
||||
INSERT INTO user_update_events (
|
||||
user_id, pts, pts_count, date, event_type,
|
||||
message_box_id, peer_type, peer_id
|
||||
) VALUES (
|
||||
repair.owner_user_id, next_pts, 1, event_date, 'edit_message',
|
||||
repair.box_id, repair.peer_type, repair.peer_id
|
||||
);
|
||||
|
||||
INSERT INTO dispatch_outbox (
|
||||
target_user_id, pts, event_type,
|
||||
exclude_auth_key_id, exclude_session_id
|
||||
) VALUES (repair.owner_user_id, next_pts, 'edit_message', 0, 0);
|
||||
END LOOP;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- private_messages is the logical shared envelope and cannot contain either
|
||||
-- participant's local message id. User-visible history/difference always reads
|
||||
-- the per-owner message_boxes snapshots repaired above.
|
||||
UPDATE private_messages
|
||||
SET media = media
|
||||
#- '{service_action,star_gift,saved_id}'
|
||||
#- '{service_action,star_gift,gift_msg_id}'
|
||||
#- '{service_action,star_gift,upgrade_msg_id}'
|
||||
WHERE media #>> '{service_action,kind}' = 'star_gift'
|
||||
AND (
|
||||
media #> '{service_action,star_gift,peer_user_id}' IS NOT NULL
|
||||
OR media #>> '{service_action,star_gift,to,Type}' = 'user'
|
||||
);
|
||||
|
||||
UPDATE private_messages
|
||||
SET media = media #- '{service_action,star_gift_unique,saved_id}'
|
||||
WHERE media #>> '{service_action,kind}' = 'star_gift_unique'
|
||||
AND media #>> '{service_action,star_gift_unique,peer,Type}' = 'user';
|
||||
Loading…
Add table
Add a link
Reference in a new issue