ApplyLobsterForbiddenTypoMenus.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. import java.sql.*;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import java.util.stream.Collectors;
  5. /**
  6. * Apply forbidden/typo word menus to master + all tenant DBs.
  7. * Usage:
  8. * java -cp ".;mysql-connector-j.jar" ApplyLobsterForbiddenTypoMenus
  9. */
  10. public class ApplyLobsterForbiddenTypoMenus {
  11. private static final String MASTER_HOST = getenv("DB_HOST", "cq-cdb-8fjmemkb.sql.tencentcdb.com");
  12. private static final int MASTER_PORT = Integer.parseInt(getenv("DB_PORT", "27220"));
  13. private static final String MASTER_USER = getenv("DB_USER", "root");
  14. private static final String MASTER_PASSWORD = getenv("DB_PASSWORD", "Ylrz_1q2w3e4r5t6y");
  15. private static final String MASTER_DB = getenv("DB_NAME", "ylrz_saas");
  16. public static void main(String[] args) throws Exception {
  17. String masterSql = MASTER_SQL;
  18. String tenantSql = TENANT_SQL;
  19. System.out.println("[MASTER] " + MASTER_DB);
  20. try (Connection master = open(MASTER_HOST, MASTER_PORT, MASTER_DB, MASTER_USER, MASTER_PASSWORD)) {
  21. execSqlBatch(master, masterSql);
  22. System.out.println("[OK] master menus applied");
  23. List<Long> tenantIds = loadActiveTenantIds(master);
  24. for (Long tenantId : tenantIds) {
  25. TenantDb tenant = loadTenant(master, tenantId);
  26. if (tenant == null) {
  27. System.err.println("[SKIP] tenant " + tenantId);
  28. continue;
  29. }
  30. System.out.println("[TENANT] " + tenantId + " -> " + tenant.database);
  31. try (Connection tenantConn = open(tenant.host, tenant.port, tenant.database, tenant.user, tenant.password)) {
  32. execSqlBatch(tenantConn, tenantSql);
  33. }
  34. System.out.println("[OK] tenant " + tenantId);
  35. }
  36. }
  37. }
  38. private static void execSqlBatch(Connection conn, String sql) throws SQLException {
  39. List<String> statements = splitStatements(sql);
  40. try (Statement st = conn.createStatement()) {
  41. for (String s : statements) {
  42. st.execute(s);
  43. }
  44. }
  45. }
  46. private static List<String> splitStatements(String sql) {
  47. return java.util.Arrays.stream(sql.split(";"))
  48. .map(String::trim)
  49. .filter(s -> !s.isEmpty() && !s.startsWith("--"))
  50. .map(s -> {
  51. String[] lines = s.split("\n");
  52. StringBuilder sb = new StringBuilder();
  53. for (String line : lines) {
  54. String t = line.trim();
  55. if (t.startsWith("--")) continue;
  56. sb.append(line).append('\n');
  57. }
  58. return sb.toString().trim();
  59. })
  60. .filter(s -> !s.isEmpty())
  61. .collect(Collectors.toList());
  62. }
  63. private static List<Long> loadActiveTenantIds(Connection master) throws SQLException {
  64. List<Long> ids = new ArrayList<>();
  65. try (Statement st = master.createStatement();
  66. ResultSet rs = st.executeQuery("SELECT id FROM tenant_info WHERE status = 1 ORDER BY id")) {
  67. while (rs.next()) ids.add(rs.getLong(1));
  68. }
  69. return ids;
  70. }
  71. private static TenantDb loadTenant(Connection master, long tenantId) throws SQLException {
  72. String sql = "SELECT db_url, db_account, db_pwd FROM tenant_info WHERE id = ? AND status = 1 LIMIT 1";
  73. try (PreparedStatement ps = master.prepareStatement(sql)) {
  74. ps.setLong(1, tenantId);
  75. try (ResultSet rs = ps.executeQuery()) {
  76. if (!rs.next()) return null;
  77. return parseJdbcUrl(rs.getString("db_url"), rs.getString("db_account"), rs.getString("db_pwd"));
  78. }
  79. }
  80. }
  81. private static TenantDb parseJdbcUrl(String jdbcUrl, String user, String password) {
  82. if (jdbcUrl == null || !jdbcUrl.startsWith("jdbc:mysql://")) {
  83. throw new IllegalArgumentException("Unsupported db_url: " + jdbcUrl);
  84. }
  85. String body = jdbcUrl.substring("jdbc:mysql://".length());
  86. int slash = body.indexOf('/');
  87. String hostPort = body.substring(0, slash);
  88. String rest = body.substring(slash + 1);
  89. int q = rest.indexOf('?');
  90. String database = q >= 0 ? rest.substring(0, q) : rest;
  91. String host;
  92. int port;
  93. int colon = hostPort.indexOf(':');
  94. if (colon >= 0) {
  95. host = hostPort.substring(0, colon);
  96. port = Integer.parseInt(hostPort.substring(colon + 1));
  97. } else {
  98. host = hostPort;
  99. port = 3306;
  100. }
  101. TenantDb t = new TenantDb();
  102. t.host = host;
  103. t.port = port;
  104. t.database = database;
  105. t.user = user != null ? user : MASTER_USER;
  106. t.password = password != null ? password : MASTER_PASSWORD;
  107. return t;
  108. }
  109. private static Connection open(String host, int port, String database, String user, String password)
  110. throws SQLException {
  111. String url = "jdbc:mysql://" + host + ":" + port + "/" + database
  112. + "?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&allowMultiQueries=true";
  113. return DriverManager.getConnection(url, user, password);
  114. }
  115. private static String getenv(String key, String defaultValue) {
  116. String v = System.getenv(key);
  117. return v != null && !v.isEmpty() ? v : defaultValue;
  118. }
  119. private static final String MASTER_SQL =
  120. "INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, menu_type, visible, status, perms, icon, is_frame, is_cache, create_by, create_time) "
  121. + "SELECT '\u7981\u7528\u8bcd\u5e93', 2864, 6, 'forbidden-words', 'lobster/replace-words/index', 'C', '0', '0', 'workflow:lobster:replace', 'warning', 0, 0, 'admin', NOW() "
  122. + "FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE parent_id = 2864 AND path = 'forbidden-words');"
  123. + "INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, menu_type, visible, status, perms, icon, is_frame, is_cache, create_by, create_time) "
  124. + "SELECT '\u6613\u9519\u8bcd\u5e93', 2864, 7, 'typo-words', 'lobster/replace-words/index', 'C', '0', '0', 'workflow:lobster:replace', 'edit', 0, 0, 'admin', NOW() "
  125. + "FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE parent_id = 2864 AND path = 'typo-words');"
  126. + "UPDATE sys_menu SET menu_name='\u7981\u7528\u8bcd\u5e93', order_num=6, component='lobster/replace-words/index', icon='warning', visible='0', status='0', perms='workflow:lobster:replace' WHERE parent_id=2864 AND path='forbidden-words';"
  127. + "UPDATE sys_menu SET menu_name='\u6613\u9519\u8bcd\u5e93', order_num=7, component='lobster/replace-words/index', icon='edit', visible='0', status='0', perms='workflow:lobster:replace' WHERE parent_id=2864 AND path='typo-words';"
  128. + "INSERT INTO sys_role_menu (role_id, menu_id) SELECT DISTINCT rm.role_id, m_new.menu_id FROM sys_role_menu rm "
  129. + "JOIN sys_menu m_ref ON rm.menu_id=m_ref.menu_id AND m_ref.parent_id=2864 "
  130. + "JOIN sys_menu m_new ON m_new.parent_id=2864 AND m_new.path='forbidden-words' "
  131. + "WHERE NOT EXISTS (SELECT 1 FROM sys_role_menu x WHERE x.role_id=rm.role_id AND x.menu_id=m_new.menu_id);"
  132. + "INSERT INTO sys_role_menu (role_id, menu_id) SELECT DISTINCT rm.role_id, m_new.menu_id FROM sys_role_menu rm "
  133. + "JOIN sys_menu m_ref ON rm.menu_id=m_ref.menu_id AND m_ref.parent_id=2864 "
  134. + "JOIN sys_menu m_new ON m_new.parent_id=2864 AND m_new.path='typo-words' "
  135. + "WHERE NOT EXISTS (SELECT 1 FROM sys_role_menu x WHERE x.role_id=rm.role_id AND x.menu_id=m_new.menu_id);"
  136. + "INSERT IGNORE INTO tenant_sys_menu (menu_id, menu_name, parent_id, order_num, path, component, menu_type, icon, visible, status, is_frame, is_cache, perms, create_by, create_time, remark) VALUES "
  137. + "(29963, '\u7981\u7528\u8bcd\u5e93', 29900, 29, 'forbidden-words', 'lobster/replace-words/index', 'C', 'el-icon-warning', '0', '0', 0, 0, 'workflow:lobster:replace', 'admin', NOW(), 'forbidden'), "
  138. + "(29964, '\u6613\u9519\u8bcd\u5e93', 29900, 30, 'typo-words', 'lobster/replace-words/index', 'C', 'el-icon-edit', '0', '0', 0, 0, 'workflow:lobster:replace', 'admin', NOW(), 'typo');"
  139. + "INSERT IGNORE INTO tenant_company_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, company_id, remark) "
  140. + "SELECT menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, NULL, remark FROM tenant_sys_menu WHERE menu_id IN (29963,29964);";
  141. private static final String TENANT_SQL =
  142. "INSERT IGNORE INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, menu_type, icon, visible, status, is_frame, is_cache, perms, create_by, create_time, remark) VALUES "
  143. + "(29963, '\u7981\u7528\u8bcd\u5e93', 29900, 29, 'forbidden-words', 'lobster/replace-words/index', 'C', 'el-icon-warning', '0', '0', 0, 0, 'workflow:lobster:replace', 'admin', NOW(), 'forbidden'), "
  144. + "(29964, '\u6613\u9519\u8bcd\u5e93', 29900, 30, 'typo-words', 'lobster/replace-words/index', 'C', 'el-icon-edit', '0', '0', 0, 0, 'workflow:lobster:replace', 'admin', NOW(), 'typo');"
  145. + "INSERT IGNORE INTO company_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, company_id, remark) "
  146. + "SELECT 29963, '\u7981\u7528\u8bcd\u5e93', 29900, 29, 'forbidden-words', 'lobster/replace-words/index', 0, 0, 'C', '0', '0', 'workflow:lobster:replace', 'el-icon-warning', 'admin', NOW(), c.company_id, 'forbidden' "
  147. + "FROM (SELECT DISTINCT company_id FROM company_menu WHERE company_id IS NOT NULL) c "
  148. + "WHERE NOT EXISTS (SELECT 1 FROM company_menu x WHERE x.menu_id=29963 AND x.company_id=c.company_id);"
  149. + "INSERT IGNORE INTO company_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, company_id, remark) "
  150. + "SELECT 29964, '\u6613\u9519\u8bcd\u5e93', 29900, 30, 'typo-words', 'lobster/replace-words/index', 0, 0, 'C', '0', '0', 'workflow:lobster:replace', 'el-icon-edit', 'admin', NOW(), c.company_id, 'typo' "
  151. + "FROM (SELECT DISTINCT company_id FROM company_menu WHERE company_id IS NOT NULL) c "
  152. + "WHERE NOT EXISTS (SELECT 1 FROM company_menu x WHERE x.menu_id=29964 AND x.company_id=c.company_id);"
  153. + "INSERT IGNORE INTO sys_role_menu (role_id, menu_id) SELECT DISTINCT srm.role_id, 29963 FROM sys_role_menu srm WHERE srm.menu_id=29925 "
  154. + "AND NOT EXISTS (SELECT 1 FROM sys_role_menu x WHERE x.role_id=srm.role_id AND x.menu_id=29963);"
  155. + "INSERT IGNORE INTO sys_role_menu (role_id, menu_id) SELECT DISTINCT srm.role_id, 29964 FROM sys_role_menu srm WHERE srm.menu_id=29925 "
  156. + "AND NOT EXISTS (SELECT 1 FROM sys_role_menu x WHERE x.role_id=srm.role_id AND x.menu_id=29964);"
  157. + "INSERT IGNORE INTO company_role_menu (role_id, menu_id) SELECT DISTINCT crm.role_id, 29963 FROM company_role_menu crm WHERE crm.menu_id=29925 "
  158. + "AND NOT EXISTS (SELECT 1 FROM company_role_menu x WHERE x.role_id=crm.role_id AND x.menu_id=29963);"
  159. + "INSERT IGNORE INTO company_role_menu (role_id, menu_id) SELECT DISTINCT crm.role_id, 29964 FROM company_role_menu crm WHERE crm.menu_id=29925 "
  160. + "AND NOT EXISTS (SELECT 1 FROM company_role_menu x WHERE x.role_id=crm.role_id AND x.menu_id=29964);";
  161. private static final class TenantDb {
  162. String host;
  163. int port;
  164. String database;
  165. String user;
  166. String password;
  167. }
  168. }