Skip to content

Commit

Permalink
add sqlite support
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobmichels committed Jun 13, 2023
1 parent d84df64 commit 7cfbe97
Show file tree
Hide file tree
Showing 13 changed files with 506 additions and 71 deletions.
14 changes: 7 additions & 7 deletions cmd/coursesense/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (
"time"

"github.com/jacobmichels/Course-Sense-Go/config"
"github.com/jacobmichels/Course-Sense-Go/firestore"
"github.com/jacobmichels/Course-Sense-Go/notifier"
"github.com/jacobmichels/Course-Sense-Go/register"
"github.com/jacobmichels/Course-Sense-Go/repository"
"github.com/jacobmichels/Course-Sense-Go/server"
"github.com/jacobmichels/Course-Sense-Go/trigger"
"github.com/jacobmichels/Course-Sense-Go/webadvisor"
Expand All @@ -29,7 +29,7 @@ func main() {
cancel()
}()

cfg, err := config.ReadConfig()
cfg, err := config.ParseConfig()
if err != nil {
log.Panicf("failed to get config: %s", err)
}
Expand All @@ -39,15 +39,15 @@ func main() {
log.Panicf("failed to create WebAdvisorSectionService: %s", err)
}

firestoreService, err := firestore.NewFirestoreWatcherService(ctx, cfg.Firestore.ProjectID, cfg.Firestore.SectionCollectionID, cfg.Firestore.WatcherCollectionID, cfg.Firestore.CredentialsFilePath)
repository, err := repository.New(ctx, cfg.Database)
if err != nil {
log.Panicf("failed to create FirestoreWatcherService: %s", err)
log.Panicf("failed to create repository: %s", err)
}

emailNotifier := notifier.NewEmail(cfg.Smtp.Host, cfg.Smtp.Username, cfg.Smtp.Password, cfg.Smtp.From, cfg.Smtp.Port)
emailNotifier := notifier.NewEmail(cfg.Notifications.EmailSmtp.Host, cfg.Notifications.EmailSmtp.Username, cfg.Notifications.EmailSmtp.Password, cfg.Notifications.EmailSmtp.From, cfg.Notifications.EmailSmtp.Port)

register := register.NewRegister(webadvisorService, firestoreService)
trigger := trigger.NewTrigger(webadvisorService, firestoreService, emailNotifier)
register := register.NewRegister(webadvisorService, repository)
trigger := trigger.NewTrigger(webadvisorService, repository, emailNotifier)

go func() {
log.Println("starting trigger ticker")
Expand Down
68 changes: 39 additions & 29 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,30 @@ import (
"github.com/spf13/viper"
)

type Config struct {
Firestore struct {
ProjectID string `mapstructure:"project_id"`
CredentialsFilePath string `mapstructure:"credentials_file"`
SectionCollectionID string `mapstructure:"section_collection_id"`
WatcherCollectionID string `mapstructure:"watcher_collection_id"`
}
Smtp struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
From string `mapstructure:"from"`
}
// returns a slice of the supported db names
// a function is used to access this list instead of a global slice to prevent accidental mutation of the slice
func getSupportedDbs() []string {
return []string{"sqlite", "firestore"}
}

func ReadConfig() (Config, error) {
// reads the config file
// returns an error if the file couldn't be read or is invalid
func ParseConfig() (Config, error) {
viper.AddConfigPath(".")
viper.SetConfigName("config")
viper.SetConfigType("yaml")

viper.SetDefault("firestore.project_id", "")
viper.SetDefault("firestore.credentials_file", "")
viper.SetDefault("firestore.section_collection_id", "sections")
viper.SetDefault("firestore.watcher_collection_id", "watchers")
viper.SetDefault("smtp.port", 0)
viper.SetDefault("smtp.host", "")
viper.SetDefault("smtp.username", "")
viper.SetDefault("smtp.password", "")
viper.SetDefault("smtp.from", "")
viper.SetDefault("auth.username", "")
viper.SetDefault("auth.password", "")
viper.SetDefault("database.type", "")
viper.SetDefault("database.firestore.project_id", "")
viper.SetDefault("database.firestore.credentials_file", "")
viper.SetDefault("database.firestore.section_collection_id", "sections")
viper.SetDefault("database.firestore.watcher_collection_id", "watchers")
viper.SetDefault("database.sqlite.connection_string", "")
viper.SetDefault("notifications.emailsmtp.port", 0)
viper.SetDefault("notifications.emailsmtp.host", "")
viper.SetDefault("notifications.emailsmtp.username", "")
viper.SetDefault("notifications.emailsmtp.password", "")
viper.SetDefault("notifications.emailsmtp.from", "")

viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()
Expand All @@ -53,10 +45,28 @@ func ReadConfig() (Config, error) {
}
}

var config Config
if err := viper.Unmarshal(&config); err != nil {
var cfg Config
if err := viper.Unmarshal(&cfg); err != nil {
return Config{}, fmt.Errorf("failed to unmarshal config: %s", err)
}

return config, nil
if err := validateConfig(cfg); err != nil {
return Config{}, fmt.Errorf("invalid config: %w", err)
}

return cfg, nil
}

func validateConfig(cfg Config) error {
if cfg.Database.Type == "" {
return fmt.Errorf("no database type set. database type can be one of: %v", getSupportedDbs())
} else if cfg.Database.Type != "sqlite" && cfg.Database.Type != "firestore" {
return fmt.Errorf("bad database type. database type can be one of: %v", getSupportedDbs())
}

if cfg.Database.Type == "sqlite" && cfg.Database.SQLite.ConnectionString == "" {
log.Printf("warn: sqlite connection string is empty")
}

return nil
}
35 changes: 35 additions & 0 deletions config/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package config

type Config struct {
Database Database
Notifications Notifications
}

type Database struct {
Type string `mapstructure:"type"`
Firestore Firestore
SQLite SQLite
}

type Firestore struct {
ProjectID string `mapstructure:"project_id"`
CredentialsFile string `mapstructure:"credentials_file"`
SectionCollectionID string `mapstructure:"section_collection_id"`
WatcherCollectionID string `mapstructure:"watcher_collection_id"`
}

type SQLite struct {
ConnectionString string `mapstructure:"connection_string"`
}

type Notifications struct {
EmailSmtp EmailSmtp
}

type EmailSmtp struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
From string `mapstructure:"from"`
}
7 changes: 4 additions & 3 deletions coursesense.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,13 @@ func (w Watcher) String() string {
return fmt.Sprintf("%s:%s", w.Email, w.Phone)
}

// Service that manages Watchers
type WatcherService interface {
// Service that persists watched sections
type Repository interface {
AddWatcher(context.Context, Section, Watcher) error
GetWatchedSections(context.Context) ([]Section, error)
GetWatchers(context.Context, Section) ([]Watcher, error)
RemoveWatchers(context.Context, Section) error
// This function removes a section and its watchers. It will also remove the associated course if no other sections reference it
Cleanup(context.Context, Section) error
}

// A type that sends can send notifications to Watchers
Expand Down
21 changes: 21 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,52 @@ go 1.19

require (
cloud.google.com/go/firestore v1.10.0
github.com/golang-migrate/migrate/v4 v4.16.2
github.com/julienschmidt/httprouter v1.3.0
github.com/spf13/viper v1.16.0
google.golang.org/api v0.126.0
modernc.org/sqlite v1.23.1
)

require (
cloud.google.com/go v0.110.2 // indirect
cloud.google.com/go/compute v1.19.3 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/longrunning v0.4.2 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/s2a-go v0.1.4 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
github.com/googleapis/gax-go/v2 v2.10.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/spf13/afero v1.9.5 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/crypto v0.9.0 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/oauth2 v0.8.0 // indirect
golang.org/x/sync v0.2.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.9.1 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect
Expand All @@ -47,4 +59,13 @@ require (
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.40.0 // indirect
modernc.org/ccgo/v3 v3.16.13 // indirect
modernc.org/libc v1.22.5 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.5.0 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
)
Loading

0 comments on commit 7cfbe97

Please sign in to comment.