Initial commit

This commit is contained in:
Hayden 2022-08-29 18:30:36 -08:00
commit 29f583e936
135 changed files with 18463 additions and 0 deletions

View file

@ -0,0 +1,81 @@
package config
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"github.com/ardanlabs/conf/v2"
"github.com/ardanlabs/conf/v2/yaml"
"os"
)
const (
ModeDevelopment = "development"
ModeProduction = "production"
)
type Config struct {
Mode string `yaml:"mode" conf:"default:development"` // development or production
Web WebConfig `yaml:"web"`
Database Database `yaml:"database"`
Log LoggerConf `yaml:"logger"`
Mailer MailerConf `yaml:"mailer"`
Seed Seed `yaml:"seed"`
Swagger SwaggerConf `yaml:"swagger"`
}
type SwaggerConf struct {
Host string `yaml:"host" conf:"default:localhost:7745"`
Scheme string `yaml:"scheme" conf:"default:http"`
}
type WebConfig struct {
Port string `yaml:"port" conf:"default:7745"`
Host string `yaml:"host" conf:"default:127.0.0.1"`
}
// NewConfig parses the CLI/Config file and returns a Config struct. If the file argument is an empty string, the
// file is not read. If the file is not empty, the file is read and the Config struct is returned.
func NewConfig(file string) (*Config, error) {
var cfg Config
const prefix = "API"
help, err := func() (string, error) {
if _, err := os.Stat(file); errors.Is(err, os.ErrNotExist) {
return conf.Parse(prefix, &cfg)
} else {
yamlData, err := ioutil.ReadFile(file)
if err != nil {
return "", err
}
return conf.Parse(prefix, &cfg, yaml.WithData(yamlData))
}
}()
if err != nil {
if errors.Is(err, conf.ErrHelpWanted) {
fmt.Println(help)
os.Exit(0)
}
return &cfg, fmt.Errorf("parsing config: %w", err)
}
return &cfg, nil
}
// Print prints the configuration to stdout as a json indented string
// This is useful for debugging. If the marshaller errors out, it will panic.
func (c *Config) Print() {
res, err := json.MarshalIndent(c, "", " ")
if err != nil {
panic(err)
}
fmt.Println(string(res))
}

View file

@ -0,0 +1,27 @@
package config
const (
DriverSqlite3 = "sqlite3"
DriverPostgres = "postgres"
)
type Database struct {
Driver string `yaml:"driver" conf:"default:sqlite3"`
SqliteUrl string `yaml:"sqlite-url" conf:"default:file:ent?mode=memory&cache=shared&_fk=1"`
PostgresUrl string `yaml:"postgres-url" conf:""`
}
func (d *Database) GetDriver() string {
return d.Driver
}
func (d *Database) GetUrl() string {
switch d.Driver {
case DriverSqlite3:
return d.SqliteUrl
case DriverPostgres:
return d.PostgresUrl
default:
panic("unknown database driver")
}
}

View file

@ -0,0 +1,36 @@
package config
import (
"testing"
"github.com/stretchr/testify/assert"
)
func Test_DatabaseConfig_Sqlite(t *testing.T) {
dbConf := &Database{
Driver: DriverSqlite3,
SqliteUrl: "file:ent?mode=memory&cache=shared&_fk=1",
}
assert.Equal(t, "sqlite3", dbConf.GetDriver())
assert.Equal(t, "file:ent?mode=memory&cache=shared&_fk=1", dbConf.GetUrl())
}
func Test_DatabaseConfig_Postgres(t *testing.T) {
dbConf := &Database{
Driver: DriverPostgres,
PostgresUrl: "postgres://user:pass@host:port/dbname?sslmode=disable",
}
assert.Equal(t, "postgres", dbConf.GetDriver())
assert.Equal(t, "postgres://user:pass@host:port/dbname?sslmode=disable", dbConf.GetUrl())
}
func Test_DatabaseConfig_Unknown(t *testing.T) {
dbConf := &Database{
Driver: "null",
}
assert.Panics(t, func() { dbConf.GetUrl() })
}

View file

@ -0,0 +1,6 @@
package config
type LoggerConf struct {
Level string `conf:"default:debug"`
File string `conf:""`
}

View file

@ -0,0 +1,15 @@
package config
type MailerConf struct {
Host string `conf:""`
Port int `conf:""`
Username string `conf:""`
Password string `conf:""`
From string `conf:""`
}
// Ready is a simple check to ensure that the configuration is not empty.
// or with it's default state.
func (mc *MailerConf) Ready() bool {
return mc.Host != "" && mc.Port != 0 && mc.Username != "" && mc.Password != "" && mc.From != ""
}

View file

@ -0,0 +1,40 @@
package config
import (
"testing"
"github.com/stretchr/testify/assert"
)
func Test_MailerReady_Success(t *testing.T) {
mc := &MailerConf{
Host: "host",
Port: 1,
Username: "username",
Password: "password",
From: "from",
}
assert.True(t, mc.Ready())
}
func Test_MailerReady_Failure(t *testing.T) {
mc := &MailerConf{}
assert.False(t, mc.Ready())
mc.Host = "host"
assert.False(t, mc.Ready())
mc.Port = 1
assert.False(t, mc.Ready())
mc.Username = "username"
assert.False(t, mc.Ready())
mc.Password = "password"
assert.False(t, mc.Ready())
mc.From = "from"
assert.True(t, mc.Ready())
}

View file

@ -0,0 +1,13 @@
package config
type SeedUser struct {
Name string `yaml:"name"`
Email string `yaml:"email"`
Password string `yaml:"password"`
IsSuperuser bool `yaml:"isSuperuser"`
}
type Seed struct {
Enabled bool `yaml:"enabled" conf:"default:false"`
Users []SeedUser `yaml:"users"`
}