仰望星辰工作室

clearlove2.1

clearlove2.1/ internal/handlers/install.go 3.8 KB · 114 行 原始文件
1// 安装向导:首次启动自动进入,三步完成(数据库 -> 站点信息 -> 管理员),
2// 完成后写入 data/config.json 标记安装状态并自动建表。
3package handlers
4
5import (
6 "database/sql"
7 "fmt"
8 "net/http"
9 "path/filepath"
10 "strings"
11
12 _ "github.com/go-sql-driver/mysql"
13 _ "modernc.org/sqlite"
14
15 "clearlove/internal/config"
16 "clearlove/internal/database"
17 "clearlove/internal/models"
18 "clearlove/internal/util"
19)
20
21// InstallPage 渲染安装引导页
22func InstallPage(w http.ResponseWriter, r *http.Request) {
23 Render(w, r, "layout.html", "pg_install", map[string]any{"version": config.Version})
24}
25
26// InstallSubmit 处理安装表单:校验数据库连接、建表、写入管理员与默认设置
27func InstallSubmit(w http.ResponseWriter, r *http.Request) {
28 dbType := r.FormValue("db_type")
29 siteName := strings.TrimSpace(r.FormValue("site_name"))
30 adminUser := strings.TrimSpace(r.FormValue("admin_user"))
31 adminPass := r.FormValue("admin_pass")
32
33 if siteName == "" || len([]rune(siteName)) > 30 { // 站名必填且不超过30字
34 fail(w, 400, "请填写网站名称(30字以内)")
35 return
36 }
37 if len(adminUser) < 3 || len(adminPass) < 6 {
38 fail(w, 400, "管理员用户名至少3位、密码至少6位")
39 return
40 }
41
42 // 构造 DSN 并测试连接
43 var dsn string
44 switch dbType {
45 case "mysql":
46 host := strings.TrimSpace(r.FormValue("mysql_host"))
47 port := strings.TrimSpace(r.FormValue("mysql_port"))
48 name := strings.TrimSpace(r.FormValue("mysql_name"))
49 user := strings.TrimSpace(r.FormValue("mysql_user"))
50 pass := r.FormValue("mysql_pass")
51 if host == "" || port == "" || name == "" || user == "" {
52 fail(w, 400, "请完整填写 MySQL 连接信息")
53 return
54 }
55 dsn = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=false&loc=UTC&charset=utf8mb4", user, pass, host, port, name)
56 db, err := sql.Open("mysql", dsn)
57 if err != nil || db.Ping() != nil {
58 fail(w, 400, "MySQL 连接失败,请检查主机、端口、库名与账号密码")
59 return
60 }
61 db.Close()
62 default:
63 dbType = "sqlite"
64 // SQLite 库文件放在数据目录下,跟随 CLEARLOVE_DATA_DIR 设置
65 dsn = filepath.Join(config.Cfg.DataDir, "clearlove.db")
66 }
67
68 // 持久化配置
69 config.Cfg.DBType = dbType
70 config.Cfg.SQLitePath = dsn
71 config.Cfg.MySQLDsn = dsn
72 config.Cfg.Secret = util.RandomHex(32)
73 config.Cfg.Version = config.Version
74 if err := database.Connect(); err != nil {
75 fail(w, 500, "数据库初始化失败: "+err.Error())
76 return
77 }
78 if err := database.Migrate(); err != nil {
79 fail(w, 500, "数据表创建失败: "+err.Error())
80 return
81 }
82
83 // 默认设置
84 defaults := map[string]string{
85 "site_name": siteName, "theme": "default", "allow_register": "1",
86 "require_login_post": "0", "ai_enabled": "0", "ai_autopatrol": "0",
87 "ai_precheck": "0", "community_rules": "禁止发布违法违规、暴力、色情、辱骂及广告刷屏内容。",
88 "ai_vision": "0", "ai_precheck_fail": "open", "ai_auto_delete": "0", "ai_auto_ban": "0",
89 "update_url": "https://clearlove.kazx.top/update",
90 "donate_img": "https://clearlove.kazx.top/%E6%8D%90%E8%B5%A0.webp",
91 "enabled_plugins": "[]",
92 "cloud_api": "https://clearlove.kazx.top",
93 }
94 for k, v := range defaults {
95 _ = models.SetSetting(k, v)
96 }
97
98 // 创建超级管理员
99 if _, err := database.DB.Exec(
100 "INSERT INTO admins(username,password,role,perms,created_at) VALUES(?,?,?,?,?)",
101 adminUser, util.HashPassword(adminPass), "super", "[]", models.Now()); err != nil {
102 fail(w, 500, "管理员创建失败: "+err.Error())
103 return
104 }
105
106 // 标记安装完成并重启协程不需要:配置已生效
107 config.Cfg.Installed = true
108 if err := config.Save(); err != nil {
109 fail(w, 500, "配置写入失败: "+err.Error())
110 return
111 }
112 util.Log("info", "安装完成,站点: %s,数据库: %s", siteName, dbType)
113 okJSON(w, map[string]any{"redirect": "/"})
114}