seed-lobster-channel-data.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. const mysql = require('mysql2/promise')
  2. const BUILTIN = ['QW', 'WX', 'IM']
  3. /** Keep in sync with ChannelTypeRegistry.registerDefaults() */
  4. const ALL_CHANNELS = [
  5. 'QW', 'WX', 'IM',
  6. 'WHATSAPP', 'LINE', 'TELEGRAM', 'APP_IM',
  7. 'TMALL', 'JD', 'DOUYIN_DM', 'KUAISHOU_DM', 'XIAOHONGSHU_DM', 'DOUYIN_EC', 'OTHER'
  8. ]
  9. const DB_CFG = {
  10. host: 'cq-cdb-8fjmemkb.sql.tencentcdb.com',
  11. port: 27220,
  12. user: 'root',
  13. password: 'Ylrz_1q2w3e4r5t6y',
  14. multipleStatements: true
  15. }
  16. function dbNameFromUrl(url) {
  17. if (!url) return null
  18. const m = String(url).match(/\/([^/?]+)(?:\?|$)/)
  19. return m ? m[1] : null
  20. }
  21. async function seedMasterGrants(conn) {
  22. const [result] = await conn.query(`
  23. INSERT IGNORE INTO lobster_tenant_channel_grant (tenant_id, channel_type, granted, create_by)
  24. SELECT t.id, ch.channel_type, 1, 'seed'
  25. FROM tenant_info t
  26. CROSS JOIN (
  27. SELECT 'QW' AS channel_type
  28. UNION ALL SELECT 'WX'
  29. UNION ALL SELECT 'IM'
  30. ) ch
  31. WHERE t.id IS NOT NULL
  32. `)
  33. return result.affectedRows || 0
  34. }
  35. async function seedTenantPluginConfig(conn) {
  36. let inserted = 0
  37. for (const channelType of ALL_CHANNELS) {
  38. const enabled = BUILTIN.includes(channelType) ? 1 : 0
  39. const [result] = await conn.query(
  40. `INSERT IGNORE INTO lobster_channel_plugin_config (company_id, channel_type, enabled, config_json)
  41. VALUES (0, ?, ?, '{}')`,
  42. [channelType, enabled]
  43. )
  44. inserted += result.affectedRows || 0
  45. }
  46. return inserted
  47. }
  48. async function ensureChannelAccountTable(conn) {
  49. await conn.query(`
  50. CREATE TABLE IF NOT EXISTS lobster_channel_account (
  51. id BIGINT AUTO_INCREMENT PRIMARY KEY,
  52. company_id BIGINT NOT NULL COMMENT 'tenant-level uses 0',
  53. channel_type VARCHAR(30) NOT NULL COMMENT 'WHATSAPP/TMALL/DOUYIN_DM/...',
  54. account_code VARCHAR(64) NOT NULL COMMENT 'unique code within channel',
  55. account_name VARCHAR(128) DEFAULT NULL,
  56. config_json TEXT,
  57. enabled TINYINT DEFAULT 1,
  58. is_default TINYINT DEFAULT 0,
  59. sort_order INT DEFAULT 0,
  60. create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
  61. update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  62. UNIQUE KEY uk_company_channel_account (company_id, channel_type, account_code),
  63. KEY idx_company_channel (company_id, channel_type)
  64. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
  65. `)
  66. const [result] = await conn.query(`
  67. INSERT IGNORE INTO lobster_channel_account (
  68. company_id, channel_type, account_code, account_name, config_json, enabled, is_default, sort_order
  69. )
  70. SELECT
  71. p.company_id,
  72. p.channel_type,
  73. 'default',
  74. CONCAT(p.channel_type, '-default'),
  75. COALESCE(NULLIF(p.config_json, ''), '{}'),
  76. COALESCE(p.enabled, 0),
  77. 1,
  78. 0
  79. FROM lobster_channel_plugin_config p
  80. WHERE p.channel_type NOT IN ('QW', 'WX', 'IM')
  81. `)
  82. return result.affectedRows || 0
  83. }
  84. async function main() {
  85. const masterConn = await mysql.createConnection({ ...DB_CFG, database: 'ylrz_saas' })
  86. const tenantDbs = new Set()
  87. try {
  88. const [tenants] = await masterConn.query(
  89. 'SELECT id, tenant_code, db_url FROM tenant_info WHERE db_url IS NOT NULL AND db_url != \'\''
  90. )
  91. for (const t of tenants) {
  92. const name = dbNameFromUrl(t.db_url)
  93. if (name) tenantDbs.add(name)
  94. }
  95. } catch (e) {
  96. console.warn('tenant_info query skipped:', e.message)
  97. }
  98. const grantInserted = await seedMasterGrants(masterConn)
  99. const [grantCount] = await masterConn.query(
  100. 'SELECT COUNT(*) AS c FROM lobster_tenant_channel_grant WHERE granted = 1'
  101. )
  102. console.log(`master(ylrz_saas): grant inserted=${grantInserted}, total granted rows=${grantCount[0].c}`)
  103. await masterConn.end()
  104. for (const db of tenantDbs) {
  105. try {
  106. const conn = await mysql.createConnection({ ...DB_CFG, database: db })
  107. const n = await seedTenantPluginConfig(conn)
  108. const migrated = await ensureChannelAccountTable(conn)
  109. const [rows] = await conn.query(
  110. 'SELECT COUNT(*) AS c FROM lobster_channel_plugin_config WHERE company_id = 0'
  111. )
  112. const [accRows] = await conn.query(
  113. 'SELECT COUNT(*) AS c FROM lobster_channel_account WHERE company_id = 0'
  114. )
  115. await conn.end()
  116. console.log(`${db}: plugin inserted=${n}, account migrated=${migrated}, plugin rows=${rows[0].c}, account rows=${accRows[0].c}`)
  117. } catch (e) {
  118. console.error(`${db}: ERROR ${e.message}`)
  119. }
  120. }
  121. }
  122. main().catch(e => {
  123. console.error(e)
  124. process.exit(1)
  125. })