// Package batch contains the non-interactive maintenence commands. package batch import ( _ "embed" "errors" "fmt" "os" "path" "strings" "text/template" "time" "git.lyda.ie/kevin/bulletin/ask" "git.lyda.ie/kevin/bulletin/key" "git.lyda.ie/kevin/bulletin/storage" "github.com/adrg/xdg" ) //go:embed crontab var crontabTemplate string // Reboot deletes all messages with `shutdown` set. func Reboot() int { ctx := storage.Context() store, err := storage.Open() ask.CheckErr(err) q := storage.New(store.DB) rows, err := q.DeleteAllShutdownMessages(ctx) ask.CheckErr(err) fmt.Printf("Removed %d shutdown messages\n", rows) return 0 } // Expire deletes all messages that have hit their expiration date. func Expire() int { ctx := storage.Context() store, err := storage.Open() ask.CheckErr(err) q := storage.New(store.DB) rows, err := q.DeleteAllExpiredMessages(ctx) ask.CheckErr(err) fmt.Printf("Expired %d messages\n", rows) return 0 } // Install is an interactive command used to install the crontab. func Install() int { ctx := storage.Context() // Check if install has run before. touchfile := path.Join(xdg.Home, ".bulletin-installed") if _, err := os.Stat(touchfile); err == nil { ask.CheckErr(errors.New("~/.bulletin-installed exists; BULLETIN install has run")) } else { if !errors.Is(err, os.ErrNotExist) { fmt.Println("ERROR: Unknown error checking in ~/.bulletin-installed exists.") fmt.Println("ERROR: Can't see if BULLETIN has been installed.") ask.CheckErr(err) } } // Connect to the database. store, err := storage.Open() ask.CheckErr(err) q := storage.New(store.DB) // Create the initial users. fmt.Println(`Welcome to the BULLETIN install process. This will create the following files: * ~/.local/share/BULLETIN/bulletin.db - BULLETIN's folder and user db. * ~/.bulletin-installed - A file to make sure install isn't run again. * ~/.config/BULLETIN/* - history files for each user. * ~/.ssh/authorized_keys - key lines to let users connect to BULLETIN To complete the installation, please enter the login, name and ssh key for the first user.`) login, err := ask.GetLine("Enter login of initial user: ") login = strings.ToUpper(login) ask.CheckErr(err) name, err := ask.GetLine("Enter name of initial user: ") ask.CheckErr(err) sshkey, err := ask.GetLine("Enter ssh public key of initial user: ") ask.CheckErr(err) // Seed data. seedMsgs, err := GetSeedMessages() ask.CheckErr(err) ask.CheckErr(q.SeedUserSystem(ctx)) ask.CheckErr(q.SeedFolderGeneral(ctx)) ask.CheckErr(q.SeedGeneralOwner(ctx)) _, err = q.AddUser(ctx, storage.AddUserParams{ Login: login, Name: name, }) key.Add(login, sshkey) userCreated := map[string]bool{ "SYSTEM": true, login: true, } for i := range seedMsgs { if !userCreated[seedMsgs[i].Login] { _, err = q.AddUser(ctx, storage.AddUserParams{ Login: seedMsgs[i].Login, Name: seedMsgs[i].Name, Disabled: 1, }) ask.CheckErr(err) userCreated[seedMsgs[i].Login] = true } ask.CheckErr(q.SeedCreateMessage(ctx, storage.SeedCreateMessageParams{ Folder: "GENERAL", Author: seedMsgs[i].Login, Subject: seedMsgs[i].Subject, Message: seedMsgs[i].Message, CreateAt: seedMsgs[i].Date, Expiration: time.Now(), })) } // Install crontab. bulletin, err := os.Executable() if err != nil { panic(err) // TODO: cleanup error handling. } crontab := &strings.Builder{} template.Must(template.New("crontab").Parse(crontabTemplate)). Execute(crontab, map[string]string{"Bulletin": bulletin}) fmt.Printf("Adding this to crontab:\n\n%s\n", crontab.String()) err = installCrontab(crontab.String()) if err != nil { panic(err) // TODO: cleanup error handling. } // Mark that install has happened. err = touch(touchfile) if err != nil { panic(err) // TODO: cleanup error handling. } return 0 }