init.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. package tool
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "log"
  6. "os"
  7. "path/filepath"
  8. )
  9. func DB_table_list() map[string][]string {
  10. create_data := map[string][]string{}
  11. // 폐지 예정 (data_set으로 통합)
  12. create_data["data_set"] = []string{"doc_name", "doc_rev", "set_name", "set_data"}
  13. create_data["data"] = []string{"title", "data", "type"}
  14. create_data["history"] = []string{"id", "title", "data", "date", "ip", "send", "leng", "hide", "type"}
  15. create_data["rc"] = []string{"id", "title", "date", "type"}
  16. create_data["acl"] = []string{"title", "data", "type"}
  17. // 개편 예정 (data_link로 변경)
  18. create_data["back"] = []string{"title", "link", "type", "data"}
  19. // 폐지 예정 (topic_set으로 통합) [가장 시급]
  20. create_data["topic_set"] = []string{"thread_code", "set_name", "set_id", "set_data"}
  21. create_data["rd"] = []string{"title", "sub", "code", "date", "band", "stop", "agree", "acl"}
  22. create_data["topic"] = []string{"id", "data", "date", "ip", "block", "top", "code"}
  23. // 폐지 예정 (user_set으로 통합)
  24. create_data["rb"] = []string{"block", "end", "today", "blocker", "why", "band", "login", "ongoing"}
  25. // 개편 예정 (wiki_set과 wiki_filter과 wiki_vote으로 변경)
  26. create_data["other"] = []string{"name", "data", "coverage"}
  27. create_data["html_filter"] = []string{"html", "kind", "plus", "plus_t"}
  28. create_data["vote"] = []string{"name", "id", "subject", "data", "user", "type", "acl"}
  29. // 개편 예정 (auth와 auth_log로 변경)
  30. create_data["alist"] = []string{"name", "acl"}
  31. create_data["re_admin"] = []string{"who", "what", "time"}
  32. // 개편 예정 (user_notice와 user_agent로 변경)
  33. create_data["ua_d"] = []string{"name", "ip", "ua", "today", "sub"}
  34. create_data["user_set"] = []string{"name", "id", "data"}
  35. create_data["user_notice"] = []string{"id", "name", "data", "date", "readme"}
  36. create_data["bbs_set"] = []string{"set_name", "set_code", "set_id", "set_data"}
  37. create_data["bbs_data"] = []string{"set_name", "set_code", "set_id", "set_data"}
  38. return create_data
  39. }
  40. func DB_make_MySQL(db *sql.DB, new_db_set map[string]string) {
  41. Exec_DB(
  42. db,
  43. `create database if not exists ` + new_db_set["db_name"] + ` default character set utf8mb4`,
  44. )
  45. }
  46. func DB_column_exists(db *sql.DB, table_name string, column_name string) bool {
  47. query := fmt.Sprintf(
  48. "SELECT %s FROM %s LIMIT 1",
  49. column_name,
  50. table_name,
  51. )
  52. rows, err := db.Query(query)
  53. if err != nil {
  54. return false
  55. }
  56. defer rows.Close()
  57. return true
  58. }
  59. func DB_field_text(db_type string) string {
  60. if db_type == "mysql" {
  61. return "longtext"
  62. }
  63. return "text default ''"
  64. }
  65. func DB_warn_null_column(db *sql.DB, table_name string, column_name string) {
  66. query := fmt.Sprintf(
  67. "select count(*) from %s where %s is null",
  68. table_name,
  69. column_name,
  70. )
  71. var count int
  72. err := db.QueryRow(query).Scan(&count)
  73. if err != nil {
  74. log.Printf("[DB WARNING] null check failed: %s.%s: %v", table_name, column_name, err)
  75. return
  76. }
  77. if count > 0 {
  78. log.Printf("[DB WARNING] %s.%s has %d null values", table_name, column_name, count)
  79. }
  80. }
  81. func DB_create_table(db *sql.DB, table_name string, field_text string) {
  82. Exec_DB(
  83. db,
  84. fmt.Sprintf(
  85. "create table if not exists %s (test %s)",
  86. table_name,
  87. field_text,
  88. ),
  89. )
  90. }
  91. func DB_alter_add_column(db *sql.DB, table_name string, column_name string, field_text string) {
  92. Exec_DB(
  93. db,
  94. fmt.Sprintf(
  95. "alter table %s add column %s %s",
  96. table_name,
  97. column_name,
  98. field_text,
  99. ),
  100. )
  101. }
  102. func DB_create_history_index(db *sql.DB) {
  103. _, err := db.Exec(DB_change(
  104. `create index history_index on history (title, ip)`,
  105. ))
  106. if err != nil {
  107. return
  108. }
  109. }
  110. func DB_make(db *sql.DB, new_db_set map[string]string) error {
  111. if new_db_set["db_type"] == "mysql" {
  112. DB_make_MySQL(db, new_db_set)
  113. } else {
  114. Exec_DB(
  115. db,
  116. `pragma journal_mode = WAL`,
  117. )
  118. }
  119. db = DB_connect()
  120. defer DB_close(db)
  121. if err := db.Ping(); err != nil {
  122. return err
  123. }
  124. field_text := DB_field_text(new_db_set["db_type"])
  125. table_list := DB_table_list()
  126. for table_name, table_data := range table_list {
  127. DB_create_table(db, table_name, field_text)
  128. columns := append([]string{"test"}, table_data...)
  129. for _, column_name := range columns {
  130. if !DB_column_exists(db, table_name, column_name) {
  131. DB_alter_add_column(db, table_name, column_name, field_text)
  132. }
  133. DB_warn_null_column(db, table_name, column_name)
  134. }
  135. }
  136. DB_create_history_index(db)
  137. return nil
  138. }
  139. func DB_init() {
  140. new_db_set := DB_boot()
  141. db, err := DB_connect_init()
  142. if err != nil {
  143. panic(fmt.Errorf("DB connection failed: %w", err))
  144. }
  145. defer DB_close(db)
  146. if err := DB_make(db, new_db_set); err != nil {
  147. panic(fmt.Errorf("DB setup failed: %w", err))
  148. }
  149. }
  150. func Main_init() {
  151. DB_init()
  152. DB_boot()
  153. db := DB_connect()
  154. defer DB_close(db)
  155. now_version := ""
  156. QueryRow_DB(
  157. db,
  158. `select data from other where name = "ver"`,
  159. []any{ &now_version },
  160. )
  161. last_version := Get_last_version()
  162. if now_version == "" {
  163. First_init(db)
  164. } else {
  165. if now_version != last_version["c_ver"] {
  166. Update_init(db)
  167. }
  168. }
  169. Always_init(db, last_version["c_ver"])
  170. }
  171. func Get_last_version() map[string]string {
  172. version_file_path := filepath.Join("..", "version.json")
  173. if _, err := os.Stat(version_file_path); err == nil {
  174. data, err := os.ReadFile(version_file_path)
  175. if err != nil {
  176. panic(err)
  177. }
  178. version_json := map[string]string{}
  179. json.Unmarshal([]byte(data), &version_json)
  180. return version_json
  181. } else {
  182. panic(err)
  183. }
  184. }
  185. func First_init(db *sql.DB) {
  186. email := ""
  187. exists := QueryRow_DB(
  188. db,
  189. `select html from html_filter where kind = 'email'`,
  190. []any{ &email },
  191. )
  192. if !exists {
  193. for _, v := range []string{ "naver.com", "gmail.com", "daum.net", "kakao.com" } {
  194. Exec_DB(
  195. db,
  196. `insert into html_filter (html, kind, plus, plus_t) values (?, 'email', '', '')`,
  197. v,
  198. )
  199. }
  200. }
  201. extension := ""
  202. exists = QueryRow_DB(
  203. db,
  204. `select html from html_filter where kind = 'extension'`,
  205. []any{ &extension },
  206. )
  207. if !exists {
  208. for _, v := range []string{ "jpg", "jpeg", "png", "gif", "webp" } {
  209. Exec_DB(
  210. db,
  211. `insert into html_filter (html, kind, plus, plus_t) values (?, 'extension', '', '')`,
  212. v,
  213. )
  214. }
  215. }
  216. smtp_server := ""
  217. exists = QueryRow_DB(
  218. db,
  219. `select data from other where name = "smtp_server"`,
  220. []any{ &smtp_server },
  221. )
  222. if !exists {
  223. for _, v := range [][]string{
  224. { "smtp_server", "smtp.gmail.com" },
  225. { "smtp_port", "587" },
  226. { "smtp_security", "starttls" },
  227. } {
  228. Exec_DB(
  229. db,
  230. `insert into other (name, data, coverage) values (?, ?, '')`,
  231. v[0],
  232. v[1],
  233. )
  234. }
  235. }
  236. name_filter := ""
  237. exists = QueryRow_DB(
  238. db,
  239. `select html from html_filter where kind = 'name'`,
  240. []any{ &name_filter },
  241. )
  242. if !exists {
  243. Exec_DB(
  244. db,
  245. `insert into html_filter (html, kind, plus, plus_t) values (?, "name", "", "")`,
  246. `(?:[^A-Za-zㄱ-ㅣ가-힣0-9])`,
  247. )
  248. }
  249. }
  250. func Update_init(db *sql.DB) {
  251. }
  252. func Always_init(db *sql.DB, version string) {
  253. // 버전 기입
  254. Exec_DB(
  255. db,
  256. `delete from other where name = "ver"`,
  257. )
  258. Exec_DB(
  259. db,
  260. `insert into other (name, data, coverage) values ("ver", ?, "")`,
  261. version,
  262. )
  263. // 기본 권한 그룹 설정
  264. Exec_DB(
  265. db,
  266. `delete from alist where name = "owner"`,
  267. )
  268. Exec_DB(
  269. db,
  270. `insert into alist (name, acl) values ("owner", "owner")`,
  271. )
  272. user := ""
  273. QueryRow_DB(
  274. db,
  275. `select name from alist where name = 'user' limit 1`,
  276. []any{ &user },
  277. )
  278. if user == "" {
  279. Exec_DB(
  280. db,
  281. `insert into alist (name, acl) values ("user", "user")`,
  282. )
  283. }
  284. ip := ""
  285. QueryRow_DB(
  286. db,
  287. `select name from alist where name = 'ip' limit 1`,
  288. []any{ &ip },
  289. )
  290. if ip == "" {
  291. Exec_DB(
  292. db,
  293. `insert into alist (name, acl) values ("ip", "ip")`,
  294. )
  295. }
  296. ban := ""
  297. QueryRow_DB(
  298. db,
  299. `select name from alist where name = 'ban' limit 1`,
  300. []any{ &ban },
  301. )
  302. if ban == "" {
  303. Exec_DB(
  304. db,
  305. `insert into alist (name, acl) values ("ban", "view")`,
  306. )
  307. }
  308. length := 0
  309. QueryRow_DB(
  310. db,
  311. `select count(*) from bbs_set where set_id = "0" and set_name = "bbs_name"`,
  312. []any{ &length },
  313. )
  314. if length > 1 {
  315. Exec_DB(
  316. db,
  317. `delete from bbs_set where set_id = "0" and set_name = "bbs_name"`,
  318. )
  319. Exec_DB(
  320. db,
  321. `delete from bbs_set where set_id = "0" and set_name = "bbs_type"`,
  322. )
  323. length = 0
  324. }
  325. if length == 0 {
  326. Exec_DB(
  327. db,
  328. `insert into bbs_set (set_name, set_code, set_id, set_data) values ('bbs_name', '', '0', 'document_comment')`,
  329. )
  330. Exec_DB(
  331. db,
  332. `insert into bbs_set (set_name, set_code, set_id, set_data) values ('bbs_type', '', '0', 'comment')`,
  333. )
  334. }
  335. image_url := Get_image_url(db)
  336. exists_folder := false
  337. _, err := os.Stat(image_url)
  338. if err == nil {
  339. exists_folder = true
  340. }
  341. if !exists_folder {
  342. os.MkdirAll(image_url, 0755)
  343. }
  344. key := ""
  345. exists := QueryRow_DB(
  346. db,
  347. `select data from other where name = "key"`,
  348. []any{ &key },
  349. )
  350. if !exists {
  351. Exec_DB(
  352. db,
  353. `insert into other (name, data, coverage) values ("key", ?, "")`,
  354. Get_random_key(128),
  355. )
  356. }
  357. salt := ""
  358. exists = QueryRow_DB(
  359. db,
  360. `select data from other where name = "salt_key"`,
  361. []any{ &salt },
  362. )
  363. if !exists {
  364. Exec_DB(
  365. db,
  366. `insert into other (name, data, coverage) values ("salt_key", ?, "")`,
  367. Get_random_key(4),
  368. )
  369. }
  370. document_count := ""
  371. exists = QueryRow_DB(
  372. db,
  373. `select data from other where name = "count_all_title"`,
  374. []any{ &document_count },
  375. )
  376. if !exists {
  377. Exec_DB(
  378. db,
  379. `insert into other (name, data, coverage) values ("count_all_title", "0", "")`,
  380. )
  381. }
  382. }