feat: add stickers

This commit is contained in:
Krispire Admin
2026-08-30 02:18:53 +05:30
parent cee2d3c874
commit fecb9bc045
15 changed files with 752 additions and 6 deletions
+14
View File
@@ -0,0 +1,14 @@
DELETE FROM message_attachments WHERE kind = 'sticker';
ALTER TABLE message_attachments DROP CONSTRAINT IF EXISTS message_attachments_kind_check;
ALTER TABLE message_attachments
ADD CONSTRAINT message_attachments_kind_check
CHECK (kind IN ('image', 'video', 'audio', 'file', 'link', 'entity', 'quote'));
ALTER TABLE message_attachments DROP CONSTRAINT IF EXISTS message_attachments_entity_type_check;
ALTER TABLE message_attachments
ADD CONSTRAINT message_attachments_entity_type_check
CHECK (entity_type IS NULL OR
entity_type IN ('post', 'comment', 'profile', 'collection'));
DROP TABLE IF EXISTS saved_stickers;
+43
View File
@@ -0,0 +1,43 @@
-- Stickers in chat.
--
-- A sticker IS a sādhana reward — same catalog, same artwork — so there is no
-- separate sticker table. What's new is a second way to come by one: someone
-- sends you theirs and you keep it.
--
-- saved_stickers records only that second route. A reward you earned is
-- already yours through sadhna_reward_grants, and duplicating it here would
-- give two answers to "do I own this?".
CREATE TABLE IF NOT EXISTS saved_stickers (
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
reward_id UUID NOT NULL REFERENCES sadhna_rewards(id) ON DELETE CASCADE,
-- Who sent it. Kept for provenance, and SET NULL rather than CASCADE so
-- deleting an account doesn't take away stickers other people saved.
saved_from UUID REFERENCES users(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (user_id, reward_id)
);
-- "What's in my sticker drawer?" — the whole reason this table exists.
CREATE INDEX IF NOT EXISTS saved_stickers_user_idx
ON saved_stickers (user_id, created_at DESC);
-- A sticker message: kind 'sticker', with the artwork denormalized onto the
-- attachment's existing image_url/title columns.
--
-- Denormalized rather than resolved per read, unlike a shared post: the
-- catalog is static art with no viewer-dependent visibility, so there is
-- nothing to re-check and a join on every message would buy nothing.
ALTER TABLE message_attachments DROP CONSTRAINT IF EXISTS message_attachments_kind_check;
ALTER TABLE message_attachments
ADD CONSTRAINT message_attachments_kind_check
CHECK (kind IN ('image', 'video', 'audio', 'file', 'link', 'entity', 'quote', 'sticker'));
-- entity_id carries the reward key on a sticker attachment, so a recipient can
-- save it without the client having to trust a URL it was handed.
ALTER TABLE message_attachments DROP CONSTRAINT IF EXISTS message_attachments_entity_type_check;
ALTER TABLE message_attachments
ADD CONSTRAINT message_attachments_entity_type_check
CHECK (entity_type IS NULL OR
entity_type IN ('post', 'comment', 'profile', 'collection', 'sticker'));
+12
View File
@@ -0,0 +1,12 @@
DELETE FROM sadhna_reward_grants WHERE source = 'gift';
DROP INDEX IF EXISTS sadhna_reward_grants_unopened_idx;
DROP INDEX IF EXISTS sadhna_reward_grants_gift_uniq;
DROP INDEX IF EXISTS sadhna_reward_grants_streak_uniq;
ALTER TABLE sadhna_reward_grants ALTER COLUMN milestone SET NOT NULL;
ALTER TABLE sadhna_reward_grants
ADD CONSTRAINT sadhna_reward_grants_user_id_milestone_key UNIQUE (user_id, milestone);
ALTER TABLE sadhna_reward_grants DROP CONSTRAINT IF EXISTS sadhna_reward_grants_source_check;
ALTER TABLE sadhna_reward_grants DROP COLUMN IF EXISTS source;
+41
View File
@@ -0,0 +1,41 @@
-- Occasional gift rewards, granted from the admin panel.
--
-- A gift IS a reward grant — same catalog, same gallery, same vault — so it
-- reuses sadhna_reward_grants rather than introducing a parallel table that
-- every reader would then have to union in. What differs is only where it came
-- from, which `source` records.
--
-- `celebrated_at` already means "the devotee has seen this", which is exactly
-- the claim flag a gift needs: unclaimed gifts render blurred, and dismissing
-- the celebration is what clears them.
ALTER TABLE sadhna_reward_grants
ADD COLUMN IF NOT EXISTS source VARCHAR(8) NOT NULL DEFAULT 'streak';
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'sadhna_reward_grants_source_check') THEN
ALTER TABLE sadhna_reward_grants
ADD CONSTRAINT sadhna_reward_grants_source_check
CHECK (source IN ('streak', 'gift'));
END IF;
END $$;
-- A gift is not tied to a streak day, so it has no milestone.
ALTER TABLE sadhna_reward_grants ALTER COLUMN milestone DROP NOT NULL;
-- UNIQUE (user_id, milestone) was the streak rule: one reward per milestone.
-- It can't police gifts, which have no milestone — so it becomes a partial
-- index over streak rows, and gifts get their own rule: one of each reward
-- per person, so re-gifting is idempotent rather than a duplicate tile.
ALTER TABLE sadhna_reward_grants
DROP CONSTRAINT IF EXISTS sadhna_reward_grants_user_id_milestone_key;
CREATE UNIQUE INDEX IF NOT EXISTS sadhna_reward_grants_streak_uniq
ON sadhna_reward_grants (user_id, milestone) WHERE source = 'streak';
CREATE UNIQUE INDEX IF NOT EXISTS sadhna_reward_grants_gift_uniq
ON sadhna_reward_grants (user_id, reward_id) WHERE source = 'gift';
-- "Which gifts is this devotee still to open?" — the blurred tiles.
CREATE INDEX IF NOT EXISTS sadhna_reward_grants_unopened_idx
ON sadhna_reward_grants (user_id) WHERE celebrated_at IS NULL;