--liquibase formatted sql -- PANELS · iam · RPC usuarios y permisos del tenant --changeset panel:iam-004a-fn-iam-user-list splitStatements:false CREATE OR REPLACE FUNCTION iam.fn_user_list(payload jsonb) RETURNS jsonb LANGUAGE plpgsql SECURITY INVOKER SET search_path = iam AS $$ DECLARE v_tid integer := COALESCE( NULLIF(payload->>'tenant_id', '')::integer, NULLIF(current_setting('app.tenant_id', true), '')::integer ); v_rows jsonb; BEGIN SELECT COALESCE(jsonb_agg(to_jsonb(u) ORDER BY u.display_name), '[]'::jsonb) INTO v_rows FROM ( SELECT id, username, display_name, email, role_code, company_id, tenant_id, created_at FROM users WHERE tenant_id = v_tid ) u; RETURN core.rpc_ok( jsonb_build_object('users', v_rows), format('Usuarios del tenant %s: %s cuenta(s)', v_tid, jsonb_array_length(v_rows)), jsonb_build_object('fn', 'fn_user_list', 'tenant_id', v_tid) ); EXCEPTION WHEN OTHERS THEN RETURN core.rpc_from_exception('fn_user_list', SQLSTATE, SQLERRM); END; $$; --changeset panel:iam-004b-fn-iam-permission-list splitStatements:false CREATE OR REPLACE FUNCTION iam.fn_permission_list(payload jsonb) RETURNS jsonb LANGUAGE plpgsql SECURITY INVOKER SET search_path = iam AS $$ DECLARE v_rows jsonb; BEGIN SELECT COALESCE(jsonb_agg(to_jsonb(p) ORDER BY p.code), '[]'::jsonb) INTO v_rows FROM (SELECT code, label FROM permissions) p; RETURN core.rpc_ok(jsonb_build_object('permissions', v_rows), format('Catálogo de permisos: %s', jsonb_array_length(v_rows)), jsonb_build_object('fn', 'fn_permission_list')); EXCEPTION WHEN OTHERS THEN RETURN core.rpc_from_exception('fn_permission_list', SQLSTATE, SQLERRM); END; $$; --changeset panel:iam-004c-fn-iam-role-permissions-get splitStatements:false CREATE OR REPLACE FUNCTION iam.fn_role_permissions_get(payload jsonb) RETURNS jsonb LANGUAGE plpgsql SECURITY INVOKER SET search_path = iam AS $$ DECLARE v_role text := nullif(btrim(payload->>'role_code'), ''); v_rows jsonb; BEGIN IF v_role IS NULL THEN RETURN core.rpc_err('VALIDATION', 'fn_role_permissions_get: role_code es obligatorio', jsonb_build_object('fn', 'fn_role_permissions_get')); END IF; SELECT COALESCE(jsonb_agg(rp.permission_code), '[]'::jsonb) INTO v_rows FROM role_permissions rp WHERE rp.role_code = v_role; RETURN core.rpc_ok(jsonb_build_object('role_code', v_role, 'permissions', v_rows), format('Permisos del rol %s: %s', v_role, jsonb_array_length(v_rows)), jsonb_build_object('fn', 'fn_role_permissions_get', 'role_code', v_role)); EXCEPTION WHEN OTHERS THEN RETURN core.rpc_from_exception('fn_role_permissions_get', SQLSTATE, SQLERRM); END; $$; --changeset panel:iam-004d-fn-iam-role-permissions-save splitStatements:false CREATE OR REPLACE FUNCTION iam.fn_role_permissions_save(payload jsonb) RETURNS jsonb LANGUAGE plpgsql SECURITY INVOKER SET search_path = iam AS $$ DECLARE v_role text := nullif(btrim(payload->>'role_code'), ''); v_perms jsonb := COALESCE(payload->'permissions', '[]'::jsonb); v_perm text; BEGIN IF v_role IS NULL OR v_role = 'tenant_admin' THEN RETURN core.rpc_err('VALIDATION', 'fn_role_permissions_save: no se puede modificar tenant_admin', jsonb_build_object('fn', 'fn_role_permissions_save', 'role_code', v_role)); END IF; DELETE FROM role_permissions WHERE role_code = v_role; FOR v_perm IN SELECT jsonb_array_elements_text(v_perms) LOOP INSERT INTO role_permissions (role_code, permission_code) VALUES (v_role, v_perm) ON CONFLICT DO NOTHING; END LOOP; RETURN core.rpc_ok( jsonb_build_object('role_code', v_role, 'permissions', v_perms), format('Permisos del rol %s actualizados (%s permiso(s))', v_role, jsonb_array_length(v_perms)), jsonb_build_object('fn', 'fn_role_permissions_save', 'role_code', v_role)); EXCEPTION WHEN OTHERS THEN RETURN core.rpc_from_exception('fn_role_permissions_save', SQLSTATE, SQLERRM); END; $$; --changeset panel:iam-004e-iam-rpc-grants endDelimiter:; splitStatements:true GRANT EXECUTE ON FUNCTION iam.fn_user_list(jsonb) TO panels_iam_app; GRANT EXECUTE ON FUNCTION iam.fn_permission_list(jsonb) TO panels_iam_app; GRANT EXECUTE ON FUNCTION iam.fn_role_permissions_get(jsonb) TO panels_iam_app; GRANT EXECUTE ON FUNCTION iam.fn_role_permissions_save(jsonb) TO panels_iam_app;