From 1d38f81bbb1a79eb0b43d7ce0ad81d0d4b447312 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Mon, 4 Sep 2023 20:46:09 +0200 Subject: [PATCH] chore:more strict linting (#206) * bumped the staticcheck version we are tested against * migrated from `staticcheck` to `golangci-lint` (includes `staticcheck` and other linters) * renamed the workflow file from `staticcheck` to `ci` * migrated to go 1.21 * fixed linting not running * fixed defects the new logger turned up * fixed more issues turned up by the linter * fixed more issues turned up by the linter * fixed another bug * Apply suggestions from code review --- .github/workflows/ci.yml | 29 ++++++++++++++ .github/workflows/staticcheck.yml | 22 ----------- client/go.mod | 2 +- client/go.sum | 4 ++ server/Dockerfile | 2 +- .../backend/cafeteriaRatingDBInitializer.go | 38 ++++++++++--------- server/backend/cafeteriaService.go | 3 +- server/backend/cron/canteenHeadCount.go | 8 +++- server/backend/cron/cronjobs.go | 12 +++--- server/backend/cron/dishNameDownload.go | 9 +++-- server/backend/cron/news.go | 11 ++++-- .../ios_scheduling/iosSchedulingService.go | 11 +++--- server/backend/rpcserver.go | 2 +- server/go.mod | 2 +- server/go.sum | 18 +++++++++ 15 files changed, 108 insertions(+), 65 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/staticcheck.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..505e0da3 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,29 @@ +name: CI +on: + push: + branches: [ main ] + pull_request: + +permissions: + contents: read + +jobs: + ci: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v4 + with: + go-version: '1.21' + cache: false + - name: golangci-lint-server + uses: golangci/golangci-lint-action@v3 + with: + version: v1.54 + working-directory: server + - name: golangci-lint-client + uses: golangci/golangci-lint-action@v3 + with: + version: v1.54 + working-directory: client diff --git a/.github/workflows/staticcheck.yml b/.github/workflows/staticcheck.yml deleted file mode 100644 index 921f886b..00000000 --- a/.github/workflows/staticcheck.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: "staticcheck" - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - ci: - name: "Run staticcheck" - runs-on: ubuntu-latest - strategy: - matrix: { dir: [ './server' ] } - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 1 - - uses: dominikh/staticcheck-action@v1.3.0 - with: - version: "2022.1" - working-directory: ${{ matrix.dir }} diff --git a/client/go.mod b/client/go.mod index 9d696d48..dac32653 100644 --- a/client/go.mod +++ b/client/go.mod @@ -1,6 +1,6 @@ module github.com/TUM-Dev/Campus-Backend/client -go 1.18 +go 1.21 require ( github.com/TUM-Dev/Campus-Backend/api v0.0.0-20221212204029-68b05b451617 diff --git a/client/go.sum b/client/go.sum index 2d5e3449..21378bde 100644 --- a/client/go.sum +++ b/client/go.sum @@ -12,10 +12,13 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 h1:lLT7ZLSzGLI08vc9cpd+tYmNWjdKDqyr/2L+f6U12Fk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= @@ -48,6 +51,7 @@ google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/server/Dockerfile b/server/Dockerfile index 204bf122..fb044b41 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.19.3-alpine3.15 as builder +FROM golang:1.21-alpine3.18 as builder # Install git + SSL ca certificates. # Git is required for fetching the dependencies. diff --git a/server/backend/cafeteriaRatingDBInitializer.go b/server/backend/cafeteriaRatingDBInitializer.go index f51dd4db..b8fd3056 100644 --- a/server/backend/cafeteriaRatingDBInitializer.go +++ b/server/backend/cafeteriaRatingDBInitializer.go @@ -103,21 +103,22 @@ func updateNameTagOptions(db *gorm.DB) { func addNotIncluded(parentId int32, db *gorm.DB, v nameTag) { var count int64 - for _, u := range v.NotIncluded { - errorLoadingIncluded := db.Model(&model.DishNameTagOptionExcluded{}). - Where("expression LIKE ? AND NameTagID = ?", u, parentId). + for _, expression := range v.NotIncluded { + fields := log.Fields{"expression": expression, "parentId": parentId} + err := db.Model(&model.DishNameTagOptionExcluded{}). + Where("expression LIKE ? AND NameTagID = ?", expression, parentId). Select("DishNameTagOptionExcluded"). Count(&count).Error - if errorLoadingIncluded != nil { - log.WithError(errorLoadingIncluded).Errorf("Unable to load can be excluded tag with expression %s and parentId %s", u, parentId) + if err != nil { + log.WithError(err).WithFields(fields).Error("Unable to load can be excluded tag") } else { if count == 0 { - createError := db.Model(&model.DishNameTagOptionExcluded{}). + err := db.Model(&model.DishNameTagOptionExcluded{}). Create(&model.DishNameTagOptionExcluded{ - Expression: u, + Expression: expression, NameTagID: parentId}).Error - if createError != nil { - log.WithError(errorLoadingIncluded).Error("Unable to create new can be excluded tag with expression {} and parentId {} ", u, parentId) + if err != nil { + log.WithError(err).WithFields(fields).Error("Unable to create new can be excluded tag") } } } @@ -126,22 +127,23 @@ func addNotIncluded(parentId int32, db *gorm.DB, v nameTag) { func addCanBeIncluded(parentId int32, db *gorm.DB, v nameTag) { var count int64 - for _, u := range v.CanBeIncluded { - errorLoadingIncluded := db.Model(&model.DishNameTagOptionIncluded{}). - Where("expression LIKE ? AND NameTagID = ?", u, parentId). + for _, expression := range v.CanBeIncluded { + fields := log.Fields{"expression": expression, "parentId": parentId} + err := db.Model(&model.DishNameTagOptionIncluded{}). + Where("expression LIKE ? AND NameTagID = ?", expression, parentId). Select("DishNameTagOptionIncluded"). Count(&count).Error - if errorLoadingIncluded != nil { - log.WithError(errorLoadingIncluded).Errorf("Unable to load can be included tag with expression %s and parentId %s", u, parentId) + if err != nil { + log.WithError(err).WithFields(fields).Error("Unable to load can be included tag") } else { if count == 0 { - createError := db.Model(&model.DishNameTagOptionIncluded{}). + err := db.Model(&model.DishNameTagOptionIncluded{}). Create(&model.DishNameTagOptionIncluded{ - Expression: u, + Expression: expression, NameTagID: parentId, }).Error - if createError != nil { - log.WithError(errorLoadingIncluded).Errorf("Unable to create new can be excluded tag with expression %s and parentId %s", u, parentId) + if err != nil { + log.WithError(err).WithFields(fields).Error("Unable to create new can be excluded tag") } } } diff --git a/server/backend/cafeteriaService.go b/server/backend/cafeteriaService.go index 0c79a9be..55acd47a 100644 --- a/server/backend/cafeteriaService.go +++ b/server/backend/cafeteriaService.go @@ -155,7 +155,8 @@ func (s *CampusServer) GetDishRatings(_ context.Context, input *pb.DishRatingReq First(&result) if err.Error != nil { - log.WithError(err.Error).Errorf("Error while querying the average ratings for the dish %s in the cafeteria %s.", dishID, cafeteriaID) + fields := log.Fields{"dishID": dishID, "cafeteriaID": cafeteriaID} + log.WithError(err.Error).WithFields(fields).Error("Error while querying the average ratings") return nil, status.Errorf(codes.Internal, "This dish has not yet been rated.") } diff --git a/server/backend/cron/canteenHeadCount.go b/server/backend/cron/canteenHeadCount.go index 2bb486c5..168af083 100644 --- a/server/backend/cron/canteenHeadCount.go +++ b/server/backend/cron/canteenHeadCount.go @@ -143,8 +143,12 @@ func (c *CronService) canteenHeadCountCron() error { } count := sumApCounts(aps) - updateDb(&canteen, count, c.db) - log.Debug("Canteen head count stats (", count, ") updated for: ", canteen.CanteenId) + fields := log.Fields{"count": count, "CanteenId": canteen.CanteenId} + if err := updateDb(&canteen, count, c.db); err != nil { + log.WithFields(fields).WithError(err).Error("Failed to update Canteen head count stats") + } else { + log.WithFields(fields).Debug("Canteen head count stats updated") + } } log.Info("Canteen head count stats updated.") return nil diff --git a/server/backend/cron/cronjobs.go b/server/backend/cron/cronjobs.go index d37dc1b4..8bf15fad 100644 --- a/server/backend/cron/cronjobs.go +++ b/server/backend/cron/cronjobs.go @@ -84,10 +84,13 @@ func (c *CronService) Run() error { cronjob.LastRun = int32(time.Now().Unix()) + offset c.db.Save(&cronjob) - // Run each job in a separate goroutine so we can parallelize them + // Run each job in a separate goroutine, so we can parallelize them switch cronjob.Type.String { case NewsType: - g.Go(func() error { return c.newsCron(&cronjob) }) + // if this is not copied here, this may not be threads save due to go's guarantees + // loop variable cronjob captured by func literal (govet) + copyCronjob := cronjob + g.Go(func() error { return c.newsCron(©Cronjob) }) case FileDownloadType: g.Go(func() error { return c.fileDownloadCron() }) case DishNameDownload: @@ -122,9 +125,8 @@ func (c *CronService) Run() error { } } - err := g.Wait() - if err != nil { - log.Println("Couldn't run all cron jobs: %v", err) + if err := g.Wait(); err != nil { + log.WithError(err).Println("Couldn't run all cron jobs") } log.Trace("Cron: sleeping for 60 seconds") time.Sleep(60 * time.Second) diff --git a/server/backend/cron/dishNameDownload.go b/server/backend/cron/dishNameDownload.go index 46e2de86..1dab432e 100644 --- a/server/backend/cron/dishNameDownload.go +++ b/server/backend/cron/dishNameDownload.go @@ -202,14 +202,15 @@ func addDishTagsToMapping(dishID int32, dishName string, db *gorm.DB) { } } - for _, a := range includedTags { - if a != -1 { + for _, nametagID := range includedTags { + if nametagID != -1 { err := db.Model(&model.DishToDishNameTag{}).Create(&model.DishToDishNameTag{ DishID: dishID, - NameTagID: a, + NameTagID: nametagID, }).Error if err != nil { - log.WithError(err).Errorf("Error while creating a new entry with dish %s and nametag %s", dishID, a) + fields := log.Fields{"dishID": dishID, "nametagID": nametagID} + log.WithError(err).WithFields(fields).Error("creating a new entry") } } } diff --git a/server/backend/cron/news.go b/server/backend/cron/news.go index 95ef7be3..4a7f4723 100644 --- a/server/backend/cron/news.go +++ b/server/backend/cron/news.go @@ -3,7 +3,6 @@ package cron import ( "crypto/md5" "database/sql" - "encoding/json" "errors" "fmt" "github.com/TUM-Dev/Campus-Backend/server/model" @@ -31,8 +30,14 @@ var ImageContentTypeRegex, _ = regexp.Compile("image/[a-z.]+") func (c *CronService) newsCron(cronjob *model.Crontab) error { //check if source id provided for news job is not null if !cronjob.ID.Valid { - cronjobJson, _ := json.Marshal(cronjob) - log.Println("skipping news job, id of source is null, cronjob: %s", string(cronjobJson)) + fields := log.Fields{ + "Cron": cronjob.Cron, + "Interval": cronjob.Interval, + "LastRun": cronjob.LastRun, + "Type": cronjob.Type, + "ID": cronjob.ID, + } + log.WithFields(fields).Warn("skipping news job, id of source is null") return nil } // get news source for cronjob diff --git a/server/backend/ios_notifications/ios_scheduling/iosSchedulingService.go b/server/backend/ios_notifications/ios_scheduling/iosSchedulingService.go index c27709c1..a2e60dad 100644 --- a/server/backend/ios_notifications/ios_scheduling/iosSchedulingService.go +++ b/server/backend/ios_notifications/ios_scheduling/iosSchedulingService.go @@ -97,14 +97,13 @@ func (service *Service) handleDevices(devices []model.IOSDeviceLastUpdated) { func (service *Service) handleDevicesChunk(devices []model.IOSDeviceLastUpdated) { for _, device := range devices { - err := service.APNs.RequestGradeUpdateForDevice(device.DeviceID) - - if err != nil { - log.Errorf("Error while handling device: %s", err) + if err := service.APNs.RequestGradeUpdateForDevice(device.DeviceID); err != nil { + log.WithError(err).Error("could not RequestGradeUpdateForDevice") continue } - - service.LogScheduledUpdate(device.DeviceID) + if err := service.LogScheduledUpdate(device.DeviceID); err != nil { + log.WithError(err).WithField("deviceID", device.DeviceID).Error("could not log scheduled update") + } } } diff --git a/server/backend/rpcserver.go b/server/backend/rpcserver.go index 5c974785..0a4b6d00 100644 --- a/server/backend/rpcserver.go +++ b/server/backend/rpcserver.go @@ -153,7 +153,7 @@ func (s *CampusServer) GetTopNews(ctx context.Context, _ *emptypb.Empty) (*pb.Ge var res *model.NewsAlert err := s.db.Joins("Company").Where("NOW() between `from` and `to`").Limit(1).First(&res).Error if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - log.Errorf("Failed to fetch top news: %w", err) + log.WithError(err).Errorf("Failed to fetch top news") } else if res != nil { return &pb.GetTopNewsReply{ //ImageUrl: res.Name, diff --git a/server/go.mod b/server/go.mod index f8c7e795..af09fc68 100644 --- a/server/go.mod +++ b/server/go.mod @@ -1,6 +1,6 @@ module github.com/TUM-Dev/Campus-Backend/server -go 1.18 +go 1.21 require ( github.com/disintegration/imaging v1.6.2 diff --git a/server/go.sum b/server/go.sum index e8dd74ad..9a66ee21 100644 --- a/server/go.sum +++ b/server/go.sum @@ -22,6 +22,7 @@ github.com/getsentry/sentry-go v0.23.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gormigrate/gormigrate/v2 v2.1.0 h1:4/1xr9CjOox714EJWbxkF00lrNmbWJToSZzhykKKcKY= github.com/go-gormigrate/gormigrate/v2 v2.1.0/go.mod h1:gpA97koYGyjqaiLDTmLE5W7nyYTmI26AYIf2a/earuo= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -31,7 +32,9 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9 github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -40,6 +43,7 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= @@ -53,17 +57,22 @@ github.com/influxdata/influxdb-client-go/v2 v2.12.3/go.mod h1:IrrLUbCjjfkmRuaCiG github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= +github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 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= @@ -80,9 +89,11 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 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.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= github.com/microsoft/go-mssqldb v0.21.0 h1:p2rpHIL7TlSv1QrbXJUAcbyRKnIT0C9rRkH2E4OjLn8= +github.com/microsoft/go-mssqldb v0.21.0/go.mod h1:+4wZTUnz/SV6nffv+RRRB/ss8jPng5Sho2SmM1l2ts4= github.com/mmcdole/gofeed v1.2.1 h1:tPbFN+mfOLcM1kDF1x2c/N68ChbdBatkppdzf/vDe1s= github.com/mmcdole/gofeed v1.2.1/go.mod h1:2wVInNpgmC85q16QTTuwbuKxtKkHLCDDtf0dCmnrNr4= github.com/mmcdole/goxpp v1.1.0 h1:WwslZNF7KNAXTFuzRtn/OKZxFLJAAyOA9w82mDz2ZGI= @@ -93,12 +104,14 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= @@ -122,6 +135,7 @@ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI= golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4= @@ -195,6 +209,7 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw 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/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -203,8 +218,11 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw= gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= +gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= gorm.io/driver/sqlite v1.5.1 h1:hYyrLkAWE71bcarJDPdZNTLWtr8XrSjOWyjUYI6xdL4= +gorm.io/driver/sqlite v1.5.1/go.mod h1:7MZZ2Z8bqyfSQA1gYEV6MagQWj3cpUkJj9Z+d1HEMEQ= gorm.io/driver/sqlserver v1.5.0 h1:zol7ePfY1XiPfjEvjjBh4VatIF3kycNcPE0EMCXznHY= +gorm.io/driver/sqlserver v1.5.0/go.mod h1:tBAqioK34BHl0Iiez+BFfG5/K9nDAlhLxRkgc2qy3+4= gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw= gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=