Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🧑‍💻 Add Command to create User #260

Merged
merged 2 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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: "admin@systemli.org"
# 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: "admin@systemli.org"
# 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: "admin@systemli.org",
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
Loading