Files
Sauci/apps/supabase/migrations/20260101114500_add_redemption_codes_permission_rls.sql
T

133 lines
4.7 KiB
PL/PgSQL

-- Redemption codes table
CREATE TABLE redemption_codes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
code TEXT NOT NULL UNIQUE,
description TEXT,
max_uses INTEGER DEFAULT 1,
current_uses INTEGER DEFAULT 0,
expires_at TIMESTAMPTZ,
is_active BOOLEAN DEFAULT true,
created_by UUID REFERENCES auth.users(id),
created_at TIMESTAMPTZ DEFAULT now(),
updated_at TIMESTAMPTZ DEFAULT now()
);
-- Code redemptions table
CREATE TABLE code_redemptions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
code_id UUID NOT NULL REFERENCES redemption_codes(id),
user_id UUID NOT NULL REFERENCES auth.users(id),
redeemed_at TIMESTAMPTZ DEFAULT now(),
UNIQUE(code_id, user_id)
);
ALTER TABLE redemption_codes ENABLE ROW LEVEL SECURITY;
ALTER TABLE code_redemptions ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Admins with manage_codes permission can view redemption codes"
ON redemption_codes FOR SELECT
USING (has_permission('manage_codes'::text));
CREATE POLICY "Admins with manage_codes permission can insert redemption codes"
ON redemption_codes FOR INSERT
WITH CHECK (has_permission('manage_codes'::text));
CREATE POLICY "Admins with manage_codes permission can update redemption codes"
ON redemption_codes FOR UPDATE
USING (has_permission('manage_codes'::text));
CREATE POLICY "Admins with manage_codes permission can delete redemption codes"
ON redemption_codes FOR DELETE
USING (has_permission('manage_codes'::text));
CREATE POLICY "Super admins can manage redemption codes"
ON redemption_codes FOR ALL
USING (
EXISTS (
SELECT 1
FROM admin_users
WHERE admin_users.user_id = auth.uid()
AND admin_users.role = 'super_admin'::admin_role
)
);
CREATE POLICY "Users can view own redemptions"
ON code_redemptions FOR SELECT
USING (auth.uid() = user_id);
CREATE POLICY "Super admins can view all redemptions"
ON code_redemptions FOR SELECT
USING (
EXISTS (
SELECT 1
FROM admin_users
WHERE admin_users.user_id = auth.uid()
AND admin_users.role = 'super_admin'::admin_role
)
);
CREATE OR REPLACE FUNCTION public.redeem_code_by_email(p_email text, p_code text)
RETURNS jsonb
LANGUAGE plpgsql
SECURITY DEFINER
AS $function$
DECLARE
v_code_record record;
v_user_record record;
v_existing_redemption record;
BEGIN
-- Find the user by email
SELECT id INTO v_user_record
FROM public.profiles
WHERE LOWER(email) = LOWER(p_email);
IF v_user_record IS NULL THEN
RETURN jsonb_build_object('success', false, 'error', 'No account found with this email address');
END IF;
-- Find the code
SELECT * INTO v_code_record
FROM public.redemption_codes
WHERE UPPER(code) = UPPER(p_code);
IF v_code_record IS NULL THEN
RETURN jsonb_build_object('success', false, 'error', 'Invalid redemption code');
END IF;
-- Check if code is active
IF NOT v_code_record.is_active THEN
RETURN jsonb_build_object('success', false, 'error', 'This code is no longer active');
END IF;
-- Check if code has expired
IF v_code_record.expires_at IS NOT NULL AND v_code_record.expires_at < now() THEN
RETURN jsonb_build_object('success', false, 'error', 'This code has expired');
END IF;
-- Check if code has uses remaining
IF v_code_record.max_uses IS NOT NULL AND v_code_record.current_uses >= v_code_record.max_uses THEN
RETURN jsonb_build_object('success', false, 'error', 'This code has reached its maximum number of uses');
END IF;
-- Check if user has already redeemed this code
SELECT * INTO v_existing_redemption
FROM public.code_redemptions
WHERE code_id = v_code_record.id AND user_id = v_user_record.id;
IF v_existing_redemption IS NOT NULL THEN
RETURN jsonb_build_object('success', false, 'error', 'You have already redeemed this code');
END IF;
-- All checks passed - redeem the code
-- 1. Create redemption record
INSERT INTO public.code_redemptions (code_id, user_id)
VALUES (v_code_record.id, v_user_record.id);
-- 2. Increment current_uses
UPDATE public.redemption_codes
SET current_uses = current_uses + 1,
updated_at = now()
WHERE id = v_code_record.id;
-- 3. Set user as premium
UPDATE public.profiles
SET is_premium = true,
updated_at = now()
WHERE id = v_user_record.id;
RETURN jsonb_build_object('success', true, 'message', 'Code redeemed successfully! You now have premium access.');
END;
$function$;
GRANT EXECUTE ON FUNCTION public.redeem_code_by_email(text, text) TO PUBLIC;
GRANT EXECUTE ON FUNCTION public.redeem_code_by_email(text, text) TO anon, authenticated, service_role;