1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-09-08 13:26:25 -07:00
gochan/cmd/gochan/commandline.go

197 lines
5.7 KiB
Go

package main
import (
"errors"
"flag"
"fmt"
"os"
"strings"
"github.com/gochan-org/gochan/pkg/config"
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/rs/zerolog"
"golang.org/x/term"
)
var (
errAborted = fmt.Errorf("aborted")
)
func printInfoAndLog(msg string, infoEv ...*zerolog.Event) {
fmt.Println(msg)
if len(infoEv) > 0 {
infoEv[0].Msg(msg)
} else {
gcutil.LogInfo().Str("source", "commandLine").Msg(msg)
}
}
func initCommandLine() *zerolog.Event {
var err error
if err = config.InitConfig(); err != nil {
fmt.Fprintln(os.Stderr, "Error initializing config:", err)
os.Exit(1)
}
systemCritical := config.GetSystemCriticalConfig()
if err = gcutil.InitLogs(systemCritical.LogDir, &gcutil.LogOptions{FileOnly: true}); err != nil {
os.Exit(1)
}
fatalEv := gcutil.LogFatal()
initDB(fatalEv)
return fatalEv
}
func fatalAndLog(msg string, err error, fatalEv *zerolog.Event) {
fmt.Fprintln(os.Stderr, msg, err)
fatalEv.Err(err).Caller(1).Msg(msg)
}
func parseCommandLine() {
var newstaff string
var delstaff string
var password string
var rank int
var err error
if len(os.Args) < 2 {
return
}
cmd := os.Args[1]
var fatalEv *zerolog.Event
switch cmd {
case "version", "-v", "-version":
fmt.Println(config.GochanVersion)
return
case "help", "-h", "-help":
fmt.Println("Usage: gochan [command] [options]")
fmt.Println("Commands:")
fmt.Println(" version Show the version of gochan")
fmt.Println(" help Show this help message")
fmt.Println(" newstaff Create a new staff account")
fmt.Println(" delstaff Delete a staff account")
fmt.Println(" rebuild Rebuild the specified components")
fmt.Println("Run 'gochan [command] --help' for more information on a command.")
case "newstaff":
flagSet := flag.NewFlagSet("newstaff", flag.ExitOnError)
flagSet.StringVar(&newstaff, "username", "", "Username for the new staff account")
flagSet.StringVar(&password, "password", "", "Password for the new staff account")
flagSet.IntVar(&rank, "rank", 0, "Rank for the new staff account")
flagSet.Parse(os.Args[2:])
if newstaff == "" || rank <= 0 {
fmt.Fprintln(os.Stderr, "Error: -username and -rank are required")
flagSet.Usage()
os.Exit(1)
}
var passwordBytes, confirmBytes []byte
if password == "" {
fmt.Print("Enter password for new staff account: ")
passwordBytes, err = term.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
if errors.Is(err, errAborted) {
fmt.Println("Aborted.")
} else {
fmt.Fprintln(os.Stderr, "Error getting password:", err)
}
os.Exit(1)
}
if len(passwordBytes) == 0 {
fmt.Fprintln(os.Stderr, "Error: Password cannot be empty")
os.Exit(1)
}
fmt.Print("\nConfirm password: ")
confirmBytes, err = term.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
if errors.Is(err, errAborted) {
fmt.Println("Aborted.")
} else {
fmt.Fprintln(os.Stderr, "Error getting password confirmation:", err)
}
os.Exit(1)
}
password = string(passwordBytes)
confirm := string(confirmBytes)
if password != confirm {
fmt.Fprintln(os.Stderr, "Error: Passwords do not match")
os.Exit(1)
}
}
fatalEv = initCommandLine()
staff, err := gcsql.NewStaff(newstaff, password, rank)
if err != nil {
fatalAndLog("Error creating new staff account:", err, fatalEv.Str("source", "commandLine").Str("username", newstaff))
}
gcutil.LogInfo().
Str("source", "commandLine").
Str("username", newstaff).
Msg("New staff account created")
fmt.Printf("New staff account %q created with rank %s\n", newstaff, staff.RankTitle())
case "delstaff":
var force bool
flagSet := flag.NewFlagSet("delstaff", flag.ExitOnError)
flagSet.StringVar(&delstaff, "username", "", "Username of the staff account to delete")
flagSet.BoolVar(&force, "force", false, "Force deletion without confirmation")
flagSet.Parse(os.Args[2:])
if delstaff == "" {
fmt.Fprintln(os.Stderr, "Error: -username is required")
flagSet.Usage()
os.Exit(1)
}
if !force {
fmt.Printf("Are you sure you want to delete the staff account %q? [y/N]: ", delstaff)
var answer string
fmt.Scanln(&answer)
answer = strings.ToLower(answer)
if answer != "y" && answer != "yes" {
fmt.Println("Not deleting.")
return
}
}
fatalEv = initCommandLine()
if err = gcsql.DeactivateStaff(delstaff); err != nil {
fatalAndLog("Error deleting staff account:", err, fatalEv.Str("source", "commandLine").Str("username", delstaff))
}
printInfoAndLog("Staff account deleted successfully", gcutil.LogInfo().Str("source", "commandLine").Str("username", delstaff))
case "rebuild":
flagSet := flag.NewFlagSet("rebuild", flag.ExitOnError)
var rebuildAll bool
var rebuildBoards bool
var rebuildFront bool
var rebuildJS bool
flagSet.BoolVar(&rebuildBoards, "boards", false, "Rebuild boards and threads")
flagSet.BoolVar(&rebuildFront, "front", false, "Rebuild front page")
flagSet.BoolVar(&rebuildJS, "js", false, "Rebuild consts.js")
flagSet.BoolVar(&rebuildAll, "all", false, "Rebuild all components (overrides other flags)")
flagSet.Parse(os.Args[2:])
var rebuildFlag int
if rebuildAll {
rebuildFlag = buildAll
}
if rebuildBoards {
rebuildFlag |= buildBoards
}
if rebuildFront {
rebuildFlag |= buildFront
}
if rebuildJS {
rebuildFlag |= buildJS
}
if rebuildFlag == 0 {
fmt.Fprintln(os.Stderr, "Error: At least one rebuild option is required")
flagSet.Usage()
os.Exit(1)
}
fatalEv = initCommandLine()
startupRebuild(rebuildFlag, fatalEv)
default:
fmt.Fprintln(os.Stderr, "Unknown command:", cmd)
fmt.Println("Run 'gochan help' for a list of commands.")
os.Exit(1)
}
}