redesign
This commit is contained in:
84
internal/command/command.go
Normal file
84
internal/command/command.go
Normal file
@ -0,0 +1,84 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
|
||||
// "github.com/jordanknott/taskcafe/internal/config"
|
||||
// "github.com/jordanknott/taskcafe/internal/utils"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const mainDescription = `Taskcafé is an open soure project management
|
||||
system written in Golang & React.`
|
||||
|
||||
func VersionTemplate() string {
|
||||
/*
|
||||
info := utils.Version()
|
||||
return fmt.Sprintf(`Version: %s
|
||||
Commit: %s
|
||||
Built: %s`, info.Version, info.CommitHash, info.BuildDate+"\n")
|
||||
*/
|
||||
return ""
|
||||
}
|
||||
|
||||
var cfgFile string
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "taskcafe",
|
||||
Long: mainDescription,
|
||||
Version: VersionTemplate(),
|
||||
}
|
||||
|
||||
var migration http.FileSystem
|
||||
|
||||
func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
|
||||
Formatter := new(logrus.TextFormatter)
|
||||
Formatter.TimestampFormat = "02-01-2006 15:04:05"
|
||||
Formatter.FullTimestamp = true
|
||||
logrus.SetFormatter(Formatter)
|
||||
logrus.SetLevel(logrus.InfoLevel)
|
||||
|
||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file path")
|
||||
migration = http.Dir("./migrations")
|
||||
}
|
||||
|
||||
func initConfig() {
|
||||
if cfgFile != "" {
|
||||
// Use config file from the flag.
|
||||
viper.SetConfigFile(cfgFile)
|
||||
} else {
|
||||
// Search config in home directory with name ".cobra" (without extension).
|
||||
viper.AddConfigPath("./conf")
|
||||
viper.AddConfigPath(".")
|
||||
viper.AddConfigPath("/etc/taskcafe")
|
||||
viper.SetConfigName("taskcafe")
|
||||
}
|
||||
|
||||
viper.SetEnvPrefix("TASKCAFE")
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
viper.AutomaticEnv()
|
||||
// config.InitDefaults()
|
||||
|
||||
err := viper.ReadInConfig()
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Execute the root cobra command
|
||||
func Execute() {
|
||||
rootCmd.SetVersionTemplate(VersionTemplate())
|
||||
rootCmd.AddCommand(newMigrateCmd(), newUserCmd(), newWebCmd())
|
||||
rootCmd.Execute()
|
||||
}
|
33
internal/command/migrate.go
Normal file
33
internal/command/migrate.go
Normal file
@ -0,0 +1,33 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
"github.com/pressly/goose/v3"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newMigrateCmd() *cobra.Command {
|
||||
cc := &cobra.Command{
|
||||
Use: "migrate",
|
||||
Short: "run the migrations",
|
||||
Long: "Run the migrations",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
appConfig, err := config.GetAppConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(appConfig.Database.GetDatabaseConnectionUri())
|
||||
db, err := sql.Open("postgres", appConfig.Database.GetDatabaseConnectionUri())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return goose.Up(db, "migrations")
|
||||
},
|
||||
}
|
||||
cc.AddCommand(newMigrateCreateCmd())
|
||||
return cc
|
||||
}
|
29
internal/command/migrate_create.go
Normal file
29
internal/command/migrate_create.go
Normal file
@ -0,0 +1,29 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
"github.com/pressly/goose/v3"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newMigrateCreateCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "create name type",
|
||||
Short: "Create a new migration file",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
appConfig, err := config.GetAppConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
db, err := sql.Open("postgres", appConfig.Database.GetDatabaseConnectionUri())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return goose.Create(db, "migrations", args[0], args[1])
|
||||
},
|
||||
}
|
||||
}
|
9
internal/command/user.go
Normal file
9
internal/command/user.go
Normal file
@ -0,0 +1,9 @@
|
||||
package command
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
func newUserCmd() *cobra.Command {
|
||||
cc := cobra.Command{Use: "user"}
|
||||
cc.AddCommand(newUserListCmd(), newUserCreateCmd())
|
||||
return &cc
|
||||
}
|
57
internal/command/user_create.go
Normal file
57
internal/command/user_create.go
Normal file
@ -0,0 +1,57 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
"github.com/manifoldco/promptui"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func newUserCreateCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "create <username> <email>",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
appConfig, err := config.GetAppConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dbConn, err := sql.Open("postgres", appConfig.Database.GetDatabaseConnectionUri())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
prompt := promptui.Prompt{
|
||||
Label: "User's fullname",
|
||||
}
|
||||
fullname, err := prompt.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
prompt = promptui.Prompt{
|
||||
Label: "User's password",
|
||||
Mask: '*',
|
||||
}
|
||||
password, err := prompt.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repo := db.NewRepository(dbConn)
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(password), 10)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
createdAt := time.Now().UTC()
|
||||
account, err := repo.CreateUserAccount(context.Background(), db.CreateUserAccountParams{Username: args[0], Email: args[1], Fullname: fullname, PasswordHash: string(hash), CreatedAt: createdAt})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Created account: " + account.UserID.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
41
internal/command/user_list.go
Normal file
41
internal/command/user_list.go
Normal file
@ -0,0 +1,41 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"os"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newUserListCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "list",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
appConfig, err := config.GetAppConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dbConn, err := sql.Open("postgres", appConfig.Database.GetDatabaseConnectionUri())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t := table.NewWriter()
|
||||
t.SetOutputMirror(os.Stdout)
|
||||
t.AppendHeader(table.Row{"#", "Full Name", "Username", "Email"})
|
||||
repo := db.NewRepository(dbConn)
|
||||
accounts, err := repo.GetUserAccounts(context.Background())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
for _, account := range accounts {
|
||||
t.AppendRow(table.Row{account.UserID.String(), account.Fullname, account.Username, account.Email})
|
||||
}
|
||||
t.Render()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
75
internal/command/web.go
Normal file
75
internal/command/web.go
Normal file
@ -0,0 +1,75 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/jordanknott/taskcafe/internal/api"
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func newWebCmd() *cobra.Command{
|
||||
cc := &cobra.Command{
|
||||
Use: "web",
|
||||
Short: "Run the web server",
|
||||
Long: "Run the web & api server",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
Formatter := new(logrus.TextFormatter)
|
||||
Formatter.TimestampFormat = "02-01-2006 15:04:05"
|
||||
Formatter.FullTimestamp = true
|
||||
logrus.SetFormatter(Formatter)
|
||||
logrus.SetLevel(logrus.InfoLevel)
|
||||
|
||||
appConfig, err := config.GetAppConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var db *sql.DB
|
||||
var retryDuration time.Duration
|
||||
maxRetryNumber := 4
|
||||
for i := 0; i < maxRetryNumber; i++ {
|
||||
db, err = sql.Open("postgres", appConfig.Database.GetDatabaseConnectionUri())
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
retryDuration = time.Duration(i*2) * time.Second
|
||||
logrus.WithFields(logrus.Fields{"retryNumber": i, "retryDuration": retryDuration}).WithError(err).Error("issue connecting to database, retrying")
|
||||
if i != maxRetryNumber-1 {
|
||||
time.Sleep(retryDuration)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
db.SetMaxOpenConns(25)
|
||||
db.SetMaxIdleConns(25)
|
||||
db.SetConnMaxLifetime(5 * time.Minute)
|
||||
defer db.Close()
|
||||
|
||||
if viper.GetBool("migrate") {
|
||||
logrus.Info("running auto schema migrations")
|
||||
/*
|
||||
if err = runMigration(db); err != nil {
|
||||
return err
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
r, _ := api.NewRouter(db)
|
||||
|
||||
logrus.WithFields(logrus.Fields{"url": viper.GetString("server.hostname")}).Info("starting server")
|
||||
return http.ListenAndServe(viper.GetString("server.hostname"), r)
|
||||
},
|
||||
}
|
||||
|
||||
cc.Flags().Bool("migrate", false, "if true, auto run's schema migrations before starting the web server")
|
||||
|
||||
viper.BindPFlag("migrate", cc.Flags().Lookup("migrate"))
|
||||
viper.SetDefault("migrate", false)
|
||||
return cc
|
||||
}
|
Reference in New Issue
Block a user