197 lines
7.6 KiB
PL/PgSQL
197 lines
7.6 KiB
PL/PgSQL
-- Chattyness Admin Restore Props Function
|
|
-- PostgreSQL 18
|
|
--
|
|
-- Admin function to restore missing essential props for users.
|
|
-- Load via: psql -f schema/functions/003_admin_restore_props.sql
|
|
|
|
\set ON_ERROR_STOP on
|
|
|
|
BEGIN;
|
|
|
|
-- =============================================================================
|
|
-- Restore Essential Props for a Single User
|
|
-- =============================================================================
|
|
-- Restores missing face-tagged server props to a user's inventory and fixes
|
|
-- any broken avatar slot references.
|
|
--
|
|
-- Usage: SELECT * FROM auth.restore_essential_props('username');
|
|
-- =============================================================================
|
|
|
|
CREATE OR REPLACE FUNCTION auth.restore_essential_props(p_username TEXT)
|
|
RETURNS TABLE(
|
|
action TEXT,
|
|
prop_slug TEXT,
|
|
inventory_id UUID
|
|
) AS $$
|
|
DECLARE
|
|
v_user_id UUID;
|
|
v_prop RECORD;
|
|
v_inventory_id UUID;
|
|
v_avatar_id UUID;
|
|
BEGIN
|
|
-- Get user ID
|
|
SELECT id INTO v_user_id FROM auth.users WHERE username = p_username;
|
|
IF v_user_id IS NULL THEN
|
|
RAISE EXCEPTION 'User not found: %', p_username;
|
|
END IF;
|
|
|
|
-- For each face-tagged server prop
|
|
FOR v_prop IN
|
|
SELECT id, name, asset_path, default_layer, default_emotion, default_position, slug,
|
|
is_transferable, is_portable, is_droppable
|
|
FROM server.props
|
|
WHERE tags @> ARRAY['face'] AND is_active = true
|
|
LOOP
|
|
-- Check if user already has this prop
|
|
SELECT inv.id INTO v_inventory_id
|
|
FROM auth.inventory inv
|
|
WHERE inv.user_id = v_user_id AND inv.server_prop_id = v_prop.id;
|
|
|
|
IF v_inventory_id IS NULL THEN
|
|
-- Insert missing prop
|
|
INSERT INTO auth.inventory (
|
|
user_id, server_prop_id, prop_name, prop_asset_path,
|
|
layer, position, origin,
|
|
is_transferable, is_portable, is_droppable
|
|
)
|
|
VALUES (
|
|
v_user_id, v_prop.id, v_prop.name, v_prop.asset_path,
|
|
v_prop.default_layer,
|
|
CASE WHEN v_prop.default_layer IS NOT NULL THEN v_prop.default_position ELSE NULL END,
|
|
'server_library',
|
|
v_prop.is_transferable, v_prop.is_portable, v_prop.is_droppable
|
|
)
|
|
RETURNING id INTO v_inventory_id;
|
|
|
|
action := 'restored';
|
|
prop_slug := v_prop.slug;
|
|
inventory_id := v_inventory_id;
|
|
RETURN NEXT;
|
|
ELSE
|
|
action := 'exists';
|
|
prop_slug := v_prop.slug;
|
|
inventory_id := v_inventory_id;
|
|
RETURN NEXT;
|
|
END IF;
|
|
END LOOP;
|
|
|
|
-- Get the user's default avatar (slot 0)
|
|
SELECT id INTO v_avatar_id FROM auth.avatars WHERE user_id = v_user_id AND slot_number = 0;
|
|
|
|
IF v_avatar_id IS NOT NULL THEN
|
|
-- Update avatar slots with correct inventory references where NULL
|
|
UPDATE auth.avatars a
|
|
SET
|
|
l_skin_4 = COALESCE(a.l_skin_4, (
|
|
SELECT inv.id FROM auth.inventory inv
|
|
JOIN server.props sp ON inv.server_prop_id = sp.id
|
|
WHERE inv.user_id = v_user_id AND sp.slug = 'face'
|
|
)),
|
|
e_neutral_4 = COALESCE(a.e_neutral_4, (
|
|
SELECT inv.id FROM auth.inventory inv
|
|
JOIN server.props sp ON inv.server_prop_id = sp.id
|
|
WHERE inv.user_id = v_user_id AND sp.slug = 'neutral'
|
|
)),
|
|
e_happy_4 = COALESCE(a.e_happy_4, (
|
|
SELECT inv.id FROM auth.inventory inv
|
|
JOIN server.props sp ON inv.server_prop_id = sp.id
|
|
WHERE inv.user_id = v_user_id AND sp.slug = 'smile'
|
|
)),
|
|
e_sad_4 = COALESCE(a.e_sad_4, (
|
|
SELECT inv.id FROM auth.inventory inv
|
|
JOIN server.props sp ON inv.server_prop_id = sp.id
|
|
WHERE inv.user_id = v_user_id AND sp.slug = 'sad'
|
|
)),
|
|
e_angry_4 = COALESCE(a.e_angry_4, (
|
|
SELECT inv.id FROM auth.inventory inv
|
|
JOIN server.props sp ON inv.server_prop_id = sp.id
|
|
WHERE inv.user_id = v_user_id AND sp.slug = 'angry'
|
|
)),
|
|
e_surprised_4 = COALESCE(a.e_surprised_4, (
|
|
SELECT inv.id FROM auth.inventory inv
|
|
JOIN server.props sp ON inv.server_prop_id = sp.id
|
|
WHERE inv.user_id = v_user_id AND sp.slug = 'surprised'
|
|
)),
|
|
e_thinking_4 = COALESCE(a.e_thinking_4, (
|
|
SELECT inv.id FROM auth.inventory inv
|
|
JOIN server.props sp ON inv.server_prop_id = sp.id
|
|
WHERE inv.user_id = v_user_id AND sp.slug = 'thinking'
|
|
)),
|
|
e_laughing_4 = COALESCE(a.e_laughing_4, (
|
|
SELECT inv.id FROM auth.inventory inv
|
|
JOIN server.props sp ON inv.server_prop_id = sp.id
|
|
WHERE inv.user_id = v_user_id AND sp.slug = 'laughing'
|
|
)),
|
|
e_crying_4 = COALESCE(a.e_crying_4, (
|
|
SELECT inv.id FROM auth.inventory inv
|
|
JOIN server.props sp ON inv.server_prop_id = sp.id
|
|
WHERE inv.user_id = v_user_id AND sp.slug = 'crying'
|
|
)),
|
|
e_love_4 = COALESCE(a.e_love_4, (
|
|
SELECT inv.id FROM auth.inventory inv
|
|
JOIN server.props sp ON inv.server_prop_id = sp.id
|
|
WHERE inv.user_id = v_user_id AND sp.slug = 'love'
|
|
)),
|
|
e_confused_4 = COALESCE(a.e_confused_4, (
|
|
SELECT inv.id FROM auth.inventory inv
|
|
JOIN server.props sp ON inv.server_prop_id = sp.id
|
|
WHERE inv.user_id = v_user_id AND sp.slug = 'confused'
|
|
)),
|
|
e_sleeping_4 = COALESCE(a.e_sleeping_4, (
|
|
SELECT inv.id FROM auth.inventory inv
|
|
JOIN server.props sp ON inv.server_prop_id = sp.id
|
|
WHERE inv.user_id = v_user_id AND sp.slug = 'sleeping'
|
|
)),
|
|
e_wink_4 = COALESCE(a.e_wink_4, (
|
|
SELECT inv.id FROM auth.inventory inv
|
|
JOIN server.props sp ON inv.server_prop_id = sp.id
|
|
WHERE inv.user_id = v_user_id AND sp.slug = 'wink'
|
|
))
|
|
WHERE a.id = v_avatar_id;
|
|
|
|
action := 'avatar_fixed';
|
|
prop_slug := NULL;
|
|
inventory_id := v_avatar_id;
|
|
RETURN NEXT;
|
|
END IF;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
COMMENT ON FUNCTION auth.restore_essential_props(TEXT) IS
|
|
'Restore missing essential (face-tagged) props to a user''s inventory and fix avatar slots';
|
|
|
|
-- =============================================================================
|
|
-- Restore Essential Props for All Users
|
|
-- =============================================================================
|
|
-- Batch operation to restore props for all users.
|
|
--
|
|
-- Usage: SELECT * FROM auth.restore_essential_props_all_users();
|
|
-- =============================================================================
|
|
|
|
CREATE OR REPLACE FUNCTION auth.restore_essential_props_all_users()
|
|
RETURNS TABLE(
|
|
username TEXT,
|
|
props_restored INTEGER
|
|
) AS $$
|
|
DECLARE
|
|
v_user RECORD;
|
|
v_count INTEGER;
|
|
BEGIN
|
|
FOR v_user IN SELECT id, u.username FROM auth.users u LOOP
|
|
SELECT COUNT(*) INTO v_count
|
|
FROM auth.restore_essential_props(v_user.username)
|
|
WHERE action = 'restored';
|
|
|
|
IF v_count > 0 THEN
|
|
username := v_user.username;
|
|
props_restored := v_count;
|
|
RETURN NEXT;
|
|
END IF;
|
|
END LOOP;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
COMMENT ON FUNCTION auth.restore_essential_props_all_users() IS
|
|
'Restore missing essential props for all users - returns users who had props restored';
|
|
|
|
COMMIT;
|