@knowcode/doc-builder 1.8.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +4 -1
- package/CHANGELOG.md +7 -0
- package/assets/js/main.js +10 -6
- package/html/README.html +43 -5
- package/html/auth.js +62 -13
- package/html/documentation-index.html +43 -5
- package/html/guides/authentication-default-change.html +43 -5
- package/html/guides/authentication-guide.html +43 -5
- package/html/guides/claude-workflow-guide.html +43 -5
- package/html/guides/documentation-standards.html +43 -5
- package/html/guides/phosphor-icons-guide.html +43 -5
- package/html/guides/private-directory-authentication.html +237 -117
- package/html/guides/public-site-deployment.html +43 -5
- package/html/guides/search-engine-verification-guide.html +43 -5
- package/html/guides/seo-guide.html +43 -5
- package/html/guides/seo-optimization-guide.html +43 -5
- package/html/guides/troubleshooting-guide.html +43 -5
- package/html/guides/windows-setup-guide.html +43 -5
- package/html/index.html +43 -5
- package/html/js/auth.js +118 -39
- package/html/js/main.js +10 -6
- package/html/login.html +4 -4
- package/html/logout.html +2 -2
- package/html/private/cache-control-anti-pattern.html +66 -5
- package/html/private/launch/README.html +66 -5
- package/html/private/launch/auth-cleanup-summary.html +66 -5
- package/html/private/launch/bubble-plugin-specification.html +66 -5
- package/html/private/launch/go-to-market-strategy.html +66 -5
- package/html/private/launch/launch-announcements.html +66 -5
- package/html/private/launch/vercel-deployment-auth-setup.html +66 -5
- package/html/private/next-steps-walkthrough.html +66 -5
- package/html/private/supabase-auth-implementation-completed.html +66 -5
- package/html/private/supabase-auth-implementation-plan.html +66 -5
- package/html/private/supabase-auth-integration-plan.html +66 -5
- package/html/private/supabase-auth-setup-guide.html +66 -5
- package/html/private/test-private-doc.html +66 -5
- package/html/robots.txt +4 -0
- package/html/sitemap.xml +43 -43
- package/html/vercel-cli-setup-guide.html +43 -5
- package/html/vercel-first-time-setup-guide.html +43 -5
- package/lib/config.js +15 -21
- package/lib/core-builder.js +9 -1
- package/lib/supabase-auth.js +20 -14
- package/package.json +1 -1
- package/user-management/README.md +276 -51
- package/user-management/add-users.sh +635 -262
- package/user-management/create-user.js +65 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
#
|
|
3
|
+
# Doc-Builder User Management System
|
|
4
|
+
# Uses Supabase CLI for user creation and database operations
|
|
5
5
|
|
|
6
6
|
set -e
|
|
7
7
|
|
|
@@ -10,98 +10,341 @@ RED='\033[0;31m'
|
|
|
10
10
|
GREEN='\033[0;32m'
|
|
11
11
|
YELLOW='\033[1;33m'
|
|
12
12
|
BLUE='\033[0;34m'
|
|
13
|
+
CYAN='\033[0;36m'
|
|
14
|
+
MAGENTA='\033[0;35m'
|
|
15
|
+
BOLD='\033[1m'
|
|
13
16
|
NC='\033[0m' # No Color
|
|
14
17
|
|
|
15
|
-
#
|
|
16
|
-
|
|
18
|
+
# Configuration
|
|
19
|
+
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
20
|
+
CONFIG_FILE="$SCRIPT_DIR/.supabase-config"
|
|
21
|
+
PROJECT_ID="xcihhnfcitjrwbynxmka" # Default project ID
|
|
17
22
|
|
|
18
|
-
#
|
|
23
|
+
# Load configuration if exists
|
|
24
|
+
if [ -f "$CONFIG_FILE" ]; then
|
|
25
|
+
source "$CONFIG_FILE"
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# Show comprehensive help
|
|
19
29
|
show_help() {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
30
|
+
cat << 'EOF'
|
|
31
|
+
═══════════════════════════════════════════════════════════════════════════════════
|
|
32
|
+
DOC-BUILDER USER MANAGEMENT SYSTEM
|
|
33
|
+
═══════════════════════════════════════════════════════════════════════════════════
|
|
34
|
+
|
|
35
|
+
Manage user access to Supabase-authenticated documentation sites using the
|
|
36
|
+
Supabase CLI. This tool creates users and manages their site access.
|
|
37
|
+
|
|
38
|
+
PREREQUISITES:
|
|
39
|
+
✓ Supabase CLI installed (npm install -g supabase)
|
|
40
|
+
✓ Logged in to Supabase (supabase login)
|
|
41
|
+
✓ Project linked (or use 'setup' command)
|
|
42
|
+
|
|
43
|
+
USAGE:
|
|
44
|
+
./add-users.sh <command> [options]
|
|
45
|
+
|
|
46
|
+
COMMANDS:
|
|
47
|
+
|
|
48
|
+
setup Initial setup - link your Supabase project
|
|
49
|
+
Example: ./add-users.sh setup
|
|
50
|
+
|
|
51
|
+
add <site-url> <email> Grant user access to a site
|
|
52
|
+
Example: ./add-users.sh add docs.example.com user@email.com
|
|
53
|
+
- Checks if user exists
|
|
54
|
+
- If not, prompts you to create via Supabase dashboard
|
|
55
|
+
- Grants access to the specified site
|
|
56
|
+
|
|
57
|
+
bulk <site-url> <file> Add multiple users from a file
|
|
58
|
+
Example: ./add-users.sh bulk docs.example.com users.txt
|
|
59
|
+
- File should contain one email per line
|
|
60
|
+
- Lines starting with # are ignored
|
|
61
|
+
- Empty lines are skipped
|
|
62
|
+
|
|
63
|
+
list <site-url> List all users with access to a site
|
|
64
|
+
Example: ./add-users.sh list docs.example.com
|
|
65
|
+
- Shows email, creation date, last login
|
|
66
|
+
- Shows total user count
|
|
67
|
+
|
|
68
|
+
check <email> Check user status across all sites
|
|
69
|
+
Example: ./add-users.sh check user@email.com
|
|
70
|
+
- Shows if user exists
|
|
71
|
+
- Lists all sites they have access to
|
|
72
|
+
- Shows last login time
|
|
73
|
+
|
|
74
|
+
remove <site-url> <email> Remove user's access to a site
|
|
75
|
+
Example: ./add-users.sh remove docs.example.com user@email.com
|
|
76
|
+
- Only removes access, doesn't delete user
|
|
77
|
+
- User can still access other sites
|
|
78
|
+
|
|
79
|
+
sites List all documentation sites
|
|
80
|
+
Example: ./add-users.sh sites
|
|
81
|
+
- Shows site URL, name, and user count
|
|
82
|
+
|
|
83
|
+
delete-user <email> Remove user access from ALL sites
|
|
84
|
+
Example: ./add-users.sh delete-user user@email.com
|
|
85
|
+
- Removes access to all sites
|
|
86
|
+
- Does NOT delete the user account (use dashboard for that)
|
|
87
|
+
|
|
88
|
+
SITE URLS:
|
|
89
|
+
- Use domain without https:// prefix
|
|
90
|
+
- Examples: docs.example.com, my-app.vercel.app
|
|
91
|
+
|
|
92
|
+
ENVIRONMENT VARIABLES:
|
|
93
|
+
SUPABASE_PROJECT_ID Your Supabase project ID (optional)
|
|
94
|
+
SUPABASE_DB_URL Database connection URL (optional)
|
|
95
|
+
|
|
96
|
+
EXAMPLES:
|
|
97
|
+
|
|
98
|
+
Initial Setup:
|
|
99
|
+
./add-users.sh setup
|
|
100
|
+
|
|
101
|
+
Add a single user:
|
|
102
|
+
./add-users.sh add wru-bid-analysis.vercel.app lindsay@knowcode.tech
|
|
103
|
+
|
|
104
|
+
Add multiple users:
|
|
105
|
+
echo "user1@example.com" > users.txt
|
|
106
|
+
echo "user2@example.com" >> users.txt
|
|
107
|
+
./add-users.sh bulk my-docs.vercel.app users.txt
|
|
108
|
+
|
|
109
|
+
Check who has access:
|
|
110
|
+
./add-users.sh list my-docs.vercel.app
|
|
111
|
+
|
|
112
|
+
Remove someone's access:
|
|
113
|
+
./add-users.sh remove my-docs.vercel.app user@example.com
|
|
114
|
+
|
|
115
|
+
TROUBLESHOOTING:
|
|
116
|
+
|
|
117
|
+
"Supabase CLI not found"
|
|
118
|
+
→ Install it: npm install -g supabase
|
|
119
|
+
|
|
120
|
+
"Not logged in to Supabase"
|
|
121
|
+
→ Run: supabase login
|
|
122
|
+
|
|
123
|
+
"Project not linked"
|
|
124
|
+
→ Run: ./add-users.sh setup
|
|
125
|
+
|
|
126
|
+
"User already exists"
|
|
127
|
+
→ This is fine, the script will continue
|
|
128
|
+
|
|
129
|
+
"Access already granted"
|
|
130
|
+
→ User already has access to this site
|
|
131
|
+
|
|
132
|
+
MORE HELP:
|
|
133
|
+
GitHub: https://github.com/wapdat/doc-builder
|
|
134
|
+
Docs: https://doc-builder-delta.vercel.app
|
|
135
|
+
|
|
136
|
+
═══════════════════════════════════════════════════════════════════════════════════
|
|
137
|
+
EOF
|
|
43
138
|
}
|
|
44
139
|
|
|
45
|
-
#
|
|
46
|
-
|
|
47
|
-
|
|
140
|
+
# Check if Supabase CLI is installed
|
|
141
|
+
check_supabase_cli() {
|
|
142
|
+
if ! command -v supabase &> /dev/null; then
|
|
143
|
+
echo -e "${RED}❌ Supabase CLI is not installed${NC}"
|
|
144
|
+
echo -e "${YELLOW}Install it with: ${CYAN}npm install -g supabase${NC}"
|
|
145
|
+
echo -e "${YELLOW}Or visit: ${CYAN}https://supabase.com/docs/guides/cli${NC}"
|
|
146
|
+
exit 1
|
|
147
|
+
fi
|
|
148
|
+
}
|
|
48
149
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
150
|
+
# Check if logged in to Supabase
|
|
151
|
+
check_supabase_login() {
|
|
152
|
+
if ! supabase projects list &> /dev/null; then
|
|
153
|
+
echo -e "${RED}❌ Not logged in to Supabase${NC}"
|
|
154
|
+
echo -e "${YELLOW}Please run: ${CYAN}supabase login${NC}"
|
|
155
|
+
exit 1
|
|
156
|
+
fi
|
|
157
|
+
}
|
|
53
158
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
159
|
+
# Setup command - link project
|
|
160
|
+
setup_project() {
|
|
161
|
+
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
162
|
+
echo -e "${BOLD}Setting up Supabase User Management${NC}"
|
|
163
|
+
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
164
|
+
echo
|
|
165
|
+
|
|
166
|
+
check_supabase_cli
|
|
167
|
+
check_supabase_login
|
|
168
|
+
|
|
169
|
+
# Get project ID
|
|
170
|
+
echo -e "${YELLOW}Enter your Supabase project ID (or press Enter for default):${NC}"
|
|
171
|
+
echo -e "${CYAN}Default: $PROJECT_ID${NC}"
|
|
172
|
+
read -p "> " input_project_id
|
|
173
|
+
|
|
174
|
+
if [ ! -z "$input_project_id" ]; then
|
|
175
|
+
PROJECT_ID="$input_project_id"
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
# Link the project
|
|
179
|
+
echo -e "\n${BLUE}Linking to project...${NC}"
|
|
180
|
+
if supabase link --project-ref "$PROJECT_ID"; then
|
|
181
|
+
echo -e "${GREEN}✅ Successfully linked to project${NC}"
|
|
182
|
+
|
|
183
|
+
# Save configuration
|
|
184
|
+
echo "PROJECT_ID=\"$PROJECT_ID\"" > "$CONFIG_FILE"
|
|
185
|
+
echo -e "${GREEN}✅ Configuration saved${NC}"
|
|
186
|
+
|
|
187
|
+
# Test database connection
|
|
188
|
+
echo -e "\n${BLUE}Testing database connection...${NC}"
|
|
189
|
+
if supabase db push --dry-run <<< "SELECT 1;" &> /dev/null; then
|
|
190
|
+
echo -e "${GREEN}✅ Database connection successful${NC}"
|
|
191
|
+
else
|
|
192
|
+
echo -e "${YELLOW}⚠️ Could not verify database connection${NC}"
|
|
193
|
+
fi
|
|
194
|
+
|
|
195
|
+
echo -e "\n${GREEN}Setup complete! You can now manage users.${NC}"
|
|
196
|
+
else
|
|
197
|
+
echo -e "${RED}❌ Failed to link project${NC}"
|
|
198
|
+
echo -e "${YELLOW}Make sure the project ID is correct${NC}"
|
|
199
|
+
exit 1
|
|
200
|
+
fi
|
|
201
|
+
}
|
|
62
202
|
|
|
63
|
-
|
|
203
|
+
# Execute SQL using Supabase CLI
|
|
204
|
+
execute_sql() {
|
|
205
|
+
local sql="$1"
|
|
206
|
+
local temp_file=$(mktemp)
|
|
207
|
+
|
|
208
|
+
echo "$sql" > "$temp_file"
|
|
209
|
+
|
|
210
|
+
# Use db execute instead of db push for running queries
|
|
211
|
+
local output=$(supabase db execute -f "$temp_file" 2>&1)
|
|
212
|
+
local status=$?
|
|
213
|
+
|
|
214
|
+
rm "$temp_file"
|
|
215
|
+
|
|
216
|
+
if [ $status -eq 0 ]; then
|
|
217
|
+
echo "$output"
|
|
218
|
+
return 0
|
|
219
|
+
else
|
|
220
|
+
echo -e "${RED}SQL Error: $output${NC}" >&2
|
|
221
|
+
return 1
|
|
222
|
+
fi
|
|
64
223
|
}
|
|
65
224
|
|
|
66
|
-
#
|
|
67
|
-
|
|
68
|
-
local
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
225
|
+
# Create a user using SQL (Supabase doesn't have CLI user creation)
|
|
226
|
+
create_user() {
|
|
227
|
+
local email="$1"
|
|
228
|
+
|
|
229
|
+
echo -e "${BLUE}Checking/Creating user: $email${NC}"
|
|
230
|
+
|
|
231
|
+
# Check if user exists first
|
|
232
|
+
local check_sql="SELECT id, email FROM auth.users WHERE email = '$email';"
|
|
233
|
+
|
|
234
|
+
local result=$(execute_sql "$check_sql")
|
|
235
|
+
|
|
236
|
+
if echo "$result" | grep -q "$email"; then
|
|
237
|
+
echo -e "${YELLOW}ℹ️ User already exists${NC}"
|
|
238
|
+
return 0
|
|
239
|
+
else
|
|
240
|
+
echo -e "${YELLOW}⚠️ User doesn't exist yet${NC}"
|
|
241
|
+
echo -e "${CYAN}You have two options to create the user:${NC}"
|
|
242
|
+
echo
|
|
243
|
+
echo -e "${BOLD}Option 1: Use Supabase Dashboard (Recommended)${NC}"
|
|
244
|
+
echo -e "${CYAN}1. Go to: https://supabase.com/dashboard/project/$PROJECT_ID/auth/users${NC}"
|
|
245
|
+
echo -e "${CYAN}2. Click 'Invite user'${NC}"
|
|
246
|
+
echo -e "${CYAN}3. Enter email: $email${NC}"
|
|
247
|
+
echo
|
|
248
|
+
echo -e "${BOLD}Option 2: Use Service Role Key (Advanced)${NC}"
|
|
249
|
+
echo -e "${CYAN}If you have your service_role key, I can create the user programmatically.${NC}"
|
|
250
|
+
echo -e "${CYAN}Find it at: https://supabase.com/dashboard/project/$PROJECT_ID/settings/api${NC}"
|
|
251
|
+
echo
|
|
252
|
+
echo -e "${YELLOW}Choose an option:${NC}"
|
|
253
|
+
echo -e " 1) Open dashboard and create manually"
|
|
254
|
+
echo -e " 2) Enter service role key"
|
|
255
|
+
echo -e " 3) Skip (user already exists elsewhere)"
|
|
256
|
+
read -p "Choice (1/2/3): " choice
|
|
257
|
+
|
|
258
|
+
case $choice in
|
|
259
|
+
1)
|
|
260
|
+
echo -e "${CYAN}Opening dashboard...${NC}"
|
|
261
|
+
if command -v open &> /dev/null; then
|
|
262
|
+
open "https://supabase.com/dashboard/project/$PROJECT_ID/auth/users"
|
|
263
|
+
fi
|
|
264
|
+
echo -e "${CYAN}Press Enter after creating the user...${NC}"
|
|
265
|
+
read -p ""
|
|
266
|
+
;;
|
|
267
|
+
2)
|
|
268
|
+
echo -e "${YELLOW}Enter your service_role key:${NC}"
|
|
269
|
+
read -s service_key
|
|
270
|
+
echo
|
|
271
|
+
if [ ! -z "$service_key" ]; then
|
|
272
|
+
echo -e "${BLUE}Creating user programmatically...${NC}"
|
|
273
|
+
# Get Supabase URL from config
|
|
274
|
+
local supabase_url="https://$PROJECT_ID.supabase.co"
|
|
275
|
+
if node "$SCRIPT_DIR/create-user.js" "$email" "$supabase_url" "$service_key" 2>&1; then
|
|
276
|
+
echo -e "${GREEN}✅ User created programmatically${NC}"
|
|
277
|
+
return 0
|
|
278
|
+
else
|
|
279
|
+
echo -e "${RED}❌ Failed to create user programmatically${NC}"
|
|
280
|
+
echo -e "${CYAN}Please try the dashboard method instead${NC}"
|
|
281
|
+
return 1
|
|
282
|
+
fi
|
|
283
|
+
fi
|
|
284
|
+
;;
|
|
285
|
+
3)
|
|
286
|
+
echo -e "${YELLOW}Skipping user creation...${NC}"
|
|
287
|
+
;;
|
|
288
|
+
*)
|
|
289
|
+
echo -e "${RED}Invalid choice${NC}"
|
|
290
|
+
return 1
|
|
291
|
+
;;
|
|
292
|
+
esac
|
|
293
|
+
|
|
294
|
+
# Check again if user was created
|
|
295
|
+
result=$(execute_sql "$check_sql")
|
|
296
|
+
if echo "$result" | grep -q "$email"; then
|
|
297
|
+
echo -e "${GREEN}✅ User confirmed in database${NC}"
|
|
298
|
+
return 0
|
|
299
|
+
else
|
|
300
|
+
echo -e "${RED}❌ User not found. Please create the user first.${NC}"
|
|
301
|
+
return 1
|
|
302
|
+
fi
|
|
303
|
+
fi
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
# Grant access to a site
|
|
307
|
+
grant_access() {
|
|
308
|
+
local site_url="$1"
|
|
309
|
+
local email="$2"
|
|
310
|
+
|
|
311
|
+
echo -e "${BLUE}Granting access to $site_url...${NC}"
|
|
312
|
+
|
|
313
|
+
local sql="
|
|
314
|
+
-- Get site info
|
|
315
|
+
DO \$\$
|
|
316
|
+
DECLARE
|
|
317
|
+
v_site_id UUID;
|
|
318
|
+
v_user_id UUID;
|
|
319
|
+
v_site_name TEXT;
|
|
320
|
+
BEGIN
|
|
321
|
+
-- Get site ID
|
|
322
|
+
SELECT id, name INTO v_site_id, v_site_name
|
|
323
|
+
FROM docbuilder_sites
|
|
324
|
+
WHERE domain = '$site_url';
|
|
325
|
+
|
|
326
|
+
IF v_site_id IS NULL THEN
|
|
327
|
+
RAISE EXCEPTION 'Site not found: $site_url';
|
|
328
|
+
END IF;
|
|
329
|
+
|
|
330
|
+
-- Get user ID
|
|
331
|
+
SELECT id INTO v_user_id
|
|
332
|
+
FROM auth.users
|
|
333
|
+
WHERE email = '$email';
|
|
334
|
+
|
|
335
|
+
IF v_user_id IS NULL THEN
|
|
336
|
+
RAISE EXCEPTION 'User not found: $email';
|
|
337
|
+
END IF;
|
|
338
|
+
|
|
339
|
+
-- Grant access
|
|
340
|
+
INSERT INTO docbuilder_access (user_id, site_id)
|
|
341
|
+
VALUES (v_user_id, v_site_id)
|
|
342
|
+
ON CONFLICT (user_id, site_id) DO NOTHING;
|
|
343
|
+
|
|
344
|
+
RAISE NOTICE 'Access granted to % for site: %', '$email', v_site_name;
|
|
345
|
+
END\$\$;
|
|
346
|
+
|
|
347
|
+
-- Show result
|
|
105
348
|
SELECT
|
|
106
349
|
u.email,
|
|
107
350
|
s.name as site_name,
|
|
@@ -110,57 +353,130 @@ SELECT
|
|
|
110
353
|
FROM docbuilder_access da
|
|
111
354
|
JOIN auth.users u ON u.id = da.user_id
|
|
112
355
|
JOIN docbuilder_sites s ON s.id = da.site_id
|
|
113
|
-
WHERE u.email = '$
|
|
356
|
+
WHERE u.email = '$email' AND s.domain = '$site_url';
|
|
357
|
+
"
|
|
358
|
+
|
|
359
|
+
if execute_sql "$sql"; then
|
|
360
|
+
echo -e "${GREEN}✅ Access granted successfully${NC}"
|
|
361
|
+
return 0
|
|
362
|
+
else
|
|
363
|
+
echo -e "${RED}❌ Failed to grant access${NC}"
|
|
364
|
+
return 1
|
|
365
|
+
fi
|
|
366
|
+
}
|
|
114
367
|
|
|
115
|
-
|
|
368
|
+
# Add command - create user and grant access
|
|
369
|
+
add_user() {
|
|
370
|
+
local site_url="$1"
|
|
371
|
+
local email="$2"
|
|
372
|
+
|
|
373
|
+
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
374
|
+
echo -e "${BOLD}Adding User${NC}"
|
|
375
|
+
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
376
|
+
echo -e "Site: ${CYAN}$site_url${NC}"
|
|
377
|
+
echo -e "Email: ${CYAN}$email${NC}"
|
|
378
|
+
echo
|
|
379
|
+
|
|
380
|
+
# Create user first
|
|
381
|
+
if create_user "$email"; then
|
|
382
|
+
# Then grant access
|
|
383
|
+
grant_access "$site_url" "$email"
|
|
384
|
+
fi
|
|
116
385
|
}
|
|
117
386
|
|
|
118
|
-
#
|
|
119
|
-
|
|
120
|
-
local site_url
|
|
121
|
-
|
|
387
|
+
# Bulk add users
|
|
388
|
+
bulk_add() {
|
|
389
|
+
local site_url="$1"
|
|
390
|
+
local file_path="$2"
|
|
391
|
+
|
|
392
|
+
if [ ! -f "$file_path" ]; then
|
|
393
|
+
echo -e "${RED}❌ File not found: $file_path${NC}"
|
|
394
|
+
exit 1
|
|
395
|
+
fi
|
|
396
|
+
|
|
397
|
+
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
398
|
+
echo -e "${BOLD}Bulk Adding Users${NC}"
|
|
399
|
+
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
400
|
+
echo -e "Site: ${CYAN}$site_url${NC}"
|
|
401
|
+
echo -e "File: ${CYAN}$file_path${NC}"
|
|
402
|
+
echo
|
|
403
|
+
|
|
404
|
+
local success_count=0
|
|
405
|
+
local fail_count=0
|
|
406
|
+
|
|
407
|
+
while IFS= read -r email; do
|
|
408
|
+
# Skip empty lines and comments
|
|
409
|
+
[[ -z "$email" || "$email" =~ ^#.*$ ]] && continue
|
|
410
|
+
|
|
411
|
+
# Trim whitespace
|
|
412
|
+
email=$(echo "$email" | xargs)
|
|
413
|
+
|
|
414
|
+
echo -e "\n${MAGENTA}Processing: $email${NC}"
|
|
415
|
+
echo -e "${CYAN}────────────────────────────────${NC}"
|
|
416
|
+
|
|
417
|
+
if create_user "$email" && grant_access "$site_url" "$email"; then
|
|
418
|
+
((success_count++))
|
|
419
|
+
else
|
|
420
|
+
((fail_count++))
|
|
421
|
+
fi
|
|
422
|
+
done < "$file_path"
|
|
423
|
+
|
|
424
|
+
echo -e "\n${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
425
|
+
echo -e "${BOLD}Summary${NC}"
|
|
426
|
+
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
427
|
+
echo -e "${GREEN}✅ Successful: $success_count${NC}"
|
|
428
|
+
echo -e "${RED}❌ Failed: $fail_count${NC}"
|
|
429
|
+
}
|
|
122
430
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
431
|
+
# List users for a site
|
|
432
|
+
list_users() {
|
|
433
|
+
local site_url="$1"
|
|
434
|
+
|
|
435
|
+
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
436
|
+
echo -e "${BOLD}Users with access to: $site_url${NC}"
|
|
437
|
+
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
438
|
+
|
|
439
|
+
local sql="
|
|
440
|
+
-- Site info
|
|
441
|
+
SELECT name, domain, created_at
|
|
442
|
+
FROM docbuilder_sites
|
|
443
|
+
WHERE domain = '$site_url';
|
|
128
444
|
|
|
445
|
+
-- Users with access
|
|
129
446
|
SELECT
|
|
130
447
|
u.email,
|
|
131
448
|
u.created_at as user_created,
|
|
132
449
|
da.created_at as access_granted,
|
|
133
450
|
CASE
|
|
134
451
|
WHEN u.last_sign_in_at IS NULL THEN 'Never logged in'
|
|
135
|
-
ELSE 'Last login: ' || u.last_sign_in_at
|
|
452
|
+
ELSE 'Last login: ' || to_char(u.last_sign_in_at, 'YYYY-MM-DD HH24:MI')
|
|
136
453
|
END as login_status
|
|
137
454
|
FROM docbuilder_access da
|
|
138
455
|
JOIN auth.users u ON u.id = da.user_id
|
|
139
456
|
JOIN docbuilder_sites s ON s.id = da.site_id
|
|
140
|
-
WHERE s.domain = '$
|
|
457
|
+
WHERE s.domain = '$site_url'
|
|
141
458
|
ORDER BY da.created_at DESC;
|
|
142
459
|
|
|
143
|
-
--
|
|
144
|
-
SELECT
|
|
145
|
-
FROM
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
460
|
+
-- Count
|
|
461
|
+
SELECT COUNT(*) as total_users
|
|
462
|
+
FROM docbuilder_access da
|
|
463
|
+
JOIN docbuilder_sites s ON s.id = da.site_id
|
|
464
|
+
WHERE s.domain = '$site_url';
|
|
465
|
+
"
|
|
466
|
+
|
|
467
|
+
execute_sql "$sql"
|
|
149
468
|
}
|
|
150
469
|
|
|
151
|
-
#
|
|
152
|
-
|
|
153
|
-
local
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
--
|
|
161
|
-
-- =====================================================
|
|
162
|
-
|
|
163
|
-
-- Check if user exists
|
|
470
|
+
# Check user status
|
|
471
|
+
check_user() {
|
|
472
|
+
local email="$1"
|
|
473
|
+
|
|
474
|
+
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
475
|
+
echo -e "${BOLD}User Status: $email${NC}"
|
|
476
|
+
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
477
|
+
|
|
478
|
+
local sql="
|
|
479
|
+
-- User info
|
|
164
480
|
SELECT
|
|
165
481
|
id,
|
|
166
482
|
email,
|
|
@@ -168,52 +484,58 @@ SELECT
|
|
|
168
484
|
last_sign_in_at,
|
|
169
485
|
CASE
|
|
170
486
|
WHEN last_sign_in_at IS NULL THEN 'Never logged in'
|
|
171
|
-
ELSE 'Last login: ' || last_sign_in_at
|
|
487
|
+
ELSE 'Last login: ' || to_char(last_sign_in_at, 'YYYY-MM-DD HH24:MI')
|
|
172
488
|
END as login_status
|
|
173
489
|
FROM auth.users
|
|
174
|
-
WHERE email = '$
|
|
490
|
+
WHERE email = '$email';
|
|
175
491
|
|
|
176
|
-
--
|
|
492
|
+
-- Sites with access
|
|
177
493
|
SELECT
|
|
178
494
|
s.name as site_name,
|
|
179
495
|
s.domain as site_url,
|
|
180
|
-
'Has Access' as status,
|
|
181
496
|
da.created_at as access_granted
|
|
182
497
|
FROM docbuilder_access da
|
|
183
498
|
JOIN auth.users u ON u.id = da.user_id
|
|
184
499
|
JOIN docbuilder_sites s ON s.id = da.site_id
|
|
185
|
-
WHERE u.email = '$
|
|
500
|
+
WHERE u.email = '$email'
|
|
501
|
+
ORDER BY da.created_at DESC;
|
|
186
502
|
|
|
187
|
-
--
|
|
188
|
-
SELECT
|
|
189
|
-
s.name as site_name,
|
|
190
|
-
s.domain as site_url,
|
|
191
|
-
da.created_at as access_granted
|
|
503
|
+
-- Count
|
|
504
|
+
SELECT COUNT(*) as total_sites
|
|
192
505
|
FROM docbuilder_access da
|
|
193
506
|
JOIN auth.users u ON u.id = da.user_id
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
EOF
|
|
507
|
+
WHERE u.email = '$email';
|
|
508
|
+
"
|
|
509
|
+
|
|
510
|
+
execute_sql "$sql"
|
|
199
511
|
}
|
|
200
512
|
|
|
201
|
-
#
|
|
202
|
-
|
|
203
|
-
local site_url
|
|
204
|
-
local email
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
513
|
+
# Remove user access
|
|
514
|
+
remove_access() {
|
|
515
|
+
local site_url="$1"
|
|
516
|
+
local email="$2"
|
|
517
|
+
|
|
518
|
+
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
519
|
+
echo -e "${BOLD}Removing Access${NC}"
|
|
520
|
+
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
521
|
+
echo -e "Site: ${CYAN}$site_url${NC}"
|
|
522
|
+
echo -e "Email: ${CYAN}$email${NC}"
|
|
523
|
+
echo
|
|
524
|
+
|
|
525
|
+
# Confirm
|
|
526
|
+
echo -e "${YELLOW}Are you sure you want to remove access? (y/N)${NC}"
|
|
527
|
+
read -p "> " confirm
|
|
528
|
+
|
|
529
|
+
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
|
|
530
|
+
echo -e "${YELLOW}Cancelled${NC}"
|
|
531
|
+
return
|
|
532
|
+
fi
|
|
533
|
+
|
|
534
|
+
local sql="
|
|
535
|
+
-- Remove access
|
|
214
536
|
DELETE FROM docbuilder_access
|
|
215
|
-
WHERE user_id = (SELECT id FROM auth.users WHERE email = '$
|
|
216
|
-
AND site_id = (SELECT id FROM docbuilder_sites WHERE domain = '$
|
|
537
|
+
WHERE user_id = (SELECT id FROM auth.users WHERE email = '$email')
|
|
538
|
+
AND site_id = (SELECT id FROM docbuilder_sites WHERE domain = '$site_url');
|
|
217
539
|
|
|
218
540
|
-- Verify removal
|
|
219
541
|
SELECT
|
|
@@ -224,7 +546,7 @@ SELECT
|
|
|
224
546
|
FROM docbuilder_access da
|
|
225
547
|
JOIN auth.users u ON u.id = da.user_id
|
|
226
548
|
JOIN docbuilder_sites s ON s.id = da.site_id
|
|
227
|
-
WHERE u.email = '$
|
|
549
|
+
WHERE u.email = '$email' AND s.domain = '$site_url';
|
|
228
550
|
|
|
229
551
|
-- Show remaining sites for this user
|
|
230
552
|
SELECT
|
|
@@ -234,124 +556,175 @@ SELECT
|
|
|
234
556
|
FROM docbuilder_access da
|
|
235
557
|
JOIN auth.users u ON u.id = da.user_id
|
|
236
558
|
JOIN docbuilder_sites s ON s.id = da.site_id
|
|
237
|
-
WHERE u.email = '$
|
|
559
|
+
WHERE u.email = '$email'
|
|
238
560
|
ORDER BY da.created_at DESC;
|
|
561
|
+
"
|
|
562
|
+
|
|
563
|
+
if execute_sql "$sql"; then
|
|
564
|
+
echo -e "${GREEN}✅ Access removed${NC}"
|
|
565
|
+
else
|
|
566
|
+
echo -e "${RED}❌ Failed to remove access${NC}"
|
|
567
|
+
fi
|
|
568
|
+
}
|
|
239
569
|
|
|
240
|
-
|
|
570
|
+
# List all sites
|
|
571
|
+
list_sites() {
|
|
572
|
+
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
573
|
+
echo -e "${BOLD}All Documentation Sites${NC}"
|
|
574
|
+
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
575
|
+
|
|
576
|
+
local sql="
|
|
577
|
+
SELECT
|
|
578
|
+
id as site_id,
|
|
579
|
+
domain,
|
|
580
|
+
name,
|
|
581
|
+
created_at,
|
|
582
|
+
(SELECT COUNT(*) FROM docbuilder_access WHERE site_id = docbuilder_sites.id) as user_count
|
|
583
|
+
FROM docbuilder_sites
|
|
584
|
+
ORDER BY created_at DESC;
|
|
585
|
+
"
|
|
586
|
+
|
|
587
|
+
execute_sql "$sql"
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
# Delete user completely
|
|
591
|
+
delete_user() {
|
|
592
|
+
local email="$1"
|
|
593
|
+
|
|
594
|
+
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
595
|
+
echo -e "${BOLD}${RED}⚠️ REMOVE USER ACCESS - NOT DELETE ⚠️${NC}"
|
|
596
|
+
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
|
|
597
|
+
echo -e "Email: ${CYAN}$email${NC}"
|
|
598
|
+
echo
|
|
599
|
+
echo -e "${YELLOW}Note: Supabase CLI cannot delete users directly.${NC}"
|
|
600
|
+
echo -e "${YELLOW}This will remove the user's access to ALL sites.${NC}"
|
|
601
|
+
echo -e "${YELLOW}To fully delete, use Supabase dashboard.${NC}"
|
|
602
|
+
echo
|
|
603
|
+
echo -e "${YELLOW}Type 'REMOVE' to confirm:${NC}"
|
|
604
|
+
read -p "> " confirm
|
|
605
|
+
|
|
606
|
+
if [[ "$confirm" != "REMOVE" ]]; then
|
|
607
|
+
echo -e "${YELLOW}Cancelled${NC}"
|
|
608
|
+
return
|
|
609
|
+
fi
|
|
610
|
+
|
|
611
|
+
echo -e "${BLUE}Removing all access...${NC}"
|
|
612
|
+
|
|
613
|
+
local sql="
|
|
614
|
+
-- Remove all access for user
|
|
615
|
+
DELETE FROM docbuilder_access
|
|
616
|
+
WHERE user_id = (SELECT id FROM auth.users WHERE email = '$email');
|
|
617
|
+
|
|
618
|
+
-- Show result
|
|
619
|
+
SELECT
|
|
620
|
+
CASE
|
|
621
|
+
WHEN COUNT(*) = 0 THEN 'All access removed successfully'
|
|
622
|
+
ELSE 'ERROR: User still has some access'
|
|
623
|
+
END as status
|
|
624
|
+
FROM docbuilder_access da
|
|
625
|
+
JOIN auth.users u ON u.id = da.user_id
|
|
626
|
+
WHERE u.email = '$email';
|
|
627
|
+
"
|
|
628
|
+
|
|
629
|
+
if execute_sql "$sql"; then
|
|
630
|
+
echo -e "${GREEN}✅ All access removed${NC}"
|
|
631
|
+
echo -e "${CYAN}To fully delete user, go to:${NC}"
|
|
632
|
+
echo -e "${CYAN}https://supabase.com/dashboard/project/$PROJECT_ID/auth/users${NC}"
|
|
633
|
+
else
|
|
634
|
+
echo -e "${RED}❌ Failed to remove access${NC}"
|
|
635
|
+
fi
|
|
241
636
|
}
|
|
242
637
|
|
|
243
638
|
# Main script logic
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
sql)
|
|
337
|
-
echo -e "${BLUE}Generating all SQL templates${NC}"
|
|
338
|
-
echo "-- Example: List all sites"
|
|
339
|
-
generate_sites_sql
|
|
340
|
-
echo ""
|
|
341
|
-
echo "-- Example: Add user"
|
|
342
|
-
generate_add_sql "example-docs.vercel.app" "user@example.com"
|
|
343
|
-
echo ""
|
|
344
|
-
echo "-- Example: List users"
|
|
345
|
-
generate_list_sql "example-docs.vercel.app"
|
|
346
|
-
echo ""
|
|
347
|
-
echo "-- Example: Check user"
|
|
348
|
-
generate_check_sql "example-docs.vercel.app" "user@example.com"
|
|
349
|
-
echo ""
|
|
350
|
-
echo "-- Example: Remove user"
|
|
351
|
-
generate_remove_sql "example-docs.vercel.app" "user@example.com"
|
|
352
|
-
;;
|
|
353
|
-
|
|
354
|
-
*)
|
|
355
|
-
show_help
|
|
356
|
-
;;
|
|
357
|
-
esac
|
|
639
|
+
main() {
|
|
640
|
+
case "$1" in
|
|
641
|
+
setup)
|
|
642
|
+
setup_project
|
|
643
|
+
;;
|
|
644
|
+
|
|
645
|
+
add)
|
|
646
|
+
if [ -z "$2" ] || [ -z "$3" ]; then
|
|
647
|
+
echo -e "${RED}❌ Missing parameters${NC}"
|
|
648
|
+
echo -e "${YELLOW}Usage: $0 add <site-url> <email>${NC}"
|
|
649
|
+
echo -e "${CYAN}Example: $0 add docs.example.com user@email.com${NC}"
|
|
650
|
+
exit 1
|
|
651
|
+
fi
|
|
652
|
+
check_supabase_cli
|
|
653
|
+
check_supabase_login
|
|
654
|
+
add_user "$2" "$3"
|
|
655
|
+
;;
|
|
656
|
+
|
|
657
|
+
bulk)
|
|
658
|
+
if [ -z "$2" ] || [ -z "$3" ]; then
|
|
659
|
+
echo -e "${RED}❌ Missing parameters${NC}"
|
|
660
|
+
echo -e "${YELLOW}Usage: $0 bulk <site-url> <file>${NC}"
|
|
661
|
+
echo -e "${CYAN}Example: $0 bulk docs.example.com users.txt${NC}"
|
|
662
|
+
exit 1
|
|
663
|
+
fi
|
|
664
|
+
check_supabase_cli
|
|
665
|
+
check_supabase_login
|
|
666
|
+
bulk_add "$2" "$3"
|
|
667
|
+
;;
|
|
668
|
+
|
|
669
|
+
list)
|
|
670
|
+
if [ -z "$2" ]; then
|
|
671
|
+
echo -e "${RED}❌ Missing site URL${NC}"
|
|
672
|
+
echo -e "${YELLOW}Usage: $0 list <site-url>${NC}"
|
|
673
|
+
echo -e "${CYAN}Example: $0 list docs.example.com${NC}"
|
|
674
|
+
exit 1
|
|
675
|
+
fi
|
|
676
|
+
check_supabase_cli
|
|
677
|
+
check_supabase_login
|
|
678
|
+
list_users "$2"
|
|
679
|
+
;;
|
|
680
|
+
|
|
681
|
+
check)
|
|
682
|
+
if [ -z "$2" ]; then
|
|
683
|
+
echo -e "${RED}❌ Missing email${NC}"
|
|
684
|
+
echo -e "${YELLOW}Usage: $0 check <email>${NC}"
|
|
685
|
+
echo -e "${CYAN}Example: $0 check user@email.com${NC}"
|
|
686
|
+
exit 1
|
|
687
|
+
fi
|
|
688
|
+
check_supabase_cli
|
|
689
|
+
check_supabase_login
|
|
690
|
+
check_user "$2"
|
|
691
|
+
;;
|
|
692
|
+
|
|
693
|
+
remove)
|
|
694
|
+
if [ -z "$2" ] || [ -z "$3" ]; then
|
|
695
|
+
echo -e "${RED}❌ Missing parameters${NC}"
|
|
696
|
+
echo -e "${YELLOW}Usage: $0 remove <site-url> <email>${NC}"
|
|
697
|
+
echo -e "${CYAN}Example: $0 remove docs.example.com user@email.com${NC}"
|
|
698
|
+
exit 1
|
|
699
|
+
fi
|
|
700
|
+
check_supabase_cli
|
|
701
|
+
check_supabase_login
|
|
702
|
+
remove_access "$2" "$3"
|
|
703
|
+
;;
|
|
704
|
+
|
|
705
|
+
sites)
|
|
706
|
+
check_supabase_cli
|
|
707
|
+
check_supabase_login
|
|
708
|
+
list_sites
|
|
709
|
+
;;
|
|
710
|
+
|
|
711
|
+
delete-user)
|
|
712
|
+
if [ -z "$2" ]; then
|
|
713
|
+
echo -e "${RED}❌ Missing email${NC}"
|
|
714
|
+
echo -e "${YELLOW}Usage: $0 delete-user <email>${NC}"
|
|
715
|
+
echo -e "${CYAN}Example: $0 delete-user user@email.com${NC}"
|
|
716
|
+
exit 1
|
|
717
|
+
fi
|
|
718
|
+
check_supabase_cli
|
|
719
|
+
check_supabase_login
|
|
720
|
+
delete_user "$2"
|
|
721
|
+
;;
|
|
722
|
+
|
|
723
|
+
*)
|
|
724
|
+
show_help
|
|
725
|
+
;;
|
|
726
|
+
esac
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
# Run main function
|
|
730
|
+
main "$@"
|