From b701554996de0af815324e33f41d32ded128d1a5 Mon Sep 17 00:00:00 2001 From: Tim Olson Date: Wed, 1 Apr 2026 22:47:34 -0400 Subject: [PATCH] add bin/create-user script for beta user onboarding Co-Authored-By: Claude Sonnet 4.6 --- bin/create-user | 140 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100755 bin/create-user diff --git a/bin/create-user b/bin/create-user new file mode 100755 index 00000000..5883b7f4 --- /dev/null +++ b/bin/create-user @@ -0,0 +1,140 @@ +#!/usr/bin/env bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +usage() { + echo "Usage: $0 [dev|prod]" + echo "" + echo "Create a new user and assign a license." + echo "" + echo " dev - Create user in dev environment (minikube)" + echo " prod - Create user in prod environment" + exit 1 +} + +ENV="${1:-dev}" + +if [[ "$ENV" != "dev" && "$ENV" != "prod" ]]; then + echo -e "${RED}Error: Environment must be 'dev' or 'prod'${NC}" + usage +fi + +if [[ "$ENV" == "prod" ]]; then + KUBECTL="kubectl --context=prod" + BASE_URL="https://dexorder.ai" + MCP_URL="https://dexorder.ai/mcp" +else + KUBECTL="kubectl" + BASE_URL="http://dexorder.local" + MCP_URL="http://localhost:8080/mcp" +fi + +# Get postgres pod +PG_POD=$($KUBECTL get pods -l app=postgres -o jsonpath='{.items[0].metadata.name}' 2>/dev/null) +if [ -z "$PG_POD" ]; then + echo -e "${RED}No postgres pod found${NC}" + exit 1 +fi + +# Prompt for credentials +read -p "Email: " USER_EMAIL +read -rs -p "Password (min 8 chars): " USER_PASSWORD +echo "" +if [[ ${#USER_PASSWORD} -lt 8 ]]; then + echo -e "${RED}✗ Password must be at least 8 characters${NC}" + exit 1 +fi +read -p "Display name: " USER_NAME +read -p "License type [free|pro|enterprise] (default: pro): " LICENSE_TYPE +LICENSE_TYPE="${LICENSE_TYPE:-pro}" + +# Check if user already exists +EXISTING_ID=$($KUBECTL exec "$PG_POD" -- psql -U postgres -d iceberg -t \ + -c "SELECT id FROM \"user\" WHERE email = '$USER_EMAIL';" \ + 2>/dev/null | tr -d ' \n') + +if [ -n "$EXISTING_ID" ]; then + echo -e "${YELLOW}⚠️ User already exists in database ($USER_EMAIL)${NC}" + USER_ID="$EXISTING_ID" +else + echo -e "${GREEN}→${NC} Registering user via API..." + PAYLOAD=$(jq -n \ + --arg email "$USER_EMAIL" \ + --arg password "$USER_PASSWORD" \ + --arg name "$USER_NAME" \ + '{email: $email, password: $password, name: $name}') + + HTTP_CODE=$(curl -s -o /tmp/dexorder-create-user-response.json -w "%{http_code}" \ + -X POST "$BASE_URL/api/auth/register" \ + -H "Content-Type: application/json" \ + -d "$PAYLOAD") + + if [[ "$HTTP_CODE" == "200" || "$HTTP_CODE" == "201" ]]; then + echo -e "${GREEN}✓ User registered${NC}" + elif [[ "$HTTP_CODE" == "400" ]]; then + RESPONSE=$(cat /tmp/dexorder-create-user-response.json 2>/dev/null) + if echo "$RESPONSE" | grep -qi "already exist\|user already\|duplicate"; then + echo -e "${YELLOW}⚠️ User already exists, continuing...${NC}" + else + echo -e "${RED}✗ Registration failed (400):${NC}" + echo "$RESPONSE" + rm -f /tmp/dexorder-create-user-response.json + exit 1 + fi + else + echo -e "${RED}✗ API returned HTTP $HTTP_CODE${NC}" + cat /tmp/dexorder-create-user-response.json 2>/dev/null || true + rm -f /tmp/dexorder-create-user-response.json + exit 1 + fi + rm -f /tmp/dexorder-create-user-response.json + + sleep 2 + + USER_ID=$($KUBECTL exec "$PG_POD" -- psql -U postgres -d iceberg -t \ + -c "SELECT id FROM \"user\" WHERE email = '$USER_EMAIL';" \ + 2>/dev/null | tr -d ' \n') +fi + +if [ -z "$USER_ID" ]; then + echo -e "${RED}User not found in database after registration. Is the gateway running?${NC}" + exit 1 +fi +echo -e "${GREEN}User ID: $USER_ID${NC}" + +# Build license JSON +case "$LICENSE_TYPE" in + enterprise) + LICENSE_JSON='{"licenseType":"enterprise","features":{"maxIndicators":200,"maxStrategies":100,"maxBacktestDays":1825,"realtimeData":true,"customExecutors":true,"apiAccess":true},"resourceLimits":{"maxConcurrentSessions":20,"maxMessagesPerDay":10000,"maxTokensPerMessage":32768,"rateLimitPerMinute":300},"k8sResources":{"memoryRequest":"1Gi","memoryLimit":"4Gi","cpuRequest":"500m","cpuLimit":"4000m","storage":"50Gi","tmpSizeLimit":"1Gi","enableIdleShutdown":true,"idleTimeoutMinutes":120},"preferredModel":{"provider":"anthropic","model":"claude-opus-4-6","temperature":0.7}}' + ;; + free) + LICENSE_JSON='{"licenseType":"free","features":{"maxIndicators":10,"maxStrategies":3,"maxBacktestDays":30,"realtimeData":false,"customExecutors":false,"apiAccess":false},"resourceLimits":{"maxConcurrentSessions":1,"maxMessagesPerDay":100,"maxTokensPerMessage":4096,"rateLimitPerMinute":20},"k8sResources":{"memoryRequest":"256Mi","memoryLimit":"512Mi","cpuRequest":"100m","cpuLimit":"500m","storage":"2Gi","tmpSizeLimit":"128Mi","enableIdleShutdown":true,"idleTimeoutMinutes":30},"preferredModel":{"provider":"anthropic","model":"claude-haiku-4-5-20251001","temperature":0.7}}' + ;; + pro|*) + LICENSE_JSON='{"licenseType":"pro","features":{"maxIndicators":50,"maxStrategies":20,"maxBacktestDays":365,"realtimeData":true,"customExecutors":true,"apiAccess":true},"resourceLimits":{"maxConcurrentSessions":5,"maxMessagesPerDay":1000,"maxTokensPerMessage":8192,"rateLimitPerMinute":60},"k8sResources":{"memoryRequest":"512Mi","memoryLimit":"2Gi","cpuRequest":"250m","cpuLimit":"2000m","storage":"10Gi","tmpSizeLimit":"256Mi","enableIdleShutdown":true,"idleTimeoutMinutes":60},"preferredModel":{"provider":"anthropic","model":"claude-sonnet-4-6","temperature":0.7}}' + ;; +esac + +echo -e "${GREEN}→${NC} Assigning $LICENSE_TYPE license..." +$KUBECTL exec "$PG_POD" -- psql -U postgres -d iceberg -c " + INSERT INTO user_licenses (user_id, email, license, mcp_server_url) + VALUES ( + '$USER_ID', + '$USER_EMAIL', + '$LICENSE_JSON', + '$MCP_URL' + ) + ON CONFLICT (user_id) DO UPDATE SET + license = EXCLUDED.license, + updated_at = NOW(); +" > /dev/null + +echo -e "${GREEN}✓ User ready: $USER_EMAIL ($LICENSE_TYPE)${NC}"