iyougame commited on
Commit
c487d6b
·
verified ·
1 Parent(s): a05246c

Update supabase-client.js

Browse files
Files changed (1) hide show
  1. supabase-client.js +87 -118
supabase-client.js CHANGED
@@ -1,6 +1,5 @@
1
  /**
2
- * Supabase Database Client
3
- * Handles all database operations for MindVideo accounts
4
  */
5
 
6
  import { createClient } from '@supabase/supabase-js';
@@ -38,20 +37,36 @@ export function getSupabase() {
38
  export async function saveAccount(accountData) {
39
  const db = getSupabase();
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  const { data, error } = await db
42
  .from('accounts')
43
- .upsert({
44
- email: accountData.email,
45
- password: accountData.password,
46
- token: accountData.token,
47
- // If user_id is missing (e.g. during import), use a temporary placeholder
48
- user_id: accountData.user_id || `pending_${accountData.email}`,
49
- status: accountData.status || 'active',
50
- last_login_at: new Date().toISOString(),
51
- expire_at: accountData.expire_at,
52
- metadata: accountData.metadata || {},
53
- updated_at: new Date().toISOString()
54
- }, {
55
  onConflict: 'email'
56
  })
57
  .select()
@@ -67,154 +82,108 @@ export async function saveAccount(accountData) {
67
 
68
  export async function getAccount(email) {
69
  const db = getSupabase();
70
-
71
- const { data, error } = await db
72
- .from('accounts')
73
- .select('*')
74
- .eq('email', email)
75
- .single();
76
-
77
- if (error && error.code !== 'PGRST116') { // PGRST116 = not found
78
- console.error('❌ Failed to get account:', error.message);
79
- throw error;
80
- }
81
-
82
  return data;
83
  }
84
 
85
  export async function getAllAccounts(status = null) {
86
  const db = getSupabase();
87
-
88
  let query = db.from('accounts').select('*').order('created_at', { ascending: false });
89
-
90
- if (status) {
91
- query = query.eq('status', status);
92
- }
93
-
94
  const { data, error } = await query;
95
-
96
- if (error) {
97
- console.error('❌ Failed to get accounts:', error.message);
98
- throw error;
99
- }
100
-
101
  return data || [];
102
  }
103
 
104
- export async function updateAccountStatus(email, status) {
105
- const db = getSupabase();
106
-
107
- const { data, error } = await db
108
- .from('accounts')
109
- .update({
110
- status,
111
- updated_at: new Date().toISOString()
112
- })
113
- .eq('email', email)
114
- .select()
115
- .single();
116
-
117
- if (error) {
118
- console.error('❌ Failed to update account status:', error.message);
119
- throw error;
120
- }
121
-
122
- return data;
123
- }
124
-
125
  export async function updateAccountToken(email, token, expireAt, metadata = null) {
126
- const db = getSupabase();
127
-
128
  const updateData = {
 
129
  token,
130
  expire_at: expireAt,
131
- last_login_at: new Date().toISOString(),
132
- updated_at: new Date().toISOString()
133
  };
134
-
135
- if (metadata) {
136
- updateData.metadata = metadata;
137
- }
138
-
139
- const { data, error } = await db
140
- .from('accounts')
141
- .update(updateData)
142
- .eq('email', email)
143
- .select()
144
- .single();
145
-
146
- if (error) {
147
- console.error('❌ Failed to update account token:', error.message);
148
- throw error;
149
- }
150
-
151
- return data;
152
  }
153
 
154
  /**
155
- * System Logs
 
156
  */
157
- export async function logSystem(level, module, message, details = {}) {
 
158
  const db = getSupabase();
159
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  const { error } = await db
161
- .from('system_logs')
162
- .insert({
163
- level,
164
- module,
165
- message,
166
- details,
167
- created_at: new Date().toISOString()
168
  });
169
 
170
  if (error) {
171
- console.error('❌ Failed to log system event:', error.message);
 
 
172
  }
173
  }
174
 
175
  /**
176
- * Import accounts from KV or JSON data
177
  */
178
- export async function importAccounts(accountsData) {
179
  const db = getSupabase();
180
- const results = {
181
- success: 0,
182
- failed: 0,
183
- errors: []
184
- };
 
 
 
 
 
 
 
185
 
 
 
 
186
  for (const account of accountsData) {
187
  try {
188
  await saveAccount(account);
189
  results.success++;
190
  } catch (error) {
191
  results.failed++;
192
- results.errors.push({
193
- email: account.email,
194
- error: error.message
195
- });
196
  }
197
  }
198
-
199
- await logSystem('info', 'import', `Imported ${results.success} accounts`, results);
200
-
201
  return results;
202
  }
203
 
204
- /**
205
- * Get account statistics
206
- */
207
  export async function getAccountStats() {
208
  const db = getSupabase();
209
-
210
- const { data, error } = await db
211
- .from('account_statistics')
212
- .select('*');
213
-
214
- if (error) {
215
- console.error('❌ Failed to get account statistics:', error.message);
216
- return null;
217
- }
218
-
219
  return data;
220
  }
 
1
  /**
2
+ * Supabase Database Client (Updated for New Schema)
 
3
  */
4
 
5
  import { createClient } from '@supabase/supabase-js';
 
37
  export async function saveAccount(accountData) {
38
  const db = getSupabase();
39
 
40
+ // 准备数据,移除 undefined 的字段以避免覆盖
41
+ const upsertData = {
42
+ email: accountData.email,
43
+ updated_at: new Date().toISOString()
44
+ };
45
+
46
+ if (accountData.password) upsertData.password = accountData.password;
47
+ if (accountData.token) upsertData.token = accountData.token;
48
+ if (accountData.user_id) upsertData.user_id = accountData.user_id;
49
+ if (accountData.status) upsertData.status = accountData.status;
50
+ if (accountData.expire_at) upsertData.expire_at = accountData.expire_at;
51
+ if (accountData.last_login_at) upsertData.last_login_at = accountData.last_login_at;
52
+
53
+ // 如果是新插入且没有 user_id,生成一个临时的 (为了满足 NOT NULL 约束)
54
+ // 注意:这里使用 onConflict: email,所以如果 user_id 变了(从 pending 变成真实 ID),也能更新
55
+ const { data: existing } = await db.from('accounts').select('user_id').eq('email', accountData.email).single();
56
+ if (!existing && !accountData.user_id) {
57
+ upsertData.user_id = `pending_${accountData.email}`;
58
+ }
59
+
60
+ // 合并 metadata 而不是直接覆盖
61
+ if (accountData.metadata) {
62
+ // 这一步在 SQL 中比较复杂,这里简化处理:读取-合并-写入,或者直接覆盖
63
+ // 如果为了性能,可以直接覆盖,因为我们通常是获取了最新全量数据
64
+ upsertData.metadata = accountData.metadata;
65
+ }
66
+
67
  const { data, error } = await db
68
  .from('accounts')
69
+ .upsert(upsertData, {
 
 
 
 
 
 
 
 
 
 
 
70
  onConflict: 'email'
71
  })
72
  .select()
 
82
 
83
  export async function getAccount(email) {
84
  const db = getSupabase();
85
+ const { data, error } = await db.from('accounts').select('*').eq('email', email).single();
86
+ if (error && error.code !== 'PGRST116') throw error;
 
 
 
 
 
 
 
 
 
 
87
  return data;
88
  }
89
 
90
  export async function getAllAccounts(status = null) {
91
  const db = getSupabase();
 
92
  let query = db.from('accounts').select('*').order('created_at', { ascending: false });
93
+ if (status) query = query.eq('status', status);
 
 
 
 
94
  const { data, error } = await query;
95
+ if (error) throw error;
 
 
 
 
 
96
  return data || [];
97
  }
98
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  export async function updateAccountToken(email, token, expireAt, metadata = null) {
100
+ // 复用 saveAccount 逻辑,更加健壮
 
101
  const updateData = {
102
+ email,
103
  token,
104
  expire_at: expireAt,
105
+ last_login_at: new Date().toISOString()
 
106
  };
107
+ if (metadata) updateData.metadata = metadata;
108
+ return await saveAccount(updateData);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  }
110
 
111
  /**
112
+ * [NEW] Creations Operations
113
+ * 将 API 返回的列表保存到 creations 表
114
  */
115
+ export async function saveCreations(userId, creationsList) {
116
+ if (!creationsList || creationsList.length === 0) return;
117
  const db = getSupabase();
118
 
119
+ // 映射 API 数据到数据库表结构
120
+ const records = creationsList.map(item => ({
121
+ creation_id: item.id,
122
+ user_id: userId, // 外键,必须存在于 accounts 表
123
+ type: item.type || 'video', // 默认为 video,根据实际 API 调整
124
+ status: item.status === 1 ? 'success' : (item.status === 2 ? 'failed' : 'processing'),
125
+ prompt: item.prompt || item.title, // API 可能用 title 或 prompt
126
+ url: item.file_url || item.url || item.video_url,
127
+ thumbnail_url: item.cover_url,
128
+ metadata: {
129
+ duration: item.duration,
130
+ ratio: item.ratio,
131
+ engine: item.engine
132
+ },
133
+ created_at: item.created_at ? new Date(item.created_at).toISOString() : null,
134
+ fetched_at: new Date().toISOString()
135
+ }));
136
+
137
  const { error } = await db
138
+ .from('creations')
139
+ .upsert(records, {
140
+ onConflict: 'creation_id' // 根据 creation_id 去重更新
 
 
 
 
141
  });
142
 
143
  if (error) {
144
+ console.error(`❌ Failed to save creations for user ${userId}:`, error.message);
145
+ } else {
146
+ console.log(`💾 Saved ${records.length} creations for user ${userId}`);
147
  }
148
  }
149
 
150
  /**
151
+ * System Logs
152
  */
153
+ export async function logSystem(level, module, message, details = {}) {
154
  const db = getSupabase();
155
+ // 尝试获取 details 中的 email 或 user_id 来填充字段 (可选优化)
156
+ const userId = details.user_id || null;
157
+
158
+ await db.from('system_logs').insert({
159
+ level,
160
+ module,
161
+ message,
162
+ details,
163
+ user_id: userId,
164
+ created_at: new Date().toISOString()
165
+ });
166
+ }
167
 
168
+ // ... importAccounts 等其他函数保持兼容性即可 ...
169
+ export async function importAccounts(accountsData) {
170
+ const results = { success: 0, failed: 0, errors: [] };
171
  for (const account of accountsData) {
172
  try {
173
  await saveAccount(account);
174
  results.success++;
175
  } catch (error) {
176
  results.failed++;
177
+ results.errors.push({ email: account.email, error: error.message });
 
 
 
178
  }
179
  }
 
 
 
180
  return results;
181
  }
182
 
 
 
 
183
  export async function getAccountStats() {
184
  const db = getSupabase();
185
+ // 使用你新建的视图
186
+ const { data, error } = await db.from('account_statistics').select('*');
187
+ if (error) return null;
 
 
 
 
 
 
 
188
  return data;
189
  }