| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- /**
- * 创建 Contact(联系人)和 WebhookLog(系统事件日志)表
- *
- * 用法: cd backend && npx tsx scripts/create-contact-webhooklog-schema.ts
- *
- * 幂等:可重复执行,已存在的字段自动跳过
- */
- import 'dotenv/config';
- import Parse from '../src/db/parse-client.js';
- async function testConnection(): Promise<void> {
- try {
- const n = await new Parse.Query('_User').count({ useMasterKey: true });
- console.log(`✅ Parse 连接正常 (_User: ${n} 条)\n`);
- } catch (err: any) {
- console.error(`❌ Parse 连接失败: ${err.message}`);
- process.exit(1);
- }
- }
- async function ensureClassExists(className: string): Promise<void> {
- try {
- await new Parse.Schema(className).get({ useMasterKey: true });
- } catch {
- // 类不存在,创建一条空记录来建表,然后立即删除
- const tmp = new Parse.Object(className);
- tmp.set('_placeholder', true);
- await tmp.save(null, { useMasterKey: true });
- await tmp.destroy({ useMasterKey: true });
- console.log(` 📦 ${className} 表已创建`);
- }
- }
- /* ═══════════════════════════════════════════════
- 1. Contact(联系人表)
- ═══════════════════════════════════════════════ */
- async function createContactTable(): Promise<void> {
- console.log('═══ 1/3 Contact(联系人表)═══');
- await ensureClassExists('Contact');
- const schema = new Parse.Schema('Contact');
- const fields: Array<{ name: string; type: string }> = [
- { name: 'userId', type: 'String' },
- { name: 'guid', type: 'String' },
- { name: 'nickname', type: 'String' },
- { name: 'realName', type: 'String' },
- { name: 'remark', type: 'String' },
- { name: 'avatar', type: 'String' },
- { name: 'sex', type: 'Number' },
- { name: 'phone', type: 'String' },
- { name: 'corpName', type: 'String' },
- { name: 'corpFullName', type: 'String' },
- { name: 'corpId', type: 'String' },
- { name: 'position', type: 'String' },
- { name: 'alias', type: 'String' },
- { name: 'unionid', type: 'String' },
- { name: 'addTime', type: 'Number' },
- { name: 'contactType', type: 'Number' },
- { name: 'partyId', type: 'String' },
- { name: 'status', type: 'String' },
- ];
- for (const f of fields) {
- try {
- await schema.addField(f.name, f.type);
- console.log(` + ${f.name} (${f.type})`);
- } catch (err: any) {
- if (err.message?.includes('already')) {
- console.log(` ~ ${f.name} 已存在`);
- } else {
- console.warn(` ⚠ ${f.name} 添加失败: ${err.message}`);
- }
- }
- }
- // CLP 权限:仅 masterKey 可读写
- try {
- await schema.setCLP({
- find: { 'requiresAuthentication': true },
- get: { 'requiresAuthentication': true },
- create: { 'requiresAuthentication': true },
- update: { 'requiresAuthentication': true },
- delete: { 'requiresAuthentication': true },
- });
- } catch { /* CLP 设置失败不阻塞 */ }
- await schema.update({ useMasterKey: true });
- console.log(' Contact 表更新完成\n');
- }
- /* ═══════════════════════════════════════════════
- 2. WebhookLog(系统事件日志表)
- ═══════════════════════════════════════════════ */
- async function createWebhookLogTable(): Promise<void> {
- console.log('═══ 2/3 WebhookLog(系统事件日志表)═══');
- await ensureClassExists('WebhookLog');
- const schema = new Parse.Schema('WebhookLog');
- const fields: Array<{ name: string; type: string }> = [
- { name: 'guid', type: 'String' },
- { name: 'cmd', type: 'Number' },
- { name: 'msgType', type: 'Number' },
- { name: 'msgData', type: 'Object' },
- { name: 'timestamp', type: 'Date' },
- ];
- for (const f of fields) {
- try {
- await schema.addField(f.name, f.type);
- console.log(` + ${f.name} (${f.type})`);
- } catch (err: any) {
- if (err.message?.includes('already')) {
- console.log(` ~ ${f.name} 已存在`);
- } else {
- console.warn(` ⚠ ${f.name} 添加失败: ${err.message}`);
- }
- }
- }
- // CLP 权限
- try {
- await schema.setCLP({
- find: { 'requiresAuthentication': true },
- get: { 'requiresAuthentication': true },
- create: { 'requiresAuthentication': true },
- update: { 'requiresAuthentication': true },
- delete: { 'requiresAuthentication': true },
- });
- } catch { /* CLP 设置失败不阻塞 */ }
- await schema.update({ useMasterKey: true });
- console.log(' WebhookLog 表更新完成\n');
- }
- /* ═══════════════════════════════════════════════
- 3. GroupChat 补字段(ownerName)
- ═══════════════════════════════════════════════ */
- async function ensureGroupChatOwnerName(): Promise<void> {
- console.log('═══ 3/3 GroupChat 补 ownerName 字段 ═══');
- const schema = new Parse.Schema('GroupChat');
- try {
- await schema.addField('ownerName', 'String');
- console.log(' + ownerName (String)');
- } catch (err: any) {
- if (err.message?.includes('already')) {
- console.log(' ~ ownerName 已存在');
- } else {
- console.warn(` ⚠ ownerName 添加失败: ${err.message}`);
- }
- }
- await schema.update({ useMasterKey: true });
- console.log(' GroupChat 表更新完成\n');
- }
- /* ═══════════════════════════════════════════════
- Main
- ═══════════════════════════════════════════════ */
- async function main(): Promise<void> {
- console.log('=== Contact + WebhookLog 表创建 & GroupChat 字段补全 ===');
- console.log(`Server: ${Parse.serverURL}`);
- console.log(`App ID: ${Parse.applicationId}\n`);
- await testConnection();
- await createContactTable();
- await createWebhookLogTable();
- await ensureGroupChatOwnerName();
- console.log('=== 完成 ===\n');
- }
- main().catch((err) => {
- console.error('创建失败:', err.message);
- process.exit(1);
- });
|