Skip to content

Commit

Permalink
Merge pull request #260 from systemli/Add-Command-to-create-User
Browse files Browse the repository at this point in the history
πŸ§‘β€πŸ’» Add Command to create User
  • Loading branch information
0x46616c6b authored Oct 23, 2023
2 parents 2f11138 + 4fe63cc commit 4592ab5
Show file tree
Hide file tree
Showing 13 changed files with 82 additions and 104 deletions.
14 changes: 1 addition & 13 deletions cmd/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"github.com/asdine/storm"
"github.com/spf13/cobra"
"github.com/systemli/ticker/internal/legacy"
"github.com/systemli/ticker/internal/storage"
)

var (
Expand All @@ -27,19 +26,8 @@ var (
}
defer oldDb.Close()

db, err := storage.OpenGormDB(cfg.Database.Type, cfg.Database.DSN, log)
if err != nil {
log.WithError(err).Fatal("Unable to open the new database")
}

if err := storage.MigrateDB(db); err != nil {
log.WithError(err).Fatal("Unable to migrate the database")
}

legacyStorage := legacy.NewLegacyStorage(oldDb)
newStorage := storage.NewSqlStorage(db, cfg.UploadPath)

migration := legacy.NewMigration(legacyStorage, newStorage)
migration := legacy.NewMigration(legacyStorage, store)
if err := migration.Do(); err != nil {
log.WithError(err).Fatal("Unable to migrate the database")
}
Expand Down
15 changes: 15 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ import (
"github.com/systemli/ticker/internal/bridge"
"github.com/systemli/ticker/internal/config"
"github.com/systemli/ticker/internal/logger"
"github.com/systemli/ticker/internal/storage"
"gorm.io/gorm"
)

var (
configPath string
cfg config.Config
db *gorm.DB
store *storage.SqlStorage

log = logrus.New()

Expand Down Expand Up @@ -42,11 +46,22 @@ func initConfig() {
}

log = logger.NewLogrus(cfg.LogLevel, cfg.LogFormat)

var err error
db, err = storage.OpenGormDB(cfg.Database.Type, cfg.Database.DSN, log)
if err != nil {
log.WithError(err).Fatal("could not connect to database")
}
store = storage.NewSqlStorage(db, cfg.UploadPath)
if err := storage.MigrateDB(db); err != nil {
log.WithError(err).Fatal("could not migrate database")
}
}

func Execute() {
rootCmd.AddCommand(runCmd)
rootCmd.AddCommand(dbCmd)
rootCmd.AddCommand(userCmd)
rootCmd.AddCommand(versionCmd)

if err := rootCmd.Execute(); err != nil {
Expand Down
41 changes: 0 additions & 41 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,8 @@ import (
"time"

"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/sethvargo/go-password/password"
"github.com/spf13/cobra"
"github.com/systemli/ticker/internal/api"
"github.com/systemli/ticker/internal/config"
"github.com/systemli/ticker/internal/storage"
)

var (
Expand All @@ -36,23 +33,12 @@ var (
log.Fatal(http.ListenAndServe(cfg.MetricsListen, nil))
}()

db, err := storage.OpenGormDB(cfg.Database.Type, cfg.Database.DSN, log)
if err != nil {
log.WithError(err).Fatal("could not connect to database")
}
store := storage.NewSqlStorage(db, cfg.UploadPath)
if err := storage.MigrateDB(db); err != nil {
log.WithError(err).Fatal("could not migrate database")
}

router := api.API(cfg, store, log)
server := &http.Server{
Addr: cfg.Listen,
Handler: router,
}

firstRun(store, cfg)

go func() {
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal(err)
Expand All @@ -75,30 +61,3 @@ var (
},
}
)

func firstRun(store storage.Storage, config config.Config) {
count, err := store.CountUser()
if err != nil {
log.Fatal("error using database")
}

if count == 0 {
pw, err := password.Generate(24, 3, 3, false, false)
if err != nil {
log.Fatal(err)
}

user, err := storage.NewUser(config.Initiator, pw)
user.IsSuperAdmin = true
if err != nil {
log.Fatal("could not create first user")
}

err = store.SaveUser(&user)
if err != nil {
log.Fatal("could not persist first user")
}

log.WithField("email", user.Email).WithField("password", pw).Info("admin user created (change password now!)")
}
}
61 changes: 61 additions & 0 deletions cmd/user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package cmd

import (
"fmt"

"github.com/spf13/cobra"
"github.com/systemli/ticker/internal/storage"

pwd "github.com/sethvargo/go-password/password"
)

var (
email string
password string
isSuperAdmin bool

userCmd = &cobra.Command{
Use: "user",
Short: "Manage users",
Long: "Commands for managing users.",
Args: cobra.ExactArgs(1),
}

userCreateCmd = &cobra.Command{
Use: "create",
Short: "Create a new user",
Run: func(cmd *cobra.Command, args []string) {
var err error
if email == "" {
log.Fatal("email is required")
}
if password == "" {
password, err = pwd.Generate(24, 3, 3, false, false)
if err != nil {
log.WithError(err).Fatal("could not generate password")
}
}

user, err := storage.NewUser(email, password)
if err != nil {
log.WithError(err).Fatal("could not create user")
}
user.IsSuperAdmin = isSuperAdmin

if err := store.SaveUser(&user); err != nil {
log.WithError(err).Fatal("could not save user")
}

fmt.Printf("Created user %d\n", user.ID)
fmt.Printf("Password: %s\n", password)
},
}
)

func init() {
userCmd.AddCommand(userCreateCmd)

userCreateCmd.Flags().StringVar(&email, "email", "", "email address of the user")
userCreateCmd.Flags().StringVar(&password, "password", "", "password of the user")
userCreateCmd.Flags().BoolVar(&isSuperAdmin, "super-admin", false, "make the user a super admin")
}
2 changes: 0 additions & 2 deletions config.yml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ listen: "localhost:8080"
log_level: "error"
# log_format sets log format for logrus (default: json)
log_format: "json"
# initiator is the email for the first admin user (see password in logs)
initiator: "[email protected]"
# configuration for the database
database:
type: "sqlite" # postgres, mysql, sqlite
Expand Down
2 changes: 0 additions & 2 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ listen: "localhost:8080"
log_level: "error"
# log_format sets log format for logrus (default: json)
log_format: "json"
# initiator is the email for the first admin user (see password in logs)
initiator: "[email protected]"
# configuration for the database
database:
type: "sqlite" # postgres, mysql, sqlite
Expand Down
4 changes: 4 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ This repository contains the API for the [Systemli Ticker Project](https://www.s

curl http://localhost:8080/healthz

4. Create a user

go run . user create --email <email-address> --password <password> --super-admin

## Testing

```shell
Expand Down
3 changes: 0 additions & 3 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ type Config struct {
Listen string `mapstructure:"listen"`
LogLevel string `mapstructure:"log_level"`
LogFormat string `mapstructure:"log_format"`
Initiator string `mapstructure:"initiator"`
Secret string `mapstructure:"secret"`
Database Database `mapstructure:"database"`
TelegramBotToken string `mapstructure:"telegram_bot_token"`
Expand All @@ -39,7 +38,6 @@ func NewConfig() Config {
Listen: ":8080",
LogLevel: "debug",
LogFormat: "json",
Initiator: "[email protected]",
Secret: secret,
Database: Database{Type: "sqlite", DSN: "ticker.db"},
MetricsListen: ":8181",
Expand All @@ -63,7 +61,6 @@ func LoadConfig(path string) Config {
viper.SetDefault("listen", c.Listen)
viper.SetDefault("log_level", c.LogLevel)
viper.SetDefault("log_format", c.LogFormat)
viper.SetDefault("initiator", c.Initiator)
viper.SetDefault("secret", c.Secret)
viper.SetDefault("database", c.Database)
viper.SetDefault("metrics_listen", c.MetricsListen)
Expand Down
24 changes: 0 additions & 24 deletions internal/storage/mock_Storage.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 0 additions & 7 deletions internal/storage/sql_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,6 @@ func NewSqlStorage(db *gorm.DB, uploadPath string) *SqlStorage {
}
}

func (s *SqlStorage) CountUser() (int, error) {
var count int64
err := s.DB.Model(&User{}).Count(&count).Error

return int(count), err
}

func (s *SqlStorage) FindUsers() ([]User, error) {
users := make([]User, 0)
err := s.DB.Find(&users).Error
Expand Down
10 changes: 0 additions & 10 deletions internal/storage/sql_storage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,6 @@ var _ = Describe("SqlStorage", func() {
db.Exec("DELETE FROM uploads")
})

Describe("CountUser", func() {
It("returns the number of users", func() {
Expect(store.CountUser()).To(Equal(0))

err := db.Create(&User{}).Error
Expect(err).ToNot(HaveOccurred())
Expect(store.CountUser()).To(Equal(1))
})
})

Describe("FindUsers", func() {
It("returns all users", func() {
users, err := store.FindUsers()
Expand Down
1 change: 0 additions & 1 deletion internal/storage/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
var log = logrus.WithField("package", "storage")

type Storage interface {
CountUser() (int, error)
FindUsers() ([]User, error)
FindUserByID(id int) (User, error)
FindUsersByIDs(ids []int) ([]User, error)
Expand Down
2 changes: 1 addition & 1 deletion internal/storage/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type User struct {
ID int `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
Email string `storm:"unique"`
Email string `gorm:"uniqueIndex;not null"`
EncryptedPassword string
IsSuperAdmin bool
Tickers []Ticker `gorm:"many2many:ticker_users;"`
Expand Down

0 comments on commit 4592ab5

Please sign in to comment.