From 922c47d4915ddd73e30cd080991148b552660655 Mon Sep 17 00:00:00 2001 From: lauralani Date: Tue, 4 Jul 2023 16:56:09 +0200 Subject: [PATCH] working daemon with new logging and posting --- app/cli.go | 30 ++++++-- app/humble.go | 130 ++++++++++++++------------------ app/mastodon.go | 72 ++++++++++++++++++ app/queue.go | 49 ++++++++++++ cmd/daemon.go | 5 +- cmd/root.go | 25 +++--- {app => constants}/constants.go | 6 +- db/db.go | 80 +++++++++++++++++++- examples/config.yaml | 15 +++- go.mod | 40 ++++------ go.sum | 75 +++++++++--------- log/logger.go | 27 +++++++ misc/http.go | 27 +++++++ models/db.go | 9 ++- 14 files changed, 426 insertions(+), 164 deletions(-) create mode 100644 app/mastodon.go create mode 100644 app/queue.go rename {app => constants}/constants.go (62%) create mode 100644 log/logger.go create mode 100644 misc/http.go diff --git a/app/cli.go b/app/cli.go index 68a6a36..2574301 100644 --- a/app/cli.go +++ b/app/cli.go @@ -7,16 +7,36 @@ package app import ( - "fmt" + "github.com/go-co-op/gocron" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" + "github.com/spf13/viper" + "time" ) func RunRoot(cmd *cobra.Command, args []string) { - for _, category := range HumbleCategories { - UpdateCategory(category) - } + UpdateBundles() } func RunDaemon(cmd *cobra.Command, args []string) { - fmt.Println("daemon called") + StartCronJobs() +} + +func StartCronJobs() { + s := gocron.NewScheduler(time.UTC) + + _, err := s.Every(viper.GetString("humblebundle.pollinterval")).Do(UpdateBundles) + if err != nil { + log.Error().Str("func", "StartCronJobs").Str("job", "UpdateBundlesJob"). + Msgf("Scheduler Error: %q", err) + return + } + + _, err = s.Every(viper.GetString("mastodon.postinterval")).Do(RunSingleQueueItem) + if err != nil { + log.Error().Str("func", "StartCronJobs").Str("job", "RunSingleQueueItem"). + Msgf("Scheduler Error: %q", err) + return + } + s.StartBlocking() } diff --git a/app/humble.go b/app/humble.go index c7296ed..7fcb21a 100644 --- a/app/humble.go +++ b/app/humble.go @@ -7,98 +7,65 @@ package app import ( - "bytes" + "codeberg.org/lauralani/humble-bot/constants" + "codeberg.org/lauralani/humble-bot/db" "codeberg.org/lauralani/humble-bot/misc" "codeberg.org/lauralani/humble-bot/models" "encoding/json" "fmt" "github.com/PuerkitoBio/goquery" - "github.com/google/uuid" - "github.com/spf13/viper" + "github.com/rs/zerolog/log" "io" - "log" - "net/http" "net/url" - "strings" - "time" ) -func UpdateCategory(category string) { - response, err := http.Get("https://www.humblebundle.com/" + category) - if err != nil { - log.Printf("Status: %v, Error: %q\n", response.Status, err) - } - defer func(Body io.ReadCloser) { - err = Body.Close() +func UpdateBundles() { + log.Debug().Str("func", "UpdateBundles").Msg("starting bundle run") + + for _, category := range constants.HumbleCategories { + log.Debug().Str("category", category).Msg("starting bundle update") + endpoint, _ := url.Parse("https://www.humblebundle.com/" + category) + + client := misc.CustomHttpClient() + req := misc.CustomHttpRequest() + req.URL = endpoint + req.Method = "GET" + + response, err := client.Do(req) if err != nil { - log.Printf("Error: %q\n", err) + log.Error().Str("category", category).Str("status", response.Status). + Str("func", "app.UpdateBundles").Msgf("HTTP Error: %q", err) } - }(response.Body) + defer func(Body io.ReadCloser) { + err = Body.Close() + if err != nil { + log.Error().Str("func", "app.UpdateBundles").Msg(err.Error()) + } + }(response.Body) - document, err := goquery.NewDocumentFromReader(response.Body) - if err != nil { - log.Printf("Error: %q\n", err) - } - - document.Find("script#landingPage-json-data").Each(func(idx int, s *goquery.Selection) { - node := s.Nodes[0] - data := node.FirstChild.Data - products, err := parseBundles([]byte(data), category) + document, err := goquery.NewDocumentFromReader(response.Body) if err != nil { - log.Printf("Error: %q\n", err) + log.Error().Str("func", "app.UpdateBundles").Msg(err.Error()) } - for _, product := range products { - builder := new(strings.Builder) - - builder.WriteString(product.TileName) - builder.WriteString("\n\n") - - builder.WriteString(misc.Sanitize(product.MarketingBlurb)) - builder.WriteString("\n\n") - - builder.WriteString("https://www.humblebundle.com") - builder.WriteString(product.ProductURL) - - builder.WriteString("\n\n") - builder.WriteString("#humblebundle #humble" + category + "bundle #" + category) - - payload := url.Values{} - payload.Add("status", builder.String()) - payload.Add("visibility", "private") - payload.Add("language", "en") - - endpoint := viper.GetString("mastodon.url") + "/api/v1/statuses" - token := viper.GetString("mastodon.token") - idemkey := uuid.New().String() - - client := &http.Client{} - req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer([]byte(payload.Encode()))) + document.Find("script#landingPage-json-data").Each(func(idx int, s *goquery.Selection) { + node := s.Nodes[0] + data := node.FirstChild.Data + bundles, err := parseBundles([]byte(data), category) if err != nil { - log.Panicln(err) + log.Error().Str("func", "UpdateBundles").Msg(err.Error()) } - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - req.Header.Add("Idempotency-Key", idemkey) - req.Header.Add("Authorization", fmt.Sprintf("Bearer %v", token)) - - res, err := client.Do(req) - if err != nil { - fmt.Println(err) - return + for _, bundle := range bundles { + err := handleHumbleBundle(bundle, category) + if err != nil { + log.Error().Str("bundle", bundle.MachineName). + Msgf("Error handling humble bundle: %v", err) + } } - - if res.StatusCode != 200 { - log.Printf("Error sending Mastodon post: %q\n", res.Status) - } - - //sum := sha256.Sum256([]byte(product.ProductURL)) - //sumstring := hex.EncodeToString(sum[:]) - log.Printf("%v: %v\n", category, misc.Sanitize(product.MarketingBlurb)) - time.Sleep(5 * time.Second) - } - - }) + }) + log.Debug().Str("category", category).Msg("finished bundle update") + } } func parseBundles(data []byte, category string) ([]models.Bundle, error) { @@ -128,3 +95,20 @@ func parseBundles(data []byte, category string) ([]models.Bundle, error) { return nil, fmt.Errorf("unknown category %s", category) } } + +func handleHumbleBundle(bundle models.Bundle, category string) error { + isnew, err := db.IsANewBundle(bundle) + if err != nil { + return err + } + + if !isnew { + log.Debug().Str("bundle", bundle.MachineName).Msg("bundle already exists") + return nil + } + + log.Info().Str("bundle", bundle.ProductURL).Msg("found new Bundle") + + err = db.Enqueue(bundle, category) + return err +} diff --git a/app/mastodon.go b/app/mastodon.go new file mode 100644 index 0000000..0bdb862 --- /dev/null +++ b/app/mastodon.go @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2023 Laura Kalb + * The code of this project is available under the MIT license. See the LICENSE file for more info. + * + */ + +package app + +import ( + "bytes" + "codeberg.org/lauralani/humble-bot/misc" + "codeberg.org/lauralani/humble-bot/models" + "errors" + "fmt" + "github.com/google/uuid" + "github.com/rs/zerolog/log" + "github.com/spf13/viper" + "io" + "net/url" + "strings" +) + +func postQueueItemToMastodon(bundle models.QueueItem) error { + urlstring := viper.GetString("mastodon.url") + "/api/v1/statuses" + endpoint, _ := url.Parse(urlstring) + + token := viper.GetString("mastodon.token") + idemkey := uuid.New().String() + + builder := new(strings.Builder) + + builder.WriteString(bundle.Headline) + builder.WriteString("\n\n") + + builder.WriteString(bundle.Body) + builder.WriteString("\n\n") + + builder.WriteString(bundle.URL) + + builder.WriteString("\n\n") + builder.WriteString(bundle.Hashtags) + + payload := url.Values{} + payload.Add("status", builder.String()) + payload.Add("visibility", "private") + payload.Add("language", "en") + + client := misc.CustomHttpClient() + req := misc.CustomHttpRequest() + req.URL = endpoint + req.Method = "POST" + req.Body = io.NopCloser(bytes.NewBuffer([]byte(payload.Encode()))) + + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + req.Header.Add("Idempotency-Key", idemkey) + req.Header.Add("Authorization", fmt.Sprintf("Bearer %v", token)) + + res, err := client.Do(req) + if err != nil { + return err + } + + if res.StatusCode != 200 { + log.Error().Int("code", res.StatusCode).Str("status", res.Status). + Str("url", urlstring).Msg("Error with http request") + return errors.New("couldn't POST message to Mastodon") + } + + log.Info(). + Str("url", bundle.URL).Msg("posted new Bundle to Mastodon =)") + return nil +} diff --git a/app/queue.go b/app/queue.go new file mode 100644 index 0000000..49af633 --- /dev/null +++ b/app/queue.go @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 Laura Kalb + * The code of this project is available under the MIT license. See the LICENSE file for more info. + * + */ + +package app + +import ( + "codeberg.org/lauralani/humble-bot/db" + "codeberg.org/lauralani/humble-bot/models" + "context" + "database/sql" + "github.com/rs/zerolog/log" +) + +func RunSingleQueueItem() { + log.Debug().Str("func", "RunSingleQueueItem").Msg("starting single queue item run") + var item = models.QueueItem{} + + err := models.DB.NewSelect().Model(&item).Order("created ASC").Limit(1).Scan(context.Background()) + if err != nil { + if err == sql.ErrNoRows { + log.Debug().Str("func", "RunSingleQueueItem"). + Str("table", "queue").Msg("no item in queue") + return + } else { + log.Error().Str("func", "RunSingleQueueItem"). + Str("table", "queue").Msgf("DB Error: SELECT failed: %v", err) + return + } + } + log.Debug().Str("func", "RunSingleQueueItem").Str("item", item.Name). + Msg("got new item from db") + + err = postQueueItemToMastodon(item) + if err != nil { + return + } + log.Debug().Str("func", "RunSingleQueueItem").Str("item", item.Name). + Msg("posted to mastodon") + + err = db.Dequeue(item) + if err != nil { + log.Error().Str("func", "RunSingleQueueItem").Str("item", item.Name). + Msg("Error: couldnt dequeue item") + return + } +} diff --git a/cmd/daemon.go b/cmd/daemon.go index 303bd64..5c82a7f 100644 --- a/cmd/daemon.go +++ b/cmd/daemon.go @@ -14,14 +14,15 @@ import ( // daemonCmd represents the daemon command var daemonCmd = &cobra.Command{ Use: "daemon", - Short: "Run humble-bot as a daemon", + Short: "Run humble-bot as daemon", Long: `A longer description that spans multiple lines and likely contains examples and usage of using your command. For example: Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application.`, - Run: app.RunDaemon, + Args: cobra.ExactArgs(0), + Run: app.RunDaemon, } func init() { diff --git a/cmd/root.go b/cmd/root.go index 04f2e25..bb77f06 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -8,8 +8,10 @@ package cmd import ( "codeberg.org/lauralani/humble-bot/app" + "codeberg.org/lauralani/humble-bot/constants" "codeberg.org/lauralani/humble-bot/db" - "log" + "codeberg.org/lauralani/humble-bot/log" + log2 "log" "os" "github.com/spf13/cobra" @@ -35,23 +37,20 @@ func Execute() { } func init() { - cobra.OnInitialize(initConfig, db.Initialize) - - // Here you will define your flags and configuration settings. - // Cobra supports persistent flags, which, if defined here, - // will be global for your application. + cobra.OnInitialize(initConfig, db.Initialize, log.InitializeLogger) rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $workingdir/config.yaml)") + rootCmd.PersistentFlags().BoolVarP(&log.FlagDebug, "debug", "d", false, "enable debug logging") // Cobra also supports local flags, which will only run // when this action is called directly. - rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + // rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + } // initConfig reads in config file and ENV variables if set. func initConfig() { if cfgFile != "" { - // Use config file from the flag. viper.SetConfigFile(cfgFile) } else { @@ -60,15 +59,15 @@ func initConfig() { viper.AddConfigPath(workingdir) viper.SetConfigName("config") - //viper.SetConfigType("yaml") } - viper.AutomaticEnv() // read in environment variables that match + viper.SetDefault("mastodon.postinterval", "5m") + viper.SetDefault("humblebundle.pollinterval", "30m") - // If a config file is found, read it in. if err := viper.ReadInConfig(); err == nil { - log.Printf("Using config file: %v\n", viper.ConfigFileUsed()) + log2.Printf("Starting humble-bot %v with config file: %v\n", constants.AppVersion, viper.ConfigFileUsed()) } else { - log.Panicf("Can't find config file: %v\n", viper.ConfigFileUsed()) + log2.Printf("Can't find config file: %v\n", viper.ConfigFileUsed()) + os.Exit(1) } } diff --git a/app/constants.go b/constants/constants.go similarity index 62% rename from app/constants.go rename to constants/constants.go index 6b73b9c..73e3d63 100644 --- a/app/constants.go +++ b/constants/constants.go @@ -4,6 +4,10 @@ * */ -package app +package constants + +var AppVersion = "0.0.1" var HumbleCategories = []string{"games", "books", "software"} + +var UserAgent = "humble-bot/" + AppVersion + " https://codeberg.org/lauralani/humble-bot" diff --git a/db/db.go b/db/db.go index 513da2d..64284ca 100644 --- a/db/db.go +++ b/db/db.go @@ -7,20 +7,26 @@ package db import ( + "codeberg.org/lauralani/humble-bot/misc" "codeberg.org/lauralani/humble-bot/models" "context" "database/sql" + "fmt" + "github.com/rs/zerolog/log" "github.com/spf13/viper" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect/pgdialect" "github.com/uptrace/bun/driver/pgdriver" - "log" + "os" + "time" ) func Initialize() { dsn := viper.GetString("database.url") if dsn == "" { - log.Fatalln("config item database.url is invalid! Aborting...") + log.Error().Str("config", viper.ConfigFileUsed()). + Str("func", "db.Initialize").Msg("empty config value vor key database.url") + os.Exit(1) } sqldb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(dsn))) @@ -28,12 +34,78 @@ func Initialize() { _, err := models.DB.NewCreateTable().IfNotExists().Model((*models.QueueItem)(nil)).Exec(context.Background()) if err != nil { - log.Panicf("[DB] couldn't create database: %q", err) + log.Error().Str("table", "queue"). + Str("func", "db.Initialize").Msgf("DB Error: CREATE TABLE failed: %q", err) + os.Exit(1) } _, err = models.DB.NewCreateTable().IfNotExists().Model((*models.SeenBundle)(nil)).Exec(context.Background()) if err != nil { - log.Panicf("[DB] couldn't create database: %q", err) + log.Error().Str("table", "queue"). + Str("func", "db.Initialize").Msgf("DB Error: CREATE TABLE failed: %q", err) + os.Exit(1) } } + +func Enqueue(bundle models.Bundle, category string) error { + var item = models.QueueItem{} + var seenitem = models.SeenBundle{} + + item.Name = bundle.MachineName + item.Headline = bundle.TileName + item.Body = misc.Sanitize(bundle.MarketingBlurb) + item.URL = "https://www.humblebundle.com" + bundle.ProductURL + item.Hashtags = fmt.Sprintf("#humblebundle #humble%sbundle #%s", category, category) + item.Created = time.Now() + + seenitem.Name = bundle.MachineName + seenitem.URL = bundle.ProductURL + seenitem.SeenAt = time.Now() + + log.Debug().Str("bundle", bundle.MachineName).Msg("adding bundle to seen table") + _, err := models.DB.NewInsert().Model(&seenitem).Exec(context.Background()) + if err != nil { + log.Debug().Str("func", "db.Enqueue").Str("bundle", bundle.MachineName). + Str("table", "seen").Msgf("DB Error: INSERT failed: %v", err) + return err + } + + _, err = models.DB.NewInsert().Model(&item).Exec(context.Background()) + if err != nil { + log.Debug().Str("func", "db.Enqueue").Str("bundle", bundle.MachineName). + Str("table", "queue").Msgf("DB Error: INSERT failed: %v", err) + return err + } + + log.Debug().Str("bundle", bundle.MachineName).Msg("added bundle to queue") + return nil +} + +func Dequeue(item models.QueueItem) error { + _, err := models.DB.NewDelete().Model((*models.QueueItem)(nil)). + Where("id = ?", item.ID).Exec(context.Background()) + if err != nil { + log.Debug().Str("func", "Dequeue").Str("item", item.Name). + Msgf("DB Error: DELETE failed: %v", err) + return err + } + log.Debug().Str("func", "Dequeue").Str("item", item.Name). + Msg("dequeued item") + return nil +} + +func IsANewBundle(bundle models.Bundle) (bool, error) { + count, err := models.DB.NewSelect().Model((*models.SeenBundle)(nil)).Where("name = ?", bundle.MachineName). + Where("url = ?", bundle.ProductURL).Count(context.Background()) + if err != nil { + log.Error().Str("bundle", bundle.MachineName).Str("func", "IsANewBundle"). + Msgf("DB error: %v", err.Error()) + return false, err + } + + if count != 0 { + return false, nil + } + return true, nil +} diff --git a/examples/config.yaml b/examples/config.yaml index 032aa4e..7f3c5b0 100644 --- a/examples/config.yaml +++ b/examples/config.yaml @@ -13,4 +13,17 @@ mastodon: # Access token for your mastodon account # see $your_mastodon_url/settings/applications - token: "" \ No newline at end of file + token: "" + + # Interval in which humble-bot tries to post bundles + # format: "20s" or "15m" or "1h" + # default: 5m + postinterval: "5m" + +# Humble Bundle settings +humblebundle: + + # Interval in which humble-bot tries to query humblebundle.com + # format: "20s" or "15m" or "1h" + # default: 30m + pollinterval: "30m" \ No newline at end of file diff --git a/go.mod b/go.mod index 34ea2a9..6bc3d72 100644 --- a/go.mod +++ b/go.mod @@ -3,54 +3,46 @@ module codeberg.org/lauralani/humble-bot go 1.20 require ( - github.com/PuerkitoBio/goquery v1.8.1 // indirect + github.com/PuerkitoBio/goquery v1.8.1 + github.com/go-co-op/gocron v1.30.1 + github.com/google/uuid v1.3.0 + github.com/microcosm-cc/bluemonday v1.0.24 + github.com/rs/zerolog v1.29.1 + github.com/spf13/cobra v1.7.0 + github.com/spf13/viper v1.16.0 + github.com/uptrace/bun v1.1.14 + github.com/uptrace/bun/dialect/pgdialect v1.1.14 + github.com/uptrace/bun/driver/pgdriver v1.1.14 +) + +require ( github.com/andybalholm/cascadia v1.3.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/google/uuid v1.3.0 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jinzhu/inflection 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-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect - github.com/mattn/go-sqlite3 v1.14.16 // indirect - github.com/microcosm-cc/bluemonday v1.0.24 // 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/robfig/cron/v3 v3.0.1 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect - github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.16.0 // indirect github.com/subosito/gotenv v1.4.2 // indirect github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect - github.com/uptrace/bun v1.1.14 // indirect - github.com/uptrace/bun/dialect/pgdialect v1.1.14 // indirect - github.com/uptrace/bun/driver/pgdriver v1.1.14 // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.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/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect - golang.org/x/tools v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - lukechampine.com/uint128 v1.3.0 // indirect mellium.im/sasl v0.3.1 // indirect - modernc.org/cc/v3 v3.40.0 // indirect - modernc.org/ccgo/v3 v3.16.13 // indirect - modernc.org/libc v1.22.6 // indirect - modernc.org/mathutil v1.5.0 // indirect - modernc.org/memory v1.5.0 // indirect - modernc.org/opt v0.1.3 // indirect - modernc.org/sqlite v1.22.1 // indirect - modernc.org/strutil v1.1.3 // indirect - modernc.org/token v1.1.0 // indirect ) diff --git a/go.sum b/go.sum index e29e340..fcbb227 100644 --- a/go.sum +++ b/go.sum @@ -52,22 +52,27 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/go-co-op/gocron v1.30.1 h1:tjWUvJl5KrcwpkEkSXFSQFr4F9h5SfV/m4+RX0cV2fs= +github.com/go-co-op/gocron v1.30.1/go.mod h1:39f6KNSGVOU1LO/ZOoZfcSxwlsJDQOKSu8erN0SH48Y= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -104,6 +109,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -138,33 +144,46 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= -github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/microcosm-cc/bluemonday v1.0.24 h1:NGQoPtwGVcbGkKfvyYk1yRqknzBuoMiUrO6R7uFTPlw= github.com/microcosm-cc/bluemonday v1.0.24/go.mod h1:ArQySAMps0790cHSkdPEJ7bGkF2VePWH773hsJNSHf8= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= +github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= @@ -182,12 +201,15 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= @@ -197,12 +219,8 @@ github.com/uptrace/bun v1.1.14 h1:S5vvNnjEynJ0CvnrBOD7MIRW7q/WbtvFXrdfy0lddAM= github.com/uptrace/bun v1.1.14/go.mod h1:RHk6DrIisO62dv10pUOJCz5MphXThuOTpVNYEYv7NI8= github.com/uptrace/bun/dialect/pgdialect v1.1.14 h1:b7+V1KDJPQSFYgkG/6YLXCl2uvwEY3kf/GSM7hTHRDY= github.com/uptrace/bun/dialect/pgdialect v1.1.14/go.mod h1:v6YiaXmnKQ2FlhRD2c0ZfKd+QXH09pYn4H8ojaavkKk= -github.com/uptrace/bun/dialect/sqlitedialect v1.1.14 h1:SlwXLxr+N1kEo8Q0cheRlnIZLZlWniEB1OI+jkiLgWE= -github.com/uptrace/bun/dialect/sqlitedialect v1.1.14/go.mod h1:9RTEj1l4bB9a4l1Mnc9y4COTwWlFYe1dh6fyxq1rR7A= github.com/uptrace/bun/driver/pgdriver v1.1.14 h1:V2Etm7mLGS3mhx8ddxZcUnwZLX02Jmq9JTlo0sNVDhA= github.com/uptrace/bun/driver/pgdriver v1.1.14/go.mod h1:D4FjWV9arDYct6sjMJhFoyU71SpllZRHXFRRP2Kd0Kw= -github.com/uptrace/bun/driver/sqliteshim v1.1.14 h1:DFPUJ6KjDP2myjq15gtYYNngmAFMww1Y2UFZv4tbUw8= -github.com/uptrace/bun/driver/sqliteshim v1.1.14/go.mod h1:5BFN7V6Sm37Tn7UE4FWNm/F6V3iJPUzAJ7QyRwA5b1k= github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= @@ -218,6 +236,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -262,8 +282,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -356,8 +374,11 @@ golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -428,8 +449,6 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -524,6 +543,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -538,28 +559,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo= -lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= mellium.im/sasl v0.3.1 h1:wE0LW6g7U83vhvxjC1IY8DnXM+EU095yeo8XClvCdfo= mellium.im/sasl v0.3.1/go.mod h1:xm59PUYpZHhgQ9ZqoJ5QaCqzWMi8IeS49dhp6plPCzw= -modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw= -modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= -modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= -modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= -modernc.org/libc v1.22.6 h1:cbXU8R+A6aOjRuhsFh3nbDWXO/Hs4ClJRXYB11KmPDo= -modernc.org/libc v1.22.6/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= -modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= -modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= -modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.22.1 h1:P2+Dhp5FR1RlVRkQ3dDfCiv3Ok8XPxqpe70IjYVA9oE= -modernc.org/sqlite v1.22.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= -modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= -modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= -modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= -modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/log/logger.go b/log/logger.go new file mode 100644 index 0000000..c30c00f --- /dev/null +++ b/log/logger.go @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Laura Kalb + * The code of this project is available under the MIT license. See the LICENSE file for more info. + * + */ + +package log + +import ( + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + "os" + "time" +) + +var FlagDebug bool + +func InitializeLogger() { + + log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339}) + + if FlagDebug { + zerolog.SetGlobalLevel(zerolog.DebugLevel) + } else { + zerolog.SetGlobalLevel(zerolog.InfoLevel) + } +} diff --git a/misc/http.go b/misc/http.go new file mode 100644 index 0000000..f80022f --- /dev/null +++ b/misc/http.go @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Laura Kalb + * The code of this project is available under the MIT license. See the LICENSE file for more info. + * + */ + +package misc + +import ( + "codeberg.org/lauralani/humble-bot/constants" + "net/http" + "time" +) + +func CustomHttpClient() *http.Client { + c := http.Client{} + c.Timeout = time.Duration(60) * time.Second + return &c +} + +func CustomHttpRequest() *http.Request { + h := map[string][]string{ + "User-Agent": {constants.UserAgent}, + } + r := http.Request{Header: h} + return &r +} diff --git a/models/db.go b/models/db.go index c2edd0e..b550822 100644 --- a/models/db.go +++ b/models/db.go @@ -16,7 +16,7 @@ var DB *bun.DB type QueueItem struct { bun.BaseModel `bun:"table:queue"` ID int64 `bun:"id,pk,autoincrement"` - Hash string `bun:"hash,notnull"` + Name string `bun:"name"` Headline string `bun:"headline"` Body string `bun:"body"` URL string `bun:"url"` @@ -26,7 +26,8 @@ type QueueItem struct { type SeenBundle struct { bun.BaseModel `bun:"table:seen"` - ID int64 `bun:"id,pk,autoincrement"` - NameHash string `bun:"namehash,notnull"` - URLHash string `bun:"urlhash,notnull"` + ID int64 `bun:"id,pk,autoincrement"` + Name string `bun:"name,notnull"` + URL string `bun:"url,notnull"` + SeenAt time.Time `bun:"seenat"` }