diff --git a/Makefile b/Makefile index 218e395..3e61870 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ ifneq ($(LOCAL_DB_MONGO),mongodb-pilot) docker run -d -p 27017:27017 --name mongodb-pilot \ -e MONGO_INITDB_ROOT_USERNAME=mongoadmin \ -e MONGO_INITDB_ROOT_PASSWORD=secret \ - mongo:4.2.11 + mongo:5.0.9 endif stop-local-db: diff --git a/pkg/db/db.go b/pkg/db/db.go index a153de9..eb0b9ea 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -4,22 +4,27 @@ import "time" // Plugin The plugin information. type Plugin struct { - ID string `json:"id,omitempty" bson:"id"` - Name string `json:"name,omitempty" bson:"name"` - DisplayName string `json:"displayName,omitempty" bson:"displayName"` - Author string `json:"author,omitempty" bson:"author"` - Type string `json:"type,omitempty" bson:"type"` - Import string `json:"import,omitempty" bson:"import"` - Compatibility string `json:"compatibility,omitempty" bson:"compatibility"` - Summary string `json:"summary,omitempty" bson:"summary"` - IconURL string `json:"iconUrl,omitempty" bson:"iconUrl"` - BannerURL string `json:"bannerUrl,omitempty" bson:"bannerUrl"` - Readme string `json:"readme,omitempty" bson:"readme"` - LatestVersion string `json:"latestVersion,omitempty" bson:"latestVersion"` - Versions []string `json:"versions,omitempty" bson:"versions"` - Stars int `json:"stars,omitempty" bson:"stars"` - Snippet map[string]interface{} `json:"snippet,omitempty" bson:"snippet"` - CreatedAt time.Time `json:"createdAt" bson:"createdAt"` + ID string `bson:"id"` + Name string `bson:"name"` + DisplayName string `bson:"displayName"` + Author string `bson:"author"` + Type string `bson:"type"` + Compatibility string `bson:"compatibility"` + Summary string `bson:"summary"` + IconURL string `bson:"iconUrl"` + BannerURL string `bson:"bannerUrl"` + Readme string `bson:"readme"` + LatestVersion string `bson:"latestVersion"` + Versions []PluginVersion `bson:"versions"` + Stars int `bson:"stars"` + Snippet map[string]interface{} `bson:"snippet"` + CreatedAt time.Time `bson:"createdAt"` +} + +// PluginVersion is a plugin version with the correct import. +type PluginVersion struct { + Name string `json:"name" bson:"name"` + Import string `json:"import" bson:"import"` } // PluginHash The plugin hash tuple.. diff --git a/pkg/db/mongodb/plugindb.go b/pkg/db/mongodb/plugindb.go index d8514fc..f8e41f6 100644 --- a/pkg/db/mongodb/plugindb.go +++ b/pkg/db/mongodb/plugindb.go @@ -179,7 +179,7 @@ func (m *MongoDB) GetByName(ctx context.Context, name string) (db.Plugin, error) defer span.End() criteria := bson.D{ - {Key: "name", Value: name}, + {Key: "name", Value: primitive.Regex{Pattern: regexp.QuoteMeta(name), Options: "i"}}, } opts := &options.FindOneOptions{} @@ -200,8 +200,8 @@ func (m *MongoDB) GetByName(ctx context.Context, name string) (db.Plugin, error) return plugin, nil } -// SearchByName searches for plugins matching with the given name. -func (m *MongoDB) SearchByName(ctx context.Context, name string, page db.Pagination) ([]db.Plugin, string, error) { +// SearchByDisplayName searches for plugins matching with the given display name. +func (m *MongoDB) SearchByDisplayName(ctx context.Context, name string, page db.Pagination) ([]db.Plugin, string, error) { ctx, span := m.tracer.Start(ctx, "db_search_by_name") defer span.End() @@ -286,8 +286,37 @@ func (m *MongoDB) Update(ctx context.Context, id string, plugin db.Plugin) (db.P {Key: "id", Value: id}, } - update := bson.D{ - {Key: "$set", Value: plugin}, + update := bson.A{ + bson.D{{Key: "$set", Value: bson.D{{Key: "name", Value: plugin.Name}}}}, + bson.D{{Key: "$set", Value: bson.D{{Key: "displayName", Value: plugin.DisplayName}}}}, + bson.D{{Key: "$set", Value: bson.D{{Key: "author", Value: plugin.Author}}}}, + bson.D{{Key: "$set", Value: bson.D{{Key: "type", Value: plugin.Type}}}}, + bson.D{{Key: "$set", Value: bson.D{{Key: "compatibility", Value: plugin.Compatibility}}}}, + bson.D{{Key: "$set", Value: bson.D{{Key: "summary", Value: plugin.Summary}}}}, + bson.D{{Key: "$set", Value: bson.D{{Key: "iconUrl", Value: plugin.IconURL}}}}, + bson.D{{Key: "$set", Value: bson.D{{Key: "bannerUrl", Value: plugin.BannerURL}}}}, + bson.D{{Key: "$set", Value: bson.D{{Key: "readme", Value: plugin.Readme}}}}, + bson.D{{Key: "$set", Value: bson.D{{Key: "latestVersion", Value: plugin.LatestVersion}}}}, + bson.D{{Key: "$set", Value: bson.D{{Key: "stars", Value: plugin.Stars}}}}, + bson.D{{Key: "$set", Value: bson.D{{Key: "snippet", Value: plugin.Snippet}}}}, + // needs mongo > 4.2 + bson.D{{Key: "$set", Value: bson.D{{Key: "versions", Value: bson.D{ + {Key: "$concatArrays", Value: bson.A{"$versions", bson.D{ + {Key: "$filter", Value: bson.D{ + {Key: "input", Value: plugin.Versions}, + {Key: "cond", Value: bson.D{ + {Key: "$not", Value: bson.D{ + {Key: "$in", Value: bson.A{ + "$$this.name", "$versions.name", + }}, + }}, + }}, + }, + }}, + }}, + }}, + }}, + }, } opts := &options.FindOneAndUpdateOptions{} diff --git a/pkg/db/mongodb/plugindb_test.go b/pkg/db/mongodb/plugindb_test.go index 8f39ba9..f6df474 100644 --- a/pkg/db/mongodb/plugindb_test.go +++ b/pkg/db/mongodb/plugindb_test.go @@ -30,14 +30,13 @@ func TestMongoDB_Create(t *testing.T) { DisplayName: "display-name", Author: "author", Type: "type", - Import: "import", Compatibility: "compatibility", Summary: "summary", IconURL: "iconURL", BannerURL: "bannerURL", Readme: "readme", LatestVersion: "latestVersion", - Versions: []string{"v1.0.0"}, + Versions: []db.PluginVersion{{Name: "v1.0.0", Import: "import"}}, Stars: 10, Snippet: map[string]interface{}{ "something": "there", @@ -80,14 +79,13 @@ func TestMongoDB_Get(t *testing.T) { DisplayName: "display-name", Author: "author", Type: "type", - Import: "import", Compatibility: "compatibility", Summary: "summary", IconURL: "iconURL", BannerURL: "bannerURL", Readme: "readme", LatestVersion: "latestVersion", - Versions: []string{"v1.0.0"}, + Versions: []db.PluginVersion{{Name: "v1.0.0", Import: "import"}}, Stars: 10, Snippet: map[string]interface{}{ "something": "there", @@ -186,14 +184,13 @@ func TestMongoDB_GetByName(t *testing.T) { DisplayName: "display-name", Author: "author", Type: "type", - Import: "import", Compatibility: "compatibility", Summary: "summary", IconURL: "iconURL", BannerURL: "bannerURL", Readme: "readme", LatestVersion: "latestVersion", - Versions: []string{"v1.0.0"}, + Versions: []db.PluginVersion{{Name: "v1.0.0", Import: "import"}}, Stars: 10, Snippet: map[string]interface{}{ "something": "there", @@ -210,6 +207,12 @@ func TestMongoDB_GetByName(t *testing.T) { assert.Equal(t, fixtures["my-super-plugin"].Plugin, toUTCPlugin(got)) + // Make sure we can get an existing plugin (case-insensitive). + got, err = store.GetByName(ctx, "My-Super-Plugin") + require.NoError(t, err) + + assert.Equal(t, fixtures["my-super-plugin"].Plugin, toUTCPlugin(got)) + // Make sure we receive a NotFound error when the plugin doesn't exist. _, err = store.GetByName(ctx, "something-else") require.ErrorAs(t, err, &db.NotFoundError{}) @@ -227,14 +230,13 @@ func TestMongoDB_SearchByName(t *testing.T) { DisplayName: "plugin-1", Author: "author", Type: "type", - Import: "import", Compatibility: "compatibility", Summary: "summary", IconURL: "iconURL", BannerURL: "bannerURL", Readme: "readme", LatestVersion: "latestVersion", - Versions: []string{"v1.0.0"}, + Versions: []db.PluginVersion{{Name: "v1.0.0", Import: "import"}}, Stars: 10, Snippet: map[string]interface{}{ "something": "there", @@ -252,14 +254,13 @@ func TestMongoDB_SearchByName(t *testing.T) { DisplayName: "plugin-2", Author: "author", Type: "type", - Import: "import", Compatibility: "compatibility", Summary: "summary", IconURL: "iconURL", BannerURL: "bannerURL", Readme: "readme", LatestVersion: "latestVersion", - Versions: []string{"v1.0.0"}, + Versions: []db.PluginVersion{{Name: "v1.0.0", Import: "import"}}, Stars: 10, Snippet: map[string]interface{}{ "something": "there", @@ -277,14 +278,13 @@ func TestMongoDB_SearchByName(t *testing.T) { DisplayName: "plugin-3", Author: "author", Type: "type", - Import: "import", Compatibility: "compatibility", Summary: "summary", IconURL: "iconURL", BannerURL: "bannerURL", Readme: "readme", LatestVersion: "latestVersion", - Versions: []string{"v1.0.0"}, + Versions: []db.PluginVersion{{Name: "v1.0.0", Import: "import"}}, Stars: 10, Snippet: map[string]interface{}{ "something": "there", @@ -302,14 +302,13 @@ func TestMongoDB_SearchByName(t *testing.T) { DisplayName: "plugin-4", Author: "author", Type: "type", - Import: "import", Compatibility: "compatibility", Summary: "summary", IconURL: "iconURL", BannerURL: "bannerURL", Readme: "readme", LatestVersion: "latestVersion", - Versions: []string{"v1.0.0"}, + Versions: []db.PluginVersion{{Name: "v1.0.0", Import: "import"}}, Stars: 10, Snippet: map[string]interface{}{ "something": "there", @@ -327,14 +326,13 @@ func TestMongoDB_SearchByName(t *testing.T) { DisplayName: "salad-tomate-onion", Author: "author", Type: "type", - Import: "import", Compatibility: "compatibility", Summary: "summary", IconURL: "iconURL", BannerURL: "bannerURL", Readme: "readme", LatestVersion: "latestVersion", - Versions: []string{"v1.0.0"}, + Versions: []db.PluginVersion{{Name: "v1.0.0", Import: "import"}}, Stars: 10, Snippet: map[string]interface{}{ "something": "there", @@ -352,14 +350,13 @@ func TestMongoDB_SearchByName(t *testing.T) { DisplayName: "salad-tom.te-onion", Author: "author", Type: "type", - Import: "import", Compatibility: "compatibility", Summary: "summary", IconURL: "iconURL", BannerURL: "bannerURL", Readme: "readme", LatestVersion: "latestVersion", - Versions: []string{"v1.0.0"}, + Versions: []db.PluginVersion{{Name: "v1.0.0", Import: "import"}}, Stars: 10, Snippet: map[string]interface{}{ "something": "there", @@ -377,14 +374,13 @@ func TestMongoDB_SearchByName(t *testing.T) { DisplayName: "hi^hello", Author: "author", Type: "type", - Import: "import", Compatibility: "compatibility", Summary: "summary", IconURL: "iconURL", BannerURL: "bannerURL", Readme: "readme", LatestVersion: "latestVersion", - Versions: []string{"v1.0.0"}, + Versions: []db.PluginVersion{{Name: "v1.0.0", Import: "import"}}, Stars: 10, Snippet: map[string]interface{}{ "something": "there", @@ -402,14 +398,13 @@ func TestMongoDB_SearchByName(t *testing.T) { DisplayName: "hello", Author: "author", Type: "type", - Import: "import", Compatibility: "compatibility", Summary: "summary", IconURL: "iconURL", BannerURL: "bannerURL", Readme: "readme", LatestVersion: "latestVersion", - Versions: []string{"v1.0.0"}, + Versions: []db.PluginVersion{{Name: "v1.0.0", Import: "import"}}, Stars: 10, Snippet: map[string]interface{}{ "something": "there", @@ -427,14 +422,13 @@ func TestMongoDB_SearchByName(t *testing.T) { DisplayName: "h([]){}.*p", Author: "author", Type: "type", - Import: "import", Compatibility: "compatibility", Summary: "summary", IconURL: "iconURL", BannerURL: "bannerURL", Readme: "readme", LatestVersion: "latestVersion", - Versions: []string{"v1.0.0"}, + Versions: []db.PluginVersion{{Name: "v1.0.0", Import: "import"}}, Stars: 10, Snippet: map[string]interface{}{ "something": "there", @@ -452,14 +446,13 @@ func TestMongoDB_SearchByName(t *testing.T) { DisplayName: "*", Author: "author", Type: "type", - Import: "import", Compatibility: "compatibility", Summary: "summary", IconURL: "iconURL", BannerURL: "bannerURL", Readme: "readme", LatestVersion: "latestVersion", - Versions: []string{"v1.0.0"}, + Versions: []db.PluginVersion{{Name: "v1.0.0", Import: "import"}}, Stars: 10, Snippet: map[string]interface{}{ "something": "there", @@ -544,7 +537,7 @@ func TestMongoDB_SearchByName(t *testing.T) { test := test t.Run(test.desc, func(t *testing.T) { - plugins, nextID, err := store.SearchByName(ctx, test.query, test.pagination) + plugins, nextID, err := store.SearchByDisplayName(ctx, test.query, test.pagination) if test.wantErr { require.Error(t, err) return @@ -570,18 +563,15 @@ func TestMongoDB_Update(t *testing.T) { DisplayName: "plugin", Author: "author", Type: "type", - Import: "import", Compatibility: "compatibility", Summary: "summary", IconURL: "icon", BannerURL: "banner", Readme: "readme", LatestVersion: "v1.1.1", - Versions: []string{ - "v1.1.1", - }, - Stars: 10, - Snippet: nil, + Versions: []db.PluginVersion{{Name: "v1.1.1", Import: "import"}}, + Stars: 10, + Snippet: nil, }, Hashes: []db.PluginHash{ {Name: "plugin@v1.1.1", Hash: "123"}, @@ -596,24 +586,22 @@ func TestMongoDB_Update(t *testing.T) { DisplayName: "plugin", Author: "New Author", Type: "type", - Import: "import", Compatibility: "compatibility", Summary: "summary", IconURL: "icon", BannerURL: "banner", Readme: "readme", LatestVersion: "v1.1.1", - Versions: []string{ - "v1.1.1", - }, - Stars: 10, - Snippet: nil, + Versions: []db.PluginVersion{{Name: "v1.1.1", Import: "import2"}, {Name: "v1.1.2", Import: "import2"}}, + Stars: 10, + Snippet: nil, }) require.NoError(t, err) want := fixtures["plugin"].Plugin want.Name = "New Name" want.Author = "New Author" + want.Versions = []db.PluginVersion{{Name: "v1.1.1", Import: "import"}, {Name: "v1.1.2", Import: "import2"}} assert.Equal(t, want, got) @@ -650,18 +638,15 @@ func TestMongoDB_CreateHash(t *testing.T) { DisplayName: "plugin", Author: "author", Type: "type", - Import: "import", Compatibility: "compatibility", Summary: "summary", IconURL: "icon", BannerURL: "banner", Readme: "readme", LatestVersion: "v1.1.1", - Versions: []string{ - "v1.1.1", - }, - Stars: 10, - Snippet: nil, + Versions: []db.PluginVersion{{Name: "v1.1.1", Import: "import"}}, + Stars: 10, + Snippet: nil, }, Hashes: []db.PluginHash{ {Name: "plugin@v1.1.1", Hash: "123"}, @@ -707,18 +692,15 @@ func TestMongoDB_GetHashByName(t *testing.T) { DisplayName: "plugin", Author: "author", Type: "type", - Import: "import", Compatibility: "compatibility", Summary: "summary", IconURL: "icon", BannerURL: "banner", Readme: "readme", LatestVersion: "v1.1.1", - Versions: []string{ - "v1.1.1", - }, - Stars: 10, - Snippet: nil, + Versions: []db.PluginVersion{{Name: "v1.1.1", Import: "import"}}, + Stars: 10, + Snippet: nil, }, Hashes: []db.PluginHash{ {Name: "plugin@v1.1.2", Hash: "123"}, diff --git a/pkg/handlers/dbmock_test.go b/pkg/handlers/dbmock_test.go index a020ea4..c56d75b 100644 --- a/pkg/handlers/dbmock_test.go +++ b/pkg/handlers/dbmock_test.go @@ -40,7 +40,7 @@ func (m mockDB) GetByName(ctx context.Context, name string) (db.Plugin, error) { return m.getByNameFn(ctx, name) } -func (m mockDB) SearchByName(ctx context.Context, query string, pagination db.Pagination) ([]db.Plugin, string, error) { +func (m mockDB) SearchByDisplayName(ctx context.Context, query string, pagination db.Pagination) ([]db.Plugin, string, error) { return m.searchByNameFn(ctx, query, pagination) } diff --git a/pkg/handlers/handlers.go b/pkg/handlers/handlers.go index 1014371..1ded941 100644 --- a/pkg/handlers/handlers.go +++ b/pkg/handlers/handlers.go @@ -9,6 +9,7 @@ import ( "net/url" "regexp" "strconv" + "time" "github.com/google/go-github/v35/github" "github.com/ldez/grignotin/goproxy" @@ -30,13 +31,33 @@ type PluginStorer interface { Create(context.Context, db.Plugin) (db.Plugin, error) List(context.Context, db.Pagination) ([]db.Plugin, string, error) GetByName(context.Context, string) (db.Plugin, error) - SearchByName(context.Context, string, db.Pagination) ([]db.Plugin, string, error) + SearchByDisplayName(context.Context, string, db.Pagination) ([]db.Plugin, string, error) Update(context.Context, string, db.Plugin) (db.Plugin, error) CreateHash(ctx context.Context, module, version, hash string) (db.PluginHash, error) GetHashByName(ctx context.Context, module, version string) (db.PluginHash, error) } +// PluginView The plugin information. +type PluginView struct { + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + DisplayName string `json:"displayName,omitempty"` + Author string `json:"author,omitempty"` + Type string `json:"type,omitempty"` + Import string `json:"import,omitempty"` + Compatibility string `json:"compatibility,omitempty"` + Summary string `json:"summary,omitempty"` + IconURL string `json:"iconUrl,omitempty"` + BannerURL string `json:"bannerUrl,omitempty"` + Readme string `json:"readme,omitempty"` + LatestVersion string `json:"latestVersion,omitempty"` + Versions []string `json:"versions,omitempty"` + Stars int `json:"stars,omitempty"` + Snippet map[string]interface{} `json:"snippet,omitempty"` + CreatedAt time.Time `json:"createdAt"` +} + // Handlers a set of handlers. type Handlers struct { store PluginStorer @@ -85,7 +106,7 @@ func (h Handlers) Get(rw http.ResponseWriter, req *http.Request) { return } - if err := json.NewEncoder(rw).Encode(plugin); err != nil { + if err := json.NewEncoder(rw).Encode(pluginToPluginView(plugin)); err != nil { span.RecordError(err) logger.Error().Err(err).Msg("Failed to get plugin") JSONInternalServerError(rw) @@ -126,13 +147,13 @@ func (h Handlers) List(rw http.ResponseWriter, req *http.Request) { } // TODO: detection of the plugin name changes must be done in piceus. - var cleanPlugins []db.Plugin + var cleanPlugins []PluginView for _, plugin := range plugins { if plugin.Name == "github.com/tommoulard/fail2ban" || plugin.Name == "github.com/tommoulard/htransformation" { continue } - cleanPlugins = append(cleanPlugins, plugin) + cleanPlugins = append(cleanPlugins, pluginToPluginView(plugin)) } if len(cleanPlugins) == 0 { @@ -177,7 +198,7 @@ func (h Handlers) Create(rw http.ResponseWriter, req *http.Request) { return } - pl := db.Plugin{} + pl := PluginView{} err = json.Unmarshal(body, &pl) if err != nil { @@ -189,7 +210,7 @@ func (h Handlers) Create(rw http.ResponseWriter, req *http.Request) { logger := log.With().Str("module_name", pl.Name).Logger() - created, err := h.store.Create(ctx, pl) + created, err := h.store.Create(ctx, pluginViewToPlugin(pl)) if err != nil { span.RecordError(err) logger.Error().Err(err).Msg("Error persisting plugin") @@ -223,7 +244,7 @@ func (h Handlers) Update(rw http.ResponseWriter, req *http.Request) { logger := log.With().Str("plugin_id", id).Logger() - input := db.Plugin{} + input := PluginView{} err = json.NewDecoder(req.Body).Decode(&input) if err != nil { span.RecordError(err) @@ -232,7 +253,7 @@ func (h Handlers) Update(rw http.ResponseWriter, req *http.Request) { return } - pg, err := h.store.Update(ctx, id, input) + pg, err := h.store.Update(ctx, id, pluginViewToPlugin(input)) if err != nil { span.RecordError(err) @@ -300,7 +321,7 @@ func (h Handlers) searchByName(rw http.ResponseWriter, req *http.Request) { logger := log.With().Str("search_query", query).Str("search_start", start).Logger() - plugins, next, err := h.store.SearchByName(ctx, query, db.Pagination{ + plugins, next, err := h.store.SearchByDisplayName(ctx, query, db.Pagination{ Start: start, Size: defaultPerPage, }) @@ -353,7 +374,9 @@ func (h Handlers) getByName(rw http.ResponseWriter, req *http.Request) { return } - if err := json.NewEncoder(rw).Encode([]*db.Plugin{&plugin}); err != nil { + pv := pluginToPluginView(plugin) + + if err := json.NewEncoder(rw).Encode([]*PluginView{&pv}); err != nil { span.RecordError(err) logger.Error().Err(err).Msg("Failed to encode response") JSONInternalServerError(rw) @@ -385,3 +408,62 @@ func unquote(value string) string { return unquote } + +func pluginToPluginView(plugin db.Plugin) PluginView { + p := PluginView{ + ID: plugin.ID, + Name: plugin.Name, + DisplayName: plugin.DisplayName, + Author: plugin.Author, + Type: plugin.Type, + Import: "", + Compatibility: plugin.Compatibility, + Summary: plugin.Summary, + IconURL: plugin.IconURL, + BannerURL: plugin.BannerURL, + Readme: plugin.Readme, + LatestVersion: plugin.LatestVersion, + Stars: plugin.Stars, + Snippet: plugin.Snippet, + CreatedAt: plugin.CreatedAt, + } + + for _, version := range plugin.Versions { + p.Versions = append(p.Versions, version.Name) + if version.Name == p.LatestVersion { + p.Import = version.Import + } + } + + return p +} + +func pluginViewToPlugin(plugin PluginView) db.Plugin { + p := db.Plugin{ + ID: plugin.ID, + Name: plugin.Name, + DisplayName: plugin.DisplayName, + Author: plugin.Author, + Type: plugin.Type, + Compatibility: plugin.Compatibility, + Summary: plugin.Summary, + IconURL: plugin.IconURL, + BannerURL: plugin.BannerURL, + Readme: plugin.Readme, + LatestVersion: plugin.LatestVersion, + Stars: plugin.Stars, + Snippet: plugin.Snippet, + CreatedAt: plugin.CreatedAt, + } + + for _, version := range plugin.Versions { + if version == plugin.LatestVersion { + p.Versions = append(p.Versions, db.PluginVersion{ + Name: plugin.LatestVersion, + Import: plugin.Import, + }) + } + } + + return p +} diff --git a/pkg/handlers/handlers_test.go b/pkg/handlers/handlers_test.go index 504bf56..3b4ade3 100644 --- a/pkg/handlers/handlers_test.go +++ b/pkg/handlers/handlers_test.go @@ -21,7 +21,6 @@ func TestHandlers_List(t *testing.T) { CreatedAt: time.Date(2020, 1, 1, 1, 0, 0, 0, time.UTC), DisplayName: "Demo Plugin", ID: "276809780784267776", - Import: "github.com/traefik/plugindemo", LatestVersion: "v0.2.1", Name: "github.com/traefik/plugindemo", Readme: "README", @@ -29,7 +28,11 @@ func TestHandlers_List(t *testing.T) { Stars: 22, Summary: "[Demo] Add Request Header", Type: "middleware", - Versions: []string{"v0.2.1", "v0.2.0", "v0.1.0"}, + Versions: []db.PluginVersion{{ + Name: "v0.2.1", Import: "github.com/traefik/plugindemo"}, + {Name: "v0.2.0", Import: "github.com/traefik/plugindemo"}, + {Name: "v0.1.0", Import: "github.com/Traefik/plugindemo"}, + }, }, { Author: "traefik", @@ -37,7 +40,6 @@ func TestHandlers_List(t *testing.T) { CreatedAt: time.Date(2020, 1, 1, 1, 0, 0, 0, time.UTC), DisplayName: "Block Path", ID: "2768097807845374", - Import: "github.com/traefik/plugin-blockpath", LatestVersion: "v0.3.1", Name: "github.com/traefik/plugin-blockpath", Readme: "README", @@ -45,7 +47,11 @@ func TestHandlers_List(t *testing.T) { Stars: 3, Summary: "Block Path plugin", Type: "middleware", - Versions: []string{"v0.3.1", "v0.2.0", "v0.1.0"}, + Versions: []db.PluginVersion{{ + Name: "v0.3.1", Import: "github.com/traefik/plugin-blockpath"}, + {Name: "v0.2.0", Import: "github.com/traefik/plugin-blockpath"}, + {Name: "v0.1.0", Import: "github.com/traefik/plugin-blockpath"}, + }, }, } @@ -77,7 +83,6 @@ func TestHandlers_List_GetByName(t *testing.T) { CreatedAt: time.Date(2020, 1, 1, 1, 0, 0, 0, time.UTC), DisplayName: "Demo Plugin", ID: "276809780784267776", - Import: "github.com/traefik/plugindemo", LatestVersion: "v0.2.1", Name: "github.com/traefik/plugindemo", Readme: "README", @@ -85,7 +90,11 @@ func TestHandlers_List_GetByName(t *testing.T) { Stars: 22, Summary: "[Demo] Add Request Header", Type: "middleware", - Versions: []string{"v0.2.1", "v0.2.0", "v0.1.0"}, + Versions: []db.PluginVersion{ + {Name: "v0.2.1", Import: "github.com/traefik/plugindemo"}, + {Name: "v0.2.0", Import: "github.com/traefik/plugindemo"}, + {Name: "v0.1.0", Import: "github.com/Traefik/plugindemo"}, + }, } testDB := mockDB{ @@ -115,7 +124,6 @@ func TestHandlers_List_SearchByName(t *testing.T) { CreatedAt: time.Date(2020, 1, 1, 1, 0, 0, 0, time.UTC), DisplayName: "Demo Plugin", ID: "276809780784267776", - Import: "github.com/traefik/plugindemo", LatestVersion: "v0.2.1", Name: "github.com/traefik/plugindemo", Readme: "README", @@ -123,7 +131,11 @@ func TestHandlers_List_SearchByName(t *testing.T) { Stars: 22, Summary: "[Demo] Add Request Header", Type: "middleware", - Versions: []string{"v0.2.1", "v0.2.0", "v0.1.0"}, + Versions: []db.PluginVersion{{ + Name: "v0.2.1", Import: "github.com/traefik/plugindemo"}, + {Name: "v0.2.0", Import: "github.com/traefik/plugindemo"}, + {Name: "v0.1.0", Import: "github.com/Traefik/plugindemo"}, + }, } testDB := mockDB{ diff --git a/pkg/handlers/module.go b/pkg/handlers/module.go index 2945d17..76ed8ec 100644 --- a/pkg/handlers/module.go +++ b/pkg/handlers/module.go @@ -40,7 +40,7 @@ func (h Handlers) Download(rw http.ResponseWriter, req *http.Request) { logger := log.With().Str("module_name", moduleName).Str("module_version", version).Logger() - _, err := h.store.GetByName(ctx, moduleName) + plugin, err := h.store.GetByName(ctx, moduleName) if err != nil { span.RecordError(err) if errors.As(err, &db.NotFoundError{}) { @@ -54,6 +54,13 @@ func (h Handlers) Download(rw http.ResponseWriter, req *http.Request) { return } + moduleName, err = getModuleNameWithVersion(plugin, version) + if err != nil { + logger.Error().Err(err).Msg("Failed to get plugin version") + JSONErrorf(rw, http.StatusInternalServerError, "Failed to get plugin %s@%s", moduleName, version) + return + } + sum := req.Header.Get(hashHeader) if sum != "" { ph, errH := h.store.GetHashByName(ctx, moduleName, version) @@ -96,6 +103,16 @@ func (h Handlers) Download(rw http.ResponseWriter, req *http.Request) { h.downloadGoProxy(ctx, moduleName, version)(rw, req) } +func getModuleNameWithVersion(plugin db.Plugin, version string) (string, error) { + for _, v := range plugin.Versions { + if v.Name == version { + return v.Import, nil + } + } + + return "", errors.New("version not found") +} + func (h Handlers) downloadGoProxy(ctx context.Context, moduleName, version string) http.HandlerFunc { return func(rw http.ResponseWriter, req *http.Request) { var span trace.Span