2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 01:57:19 +08:00
Files
panel/internal/service/cli.go
2025-01-01 15:33:47 +08:00

869 lines
23 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"context"
"errors"
"fmt"
"path/filepath"
"time"
"github.com/go-rat/utils/collect"
"github.com/go-rat/utils/hash"
"github.com/go-rat/utils/str"
"github.com/knadh/koanf/v2"
"github.com/spf13/cast"
"github.com/urfave/cli/v3"
"gopkg.in/yaml.v3"
"gorm.io/gorm"
"github.com/tnb-labs/panel/internal/app"
"github.com/tnb-labs/panel/internal/biz"
"github.com/tnb-labs/panel/internal/http/request"
"github.com/tnb-labs/panel/pkg/api"
"github.com/tnb-labs/panel/pkg/cert"
"github.com/tnb-labs/panel/pkg/firewall"
"github.com/tnb-labs/panel/pkg/io"
"github.com/tnb-labs/panel/pkg/ntp"
"github.com/tnb-labs/panel/pkg/os"
"github.com/tnb-labs/panel/pkg/systemctl"
"github.com/tnb-labs/panel/pkg/tools"
"github.com/tnb-labs/panel/pkg/types"
)
type CliService struct {
hr string
api *api.API
conf *koanf.Koanf
db *gorm.DB
appRepo biz.AppRepo
cacheRepo biz.CacheRepo
userRepo biz.UserRepo
settingRepo biz.SettingRepo
backupRepo biz.BackupRepo
websiteRepo biz.WebsiteRepo
databaseServerRepo biz.DatabaseServerRepo
hash hash.Hasher
}
func NewCliService(conf *koanf.Koanf, db *gorm.DB, appRepo biz.AppRepo, cache biz.CacheRepo, user biz.UserRepo, setting biz.SettingRepo, backup biz.BackupRepo, website biz.WebsiteRepo, databaseServer biz.DatabaseServerRepo) *CliService {
return &CliService{
hr: `+----------------------------------------------------`,
api: api.NewAPI(app.Version),
conf: conf,
db: db,
appRepo: appRepo,
cacheRepo: cache,
userRepo: user,
settingRepo: setting,
backupRepo: backup,
websiteRepo: website,
databaseServerRepo: databaseServer,
hash: hash.NewArgon2id(),
}
}
func (s *CliService) Restart(ctx context.Context, cmd *cli.Command) error {
if err := systemctl.Restart("panel"); err != nil {
return err
}
fmt.Println("面板服务已重启")
return nil
}
func (s *CliService) Stop(ctx context.Context, cmd *cli.Command) error {
if err := systemctl.Stop("panel"); err != nil {
return err
}
fmt.Println("面板服务已停止")
return nil
}
func (s *CliService) Start(ctx context.Context, cmd *cli.Command) error {
if err := systemctl.Start("panel"); err != nil {
return err
}
fmt.Println("面板服务已启动")
return nil
}
func (s *CliService) Update(ctx context.Context, cmd *cli.Command) error {
panel, err := s.api.LatestVersion()
if err != nil {
return fmt.Errorf("获取最新版本失败:%v", err)
}
download := collect.First(panel.Downloads)
if download == nil {
return fmt.Errorf("下载地址为空")
}
ver, url, checksum := panel.Version, download.URL, download.Checksum
return s.backupRepo.UpdatePanel(ver, url, checksum)
}
func (s *CliService) Sync(ctx context.Context, cmd *cli.Command) error {
if err := s.cacheRepo.UpdateApps(); err != nil {
return fmt.Errorf("同步应用数据失败:%v", err)
}
if err := s.cacheRepo.UpdateRewrites(); err != nil {
return fmt.Errorf("同步伪静态规则失败:%v", err)
}
fmt.Println("数据同步成功")
return nil
}
func (s *CliService) Fix(ctx context.Context, cmd *cli.Command) error {
return s.backupRepo.FixPanel()
}
func (s *CliService) Info(ctx context.Context, cmd *cli.Command) error {
user := new(biz.User)
if err := s.db.Where("id", 1).First(user).Error; err != nil {
return fmt.Errorf("获取管理员信息失败:%v", err)
}
password := str.Random(16)
hashed, err := s.hash.Make(password)
if err != nil {
return fmt.Errorf("密码生成失败:%v", err)
}
user.Username = str.Random(8)
user.Password = hashed
if user.Email == "" {
user.Email = str.Random(8) + "@example.com"
}
if err = s.db.Save(user).Error; err != nil {
return fmt.Errorf("管理员信息保存失败:%v", err)
}
protocol := "http"
if s.conf.Bool("http.tls") {
protocol = "https"
}
port := s.conf.String("http.port")
if port == "" {
return fmt.Errorf("端口获取失败")
}
entrance := s.conf.String("http.entrance")
if entrance == "" {
return fmt.Errorf("入口获取失败")
}
fmt.Printf("用户名: %s\n", user.Username)
fmt.Printf("密码: %s\n", password)
fmt.Printf("端口: %s\n", port)
fmt.Printf("入口: %s\n", entrance)
lv4, err := tools.GetLocalIPv4()
if err == nil {
fmt.Printf("本地IPv4地址: %s://%s:%s%s\n", protocol, lv4, port, entrance)
}
lv6, err := tools.GetLocalIPv6()
if err == nil {
fmt.Printf("本地IPv6地址: %s://[%s]:%s%s\n", protocol, lv6, port, entrance)
}
rv4, err := tools.GetPublicIPv4()
if err == nil {
fmt.Printf("公网IPv4地址: %s://%s:%s%s\n", protocol, rv4, port, entrance)
}
rv6, err := tools.GetPublicIPv6()
if err == nil {
fmt.Printf("公网IPv6地址: %s://[%s]:%s%s\n", protocol, rv6, port, entrance)
}
fmt.Println("请根据自身网络情况自行选择合适的地址访问面板")
fmt.Printf("如无法访问,请检查服务器运营商安全组和防火墙是否放行%s端口\n", port)
fmt.Println("若仍无法访问,可尝试运行 panel-cli https off 关闭面板HTTPS")
fmt.Println("警告关闭面板HTTPS后面板安全性将大大降低请谨慎操作")
return nil
}
func (s *CliService) UserList(ctx context.Context, cmd *cli.Command) error {
users := make([]biz.User, 0)
if err := s.db.Find(&users).Error; err != nil {
return fmt.Errorf("获取用户列表失败:%v", err)
}
for _, user := range users {
fmt.Printf("ID: %d, 用户名: %s, 邮箱: %s, 创建日期: %s\n", user.ID, user.Username, user.Email, user.CreatedAt.Format(time.DateTime))
}
return nil
}
func (s *CliService) UserName(ctx context.Context, cmd *cli.Command) error {
user := new(biz.User)
oldUsername := cmd.Args().Get(0)
newUsername := cmd.Args().Get(1)
if oldUsername == "" {
return fmt.Errorf("旧用户名不能为空")
}
if newUsername == "" {
return fmt.Errorf("新用户名不能为空")
}
if err := s.db.Where("username", oldUsername).First(user).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return fmt.Errorf("用户不存在")
} else {
return fmt.Errorf("获取用户失败:%v", err)
}
}
user.Username = newUsername
if err := s.db.Save(user).Error; err != nil {
return fmt.Errorf("用户名修改失败:%v", err)
}
fmt.Printf("用户 %s 修改为 %s 成功\n", oldUsername, newUsername)
return nil
}
func (s *CliService) UserPassword(ctx context.Context, cmd *cli.Command) error {
user := new(biz.User)
username := cmd.Args().Get(0)
password := cmd.Args().Get(1)
if username == "" || password == "" {
return fmt.Errorf("用户名和密码不能为空")
}
if len(password) < 6 {
return fmt.Errorf("密码长度不能小于6")
}
if err := s.db.Where("username", username).First(user).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return fmt.Errorf("用户不存在")
} else {
return fmt.Errorf("获取用户失败:%v", err)
}
}
hashed, err := s.hash.Make(password)
if err != nil {
return fmt.Errorf("密码生成失败:%v", err)
}
user.Password = hashed
if err = s.db.Save(user).Error; err != nil {
return fmt.Errorf("密码修改失败:%v", err)
}
fmt.Printf("用户 %s 密码修改成功\n", username)
return nil
}
func (s *CliService) HTTPSOn(ctx context.Context, cmd *cli.Command) error {
config := new(types.PanelConfig)
raw, err := io.Read("/usr/local/etc/panel/config.yml")
if err != nil {
return err
}
if err = yaml.Unmarshal([]byte(raw), config); err != nil {
return err
}
config.HTTP.TLS = true
encoded, err := yaml.Marshal(config)
if err != nil {
return err
}
if err = io.Write("/usr/local/etc/panel/config.yml", string(encoded), 0700); err != nil {
return err
}
fmt.Println("已开启HTTPS")
return s.Restart(ctx, cmd)
}
func (s *CliService) HTTPSOff(ctx context.Context, cmd *cli.Command) error {
config := new(types.PanelConfig)
raw, err := io.Read("/usr/local/etc/panel/config.yml")
if err != nil {
return err
}
if err = yaml.Unmarshal([]byte(raw), config); err != nil {
return err
}
config.HTTP.TLS = false
encoded, err := yaml.Marshal(config)
if err != nil {
return err
}
if err = io.Write("/usr/local/etc/panel/config.yml", string(encoded), 0700); err != nil {
return err
}
fmt.Println("已关闭HTTPS")
return s.Restart(ctx, cmd)
}
func (s *CliService) HTTPSGenerate(ctx context.Context, cmd *cli.Command) error {
var names []string
if lv4, err := tools.GetLocalIPv4(); err == nil {
names = append(names, lv4)
}
if lv6, err := tools.GetLocalIPv6(); err == nil {
names = append(names, lv6)
}
if rv4, err := tools.GetPublicIPv4(); err == nil {
names = append(names, rv4)
}
if rv6, err := tools.GetPublicIPv6(); err == nil {
names = append(names, rv6)
}
crt, key, err := cert.GenerateSelfSigned(names)
if err != nil {
return err
}
if err = io.Write(filepath.Join(app.Root, "panel/storage/cert.pem"), string(crt), 0644); err != nil {
return err
}
if err = io.Write(filepath.Join(app.Root, "panel/storage/cert.key"), string(key), 0644); err != nil {
return err
}
fmt.Println("已生成HTTPS证书")
return s.Restart(ctx, cmd)
}
func (s *CliService) EntranceOn(ctx context.Context, cmd *cli.Command) error {
config := new(types.PanelConfig)
raw, err := io.Read("/usr/local/etc/panel/config.yml")
if err != nil {
return err
}
if err = yaml.Unmarshal([]byte(raw), config); err != nil {
return err
}
config.HTTP.Entrance = "/" + str.Random(6)
encoded, err := yaml.Marshal(config)
if err != nil {
return err
}
if err = io.Write("/usr/local/etc/panel/config.yml", string(encoded), 0700); err != nil {
return err
}
fmt.Println("已开启访问入口")
fmt.Printf("访问入口:%s\n", config.HTTP.Entrance)
return s.Restart(ctx, cmd)
}
func (s *CliService) EntranceOff(ctx context.Context, cmd *cli.Command) error {
config := new(types.PanelConfig)
raw, err := io.Read("/usr/local/etc/panel/config.yml")
if err != nil {
return err
}
if err = yaml.Unmarshal([]byte(raw), config); err != nil {
return err
}
config.HTTP.Entrance = "/"
encoded, err := yaml.Marshal(config)
if err != nil {
return err
}
if err = io.Write("/usr/local/etc/panel/config.yml", string(encoded), 0700); err != nil {
return err
}
fmt.Println("已关闭访问入口")
return s.Restart(ctx, cmd)
}
func (s *CliService) Port(ctx context.Context, cmd *cli.Command) error {
port := cast.ToUint(cmd.Args().First())
if port < 1 || port > 65535 {
return fmt.Errorf("端口范围错误")
}
config := new(types.PanelConfig)
raw, err := io.Read("/usr/local/etc/panel/config.yml")
if err != nil {
return err
}
if err = yaml.Unmarshal([]byte(raw), config); err != nil {
return err
}
if port != config.HTTP.Port {
if os.TCPPortInUse(port) {
return errors.New("端口已被占用")
}
}
config.HTTP.Port = port
encoded, err := yaml.Marshal(config)
if err != nil {
return err
}
// 放行端口
fw := firewall.NewFirewall()
err = fw.Port(firewall.FireInfo{
Type: firewall.TypeNormal,
PortStart: uint(config.HTTP.Port),
PortEnd: uint(config.HTTP.Port),
Direction: firewall.DirectionIn,
Strategy: firewall.StrategyAccept,
}, firewall.OperationAdd)
if err != nil {
return err
}
if err = io.Write("/usr/local/etc/panel/config.yml", string(encoded), 0700); err != nil {
return err
}
fmt.Printf("已修改端口为 %d\n", port)
return s.Restart(ctx, cmd)
}
func (s *CliService) WebsiteCreate(ctx context.Context, cmd *cli.Command) error {
req := &request.WebsiteCreate{
Name: cmd.String("name"),
Domains: cmd.StringSlice("domains"),
Listens: cmd.StringSlice("listens"),
Path: cmd.String("path"),
PHP: int(cmd.Int("php")),
DB: false,
}
website, err := s.websiteRepo.Create(req)
if err != nil {
return err
}
fmt.Printf("网站 %s 创建成功\n", website.Name)
return nil
}
func (s *CliService) WebsiteRemove(ctx context.Context, cmd *cli.Command) error {
website, err := s.websiteRepo.GetByName(cmd.String("name"))
if err != nil {
return err
}
req := &request.WebsiteDelete{
ID: website.ID,
}
if err = s.websiteRepo.Delete(req); err != nil {
return err
}
fmt.Printf("网站 %s 移除成功\n", website.Name)
return nil
}
func (s *CliService) WebsiteDelete(ctx context.Context, cmd *cli.Command) error {
website, err := s.websiteRepo.GetByName(cmd.String("name"))
if err != nil {
return err
}
req := &request.WebsiteDelete{
ID: website.ID,
Path: true,
DB: true,
}
if err = s.websiteRepo.Delete(req); err != nil {
return err
}
fmt.Printf("网站 %s 删除成功\n", website.Name)
return nil
}
func (s *CliService) WebsiteWrite(ctx context.Context, cmd *cli.Command) error {
println("not support")
return nil
}
func (s *CliService) DatabaseAddServer(ctx context.Context, cmd *cli.Command) error {
req := &request.DatabaseServerCreate{
Type: cmd.String("type"),
Name: cmd.String("name"),
Host: cmd.String("host"),
Port: uint(cmd.Uint("port")),
Username: cmd.String("username"),
Password: cmd.String("password"),
Remark: cmd.String("remark"),
}
if err := s.databaseServerRepo.Create(req); err != nil {
return err
}
fmt.Printf("数据库服务器 %s 添加成功\n", cmd.String("name"))
return nil
}
func (s *CliService) DatabaseDeleteServer(ctx context.Context, cmd *cli.Command) error {
server, err := s.databaseServerRepo.GetByName(cmd.String("name"))
if err != nil {
return err
}
if err = s.databaseServerRepo.Delete(server.ID); err != nil {
return err
}
fmt.Printf("数据库服务器 %s 删除成功\n", server.Name)
return nil
}
func (s *CliService) BackupWebsite(ctx context.Context, cmd *cli.Command) error {
fmt.Println(s.hr)
fmt.Printf("★ 开始备份 [%s]\n", time.Now().Format(time.DateTime))
fmt.Println(s.hr)
fmt.Println("|-备份类型:网站")
fmt.Printf("|-备份目标:%s\n", cmd.String("name"))
if err := s.backupRepo.Create(biz.BackupTypeWebsite, cmd.String("name"), cmd.String("path")); err != nil {
return fmt.Errorf("备份失败:%v", err)
}
fmt.Println(s.hr)
fmt.Printf("☆ 备份成功 [%s]\n", time.Now().Format(time.DateTime))
fmt.Println(s.hr)
return nil
}
func (s *CliService) BackupDatabase(ctx context.Context, cmd *cli.Command) error {
fmt.Println(s.hr)
fmt.Printf("★ 开始备份 [%s]\n", time.Now().Format(time.DateTime))
fmt.Println(s.hr)
fmt.Println("|-备份类型:数据库")
fmt.Printf("|-数据库:%s\n", cmd.String("type"))
fmt.Printf("|-备份目标:%s\n", cmd.String("name"))
if err := s.backupRepo.Create(biz.BackupType(cmd.String("type")), cmd.String("name"), cmd.String("path")); err != nil {
return fmt.Errorf("备份失败:%v", err)
}
fmt.Println(s.hr)
fmt.Printf("☆ 备份成功 [%s]\n", time.Now().Format(time.DateTime))
fmt.Println(s.hr)
return nil
}
func (s *CliService) BackupPanel(ctx context.Context, cmd *cli.Command) error {
fmt.Println(s.hr)
fmt.Printf("★ 开始备份 [%s]\n", time.Now().Format(time.DateTime))
fmt.Println(s.hr)
fmt.Println("|-备份类型:面板")
if err := s.backupRepo.Create(biz.BackupTypePanel, "", cmd.String("path")); err != nil {
return fmt.Errorf("备份失败:%v", err)
}
fmt.Println(s.hr)
fmt.Printf("☆ 备份成功 [%s]\n", time.Now().Format(time.DateTime))
fmt.Println(s.hr)
return nil
}
func (s *CliService) BackupClear(ctx context.Context, cmd *cli.Command) error {
path, err := s.backupRepo.GetPath(biz.BackupType(cmd.String("type")))
if err != nil {
return err
}
if cmd.String("path") != "" {
path = cmd.String("path")
}
fmt.Println(s.hr)
fmt.Printf("★ 开始清理 [%s]\n", time.Now().Format(time.DateTime))
fmt.Println(s.hr)
fmt.Printf("|-清理类型:%s\n", cmd.String("type"))
fmt.Printf("|-清理目标:%s\n", cmd.String("file"))
fmt.Printf("|-保留份数:%d\n", cmd.Int("save"))
if err = s.backupRepo.ClearExpired(path, cmd.String("file"), int(cmd.Int("save"))); err != nil {
return fmt.Errorf("清理失败:%v", err)
}
fmt.Println(s.hr)
fmt.Printf("☆ 清理成功 [%s]\n", time.Now().Format(time.DateTime))
fmt.Println(s.hr)
return nil
}
func (s *CliService) CutoffWebsite(ctx context.Context, cmd *cli.Command) error {
website, err := s.websiteRepo.GetByName(cmd.String("name"))
if err != nil {
return err
}
path := filepath.Join(app.Root, "wwwlogs")
if cmd.String("path") != "" {
path = cmd.String("path")
}
fmt.Println(s.hr)
fmt.Printf("★ 开始切割日志 [%s]\n", time.Now().Format(time.DateTime))
fmt.Println(s.hr)
fmt.Println("|-切割类型:网站")
fmt.Printf("|-切割目标:%s\n", website.Name)
if err = s.backupRepo.CutoffLog(path, filepath.Join(app.Root, "wwwlogs", website.Name+".log")); err != nil {
return err
}
fmt.Println(s.hr)
fmt.Printf("☆ 切割成功 [%s]\n", time.Now().Format(time.DateTime))
fmt.Println(s.hr)
return nil
}
func (s *CliService) CutoffClear(ctx context.Context, cmd *cli.Command) error {
if cmd.String("type") != "website" {
return errors.New("当前仅支持网站日志切割")
}
path := filepath.Join(app.Root, "wwwlogs")
if cmd.String("path") != "" {
path = cmd.String("path")
}
fmt.Println(s.hr)
fmt.Printf("★ 开始清理切割日志 [%s]\n", time.Now().Format(time.DateTime))
fmt.Println(s.hr)
fmt.Printf("|-清理类型:%s\n", cmd.String("type"))
fmt.Printf("|-清理目标:%s\n", cmd.String("file"))
fmt.Printf("|-保留份数:%d\n", cmd.Int("save"))
if err := s.backupRepo.ClearExpired(path, cmd.String("file"), int(cmd.Int("save"))); err != nil {
return err
}
fmt.Println(s.hr)
fmt.Printf("☆ 清理成功 [%s]\n", time.Now().Format(time.DateTime))
fmt.Println(s.hr)
return nil
}
func (s *CliService) AppInstall(ctx context.Context, cmd *cli.Command) error {
slug := cmd.Args().First()
channel := cmd.Args().Get(1)
if channel == "" || slug == "" {
return fmt.Errorf("参数不能为空")
}
if err := s.appRepo.Install(channel, slug); err != nil {
return fmt.Errorf("应用安装失败:%v", err)
}
fmt.Printf("应用 %s 安装完成\n", slug)
return nil
}
func (s *CliService) AppUnInstall(ctx context.Context, cmd *cli.Command) error {
slug := cmd.Args().First()
if slug == "" {
return fmt.Errorf("参数不能为空")
}
if err := s.appRepo.UnInstall(slug); err != nil {
return fmt.Errorf("应用卸载失败:%v", err)
}
fmt.Printf("应用 %s 卸载完成\n", slug)
return nil
}
func (s *CliService) AppUpdate(ctx context.Context, cmd *cli.Command) error {
slug := cmd.Args().First()
if slug == "" {
return fmt.Errorf("参数不能为空")
}
if err := s.appRepo.Update(slug); err != nil {
return fmt.Errorf("应用更新失败:%v", err)
}
fmt.Printf("应用 %s 更新完成\n", slug)
return nil
}
func (s *CliService) AppWrite(ctx context.Context, cmd *cli.Command) error {
slug := cmd.Args().Get(0)
channel := cmd.Args().Get(1)
version := cmd.Args().Get(2)
if slug == "" || channel == "" || version == "" {
return fmt.Errorf("参数不能为空")
}
newApp := new(biz.App)
if err := s.db.Where("slug", slug).First(newApp).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return fmt.Errorf("获取应用失败:%v", err)
}
}
newApp.Slug = slug
newApp.Channel = channel
newApp.Version = version
if err := s.db.Save(newApp).Error; err != nil {
return fmt.Errorf("应用保存失败:%v", err)
}
return nil
}
func (s *CliService) AppRemove(ctx context.Context, cmd *cli.Command) error {
slug := cmd.Args().First()
if slug == "" {
return fmt.Errorf("参数不能为空")
}
if err := s.db.Where("slug", slug).Delete(&biz.App{}).Error; err != nil {
return fmt.Errorf("应用删除失败:%v", err)
}
return nil
}
func (s *CliService) SyncTime(ctx context.Context, cmd *cli.Command) error {
now, err := ntp.Now()
if err != nil {
return err
}
if err = ntp.UpdateSystemTime(now); err != nil {
return err
}
fmt.Println("时间同步成功")
return nil
}
func (s *CliService) ClearTask(ctx context.Context, cmd *cli.Command) error {
if err := s.db.Model(&biz.Task{}).
Where("status", biz.TaskStatusRunning).Or("status", biz.TaskStatusWaiting).
Update("status", biz.TaskStatusFailed).
Error; err != nil {
return fmt.Errorf("任务清理失败:%v", err)
}
fmt.Println("任务清理成功")
return nil
}
func (s *CliService) GetSetting(ctx context.Context, cmd *cli.Command) error {
key := cmd.Args().First()
if key == "" {
return fmt.Errorf("参数不能为空")
}
setting := new(biz.Setting)
if err := s.db.Where("key", key).First(setting).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return fmt.Errorf("设置不存在")
}
return fmt.Errorf("获取设置失败:%v", err)
}
fmt.Print(setting.Value)
return nil
}
func (s *CliService) WriteSetting(ctx context.Context, cmd *cli.Command) error {
key := cmd.Args().Get(0)
value := cmd.Args().Get(1)
if key == "" || value == "" {
return fmt.Errorf("参数不能为空")
}
setting := new(biz.Setting)
if err := s.db.Where("key", key).First(setting).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return fmt.Errorf("获取设置失败:%v", err)
}
}
setting.Key = biz.SettingKey(key)
setting.Value = value
if err := s.db.Save(setting).Error; err != nil {
return fmt.Errorf("设置保存失败:%v", err)
}
return nil
}
func (s *CliService) RemoveSetting(ctx context.Context, cmd *cli.Command) error {
key := cmd.Args().First()
if key == "" {
return fmt.Errorf("参数不能为空")
}
if err := s.db.Where("key", key).Delete(&biz.Setting{}).Error; err != nil {
return fmt.Errorf("设置删除失败:%v", err)
}
return nil
}
func (s *CliService) Init(ctx context.Context, cmd *cli.Command) error {
var check biz.User
if err := s.db.First(&check).Error; err == nil {
return fmt.Errorf("已经初始化过了")
}
settings := []biz.Setting{
{Key: biz.SettingKeyName, Value: "耗子面板"},
{Key: biz.SettingKeyMonitor, Value: "1"},
{Key: biz.SettingKeyMonitorDays, Value: "30"},
{Key: biz.SettingKeyBackupPath, Value: filepath.Join(app.Root, "backup")},
{Key: biz.SettingKeyWebsitePath, Value: filepath.Join(app.Root, "wwwroot")},
{Key: biz.SettingKeyVersion, Value: app.Version},
}
if err := s.db.Create(&settings).Error; err != nil {
return fmt.Errorf("初始化失败:%v", err)
}
value, err := hash.NewArgon2id().Make(str.Random(32))
if err != nil {
return fmt.Errorf("初始化失败:%v", err)
}
_, err = s.userRepo.Create("admin", value)
if err != nil {
return fmt.Errorf("初始化失败:%v", err)
}
if err = s.HTTPSGenerate(ctx, cmd); err != nil {
return fmt.Errorf("初始化失败:%v", err)
}
config := new(types.PanelConfig)
raw, err := io.Read("/usr/local/etc/panel/config.yml")
if err != nil {
return err
}
if err = yaml.Unmarshal([]byte(raw), config); err != nil {
return err
}
config.App.Key = str.Random(32)
config.HTTP.Entrance = "/" + str.Random(6)
encoded, err := yaml.Marshal(config)
if err != nil {
return err
}
if err = io.Write("/usr/local/etc/panel/config.yml", string(encoded), 0700); err != nil {
return err
}
return nil
}