tonyslist/config/config.go
Tony Grosinger d7d12d51c2
All checks were successful
Build Production Image / Build Production Image (push) Successful in 9m11s
Add wiki oauth config
2025-03-30 21:54:25 -07:00

273 lines
7.6 KiB
Go

package config
import (
"path/filepath"
"time"
"github.com/spf13/viper"
)
const (
migrationsDir = "db/migrations"
// templateDir stores the name of the directory that contains templates
templateDir = "templates"
// TemplateExt stores the extension used for the template files
TemplateExt = ".gohtml"
// staticDir stores the name of the directory that will serve static files
staticDir = "static"
// StaticPrefix stores the URL prefix used when serving static files
StaticPrefix = "files"
// UserContentPrefix stores the URL prefix used when service static files that were uploaded by users.
UserContentPrefix = "usercontent"
)
type environment string
const (
// EnvLocal represents the local environment
EnvLocal environment = "local"
// EnvTest represents the test environment
EnvTest environment = "test"
// EnvProduction represents the production environment
EnvProduction environment = "prod"
)
// builtinDirectoryPath returns the path to a directory depending on whether the
// app is running in production or not. During development and testing it is
// assumed that the directory is contained in the root directory. During
// production it should be at the filesystem root since it will be included in
// the container at build time.
func builtinDirectoryPath(cfg *Config, dirname string) string {
if cfg.App.Environment == EnvProduction {
return "/" + dirname
}
return filepath.Join(cfg.Storage.RootDir, dirname)
}
func StaticDir(cfg *Config) string {
return builtinDirectoryPath(cfg, staticDir)
}
func TemplateDir(cfg *Config) string {
return builtinDirectoryPath(cfg, templateDir)
}
func MigrationsDir(cfg *Config) string {
return builtinDirectoryPath(cfg, migrationsDir)
}
type (
// Config stores complete configuration
Config struct {
HTTP HTTPConfig
App AppConfig
Flags FlagsConfig
Cache CacheConfig
Storage StorageConfig
Mail MailConfig
Mapbox MapboxConfig
Discourse DiscourseConfig
Wiki WikiConfig
Stripe StripeConfig
}
// HTTPConfig stores HTTP configuration
HTTPConfig struct {
Hostname string
Port uint16
ReadTimeout time.Duration
WriteTimeout time.Duration
IdleTimeout time.Duration
TLS struct {
Enabled bool
Certificate string
Key string
}
}
// AppConfig stores application configuration
AppConfig struct {
Name string
Environment environment
// Location is the IANA timezone database name where the users are located.
// This assumes that the application serves a narrow geographical area.
Location string
// Loc is the parsed Location
Loc *time.Location
// Should include the protocol but not the trailing slash.
PublicURL string
// THIS MUST BE OVERRIDDEN ON ANY LIVE ENVIRONMENTS
EncryptionKey string
Timeout time.Duration
EmailVerificationTokenExpiration time.Duration
// MaxWorkers defines the maximum number of workers that will be created
// in the worker pool for async tasks.
MaxWorkers int
// MetricsPort is the port on which Prometheus metrics will be served.
MetricsPort uint16
// HooksUsername is the basic auth username which protects the hooks endpoints
HooksUsername string
// HooksPassword string is the basic auth password which protects the hooks endpoints
HooksPassword string
}
FlagsConfig struct{}
// CacheConfig stores the cache configuration
// TODO: Tune these
CacheConfig struct {
NumCounters int64
MaxCost int64
BufferItems int64
Expiration struct {
StaticFile time.Duration
Page time.Duration
}
}
// Storage stores the configuration for different types of storage. The
// template and static file directories are not included here because their
// location is predefined at the root of the container when running in
// production and
StorageConfig struct {
// PhotoStorageDir is the path relative to RootDir where uploaded
// photos are stored until they can be converted and stored in the database.
PhotoStorageDir string
// DatabaseFile is the absolute path to the database sqlite file.
DatabaseFile string
// RBACPolicyPath is the path relative to the root dir containing the policy csv.
RBACPolicyPath string
// RootDir is the absolute path to the directory where the templates,
// db, and static directories can be found. This setting will default to
// "/" when not set, and should not be set in production.
RootDir string
}
// MailConfig stores the mail configuration
MailConfig struct {
// ConfigurePostmark controls whether the application will attempt to
// configure the Postmark provider by creating the message streams and
// webhooks.
ConfigurePostmark bool
Token string
Enable bool
// Domain is the part after the @ where this application is listening for emails.
// It is used for anonymous email addresses on classified posts.
Domain string
// FromAddress is the email address used to send emails from the app.
FromAddress string
// DigestsAddress is the email used to send the twice weekly email digests.
DigestsAddress string
// SupportAddress is the address which users send to when they need support.
// Emails received for this address will be forwarded to the AdminAddress.
SupportAddress string
// EventsAddress is the address used for RSVPs on events.
EventsAddress string
// AdminAddress is the address which incoming emails that are for an unknown address for for support are forwarded to.
// It should be a real mailbox, not the email provider used by this app, otherwise a loop will occur.
AdminAddress string
}
// MapboxConfig stores the configuration for interacting with Mapbox
MapboxConfig struct {
Token string
// BoundingBox is a string such as "-123.0414,48.5843,-122.7352,48.7191"
// which denotes the minimum area that should be included in the map
// image retrieved.
//
// The bounding box is also used to restrict address lookups.
BoundingBox string
// Resolution is a string such as "560x420" which determines the
// resolution of the image retrieved from MapBox.
Resolution string
}
DiscourseConfig struct {
// ClientID is the OAuth2 client_id used by Discourse to connect to this server.
ClientID string
// ClientSecret is the OAuth2 client_secret used by Discourse to connect to this server.
ClientSecret string
// Domain is the domain Discourse is accessible on.
Domain string
}
// Parameters are the same as for the DiscourseConfig.
WikiConfig struct {
ClientID string
ClientSecret string
Domain string
}
StripeConfig struct {
SecretKey string
PublishableKey string
// ID of the subscription product in Stripe. This is used for creating
// custom subscription amounts.
SubscriptionIDProduct string
// ID of the $5/yr subscription in Stripe.
SubscriptionID5 string
// ID of the $10/yr subscription in Stripe.
SubscriptionID10 string
// ID of the $25/yr subscription in Stripe.
SubscriptionID25 string
}
)
// GetConfig loads and returns configuration
func GetConfig(configFilePath string) (Config, error) {
viper.SetConfigFile(configFilePath)
configDir := filepath.Dir(configFilePath)
viper.SetDefault("storage.rootDir", configDir)
viper.SetDefault("storage.DatabaseFile", "data.sqlite")
viper.SetDefault("storage.PhotoStorageDir", "storage")
var c Config
if err := viper.ReadInConfig(); err != nil {
return c, err
}
if err := viper.Unmarshal(&c); err != nil {
return c, err
}
var err error
c.App.Loc, err = time.LoadLocation(c.App.Location)
if err != nil {
return c, err
}
// TODO: Check for required config values
return c, nil
}