From aea7a53dbfddb5ec217a89bd01281874149a0510 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Mon, 10 Oct 2022 19:27:26 +0200 Subject: [PATCH 01/54] feat: implement Publishers PATCH (#167) Fix #160. --- internal/common/requests.go | 10 +- internal/handlers/publishers.go | 163 ++++++++++++++++++-------- main_test.go | 195 +++++++++++++++++++++----------- 3 files changed, 249 insertions(+), 119 deletions(-) diff --git a/internal/common/requests.go b/internal/common/requests.go index 6c40f94..ca8e20c 100644 --- a/internal/common/requests.go +++ b/internal/common/requests.go @@ -11,11 +11,11 @@ type PublisherPost struct { } type PublisherPatch struct { - CodeHosting []CodeHosting `json:"codeHosting" validate:"gt=0"` - Description string `json:"description"` - Email string `json:"email" validate:"email"` - Active *bool `json:"active"` - AlternativeID string `json:"alternativeId" validate:"max=255"` + CodeHosting *[]CodeHosting `json:"codeHosting" validate:"omitempty,gt=0,dive"` + Description *string `json:"description"` + Email *string `json:"email" validate:"omitempty,email"` + Active *bool `json:"active"` + AlternativeID *string `json:"alternativeId" validate:"omitempty,max=255"` } type CodeHosting struct { diff --git a/internal/handlers/publishers.go b/internal/handlers/publishers.go index 4faf6f5..c96aa3a 100644 --- a/internal/handlers/publishers.go +++ b/internal/handlers/publishers.go @@ -2,10 +2,11 @@ package handlers import ( "errors" - "fmt" "net/url" + "sort" "github.com/italia/developers-italia-api/internal/database" + "golang.org/x/exp/slices" "github.com/italia/developers-italia-api/internal/handlers/general" @@ -135,69 +136,83 @@ func (p *Publisher) PostPublisher(ctx *fiber.Ctx) error { } // PatchPublisher updates the publisher with the given ID. CodeHosting URLs will be overwritten from the request. -func (p *Publisher) PatchPublisher(ctx *fiber.Ctx) error { - requests := new(common.PublisherPatch) - - if err := common.ValidateRequestEntity(ctx, requests, "can't update Publisher"); err != nil { - return err //nolint:wrapcheck - } - +func (p *Publisher) PatchPublisher(ctx *fiber.Ctx) error { //nolint:cyclop // mostly error handling ifs + publisherReq := new(common.PublisherPatch) publisher := models.Publisher{} - if err := p.db.Transaction(func(gormTrx *gorm.DB) error { - return p.updatePublisherTrx(gormTrx, publisher, ctx, requests) - }); err != nil { - return err //nolint:wrapcheck - } - - return ctx.JSON(&publisher) -} - -func (p *Publisher) updatePublisherTrx( - gormTrx *gorm.DB, - publisher models.Publisher, - ctx *fiber.Ctx, - request *common.PublisherPatch, -) error { - if err := gormTrx.Model(&models.Publisher{}).Preload("CodeHosting"). - First(&publisher, "id = ?", ctx.Params("id")).Error; err != nil { + // Preload will load all the associated CodeHosting. We'll manually handle that later. + if err := p.db.Preload("CodeHosting").First(&publisher, "id = ?", ctx.Params("id")). + Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { - return common.Error(fiber.StatusNotFound, "Not found", "can't update Publisher. Publisher was not found") + return common.Error(fiber.StatusNotFound, "can't update Publisher", "Publisher was not found") } - return common.Error(fiber.StatusInternalServerError, + return common.Error( + fiber.StatusInternalServerError, "can't update Publisher", - fmt.Errorf("db error: %w", err).Error()) + fiber.ErrInternalServerError.Message, + ) } - if request.Description != "" { - publisher.Description = request.Description + if err := common.ValidateRequestEntity(ctx, publisherReq, "can't update Publisher"); err != nil { + return err //nolint:wrapcheck } - if request.Email != "" { - normalizedEmail := common.NormalizeEmail(&request.Email) - publisher.Email = normalizedEmail - } + // Slice of CodeHosting URLs that we expect in the database after the PATCH + var expectedURLs []string - if request.AlternativeID != "" { - publisher.AlternativeID = &request.AlternativeID + // application/merge-patch+json semantics: change CodeHosting only if + // the request specifies a "CodeHosting" key. + if publisherReq.CodeHosting != nil { + for _, ch := range *publisherReq.CodeHosting { + expectedURLs = append(expectedURLs, purell.MustNormalizeURLString(ch.URL, normalizeFlags)) + } + } else { + for _, ch := range publisher.CodeHosting { + expectedURLs = append(expectedURLs, ch.URL) + } } - if request.CodeHosting != nil && len(request.CodeHosting) > 0 { - gormTrx.Delete(&publisher.CodeHosting) + if err := p.db.Transaction(func(tran *gorm.DB) error { + codeHosting, err := syncCodeHosting(tran, publisher, expectedURLs) + if err != nil { + return err + } - for _, URLAddress := range request.CodeHosting { - publisher.CodeHosting = append(publisher.CodeHosting, models.CodeHosting{ID: utils.UUIDv4(), URL: URLAddress.URL}) + if publisherReq.Description != nil { + publisher.Description = *publisherReq.Description + } + if publisherReq.Email != nil { + publisher.Email = common.NormalizeEmail(publisherReq.Email) + } + if publisherReq.Active != nil { + publisher.Active = publisherReq.Active + } + if publisher.AlternativeID != nil { + publisher.AlternativeID = publisherReq.AlternativeID } - } - if err := gormTrx.Updates(&publisher).Error; err != nil { - return common.Error(fiber.StatusInternalServerError, - "can't update Publisher", - fmt.Errorf("db error: %w", err).Error()) + // Set CodeHosting to a zero value, so it's not touched by gorm's Update(), + // because we handle the alias manually + publisher.CodeHosting = []models.CodeHosting{} + + if err := tran.Updates(&publisher).Error; err != nil { + return err + } + + publisher.CodeHosting = codeHosting + + return nil + }); err != nil { + return common.Error(fiber.StatusInternalServerError, "can't update Publisher", err.Error()) } - return nil + // Sort the aliases to always have a consistent output + sort.Slice(publisher.CodeHosting, func(a int, b int) bool { + return publisher.CodeHosting[a].URL < publisher.CodeHosting[b].URL + }) + + return ctx.JSON(&publisher) } // DeletePublisher deletes the publisher with the given ID. @@ -214,3 +229,59 @@ func (p *Publisher) DeletePublisher(ctx *fiber.Ctx) error { return ctx.SendStatus(fiber.StatusNoContent) } + +// syncCodeHosting synchs the CodeHosting for a `publisher` in the database to reflect the +// passed slice of `codeHosting` URLs. +// +// It returns the slice of CodeHosting in the database. +func syncCodeHosting( //nolint:cyclop // mostly error handling ifs + gormdb *gorm.DB, publisher models.Publisher, codeHosting []string, +) ([]models.CodeHosting, error) { + toRemove := []string{} // Slice of CodeHosting ids to remove from the database + toAdd := []models.CodeHosting{} // Slice of CodeHosting to add to the database + + // Map mirroring the state of CodeHosting for this software in the database, + // keyed by url + urlMap := map[string]models.CodeHosting{} + + for _, ch := range publisher.CodeHosting { + urlMap[ch.URL] = ch + } + + for url, ch := range urlMap { + if !slices.Contains(codeHosting, url) { + toRemove = append(toRemove, ch.ID) + + delete(urlMap, url) + } + } + + for _, url := range codeHosting { + _, exists := urlMap[url] + if !exists { + ch := models.CodeHosting{ID: utils.UUIDv4(), URL: url} + + toAdd = append(toAdd, ch) + urlMap[url] = ch + } + } + + if len(toRemove) > 0 { + if err := gormdb.Delete(&models.CodeHosting{}, toRemove).Error; err != nil { + return nil, err + } + } + + if len(toAdd) > 0 { + if err := gormdb.Create(toAdd).Error; err != nil { + return nil, err + } + } + + retCodeHosting := make([]models.CodeHosting, 0, len(urlMap)) + for _, ch := range urlMap { + retCodeHosting = append(retCodeHosting, ch) + } + + return retCodeHosting, nil +} diff --git a/main_test.go b/main_test.go index d05f9b7..bfffd9e 100644 --- a/main_test.go +++ b/main_test.go @@ -748,50 +748,103 @@ func TestPublishersEndpoints(t *testing.T) { assert.Equal(t, "invalid json", response["detail"]) }, }, + + // PATCH /publishers/:id { - description: "PATCH non-existing publishers", - query: "PATCH /v1/publishers/NO_SUCH_publishers", - body: `{"codeHosting": [{"url" : "https://www.example.com"}], "email":"example@example.com"}`, + description: "PATCH non existing publisher", + query: "PATCH /v1/publishers/NO_SUCH_PUBLISHER", + body: ``, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, }, expectedCode: 404, - expectedBody: `{"title":"Not found","detail":"can't update Publisher. Publisher was not found","status":404}`, - expectedContentType: "application/problem+json", - }, - //TODO fix database locked test - /* - { - query: "PATCH /v1/publishers/15fda7c4-6bbf-4387-8f89-258c1e6fafb1", - body: `{"codeHosting": [{"url" : "https://www.example.com"}], "email":"example@example.com"}`, - headers: map[string][]string{ - "Authorization": {goodToken}, - "Content-Type": {"application/json"}, - }, - - expectedCode: 200, - expectedContentType: "application/json", - validateFunc: func(t *testing.T, response map[string]interface{}) { - assert.IsType(t, []interface{}{}, response["codeHosting"]) - assert.Equal(t, 3, len(response["codeHosting"].([]interface{}))) - - match, err := regexp.MatchString(UUID_REGEXP, response["id"].(string)) - assert.Nil(t, err) - assert.True(t, match) + expectedBody: `{"title":"can't update Publisher","detail":"Publisher was not found","status":404}`, + expectedContentType: "application/problem+json", + }, + { + description: "PATCH a publisher", + query: "PATCH /v1/publishers/2ded32eb-c45e-4167-9166-a44e18b8adde", + body: `{"description": "new PATCHed description", "codeHosting": [{"url": "https://gitlab.example.org/patched-repo"}]}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + expectedCode: 200, + expectedContentType: "application/json", + validateFunc: func(t *testing.T, response map[string]interface{}) { + assert.Equal(t, "new PATCHed description", response["description"]) + assert.IsType(t, []interface{}{}, response["codeHosting"]) - created, err := time.Parse(time.RFC3339, response["createdAt"].(string)) - assert.Nil(t, err) + codeHosting := response["codeHosting"].([]interface{}) + assert.Equal(t, 1, len(codeHosting)) - updated, err := time.Parse(time.RFC3339, response["updatedAt"].(string)) - assert.Nil(t, err) + firstCodeHosting := codeHosting[0].(map[string]interface{}) + + assert.Equal(t, "https://gitlab.example.org/patched-repo", firstCodeHosting["url"]) + assert.Equal(t, "2ded32eb-c45e-4167-9166-a44e18b8adde", response["id"]) + + created, err := time.Parse(time.RFC3339, response["createdAt"].(string)) + assert.Nil(t, err) + + updated, err := time.Parse(time.RFC3339, response["updatedAt"].(string)) + assert.Nil(t, err) + + assert.Greater(t, updated, created) + }, + }, + { + description: "PATCH publishers with no codeHosting (should leave current codeHosting untouched)", + query: "PATCH /v1/publishers/2ded32eb-c45e-4167-9166-a44e18b8adde", + body: `{"description": "new description"}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + + expectedCode: 200, + expectedContentType: "application/json", + validateFunc: func(t *testing.T, response map[string]interface{}) { + assert.Equal(t, "2ded32eb-c45e-4167-9166-a44e18b8adde", response["id"]) + assert.Equal(t, "new description", response["description"]) + assert.Equal(t, "foobar@1.example.org", response["email"]) + + assert.IsType(t, []interface{}{}, response["codeHosting"]) + + codeHosting := response["codeHosting"].([]interface{}) + assert.Equal(t, 2, len(codeHosting)) + + firstCodeHosting := codeHosting[0].(map[string]interface{}) + assert.Equal(t, "https://1-a.example.org/code/repo", firstCodeHosting["url"]) + secondCodeHosting := codeHosting[1].(map[string]interface{}) + assert.Equal(t, "https://1-b.example.org/code/repo", secondCodeHosting["url"]) + + assert.Equal(t, "2018-05-01T00:00:00Z", response["createdAt"]) + created, err := time.Parse(time.RFC3339, response["createdAt"].(string)) + assert.Nil(t, err) + + updated, err := time.Parse(time.RFC3339, response["updatedAt"].(string)) + assert.Nil(t, err) - assert.Greater(t, updated, created) - }, - },*/ + assert.Greater(t, updated, created) + }, + }, + { + description: "PATCH publishers with empty codeHosting", + query: "PATCH /v1/publishers/2ded32eb-c45e-4167-9166-a44e18b8adde", + body: `{"description": "new description", "codeHosting": []}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + + expectedCode: 422, + expectedContentType: "application/problem+json", + expectedBody: `{"title":"can't update Publisher","detail":"invalid format","status":422,"validationErrors":[{"field":"codeHosting","rule":"gt"}]}`, + }, { description: "PATCH publishers - wrong token", - query: "PATCH /v1/publishers/15fda7c4-6bbf-4387-8f89-258c1e6fafb1", + query: "PATCH /v1/publishers/2ded32eb-c45e-4167-9166-a44e18b8adde", body: ``, headers: map[string][]string{ "Authorization": {badToken}, @@ -802,8 +855,8 @@ func TestPublishersEndpoints(t *testing.T) { expectedContentType: "application/problem+json", }, { - description: "PATCH publishers with invalid JSON", - query: "PATCH /v1/publishers/15fda7c4-6bbf-4387-8f89-258c1e6fafb1", + description: "PATCH publisher with invalid JSON", + query: "PATCH /v1/publishers/2ded32eb-c45e-4167-9166-a44e18b8adde", body: `INVALID_JSON`, headers: map[string][]string{ "Authorization": {goodToken}, @@ -816,37 +869,37 @@ func TestPublishersEndpoints(t *testing.T) { assert.Equal(t, "invalid json", response["detail"]) }, }, - //TODO fix database locked test - /* - { - description: "PATCH publishers with validation errors", - query: "PATCH /v1/publishers/15fda7c4-6bbf-4387-8f89-258c1e6fafb1", - body: `{"codeHosting": [{"url" : "INVALID_URL"}], "email":"example@example.com"}`, - headers: map[string][]string{ - "Authorization": {goodToken}, - "Content-Type": {"application/json"}, - }, - expectedCode: 422, - expectedContentType: "application/problem+json", - validateFunc: func(t *testing.T, response map[string]interface{}) { - assert.Equal(t, `can't update Publisher`, response["title"]) - assert.Equal(t, "invalid format", response["detail"]) - - assert.IsType(t, []interface{}{}, response["validationErrors"]) - - validationErrors := response["validationErrors"].([]interface{}) - assert.Equal(t, 1, len(validationErrors)) - - firstValidationError := validationErrors[0].(map[string]interface{}) - - for key := range firstValidationError { - assert.Contains(t, []string{"field", "rule", "value"}, key) - } - }, - },*/ + // TODO: make this pass + // { + // description: "PATCH publishers with JSON with extra fields", + // query: "PATCH /v1/publishers", + // body: `{"description": "new description", EXTRA_FIELD: "extra field not in schema"}`, + // headers: map[string][]string{ + // "Authorization": {goodToken}, + // "Content-Type": {"application/json"}, + // }, + // expectedCode: 422, + // expectedContentType: "application/problem+json", + // validateFunc: func(t *testing.T, response map[string]interface{}) { + // assert.Equal(t, `can't create Publisher`, response["title"]) + // assert.Equal(t, "invalid json", response["detail"]) + // }, + // }, + { + description: "PATCH publisher with validation errors", + query: "PATCH /v1/publishers/2ded32eb-c45e-4167-9166-a44e18b8adde", + body: `{"description": "new description", "codeHosting": [{"url": "INVALID_URL"}]}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + expectedCode: 422, + expectedContentType: "application/problem+json", + expectedBody: `{"title":"can't update Publisher","detail":"invalid format","status":422,"validationErrors":[{"field":"url","rule":"url","value":"INVALID_URL"}]}`, + }, { description: "PATCH publishers with empty body", - query: "PATCH /v1/publishers/15fda7c4-6bbf-4387-8f89-258c1e6fafb1", + query: "PATCH /v1/publishers/2ded32eb-c45e-4167-9166-a44e18b8adde", body: "", headers: map[string][]string{ "Authorization": {goodToken}, @@ -854,11 +907,17 @@ func TestPublishersEndpoints(t *testing.T) { }, expectedCode: 400, expectedContentType: "application/problem+json", - validateFunc: func(t *testing.T, response map[string]interface{}) { - assert.Equal(t, `can't update Publisher`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) - }, + expectedBody: `{"title":"can't update Publisher","detail":"invalid json","status":400}`, }, + // TODO: enforce this? + // { + // query: "PATCH /v1/publishers with no Content-Type", + // body: "", + // headers: map[string][]string{ + // "Authorization": {goodToken}, + // }, + // expectedCode: 404, + // } // DELETE /publishers/:id { From ada1cf8c254a9cc419a46ed350a9d3ed517891ef Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Tue, 11 Oct 2022 13:04:15 +0200 Subject: [PATCH 02/54] fix: set publisher id in CodeHosting when PATCHing (#170) --- internal/handlers/publishers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/handlers/publishers.go b/internal/handlers/publishers.go index c96aa3a..1eb0e29 100644 --- a/internal/handlers/publishers.go +++ b/internal/handlers/publishers.go @@ -259,7 +259,7 @@ func syncCodeHosting( //nolint:cyclop // mostly error handling ifs for _, url := range codeHosting { _, exists := urlMap[url] if !exists { - ch := models.CodeHosting{ID: utils.UUIDv4(), URL: url} + ch := models.CodeHosting{ID: utils.UUIDv4(), URL: url, PublisherID: publisher.ID} toAdd = append(toAdd, ch) urlMap[url] = ch From ebc599362f626210246fc818235d93c646fccf4b Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Tue, 11 Oct 2022 13:04:28 +0200 Subject: [PATCH 03/54] fix: publisher conflict message (#169) Remove `email` from the conflict message as it's no longer a unique field. --- internal/handlers/publishers.go | 2 +- main_test.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/handlers/publishers.go b/internal/handlers/publishers.go index 1eb0e29..dd8b3a3 100644 --- a/internal/handlers/publishers.go +++ b/internal/handlers/publishers.go @@ -124,7 +124,7 @@ func (p *Publisher) PostPublisher(ctx *fiber.Ctx) error { case common.ErrDBUniqueConstraint: return common.Error(fiber.StatusConflict, "can't create Publisher", - "Publisher with provided description, email, alternativeId or CodeHosting URL already exists") + "description, alternativeId or codeHosting URL already exists") default: return common.Error(fiber.StatusInternalServerError, "can't create Publisher", diff --git a/main_test.go b/main_test.go index bfffd9e..1fa6d9d 100644 --- a/main_test.go +++ b/main_test.go @@ -477,7 +477,7 @@ func TestPublishersEndpoints(t *testing.T) { }, expectedCode: 409, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't create Publisher","detail":"Publisher with provided description, email, alternativeId or CodeHosting URL already exists","status":409}`, + expectedBody: `{"title":"can't create Publisher","detail":"description, alternativeId or codeHosting URL already exists","status":409}`, }, { description: "POST publisher with empty alternativeId", @@ -528,7 +528,7 @@ func TestPublishersEndpoints(t *testing.T) { }, expectedCode: 409, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't create Publisher","detail":"Publisher with provided description, email, alternativeId or CodeHosting URL already exists","status":409}`, + expectedBody: `{"title":"can't create Publisher","detail":"description, alternativeId or codeHosting URL already exists","status":409}`, }, { description: "POST new publisher with an existing email", @@ -596,7 +596,7 @@ func TestPublishersEndpoints(t *testing.T) { }, expectedCode: 409, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't create Publisher","detail":"Publisher with provided description, email, alternativeId or CodeHosting URL already exists","status":409}`, + expectedBody: `{"title":"can't create Publisher","detail":"description, alternativeId or codeHosting URL already exists","status":409}`, }, { description: "POST new publisher with no description", @@ -632,7 +632,7 @@ func TestPublishersEndpoints(t *testing.T) { }, expectedCode: 409, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't create Publisher","detail":"Publisher with provided description, email, alternativeId or CodeHosting URL already exists","status":409}`, + expectedBody: `{"title":"can't create Publisher","detail":"description, alternativeId or codeHosting URL already exists","status":409}`, }, { description: "POST publishers with invalid payload", From 5880e055a8bda42b1d023b31034b2d06efa40167 Mon Sep 17 00:00:00 2001 From: Lorenzo <5399264+LorenzoS92@users.noreply.github.com> Date: Wed, 12 Oct 2022 08:52:21 +0200 Subject: [PATCH 04/54] feat(metrics): add prometheus endpoint (#147) Co-authored-by: Fabio Bonelli Co-authored-by: Nicola Squartini --- charts/developers-italia-api/README.md | 6 + .../templates/servicemonitor.yaml | 35 ++ charts/developers-italia-api/values.yaml | 12 + go.mod | 17 +- go.sum | 410 +++++++++++++++++- main.go | 8 +- 6 files changed, 484 insertions(+), 4 deletions(-) create mode 100644 charts/developers-italia-api/templates/servicemonitor.yaml diff --git a/charts/developers-italia-api/README.md b/charts/developers-italia-api/README.md index 7dda4d7..c57501c 100644 --- a/charts/developers-italia-api/README.md +++ b/charts/developers-italia-api/README.md @@ -41,6 +41,12 @@ The API of Developers Italia | serviceAccount.annotations | object | `{}` | | | serviceAccount.create | bool | `true` | | | serviceAccount.name | string | `""` | | +| serviceMonitor.additionalLabels | object | `{}` | | +| serviceMonitor.enabled | bool | `false` | Create ServiceMonitor resource (requires corresponding Prometheus Operator CRD installed). | +| serviceMonitor.interval | string | `nil` | Interval at which metrics should be scraped (uses Prometheus default if unspecified, details [here](https://prometheus-operator.dev/docs/operator/api/#monitoring.coreos.com/v1.Endpoint)) | +| serviceMonitor.jobLabel | string | `nil` | Defaults to the name of the Kubernetes service (details [here](https://prometheus-operator.dev/docs/operator/api/#monitoring.coreos.com/v1.ServiceMonitor)). | +| serviceMonitor.scrapeTimeout | string | `nil` | Timeout after which the scrape is ended (uses Prometheus default if unspecified, details [here](https://prometheus-operator.dev/docs/operator/api/#monitoring.coreos.com/v1.Endpoint)). | +| serviceMonitor.targetLabels | list | `[]` | | | tolerations | list | `[]` | | | useExistingSecret | string | `nil` | Name of existing Kubernetes secret containing keys 'databaseDSN' and 'pasetoKey'. If not provided, a secret will be generated using values from 'databaseDSN' and 'pasetoKey'. | diff --git a/charts/developers-italia-api/templates/servicemonitor.yaml b/charts/developers-italia-api/templates/servicemonitor.yaml new file mode 100644 index 0000000..6c29a56 --- /dev/null +++ b/charts/developers-italia-api/templates/servicemonitor.yaml @@ -0,0 +1,35 @@ +{{- if .Values.serviceMonitor.enabled -}} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "developers-italia-api.fullname" . }} + labels: + {{- include "developers-italia-api.labels" . | nindent 4 }} + {{- if .Values.serviceMonitor.additionalLabels }} + {{- toYaml .Values.serviceMonitor.additionalLabels | nindent 4 }} + {{- end }} +spec: + endpoints: + - port: http + {{- if .Values.serviceMonitor.interval }} + interval: {{ .Values.serviceMonitor.interval }} + {{- end }} + {{- if .Values.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.serviceMonitor.scrapeTimeout }} + {{- end }} +{{- if .Values.serviceMonitor.jobLabel }} + jobLabel: {{ .Values.serviceMonitor.jobLabel | quote }} +{{- end }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} +{{- if .Values.serviceMonitor.targetLabels }} + targetLabels: + {{- range .Values.serviceMonitor.targetLabels }} + - {{ . }} + {{- end }} +{{- end }} + selector: + matchLabels: + {{- include "developers-italia-api.selectorLabels" . | nindent 6 }} +{{- end }} diff --git a/charts/developers-italia-api/values.yaml b/charts/developers-italia-api/values.yaml index 3e97147..547646a 100644 --- a/charts/developers-italia-api/values.yaml +++ b/charts/developers-italia-api/values.yaml @@ -100,3 +100,15 @@ databaseDSN: "" # -- Base64 encoded Paseto Key. pasetoKey: "" + +serviceMonitor: + # -- Create ServiceMonitor resource (requires corresponding Prometheus Operator CRD installed). + enabled: false + additionalLabels: {} + # -- (string) Defaults to the name of the Kubernetes service (details [here](https://prometheus-operator.dev/docs/operator/api/#monitoring.coreos.com/v1.ServiceMonitor)). + jobLabel: + # -- (string) Interval at which metrics should be scraped (uses Prometheus default if unspecified, details [here](https://prometheus-operator.dev/docs/operator/api/#monitoring.coreos.com/v1.Endpoint)) + interval: + # -- (string) Timeout after which the scrape is ended (uses Prometheus default if unspecified, details [here](https://prometheus-operator.dev/docs/operator/api/#monitoring.coreos.com/v1.Endpoint)). + scrapeTimeout: + targetLabels: [] diff --git a/go.mod b/go.mod index 2e2d65f..cdb6895 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/go-playground/validator/v10 v10.11.0 github.com/go-testfixtures/testfixtures/v3 v3.8.0 github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e - github.com/gofiber/fiber/v2 v2.34.1 + github.com/gofiber/fiber/v2 v2.36.0 github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa github.com/stretchr/testify v1.7.5 gorm.io/driver/postgres v1.3.7 @@ -16,11 +16,24 @@ require ( gorm.io/gorm v1.23.6 ) -require golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 +require ( + github.com/ansrivas/fiberprometheus/v2 v2.4.1 + golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 +) require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/gofiber/adaptor/v2 v2.1.25 // indirect + github.com/golang/protobuf v1.5.2 // indirect github.com/mattn/go-sqlite3 v1.14.13 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/prometheus/client_golang v1.12.2 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.32.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect + google.golang.org/protobuf v1.26.0 // indirect ) require ( diff --git a/go.sum b/go.sum index 91fb1c3..aa944a8 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,38 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/PuerkitoBio/purell v1.2.0 h1:/Jdm5QfyM8zdlqT6WVZU4cfP23sot6CEHA4CS49Ezig= @@ -10,10 +44,30 @@ github.com/aead/chacha20poly1305 v0.0.0-20201124145622-1a5aba2a8b29 h1:1DcvRPZOd github.com/aead/chacha20poly1305 v0.0.0-20201124145622-1a5aba2a8b29/go.mod h1:UzH9IX1MMqOcwhoNOIjmTQeAxrFgzs50j4golQtXXxU= github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw= github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635/go.mod h1:lmLxL+FV291OopO93Bwf9fQLQeLyt33VJRUg5VJ30us= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/ansrivas/fiberprometheus/v2 v2.4.1 h1:V87ahTcU/I4c8tD6GKiuyyB0Z82dw2VVqLDgBtUcUgc= +github.com/ansrivas/fiberprometheus/v2 v2.4.1/go.mod h1:ATJ3l0sufyoZBz+TEohAyQJqbgUSQaPwCHNL/L67Wnw= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/caarlos0/env/v6 v6.9.3 h1:Tyg69hoVXDnpO5Qvpsu8EoquarbPyQb+YwExWHP8wWU= github.com/caarlos0/env/v6 v6.9.3/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -24,7 +78,18 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs 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/denisenkom/go-mssqldb v0.12.2 h1:1OcPn5GBIobjWNd+8yjfHNIaFX14B1pWI3F9HZy5KXw= +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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +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/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= @@ -38,20 +103,79 @@ github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfC github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-testfixtures/testfixtures/v3 v3.8.0 h1:ZdMx3/TQvzOWMm7x03IMpGTsIKRo6WCIfNm6dBOYO1M= github.com/go-testfixtures/testfixtures/v3 v3.8.0/go.mod h1:r3jeE9Ten7qBsZYSCwZiqCCUnq4pJsZEsq5ShqoX5aA= +github.com/gofiber/adaptor/v2 v2.1.25 h1:K2Ef2a7mUsCfL/oJdzbjyMXchGYuUUwIVXrYVm+P+xs= +github.com/gofiber/adaptor/v2 v2.1.25/go.mod h1:gOxtwMVqUStB5goAYtKd+hSvGupdd+aRIafZHPLNaUk= github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e h1:ZsZeaEFExhECRgT/yYWxmOtbKjPbZxhe9pk1MSz1rOE= github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e/go.mod h1:zU7RONlVB7dBKM0EijoExlxAWJtevT5+9RqAH2imOUI= -github.com/gofiber/fiber/v2 v2.34.1 h1:C6saXB7385HvtXX+XMzc5Dqj5S/aEXOfKCW7JNep4rA= github.com/gofiber/fiber/v2 v2.34.1/go.mod h1:ozRQfS+D7EL1+hMH+gutku0kfx1wLX4hAxDCtDzpj4U= +github.com/gofiber/fiber/v2 v2.36.0 h1:1qLMe5rhXFLPa2SjK10Wz7WFgLwYi4TYg7XrjztJHqA= +github.com/gofiber/fiber/v2 v2.36.0/go.mod h1:tgCr+lierLwLoVHHO/jn3Niannv34WRkQETU8wiL9fQ= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +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= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/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.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +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/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7 h1:ux/56T2xqZO/3cP1I2F86qpeoYPCOzk+KF/UH/Ar+lk= github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= @@ -124,12 +248,23 @@ github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/ 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.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +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/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.7 h1:7cgTQxJCU/vy+oP/E3B9RGbQTgbiVzIJWIKOLoAsPok= github.com/klauspost/compress v1.15.7/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 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 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= @@ -159,6 +294,15 @@ github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGw github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.13 h1:1tj15ngiFfcZzii7yd82foL+ks+ouQcj8j/TPq3fk1I= github.com/mattn/go-sqlite3 v1.14.13/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/o1egl/paseto v1.0.0 h1:bwpvPu2au176w4IBlhbyUv/S5VPptERIA99Oap5qUd0= github.com/o1egl/paseto v1.0.0/go.mod h1:5HxsZPmw/3RI2pAwGo1HhOOwSdvBpcuVzO7uDkm+CLU= github.com/pilagod/gorm-cursor-paginator/v2 v2.3.0 h1:/jMv0+CtmpF5gf8Fn0JwgFsKcVrmvhPahHluHEcP13I= @@ -170,6 +314,28 @@ 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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= +github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 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.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= @@ -183,8 +349,10 @@ github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9Nz github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -205,7 +373,15 @@ github.com/valyala/fasthttp v1.38.0 h1:yTjSSNjuDi2PPvXY2836bIwLmiTS2T4T9p1coQshp github.com/valyala/fasthttp v1.38.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +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.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -217,10 +393,12 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= 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= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -234,72 +412,293 @@ golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 h1:tnebWN09GYg9OLPss1KXj8txwZc6X6uMr6VFdcGNbHw= golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 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-20190902080502-41f04d3bba15/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/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -316,4 +715,13 @@ gorm.io/gorm v1.21.7/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/gorm v1.23.6 h1:KFLdNgri4ExFFGTRGGFWON2P1ZN28+9SJRN8voOoYe0= gorm.io/gorm v1.23.6/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 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= +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/main.go b/main.go index 7196696..956fcb6 100644 --- a/main.go +++ b/main.go @@ -2,22 +2,24 @@ package main import ( "log" + "os" "time" "github.com/caarlos0/env/v6" "gorm.io/gorm" "github.com/italia/developers-italia-api/internal/common" + "github.com/italia/developers-italia-api/internal/database" "github.com/italia/developers-italia-api/internal/handlers" "github.com/italia/developers-italia-api/internal/middleware" "github.com/italia/developers-italia-api/internal/models" "github.com/italia/developers-italia-api/internal/webhooks" + "github.com/ansrivas/fiberprometheus/v2" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cache" "github.com/gofiber/fiber/v2/middleware/limiter" "github.com/gofiber/fiber/v2/middleware/recover" - "github.com/italia/developers-italia-api/internal/database" ) func main() { @@ -88,6 +90,10 @@ func Setup() *fiber.App { common.EnvironmentConfig.PasetoKey = middleware.NewRandomPasetoKey() } + prometheus := fiberprometheus.New(os.Args[0]) + prometheus.RegisterAt(app, "/metrics") + app.Use(prometheus.Middleware) + app.Use(middleware.NewPasetoMiddleware(common.EnvironmentConfig)) setupHandlers(app, gormDB) From c1dd6a64bbcf535b763911f2bc9d51cae2db5592 Mon Sep 17 00:00:00 2001 From: Nicola Squartini Date: Wed, 12 Oct 2022 10:18:30 +0200 Subject: [PATCH 05/54] chore(chart): bump version (#172) --- charts/developers-italia-api/Chart.yaml | 4 ++-- charts/developers-italia-api/README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/developers-italia-api/Chart.yaml b/charts/developers-italia-api/Chart.yaml index a0bcdec..d4b6733 100644 --- a/charts/developers-italia-api/Chart.yaml +++ b/charts/developers-italia-api/Chart.yaml @@ -15,12 +15,12 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: v0.1.0 +version: v0.2.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "v0.3.0" +appVersion: "v0.7.0" icon: https://avatars.githubusercontent.com/u/15377824?s=96&v=4 diff --git a/charts/developers-italia-api/README.md b/charts/developers-italia-api/README.md index c57501c..0af9797 100644 --- a/charts/developers-italia-api/README.md +++ b/charts/developers-italia-api/README.md @@ -1,6 +1,6 @@ # developers-italia-api -![Version: v0.1.0](https://img.shields.io/badge/Version-v0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.3.0](https://img.shields.io/badge/AppVersion-v0.3.0-informational?style=flat-square) +![Version: v0.2.0](https://img.shields.io/badge/Version-v0.2.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.7.0](https://img.shields.io/badge/AppVersion-v0.7.0-informational?style=flat-square) The API of Developers Italia From de88cdc4f0e1c27dc54f68bc0ed26b2315605871 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Mon, 24 Oct 2022 10:07:57 +0200 Subject: [PATCH 06/54] feat(publishers): make alternativeId work as an id in endpoints (#176) --- developers-italia.oas.yaml | 15 ++++-- internal/handlers/publishers.go | 46 ++++++++++++++++-- main_test.go | 85 +++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 9 deletions(-) diff --git a/developers-italia.oas.yaml b/developers-italia.oas.yaml index 9c3b1ee..fc2c074 100644 --- a/developers-italia.oas.yaml +++ b/developers-italia.oas.yaml @@ -910,7 +910,7 @@ paths: required: true get: summary: Get a Publisher - description: Get a Publisher by its id + description: Get a Publisher by its id or alternativeId tags: - publishers responses: @@ -927,7 +927,7 @@ paths: operationId: show-publisher-publisherId patch: summary: Update a Publisher - description: Update a Publisher by its id. Only the fields that are provided will be updated, codeHosting field will be overwritten entirely. + description: Update a Publisher by its id or alternativeId tags: - publishers security: @@ -958,7 +958,7 @@ paths: $ref: '#/components/schemas/Publisher' delete: summary: Delete a Publisher - description: Delete a Publisher by its id + description: Delete a Publisher by its id or alternativeId tags: - publishers security: @@ -1531,8 +1531,13 @@ components: alternativeId: type: string description: | - Optional alternative custom id for this Publisher. This is useful for example if this - Publisher has another id or code in a different database. + Optional alternative user-provided identifier for this Publisher. + + If present, you can use it in place of the Publisher `id` as path query + argument. + + This is useful for example if this Publisher has another id or code in a + different database. maxLength: 255 example: 'ID-1234' pattern: '.*' diff --git a/internal/handlers/publishers.go b/internal/handlers/publishers.go index dd8b3a3..34dc0bf 100644 --- a/internal/handlers/publishers.go +++ b/internal/handlers/publishers.go @@ -2,6 +2,7 @@ package handlers import ( "errors" + "fmt" "net/url" "sort" @@ -72,8 +73,9 @@ func (p *Publisher) GetPublishers(ctx *fiber.Ctx) error { // GetPublisher gets the publisher with the given ID and returns any error encountered. func (p *Publisher) GetPublisher(ctx *fiber.Ctx) error { publisher := models.Publisher{} + id := ctx.Params("id") - if err := p.db.Preload("CodeHosting").First(&publisher, "id = ?", ctx.Params("id")).Error; err != nil { + if err := p.db.Preload("CodeHosting").First(&publisher, "id = ? or alternative_id = ?", id, id).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return common.Error(fiber.StatusNotFound, "can't get Publisher", "Publisher was not found") } @@ -93,6 +95,23 @@ func (p *Publisher) PostPublisher(ctx *fiber.Ctx) error { return err //nolint:wrapcheck } + if request.AlternativeID != nil { + //nolint:godox // postpone the fix + // FIXME: Possible TOCTTOU race here + result := p.db.Limit(1).Find(&models.Publisher{ID: *request.AlternativeID}) + + if result.Error != nil { + return common.Error(fiber.StatusInternalServerError, "can't create Publisher", "db error") + } + + if result.RowsAffected != 0 { + return common.Error(fiber.StatusConflict, + "can't create Publisher", + fmt.Sprintf("Publisher with id '%s' already exists", *request.AlternativeID), + ) + } + } + normalizedEmail := common.NormalizeEmail(request.Email) publisher := &models.Publisher{ @@ -136,12 +155,13 @@ func (p *Publisher) PostPublisher(ctx *fiber.Ctx) error { } // PatchPublisher updates the publisher with the given ID. CodeHosting URLs will be overwritten from the request. -func (p *Publisher) PatchPublisher(ctx *fiber.Ctx) error { //nolint:cyclop // mostly error handling ifs +func (p *Publisher) PatchPublisher(ctx *fiber.Ctx) error { //nolint:cyclop,funlen // mostly error handling ifs publisherReq := new(common.PublisherPatch) publisher := models.Publisher{} + id := ctx.Params("id") // Preload will load all the associated CodeHosting. We'll manually handle that later. - if err := p.db.Preload("CodeHosting").First(&publisher, "id = ?", ctx.Params("id")). + if err := p.db.Preload("CodeHosting").First(&publisher, "id = ? or alternative_id = ?", id, id). Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return common.Error(fiber.StatusNotFound, "can't update Publisher", "Publisher was not found") @@ -158,6 +178,23 @@ func (p *Publisher) PatchPublisher(ctx *fiber.Ctx) error { //nolint:cyclop // mo return err //nolint:wrapcheck } + if publisherReq.AlternativeID != nil { + //nolint:godox // postpone the fix + // FIXME: Possible TOCTTOU race here + result := p.db.Limit(1).Find(&models.Publisher{ID: *publisherReq.AlternativeID}) + + if result.Error != nil { + return common.Error(fiber.StatusInternalServerError, "can't update Publisher", "db error") + } + + if result.RowsAffected != 0 { + return common.Error(fiber.StatusConflict, + "can't update Publisher", + fmt.Sprintf("Publisher with id '%s' already exists", *publisherReq.AlternativeID), + ) + } + } + // Slice of CodeHosting URLs that we expect in the database after the PATCH var expectedURLs []string @@ -217,7 +254,8 @@ func (p *Publisher) PatchPublisher(ctx *fiber.Ctx) error { //nolint:cyclop // mo // DeletePublisher deletes the publisher with the given ID. func (p *Publisher) DeletePublisher(ctx *fiber.Ctx) error { - result := p.db.Select("CodeHosting").Delete(&models.Publisher{ID: ctx.Params("id")}) + id := ctx.Params("id") + result := p.db.Select("CodeHosting").Where("id = ? or alternative_id = ?", id, id).Delete(&models.Publisher{}) if result.Error != nil { return common.Error(fiber.StatusInternalServerError, "can't delete Publisher", "db error") diff --git a/main_test.go b/main_test.go index 1fa6d9d..c05ac79 100644 --- a/main_test.go +++ b/main_test.go @@ -399,6 +399,25 @@ func TestPublishersEndpoints(t *testing.T) { } }, }, + { + description: "GET publisher with alternativeId", + query: "GET /v1/publishers/alternative-id-12345", + expectedCode: 200, + expectedContentType: "application/json", + validateFunc: func(t *testing.T, response map[string]interface{}) { + assert.Equal(t, "15fda7c4-6bbf-4387-8f89-258c1e6facb0", response["id"]) + assert.Equal(t, "alternative-id-12345", response["alternativeId"]) + + _, err := time.Parse(time.RFC3339, response["createdAt"].(string)) + assert.Nil(t, err) + _, err = time.Parse(time.RFC3339, response["updatedAt"].(string)) + assert.Nil(t, err) + + for key := range response { + assert.Contains(t, []string{"id", "createdAt", "updatedAt", "codeHosting", "email", "description", "active", "alternativeId"}, key) + } + }, + }, // POST /publishers { @@ -479,6 +498,18 @@ func TestPublishersEndpoints(t *testing.T) { expectedContentType: "application/problem+json", expectedBody: `{"title":"can't create Publisher","detail":"description, alternativeId or codeHosting URL already exists","status":409}`, }, + { + description: "POST publisher with alternativeId matching an existing id", + query: "POST /v1/publishers", + body: `{"alternativeId": "2ded32eb-c45e-4167-9166-a44e18b8adde", "description":"new description", "codeHosting": [{"url" : "https://example-testcase-xx3.com"}]}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + expectedCode: 409, + expectedContentType: "application/problem+json", + expectedBody: `{"title":"can't create Publisher","detail":"Publisher with id '2ded32eb-c45e-4167-9166-a44e18b8adde' already exists","status":409}`, + }, { description: "POST publisher with empty alternativeId", query: "POST /v1/publishers", @@ -842,6 +873,49 @@ func TestPublishersEndpoints(t *testing.T) { expectedContentType: "application/problem+json", expectedBody: `{"title":"can't update Publisher","detail":"invalid format","status":422,"validationErrors":[{"field":"codeHosting","rule":"gt"}]}`, }, + { + description: "PATCH a publisher via alternativeId", + query: "PATCH /v1/publishers/alternative-id-12345", + body: `{"description": "new PATCHed description via alternativeId", "codeHosting": [{"url": "https://gitlab.example.org/patched-repo"}]}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + expectedCode: 200, + expectedContentType: "application/json", + validateFunc: func(t *testing.T, response map[string]interface{}) { + assert.Equal(t, "new PATCHed description via alternativeId", response["description"]) + assert.IsType(t, []interface{}{}, response["codeHosting"]) + + codeHosting := response["codeHosting"].([]interface{}) + assert.Equal(t, 1, len(codeHosting)) + + firstCodeHosting := codeHosting[0].(map[string]interface{}) + + assert.Equal(t, "https://gitlab.example.org/patched-repo", firstCodeHosting["url"]) + assert.Equal(t, "15fda7c4-6bbf-4387-8f89-258c1e6facb0", response["id"]) + + created, err := time.Parse(time.RFC3339, response["createdAt"].(string)) + assert.Nil(t, err) + + updated, err := time.Parse(time.RFC3339, response["updatedAt"].(string)) + assert.Nil(t, err) + + assert.Greater(t, updated, created) + }, + }, + { + description: "PATCH a publisher with alternativeId matching an existing id", + query: "PATCH /v1/publishers/2ded32eb-c45e-4167-9166-a44e18b8adde", + body: `{"alternativeId": "47807e0c-0613-4aea-9917-5455cc6eddad"}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + expectedCode: 409, + expectedContentType: "application/problem+json", + expectedBody: `{"title":"can't update Publisher","detail":"Publisher with id '47807e0c-0613-4aea-9917-5455cc6eddad' already exists","status":409}`, + }, { description: "PATCH publishers - wrong token", query: "PATCH /v1/publishers/2ded32eb-c45e-4167-9166-a44e18b8adde", @@ -952,6 +1026,17 @@ func TestPublishersEndpoints(t *testing.T) { expectedBody: "", expectedContentType: "", }, + { + description: "DELETE publisher via alternativeId", + query: "DELETE /v1/publishers/alternative-id-12345", + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + expectedCode: 204, + expectedBody: "", + expectedContentType: "", + }, // WebHooks From 0563de964be941123f2b25be94f9b1c95f61a85b Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Mon, 7 Nov 2022 14:12:43 +0100 Subject: [PATCH 07/54] fix: implement entity field in /{software/,}logs (#177) --- developers-italia.oas.yaml | 6 ++++++ go.mod | 6 +++--- go.sum | 15 ++++++++------- internal/handlers/logs.go | 6 ++++-- internal/models/models.go | 5 +++-- main_test.go | 24 ++++++++++++++++++++---- test/testdata/fixtures/logs.yml | 2 ++ 7 files changed, 46 insertions(+), 18 deletions(-) diff --git a/developers-italia.oas.yaml b/developers-italia.oas.yaml index fc2c074..3c1ab46 100644 --- a/developers-italia.oas.yaml +++ b/developers-italia.oas.yaml @@ -1577,6 +1577,12 @@ components: type: string maxLength: 255 pattern: '.*' + description: > + The resource this log is about (fe. a particular Publisher / Software). + It might be absent if the log is not about a specific resource or if + the resource doesn't exist yet, like in case of the error log caused by + failure to create it. + example: /software/7589be36-f046-45c6-9223-b7de9dbf06cd readOnly: true required: - id diff --git a/go.mod b/go.mod index cdb6895..85c51cd 100644 --- a/go.mod +++ b/go.mod @@ -12,8 +12,8 @@ require ( github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa github.com/stretchr/testify v1.7.5 gorm.io/driver/postgres v1.3.7 - gorm.io/driver/sqlite v1.3.4 - gorm.io/gorm v1.23.6 + gorm.io/driver/sqlite v1.4.3 + gorm.io/gorm v1.24.1 ) require ( @@ -26,7 +26,7 @@ require ( github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/gofiber/adaptor/v2 v2.1.25 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/mattn/go-sqlite3 v1.14.13 // indirect + github.com/mattn/go-sqlite3 v1.14.16 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/prometheus/client_golang v1.12.2 // indirect github.com/prometheus/client_model v0.2.0 // indirect diff --git a/go.sum b/go.sum index aa944a8..0667323 100644 --- a/go.sum +++ b/go.sum @@ -291,9 +291,9 @@ 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.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= -github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.13 h1:1tj15ngiFfcZzii7yd82foL+ks+ouQcj8j/TPq3fk1I= -github.com/mattn/go-sqlite3 v1.14.13/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +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/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -707,14 +707,15 @@ gorm.io/driver/postgres v1.0.8/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5d gorm.io/driver/postgres v1.3.7 h1:FKF6sIMDHDEvvMF/XJvbnCl0nu6KSKUaPXevJ4r+VYQ= gorm.io/driver/postgres v1.3.7/go.mod h1:f02ympjIcgtHEGFMZvdgTxODZ9snAHDb4hXfigBVuNI= gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw= -gorm.io/driver/sqlite v1.3.4 h1:NnFOPVfzi4CPsJPH4wXr6rMkPb4ElHEqKMvrsx9c9Fk= -gorm.io/driver/sqlite v1.3.4/go.mod h1:B+8GyC9K7VgzJAcrcXMRPdnMcck+8FgJynEehEPM16U= +gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU= +gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.21.7/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.23.6 h1:KFLdNgri4ExFFGTRGGFWON2P1ZN28+9SJRN8voOoYe0= -gorm.io/gorm v1.23.6/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/gorm v1.24.1 h1:CgvzRniUdG67hBAzsxDGOAuq4Te1osVMYsa1eQbd4fs= +gorm.io/gorm v1.24.1/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/handlers/logs.go b/internal/handlers/logs.go index 357146b..6d4871b 100644 --- a/internal/handlers/logs.go +++ b/internal/handlers/logs.go @@ -221,11 +221,13 @@ func (p *Log) PostSoftwareLog(ctx *fiber.Ctx) error { return common.ErrorWithValidationErrors(fiber.StatusUnprocessableEntity, "can't create Log", "invalid format", err) } + table := models.Software{}.TableName() + log := models.Log{ ID: utils.UUIDv4(), Message: logReq.Message, - EntityID: software.ID, - EntityType: models.Software{}.TableName(), + EntityID: &software.ID, + EntityType: &table, } if err := p.db.Create(&log).Error; err != nil { diff --git a/internal/models/models.go b/internal/models/models.go index 4d50e4d..b0c32c8 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -25,8 +25,9 @@ type Log struct { DeletedAt gorm.DeletedAt `json:"-" gorm:"index"` // Entity this Log entry is about (fe. Publisher, Software, etc.) - EntityID string `json:"-"` - EntityType string `json:"-"` + EntityID *string `json:"-"` + EntityType *string `json:"-"` + Entity string `json:"entity,omitempty" gorm:"->;type:text GENERATED ALWAYS AS (CASE WHEN entity_id IS NULL THEN NULL ELSE ('/' || entity_type || '/' || entity_id) END) STORED;default:(-);"` //nolint:lll } type Publisher struct { diff --git a/main_test.go b/main_test.go index c05ac79..87d851a 100644 --- a/main_test.go +++ b/main_test.go @@ -2101,6 +2101,8 @@ func TestSoftwareEndpoints(t *testing.T) { _, err = time.Parse(time.RFC3339, log["updatedAt"].(string)) assert.Nil(t, err) + assert.Equal(t, "/software/c353756e-8597-4e46-a99b-7da2e141603b", log["entity"]) + for key := range log { assert.Contains(t, []string{"id", "createdAt", "updatedAt", "message", "entity"}, key) } @@ -2112,8 +2114,6 @@ func TestSoftwareEndpoints(t *testing.T) { prevCreatedAt = &createdAt } - - // TODO assert.NotEmpty(t, firstLog["entity"]) }, }, { @@ -2185,6 +2185,8 @@ func TestSoftwareEndpoints(t *testing.T) { _, err = time.Parse(time.RFC3339, response["updatedAt"].(string)) assert.Nil(t, err) + assert.Equal(t, "/software/c353756e-8597-4e46-a99b-7da2e141603b", response["entity"]) + // TODO: check the record was actually created in the database }, }, @@ -2533,13 +2535,25 @@ func TestLogsEndpoints(t *testing.T) { _, err = time.Parse(time.RFC3339, log["updatedAt"].(string)) assert.Nil(t, err) + // Only certain logs from the fixtures have an associated entity. + // + // FIXME: This is ugly, see the issue about improving tests: + // https://github.com/italia/developers-italia-api/issues/91 + if log["id"] == "2dfb2bc2-042d-11ed-9338-d8bbc146d165" || + log["id"] == "12f30d9e-042e-11ed-8ddc-d8bbc146d165" || + log["id"] == "18a70362-042e-11ed-b793-d8bbc146d165" { + assert.Equal(t, "/software/c353756e-8597-4e46-a99b-7da2e141603b", log["entity"]) + } else if log["id"] == "53650508-042e-11ed-9b84-d8bbc146d165" { + assert.Equal(t, "/publishers/2ded32eb-c45e-4167-9166-a44e18b8adde", log["entity"]) + } else { + assert.Nil(t, log["entity"]) + } + var prevCreatedAt *time.Time = nil for key := range log { assert.Contains(t, []string{"id", "createdAt", "updatedAt", "message", "entity"}, key) } - // TODO assert.NotEmpty(t, firstLog["entity"]) - // Check the logs are ordered by descending createdAt if prevCreatedAt != nil { assert.GreaterOrEqual(t, *prevCreatedAt, createdAt) @@ -2708,6 +2722,8 @@ func TestLogsEndpoints(t *testing.T) { _, err = time.Parse(time.RFC3339, response["updatedAt"].(string)) assert.Nil(t, err) + assert.Nil(t, response["entity"]) + // TODO: check the record was actually created in the database }, }, diff --git a/test/testdata/fixtures/logs.yml b/test/testdata/fixtures/logs.yml index 64e9486..4572ad1 100644 --- a/test/testdata/fixtures/logs.yml +++ b/test/testdata/fixtures/logs.yml @@ -27,6 +27,8 @@ - id: 53650508-042e-11ed-9b84-d8bbc146d165 created_at: 2010-02-15 23:59:59 updated_at: 2010-12-31 23:59:59 + entity_id: 2ded32eb-c45e-4167-9166-a44e18b8adde + entity_type: publishers message: A log message - id: 55438aac-042e-11ed-848a-d8bbc146d165 From a2b29cd434dc42104192ce0ec64fbe4a1fe00566 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 11 Nov 2022 11:23:22 +0100 Subject: [PATCH 08/54] doc: add hint for PASETO_KEY generation (#178) --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4d9a038..836ec72 100644 --- a/README.md +++ b/README.md @@ -70,8 +70,13 @@ You can configure the API with environment variables: Supports PostgreSQL and SQLite. * `PASETO_KEY` (optional): Base64 encoded 32 bytes key used to check the - [PASETO](https://paseto.io/) authentication tokens. - If not set the API will run in read only mode. + [PASETO](https://paseto.io/) authentication tokens. You can generate it with + + ```console + head -c 32 /dev/urandom | base64 + ``` + + If not set, the API will run in read only mode. * `ENVIRONMENT` (optional): possible values `test`, `development`, `production`. Default `production`. From bc1a19591c10f687b7ffac1f5ed173f94de4aa39 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 11 Nov 2022 15:25:27 +0100 Subject: [PATCH 09/54] chore(ci): publish the staging Docker image with goreleaser (#179) Publish the staging Docker image (ghcr.io/italia/developers-italia-api:main) when pushing to main. --- .../publish-staging-docker-image.yml | 41 +++++++++++++++++++ .goreleaser.staging.yaml | 21 ++++++++++ Dockerfile | 2 +- 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/publish-staging-docker-image.yml create mode 100644 .goreleaser.staging.yaml diff --git a/.github/workflows/publish-staging-docker-image.yml b/.github/workflows/publish-staging-docker-image.yml new file mode 100644 index 0000000..cac33a2 --- /dev/null +++ b/.github/workflows/publish-staging-docker-image.yml @@ -0,0 +1,41 @@ +# Push the staging Docker image (ghcr.italia/developers-italia-api:main) +# on updates to main. + +on: + push: + branches: [ main ] + +permissions: + # To push Docker images to GitHub + packages: write + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - + uses: actions/setup-go@v3 + with: + go-version: 1.18.x + - + uses: actions/checkout@v2 + with: + # All history, required for goreleaser + fetch-depth: 0 + - + # FIXME: goreleaser should already take care of the login + # (see https://github.com/goreleaser/goreleaser/blame/02a3486d4ba59505113a57b438ae567351ed3dab/scripts/entrypoint.sh#L17) + # but it doesn't work for some reason. + run: echo "$GITHUB_TOKEN" | docker login ghcr.io -u docker --password-stdin + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - + # Tag with a temporary valid semantic version. This is required by goreleaser. + run: git tag $(git describe --tags --abbrev=0)-main-$(git rev-parse --short HEAD) + + - + uses: goreleaser/goreleaser-action@v2 + with: + version: v1.9.2 + args: release --config .goreleaser.staging.yaml diff --git a/.goreleaser.staging.yaml b/.goreleaser.staging.yaml new file mode 100644 index 0000000..56c9650 --- /dev/null +++ b/.goreleaser.staging.yaml @@ -0,0 +1,21 @@ +# Goreleases configuration for staging builds, just builds and pushes +# the Docker image for the main branch. +# +# Make sure to check the documentation at https://goreleaser.com + +# Don't create a GitHub release +release: + disable: true + +builds: + - env: + - CGO_ENABLED=0 + ldflags: + - -s -w + goos: + - linux +dockers: + - + dockerfile: Dockerfile.goreleaser + image_templates: + - "ghcr.io/italia/developers-italia-api:main" diff --git a/Dockerfile b/Dockerfile index e30d58e..cfeb813 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # # This is for local development only. -# See Dockerfile.goreleaser for the image published on release. +# See Dockerfile.goreleaser for the image published on release or staging. # FROM golang:1.18 as base From 01345649a3897179a4fb44e7b2303ce53821eca6 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 11 Nov 2022 16:34:42 +0100 Subject: [PATCH 10/54] chore(chart): add timestamp to annotations and bump versions (#180) Add timestamp so the deployment is updated correctly with Keel. Also, bump the chart and app versions. --- charts/developers-italia-api/Chart.yaml | 4 ++-- charts/developers-italia-api/templates/deployment.yaml | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/charts/developers-italia-api/Chart.yaml b/charts/developers-italia-api/Chart.yaml index d4b6733..dff5345 100644 --- a/charts/developers-italia-api/Chart.yaml +++ b/charts/developers-italia-api/Chart.yaml @@ -15,12 +15,12 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: v0.2.0 +version: v0.2.1 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "v0.7.0" +appVersion: "v0.7.2" icon: https://avatars.githubusercontent.com/u/15377824?s=96&v=4 diff --git a/charts/developers-italia-api/templates/deployment.yaml b/charts/developers-italia-api/templates/deployment.yaml index 4130bb0..5d2e1e2 100644 --- a/charts/developers-italia-api/templates/deployment.yaml +++ b/charts/developers-italia-api/templates/deployment.yaml @@ -6,6 +6,8 @@ metadata: {{- include "developers-italia-api.labels" . | nindent 4 }} {{- with .Values.deploymentAnnotations }} annotations: + timestamp: "{{ date "20060102150405" .Release.Time }}" + {{- toYaml . | nindent 4 }} {{- end }} spec: From e2fa721403af64362eb121c6d548f2163e34a73f Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Wed, 16 Nov 2022 11:50:49 +0100 Subject: [PATCH 11/54] chore(chart): don't use .Release.Time which is removed in Helm 3 (#182) --- charts/developers-italia-api/Chart.yaml | 2 +- charts/developers-italia-api/templates/deployment.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/developers-italia-api/Chart.yaml b/charts/developers-italia-api/Chart.yaml index dff5345..bd19d68 100644 --- a/charts/developers-italia-api/Chart.yaml +++ b/charts/developers-italia-api/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: v0.2.1 +version: v0.2.2 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/charts/developers-italia-api/templates/deployment.yaml b/charts/developers-italia-api/templates/deployment.yaml index 5d2e1e2..8e51095 100644 --- a/charts/developers-italia-api/templates/deployment.yaml +++ b/charts/developers-italia-api/templates/deployment.yaml @@ -6,7 +6,7 @@ metadata: {{- include "developers-italia-api.labels" . | nindent 4 }} {{- with .Values.deploymentAnnotations }} annotations: - timestamp: "{{ date "20060102150405" .Release.Time }}" + timestamp: {{ now | date "20060102150405" | quote }} {{- toYaml . | nindent 4 }} {{- end }} From 61f74860967676a3ddf20086b84a76da44d9355c Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 18 Nov 2022 14:18:03 +0100 Subject: [PATCH 12/54] fix: don't soft delete resources (#183) Don't soft delete API resources with unique columns, otherwise it wouldn't be possible to add a previously used (and deleted) resource, because is would still be in the database, albeit invisible to the API users. --- internal/models/models.go | 41 ++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/internal/models/models.go b/internal/models/models.go index b0c32c8..4d5bed6 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -31,15 +31,14 @@ type Log struct { } type Publisher struct { - ID string `json:"id" gorm:"primaryKey"` - Email *string `json:"email,omitempty"` - Description string `json:"description" gorm:"uniqueIndex;not null"` - CodeHosting []CodeHosting `json:"codeHosting" gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;unique"` - Active *bool `json:"active" gorm:"default:true;not null"` - AlternativeID *string `json:"alternativeId,omitempty" gorm:"uniqueIndex"` - CreatedAt time.Time `json:"createdAt" gorm:"index"` - UpdatedAt time.Time `json:"updatedAt"` - DeletedAt gorm.DeletedAt `json:"-" gorm:"index"` + ID string `json:"id" gorm:"primaryKey"` + Email *string `json:"email,omitempty"` + Description string `json:"description" gorm:"uniqueIndex;not null"` + CodeHosting []CodeHosting `json:"codeHosting" gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;unique"` + Active *bool `json:"active" gorm:"default:true;not null"` + AlternativeID *string `json:"alternativeId,omitempty" gorm:"uniqueIndex"` + CreatedAt time.Time `json:"createdAt" gorm:"index"` + UpdatedAt time.Time `json:"updatedAt"` } func (Publisher) TableName() string { @@ -55,13 +54,12 @@ func (CodeHosting) TableName() string { } type CodeHosting struct { - ID string `json:"-" gorm:"primaryKey"` - URL string `json:"url" gorm:"not null;uniqueIndex"` - Group *bool `json:"group" gorm:"default:true;not null"` - PublisherID string `json:"-"` - CreatedAt time.Time `json:"createdAt" gorm:"index"` - UpdatedAt time.Time `json:"updatedAt"` - DeletedAt gorm.DeletedAt `json:"-" gorm:"index"` + ID string `json:"-" gorm:"primaryKey"` + URL string `json:"url" gorm:"not null;uniqueIndex"` + Group *bool `json:"group" gorm:"default:true;not null"` + PublisherID string `json:"-"` + CreatedAt time.Time `json:"createdAt" gorm:"index"` + UpdatedAt time.Time `json:"updatedAt"` } type Software struct { @@ -103,12 +101,11 @@ func (su SoftwareURL) MarshalJSON() ([]byte, error) { } type Webhook struct { - ID string `json:"id" gorm:"primaryKey"` - URL string `json:"url" gorm:"index:idx_webhook_url,unique"` - Secret string `json:"-"` - CreatedAt time.Time `json:"createdAt" gorm:"index"` - UpdatedAt time.Time `json:"updatedAt"` - DeletedAt gorm.DeletedAt `json:"-" gorm:"index"` + ID string `json:"id" gorm:"primaryKey"` + URL string `json:"url" gorm:"index:idx_webhook_url,unique"` + Secret string `json:"-"` + CreatedAt time.Time `json:"createdAt" gorm:"index"` + UpdatedAt time.Time `json:"updatedAt"` // Entity this Webhook is for (fe. Publisher, Software, etc.) EntityID string `json:"-" gorm:"index:idx_webhook_url,unique"` From 13170329648188a8781b1c65cfdb5b663cc05e46 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 18 Nov 2022 14:40:26 +0100 Subject: [PATCH 13/54] chore(ci): always tag for Goreleaser with a valid semantic version (#184) The last tag can be a non valid semantic version (fe. when we tag with helm/vX.Y.Z), so let's force a valid semantic version for the temporary Goreleaser tag. --- .github/workflows/publish-staging-docker-image.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-staging-docker-image.yml b/.github/workflows/publish-staging-docker-image.yml index cac33a2..7af659e 100644 --- a/.github/workflows/publish-staging-docker-image.yml +++ b/.github/workflows/publish-staging-docker-image.yml @@ -32,7 +32,7 @@ jobs: - # Tag with a temporary valid semantic version. This is required by goreleaser. - run: git tag $(git describe --tags --abbrev=0)-main-$(git rev-parse --short HEAD) + run: git tag v0-main-$(git rev-parse --short HEAD) - uses: goreleaser/goreleaser-action@v2 From 1e54f15cd1daac05c73fd9f1e9a1ff03c91bf3c1 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 25 Nov 2022 15:09:28 +0100 Subject: [PATCH 14/54] doc: update API documentation link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 836ec72..c4e6be5 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@

- + API documentation

From 24d586df5708a7a095fa05939bf7b6317b83e53b Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 25 Nov 2022 15:25:33 +0100 Subject: [PATCH 15/54] chore(openapi): remove bundles from spec (#185) Remove Bundles from spec until the actual implementation (https://github.com/italia/developers-italia-api/issues/13) --- developers-italia.oas.yaml | 149 ------------------------------------- 1 file changed, 149 deletions(-) diff --git a/developers-italia.oas.yaml b/developers-italia.oas.yaml index 3c1ab46..b8ced06 100644 --- a/developers-italia.oas.yaml +++ b/developers-italia.oas.yaml @@ -31,8 +31,6 @@ servers: tags: - name: software description: Operations on software - - name: bundles - description: Operations on bundles - name: logs description: Operations on logs - name: publishers @@ -576,144 +574,6 @@ paths: $ref: '#/components/callbacks/ResourceUpdate' delete: $ref: '#/components/callbacks/ResourceDelete' - /bundles: - get: - summary: List all Bundles - description: List all Bundles - tags: - - bundles - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - additionalProperties: false - properties: - data: - type: array - minItems: 0 - maxItems: 100 - items: - $ref: '#/components/schemas/Bundle' - links: - $ref: '#/components/schemas/Links' - '400': - $ref: '#/components/responses/BadRequest' - '429': - $ref: '#/components/responses/TooManyRequests' - operationId: list-bundles - post: - summary: Create a Bundle - description: Create a Bundle - tags: - - bundles - security: - - bearerAuth: [] - operationId: create-bundles - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/Bundle' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '404': - $ref: '#/components/responses/NotFound' - '422': - $ref: '#/components/responses/UnprocessableEntity' - '429': - $ref: '#/components/responses/TooManyRequests' - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/Bundle' - examples: {} - '/bundle/{bundleId}': - parameters: - - schema: - type: string - maxLength: 36 - pattern: '[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}' - name: bundleId - in: path - required: true - get: - summary: Get a Bundle - description: Get a Bundle by its id - tags: - - bundles - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/Bundle' - '400': - $ref: '#/components/responses/BadRequest' - '404': - $ref: '#/components/responses/NotFound' - '429': - $ref: '#/components/responses/TooManyRequests' - operationId: show-bundle-bundleId - patch: - summary: Update a Bundle - description: Update a Bundle by its id - tags: - - bundles - security: - - bearerAuth: [] - operationId: update-bundle-bundleId - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/Software' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '404': - $ref: '#/components/responses/NotFound' - '422': - $ref: '#/components/responses/UnprocessableEntity' - '429': - $ref: '#/components/responses/TooManyRequests' - requestBody: - required: true - content: - application/merge-patch+json: - schema: - $ref: '#/components/schemas/Bundle' - delete: - summary: Delete a Bundle - description: Delete a Bundle by its id - tags: - - bundles - security: - - bearerAuth: [] - operationId: remove-bundle-bundleId - responses: - '204': - $ref: '#/components/responses/NoContent' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '404': - $ref: '#/components/responses/NotFound' - '429': - $ref: '#/components/responses/TooManyRequests' /logs: get: summary: List all Logs @@ -1589,15 +1449,6 @@ components: - createdAt - updatedAt - message - Bundle: - title: Bundle - type: object - additionalProperties: false - properties: - id: - type: string - maxLength: 36 - pattern: '[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}' Links: type: object additionalProperties: false From 390c1c0b5cc336cb420d03fa5b2dd027f48d1a96 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 25 Nov 2022 15:25:47 +0100 Subject: [PATCH 16/54] chore(openapi): add staging server (#186) --- developers-italia.oas.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/developers-italia.oas.yaml b/developers-italia.oas.yaml index b8ced06..ddecee7 100644 --- a/developers-italia.oas.yaml +++ b/developers-italia.oas.yaml @@ -28,6 +28,8 @@ info: servers: - url: 'https://api.developers.italia.it/v1' description: The production server + - url: 'https://api-staging.developers.italia.it/v1' + description: The staging server tags: - name: software description: Operations on software From 42280bc587375367f439a1fef1921b6b3ab44528 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 25 Nov 2022 15:27:34 +0100 Subject: [PATCH 17/54] chore(ci): bump to actions/checkout@v3 (Node 16) (#187) --- .github/workflows/lint.yml | 2 +- .github/workflows/publish-staging-docker-image.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/spectral.yaml | 2 +- .github/workflows/tests.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 322e8a1..bf926c2 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,7 +8,7 @@ jobs: linters: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: go-version: 1.18.x diff --git a/.github/workflows/publish-staging-docker-image.yml b/.github/workflows/publish-staging-docker-image.yml index 7af659e..ee9cc0b 100644 --- a/.github/workflows/publish-staging-docker-image.yml +++ b/.github/workflows/publish-staging-docker-image.yml @@ -18,7 +18,7 @@ jobs: with: go-version: 1.18.x - - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: # All history, required for goreleaser fetch-depth: 0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a69a3df..0329fb0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: with: go-version: 1.18.x - - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: # All history, required for goreleaser fetch-depth: 0 diff --git a/.github/workflows/spectral.yaml b/.github/workflows/spectral.yaml index df4617e..1a1805c 100644 --- a/.github/workflows/spectral.yaml +++ b/.github/workflows/spectral.yaml @@ -11,7 +11,7 @@ jobs: spectral: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - run: curl https://italia.github.io/api-oas-checker/spectral-full.yml > .spectral.yml # Get additional module required by spectral-full diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cdcbc9c..e1a34f6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,7 +8,7 @@ jobs: tests: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: go-version: 1.18.x From 4841e71b3522bf3f0c0a9c983ff1c40d67d636de Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Tue, 29 Nov 2022 15:09:40 +0100 Subject: [PATCH 18/54] doc: update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c4e6be5..9faa553 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,6 @@ who already contributed to this repository: # License -Copyright © 2022 - Presidenza del Consiglio dei Ministri +Copyright © 2022-present Presidenza del Consiglio dei Ministri The source code is released under the AGPL version 3. From 200a942ad86988aea82e857884b35c775b5c7b24 Mon Sep 17 00:00:00 2001 From: Nicola Squartini Date: Mon, 6 Feb 2023 17:20:49 +0100 Subject: [PATCH 19/54] feat(chart): add option for mounting extra volumes This option is useful when using [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/). --- charts/developers-italia-api/Chart.yaml | 4 ++-- charts/developers-italia-api/README.md | 6 ++++-- charts/developers-italia-api/templates/deployment.yaml | 8 ++++++++ charts/developers-italia-api/values.yaml | 4 ++++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/charts/developers-italia-api/Chart.yaml b/charts/developers-italia-api/Chart.yaml index bd19d68..2e59a2a 100644 --- a/charts/developers-italia-api/Chart.yaml +++ b/charts/developers-italia-api/Chart.yaml @@ -15,12 +15,12 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: v0.2.2 +version: v0.3.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "v0.7.2" +appVersion: "v0.7.3" icon: https://avatars.githubusercontent.com/u/15377824?s=96&v=4 diff --git a/charts/developers-italia-api/README.md b/charts/developers-italia-api/README.md index 0af9797..10fdbf5 100644 --- a/charts/developers-italia-api/README.md +++ b/charts/developers-italia-api/README.md @@ -1,6 +1,6 @@ # developers-italia-api -![Version: v0.2.0](https://img.shields.io/badge/Version-v0.2.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.7.0](https://img.shields.io/badge/AppVersion-v0.7.0-informational?style=flat-square) +![Version: v0.2.2](https://img.shields.io/badge/Version-v0.2.2-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.7.2](https://img.shields.io/badge/AppVersion-v0.7.2-informational?style=flat-square) The API of Developers Italia @@ -15,6 +15,8 @@ The API of Developers Italia | autoscaling.targetCPUUtilizationPercentage | int | `80` | | | databaseDSN | string | `""` | Database connection string, e.g. "host= port=5432 dbname= user= password= sslmode=require". | | deploymentAnnotations | object | `{}` | | +| extraVolumeMounts | list | `[]` | | +| extraVolumes | list | `[]` | | | fullnameOverride | string | `""` | | | image.pullPolicy | string | `"IfNotPresent"` | | | image.repository | string | `"ghcr.io/italia/developers-italia-api"` | | @@ -51,4 +53,4 @@ The API of Developers Italia | useExistingSecret | string | `nil` | Name of existing Kubernetes secret containing keys 'databaseDSN' and 'pasetoKey'. If not provided, a secret will be generated using values from 'databaseDSN' and 'pasetoKey'. | ---------------------------------------------- -Autogenerated from chart metadata using [helm-docs vv1.11.0](https://github.com/norwoodj/helm-docs/releases/vv1.11.0) +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/charts/developers-italia-api/templates/deployment.yaml b/charts/developers-italia-api/templates/deployment.yaml index 8e51095..c6217f6 100644 --- a/charts/developers-italia-api/templates/deployment.yaml +++ b/charts/developers-italia-api/templates/deployment.yaml @@ -68,6 +68,10 @@ spec: port: http resources: {{- toYaml .Values.resources | nindent 12 }} + {{- if .Values.extraVolumeMounts }} + volumeMounts: + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} @@ -80,3 +84,7 @@ spec: tolerations: {{- toYaml . | nindent 8 }} {{- end }} + {{- if .Values.extraVolumes }} + volumes: + {{- toYaml .Values.extraVolumes | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/charts/developers-italia-api/values.yaml b/charts/developers-italia-api/values.yaml index 547646a..79ef8dd 100644 --- a/charts/developers-italia-api/values.yaml +++ b/charts/developers-italia-api/values.yaml @@ -112,3 +112,7 @@ serviceMonitor: # -- (string) Timeout after which the scrape is ended (uses Prometheus default if unspecified, details [here](https://prometheus-operator.dev/docs/operator/api/#monitoring.coreos.com/v1.Endpoint)). scrapeTimeout: targetLabels: [] + +extraVolumes: [] + +extraVolumeMounts: [] From 6e5c70609410291c5eb1e166bcc085575ed1e371 Mon Sep 17 00:00:00 2001 From: Nicola Squartini Date: Mon, 6 Feb 2023 18:28:58 +0100 Subject: [PATCH 20/54] docs(chart): update versions --- charts/developers-italia-api/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/developers-italia-api/README.md b/charts/developers-italia-api/README.md index 10fdbf5..52bfb95 100644 --- a/charts/developers-italia-api/README.md +++ b/charts/developers-italia-api/README.md @@ -1,6 +1,6 @@ # developers-italia-api -![Version: v0.2.2](https://img.shields.io/badge/Version-v0.2.2-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.7.2](https://img.shields.io/badge/AppVersion-v0.7.2-informational?style=flat-square) +![Version: v0.3.0](https://img.shields.io/badge/Version-v0.3.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.7.3](https://img.shields.io/badge/AppVersion-v0.7.3-informational?style=flat-square) The API of Developers Italia From 46a610a410623d08ca30f3dd390e19eaacdc8392 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Tue, 7 Feb 2023 20:27:54 +0100 Subject: [PATCH 21/54] fix(ci): disable musttag linter (#192) Fix #190. --- .golangci.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.golangci.yaml b/.golangci.yaml index 158610a..46deccf 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -79,6 +79,9 @@ linters: - exhaustruct # False positives (https://github.com/daixiang0/gci/issues/54) - gci + # https://github.com/italia/developers-italia-api/issues/190) + # Don't feel about chasing this one down + - musttag # Run only fast linters from enabled linters set (first run won't be fast) # Default: false From c683d4aea9d1ec9811dbca1578d1cdcbe3e577c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Feb 2023 09:55:48 +0000 Subject: [PATCH 22/54] chore(deps): bump golang.org/x/text from 0.3.7 to 0.3.8 Bumps [golang.org/x/text](https://github.com/golang/text) from 0.3.7 to 0.3.8. - [Release notes](https://github.com/golang/text/releases) - [Commits](https://github.com/golang/text/compare/v0.3.7...v0.3.8) --- updated-dependencies: - dependency-name: golang.org/x/text dependency-type: indirect ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 85c51cd..6e81870 100644 --- a/go.mod +++ b/go.mod @@ -70,6 +70,6 @@ require ( github.com/valyala/tcplisten v1.0.0 // indirect golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/text v0.3.8 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 0667323..b052c1a 100644 --- a/go.sum +++ b/go.sum @@ -553,8 +553,9 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From ddd5d1320a8cb2e34af708b94d006a7813164286 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Wed, 1 Mar 2023 19:56:58 +0100 Subject: [PATCH 23/54] doc: fix link in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9faa553..19ed8a5 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ # Development -The application uses [https://github.com/cosmtrek/air](Air) for live-reloading +The application uses [Air](https://github.com/cosmtrek/air) for live-reloading in the development environment. To start developing: From 44802d1e2a73834368e24055c802acc26514b085 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Mar 2023 09:27:41 +0100 Subject: [PATCH 24/54] chore(deps): bump golang.org/x/net (#194) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.0.0-20220722155237-a158d28d115b to 0.7.0. - [Release notes](https://github.com/golang/net/releases) - [Commits](https://github.com/golang/net/commits/v0.7.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 6e81870..1442a66 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect - golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect + golang.org/x/net v0.7.0 // indirect google.golang.org/protobuf v1.26.0 // indirect ) @@ -69,7 +69,7 @@ require ( github.com/valyala/fasthttp v1.38.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect - golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect - golang.org/x/text v0.3.8 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index b052c1a..87f2771 100644 --- a/go.sum +++ b/go.sum @@ -477,8 +477,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -541,8 +541,8 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -554,8 +554,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 3e10e82e634313c40ace10a2ff45d9dd29a5e5e7 Mon Sep 17 00:00:00 2001 From: Lorenzo Barretta <43916566+Bavuett@users.noreply.github.com> Date: Thu, 9 Mar 2023 14:45:45 +0100 Subject: [PATCH 25/54] feat: generate details to make Validation Errors clearer (#195) Fix #166. --- internal/common/errors.go | 4 +++- internal/common/validator.go | 30 ++++++++++++++++++++++++++++-- internal/handlers/logs.go | 6 +++--- internal/handlers/software.go | 4 ++-- internal/handlers/webhooks.go | 6 +++--- main_test.go | 34 +++++++++++++++++----------------- 6 files changed, 56 insertions(+), 28 deletions(-) diff --git a/internal/common/errors.go b/internal/common/errors.go index b624c26..94674dd 100644 --- a/internal/common/errors.go +++ b/internal/common/errors.go @@ -20,8 +20,10 @@ func Error(status int, title string, detail string) ProblemJSONError { } func ErrorWithValidationErrors( - status int, title string, detail string, validationErrors []ValidationError, + status int, title string, validationErrors []ValidationError, ) ProblemJSONError { + detail := GenerateErrorDetails(validationErrors) + return ProblemJSONError{Title: title, Detail: detail, Status: status, ValidationErrors: validationErrors} } diff --git a/internal/common/validator.go b/internal/common/validator.go index 8540ec3..5a03202 100644 --- a/internal/common/validator.go +++ b/internal/common/validator.go @@ -2,6 +2,7 @@ package common import ( "errors" + "fmt" "reflect" "strings" @@ -18,7 +19,7 @@ const ( type ValidationError struct { Field string `json:"field"` Rule string `json:"rule"` - Value string `json:"value,omitempty"` + Value string `json:"value"` } func ValidateStruct(validateStruct interface{}) []ValidationError { @@ -67,9 +68,34 @@ func ValidateRequestEntity(ctx *fiber.Ctx, request interface{}, errorMessage str if err := ValidateStruct(request); err != nil { return ErrorWithValidationErrors( - fiber.StatusUnprocessableEntity, errorMessage, "invalid format", err, + fiber.StatusUnprocessableEntity, errorMessage, err, ) } return nil } + +func GenerateErrorDetails(validationErrors []ValidationError) string { + var errors []string + + for _, validationError := range validationErrors { + switch validationError.Rule { + case "required": + errors = append(errors, fmt.Sprintf("%s is required", validationError.Field)) + case "email": + errors = append(errors, fmt.Sprintf("%s is not a valid email", validationError.Field)) + case "min": + errors = append(errors, fmt.Sprintf("%s does not meet its size limits (too short)", validationError.Field)) + case "max": + errors = append(errors, fmt.Sprintf("%s does not meet its size limits (too long)", validationError.Field)) + case "gt": + errors = append(errors, fmt.Sprintf("%s does not meet its size limits (too few items)", validationError.Field)) + default: + errors = append(errors, fmt.Sprintf("%s is invalid", validationError.Field)) + } + } + + errorDetails := fmt.Sprintf("invalid format: %s", strings.Join(errors, ", ")) + + return errorDetails +} diff --git a/internal/handlers/logs.go b/internal/handlers/logs.go index 6d4871b..7deefdf 100644 --- a/internal/handlers/logs.go +++ b/internal/handlers/logs.go @@ -91,7 +91,7 @@ func (p *Log) PostLog(ctx *fiber.Ctx) error { } if err := common.ValidateStruct(*logReq); err != nil { - return common.ErrorWithValidationErrors(fiber.StatusUnprocessableEntity, "can't create Log", "invalid format", err) + return common.ErrorWithValidationErrors(fiber.StatusUnprocessableEntity, "can't create Log", err) } log := models.Log{ID: utils.UUIDv4(), Message: logReq.Message} @@ -112,7 +112,7 @@ func (p *Log) PatchLog(ctx *fiber.Ctx) error { } if err := common.ValidateStruct(*logReq); err != nil { - return common.ErrorWithValidationErrors(fiber.StatusUnprocessableEntity, "can't update Log", "invalid format", err) + return common.ErrorWithValidationErrors(fiber.StatusUnprocessableEntity, "can't update Log", err) } log := models.Log{} @@ -218,7 +218,7 @@ func (p *Log) PostSoftwareLog(ctx *fiber.Ctx) error { } if err := common.ValidateStruct(*logReq); err != nil { - return common.ErrorWithValidationErrors(fiber.StatusUnprocessableEntity, "can't create Log", "invalid format", err) + return common.ErrorWithValidationErrors(fiber.StatusUnprocessableEntity, "can't create Log", err) } table := models.Software{}.TableName() diff --git a/internal/handlers/software.go b/internal/handlers/software.go index 84742d9..149b4b9 100644 --- a/internal/handlers/software.go +++ b/internal/handlers/software.go @@ -157,7 +157,7 @@ func (p *Software) PostSoftware(ctx *fiber.Ctx) error { if err := common.ValidateStruct(*softwareReq); err != nil { return common.ErrorWithValidationErrors( - fiber.StatusUnprocessableEntity, "can't create Software", "invalid format", err, + fiber.StatusUnprocessableEntity, "can't create Software", err, ) } @@ -208,7 +208,7 @@ func (p *Software) PatchSoftware(ctx *fiber.Ctx) error { //nolint:cyclop // most if err := common.ValidateStruct(*softwareReq); err != nil { return common.ErrorWithValidationErrors( - fiber.StatusUnprocessableEntity, "can't update Software", "invalid format", err, + fiber.StatusUnprocessableEntity, "can't update Software", err, ) } diff --git a/internal/handlers/webhooks.go b/internal/handlers/webhooks.go index 69ced44..146f24f 100644 --- a/internal/handlers/webhooks.go +++ b/internal/handlers/webhooks.go @@ -124,7 +124,7 @@ func (p *Webhook[T]) PostResourceWebhook(ctx *fiber.Ctx) error { if err := common.ValidateStruct(*webhookReq); err != nil { return common.ErrorWithValidationErrors( - fiber.StatusUnprocessableEntity, "can't create Webhook", "invalid format", err, + fiber.StatusUnprocessableEntity, "can't create Webhook", err, ) } @@ -168,7 +168,7 @@ func (p *Webhook[T]) PostSingleResourceWebhook(ctx *fiber.Ctx) error { if err := common.ValidateStruct(*webhookReq); err != nil { return common.ErrorWithValidationErrors( - fiber.StatusUnprocessableEntity, "can't create Webhook", "invalid format", err, + fiber.StatusUnprocessableEntity, "can't create Webhook", err, ) } @@ -197,7 +197,7 @@ func (p *Webhook[T]) PatchWebhook(ctx *fiber.Ctx) error { if err := common.ValidateStruct(*webhookReq); err != nil { return common.ErrorWithValidationErrors( - fiber.StatusUnprocessableEntity, "can't update Webhook", "invalid format", err, + fiber.StatusUnprocessableEntity, "can't update Webhook", err, ) } diff --git a/main_test.go b/main_test.go index 87d851a..f996a71 100644 --- a/main_test.go +++ b/main_test.go @@ -520,7 +520,7 @@ func TestPublishersEndpoints(t *testing.T) { }, expectedCode: 422, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't create Publisher","detail":"invalid format","status":422,"validationErrors":[{"field":"alternativeId","rule":"min"}]}`, + expectedBody: `{"title":"can't create Publisher","detail":"invalid format: alternativeId does not meet its size limits (too short)","status":422,"validationErrors":[{"field":"alternativeId","rule":"min","value":""}]}`, }, { query: "POST /v1/publishers - NOT normalized URL validation passed", @@ -616,7 +616,7 @@ func TestPublishersEndpoints(t *testing.T) { }, expectedCode: 422, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't create Publisher","detail":"invalid format","status":422,"validationErrors":[{"field":"email","rule":"email"}]}`, + expectedBody: `{"title":"can't create Publisher","detail":"invalid format: email is not a valid email","status":422,"validationErrors":[{"field":"email","rule":"email","value":""}]}`, }, { query: "POST /v1/publishers - Description already exist", @@ -639,7 +639,7 @@ func TestPublishersEndpoints(t *testing.T) { }, expectedCode: 422, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't create Publisher","detail":"invalid format","status":422,"validationErrors":[{"field":"description","rule":"required"}]}`, + expectedBody: `{"title":"can't create Publisher","detail":"invalid format: description is required","status":422,"validationErrors":[{"field":"description","rule":"required","value":""}]}`, }, { description: "POST new publisher with empty description", @@ -651,7 +651,7 @@ func TestPublishersEndpoints(t *testing.T) { }, expectedCode: 422, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't create Publisher","detail":"invalid format","status":422,"validationErrors":[{"field":"description","rule":"required"}]}`, + expectedBody: `{"title":"can't create Publisher","detail":"invalid format: description is required","status":422,"validationErrors":[{"field":"description","rule":"required","value":""}]}`, }, { description: "POST publisher with duplicate alternativeId", @@ -675,7 +675,7 @@ func TestPublishersEndpoints(t *testing.T) { }, expectedCode: 422, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't create Publisher","detail":"invalid format","status":422,"validationErrors":[{"field":"codeHosting","rule":"required"},{"field":"description","rule":"required"}]}`, + expectedBody: `{"title":"can't create Publisher","detail":"invalid format: codeHosting is required, description is required","status":422,"validationErrors":[{"field":"codeHosting","rule":"required","value":""},{"field":"description","rule":"required","value":""}]}`, }, { description: "POST publishers - wrong token", @@ -750,7 +750,7 @@ func TestPublishersEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Publisher`, response["title"]) - assert.Equal(t, "invalid format", response["detail"]) + assert.Equal(t, "invalid format: url is invalid, description is required, email is not a valid email", response["detail"]) assert.IsType(t, []interface{}{}, response["validationErrors"]) @@ -871,7 +871,7 @@ func TestPublishersEndpoints(t *testing.T) { expectedCode: 422, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't update Publisher","detail":"invalid format","status":422,"validationErrors":[{"field":"codeHosting","rule":"gt"}]}`, + expectedBody: `{"title":"can't update Publisher","detail":"invalid format: codeHosting does not meet its size limits (too few items)","status":422,"validationErrors":[{"field":"codeHosting","rule":"gt","value":""}]}`, }, { description: "PATCH a publisher via alternativeId", @@ -969,7 +969,7 @@ func TestPublishersEndpoints(t *testing.T) { }, expectedCode: 422, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't update Publisher","detail":"invalid format","status":422,"validationErrors":[{"field":"url","rule":"url","value":"INVALID_URL"}]}`, + expectedBody: `{"title":"can't update Publisher","detail":"invalid format: url is invalid","status":422,"validationErrors":[{"field":"url","rule":"url","value":"INVALID_URL"}]}`, }, { description: "PATCH publishers with empty body", @@ -1214,7 +1214,7 @@ func TestPublishersEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Webhook`, response["title"]) - assert.Equal(t, "invalid format", response["detail"]) + assert.Equal(t, "invalid format: url is invalid", response["detail"]) assert.IsType(t, []interface{}{}, response["validationErrors"]) @@ -1706,7 +1706,7 @@ func TestSoftwareEndpoints(t *testing.T) { }, expectedCode: 422, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't create Software","detail":"invalid format","status":422,"validationErrors":[{"field":"url","rule":"required"}]}`, + expectedBody: `{"title":"can't create Software","detail":"invalid format: url is required","status":422,"validationErrors":[{"field":"url","rule":"required","value":""}]}`, }, { description: "POST software - wrong token", @@ -1776,7 +1776,7 @@ func TestSoftwareEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Software`, response["title"]) - assert.Equal(t, "invalid format", response["detail"]) + assert.Equal(t, "invalid format: url is required", response["detail"]) assert.IsType(t, []interface{}{}, response["validationErrors"]) @@ -1990,7 +1990,7 @@ func TestSoftwareEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't update Software`, response["title"]) - assert.Equal(t, "invalid format", response["detail"]) + assert.Equal(t, "invalid format: url is invalid", response["detail"]) assert.IsType(t, []interface{}{}, response["validationErrors"]) @@ -2244,7 +2244,7 @@ func TestSoftwareEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Log`, response["title"]) - assert.Equal(t, "invalid format", response["detail"]) + assert.Equal(t, "invalid format: message is required", response["detail"]) assert.IsType(t, []interface{}{}, response["validationErrors"]) @@ -2457,7 +2457,7 @@ func TestSoftwareEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Webhook`, response["title"]) - assert.Equal(t, "invalid format", response["detail"]) + assert.Equal(t, "invalid format: url is invalid", response["detail"]) assert.IsType(t, []interface{}{}, response["validationErrors"]) @@ -2737,7 +2737,7 @@ func TestLogsEndpoints(t *testing.T) { }, expectedCode: 422, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't create Log","detail":"invalid format","status":422,"validationErrors":[{"field":"message","rule":"required"}]}`, + expectedBody: `{"title":"can't create Log","detail":"invalid format: message is required","status":422,"validationErrors":[{"field":"message","rule":"required","value":""}]}`, }, { description: "POST log - wrong token", @@ -2793,7 +2793,7 @@ func TestLogsEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Log`, response["title"]) - assert.Equal(t, "invalid format", response["detail"]) + assert.Equal(t, "invalid format: message is required", response["detail"]) assert.IsType(t, []interface{}{}, response["validationErrors"]) @@ -2931,7 +2931,7 @@ func TestWebhooksEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't update Webhook`, response["title"]) - assert.Equal(t, "invalid format", response["detail"]) + assert.Equal(t, "invalid format: url is invalid", response["detail"]) assert.IsType(t, []interface{}{}, response["validationErrors"]) From f5d486c887f0708b8c8feafe8891c4004527b561 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 24 Mar 2023 19:05:09 +0100 Subject: [PATCH 26/54] chore(ci): bump setup-go action to v4 (#196) v4 enables caching by default, and should result in lower build times. --- .github/workflows/lint.yml | 2 +- .github/workflows/publish-staging-docker-image.yml | 2 +- .github/workflows/release-chart.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/tests.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index bf926c2..158ff1f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + - uses: actions/setup-go@v4 with: go-version: 1.18.x - uses: golangci/golangci-lint-action@v3 diff --git a/.github/workflows/publish-staging-docker-image.yml b/.github/workflows/publish-staging-docker-image.yml index ee9cc0b..d8f1b18 100644 --- a/.github/workflows/publish-staging-docker-image.yml +++ b/.github/workflows/publish-staging-docker-image.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: 1.18.x - diff --git a/.github/workflows/release-chart.yml b/.github/workflows/release-chart.yml index 9cf8175..ae0304d 100644 --- a/.github/workflows/release-chart.yml +++ b/.github/workflows/release-chart.yml @@ -10,7 +10,7 @@ jobs: release_chart: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Get version id: get_version run: echo "::set-output name=version::${GITHUB_REF_NAME#helm/}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0329fb0..f7cc67c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: 1.18.x - diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e1a34f6..beaac74 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + - uses: actions/setup-go@v4 with: go-version: 1.18.x - run: go test -race ./... From 981b5e018b698d9faf44314472160fadac8a6d88 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 16 Jun 2023 13:57:02 +0200 Subject: [PATCH 27/54] chore(lint): skip tagalign linter --- .golangci.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.golangci.yaml b/.golangci.yaml index 46deccf..3f1cb0d 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -81,7 +81,9 @@ linters: - gci # https://github.com/italia/developers-italia-api/issues/190) # Don't feel about chasing this one down - - musttag + # - musttag + # Seems excessive + - tagalign # Run only fast linters from enabled linters set (first run won't be fast) # Default: false From 90acd5e2cc9f09d88a462107d0d7f660b2cf2392 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 16 Jun 2023 14:07:35 +0200 Subject: [PATCH 28/54] chore(lint): skip depguard linter --- .golangci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.golangci.yaml b/.golangci.yaml index 3f1cb0d..ff51675 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -75,6 +75,8 @@ linters: - maligned - scopelint + # We don't want to limit dependencies + - depguard # Not terribly useful and ends up in too much boilerplate - exhaustruct # False positives (https://github.com/daixiang0/gci/issues/54) From d51959a089d263ca11f38f688aa7ac5948ec56c1 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 16 Jun 2023 14:22:38 +0200 Subject: [PATCH 29/54] chore(lint): disable deprecated structcheck linter --- .golangci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.golangci.yaml b/.golangci.yaml index ff51675..48c76bf 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -74,6 +74,7 @@ linters: - interfacer - maligned - scopelint + - structcheck # We don't want to limit dependencies - depguard From 0e5490858f35b5751c4bb8498c07f50921c436ea Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 16 Jun 2023 13:07:06 +0200 Subject: [PATCH 30/54] chore: bump fiber to v2.46.0 --- go.mod | 24 ++++++++++++++++-------- go.sum | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 1442a66..186c458 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/go-playground/validator/v10 v10.11.0 github.com/go-testfixtures/testfixtures/v3 v3.8.0 github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e - github.com/gofiber/fiber/v2 v2.36.0 + github.com/gofiber/fiber/v2 v2.46.0 github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa github.com/stretchr/testify v1.7.5 gorm.io/driver/postgres v1.3.7 @@ -26,13 +26,21 @@ require ( github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/gofiber/adaptor/v2 v2.1.25 // indirect github.com/golang/protobuf v1.5.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.18 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect github.com/mattn/go-sqlite3 v1.14.16 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/philhofer/fwd v1.1.2 // indirect github.com/prometheus/client_golang v1.12.2 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect - golang.org/x/net v0.7.0 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect + github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect + github.com/tinylib/msgp v1.1.8 // indirect + golang.org/x/net v0.8.0 // indirect google.golang.org/protobuf v1.26.0 // indirect ) @@ -47,7 +55,7 @@ require ( ) require ( - github.com/andybalholm/brotli v1.0.4 // indirect + github.com/andybalholm/brotli v1.0.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect @@ -61,15 +69,15 @@ require ( github.com/jackc/pgx/v4 v4.16.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - github.com/klauspost/compress v1.15.7 // indirect + github.com/klauspost/compress v1.16.3 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.38.0 // indirect + github.com/valyala/fasthttp v1.47.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect - golang.org/x/sys v0.5.0 // indirect - golang.org/x/text v0.7.0 // indirect + golang.org/x/crypto v0.7.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.8.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 87f2771..682e1bb 100644 --- a/go.sum +++ b/go.sum @@ -51,6 +51,8 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/ansrivas/fiberprometheus/v2 v2.4.1 h1:V87ahTcU/I4c8tD6GKiuyyB0Z82dw2VVqLDgBtUcUgc= github.com/ansrivas/fiberprometheus/v2 v2.4.1/go.mod h1:ATJ3l0sufyoZBz+TEohAyQJqbgUSQaPwCHNL/L67Wnw= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -110,6 +112,8 @@ github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e/go.mod h1:z github.com/gofiber/fiber/v2 v2.34.1/go.mod h1:ozRQfS+D7EL1+hMH+gutku0kfx1wLX4hAxDCtDzpj4U= github.com/gofiber/fiber/v2 v2.36.0 h1:1qLMe5rhXFLPa2SjK10Wz7WFgLwYi4TYg7XrjztJHqA= github.com/gofiber/fiber/v2 v2.36.0/go.mod h1:tgCr+lierLwLoVHHO/jn3Niannv34WRkQETU8wiL9fQ= +github.com/gofiber/fiber/v2 v2.46.0 h1:wkkWotblsGVlLjXj2dpgKQAYHtXumsK/HyFugQM68Ns= +github.com/gofiber/fiber/v2 v2.46.0/go.mod h1:DNl0/c37WLe0g92U6lx1VMQuxGUQY5V7EIaVoEsUffc= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -261,6 +265,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.7 h1:7cgTQxJCU/vy+oP/E3B9RGbQTgbiVzIJWIKOLoAsPok= github.com/klauspost/compress v1.15.7/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= +github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -285,11 +291,18 @@ github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +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.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 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-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= +github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= @@ -305,6 +318,9 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/o1egl/paseto v1.0.0 h1:bwpvPu2au176w4IBlhbyUv/S5VPptERIA99Oap5qUd0= github.com/o1egl/paseto v1.0.0/go.mod h1:5HxsZPmw/3RI2pAwGo1HhOOwSdvBpcuVzO7uDkm+CLU= +github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= +github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= +github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/pilagod/gorm-cursor-paginator/v2 v2.3.0 h1:/jMv0+CtmpF5gf8Fn0JwgFsKcVrmvhPahHluHEcP13I= github.com/pilagod/gorm-cursor-paginator/v2 v2.3.0/go.mod h1:N2MKvSTVk9fHC/ofXDRSbHY9WZAe23g4UzBLorR54cE= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -336,6 +352,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 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.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= @@ -345,6 +363,11 @@ github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4= +github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8= +github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4= +github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= +github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= @@ -366,16 +389,23 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q= github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw= +github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= +github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.37.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= github.com/valyala/fasthttp v1.38.0 h1:yTjSSNjuDi2PPvXY2836bIwLmiTS2T4T9p1coQshpco= github.com/valyala/fasthttp v1.38.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= +github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c= +github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -412,6 +442,8 @@ golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -444,6 +476,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/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.7.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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -473,12 +507,17 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -493,7 +532,10 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -532,6 +574,7 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -541,11 +584,19 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/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.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -554,8 +605,11 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -604,6 +658,9 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 45af1bee42e4e2b2f916f9c12f3fa92ba716d61c Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 16 Jun 2023 13:07:20 +0200 Subject: [PATCH 31/54] refactor: use Fiber's new route constraints https://docs.gofiber.io/guide/routing/#constraints --- main.go | 12 ++++++------ main_test.go | 5 ++++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/main.go b/main.go index 956fcb6..34b1a43 100644 --- a/main.go +++ b/main.go @@ -133,16 +133,16 @@ func setupHandlers(app *fiber.App, gormDB *gorm.DB) { v1.Delete("/software/:id", softwareHandler.DeleteSoftware) v1.Get("/logs", logHandler.GetLogs) - v1.Get("/logs/:id", logHandler.GetLog) + v1.Get("/logs/:id", logHandler.GetLog) v1.Post("/logs", logHandler.PostLog) - v1.Patch("/logs/:id", logHandler.PatchLog) - v1.Delete("/logs/:id", logHandler.DeleteLog) + v1.Patch("/logs/:id", logHandler.PatchLog) + v1.Delete("/logs/:id", logHandler.DeleteLog) v1.Get("/software/:id/logs", logHandler.GetSoftwareLogs) v1.Post("/software/:id/logs", logHandler.PostSoftwareLog) v1.Get("/status", statusHandler.GetStatus) - v1.Get("/webhooks/:id", publisherWebhookHandler.GetWebhook) - v1.Patch("/webhooks/:id", publisherWebhookHandler.PatchWebhook) - v1.Delete("/webhooks/:id", publisherWebhookHandler.DeleteWebhook) + v1.Get("/webhooks/:id", publisherWebhookHandler.GetWebhook) + v1.Patch("/webhooks/:id", publisherWebhookHandler.PatchWebhook) + v1.Delete("/webhooks/:id", publisherWebhookHandler.DeleteWebhook) } diff --git a/main_test.go b/main_test.go index f996a71..ba3d2ea 100644 --- a/main_test.go +++ b/main_test.go @@ -2979,7 +2979,10 @@ func TestWebhooksEndpoints(t *testing.T) { "Content-Type": {"application/json"}, }, expectedCode: 404, - expectedBody: `{"title":"can't delete Webhook","detail":"Webhook was not found","status":404}`, + // This error is different from because it's returned directly from Fiber's + // route constraints, so we don't need to hit the database to find the resource + // because we already know that's not a valid webhook id looking at its format. + expectedBody: `{"title":"Not Found","detail":"Cannot DELETE /v1/webhooks/NO_SUCH_WEBHOOK","status":404}`, expectedContentType: "application/problem+json", }, { From 9ae30c54861de465dc72fd25bdffc24fac72ba2f Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 16 Jun 2023 13:15:43 +0200 Subject: [PATCH 32/54] refactor: use Fiber's new method config for middleware/cache --- main.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 34b1a43..9fdc41b 100644 --- a/main.go +++ b/main.go @@ -74,9 +74,10 @@ func Setup() *fiber.App { app.Use(cache.New(cache.Config{ Next: func(ctx *fiber.Ctx) bool { - // Don't cache POST, PUT, PATCH or /status - return ctx.Method() != fiber.MethodGet || ctx.Route().Path == "/v1/status" + // Don't cache /status + return ctx.Route().Path == "/v1/status" }, + Methods: []string{fiber.MethodGet, fiber.MethodHead}, CacheControl: true, Expiration: 10 * time.Second, //nolint:gomnd KeyGenerator: func(ctx *fiber.Ctx) string { From 5d67ae6523d9702aeade68cc2e63ecd58d07766a Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 16 Jun 2023 13:42:07 +0200 Subject: [PATCH 33/54] refactor: use Fiber's new query parameter helpers --- internal/handlers/general/pagination.go | 12 ++++-------- internal/handlers/publishers.go | 2 +- internal/handlers/software.go | 2 +- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/internal/handlers/general/pagination.go b/internal/handlers/general/pagination.go index 38cb988..b2a48d2 100644 --- a/internal/handlers/general/pagination.go +++ b/internal/handlers/general/pagination.go @@ -3,7 +3,6 @@ package general import ( "encoding/json" "fmt" - "strconv" "github.com/gofiber/fiber/v2" "github.com/pilagod/gorm-cursor-paginator/v2/paginator" @@ -48,13 +47,10 @@ func NewPaginatorWithConfig(ctx *fiber.Ctx, config *paginator.Config) *paginator paginator.SetBeforeCursor(before) } - if size := ctx.Query("page[size]"); size != "" { - //nolint:godox // need to implement this in the future - // TODO: make the API return the error if limit is not an integer - if limit, err := strconv.Atoi(size); err == nil { - paginator.SetLimit(limit) - } - } + //nolint:godox // need to implement this in the future + // TODO: make the API return the error if limit is not an integer + size := ctx.QueryInt("page[size]", DefaultLimitCount) + paginator.SetLimit(size) return paginator } diff --git a/internal/handlers/publishers.go b/internal/handlers/publishers.go index 34dc0bf..08268a5 100644 --- a/internal/handlers/publishers.go +++ b/internal/handlers/publishers.go @@ -44,7 +44,7 @@ func (p *Publisher) GetPublishers(ctx *fiber.Ctx) error { stmt := p.db.Preload("CodeHosting") - if all := ctx.Query("all", ""); all == "" { + if all := ctx.QueryBool("all", false); !all { stmt = stmt.Scopes(models.Active) } diff --git a/internal/handlers/software.go b/internal/handlers/software.go index 149b4b9..c3eb58f 100644 --- a/internal/handlers/software.go +++ b/internal/handlers/software.go @@ -63,7 +63,7 @@ func (p *Software) GetAllSoftware(ctx *fiber.Ctx) error { //nolint:cyclop // mos stmt.Where("id = ?", softwareURL.SoftwareID) } else { - if all := ctx.Query("all", ""); all == "" { + if all := ctx.QueryBool("all", false); !all { stmt = stmt.Scopes(models.Active) } } From b6b7d58befb28e1b8fa3e345b7705e53f92d6105 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 16 Jun 2023 15:22:38 +0200 Subject: [PATCH 34/54] chore(lint): re-enable musttag linter (#204) Re-enable the musttag linter, the issue was fixed upstream. --- .golangci.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 48c76bf..39ebaa0 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -82,9 +82,6 @@ linters: - exhaustruct # False positives (https://github.com/daixiang0/gci/issues/54) - gci - # https://github.com/italia/developers-italia-api/issues/190) - # Don't feel about chasing this one down - # - musttag # Seems excessive - tagalign From fa37c160571bc1a6b37491a26ec71fe4e187da3d Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Sat, 17 Jun 2023 23:40:32 +0200 Subject: [PATCH 35/54] test: fix wrong date format in fixture (#206) --- main_test.go | 2 +- test/testdata/fixtures/webhooks.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/main_test.go b/main_test.go index ba3d2ea..56a03d0 100644 --- a/main_test.go +++ b/main_test.go @@ -2354,7 +2354,7 @@ func TestSoftwareEndpoints(t *testing.T) { links := response["links"].(map[string]interface{}) assert.Nil(t, links["prev"]) - assert.Equal(t, "?page[after]=WyIwMDAxLTAxLTAxVDAwOjAwOjAwWiIsImU3ZjZkYmRhLWMzZjUtNGIyZi1iM2Q4LTM5YTM0MDI2ZTYwYSJd", links["next"]) + assert.Equal(t, "?page[after]=WyIyMDE3LTA1LTAxVDAwOjAwOjAwWiIsImU3ZjZkYmRhLWMzZjUtNGIyZi1iM2Q4LTM5YTM0MDI2ZTYwYSJd", links["next"]) }, }, diff --git a/test/testdata/fixtures/webhooks.yml b/test/testdata/fixtures/webhooks.yml index 2a2a6ab..8b0eab5 100644 --- a/test/testdata/fixtures/webhooks.yml +++ b/test/testdata/fixtures/webhooks.yml @@ -12,8 +12,8 @@ entity_type: software secret: url: https://3-a.example.org/receiver - created_at: '2017-05-01t00:00:00+00:00' - updated_at: '2017-05-01t00:00:00+00:00' + created_at: '2017-05-01T00:00:00+00:00' + updated_at: '2017-05-01T00:00:00+00:00' - id: d6334000-69a8-43a1-ab43-50bb04e14eed entity_id: 9f135268-a37e-4ead-96ec-e4a24bb9344a entity_type: software From 60d2758b069f98661c3f10117c9e1593b54d05af Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Sun, 18 Jun 2023 00:13:24 +0200 Subject: [PATCH 36/54] refactor: remove the custom ErrDBUniqueConstraint error (#197) Remove common.ErrDBUniqueConstraint, which was used as a workaround for the lack of abstraction in gorm. With the update in https://github.com/go-gorm/gorm/pull/6004 we can now fully use gorm for db related errors (fe. gorm.ErrDuplicatedKey). --- go.mod | 43 ++++++------ go.sum | 94 +++++++------------------- internal/common/errors.go | 3 - internal/database/database.go | 28 -------- internal/database/postgres_database.go | 3 +- internal/database/sqlite_database.go | 2 +- internal/handlers/publishers.go | 7 +- internal/models/models_test.go | 14 ++-- 8 files changed, 58 insertions(+), 136 deletions(-) diff --git a/go.mod b/go.mod index 186c458..42c82cd 100644 --- a/go.mod +++ b/go.mod @@ -9,11 +9,10 @@ require ( github.com/go-testfixtures/testfixtures/v3 v3.8.0 github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e github.com/gofiber/fiber/v2 v2.46.0 - github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa - github.com/stretchr/testify v1.7.5 - gorm.io/driver/postgres v1.3.7 - gorm.io/driver/sqlite v1.4.3 - gorm.io/gorm v1.24.1 + github.com/stretchr/testify v1.8.1 + gorm.io/driver/postgres v1.5.2 + gorm.io/driver/sqlite v1.5.2 + gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55 ) require ( @@ -26,21 +25,14 @@ require ( github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/gofiber/adaptor/v2 v2.1.25 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.18 // indirect - github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/mattn/go-sqlite3 v1.14.16 // indirect + github.com/jackc/pgx/v5 v5.3.1 // indirect + github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/philhofer/fwd v1.1.2 // indirect github.com/prometheus/client_golang v1.12.2 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect - github.com/rivo/uniseg v0.2.0 // indirect - github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect - github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect - github.com/tinylib/msgp v1.1.8 // indirect - golang.org/x/net v0.8.0 // indirect + golang.org/x/net v0.9.0 // indirect google.golang.org/protobuf v1.26.0 // indirect ) @@ -59,25 +51,28 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.12.1 - github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.11.0 // indirect - github.com/jackc/pgx/v4 v4.16.1 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/klauspost/compress v1.16.3 // indirect github.com/leodido/go-urn v1.2.1 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.18 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/philhofer/fwd v1.1.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect + github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect + github.com/tinylib/msgp v1.1.8 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.47.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - golang.org/x/crypto v0.7.0 // indirect + golang.org/x/crypto v0.8.0 // indirect golang.org/x/sys v0.8.0 // indirect - golang.org/x/text v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 682e1bb..3979cbe 100644 --- a/go.sum +++ b/go.sum @@ -33,8 +33,6 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/PuerkitoBio/purell v1.2.0 h1:/Jdm5QfyM8zdlqT6WVZU4cfP23sot6CEHA4CS49Ezig= github.com/PuerkitoBio/purell v1.2.0/go.mod h1:OhLRTaaIzhvIyofkJfB24gokC7tM42Px5UhoT32THBk= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= @@ -49,7 +47,6 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= @@ -70,7 +67,6 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -110,13 +106,10 @@ github.com/gofiber/adaptor/v2 v2.1.25/go.mod h1:gOxtwMVqUStB5goAYtKd+hSvGupdd+aR github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e h1:ZsZeaEFExhECRgT/yYWxmOtbKjPbZxhe9pk1MSz1rOE= github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e/go.mod h1:zU7RONlVB7dBKM0EijoExlxAWJtevT5+9RqAH2imOUI= github.com/gofiber/fiber/v2 v2.34.1/go.mod h1:ozRQfS+D7EL1+hMH+gutku0kfx1wLX4hAxDCtDzpj4U= -github.com/gofiber/fiber/v2 v2.36.0 h1:1qLMe5rhXFLPa2SjK10Wz7WFgLwYi4TYg7XrjztJHqA= github.com/gofiber/fiber/v2 v2.36.0/go.mod h1:tgCr+lierLwLoVHHO/jn3Niannv34WRkQETU8wiL9fQ= github.com/gofiber/fiber/v2 v2.46.0 h1:wkkWotblsGVlLjXj2dpgKQAYHtXumsK/HyFugQM68Ns= github.com/gofiber/fiber/v2 v2.46.0/go.mod h1:DNl0/c37WLe0g92U6lx1VMQuxGUQY5V7EIaVoEsUffc= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= @@ -180,6 +173,7 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7 h1:ux/56T2xqZO/3cP1I2F86qpeoYPCOzk+KF/UH/Ar+lk= github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= @@ -191,20 +185,13 @@ github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5 github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgconn v1.12.1 h1:rsDFzIpRk7xT4B8FufgpCCeyjdNpKyghZeSefViE5W8= -github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= -github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa h1:s+4MhCQ6YrzisK6hFJUX53drDT4UsSW3DEhKn0ifuHw= -github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= 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/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= @@ -212,12 +199,11 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.3.0 h1:brH0pCGBDkBW07HWlN/oSBXrmo3WB0UvZd1pIuDcL8Y= -github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +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/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= @@ -225,9 +211,7 @@ github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4 github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= github.com/jackc/pgtype v1.6.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= -github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= github.com/jackc/pgtype v1.11.0 h1:u4uiGPz/1hryuXzyaBhSk6dnIyyG2683olG2OV+UUgs= -github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= @@ -235,20 +219,18 @@ github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXg github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= github.com/jackc/pgx/v4 v4.10.1/go.mod h1:QlrWebbs3kqEZPHCTGyxecvzG6tvIsYu+A5b1raylkA= -github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= github.com/jackc/pgx/v4 v4.16.1 h1:JzTglcal01DrghUqt+PmzWsZx/Yh7SC/CTQmSBMTd0Y= -github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ= +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/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 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.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 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.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= @@ -263,8 +245,6 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.7 h1:7cgTQxJCU/vy+oP/E3B9RGbQTgbiVzIJWIKOLoAsPok= -github.com/klauspost/compress v1.15.7/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -286,8 +266,8 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -304,9 +284,8 @@ github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= -github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -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/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= +github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -370,8 +349,6 @@ github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1Avp github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -380,6 +357,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 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= @@ -387,15 +365,15 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 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.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q= -github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw= github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.37.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= -github.com/valyala/fasthttp v1.38.0 h1:yTjSSNjuDi2PPvXY2836bIwLmiTS2T4T9p1coQshpco= github.com/valyala/fasthttp v1.38.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c= github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= @@ -414,15 +392,12 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -434,16 +409,11 @@ golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -514,10 +484,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -554,7 +522,6 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -588,12 +555,9 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc 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.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= @@ -602,14 +566,11 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -639,7 +600,6 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -762,18 +722,16 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/postgres v1.0.8/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg= -gorm.io/driver/postgres v1.3.7 h1:FKF6sIMDHDEvvMF/XJvbnCl0nu6KSKUaPXevJ4r+VYQ= -gorm.io/driver/postgres v1.3.7/go.mod h1:f02ympjIcgtHEGFMZvdgTxODZ9snAHDb4hXfigBVuNI= +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.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw= -gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU= -gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= +gorm.io/driver/sqlite v1.5.2 h1:TpQ+/dqCY4uCigCFyrfnrJnrW9zjpelWVoEVNy5qJkc= +gorm.io/driver/sqlite v1.5.2/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed+4= gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.21.7/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= -gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= -gorm.io/gorm v1.24.1 h1:CgvzRniUdG67hBAzsxDGOAuq4Te1osVMYsa1eQbd4fs= -gorm.io/gorm v1.24.1/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55 h1:sC1Xj4TYrLqg1n3AN10w871An7wJM0gzgcm8jkIkECQ= +gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/common/errors.go b/internal/common/errors.go index 94674dd..1daa375 100644 --- a/internal/common/errors.go +++ b/internal/common/errors.go @@ -10,9 +10,6 @@ var ( ErrAuthentication = errors.New("token authentication failed") ErrInvalidDateTime = errors.New("invalid date time format (RFC 3339 needed)") ErrKeyLen = errors.New("PASETO_KEY must be 32 bytes long once base64-decoded") - - ErrDBUniqueConstraint = errors.New("db constraint violation") - ErrDBRecordNotFound = errors.New("record not found") ) func Error(status int, title string, detail string) ProblemJSONError { diff --git a/internal/database/database.go b/internal/database/database.go index 2a694fb..55875f9 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -1,21 +1,12 @@ package database import ( - "errors" "log" - "strings" - - "github.com/jackc/pgconn" "github.com/italia/developers-italia-api/internal/common" - "github.com/jackc/pgerrcode" "gorm.io/gorm" ) -const ( - uniqueConstraintFailedErrorSQLite = "UNIQUE constraint failed" -) - type Database interface { Init(dsn string) (*gorm.DB, error) } @@ -36,22 +27,3 @@ func NewDatabase(env common.Environment) Database { dsn: env.Database, } } - -//nolint:errorlint -func WrapErrors(dbError error) error { - if strings.Contains(dbError.Error(), uniqueConstraintFailedErrorSQLite) { - return common.ErrDBUniqueConstraint - } - - if e, ok := dbError.(*pgconn.PgError); ok { - if e.Code == pgerrcode.UniqueViolation { - return common.ErrDBUniqueConstraint - } - } - - if errors.Is(dbError, gorm.ErrRecordNotFound) { - return common.ErrDBRecordNotFound - } - - return dbError -} diff --git a/internal/database/postgres_database.go b/internal/database/postgres_database.go index ae0381b..bdbb144 100644 --- a/internal/database/postgres_database.go +++ b/internal/database/postgres_database.go @@ -17,7 +17,8 @@ func (d *PostgresDB) Init(dsn string) (*gorm.DB, error) { var err error database, err := gorm.Open(postgres.Open(dsn), &gorm.Config{ - PrepareStmt: true, + TranslateError: true, + PrepareStmt: true, // Disable logging in production Logger: logger.Default.LogMode(logger.Silent), }) diff --git a/internal/database/sqlite_database.go b/internal/database/sqlite_database.go index 5276101..069bf5e 100644 --- a/internal/database/sqlite_database.go +++ b/internal/database/sqlite_database.go @@ -15,7 +15,7 @@ type SQLiteDB struct { func (d *SQLiteDB) Init(dsn string) (*gorm.DB, error) { var err error - database, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{}) + database, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{TranslateError: true}) if err != nil { return nil, fmt.Errorf("can't open database: %w", err) } diff --git a/internal/handlers/publishers.go b/internal/handlers/publishers.go index 08268a5..86705db 100644 --- a/internal/handlers/publishers.go +++ b/internal/handlers/publishers.go @@ -6,7 +6,6 @@ import ( "net/url" "sort" - "github.com/italia/developers-italia-api/internal/database" "golang.org/x/exp/slices" "github.com/italia/developers-italia-api/internal/handlers/general" @@ -135,12 +134,12 @@ func (p *Publisher) PostPublisher(ctx *fiber.Ctx) error { } if err := p.db.Create(&publisher).Error; err != nil { - switch database.WrapErrors(err) { //nolint:errorlint - case common.ErrDBRecordNotFound: + switch { + case errors.Is(err, gorm.ErrRecordNotFound): return common.Error(fiber.StatusNotFound, "can't create Publisher", "Publisher was not found") - case common.ErrDBUniqueConstraint: + case errors.Is(err, gorm.ErrDuplicatedKey): return common.Error(fiber.StatusConflict, "can't create Publisher", "description, alternativeId or codeHosting URL already exists") diff --git a/internal/models/models_test.go b/internal/models/models_test.go index 9359288..2b91b2b 100644 --- a/internal/models/models_test.go +++ b/internal/models/models_test.go @@ -37,7 +37,7 @@ func init() { // TODO: investigate the root cause sqlitedb.Exec("PRAGMA journal_mode=WAL;") - db, err = gorm.Open(sqlite.Open(dsn), &gorm.Config{}) + db, err = gorm.Open(sqlite.Open(dsn), &gorm.Config{TranslateError: true}) if err != nil { log.Fatal(err) } @@ -93,7 +93,7 @@ func TestSoftwareCreate(t *testing.T) { PubliccodeYml: "-", }, ).Error - assert.EqualError(t, err, "UNIQUE constraint failed: software.software_url_id") + assert.ErrorIs(t, err, gorm.ErrDuplicatedKey) } func TestSoftwareURLCreate(t *testing.T) { @@ -117,7 +117,7 @@ func TestSoftwareURLCreate(t *testing.T) { URL: "https://new-2.example.org", }, ).Error - assert.EqualError(t, err, "UNIQUE constraint failed: software_urls.id") + assert.ErrorIs(t, err, gorm.ErrDuplicatedKey) } func TestPublisherCreate(t *testing.T) { @@ -144,7 +144,7 @@ func TestPublisherCreate(t *testing.T) { Email: &email, }, ).Error - assert.EqualError(t, err, "UNIQUE constraint failed: publishers.description") + assert.ErrorIs(t, err, gorm.ErrDuplicatedKey) // Duplicate alternativeId alternativeID := "alternative-id-12345" @@ -155,7 +155,7 @@ func TestPublisherCreate(t *testing.T) { AlternativeID: &alternativeID, }, ).Error - assert.EqualError(t, err, "UNIQUE constraint failed: publishers.alternative_id") + assert.ErrorIs(t, err, gorm.ErrDuplicatedKey) } func TestWebhookCreate(t *testing.T) { @@ -181,7 +181,7 @@ func TestWebhookCreate(t *testing.T) { URL: "https://new-webhook-2.example.org", }, ).Error - assert.EqualError(t, err, "UNIQUE constraint failed: webhooks.id") + assert.ErrorIs(t, err, gorm.ErrDuplicatedKey) } func TestEventCreate(t *testing.T) { @@ -207,5 +207,5 @@ func TestEventCreate(t *testing.T) { EntityType: "software", }, ).Error - assert.EqualError(t, err, "UNIQUE constraint failed: events.id") + assert.ErrorIs(t, err, gorm.ErrDuplicatedKey) } From a073df95adb19027d2c6c7d8ff5cec8187a890ed Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Sat, 17 Jun 2023 11:26:20 +0200 Subject: [PATCH 37/54] chore: bump gorm postgres driver to 1.5.2 --- go.mod | 20 ++++++++++---------- go.sum | 1 - 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 42c82cd..ec26041 100644 --- a/go.mod +++ b/go.mod @@ -25,13 +25,21 @@ require ( github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/gofiber/adaptor/v2 v2.1.25 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/jackc/pgx/v5 v5.3.1 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.18 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/philhofer/fwd v1.1.2 // indirect github.com/prometheus/client_golang v1.12.2 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect + github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect + github.com/tinylib/msgp v1.1.8 // indirect golang.org/x/net v0.9.0 // indirect google.golang.org/protobuf v1.26.0 // indirect ) @@ -53,21 +61,13 @@ require ( github.com/go-playground/universal-translator v0.18.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/pgx/v5 v5.3.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/klauspost/compress v1.16.3 // indirect github.com/leodido/go-urn v1.2.1 // indirect - github.com/lib/pq v1.10.9 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.18 // indirect - github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/philhofer/fwd v1.1.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rivo/uniseg v0.2.0 // indirect - github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect - github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect - github.com/tinylib/msgp v1.1.8 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.47.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect diff --git a/go.sum b/go.sum index 3979cbe..64c17c3 100644 --- a/go.sum +++ b/go.sum @@ -191,7 +191,6 @@ github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bY github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= 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/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= From d4f4a12f119b6295a5d4b4ceda29cedf1e516fe3 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 16 Jun 2023 17:22:44 +0200 Subject: [PATCH 38/54] refactor: run tests with PostgreSQL as well Fix #198. --- .github/workflows/tests-postgresql.yml | 32 ++++++++++++ .../workflows/{tests.yml => tests-sqlite.yml} | 4 +- go.mod | 4 +- internal/database/database.go | 52 ++++++++++++++----- internal/database/postgres_database.go | 42 --------------- internal/database/sqlite_database.go | 36 ------------- main.go | 4 +- main_test.go | 27 ++++++++-- 8 files changed, 99 insertions(+), 102 deletions(-) create mode 100644 .github/workflows/tests-postgresql.yml rename .github/workflows/{tests.yml => tests-sqlite.yml} (78%) delete mode 100644 internal/database/postgres_database.go delete mode 100644 internal/database/sqlite_database.go diff --git a/.github/workflows/tests-postgresql.yml b/.github/workflows/tests-postgresql.yml new file mode 100644 index 0000000..41500a7 --- /dev/null +++ b/.github/workflows/tests-postgresql.yml @@ -0,0 +1,32 @@ +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + tests-postgresql: + runs-on: ubuntu-latest + + services: + db: + image: postgres:14 + env: + POSTGRES_PASSWORD: postgres + POSTGRES_DB: test + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v4 + with: + go-version: 1.18.x + - run: go test -race ./... + env: + DATABASE_DSN: "postgres://postgres:postgres@localhost:5432/test?sslmode=disable" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests-sqlite.yml similarity index 78% rename from .github/workflows/tests.yml rename to .github/workflows/tests-sqlite.yml index beaac74..7ecf571 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests-sqlite.yml @@ -5,7 +5,7 @@ on: branches: [main] jobs: - tests: + tests-sqlite: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -13,3 +13,5 @@ jobs: with: go-version: 1.18.x - run: go test -race ./... + env: + DATABASE_DSN: "file:/tmp/test.db" diff --git a/go.mod b/go.mod index ec26041..0864923 100644 --- a/go.mod +++ b/go.mod @@ -25,11 +25,11 @@ require ( github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/gofiber/adaptor/v2 v2.1.25 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/lib/pq v1.10.9 // indirect + github.com/lib/pq v1.10.9 github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.18 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/mattn/go-sqlite3 v1.14.17 // indirect + github.com/mattn/go-sqlite3 v1.14.17 github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/philhofer/fwd v1.1.2 // indirect github.com/prometheus/client_golang v1.12.2 // indirect diff --git a/internal/database/database.go b/internal/database/database.go index 55875f9..5c7d79e 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -1,29 +1,55 @@ package database import ( + "fmt" "log" + "strings" - "github.com/italia/developers-italia-api/internal/common" + "github.com/italia/developers-italia-api/internal/models" + + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" "gorm.io/gorm" + "gorm.io/gorm/logger" ) -type Database interface { - Init(dsn string) (*gorm.DB, error) -} +func NewDatabase(connection string) (*gorm.DB, error) { + var ( + database *gorm.DB + err error + ) -//nolintlint:ireturn -func NewDatabase(env common.Environment) Database { - if env.IsTest() { + switch { + case strings.HasPrefix(connection, "file:"): log.Println("using SQLite database") - return &SQLiteDB{ - dsn: env.Database, - } + database, err = gorm.Open(sqlite.Open(connection), &gorm.Config{TranslateError: true}) + case strings.HasPrefix(connection, "postgres:"): + log.Println("using Postgres database") + + database, err = gorm.Open(postgres.Open(connection), &gorm.Config{ + TranslateError: true, + PrepareStmt: true, + // Disable logging in production + Logger: logger.Default.LogMode(logger.Silent), + }) } - log.Println("using Postgres database") + if err != nil { + return nil, fmt.Errorf("can't open database: %w", err) + } - return &PostgresDB{ - dsn: env.Database, + if err = database.AutoMigrate( + &models.Publisher{}, + &models.Event{}, + &models.CodeHosting{}, + &models.Log{}, + &models.Software{}, + &models.SoftwareURL{}, + &models.Webhook{}, + ); err != nil { + return nil, fmt.Errorf("can't migrate database: %w", err) } + + return database, nil } diff --git a/internal/database/postgres_database.go b/internal/database/postgres_database.go deleted file mode 100644 index bdbb144..0000000 --- a/internal/database/postgres_database.go +++ /dev/null @@ -1,42 +0,0 @@ -package database - -import ( - "fmt" - - "github.com/italia/developers-italia-api/internal/models" - "gorm.io/driver/postgres" - "gorm.io/gorm" - "gorm.io/gorm/logger" -) - -type PostgresDB struct { - dsn string -} - -func (d *PostgresDB) Init(dsn string) (*gorm.DB, error) { - var err error - - database, err := gorm.Open(postgres.Open(dsn), &gorm.Config{ - TranslateError: true, - PrepareStmt: true, - // Disable logging in production - Logger: logger.Default.LogMode(logger.Silent), - }) - if err != nil { - return nil, fmt.Errorf("can't open database: %w", err) - } - - if err = database.AutoMigrate( - &models.Publisher{}, - &models.Event{}, - &models.CodeHosting{}, - &models.Log{}, - &models.Software{}, - &models.SoftwareURL{}, - &models.Webhook{}, - ); err != nil { - return nil, fmt.Errorf("can't migrate database: %w", err) - } - - return database, nil -} diff --git a/internal/database/sqlite_database.go b/internal/database/sqlite_database.go deleted file mode 100644 index 069bf5e..0000000 --- a/internal/database/sqlite_database.go +++ /dev/null @@ -1,36 +0,0 @@ -package database - -import ( - "fmt" - - "github.com/italia/developers-italia-api/internal/models" - "gorm.io/driver/sqlite" - "gorm.io/gorm" -) - -type SQLiteDB struct { - dsn string -} - -func (d *SQLiteDB) Init(dsn string) (*gorm.DB, error) { - var err error - - database, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{TranslateError: true}) - if err != nil { - return nil, fmt.Errorf("can't open database: %w", err) - } - - if err = database.AutoMigrate( - &models.Publisher{}, - &models.Event{}, - &models.CodeHosting{}, - &models.Log{}, - &models.Software{}, - &models.SoftwareURL{}, - &models.Webhook{}, - ); err != nil { - return nil, fmt.Errorf("can't migrate database: %w", err) - } - - return database, nil -} diff --git a/main.go b/main.go index 9fdc41b..5331e95 100644 --- a/main.go +++ b/main.go @@ -34,9 +34,7 @@ func Setup() *fiber.App { panic(err) } - db := database.NewDatabase(common.EnvironmentConfig) - - gormDB, err := db.Init(common.EnvironmentConfig.Database) + gormDB, err := database.NewDatabase(common.EnvironmentConfig.Database) if err != nil { panic(err) } diff --git a/main_test.go b/main_test.go index 56a03d0..e76e774 100644 --- a/main_test.go +++ b/main_test.go @@ -16,6 +16,9 @@ import ( "github.com/go-testfixtures/testfixtures/v3" "github.com/gofiber/fiber/v2" "github.com/stretchr/testify/assert" + + _ "github.com/mattn/go-sqlite3" + _ "github.com/lib/pq" ) const UUID_REGEXP = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" @@ -23,6 +26,7 @@ const UUID_REGEXP = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12 var ( app *fiber.App db *sql.DB + dbDriver string goodToken = "Bearer v2.local.TwwHUQEi8hr2Eo881_Bs5vK9dHOR5BgEU24QRf-U7VmUwI1yOEA6mFT0EsXioMkFT_T-jjrtIJ_Nv8f6hR6ifJXUOuzWEkm9Ijq1mqSjQatD3aDqKMyjjBA" badToken = "Bearer v2.local.UngfrCDNwGUw4pff2oBNoyxYvOErcbVVqLndl6nzONafUCzktaOeMSmoI7B0h62zoxXXLqTm_Phl" ) @@ -43,23 +47,36 @@ type TestCase struct { } func init() { - _ = os.Remove("./test.db") + // Test on SQLite by default if DATABASE_DSN is not set + if _, exists := os.LookupEnv("DATABASE_DSN"); !exists { + _ = os.Setenv("DATABASE_DSN", "file:./test.db") + _ = os.Remove("./test.db") + } - _ = os.Setenv("DATABASE_DSN", "file:./test.db") _ = os.Setenv("ENVIRONMENT", "test") // echo -n 'test-paseto-key-dont-use-in-prod' | base64 _ = os.Setenv("PASETO_KEY", "dGVzdC1wYXNldG8ta2V5LWRvbnQtdXNlLWluLXByb2Q=") + dsn := os.Getenv("DATABASE_DSN") + switch { + case strings.HasPrefix(dsn, "postgres:"): + dbDriver = "postgres" + default: + dbDriver = "sqlite3" + } + var err error - db, err = sql.Open("sqlite3", os.Getenv("DATABASE_DSN")) + db, err = sql.Open(dbDriver, dsn) if err != nil { log.Fatal(err) } // This is needed, otherwise we get a database-locked error // TODO: investigate the root cause - _, _ = db.Exec("PRAGMA journal_mode=WAL;") + if dbDriver == "sqlite3" { + _, _ = db.Exec("PRAGMA journal_mode=WAL;") + } // Setup the app as it is done in the main function app = Setup() @@ -74,7 +91,7 @@ func TestMain(m *testing.M) { func loadFixtures(t *testing.T) { fixtures, err := testfixtures.New( testfixtures.Database(db), - testfixtures.Dialect("sqlite"), + testfixtures.Dialect(dbDriver), testfixtures.Directory("test/testdata/fixtures/"), ) assert.Nil(t, err) From 360ed8869b59fd36145c9a554b0bec616810bb4b Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Thu, 22 Jun 2023 15:10:10 +0200 Subject: [PATCH 39/54] doc: headings hierarchy in README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 19ed8a5..baf056e 100644 --- a/README.md +++ b/README.md @@ -35,12 +35,12 @@ aimed at Italian Public Administrations.

-# Requirements +## Requirements * Golang 1.18 * [PostgreSQL](https://https://www.postgresql.org/) -# Development +## Development The application uses [Air](https://github.com/cosmtrek/air) for live-reloading in the development environment. @@ -61,7 +61,7 @@ endpoints at `http://localhost:3000/v1/`. The application will automatically reload when a change is made. -# Configuration +## Configuration You can configure the API with environment variables: @@ -85,7 +85,7 @@ You can configure the API with environment variables: will be ratelimited. Default: no limit. -# Contributing +## Contributing This project exists also thanks to your contributions! Here is a list of people who already contributed to this repository: @@ -96,7 +96,7 @@ who already contributed to this repository: /> -# License +## License Copyright © 2022-present Presidenza del Consiglio dei Ministri From 39841aa69f241014eaf52bcfd0290923fb5768cc Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Thu, 22 Jun 2023 15:16:09 +0200 Subject: [PATCH 40/54] doc: minor changes to README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index baf056e..1be74fd 100644 --- a/README.md +++ b/README.md @@ -31,13 +31,13 @@

- Developers Italia API is the RESTful API of the Free and Open Source software catalog + Developers Italia API is the RESTful API of the Free and Open Source software catalog aimed at Italian Public Administrations.

## Requirements -* Golang 1.18 +* Golang 1.18+ * [PostgreSQL](https://https://www.postgresql.org/) ## Development From 23b5a6cb494922758f238cfbf3ecf6f436aa1571 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Mon, 26 Jun 2023 12:37:41 +0200 Subject: [PATCH 41/54] fix(backward comp): use postgres as default db Use PostgreSQL as default database, so it works with DSN as well. (fe. host=db user=postgres password=postgres dbname=postgres port=5432) --- README.md | 4 ++-- internal/database/database.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1be74fd..3a18965 100644 --- a/README.md +++ b/README.md @@ -65,8 +65,8 @@ The application will automatically reload when a change is made. You can configure the API with environment variables: -* `DATABASE_DSN`: the data source used to connect to the database, - fe `host=db user=postgres password=postgres dbname=postgres port=5432`. +* `DATABASE_DSN`: the URI used to connect to the database, + fe `postgres://user:password@host:5432/dbname`. Supports PostgreSQL and SQLite. * `PASETO_KEY` (optional): Base64 encoded 32 bytes key used to check the diff --git a/internal/database/database.go b/internal/database/database.go index 5c7d79e..f87b6c0 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -24,7 +24,7 @@ func NewDatabase(connection string) (*gorm.DB, error) { log.Println("using SQLite database") database, err = gorm.Open(sqlite.Open(connection), &gorm.Config{TranslateError: true}) - case strings.HasPrefix(connection, "postgres:"): + default: log.Println("using Postgres database") database, err = gorm.Open(postgres.Open(connection), &gorm.Config{ From 079780c561db831aecf7460a530f1bd3364086cf Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Wed, 23 Aug 2023 15:42:49 +0200 Subject: [PATCH 42/54] fix: ignore generated column when migrating (#208) Workaround for this issue in GORM: https://github.com/go-gorm/gorm/issues/5534 --- internal/database/database.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/internal/database/database.go b/internal/database/database.go index f87b6c0..32758d3 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -51,5 +51,16 @@ func NewDatabase(connection string) (*gorm.DB, error) { return nil, fmt.Errorf("can't migrate database: %w", err) } + // Migrate logs only if there is no "entity" column yet, which should mean when the database + // is empty. + // This is a workaround for https://github.com/go-gorm/gorm/issues/5534 where GORM + // fails to migrate an existing generated column on PostgreSQL if it already exists. + var entity string + if database.Raw("SELECT entity from logs LIMIT 1").Scan(&entity).Error != nil { + if err = database.AutoMigrate(&models.Log{}); err != nil { + return nil, fmt.Errorf("can't migrate database: %w", err) + } + } + return database, nil } From 7a1fa5d61e55f0472cf951b85b03d70c8bccad2b Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Wed, 23 Aug 2023 16:18:17 +0200 Subject: [PATCH 43/54] fix: continuation of 2974d40 (#209) --- internal/database/database.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/database/database.go b/internal/database/database.go index 32758d3..232c57e 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -43,7 +43,6 @@ func NewDatabase(connection string) (*gorm.DB, error) { &models.Publisher{}, &models.Event{}, &models.CodeHosting{}, - &models.Log{}, &models.Software{}, &models.SoftwareURL{}, &models.Webhook{}, @@ -56,7 +55,7 @@ func NewDatabase(connection string) (*gorm.DB, error) { // This is a workaround for https://github.com/go-gorm/gorm/issues/5534 where GORM // fails to migrate an existing generated column on PostgreSQL if it already exists. var entity string - if database.Raw("SELECT entity from logs LIMIT 1").Scan(&entity).Error != nil { + if database.Raw("SELECT entity FROM logs LIMIT 1").Scan(&entity).Error != nil { if err = database.AutoMigrate(&models.Log{}); err != nil { return nil, fmt.Errorf("can't migrate database: %w", err) } From 96ad8fa4166eea749701d919ec062e23e8a771de Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 25 Aug 2023 22:05:38 +0200 Subject: [PATCH 44/54] feat: fail when the JSON input has extra fields (#211) --- internal/common/validator.go | 8 +- internal/handlers/logs.go | 40 ++--- internal/handlers/software.go | 28 ++- internal/handlers/webhooks.go | 46 ++--- internal/jsondecoder/jsondecoder.go | 43 +++++ main.go | 4 + main_test.go | 261 +++++++++++++--------------- 7 files changed, 215 insertions(+), 215 deletions(-) create mode 100644 internal/jsondecoder/jsondecoder.go diff --git a/internal/common/validator.go b/internal/common/validator.go index 5a03202..e61c8c3 100644 --- a/internal/common/validator.go +++ b/internal/common/validator.go @@ -9,6 +9,8 @@ import ( "github.com/gofiber/fiber/v2" "github.com/go-playground/validator/v10" + + "github.com/italia/developers-italia-api/internal/jsondecoder" ) const ( @@ -63,7 +65,11 @@ func ValidateStruct(validateStruct interface{}) []ValidationError { func ValidateRequestEntity(ctx *fiber.Ctx, request interface{}, errorMessage string) error { if err := ctx.BodyParser(request); err != nil { - return Error(fiber.StatusBadRequest, errorMessage, "invalid json") + if errors.Is(err, jsondecoder.ErrUnknownField) { + return Error(fiber.StatusUnprocessableEntity, errorMessage, err.Error()) + } + + return Error(fiber.StatusBadRequest, errorMessage, "invalid or malformed JSON") } if err := ValidateStruct(request); err != nil { diff --git a/internal/handlers/logs.go b/internal/handlers/logs.go index 7deefdf..c5af3c7 100644 --- a/internal/handlers/logs.go +++ b/internal/handlers/logs.go @@ -84,20 +84,18 @@ func (p *Log) GetLog(ctx *fiber.Ctx) error { // PostLog creates a new log. func (p *Log) PostLog(ctx *fiber.Ctx) error { - logReq := new(common.Log) + const errMsg = "can't create Log" - if err := ctx.BodyParser(&logReq); err != nil { - return common.Error(fiber.StatusBadRequest, "can't create Log", "invalid json") - } + logReq := new(common.Log) - if err := common.ValidateStruct(*logReq); err != nil { - return common.ErrorWithValidationErrors(fiber.StatusUnprocessableEntity, "can't create Log", err) + if err := common.ValidateRequestEntity(ctx, logReq, errMsg); err != nil { + return err //nolint:wrapcheck } log := models.Log{ID: utils.UUIDv4(), Message: logReq.Message} if err := p.db.Create(&log).Error; err != nil { - return common.Error(fiber.StatusInternalServerError, "can't create Log", "db error") + return common.Error(fiber.StatusInternalServerError, errMsg, "db error") } return ctx.JSON(&log) @@ -105,30 +103,28 @@ func (p *Log) PostLog(ctx *fiber.Ctx) error { // PatchLog updates the log with the given ID. func (p *Log) PatchLog(ctx *fiber.Ctx) error { - logReq := new(common.Log) + const errMsg = "can't update Log" - if err := ctx.BodyParser(logReq); err != nil { - return common.Error(fiber.StatusBadRequest, "can't update Log", "invalid json") - } + logReq := new(common.Log) - if err := common.ValidateStruct(*logReq); err != nil { - return common.ErrorWithValidationErrors(fiber.StatusUnprocessableEntity, "can't update Log", err) + if err := common.ValidateRequestEntity(ctx, logReq, errMsg); err != nil { + return err //nolint:wrapcheck } log := models.Log{} if err := p.db.First(&log, "id = ?", ctx.Params("id")).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { - return common.Error(fiber.StatusNotFound, "can't update Log", "Log was not found") + return common.Error(fiber.StatusNotFound, errMsg, "Log was not found") } - return common.Error(fiber.StatusInternalServerError, "can't update Log", "internal server error") + return common.Error(fiber.StatusInternalServerError, errMsg, "internal server error") } log.Message = logReq.Message if err := p.db.Updates(&log).Error; err != nil { - return common.Error(fiber.StatusInternalServerError, "can't update Log", "db error") + return common.Error(fiber.StatusInternalServerError, errMsg, "db error") } return ctx.JSON(&log) @@ -198,6 +194,8 @@ func (p *Log) GetSoftwareLogs(ctx *fiber.Ctx) error { // PostSoftwareLog creates a new log associated to a Software with the given ID and returns any error encountered. func (p *Log) PostSoftwareLog(ctx *fiber.Ctx) error { + const errMsg = "can't create Log" + logReq := new(common.Log) software := models.Software{} @@ -213,12 +211,8 @@ func (p *Log) PostSoftwareLog(ctx *fiber.Ctx) error { ) } - if err := ctx.BodyParser(&logReq); err != nil { - return common.Error(fiber.StatusBadRequest, "can't create Log", "invalid json") - } - - if err := common.ValidateStruct(*logReq); err != nil { - return common.ErrorWithValidationErrors(fiber.StatusUnprocessableEntity, "can't create Log", err) + if err := common.ValidateRequestEntity(ctx, logReq, errMsg); err != nil { + return err //nolint:wrapcheck } table := models.Software{}.TableName() @@ -231,7 +225,7 @@ func (p *Log) PostSoftwareLog(ctx *fiber.Ctx) error { } if err := p.db.Create(&log).Error; err != nil { - return common.Error(fiber.StatusInternalServerError, "can't create Log", "db error") + return common.Error(fiber.StatusInternalServerError, errMsg, "db error") } return ctx.JSON(&log) diff --git a/internal/handlers/software.go b/internal/handlers/software.go index c3eb58f..38c25d3 100644 --- a/internal/handlers/software.go +++ b/internal/handlers/software.go @@ -149,16 +149,12 @@ func (p *Software) GetSoftware(ctx *fiber.Ctx) error { // PostSoftware creates a new software. func (p *Software) PostSoftware(ctx *fiber.Ctx) error { - softwareReq := new(common.SoftwarePost) + const errMsg = "can't create Software" - if err := ctx.BodyParser(&softwareReq); err != nil { - return common.Error(fiber.StatusBadRequest, "can't create Software", "invalid json") - } + softwareReq := new(common.SoftwarePost) - if err := common.ValidateStruct(*softwareReq); err != nil { - return common.ErrorWithValidationErrors( - fiber.StatusUnprocessableEntity, "can't create Software", err, - ) + if err := common.ValidateRequestEntity(ctx, softwareReq, errMsg); err != nil { + return err //nolint:wrapcheck } aliases := []models.SoftwareURL{} @@ -180,14 +176,16 @@ func (p *Software) PostSoftware(ctx *fiber.Ctx) error { } if err := p.db.Create(&software).Error; err != nil { - return common.Error(fiber.StatusInternalServerError, "can't create Software", err.Error()) + return common.Error(fiber.StatusInternalServerError, errMsg, err.Error()) } return ctx.JSON(&software) } // PatchSoftware updates the software with the given ID. -func (p *Software) PatchSoftware(ctx *fiber.Ctx) error { //nolint:cyclop // mostly error handling ifs +func (p *Software) PatchSoftware(ctx *fiber.Ctx) error { + const errMsg = "can't update Software" + softwareReq := new(common.SoftwarePatch) software := models.Software{} @@ -202,14 +200,8 @@ func (p *Software) PatchSoftware(ctx *fiber.Ctx) error { //nolint:cyclop // most return common.Error(fiber.StatusInternalServerError, "can't update Software", "internal server error") } - if err := ctx.BodyParser(softwareReq); err != nil { - return common.Error(fiber.StatusBadRequest, "can't update Software", "invalid json") - } - - if err := common.ValidateStruct(*softwareReq); err != nil { - return common.ErrorWithValidationErrors( - fiber.StatusUnprocessableEntity, "can't update Software", err, - ) + if err := common.ValidateRequestEntity(ctx, softwareReq, errMsg); err != nil { + return err //nolint:wrapcheck } // Slice of urls that we expect in the database after the PATCH (url + aliases) diff --git a/internal/handlers/webhooks.go b/internal/handlers/webhooks.go index 146f24f..0378bab 100644 --- a/internal/handlers/webhooks.go +++ b/internal/handlers/webhooks.go @@ -114,18 +114,14 @@ func (p *Webhook[T]) GetSingleResourceWebhooks(ctx *fiber.Ctx) error { // PostSingleResourceWebhook creates a new webhook associated to resources // (fe. Software, Publishers) and returns any error encountered. func (p *Webhook[T]) PostResourceWebhook(ctx *fiber.Ctx) error { + const errMsg = "can't create Webhook" + webhookReq := new(common.Webhook) var resource T - if err := ctx.BodyParser(&webhookReq); err != nil { - return common.Error(fiber.StatusBadRequest, "can't create Webhook", "invalid json") - } - - if err := common.ValidateStruct(*webhookReq); err != nil { - return common.ErrorWithValidationErrors( - fiber.StatusUnprocessableEntity, "can't create Webhook", err, - ) + if err := common.ValidateRequestEntity(ctx, webhookReq, errMsg); err != nil { + return err //nolint:wrapcheck } webhook := models.Webhook{ @@ -137,7 +133,7 @@ func (p *Webhook[T]) PostResourceWebhook(ctx *fiber.Ctx) error { } if err := p.db.Create(&webhook).Error; err != nil { - return common.Error(fiber.StatusInternalServerError, "can't create Webhook", "db error") + return common.Error(fiber.StatusInternalServerError, errMsg, "db error") } return ctx.JSON(&webhook) @@ -146,6 +142,8 @@ func (p *Webhook[T]) PostResourceWebhook(ctx *fiber.Ctx) error { // PostResourceWebhook creates a new webhook associated to a resource with the given ID // (fe. a specific Software or Publisher) and returns any error encountered. func (p *Webhook[T]) PostSingleResourceWebhook(ctx *fiber.Ctx) error { + const errMsg = "can't create Webhook" + webhookReq := new(common.Webhook) var resource T @@ -162,14 +160,8 @@ func (p *Webhook[T]) PostSingleResourceWebhook(ctx *fiber.Ctx) error { ) } - if err := ctx.BodyParser(&webhookReq); err != nil { - return common.Error(fiber.StatusBadRequest, "can't create Webhook", "invalid json") - } - - if err := common.ValidateStruct(*webhookReq); err != nil { - return common.ErrorWithValidationErrors( - fiber.StatusUnprocessableEntity, "can't create Webhook", err, - ) + if err := common.ValidateRequestEntity(ctx, webhookReq, errMsg); err != nil { + return err //nolint:wrapcheck } webhook := models.Webhook{ @@ -181,7 +173,7 @@ func (p *Webhook[T]) PostSingleResourceWebhook(ctx *fiber.Ctx) error { } if err := p.db.Create(&webhook).Error; err != nil { - return common.Error(fiber.StatusInternalServerError, "can't create Webhook", "db error") + return common.Error(fiber.StatusInternalServerError, errMsg, "db error") } return ctx.JSON(&webhook) @@ -189,28 +181,24 @@ func (p *Webhook[T]) PostSingleResourceWebhook(ctx *fiber.Ctx) error { // PatchWebhook updates the webhook with the given ID. func (p *Webhook[T]) PatchWebhook(ctx *fiber.Ctx) error { - webhookReq := new(common.Webhook) + const errMsg = "can't update Webhook" - if err := ctx.BodyParser(webhookReq); err != nil { - return common.Error(fiber.StatusBadRequest, "can't update Webhook", "invalid json") - } + webhookReq := new(common.Webhook) - if err := common.ValidateStruct(*webhookReq); err != nil { - return common.ErrorWithValidationErrors( - fiber.StatusUnprocessableEntity, "can't update Webhook", err, - ) + if err := common.ValidateRequestEntity(ctx, webhookReq, errMsg); err != nil { + return err //nolint:wrapcheck } webhook := models.Webhook{} if err := p.db.First(&webhook, "id = ?", ctx.Params("id")).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { - return common.Error(fiber.StatusNotFound, "can't update Webhook", "Webhook was not found") + return common.Error(fiber.StatusNotFound, errMsg, "Webhook was not found") } return common.Error( fiber.StatusInternalServerError, - "can't update Webhook", + errMsg, fiber.ErrInternalServerError.Message, ) } @@ -218,7 +206,7 @@ func (p *Webhook[T]) PatchWebhook(ctx *fiber.Ctx) error { webhook.URL = webhookReq.URL if err := p.db.Updates(&webhook).Error; err != nil { - return common.Error(fiber.StatusInternalServerError, "can't update Webhook", "db error") + return common.Error(fiber.StatusInternalServerError, errMsg, "db error") } return ctx.JSON(&webhook) diff --git a/internal/jsondecoder/jsondecoder.go b/internal/jsondecoder/jsondecoder.go new file mode 100644 index 0000000..1744a2d --- /dev/null +++ b/internal/jsondecoder/jsondecoder.go @@ -0,0 +1,43 @@ +package jsondecoder + +import ( + "bytes" + "encoding/json" + "errors" + "strings" +) + +var ( + ErrExtraDataAfterDecoding = errors.New("extra data after decoding") + ErrUnknownField = errors.New("unknown field in JSON input") +) + +// UnmarshalDisallowUnknownFieldsUnmarshal parses the JSON-encoded data +// and stores the result in the value pointed to by v like json.Unmarshal, +// but with DisallowUnknownFields() set by default for extra security. +func UnmarshalDisallowUnknownFields(data []byte, v interface{}) error { + dec := json.NewDecoder(bytes.NewReader(data)) + dec.DisallowUnknownFields() + + if err := dec.Decode(v); err != nil { + // Ugly, but the encoding/json uses a dynamic error here + if strings.HasPrefix(err.Error(), "json: unknown field ") { + return ErrUnknownField + } + + // we want to provide an alternative implementation, with the + // unwrapped errors + //nolint:wrapcheck + return err + } + + // Check if there's any data left in the decoder's buffer. + // This ensures that there's no extra JSON after the main object + // otherwise something like '{"foo": 1}{"bar": 2}' or even '{}garbage' + // will not error out. + if dec.More() { + return ErrExtraDataAfterDecoding + } + + return nil +} diff --git a/main.go b/main.go index 5331e95..4dad7b6 100644 --- a/main.go +++ b/main.go @@ -11,6 +11,7 @@ import ( "github.com/italia/developers-italia-api/internal/common" "github.com/italia/developers-italia-api/internal/database" "github.com/italia/developers-italia-api/internal/handlers" + "github.com/italia/developers-italia-api/internal/jsondecoder" "github.com/italia/developers-italia-api/internal/middleware" "github.com/italia/developers-italia-api/internal/models" "github.com/italia/developers-italia-api/internal/webhooks" @@ -54,6 +55,9 @@ func Setup() *fiber.App { app := fiber.New(fiber.Config{ ErrorHandler: common.CustomErrorHandler, + // Fiber doesn't set DisallowUnknownFields by default + // (https://github.com/gofiber/fiber/issues/2601) + JSONDecoder: jsondecoder.UnmarshalDisallowUnknownFields, }) // Automatically recover panics in handlers diff --git a/main_test.go b/main_test.go index e76e774..5858ef9 100644 --- a/main_test.go +++ b/main_test.go @@ -685,14 +685,14 @@ func TestPublishersEndpoints(t *testing.T) { { description: "POST publishers with invalid payload", query: "POST /v1/publishers", - body: `{"url": "-"}`, + body: `{"description": "-"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, }, expectedCode: 422, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't create Publisher","detail":"invalid format: codeHosting is required, description is required","status":422,"validationErrors":[{"field":"codeHosting","rule":"required","value":""},{"field":"description","rule":"required","value":""}]}`, + expectedBody: `{"title":"can't create Publisher","detail":"invalid format: codeHosting is required","status":422,"validationErrors":[{"field":"codeHosting","rule":"required","value":""}]}`, }, { description: "POST publishers - wrong token", @@ -717,7 +717,7 @@ func TestPublishersEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Publisher`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) + assert.Equal(t, "invalid or malformed JSON", response["detail"]) }, }, { @@ -793,7 +793,7 @@ func TestPublishersEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Publisher`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) + assert.Equal(t, "invalid or malformed JSON", response["detail"]) }, }, @@ -957,25 +957,21 @@ func TestPublishersEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't update Publisher`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) + assert.Equal(t, "invalid or malformed JSON", response["detail"]) }, }, - // TODO: make this pass - // { - // description: "PATCH publishers with JSON with extra fields", - // query: "PATCH /v1/publishers", - // body: `{"description": "new description", EXTRA_FIELD: "extra field not in schema"}`, - // headers: map[string][]string{ - // "Authorization": {goodToken}, - // "Content-Type": {"application/json"}, - // }, - // expectedCode: 422, - // expectedContentType: "application/problem+json", - // validateFunc: func(t *testing.T, response map[string]interface{}) { - // assert.Equal(t, `can't create Publisher`, response["title"]) - // assert.Equal(t, "invalid json", response["detail"]) - // }, - // }, + { + description: "PATCH publishers with JSON with extra fields", + query: "PATCH /v1/publishers/2ded32eb-c45e-4167-9166-a44e18b8adde", + body: `{"description": "new description", "EXTRA_FIELD": "extra field not in schema"}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + expectedCode: 422, + expectedContentType: "application/problem+json", + expectedBody: `{"title":"can't update Publisher","detail":"unknown field in JSON input","status":422}`, + }, { description: "PATCH publisher with validation errors", query: "PATCH /v1/publishers/2ded32eb-c45e-4167-9166-a44e18b8adde", @@ -998,7 +994,7 @@ func TestPublishersEndpoints(t *testing.T) { }, expectedCode: 400, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't update Publisher","detail":"invalid json","status":400}`, + expectedBody: `{"title":"can't update Publisher","detail":"invalid or malformed JSON","status":400}`, }, // TODO: enforce this? // { @@ -1201,24 +1197,21 @@ func TestPublishersEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Webhook`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) + assert.Equal(t, "invalid or malformed JSON", response["detail"]) }, }, - // TODO: make this pass - // { - // description: "POST /v1/publishers/98a069f7-57b0-464d-b300-4b4b336297a0/webhooks with JSON with extra fields", - // body: `{"url": "https://new.example.org", EXTRA_FIELD: "extra field not in schema"}`, - // headers: map[string][]string{ - // "Authorization": {goodToken}, - // "Content-Type": {"application/json"}, - // }, - // expectedCode: 422, - // expectedContentType: "application/problem+json", - // validateFunc: func(t *testing.T, response map[string]interface{}) { - // assert.Equal(t, `can't create Webhook`, response["title"]) - // assert.Equal(t, "invalid json", response["detail"]) - // }, - // }, + { + description: "POST /v1/publishers/98a069f7-57b0-464d-b300-4b4b336297a0/webhooks with JSON with extra fields", + query: "POST /v1/publishers/98a069f7-57b0-464d-b300-4b4b336297a0/webhooks", + body: `{"url": "https://new.example.org", "EXTRA_FIELD": "extra field not in schema"}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + expectedCode: 422, + expectedContentType: "application/problem+json", + expectedBody: `{"title":"can't create Webhook","detail":"unknown field in JSON input","status":422}`, + }, { description: "POST webhook with validation errors", query: "POST /v1/publishers/98a069f7-57b0-464d-b300-4b4b336297a0/webhooks", @@ -1257,7 +1250,7 @@ func TestPublishersEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Webhook`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) + assert.Equal(t, "invalid or malformed JSON", response["detail"]) }, }, // TODO: enforce this? @@ -1748,25 +1741,21 @@ func TestSoftwareEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Software`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) + assert.Equal(t, "invalid or malformed JSON", response["detail"]) }, }, - // TODO: make this pass - // { - // descrption: "POST /v1/software with JSON with extra fields", - // query: "POST /v1/software", - // body: `{"publiccodeYml": "-", EXTRA_FIELD: "extra field not in schema"}`, - // headers: map[string][]string{ - // "Authorization": {goodToken}, - // "Content-Type": {"application/json"}, - // }, - // expectedCode: 422, - // expectedContentType: "application/problem+json", - // validateFunc: func(t *testing.T, response map[string]interface{}) { - // assert.Equal(t, `can't create Software`, response["title"]) - // assert.Equal(t, "invalid json", response["detail"]) - // }, - // }, + { + description: "POST /v1/software with JSON with extra fields", + query: "POST /v1/software", + body: `{"publiccodeYml": "-", "EXTRA_FIELD": "extra field not in schema"}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + expectedCode: 422, + expectedContentType: "application/problem+json", + expectedBody: `{"title":"can't create Software","detail":"unknown field in JSON input","status":422}`, + }, { description: "POST software with optional boolean field set to false", query: "POST /v1/software", @@ -1819,7 +1808,7 @@ func TestSoftwareEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Software`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) + assert.Equal(t, "invalid or malformed JSON", response["detail"]) }, }, // TODO: enforce this? @@ -1976,25 +1965,21 @@ func TestSoftwareEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't update Software`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) + assert.Equal(t, "invalid or malformed JSON", response["detail"]) }, }, - // TODO: make this pass - // { - // description: "PATCH software with JSON with extra fields", - // query: "PATCH /v1/software", - // body: `{"publiccodeYml": "-", EXTRA_FIELD: "extra field not in schema"}`, - // headers: map[string][]string{ - // "Authorization": {goodToken}, - // "Content-Type": {"application/json"}, - // }, - // expectedCode: 422, - // expectedContentType: "application/problem+json", - // validateFunc: func(t *testing.T, response map[string]interface{}) { - // assert.Equal(t, `can't create Software`, response["title"]) - // assert.Equal(t, "invalid json", response["detail"]) - // }, - // }, + { + description: "PATCH software with JSON with extra fields", + query: "PATCH /v1/software/59803fb7-8eec-4fe5-a354-8926009c364a", + body: `{"publiccodeYml": "-", "EXTRA_FIELD": "extra field not in schema"}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + expectedCode: 422, + expectedContentType: "application/problem+json", + expectedBody: `{"title":"can't update Software","detail":"unknown field in JSON input","status":422}`, + }, { description: "PATCH software with validation errors", query: "PATCH /v1/software/59803fb7-8eec-4fe5-a354-8926009c364a", @@ -2033,7 +2018,7 @@ func TestSoftwareEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't update Software`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) + assert.Equal(t, "invalid or malformed JSON", response["detail"]) }, }, // TODO: enforce this? @@ -2231,24 +2216,21 @@ func TestSoftwareEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Log`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) + assert.Equal(t, "invalid or malformed JSON", response["detail"]) }, }, - // TODO: make this pass - // { - // description: "POST /v1/software/c353756e-8597-4e46-a99b-7da2e141603b/logs with JSON with extra fields", - // body: `{"message": "new log", EXTRA_FIELD: "extra field not in schema"}`, - // headers: map[string][]string{ - // "Authorization": {goodToken}, - // "Content-Type": {"application/json"}, - // }, - // expectedCode: 422, - // expectedContentType: "application/problem+json", - // validateFunc: func(t *testing.T, response map[string]interface{}) { - // assert.Equal(t, `can't create Log`, response["title"]) - // assert.Equal(t, "invalid json", response["detail"]) - // }, - // }, + { + description: "POST /v1/software/c353756e-8597-4e46-a99b-7da2e141603b/logs with JSON with extra fields", + query: "POST /v1/software/c353756e-8597-4e46-a99b-7da2e141603b/logs", + body: `{"message": "new log", "EXTRA_FIELD": "extra field not in schema"}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + expectedCode: 422, + expectedContentType: "application/problem+json", + expectedBody: `{"title":"can't create Log","detail":"unknown field in JSON input","status":422}`, + }, { description: "POST log with validation errors", query: "POST /v1/software/c353756e-8597-4e46-a99b-7da2e141603b/logs", @@ -2287,7 +2269,7 @@ func TestSoftwareEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Log`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) + assert.Equal(t, "invalid or malformed JSON", response["detail"]) }, }, // TODO: enforce this? @@ -2444,24 +2426,21 @@ func TestSoftwareEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Webhook`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) + assert.Equal(t, "invalid or malformed JSON", response["detail"]) }, }, - // TODO: make this pass - // { - // description: "POST /v1/software/c5dec6fa-8a01-4881-9e7d-132770d4214d/webhooks with JSON with extra fields", - // body: `{"url": "https://new.example.org", EXTRA_FIELD: "extra field not in schema"}`, - // headers: map[string][]string{ - // "Authorization": {goodToken}, - // "Content-Type": {"application/json"}, - // }, - // expectedCode: 422, - // expectedContentType: "application/problem+json", - // validateFunc: func(t *testing.T, response map[string]interface{}) { - // assert.Equal(t, `can't create Webhook`, response["title"]) - // assert.Equal(t, "invalid json", response["detail"]) - // }, - // }, + { + description: "POST /v1/software/c5dec6fa-8a01-4881-9e7d-132770d4214d/webhooks with JSON with extra fields", + query: "POST /v1/software/c5dec6fa-8a01-4881-9e7d-132770d4214d/webhooks", + body: `{"url": "https://new.example.org", "EXTRA_FIELD": "extra field not in schema"}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + expectedCode: 422, + expectedContentType: "application/problem+json", + expectedBody: `{"title":"can't create Webhook","detail":"unknown field in JSON input","status":422}`, + }, { description: "POST webhook with validation errors", query: "POST /v1/software/c5dec6fa-8a01-4881-9e7d-132770d4214d/webhooks", @@ -2500,7 +2479,7 @@ func TestSoftwareEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Webhook`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) + assert.Equal(t, "invalid or malformed JSON", response["detail"]) }, }, // TODO: enforce this? @@ -2754,7 +2733,7 @@ func TestLogsEndpoints(t *testing.T) { }, expectedCode: 422, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't create Log","detail":"invalid format: message is required","status":422,"validationErrors":[{"field":"message","rule":"required","value":""}]}`, + expectedBody: `{"title":"can't create Log","detail":"unknown field in JSON input","status":422}`, }, { description: "POST log - wrong token", @@ -2780,24 +2759,21 @@ func TestLogsEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Log`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) + assert.Equal(t, "invalid or malformed JSON", response["detail"]) }, }, - // TODO: make this pass - // { - // query: "POST /v1/logs with JSON with extra fields", - // body: `{"message": "new log", EXTRA_FIELD: "extra field not in schema"}`, - // headers: map[string][]string{ - // "Authorization": {goodToken}, - // "Content-Type": {"application/json"}, - // }, - // expectedCode: 422, - // expectedContentType: "application/problem+json", - // validateFunc: func(t *testing.T, response map[string]interface{}) { - // assert.Equal(t, `can't create Log`, response["title"]) - // assert.Equal(t, "invalid json", response["detail"]) - // }, - // }, + { + description: "POST /v1/logs with JSON with extra fields", + query: "POST /v1/logs", + body: `{"message": "new log", "EXTRA_FIELD": "extra field not in schema"}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + expectedCode: 422, + expectedContentType: "application/problem+json", + expectedBody: `{"title":"can't create Log","detail":"unknown field in JSON input","status":422}`, + }, { description: "POST log with validation errors", query: "POST /v1/logs", @@ -2836,7 +2812,7 @@ func TestLogsEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't create Log`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) + assert.Equal(t, "invalid or malformed JSON", response["detail"]) }, }, // TODO: enforce this? @@ -2918,24 +2894,21 @@ func TestWebhooksEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't update Webhook`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) + assert.Equal(t, "invalid or malformed JSON", response["detail"]) }, }, - // TODO: make this pass - // { - // query: "PATCH /v1/webhooks/007bc84a-7e2d-43a0-b7e1-a256d4114aa7 with JSON with extra fields", - // body: `{"url": "https://new.example.org/receiver", EXTRA_FIELD: "extra field not in schema"}`, - // headers: map[string][]string{ - // "Authorization": {goodToken}, - // "Content-Type": {"application/json"}, - // }, - // expectedCode: 422, - // expectedContentType: "application/problem+json", - // validateFunc: func(t *testing.T, response map[string]interface{}) { - // assert.Equal(t, `can't create Webhook`, response["title"]) - // assert.Equal(t, "invalid json", response["detail"]) - // }, - // }, + { + description: "PATCH /v1/webhooks/007bc84a-7e2d-43a0-b7e1-a256d4114aa7 with JSON with extra fields", + query: "PATCH /v1/webhooks/007bc84a-7e2d-43a0-b7e1-a256d4114aa7", + body: `{"url": "https://new.example.org/receiver", "EXTRA_FIELD": "extra field not in schema"}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + expectedCode: 422, + expectedContentType: "application/problem+json", + expectedBody: `{"title":"can't update Webhook","detail":"unknown field in JSON input","status":422}`, + }, { description: "PATCH webhook with validation errors", query: "PATCH /v1/webhooks/007bc84a-7e2d-43a0-b7e1-a256d4114aa7", @@ -2974,7 +2947,7 @@ func TestWebhooksEndpoints(t *testing.T) { expectedContentType: "application/problem+json", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, `can't update Webhook`, response["title"]) - assert.Equal(t, "invalid json", response["detail"]) + assert.Equal(t, "invalid or malformed JSON", response["detail"]) }, }, // TODO: enforce this? From e496d985d5bbb54159f9aae3f96a3d5a164231aa Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Tue, 5 Sep 2023 16:28:04 +0200 Subject: [PATCH 45/54] fix: properly implement JSON merge patch for Software (#210) Fix #173 --- go.mod | 2 + go.sum | 5 + internal/common/errors.go | 4 + internal/common/requests.go | 4 +- internal/handlers/software.go | 196 +++++++++++++++++++--------------- internal/models/models.go | 11 +- main_test.go | 135 ++++++++++++++++++++++- 7 files changed, 265 insertions(+), 92 deletions(-) diff --git a/go.mod b/go.mod index 0864923..d458dc9 100644 --- a/go.mod +++ b/go.mod @@ -57,6 +57,8 @@ require ( require ( github.com/andybalholm/brotli v1.0.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/evanphx/json-patch v0.5.2 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect diff --git a/go.sum b/go.sum index 64c17c3..8c11bb8 100644 --- a/go.sum +++ b/go.sum @@ -80,6 +80,10 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF 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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k= +github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= 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= @@ -226,6 +230,7 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= 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.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= diff --git a/internal/common/errors.go b/internal/common/errors.go index 1daa375..95859c5 100644 --- a/internal/common/errors.go +++ b/internal/common/errors.go @@ -12,6 +12,10 @@ var ( ErrKeyLen = errors.New("PASETO_KEY must be 32 bytes long once base64-decoded") ) +func InternalServerError(title string) ProblemJSONError { + return Error(fiber.StatusInternalServerError, title, fiber.ErrInternalServerError.Message) +} + func Error(status int, title string, detail string) ProblemJSONError { return ProblemJSONError{Title: title, Detail: detail, Status: status} } diff --git a/internal/common/requests.go b/internal/common/requests.go index ca8e20c..95fc904 100644 --- a/internal/common/requests.go +++ b/internal/common/requests.go @@ -31,9 +31,9 @@ type SoftwarePost struct { } type SoftwarePatch struct { - URL string `json:"url" validate:"url"` + URL *string `json:"url" validate:"omitempty,url"` Aliases *[]string `json:"aliases" validate:"omitempty,dive,url"` - PubliccodeYml string `json:"publiccodeYml"` + PubliccodeYml *string `json:"publiccodeYml"` Active *bool `json:"active"` } diff --git a/internal/handlers/software.go b/internal/handlers/software.go index 38c25d3..9ba4343 100644 --- a/internal/handlers/software.go +++ b/internal/handlers/software.go @@ -1,6 +1,7 @@ package handlers import ( + "encoding/json" "errors" "sort" @@ -12,6 +13,8 @@ import ( "github.com/italia/developers-italia-api/internal/handlers/general" "github.com/italia/developers-italia-api/internal/models" "gorm.io/gorm" + + jsonpatch "github.com/evanphx/json-patch" ) type SoftwareInterface interface { @@ -26,6 +29,11 @@ type Software struct { db *gorm.DB } +var ( + errLoadNotFound = errors.New("Software was not found") + errLoad = errors.New("error while loading Software") +) + func NewSoftware(db *gorm.DB) *Software { return &Software{db: db} } @@ -112,36 +120,16 @@ func (p *Software) GetAllSoftware(ctx *fiber.Ctx) error { //nolint:cyclop // mos // GetSoftware gets the software with the given ID and returns any error encountered. func (p *Software) GetSoftware(ctx *fiber.Ctx) error { + const errMsg = "can't get Software" + software := models.Software{} - if err := p.db.First(&software, "id = ?", ctx.Params("id")).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return common.Error(fiber.StatusNotFound, "can't get Software", "Software was not found") + if err := loadSoftware(p.db, &software, ctx.Params("id")); err != nil { + if errors.Is(err, errLoadNotFound) { + return common.Error(fiber.StatusNotFound, errMsg, "Software was not found") } - return common.Error( - fiber.StatusInternalServerError, - "can't get Software", - fiber.ErrInternalServerError.Message, - ) - } - - if err := p.db. - Where("software_id = ? AND id <> ?", software.ID, software.SoftwareURLID).Find(&software.Aliases). - Error; err != nil { - return common.Error( - fiber.StatusInternalServerError, - "can't get Software", - fiber.ErrInternalServerError.Message, - ) - } - - if err := p.db.Where("id = ?", software.SoftwareURLID).First(&software.URL).Error; err != nil { - return common.Error( - fiber.StatusInternalServerError, - "can't get Software", - fiber.ErrInternalServerError.Message, - ) + return common.InternalServerError(errMsg) } return ctx.JSON(&software) @@ -183,83 +171,93 @@ func (p *Software) PostSoftware(ctx *fiber.Ctx) error { } // PatchSoftware updates the software with the given ID. -func (p *Software) PatchSoftware(ctx *fiber.Ctx) error { +func (p *Software) PatchSoftware(ctx *fiber.Ctx) error { //nolint:funlen,cyclop const errMsg = "can't update Software" - softwareReq := new(common.SoftwarePatch) + softwareReq := common.SoftwarePatch{} software := models.Software{} - // Preload will load all the associated aliases, which include - // also the canonical url. We'll manually handle that later. - if err := p.db.Preload("Aliases").First(&software, "id = ?", ctx.Params("id")). - Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return common.Error(fiber.StatusNotFound, "can't update Software", "Software was not found") + if err := loadSoftware(p.db, &software, ctx.Params("id")); err != nil { + if errors.Is(err, errLoadNotFound) { + return common.Error(fiber.StatusNotFound, errMsg, "Software was not found") } - return common.Error(fiber.StatusInternalServerError, "can't update Software", "internal server error") + return common.Error(fiber.StatusInternalServerError, errMsg, err.Error()) } - if err := common.ValidateRequestEntity(ctx, softwareReq, errMsg); err != nil { + if err := common.ValidateRequestEntity(ctx, &softwareReq, errMsg); err != nil { return err //nolint:wrapcheck } - // Slice of urls that we expect in the database after the PATCH (url + aliases) - var expectedURLs []string + softwareJSON, err := json.Marshal(&software) + if err != nil { + return common.Error(fiber.StatusInternalServerError, errMsg, err.Error()) + } - // application/merge-patch+json semantics: change url only if - // the request specifies an "url" key. - url := software.URL.URL - if softwareReq.URL != "" { - url = softwareReq.URL + updatedJSON, err := jsonpatch.MergePatch(softwareJSON, ctx.Body()) + if err != nil { + return common.Error(fiber.StatusInternalServerError, errMsg, err.Error()) } - // application/merge-patch+json semantics: change aliases only if - // the request specifies an "aliases" key. - if softwareReq.Aliases != nil { - expectedURLs = *softwareReq.Aliases - } else { - for _, alias := range software.Aliases { - expectedURLs = append(expectedURLs, alias.URL) - } + var updatedSoftware models.Software + + err = json.Unmarshal(updatedJSON, &updatedSoftware) + if err != nil { + return common.Error(fiber.StatusInternalServerError, errMsg, err.Error()) } - expectedURLs = append(expectedURLs, url) + // Slice of aliases that we expect to be in the database after the PATCH + expectedAliases := make([]string, 0, len(updatedSoftware.Aliases)) + for _, alias := range updatedSoftware.Aliases { + expectedAliases = append(expectedAliases, alias.URL) + } if err := p.db.Transaction(func(tran *gorm.DB) error { - updatedURL, aliases, err := syncAliases(tran, software, url, expectedURLs) + //nolint:gocritic // it's fine, we want to another slice + currentURLs := append(software.Aliases, software.URL) + + updatedURL, aliases, err := syncAliases( + tran, + software.ID, + currentURLs, + updatedSoftware.URL.URL, + expectedAliases, + ) if err != nil { return err } - software.PubliccodeYml = softwareReq.PubliccodeYml - software.Active = softwareReq.Active - // Manually set the canonical URL via the foreign key because of a limitation in gorm - software.SoftwareURLID = updatedURL.ID - software.URL = *updatedURL + updatedSoftware.SoftwareURLID = updatedURL.ID + updatedSoftware.URL = *updatedURL // Set Aliases to a zero value, so it's not touched by gorm's Update(), // because we handle the alias manually - software.Aliases = []models.SoftwareURL{} + updatedSoftware.Aliases = []models.SoftwareURL{} - if err := tran.Updates(&software).Error; err != nil { + if err := tran.Updates(&updatedSoftware).Error; err != nil { return err } - software.Aliases = aliases + updatedSoftware.Aliases = aliases return nil }); err != nil { - return common.Error(fiber.StatusInternalServerError, "can't update Software", err.Error()) + switch { + case errors.Is(err, gorm.ErrDuplicatedKey): + return common.Error(fiber.StatusConflict, errMsg, "URL already exists") + default: + //nolint:wrapcheck // default to not wrap other errors, the handler will take care of this + return err + } } // Sort the aliases to always have a consistent output - sort.Slice(software.Aliases, func(a int, b int) bool { - return software.Aliases[a].URL < software.Aliases[b].URL + sort.Slice(updatedSoftware.Aliases, func(a int, b int) bool { + return updatedSoftware.Aliases[a].URL < updatedSoftware.Aliases[b].URL }) - return ctx.JSON(&software) + return ctx.JSON(&updatedSoftware) } // DeleteSoftware deletes the software with the given ID. @@ -277,12 +275,38 @@ func (p *Software) DeleteSoftware(ctx *fiber.Ctx) error { return ctx.SendStatus(fiber.StatusNoContent) } -// syncAliases synchs the SoftwareURLs for a `software` in the database to reflect the -// passed list of `expectedURLs` and the canonical `url`. +func loadSoftware(gormdb *gorm.DB, software *models.Software, id string) error { + if err := gormdb.First(&software, "id = ?", id).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return errLoadNotFound + } + + return errLoad + } + + if err := gormdb. + Where("software_id = ? AND id <> ?", software.ID, software.SoftwareURLID).Find(&software.Aliases). + Error; err != nil { + return errLoad + } + + if err := gormdb.Debug().Where("id = ?", software.SoftwareURLID).First(&software.URL).Error; err != nil { + return errLoad + } + + return nil +} + +// syncAliases synchs the SoftwareURLs for a `Software` in the database to reflect the +// passed list of `expectedAliases` and the canonical `url`. // // It returns the new canonical SoftwareURL and the new slice of aliases or an error if any. func syncAliases( //nolint:cyclop // mostly error handling ifs - gormdb *gorm.DB, software models.Software, canonicalURL string, expectedURLs []string, + gormdb *gorm.DB, + softwareID string, + currentURLs []models.SoftwareURL, + expectedURL string, + expectedAliases []string, ) (*models.SoftwareURL, []models.SoftwareURL, error) { toRemove := []string{} // Slice of SoftwareURL ids to remove from the database toAdd := []models.SoftwareURL{} // Slice of SoftwareURLs to add to the database @@ -291,25 +315,28 @@ func syncAliases( //nolint:cyclop // mostly error handling ifs // keyed by url urlMap := map[string]models.SoftwareURL{} - for _, alias := range software.Aliases { - urlMap[alias.URL] = alias + for _, url := range currentURLs { + urlMap[url.URL] = url } - for url, alias := range urlMap { - if !slices.Contains(expectedURLs, url) { - toRemove = append(toRemove, alias.ID) + //nolint:gocritic // it's fine, we want to another slice + allSoftwareURLs := append(expectedAliases, expectedURL) - delete(urlMap, url) + for urlStr, softwareURL := range urlMap { + if !slices.Contains(allSoftwareURLs, urlStr) { + toRemove = append(toRemove, softwareURL.ID) + + delete(urlMap, urlStr) } } - for _, url := range expectedURLs { - _, exists := urlMap[url] + for _, urlStr := range allSoftwareURLs { + _, exists := urlMap[urlStr] if !exists { - alias := models.SoftwareURL{ID: utils.UUIDv4(), URL: url, SoftwareID: software.ID} + su := models.SoftwareURL{ID: utils.UUIDv4(), URL: urlStr, SoftwareID: softwareID} - toAdd = append(toAdd, alias) - urlMap[url] = alias + toAdd = append(toAdd, su) + urlMap[urlStr] = su } } @@ -325,17 +352,16 @@ func syncAliases( //nolint:cyclop // mostly error handling ifs } } - updatedCanonicalURL := urlMap[canonicalURL] + updatedURL := urlMap[expectedURL] - // Remove the canonical URL from the aliases, because it need to be its own - // field. It was loaded previously together with the other aliases in Preload(), - // because of limitation in gorm. - delete(urlMap, canonicalURL) + // Remove the canonical URL from the rest of the URLs, so we can return + // URL and aliases in different fields. + delete(urlMap, expectedURL) aliases := make([]models.SoftwareURL, 0, len(urlMap)) for _, alias := range urlMap { aliases = append(aliases, alias) } - return &updatedCanonicalURL, aliases, nil + return &updatedURL, aliases, nil } diff --git a/internal/models/models.go b/internal/models/models.go index 4d5bed6..a2185db 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -1,6 +1,7 @@ package models import ( + "encoding/json" "fmt" "time" @@ -88,18 +89,24 @@ func (s Software) UUID() string { return s.ID } +//nolint:musttag // we are using a custom MarshalJSON method type SoftwareURL struct { ID string `gorm:"primarykey"` URL string `gorm:"uniqueIndex"` SoftwareID string `gorm:"not null"` - CreatedAt time.Time `json:"createdAt" gorm:"index"` - UpdatedAt time.Time `json:"updatedAt"` + CreatedAt time.Time `gorm:"index"` + UpdatedAt time.Time } func (su SoftwareURL) MarshalJSON() ([]byte, error) { return ([]byte)(fmt.Sprintf(`"%s"`, su.URL)), nil } +func (su *SoftwareURL) UnmarshalJSON(data []byte) error { + //nolint:wrapcheck // we want to pass along the error here + return json.Unmarshal(data, &su.URL) +} + type Webhook struct { ID string `json:"id" gorm:"primaryKey"` URL string `json:"url" gorm:"index:idx_webhook_url,unique"` diff --git a/main_test.go b/main_test.go index 5858ef9..2969f42 100644 --- a/main_test.go +++ b/main_test.go @@ -1835,6 +1835,7 @@ func TestSoftwareEndpoints(t *testing.T) { expectedContentType: "application/problem+json", }, { + description: "PATCH a software resource", query: "PATCH /v1/software/59803fb7-8eec-4fe5-a354-8926009c364a", body: `{"publiccodeYml": "publiccodedata", "url": "https://software-new.example.org", "aliases": ["https://software.example.com", "https://software-old.example.org"]}`, headers: map[string][]string{ @@ -1845,6 +1846,7 @@ func TestSoftwareEndpoints(t *testing.T) { expectedCode: 200, expectedContentType: "application/json", validateFunc: func(t *testing.T, response map[string]interface{}) { + assert.Equal(t, true, response["active"]) assert.Equal(t, "https://software-new.example.org", response["url"]) assert.IsType(t, []interface{}{}, response["aliases"]) @@ -1881,16 +1883,17 @@ func TestSoftwareEndpoints(t *testing.T) { expectedCode: 200, expectedContentType: "application/json", + expectedBody: "", validateFunc: func(t *testing.T, response map[string]interface{}) { + assert.Equal(t, true, response["active"]) assert.Equal(t, "https://software-new.example.org", response["url"]) assert.IsType(t, []interface{}{}, response["aliases"]) aliases := response["aliases"].([]interface{}) - assert.Equal(t, 2, len(aliases)) + assert.Equal(t, 1, len(aliases)) - assert.Equal(t, "https://18-a.example.org/code/repo", aliases[0]) - assert.Equal(t, "https://18-b.example.org/code/repo", aliases[1]) + assert.Equal(t, "https://18-b.example.org/code/repo", aliases[0]) assert.Equal(t, "publiccodedata", response["publiccodeYml"]) @@ -1919,6 +1922,7 @@ func TestSoftwareEndpoints(t *testing.T) { expectedCode: 200, expectedContentType: "application/json", validateFunc: func(t *testing.T, response map[string]interface{}) { + assert.Equal(t, true, response["active"]) assert.Equal(t, "https://software-new.example.org", response["url"]) assert.IsType(t, []interface{}{}, response["aliases"]) @@ -1941,6 +1945,118 @@ func TestSoftwareEndpoints(t *testing.T) { assert.Greater(t, updated, created) }, }, + { + description: "PATCH software with an already existing URL (of another software)", + query: "PATCH /v1/software/59803fb7-8eec-4fe5-a354-8926009c364a", + body: `{"publiccodeYml": "publiccodedata", "url": "https://21-b.example.org/code/repo"}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + + expectedCode: 409, + expectedContentType: "application/problem+json", + expectedBody: `{"title":"can't update Software","detail":"URL already exists","status":409}`, + }, + { + description: "PATCH software, change active", + query: "PATCH /v1/software/59803fb7-8eec-4fe5-a354-8926009c364a", + body: `{"active": false}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + + expectedCode: 200, + expectedContentType: "application/json", + validateFunc: func(t *testing.T, response map[string]interface{}) { + assert.Equal(t, false, response["active"]) + assert.Equal(t, "https://18-a.example.org/code/repo", response["url"]) + + assert.IsType(t, []interface{}{}, response["aliases"]) + + aliases := response["aliases"].([]interface{}) + assert.Equal(t, 1, len(aliases)) + + assert.Equal(t, "https://18-b.example.org/code/repo", aliases[0]) + + assert.Equal(t, "-", response["publiccodeYml"]) + + match, err := regexp.MatchString(UUID_REGEXP, response["id"].(string)) + assert.Nil(t, err) + assert.True(t, match) + + created, err := time.Parse(time.RFC3339, response["createdAt"].(string)) + assert.Nil(t, err) + + updated, err := time.Parse(time.RFC3339, response["updatedAt"].(string)) + assert.Nil(t, err) + + assert.Greater(t, updated, created) + }, + }, + { + description: "PATCH software, switch url and alias", + query: "PATCH /v1/software/59803fb7-8eec-4fe5-a354-8926009c364a", + body: `{"url": "https://18-b.example.org/code/repo", "aliases": ["https://18-a.example.org/code/repo"]}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + + expectedCode: 200, + expectedContentType: "application/json", + validateFunc: func(t *testing.T, response map[string]interface{}) { + assert.Equal(t, "https://18-b.example.org/code/repo", response["url"]) + + assert.IsType(t, []interface{}{}, response["aliases"]) + + aliases := response["aliases"].([]interface{}) + assert.Equal(t, 1, len(aliases)) + + assert.Equal(t, "https://18-a.example.org/code/repo", aliases[0]) + + assert.Equal(t, "-", response["publiccodeYml"]) + + match, err := regexp.MatchString(UUID_REGEXP, response["id"].(string)) + assert.Nil(t, err) + assert.True(t, match) + + created, err := time.Parse(time.RFC3339, response["createdAt"].(string)) + assert.Nil(t, err) + + updated, err := time.Parse(time.RFC3339, response["updatedAt"].(string)) + assert.Nil(t, err) + + assert.Greater(t, updated, created) + }, + }, + { + description: "PATCH software using an already taken URL as url", + query: "PATCH /v1/software/59803fb7-8eec-4fe5-a354-8926009c364a", + body: `{"url": "https://15-b.example.org/code/repo"}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + + expectedCode: 409, + expectedContentType: "application/problem+json", + expectedBody: `{"title":"can't update Software","detail":"URL already exists","status":409}`, + }, + { + description: "PATCH software using an already taken URL as an alias", + query: "PATCH /v1/software/59803fb7-8eec-4fe5-a354-8926009c364a", + body: `{"aliases": ["https://16-b.example.org/code/repo"]}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + + expectedCode: 409, + expectedContentType: "application/problem+json", + expectedBody: `{"title":"can't update Software","detail":"URL already exists","status":409}`, + }, { description: "PATCH software - wrong token", query: "PATCH /v1/software/59803fb7-8eec-4fe5-a354-8926009c364a", @@ -2006,6 +2122,19 @@ func TestSoftwareEndpoints(t *testing.T) { } }, }, + { + description: "PATCH software with an empty url", + query: "PATCH /v1/software/59803fb7-8eec-4fe5-a354-8926009c364a", + body: `{"url": ""}`, + headers: map[string][]string{ + "Authorization": {goodToken}, + "Content-Type": {"application/json"}, + }, + + expectedCode: 422, + expectedContentType: "application/problem+json", + expectedBody: `{"title":"can't update Software","detail":"invalid format: url is invalid","status":422,"validationErrors":[{"field":"url","rule":"url","value":""}]}`, + }, { description: "PATCH software with empty body", query: "PATCH /v1/software/59803fb7-8eec-4fe5-a354-8926009c364a", From e8dbc18cacba65b558805ad12f6a37c9927e759c Mon Sep 17 00:00:00 2001 From: Thomas Introini Date: Fri, 20 Oct 2023 15:17:15 +0200 Subject: [PATCH 46/54] feat: implement from and to in GET publishers (#216) Fix #214 --- developers-italia.oas.yaml | 14 ++++++++++ internal/handlers/publishers.go | 9 +++++++ main_test.go | 47 +++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/developers-italia.oas.yaml b/developers-italia.oas.yaml index ddecee7..0531c81 100644 --- a/developers-italia.oas.yaml +++ b/developers-italia.oas.yaml @@ -729,6 +729,20 @@ paths: in: query name: 'page[after]' description: Only results after this cursor + - schema: + type: string + format: date-time + example: '2022-06-07T09:56:23Z' + in: query + name: from + description: Only publishers created after this time (RFC 3339 datetime) + - schema: + type: string + format: date-time + example: '2022-06-07T14:56:23Z' + in: query + name: to + description: Only publishers created before this time (RFC 3339 datetime) post: summary: Create a new Publisher description: Create a new Publisher diff --git a/internal/handlers/publishers.go b/internal/handlers/publishers.go index 86705db..f47bd8b 100644 --- a/internal/handlers/publishers.go +++ b/internal/handlers/publishers.go @@ -43,6 +43,15 @@ func (p *Publisher) GetPublishers(ctx *fiber.Ctx) error { stmt := p.db.Preload("CodeHosting") + stmt, err := general.Clauses(ctx, stmt, "") + if err != nil { + return common.Error( + fiber.StatusUnprocessableEntity, + "can't get Publishers", + err.Error(), + ) + } + if all := ctx.QueryBool("all", false); !all { stmt = stmt.Scopes(models.Active) } diff --git a/main_test.go b/main_test.go index 2969f42..32ec52a 100644 --- a/main_test.go +++ b/main_test.go @@ -383,6 +383,53 @@ func TestPublishersEndpoints(t *testing.T) { assert.Equal(t, "wrong cursor format in page[after] or page[before]", response["detail"]) }, }, + { + description: `GET with "from" query param`, + query: "GET /v1/publishers?from=2018-11-10T00:56:23Z", + + expectedCode: 200, + expectedContentType: "application/json", + validateFunc: func(t *testing.T, response map[string]interface{}) { + assert.IsType(t, []interface{}{}, response["data"]) + data := response["data"].([]interface{}) + + assert.Equal(t, 14, len(data)) + }, + }, + { + description: `GET with invalid "from" query param`, + query: "GET /v1/publishers?from=3", + + expectedCode: 422, + expectedContentType: "application/problem+json", + validateFunc: func(t *testing.T, response map[string]interface{}) { + assert.Equal(t, `can't get Publishers`, response["title"]) + assert.Equal(t, "invalid date time format (RFC 3339 needed)", response["detail"]) + }, + }, + { + description: `GET with "to" query param`, + query: "GET /v1/publishers?to=2018-11-01T09:56:23Z", + + expectedCode: 200, + expectedContentType: "application/json", + validateFunc: func(t *testing.T, response map[string]interface{}) { + data := response["data"].([]interface{}) + + assert.Equal(t, 13, len(data)) + }, + }, + { + description: `GET with invalid "to" query param`, + query: "GET /v1/publishers?to=3", + + expectedCode: 422, + expectedContentType: "application/problem+json", + validateFunc: func(t *testing.T, response map[string]interface{}) { + assert.Equal(t, `can't get Publishers`, response["title"]) + assert.Equal(t, "invalid date time format (RFC 3339 needed)", response["detail"]) + }, + }, // GET /publishers/:id { From 100853dda2b969aac75d2ff7429c398198eb995c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 4 Nov 2023 14:50:10 +0100 Subject: [PATCH 47/54] chore(deps): bump github.com/gofiber/fiber/v2 from 2.46.0 to 2.50.0 (#217) Bumps [github.com/gofiber/fiber/v2](https://github.com/gofiber/fiber) from 2.46.0 to 2.50.0. - [Release notes](https://github.com/gofiber/fiber/releases) - [Commits](https://github.com/gofiber/fiber/compare/v2.46.0...v2.50.0) --- updated-dependencies: - dependency-name: github.com/gofiber/fiber/v2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 19 ++++++++----------- go.sum | 42 +++++++++++++++--------------------------- 2 files changed, 23 insertions(+), 38 deletions(-) diff --git a/go.mod b/go.mod index d458dc9..016c932 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/go-playground/validator/v10 v10.11.0 github.com/go-testfixtures/testfixtures/v3 v3.8.0 github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e - github.com/gofiber/fiber/v2 v2.46.0 + github.com/gofiber/fiber/v2 v2.50.0 github.com/stretchr/testify v1.8.1 gorm.io/driver/postgres v1.5.2 gorm.io/driver/sqlite v1.5.2 @@ -17,6 +17,7 @@ require ( require ( github.com/ansrivas/fiberprometheus/v2 v2.4.1 + github.com/evanphx/json-patch v0.5.2 golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 ) @@ -27,8 +28,8 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/lib/pq v1.10.9 github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.18 // indirect - github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mattn/go-sqlite3 v1.14.17 github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/philhofer/fwd v1.1.2 // indirect @@ -37,8 +38,6 @@ require ( github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect github.com/rivo/uniseg v0.2.0 // indirect - github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect - github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect github.com/tinylib/msgp v1.1.8 // indirect golang.org/x/net v0.9.0 // indirect google.golang.org/protobuf v1.26.0 // indirect @@ -48,7 +47,7 @@ require ( github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect github.com/aead/chacha20poly1305 v0.0.0-20201124145622-1a5aba2a8b29 // indirect github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.3.1 // indirect github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7 // indirect github.com/o1egl/paseto v1.0.0 github.com/pilagod/gorm-cursor-paginator/v2 v2.3.0 @@ -57,8 +56,6 @@ require ( require ( github.com/andybalholm/brotli v1.0.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/evanphx/json-patch v0.5.2 // indirect - github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect @@ -66,15 +63,15 @@ require ( github.com/jackc/pgx/v5 v5.3.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - github.com/klauspost/compress v1.16.3 // indirect + github.com/klauspost/compress v1.16.7 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.47.0 // indirect + github.com/valyala/fasthttp v1.50.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect golang.org/x/crypto v0.8.0 // indirect - golang.org/x/sys v0.8.0 // indirect + golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.9.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 8c11bb8..3fbc7da 100644 --- a/go.sum +++ b/go.sum @@ -82,8 +82,6 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= -github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= -github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= 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= @@ -111,8 +109,8 @@ github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e h1:ZsZeaEFE github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e/go.mod h1:zU7RONlVB7dBKM0EijoExlxAWJtevT5+9RqAH2imOUI= github.com/gofiber/fiber/v2 v2.34.1/go.mod h1:ozRQfS+D7EL1+hMH+gutku0kfx1wLX4hAxDCtDzpj4U= github.com/gofiber/fiber/v2 v2.36.0/go.mod h1:tgCr+lierLwLoVHHO/jn3Niannv34WRkQETU8wiL9fQ= -github.com/gofiber/fiber/v2 v2.46.0 h1:wkkWotblsGVlLjXj2dpgKQAYHtXumsK/HyFugQM68Ns= -github.com/gofiber/fiber/v2 v2.46.0/go.mod h1:DNl0/c37WLe0g92U6lx1VMQuxGUQY5V7EIaVoEsUffc= +github.com/gofiber/fiber/v2 v2.50.0 h1:ia0JaB+uw3GpNSCR5nvC5dsaxXjRU5OEu36aytx+zGw= +github.com/gofiber/fiber/v2 v2.50.0/go.mod h1:21eytvay9Is7S6z+OgPi7c7n4++tnClWmhpimVHMimw= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= @@ -168,8 +166,9 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -195,6 +194,7 @@ github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bY github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= 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/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= @@ -249,8 +249,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= -github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -283,10 +283,10 @@ 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-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= -github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= -github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +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-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= @@ -301,7 +301,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/o1egl/paseto v1.0.0 h1:bwpvPu2au176w4IBlhbyUv/S5VPptERIA99Oap5qUd0= github.com/o1egl/paseto v1.0.0/go.mod h1:5HxsZPmw/3RI2pAwGo1HhOOwSdvBpcuVzO7uDkm+CLU= -github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/pilagod/gorm-cursor-paginator/v2 v2.3.0 h1:/jMv0+CtmpF5gf8Fn0JwgFsKcVrmvhPahHluHEcP13I= @@ -346,11 +345,6 @@ github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4= -github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8= -github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4= -github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= -github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -372,21 +366,19 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw= github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.37.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= github.com/valyala/fasthttp v1.38.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= -github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c= -github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= +github.com/valyala/fasthttp v1.50.0 h1:H7fweIlBm0rXLs2q0XbalvJ6r0CUPFWK3/bB4N13e9M= +github.com/valyala/fasthttp v1.50.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -481,7 +473,6 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -504,7 +495,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -545,7 +535,6 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -560,8 +549,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= @@ -622,7 +611,6 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From d9aac4c749fec726fa1f351c0a03b5e41e5e76d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 4 Nov 2023 14:54:01 +0100 Subject: [PATCH 48/54] chore(deps): bump golang.org/x/net from 0.9.0 to 0.17.0 (#218) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.9.0 to 0.17.0. - [Commits](https://github.com/golang/net/compare/v0.9.0...v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 016c932..08f7c53 100644 --- a/go.mod +++ b/go.mod @@ -39,7 +39,7 @@ require ( github.com/prometheus/procfs v0.7.3 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/tinylib/msgp v1.1.8 // indirect - golang.org/x/net v0.9.0 // indirect + golang.org/x/net v0.17.0 // indirect google.golang.org/protobuf v1.26.0 // indirect ) @@ -70,8 +70,8 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.50.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - golang.org/x/crypto v0.8.0 // indirect + golang.org/x/crypto v0.14.0 // indirect golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/text v0.13.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 3fbc7da..4cb3a96 100644 --- a/go.sum +++ b/go.sum @@ -408,8 +408,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= -golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -479,8 +479,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -562,8 +562,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 52a1c9da034181ade81617e276154ca9bbf98ac8 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Sun, 12 Nov 2023 16:35:58 +0100 Subject: [PATCH 49/54] chore(deps): use lastest version of jsonpatch library (#219) --- go.mod | 2 +- go.sum | 5 ++--- internal/handlers/software.go | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 08f7c53..e0afa5d 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( require ( github.com/ansrivas/fiberprometheus/v2 v2.4.1 - github.com/evanphx/json-patch v0.5.2 + github.com/evanphx/json-patch/v5 v5.7.0 golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 ) diff --git a/go.sum b/go.sum index 4cb3a96..db0319c 100644 --- a/go.sum +++ b/go.sum @@ -80,8 +80,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF 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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k= -github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= +github.com/evanphx/json-patch/v5 v5.7.0 h1:nJqP7uwL84RJInrohHfW0Fx3awjbm8qZeFv0nW9SYGc= +github.com/evanphx/json-patch/v5 v5.7.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= 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= @@ -230,7 +230,6 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= 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.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= diff --git a/internal/handlers/software.go b/internal/handlers/software.go index 9ba4343..cb83a92 100644 --- a/internal/handlers/software.go +++ b/internal/handlers/software.go @@ -14,7 +14,7 @@ import ( "github.com/italia/developers-italia-api/internal/models" "gorm.io/gorm" - jsonpatch "github.com/evanphx/json-patch" + jsonpatch "github.com/evanphx/json-patch/v5" ) type SoftwareInterface interface { From 62a3bc6377035a1c4c8b3caf43b153d2dac748c2 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Fri, 17 Nov 2023 13:14:45 +0100 Subject: [PATCH 50/54] chore: add publiccode.yml (#220) Add publiccode.yml and CI validation for it. Fix #107. --- .../workflows/publiccode-yml-validation.yml | 14 ++++ publiccode.yml | 64 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 .github/workflows/publiccode-yml-validation.yml create mode 100644 publiccode.yml diff --git a/.github/workflows/publiccode-yml-validation.yml b/.github/workflows/publiccode-yml-validation.yml new file mode 100644 index 0000000..41b97a4 --- /dev/null +++ b/.github/workflows/publiccode-yml-validation.yml @@ -0,0 +1,14 @@ +on: [pull_request] + +jobs: + publiccode_yml_validation: + runs-on: ubuntu-latest + name: publiccode.yml validation + steps: + - uses: actions/checkout@v2 + - uses: italia/publiccode-parser-action@v1 + with: + publiccode: 'publiccode.yml' + comment-on-pr: true + env: + REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/publiccode.yml b/publiccode.yml new file mode 100644 index 0000000..9ebe916 --- /dev/null +++ b/publiccode.yml @@ -0,0 +1,64 @@ +# This repository adheres to the publiccode.yml standard by including this +# metadata file that makes public software easily discoverable. +# More info at https://github.com/publiccodeyml/publiccode.yml + +publiccodeYmlVersion: '0.3' +categories: + - data-collection +description: + it: + apiDocumentation: 'https://developers.italia.it/it/api/developers-italia' + features: + - RESTful API Design + - Can use either SQLite or PostgreSQL + - Optional rate limiting to manage the number of requests per minute. + - Containerization support + - Helm chart available + longDescription: | + **developers-italia-api** is a RESTful API for the free and open-source + software catalog aimed at Italian public administrations. This API serves + as a crucial tool in managing and accessing the software catalog, + providing a streamlined and efficient way for public administrations and + developers to interact with the repository. It's built with a focus on + ease of use and reliability, ensuring that users can effectively leverage + the catalog for their software needs. + shortDescription: |- + RESTful API for the free and open-source software catalog aimed at Italian + public administrations. This API serves +developmentStatus: beta +it: + conforme: + gdpr: false + lineeGuidaDesign: false + misureMinimeSicurezza: true + modelloInteroperabilita: true + countryExtensionVersion: '0.2' + piattaforme: + anpr: false + cie: false + pagopa: false + spid: false + riuso: + codiceIPA: pcm +legal: + license: AGPL-3.0-or-later +localisation: + availableLanguages: + - en + localisationReady: false +logo: .github/logo.png +maintenance: + contacts: + - name: Fabio Bonelli + type: community +name: developers-italia-api +platforms: + - web +dependsOn: + open: + - name: PostgreSQL + optional: true +releaseDate: '2023-11-04' +softwareType: standalone/backend +softwareVersion: v0.10.1 +url: 'https://github.com/italia/developers-italia-api' From 61cc7d8f97ffd02f4a0267c8e3d94e0cb439b59c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 10:22:05 +0100 Subject: [PATCH 51/54] chore(deps): bump golang.org/x/crypto from 0.14.0 to 0.17.0 (#222) Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0. - [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index e0afa5d..dae7fa4 100644 --- a/go.mod +++ b/go.mod @@ -70,8 +70,8 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.50.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/crypto v0.17.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index db0319c..10cf39a 100644 --- a/go.sum +++ b/go.sum @@ -407,8 +407,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -548,8 +548,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= @@ -561,8 +561,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From cef9f0ebc6218cdf76a9f44ec361af2768ddb7c7 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Sat, 24 Feb 2024 12:14:49 +0100 Subject: [PATCH 52/54] chore: pin the version of golangci-lint (#228) Fix #227. --- .github/workflows/lint.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 158ff1f..d38ce63 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -14,4 +14,5 @@ jobs: go-version: 1.18.x - uses: golangci/golangci-lint-action@v3 with: + version: v1.55.2 args: --timeout 3m --verbose From e610b03ab0c2fb1ce06b920051df12a93bbbc5cf Mon Sep 17 00:00:00 2001 From: Richard R <137314274+richardrdev@users.noreply.github.com> Date: Sat, 2 Mar 2024 15:02:12 -0500 Subject: [PATCH 53/54] feat: make use of application/problem+json support in Gofiber v2.51.0 (#226) Fix #225. --- go.mod | 6 +- go.sum | 12 ++-- internal/common/errors.go | 8 +-- main_test.go | 128 +++++++++++++++++++------------------- 4 files changed, 75 insertions(+), 79 deletions(-) diff --git a/go.mod b/go.mod index dae7fa4..6c17623 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/go-playground/validator/v10 v10.11.0 github.com/go-testfixtures/testfixtures/v3 v3.8.0 github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e - github.com/gofiber/fiber/v2 v2.50.0 + github.com/gofiber/fiber/v2 v2.51.0 github.com/stretchr/testify v1.8.1 gorm.io/driver/postgres v1.5.2 gorm.io/driver/sqlite v1.5.2 @@ -28,7 +28,7 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/lib/pq v1.10.9 github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mattn/go-sqlite3 v1.14.17 github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect @@ -47,7 +47,7 @@ require ( github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect github.com/aead/chacha20poly1305 v0.0.0-20201124145622-1a5aba2a8b29 // indirect github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect - github.com/google/uuid v1.3.1 // indirect + github.com/google/uuid v1.4.0 // indirect github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7 // indirect github.com/o1egl/paseto v1.0.0 github.com/pilagod/gorm-cursor-paginator/v2 v2.3.0 diff --git a/go.sum b/go.sum index 10cf39a..57139c7 100644 --- a/go.sum +++ b/go.sum @@ -109,8 +109,8 @@ github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e h1:ZsZeaEFE github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e/go.mod h1:zU7RONlVB7dBKM0EijoExlxAWJtevT5+9RqAH2imOUI= github.com/gofiber/fiber/v2 v2.34.1/go.mod h1:ozRQfS+D7EL1+hMH+gutku0kfx1wLX4hAxDCtDzpj4U= github.com/gofiber/fiber/v2 v2.36.0/go.mod h1:tgCr+lierLwLoVHHO/jn3Niannv34WRkQETU8wiL9fQ= -github.com/gofiber/fiber/v2 v2.50.0 h1:ia0JaB+uw3GpNSCR5nvC5dsaxXjRU5OEu36aytx+zGw= -github.com/gofiber/fiber/v2 v2.50.0/go.mod h1:21eytvay9Is7S6z+OgPi7c7n4++tnClWmhpimVHMimw= +github.com/gofiber/fiber/v2 v2.51.0 h1:JNACcZy5e2tGApWB2QrRpenTWn0fq0hkFm6k0C86gKQ= +github.com/gofiber/fiber/v2 v2.51.0/go.mod h1:xaQRZQJGqnKOQnbQw+ltvku3/h8QxvNi8o6JiJ7Ll0U= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= @@ -167,8 +167,8 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -282,8 +282,8 @@ 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-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-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= diff --git a/internal/common/errors.go b/internal/common/errors.go index 95859c5..f0c34a0 100644 --- a/internal/common/errors.go +++ b/internal/common/errors.go @@ -51,11 +51,7 @@ func CustomErrorHandler(ctx *fiber.Ctx, err error) error { } } - err = ctx.Status(problemJSON.Status).JSON(problemJSON) + ctx.Status(problemJSON.Status) - // Needs to be after the call to JSON(), to override the - // automatic Content-Type - ctx.Set(fiber.HeaderContentType, "application/problem+json") - - return err + return ctx.JSON(problemJSON, "application/problem+json") } diff --git a/main_test.go b/main_test.go index 32ec52a..9326610 100644 --- a/main_test.go +++ b/main_test.go @@ -17,8 +17,8 @@ import ( "github.com/gofiber/fiber/v2" "github.com/stretchr/testify/assert" - _ "github.com/mattn/go-sqlite3" _ "github.com/lib/pq" + _ "github.com/mattn/go-sqlite3" ) const UUID_REGEXP = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" @@ -35,9 +35,9 @@ type TestCase struct { description string // Test input - query string - body string - headers map[string][]string + query string + body string + headers map[string][]string // Expected output expectedCode int @@ -552,8 +552,8 @@ func TestPublishersEndpoints(t *testing.T) { }, { description: "POST publisher with duplicate alternativeId", - query: "POST /v1/publishers", - body: `{"alternativeId": "alternative-id-12345", "description":"new description", "codeHosting": [{"url" : "https://example-testcase-xx3.com"}], "email":"example-testcase-3-pass@example.com"}`, + query: "POST /v1/publishers", + body: `{"alternativeId": "alternative-id-12345", "description":"new description", "codeHosting": [{"url" : "https://example-testcase-xx3.com"}], "email":"example-testcase-3-pass@example.com"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -564,8 +564,8 @@ func TestPublishersEndpoints(t *testing.T) { }, { description: "POST publisher with alternativeId matching an existing id", - query: "POST /v1/publishers", - body: `{"alternativeId": "2ded32eb-c45e-4167-9166-a44e18b8adde", "description":"new description", "codeHosting": [{"url" : "https://example-testcase-xx3.com"}]}`, + query: "POST /v1/publishers", + body: `{"alternativeId": "2ded32eb-c45e-4167-9166-a44e18b8adde", "description":"new description", "codeHosting": [{"url" : "https://example-testcase-xx3.com"}]}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -576,8 +576,8 @@ func TestPublishersEndpoints(t *testing.T) { }, { description: "POST publisher with empty alternativeId", - query: "POST /v1/publishers", - body: `{"alternativeId": "", "description":"new description", "codeHosting": [{"url" : "https://gitlab.example.com/repo"}]}`, + query: "POST /v1/publishers", + body: `{"alternativeId": "", "description":"new description", "codeHosting": [{"url" : "https://gitlab.example.com/repo"}]}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -616,7 +616,7 @@ func TestPublishersEndpoints(t *testing.T) { { description: "POST publishers with duplicate URL (when normalized)", query: "POST /v1/publishers", - body: `{"codeHosting": [{"url" : "https://1-a.exAMple.org/code/repo"}], "description":"new description"}`, + body: `{"codeHosting": [{"url" : "https://1-a.exAMple.org/code/repo"}], "description":"new description"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -640,9 +640,9 @@ func TestPublishersEndpoints(t *testing.T) { }, }, { - description: "POST new publisher with an existing email (not normalized)", - query: "POST /v1/publishers", - body: `{"codeHosting": [{"url" : "https://new-url.example.com"}], "email":"FoobaR@1.example.org", "description": "new publisher description"}`, + description: "POST new publisher with an existing email (not normalized)", + query: "POST /v1/publishers", + body: `{"codeHosting": [{"url" : "https://new-url.example.com"}], "email":"FoobaR@1.example.org", "description": "new publisher description"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -654,9 +654,9 @@ func TestPublishersEndpoints(t *testing.T) { }, }, { - description: "POST new publisher with no email", - query: "POST /v1/publishers", - body: `{"codeHosting": [{"url" : "https://new-url.example.com"}], "description": "new publisher description"}`, + description: "POST new publisher with no email", + query: "POST /v1/publishers", + body: `{"codeHosting": [{"url" : "https://new-url.example.com"}], "description": "new publisher description"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -671,9 +671,9 @@ func TestPublishersEndpoints(t *testing.T) { }, }, { - description: "POST new publisher with empty email", - query: "POST /v1/publishers", - body: `{"email": "", "codeHosting": [{"url" : "https://new-url.example.com"}], "description": "new publisher description"}`, + description: "POST new publisher with empty email", + query: "POST /v1/publishers", + body: `{"email": "", "codeHosting": [{"url" : "https://new-url.example.com"}], "description": "new publisher description"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -683,8 +683,8 @@ func TestPublishersEndpoints(t *testing.T) { expectedBody: `{"title":"can't create Publisher","detail":"invalid format: email is not a valid email","status":422,"validationErrors":[{"field":"email","rule":"email","value":""}]}`, }, { - query: "POST /v1/publishers - Description already exist", - body: `{"codeHosting": [{"url" : "https://example-testcase-xx3.com"}], "description": "Publisher description 1"}`, + query: "POST /v1/publishers - Description already exist", + body: `{"codeHosting": [{"url" : "https://example-testcase-xx3.com"}], "description": "Publisher description 1"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -719,8 +719,8 @@ func TestPublishersEndpoints(t *testing.T) { }, { description: "POST publisher with duplicate alternativeId", - query: "POST /v1/publishers", - body: `{"alternativeId": "alternative-id-12345", "description":"new description", "codeHosting": [{"url" : "https://example-testcase-xx3.com"}]}`, + query: "POST /v1/publishers", + body: `{"alternativeId": "alternative-id-12345", "description":"new description", "codeHosting": [{"url" : "https://example-testcase-xx3.com"}]}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -859,8 +859,8 @@ func TestPublishersEndpoints(t *testing.T) { }, { description: "PATCH a publisher", - query: "PATCH /v1/publishers/2ded32eb-c45e-4167-9166-a44e18b8adde", - body: `{"description": "new PATCHed description", "codeHosting": [{"url": "https://gitlab.example.org/patched-repo"}]}`, + query: "PATCH /v1/publishers/2ded32eb-c45e-4167-9166-a44e18b8adde", + body: `{"description": "new PATCHed description", "codeHosting": [{"url": "https://gitlab.example.org/patched-repo"}]}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -935,12 +935,12 @@ func TestPublishersEndpoints(t *testing.T) { expectedCode: 422, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't update Publisher","detail":"invalid format: codeHosting does not meet its size limits (too few items)","status":422,"validationErrors":[{"field":"codeHosting","rule":"gt","value":""}]}`, + expectedBody: `{"title":"can't update Publisher","detail":"invalid format: codeHosting does not meet its size limits (too few items)","status":422,"validationErrors":[{"field":"codeHosting","rule":"gt","value":""}]}`, }, { description: "PATCH a publisher via alternativeId", - query: "PATCH /v1/publishers/alternative-id-12345", - body: `{"description": "new PATCHed description via alternativeId", "codeHosting": [{"url": "https://gitlab.example.org/patched-repo"}]}`, + query: "PATCH /v1/publishers/alternative-id-12345", + body: `{"description": "new PATCHed description via alternativeId", "codeHosting": [{"url": "https://gitlab.example.org/patched-repo"}]}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -970,8 +970,8 @@ func TestPublishersEndpoints(t *testing.T) { }, { description: "PATCH a publisher with alternativeId matching an existing id", - query: "PATCH /v1/publishers/2ded32eb-c45e-4167-9166-a44e18b8adde", - body: `{"alternativeId": "47807e0c-0613-4aea-9917-5455cc6eddad"}`, + query: "PATCH /v1/publishers/2ded32eb-c45e-4167-9166-a44e18b8adde", + body: `{"alternativeId": "47807e0c-0613-4aea-9917-5455cc6eddad"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -1010,14 +1010,14 @@ func TestPublishersEndpoints(t *testing.T) { { description: "PATCH publishers with JSON with extra fields", query: "PATCH /v1/publishers/2ded32eb-c45e-4167-9166-a44e18b8adde", - body: `{"description": "new description", "EXTRA_FIELD": "extra field not in schema"}`, + body: `{"description": "new description", "EXTRA_FIELD": "extra field not in schema"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, }, expectedCode: 422, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't update Publisher","detail":"unknown field in JSON input","status":422}`, + expectedBody: `{"title":"can't update Publisher","detail":"unknown field in JSON input","status":422}`, }, { description: "PATCH publisher with validation errors", @@ -1029,7 +1029,7 @@ func TestPublishersEndpoints(t *testing.T) { }, expectedCode: 422, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't update Publisher","detail":"invalid format: url is invalid","status":422,"validationErrors":[{"field":"url","rule":"url","value":"INVALID_URL"}]}`, + expectedBody: `{"title":"can't update Publisher","detail":"invalid format: url is invalid","status":422,"validationErrors":[{"field":"url","rule":"url","value":"INVALID_URL"}]}`, }, { description: "PATCH publishers with empty body", @@ -1041,7 +1041,7 @@ func TestPublishersEndpoints(t *testing.T) { }, expectedCode: 400, expectedContentType: "application/problem+json", - expectedBody: `{"title":"can't update Publisher","detail":"invalid or malformed JSON","status":400}`, + expectedBody: `{"title":"can't update Publisher","detail":"invalid or malformed JSON","status":400}`, }, // TODO: enforce this? // { @@ -1077,7 +1077,7 @@ func TestPublishersEndpoints(t *testing.T) { expectedContentType: "application/problem+json", }, { - query: "DELETE /v1/publishers/15fda7c4-6bbf-4387-8f89-258c1e6fafb1", + query: "DELETE /v1/publishers/15fda7c4-6bbf-4387-8f89-258c1e6fafb1", headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -1088,7 +1088,7 @@ func TestPublishersEndpoints(t *testing.T) { }, { description: "DELETE publisher via alternativeId", - query: "DELETE /v1/publishers/alternative-id-12345", + query: "DELETE /v1/publishers/alternative-id-12345", headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -1102,7 +1102,7 @@ func TestPublishersEndpoints(t *testing.T) { // GET /publishers/:id/webhooks { - query: "GET /v1/publishers/47807e0c-0613-4aea-9917-5455cc6eddad/webhooks", + query: "GET /v1/publishers/47807e0c-0613-4aea-9917-5455cc6eddad/webhooks", expectedCode: 200, expectedContentType: "application/json", @@ -1192,8 +1192,8 @@ func TestPublishersEndpoints(t *testing.T) { }, }, { - query: "POST /v1/publishers/98a069f7-57b0-464d-b300-4b4b336297a0/webhooks", - body: `{"url": "https://new.example.org", "secret": "xyz"}`, + query: "POST /v1/publishers/98a069f7-57b0-464d-b300-4b4b336297a0/webhooks", + body: `{"url": "https://new.example.org", "secret": "xyz"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -1250,7 +1250,7 @@ func TestPublishersEndpoints(t *testing.T) { { description: "POST /v1/publishers/98a069f7-57b0-464d-b300-4b4b336297a0/webhooks with JSON with extra fields", query: "POST /v1/publishers/98a069f7-57b0-464d-b300-4b4b336297a0/webhooks", - body: `{"url": "https://new.example.org", "EXTRA_FIELD": "extra field not in schema"}`, + body: `{"url": "https://new.example.org", "EXTRA_FIELD": "extra field not in schema"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -1794,7 +1794,7 @@ func TestSoftwareEndpoints(t *testing.T) { { description: "POST /v1/software with JSON with extra fields", query: "POST /v1/software", - body: `{"publiccodeYml": "-", "EXTRA_FIELD": "extra field not in schema"}`, + body: `{"publiccodeYml": "-", "EXTRA_FIELD": "extra field not in schema"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -1883,8 +1883,8 @@ func TestSoftwareEndpoints(t *testing.T) { }, { description: "PATCH a software resource", - query: "PATCH /v1/software/59803fb7-8eec-4fe5-a354-8926009c364a", - body: `{"publiccodeYml": "publiccodedata", "url": "https://software-new.example.org", "aliases": ["https://software.example.com", "https://software-old.example.org"]}`, + query: "PATCH /v1/software/59803fb7-8eec-4fe5-a354-8926009c364a", + body: `{"publiccodeYml": "publiccodedata", "url": "https://software-new.example.org", "aliases": ["https://software.example.com", "https://software-old.example.org"]}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -1930,7 +1930,7 @@ func TestSoftwareEndpoints(t *testing.T) { expectedCode: 200, expectedContentType: "application/json", - expectedBody: "", + expectedBody: "", validateFunc: func(t *testing.T, response map[string]interface{}) { assert.Equal(t, true, response["active"]) assert.Equal(t, "https://software-new.example.org", response["url"]) @@ -2209,8 +2209,8 @@ func TestSoftwareEndpoints(t *testing.T) { // DELETE /software/:id { - description: "Delete non-existent software", - query: "DELETE /v1/software/eea19c82-0449-11ed-bd84-d8bbc146d165", + description: "Delete non-existent software", + query: "DELETE /v1/software/eea19c82-0449-11ed-bd84-d8bbc146d165", headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -2231,7 +2231,7 @@ func TestSoftwareEndpoints(t *testing.T) { expectedContentType: "application/problem+json", }, { - query: "DELETE /v1/software/11e101c4-f989-4cc4-a665-63f9f34e83f6", + query: "DELETE /v1/software/11e101c4-f989-4cc4-a665-63f9f34e83f6", headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -2244,7 +2244,7 @@ func TestSoftwareEndpoints(t *testing.T) { // GET /software/:id/logs { - query: "GET /v1/software/c353756e-8597-4e46-a99b-7da2e141603b/logs", + query: "GET /v1/software/c353756e-8597-4e46-a99b-7da2e141603b/logs", expectedCode: 200, expectedContentType: "application/json", @@ -2342,8 +2342,8 @@ func TestSoftwareEndpoints(t *testing.T) { }, }, { - query: "POST /v1/software/c353756e-8597-4e46-a99b-7da2e141603b/logs", - body: `{"message": "New software log from test suite"}`, + query: "POST /v1/software/c353756e-8597-4e46-a99b-7da2e141603b/logs", + body: `{"message": "New software log from test suite"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -2398,7 +2398,7 @@ func TestSoftwareEndpoints(t *testing.T) { { description: "POST /v1/software/c353756e-8597-4e46-a99b-7da2e141603b/logs with JSON with extra fields", query: "POST /v1/software/c353756e-8597-4e46-a99b-7da2e141603b/logs", - body: `{"message": "new log", "EXTRA_FIELD": "extra field not in schema"}`, + body: `{"message": "new log", "EXTRA_FIELD": "extra field not in schema"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -2460,7 +2460,7 @@ func TestSoftwareEndpoints(t *testing.T) { // GET /software/:id/webhooks { - query: "GET /v1/software/c5dec6fa-8a01-4881-9e7d-132770d4214d/webhooks", + query: "GET /v1/software/c5dec6fa-8a01-4881-9e7d-132770d4214d/webhooks", expectedCode: 200, expectedContentType: "application/json", @@ -2550,8 +2550,8 @@ func TestSoftwareEndpoints(t *testing.T) { }, }, { - query: "POST /v1/software/c5dec6fa-8a01-4881-9e7d-132770d4214d/webhooks", - body: `{"url": "https://new.example.org", "secret": "xyz"}`, + query: "POST /v1/software/c5dec6fa-8a01-4881-9e7d-132770d4214d/webhooks", + body: `{"url": "https://new.example.org", "secret": "xyz"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -2608,7 +2608,7 @@ func TestSoftwareEndpoints(t *testing.T) { { description: "POST /v1/software/c5dec6fa-8a01-4881-9e7d-132770d4214d/webhooks with JSON with extra fields", query: "POST /v1/software/c5dec6fa-8a01-4881-9e7d-132770d4214d/webhooks", - body: `{"url": "https://new.example.org", "EXTRA_FIELD": "extra field not in schema"}`, + body: `{"url": "https://new.example.org", "EXTRA_FIELD": "extra field not in schema"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -2941,7 +2941,7 @@ func TestLogsEndpoints(t *testing.T) { { description: "POST /v1/logs with JSON with extra fields", query: "POST /v1/logs", - body: `{"message": "new log", "EXTRA_FIELD": "extra field not in schema"}`, + body: `{"message": "new log", "EXTRA_FIELD": "extra field not in schema"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -3025,8 +3025,8 @@ func TestWebhooksEndpoints(t *testing.T) { // PATCH /webhooks/:id { - query: "PATCH /v1/webhooks/007bc84a-7e2d-43a0-b7e1-a256d4114aa7", - body: `{"url": "https://new.example.org/receiver"}`, + query: "PATCH /v1/webhooks/007bc84a-7e2d-43a0-b7e1-a256d4114aa7", + body: `{"url": "https://new.example.org/receiver"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -3076,7 +3076,7 @@ func TestWebhooksEndpoints(t *testing.T) { { description: "PATCH /v1/webhooks/007bc84a-7e2d-43a0-b7e1-a256d4114aa7 with JSON with extra fields", query: "PATCH /v1/webhooks/007bc84a-7e2d-43a0-b7e1-a256d4114aa7", - body: `{"url": "https://new.example.org/receiver", "EXTRA_FIELD": "extra field not in schema"}`, + body: `{"url": "https://new.example.org/receiver", "EXTRA_FIELD": "extra field not in schema"}`, headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, @@ -3138,13 +3138,13 @@ func TestWebhooksEndpoints(t *testing.T) { // DELETE /webhooks/:id { - description: "Delete non-existent webhook", - query: "DELETE /v1/webhooks/NO_SUCH_WEBHOOK", + description: "Delete non-existent webhook", + query: "DELETE /v1/webhooks/NO_SUCH_WEBHOOK", headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, }, - expectedCode: 404, + expectedCode: 404, // This error is different from because it's returned directly from Fiber's // route constraints, so we don't need to hit the database to find the resource // because we already know that's not a valid webhook id looking at its format. @@ -3163,7 +3163,7 @@ func TestWebhooksEndpoints(t *testing.T) { expectedContentType: "application/problem+json", }, { - query: "DELETE /v1/webhooks/24bc1b5d-fe81-47be-9d55-910f820bdd04", + query: "DELETE /v1/webhooks/24bc1b5d-fe81-47be-9d55-910f820bdd04", headers: map[string][]string{ "Authorization": {goodToken}, "Content-Type": {"application/json"}, From fbc80f7caba5489336510838acc28c0682ed5226 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 2 Mar 2024 21:28:44 +0100 Subject: [PATCH 54/54] chore(deps): bump github.com/gofiber/fiber/v2 from 2.50.0 to 2.52.1 (#223) Bumps [github.com/gofiber/fiber/v2](https://github.com/gofiber/fiber) from 2.50.0 to 2.52.1. - [Release notes](https://github.com/gofiber/fiber/releases) - [Commits](https://github.com/gofiber/fiber/compare/v2.50.0...v2.52.1) --- updated-dependencies: - dependency-name: github.com/gofiber/fiber/v2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 6c17623..59ed550 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/go-playground/validator/v10 v10.11.0 github.com/go-testfixtures/testfixtures/v3 v3.8.0 github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e - github.com/gofiber/fiber/v2 v2.51.0 + github.com/gofiber/fiber/v2 v2.52.1 github.com/stretchr/testify v1.8.1 gorm.io/driver/postgres v1.5.2 gorm.io/driver/sqlite v1.5.2 @@ -47,7 +47,7 @@ require ( github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect github.com/aead/chacha20poly1305 v0.0.0-20201124145622-1a5aba2a8b29 // indirect github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect - github.com/google/uuid v1.4.0 // indirect + github.com/google/uuid v1.5.0 // indirect github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7 // indirect github.com/o1egl/paseto v1.0.0 github.com/pilagod/gorm-cursor-paginator/v2 v2.3.0 @@ -63,12 +63,12 @@ require ( github.com/jackc/pgx/v5 v5.3.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/compress v1.17.0 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.50.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect golang.org/x/crypto v0.17.0 // indirect golang.org/x/sys v0.15.0 // indirect diff --git a/go.sum b/go.sum index 57139c7..054be10 100644 --- a/go.sum +++ b/go.sum @@ -109,8 +109,8 @@ github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e h1:ZsZeaEFE github.com/gofiber/contrib/paseto v0.0.0-20220621082844-83549332c36e/go.mod h1:zU7RONlVB7dBKM0EijoExlxAWJtevT5+9RqAH2imOUI= github.com/gofiber/fiber/v2 v2.34.1/go.mod h1:ozRQfS+D7EL1+hMH+gutku0kfx1wLX4hAxDCtDzpj4U= github.com/gofiber/fiber/v2 v2.36.0/go.mod h1:tgCr+lierLwLoVHHO/jn3Niannv34WRkQETU8wiL9fQ= -github.com/gofiber/fiber/v2 v2.51.0 h1:JNACcZy5e2tGApWB2QrRpenTWn0fq0hkFm6k0C86gKQ= -github.com/gofiber/fiber/v2 v2.51.0/go.mod h1:xaQRZQJGqnKOQnbQw+ltvku3/h8QxvNi8o6JiJ7Ll0U= +github.com/gofiber/fiber/v2 v2.52.1 h1:1RoU2NS+b98o1L77sdl5mboGPiW+0Ypsi5oLmcYlgHI= +github.com/gofiber/fiber/v2 v2.52.1/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= @@ -167,8 +167,8 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -248,8 +248,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -371,8 +371,8 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.37.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= github.com/valyala/fasthttp v1.38.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= -github.com/valyala/fasthttp v1.50.0 h1:H7fweIlBm0rXLs2q0XbalvJ6r0CUPFWK3/bB4N13e9M= -github.com/valyala/fasthttp v1.50.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=