183 lines
6.9 KiB
SQL
183 lines
6.9 KiB
SQL
-- inputInvoiceStarGiftPrepaidUpgrade is for prepaying someone else's gift:
|
|
-- its peer is the gift owner. Earlier user-gift purchases copied both
|
|
-- receiver-only can_upgrade and non-owner prepaid_upgrade_hash into both
|
|
-- private message boxes. DrKLO therefore preferred the prepaid invoice on the
|
|
-- owner's incoming card and substituted the private dialog peer (the sender),
|
|
-- which correctly failed STARGIFT_INVALID.
|
|
--
|
|
-- Repair both viewer projections and publish a real account-scoped edit for
|
|
-- every changed box. The saved-gift aggregate and its owner/hash remain intact;
|
|
-- only the wire capability surface changes.
|
|
|
|
LOCK TABLE public.peer_star_gifts, public.message_boxes,
|
|
public.private_messages IN SHARE ROW EXCLUSIVE MODE;
|
|
|
|
CREATE TEMP TABLE star_gift_prepaid_viewer_sources ON COMMIT DROP AS
|
|
SELECT gift.id AS saved_gift_id,
|
|
gift.owner_peer_id AS owner_user_id,
|
|
gift.from_user_id AS sender_user_id,
|
|
gift.msg_id AS owner_box_id,
|
|
gift.gift_id,
|
|
gift.prepaid_upgrade_hash,
|
|
owner_box.message_sender_id,
|
|
owner_box.private_message_id
|
|
FROM public.peer_star_gifts gift
|
|
JOIN public.message_boxes owner_box
|
|
ON owner_box.owner_user_id = gift.owner_peer_id
|
|
AND owner_box.box_id = gift.msg_id
|
|
AND NOT owner_box.deleted
|
|
WHERE gift.owner_peer_type = 'user'
|
|
AND gift.lifecycle_status = 'active'
|
|
AND gift.unique_gift_id IS NULL
|
|
AND gift.prepaid_upgrade_stars = 0
|
|
AND gift.prepaid_upgrade_hash <> '';
|
|
|
|
DO $$
|
|
BEGIN
|
|
IF EXISTS (
|
|
SELECT 1
|
|
FROM public.peer_star_gifts gift
|
|
WHERE gift.owner_peer_type = 'user'
|
|
AND gift.lifecycle_status = 'active'
|
|
AND gift.unique_gift_id IS NULL
|
|
AND gift.prepaid_upgrade_stars = 0
|
|
AND gift.prepaid_upgrade_hash <> ''
|
|
AND NOT EXISTS (
|
|
SELECT 1
|
|
FROM star_gift_prepaid_viewer_sources source
|
|
WHERE source.saved_gift_id = gift.id
|
|
)
|
|
) THEN
|
|
RAISE EXCEPTION 'active user prepaid-upgrade entitlement is missing its owner message box';
|
|
END IF;
|
|
|
|
IF EXISTS (
|
|
SELECT 1
|
|
FROM star_gift_prepaid_viewer_sources source
|
|
JOIN public.message_boxes box
|
|
ON box.message_sender_id = source.message_sender_id
|
|
AND box.private_message_id = source.private_message_id
|
|
AND NOT box.deleted
|
|
WHERE box.owner_user_id NOT IN (source.owner_user_id, source.sender_user_id)
|
|
OR box.media #>> '{service_action,kind}' IS DISTINCT FROM 'star_gift'
|
|
OR box.media #>> '{service_action,star_gift,gift_id}' IS DISTINCT FROM source.gift_id::text
|
|
) THEN
|
|
RAISE EXCEPTION 'ordinary star gift private projections disagree with the saved aggregate';
|
|
END IF;
|
|
END
|
|
$$;
|
|
|
|
CREATE TEMP TABLE star_gift_prepaid_viewer_repairs (
|
|
owner_user_id bigint NOT NULL,
|
|
box_id integer NOT NULL,
|
|
peer_type text NOT NULL,
|
|
peer_id bigint NOT NULL,
|
|
message_sender_id bigint NOT NULL,
|
|
private_message_id bigint NOT NULL,
|
|
repaired_media jsonb NOT NULL,
|
|
PRIMARY KEY (owner_user_id, box_id)
|
|
) ON COMMIT DROP;
|
|
|
|
INSERT INTO star_gift_prepaid_viewer_repairs(
|
|
owner_user_id, box_id, peer_type, peer_id,
|
|
message_sender_id, private_message_id, repaired_media
|
|
)
|
|
SELECT box.owner_user_id,
|
|
box.box_id,
|
|
box.peer_type,
|
|
box.peer_id,
|
|
box.message_sender_id,
|
|
box.private_message_id,
|
|
CASE
|
|
WHEN box.owner_user_id = source.owner_user_id THEN
|
|
box.media #- '{service_action,star_gift,prepaid_upgrade_hash}'
|
|
ELSE
|
|
box.media #- '{service_action,star_gift,can_upgrade}'
|
|
END
|
|
FROM star_gift_prepaid_viewer_sources source
|
|
JOIN public.message_boxes box
|
|
ON box.message_sender_id = source.message_sender_id
|
|
AND box.private_message_id = source.private_message_id
|
|
AND NOT box.deleted
|
|
WHERE box.owner_user_id IN (source.owner_user_id, source.sender_user_id)
|
|
AND box.media IS DISTINCT FROM CASE
|
|
WHEN box.owner_user_id = source.owner_user_id THEN
|
|
box.media #- '{service_action,star_gift,prepaid_upgrade_hash}'
|
|
ELSE
|
|
box.media #- '{service_action,star_gift,can_upgrade}'
|
|
END;
|
|
|
|
DO $$
|
|
DECLARE
|
|
repair_row record;
|
|
next_pts integer;
|
|
event_date integer := EXTRACT(EPOCH FROM clock_timestamp())::integer;
|
|
BEGIN
|
|
FOR repair_row IN
|
|
SELECT owner_user_id, box_id, peer_type, peer_id, repaired_media
|
|
FROM star_gift_prepaid_viewer_repairs
|
|
ORDER BY owner_user_id, box_id
|
|
LOOP
|
|
INSERT INTO public.user_update_watermarks(user_id, contiguous_pts)
|
|
VALUES(repair_row.owner_user_id, 0)
|
|
ON CONFLICT(user_id) DO NOTHING;
|
|
|
|
UPDATE public.user_update_watermarks
|
|
SET contiguous_pts = contiguous_pts + 1,
|
|
updated_at = now()
|
|
WHERE user_id = repair_row.owner_user_id
|
|
RETURNING contiguous_pts INTO next_pts;
|
|
|
|
UPDATE public.message_boxes
|
|
SET media = repair_row.repaired_media,
|
|
pts = next_pts
|
|
WHERE owner_user_id = repair_row.owner_user_id
|
|
AND box_id = repair_row.box_id
|
|
AND NOT deleted;
|
|
|
|
INSERT INTO public.user_update_events(
|
|
user_id, pts, pts_count, date, event_type,
|
|
message_box_id, peer_type, peer_id
|
|
) VALUES (
|
|
repair_row.owner_user_id, next_pts, 1, event_date, 'edit_message',
|
|
repair_row.box_id, repair_row.peer_type, repair_row.peer_id
|
|
);
|
|
|
|
INSERT INTO public.dispatch_outbox(
|
|
target_user_id, pts, event_type,
|
|
exclude_auth_key_id, exclude_session_id
|
|
) VALUES(repair_row.owner_user_id, next_pts, 'edit_message', 0, 0);
|
|
END LOOP;
|
|
END
|
|
$$;
|
|
|
|
-- A shared private-message envelope is not a viewer projection. Keep neither
|
|
-- the owner-only nor non-owner-only capability there; both durable boxes above
|
|
-- remain authoritative for replay and history.
|
|
UPDATE public.private_messages private_message
|
|
SET media = private_message.media
|
|
#- '{service_action,star_gift,prepaid_upgrade_hash}'
|
|
#- '{service_action,star_gift,can_upgrade}'
|
|
FROM star_gift_prepaid_viewer_sources source
|
|
WHERE private_message.sender_user_id = source.message_sender_id
|
|
AND private_message.id = source.private_message_id;
|
|
|
|
DO $$
|
|
BEGIN
|
|
IF EXISTS (
|
|
SELECT 1
|
|
FROM star_gift_prepaid_viewer_sources source
|
|
JOIN public.message_boxes box
|
|
ON box.message_sender_id = source.message_sender_id
|
|
AND box.private_message_id = source.private_message_id
|
|
AND NOT box.deleted
|
|
WHERE (box.owner_user_id = source.owner_user_id AND
|
|
box.media #> '{service_action,star_gift,prepaid_upgrade_hash}' IS NOT NULL)
|
|
OR (box.owner_user_id = source.sender_user_id AND
|
|
box.owner_user_id <> source.owner_user_id AND
|
|
box.media #> '{service_action,star_gift,can_upgrade}' IS NOT NULL)
|
|
) THEN
|
|
RAISE EXCEPTION 'star gift prepaid viewer projection repair did not converge';
|
|
END IF;
|
|
END
|
|
$$;
|