191 lines
6.1 KiB
Go
191 lines
6.1 KiB
Go
/*
|
|
YetAnotherToDoList
|
|
Copyright © 2023 gilex-dev gilex-dev@proton.me
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, version 3.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
_ "github.com/mattn/go-sqlite3"
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/viper"
|
|
"somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/database"
|
|
"somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/globals"
|
|
)
|
|
|
|
var cfgFile string
|
|
|
|
// rootCmd represents the base command when called without any subcommands
|
|
var rootCmd = &cobra.Command{
|
|
Use: "YetAnotherToDoList",
|
|
Version: fmt.Sprintf("%s %s", globals.Version, globals.CommitHash),
|
|
Short: "Simple To Do List Web Application with Vue.js frontend and GraphQL API",
|
|
Long: `YetAnotherToDoList 2023 by gilex-dev
|
|
A simple To Do List Web Application with Go backend, Vue.js frontend and a GraphQL API
|
|
`,
|
|
// Uncomment the following line if your bare application
|
|
// has an action associated with it:
|
|
// Run: func(cmd *cobra.Command, args []string) { },
|
|
}
|
|
|
|
// Execute adds all child commands to the root command and sets flags appropriately.
|
|
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
|
func Execute() {
|
|
err := rootCmd.Execute()
|
|
if err != nil {
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func init() {
|
|
rootCmd.CompletionOptions.HiddenDefaultCmd = true
|
|
// check if first argument needs init (inspired by https://github.com/spf13/cobra/issues/823#issuecomment-617863653)
|
|
if len(os.Args) > 1 {
|
|
noSetupRequired := []string{"__complete", "__completeNoDesc", "completion", "help", licenseCmd.Name()}
|
|
for _, subcommand := range noSetupRequired {
|
|
if subcommand != os.Args[1] {
|
|
continue
|
|
}
|
|
return
|
|
}
|
|
}
|
|
cobra.OnInitialize(initConfig, initLog, initDB)
|
|
|
|
// Here you will define your flags and configuration settings.
|
|
// Cobra supports persistent flags, which, if defined here,
|
|
// will be global for your application.
|
|
|
|
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.YetAnotherToDoList.yaml)")
|
|
rootCmd.PersistentFlags().String("logFile", "", "Path to log file")
|
|
rootCmd.PersistentFlags().String("sqlite3File", "", "Path to SQLite3 database")
|
|
|
|
// Cobra also supports local flags, which will only run
|
|
// when this action is called directly.
|
|
// rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
|
}
|
|
|
|
// initConfig reads in config file and ENV variables if set.
|
|
func initConfig() {
|
|
if cfgFile != "" {
|
|
// Use config file from the flag.
|
|
viper.SetConfigFile(cfgFile)
|
|
} else {
|
|
// Find home directory.
|
|
home, err := os.UserHomeDir()
|
|
cobra.CheckErr(err)
|
|
|
|
wd, err := os.Getwd()
|
|
cobra.CheckErr(err)
|
|
|
|
// Search config in home directory with name ".YetAnotherToDoList" (without extension).
|
|
viper.AddConfigPath(home)
|
|
// Search config in working directory with name ".YetAnotherToDoList" (without extension).
|
|
viper.AddConfigPath(wd)
|
|
viper.SetConfigType("yaml")
|
|
viper.SetConfigName(".YetAnotherToDoList")
|
|
}
|
|
|
|
viper.AutomaticEnv() // read in environment variables that match
|
|
|
|
// If a config file is found, read it in.
|
|
if err := viper.ReadInConfig(); err == nil {
|
|
fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
|
|
} else {
|
|
fmt.Fprintln(os.Stderr, "Unable to read in", viper.ConfigFileUsed(), err)
|
|
}
|
|
}
|
|
|
|
func initLog() {
|
|
var utc = 0
|
|
var time_zone_use, time_zone_alt string
|
|
|
|
time_zone_local, _ := time.Now().Zone()
|
|
time_zone_offset := strings.Split(time.Now().In(time.Local).String(), " ")[2]
|
|
|
|
if viper.GetBool("logging.logUTC") {
|
|
utc = log.LUTC
|
|
time_zone_use = "UTC"
|
|
time_zone_alt = time_zone_local
|
|
time_zone_offset_rune := []rune(time_zone_offset)
|
|
|
|
if time_zone_offset_rune[0] == '+' {
|
|
time_zone_offset_rune[0] = '-'
|
|
}
|
|
|
|
time_zone_offset = string(time_zone_offset_rune)
|
|
|
|
} else {
|
|
time_zone_use = time_zone_local
|
|
time_zone_alt = "UTC"
|
|
}
|
|
|
|
logger_flags := log.Ldate | log.Ltime | utc
|
|
globals.Logger = log.New(os.Stdout, "", logger_flags)
|
|
|
|
if err := viper.BindPFlag("logging.logFile", rootCmd.Flags().Lookup("logFile")); err != nil {
|
|
fmt.Println("Unable to bind flag:", err)
|
|
}
|
|
|
|
if viper.GetString("logging.logFile") != "" {
|
|
log_path, err := filepath.Abs(viper.GetString("logging.logFile"))
|
|
|
|
globals.Logger.SetOutput(os.Stdout)
|
|
if err != nil {
|
|
globals.Logger.Println("Invalid path for log file", log_path)
|
|
}
|
|
|
|
logFile, err := os.OpenFile(log_path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
|
|
|
|
if err != nil {
|
|
globals.Logger.Println("Failed to write to log file:", err)
|
|
} else {
|
|
globals.Logger.Println("Switching to log file", log_path)
|
|
globals.Logger.SetOutput(logFile)
|
|
}
|
|
}
|
|
|
|
globals.Logger.SetFlags(0)
|
|
globals.Logger.Println()
|
|
globals.Logger.SetFlags(logger_flags)
|
|
globals.Logger.Printf("Started YetAnotherToDoList with pid: %v\n", os.Getpid())
|
|
globals.Logger.Printf("Using %v (%v %v) in logs", time_zone_use, time_zone_alt, time_zone_offset)
|
|
}
|
|
|
|
func initDB() {
|
|
if err := viper.BindPFlag("database.sqlite3File", rootCmd.Flags().Lookup("sqlite3File")); err != nil {
|
|
fmt.Println("Unable to bind flag:", err)
|
|
}
|
|
|
|
if viper.GetString("database.sqlite3File") == "" {
|
|
globals.Logger.Fatalln("No SQLite3 file specified")
|
|
}
|
|
|
|
db_path, err := filepath.Abs(viper.GetString("database.sqlite3File"))
|
|
if err != nil {
|
|
globals.Logger.Fatalln("Invalid path for SQLite3 file", db_path)
|
|
}
|
|
|
|
globals.Logger.Println("Connecting to SQLite3", db_path)
|
|
globals.DB = database.InitSQLite3(db_path, globals.DB_schema, globals.Logger, []byte(viper.GetString("database.secret")), viper.GetString("database.initialAdmin.userName"), viper.GetString("database.initialAdmin.password"))
|
|
globals.DB.CleanExpiredRefreshTokensTicker(time.Minute * 10)
|
|
globals.DB.CleanRevokedAccessTokensTicker(time.Minute * 10)
|
|
}
|