Implement plugin options retrieval
This commit is contained in:
parent
40a29b7f48
commit
bf63fa5708
12 changed files with 624 additions and 5 deletions
|
|
@ -55,6 +55,22 @@ func (uc *TestPluginController) TestPluginHandler(c *gin.Context) {
|
|||
c.Next()
|
||||
}
|
||||
|
||||
// TestPluginOptionHandler is a middleware that retrieves a specific plugin option and sets it in the context.
|
||||
func (uc *TestPluginController) TestPluginOptionHandler(c *gin.Context) {
|
||||
pname := c.Param("pname")
|
||||
optname := c.Param("optname")
|
||||
|
||||
opts, err := uc.testPluginService.GetTestPluginOptions(pname, nil, nil, nil)
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, happydns.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.Set("option", (*opts)[optname])
|
||||
|
||||
c.Next()
|
||||
}
|
||||
|
||||
// ListTestPlugins retrieves all available test plugins.
|
||||
//
|
||||
// @Summary List all test plugins
|
||||
|
|
@ -98,5 +114,140 @@ func (uc *TestPluginController) ListTestPlugins(c *gin.Context) {
|
|||
func (uc *TestPluginController) GetTestPluginStatus(c *gin.Context) {
|
||||
plugin := c.MustGet("plugin").(happydns.TestPlugin)
|
||||
|
||||
c.JSON(http.StatusOK, plugin.Version())
|
||||
c.JSON(http.StatusOK, happydns.PluginStatus{
|
||||
PluginVersionInfo: plugin.Version(),
|
||||
Opts: plugin.AvailableOptions(),
|
||||
})
|
||||
}
|
||||
|
||||
// GetTestPluginOptions retrieves all options for a test plugin.
|
||||
//
|
||||
// @Summary Get test plugin options
|
||||
// @Schemes
|
||||
// @Description Retrieves all configuration options for a specific test plugin.
|
||||
// @Tags plugins
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param pname path string true "Plugin name"
|
||||
// @Success 200 {object} happydns.PluginOptions "Plugin options as key-value pairs"
|
||||
// @Failure 404 {object} happydns.ErrorResponse "Plugin not found"
|
||||
// @Failure 500 {object} happydns.ErrorResponse "Internal server error"
|
||||
// @Router /plugins/tests/{pname}/options [get]
|
||||
func (uc *TestPluginController) GetTestPluginOptions(c *gin.Context) {
|
||||
pname := c.Param("pname")
|
||||
|
||||
opts, err := uc.testPluginService.GetTestPluginOptions(pname, nil, nil, nil)
|
||||
happydns.ApiResponse(c, opts, err)
|
||||
}
|
||||
|
||||
// AddTestPluginOptions adds or overwrites specific options for a test plugin.
|
||||
//
|
||||
// @Summary Add test plugin options
|
||||
// @Schemes
|
||||
// @Description Adds or overwrites specific configuration options for a test plugin without affecting other options.
|
||||
// @Tags plugins
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param pname path string true "Plugin name"
|
||||
// @Param body body happydns.SetPluginOptionsRequest true "Options to add or overwrite"
|
||||
// @Success 200 {object} bool "Success status"
|
||||
// @Failure 400 {object} happydns.ErrorResponse "Invalid request body"
|
||||
// @Failure 404 {object} happydns.ErrorResponse "Plugin not found"
|
||||
// @Failure 500 {object} happydns.ErrorResponse "Internal server error"
|
||||
// @Router /plugins/tests/{pname}/options [post]
|
||||
func (uc *TestPluginController) AddTestPluginOptions(c *gin.Context) {
|
||||
pname := c.Param("pname")
|
||||
|
||||
var req happydns.SetPluginOptionsRequest
|
||||
err := c.ShouldBindJSON(&req)
|
||||
if err != nil {
|
||||
middleware.ErrorResponse(c, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = uc.testPluginService.OverwriteSomeTestPluginOptions(pname, nil, nil, nil, req.Options)
|
||||
happydns.ApiResponse(c, true, err)
|
||||
}
|
||||
|
||||
// ChangeTestPluginOptions replaces all options for a test plugin.
|
||||
//
|
||||
// @Summary Replace test plugin options
|
||||
// @Schemes
|
||||
// @Description Replaces all configuration options for a test plugin with the provided options.
|
||||
// @Tags plugins
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param pname path string true "Plugin name"
|
||||
// @Param body body happydns.SetPluginOptionsRequest true "New complete set of options"
|
||||
// @Success 200 {object} bool "Success status"
|
||||
// @Failure 400 {object} happydns.ErrorResponse "Invalid request body"
|
||||
// @Failure 404 {object} happydns.ErrorResponse "Plugin not found"
|
||||
// @Failure 500 {object} happydns.ErrorResponse "Internal server error"
|
||||
// @Router /plugins/tests/{pname}/options [put]
|
||||
func (uc *TestPluginController) ChangeTestPluginOptions(c *gin.Context) {
|
||||
pname := c.Param("pname")
|
||||
|
||||
var req happydns.SetPluginOptionsRequest
|
||||
err := c.ShouldBindJSON(&req)
|
||||
if err != nil {
|
||||
middleware.ErrorResponse(c, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = uc.testPluginService.SetTestPluginOptions(pname, nil, nil, nil, req.Options)
|
||||
happydns.ApiResponse(c, true, err)
|
||||
}
|
||||
|
||||
// GetTestPluginOption retrieves a specific option value for a test plugin.
|
||||
//
|
||||
// @Summary Get test plugin option
|
||||
// @Schemes
|
||||
// @Description Retrieves the value of a specific configuration option for a test plugin.
|
||||
// @Tags plugins
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param pname path string true "Plugin name"
|
||||
// @Param optname path string true "Option name"
|
||||
// @Success 200 {object} object "Option value (type varies)"
|
||||
// @Failure 404 {object} happydns.ErrorResponse "Plugin not found"
|
||||
// @Failure 500 {object} happydns.ErrorResponse "Internal server error"
|
||||
// @Router /plugins/tests/{pname}/options/{optname} [get]
|
||||
func (uc *TestPluginController) GetTestPluginOption(c *gin.Context) {
|
||||
opt := c.MustGet("option")
|
||||
|
||||
happydns.ApiResponse(c, opt, nil)
|
||||
}
|
||||
|
||||
// SetTestPluginOption sets or updates a specific option value for a test plugin.
|
||||
//
|
||||
// @Summary Set test plugin option
|
||||
// @Schemes
|
||||
// @Description Sets or updates the value of a specific configuration option for a test plugin.
|
||||
// @Tags plugins
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param pname path string true "Plugin name"
|
||||
// @Param optname path string true "Option name"
|
||||
// @Param body body object true "Option value (type varies by option)"
|
||||
// @Success 200 {object} bool "Success status"
|
||||
// @Failure 400 {object} happydns.ErrorResponse "Invalid request body"
|
||||
// @Failure 404 {object} happydns.ErrorResponse "Plugin not found"
|
||||
// @Failure 500 {object} happydns.ErrorResponse "Internal server error"
|
||||
// @Router /plugins/tests/{pname}/options/{optname} [put]
|
||||
func (uc *TestPluginController) SetTestPluginOption(c *gin.Context) {
|
||||
pname := c.Param("pname")
|
||||
optname := c.Param("optname")
|
||||
|
||||
var req interface{}
|
||||
err := c.ShouldBindJSON(&req)
|
||||
if err != nil {
|
||||
middleware.ErrorResponse(c, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
po := happydns.PluginOptions{}
|
||||
po[optname] = req
|
||||
|
||||
err = uc.testPluginService.OverwriteSomeTestPluginOptions(pname, nil, nil, nil, po)
|
||||
happydns.ApiResponse(c, true, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,12 @@ func declareTestPluginsRoutes(router *gin.RouterGroup, dependancies happydns.Use
|
|||
apiTestPluginRoutes.GET("", tpc.GetTestPluginStatus)
|
||||
//apiTestPluginRoutes.POST("", tpc.ChangeTestPluginStatus)
|
||||
|
||||
//apiTestPluginRoutes.GET("/options", tpc.ListTestPluginOptions)
|
||||
//apiTestPluginRoutes.PUT("/options", tpc.ChangeTestPluginOptions)
|
||||
apiTestPluginRoutes.GET("/options", tpc.GetTestPluginOptions)
|
||||
apiTestPluginRoutes.POST("/options", tpc.AddTestPluginOptions)
|
||||
apiTestPluginRoutes.PUT("/options", tpc.ChangeTestPluginOptions)
|
||||
|
||||
apiTestPluginOptionsRoutes := apiTestPluginRoutes.Group("/options/:optname")
|
||||
apiTestPluginOptionsRoutes.Use(tpc.TestPluginOptionHandler)
|
||||
apiTestPluginOptionsRoutes.GET("", tpc.GetTestPluginOption)
|
||||
apiTestPluginOptionsRoutes.PUT("", tpc.SetTestPluginOption)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ func (app *App) initUsecases() {
|
|||
app.usecases.authUser = authUserService
|
||||
app.usecases.resolver = usecase.NewResolverUsecase(app.cfg)
|
||||
app.usecases.session = sessionService
|
||||
app.usecases.testPlugin = pluginUC.NewTestPluginUsecase(app.cfg, app.plugins)
|
||||
app.usecases.testPlugin = pluginUC.NewTestPluginUsecase(app.cfg, app.plugins, app.store)
|
||||
|
||||
app.usecases.orchestrator = orchestrator.NewOrchestrator(
|
||||
domainLogService,
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ type InMemoryStorage struct {
|
|||
domainLogs map[string]*happydns.DomainLogWithDomainId
|
||||
domainLogsByDomains map[string][]*happydns.Identifier
|
||||
providers map[string]*happydns.ProviderMessage
|
||||
pluginsCfg map[string]*happydns.PluginOptions
|
||||
sessions map[string]*happydns.Session
|
||||
users map[string]*happydns.User
|
||||
usersByEmail map[string]*happydns.User
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import (
|
|||
"git.happydns.org/happyDomain/internal/usecase/domain"
|
||||
"git.happydns.org/happyDomain/internal/usecase/domain_log"
|
||||
"git.happydns.org/happyDomain/internal/usecase/insight"
|
||||
"git.happydns.org/happyDomain/internal/usecase/plugin"
|
||||
"git.happydns.org/happyDomain/internal/usecase/provider"
|
||||
"git.happydns.org/happyDomain/internal/usecase/session"
|
||||
"git.happydns.org/happyDomain/internal/usecase/user"
|
||||
|
|
@ -43,6 +44,7 @@ type Storage interface {
|
|||
domain.DomainStorage
|
||||
domainlog.DomainLogStorage
|
||||
insight.InsightStorage
|
||||
plugin.PluginStorage
|
||||
provider.ProviderStorage
|
||||
session.SessionStorage
|
||||
user.UserStorage
|
||||
|
|
|
|||
185
internal/storage/kvtpl/plugin.go
Normal file
185
internal/storage/kvtpl/plugin.go
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
// This file is part of the happyDomain (R) project.
|
||||
// Copyright (c) 2020-2025 happyDomain
|
||||
// Authors: Pierre-Olivier Mercier, et al.
|
||||
//
|
||||
// This program is offered under a commercial and under the AGPL license.
|
||||
// For commercial licensing, contact us at <contact@happydomain.org>.
|
||||
//
|
||||
// For AGPL licensing:
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package database
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.happydns.org/happyDomain/model"
|
||||
)
|
||||
|
||||
func (s *KVStorage) ListAllPluginConfigurations() (happydns.Iterator[happydns.PluginOptions], error) {
|
||||
iter := s.db.Search("plugincfg-")
|
||||
return NewKVIterator[happydns.PluginOptions](s.db, iter), nil
|
||||
}
|
||||
|
||||
func buildPluginKey(pname string, user *happydns.Identifier, domain *happydns.Identifier, service *happydns.Identifier) string {
|
||||
u := ""
|
||||
if user != nil {
|
||||
u = user.String()
|
||||
}
|
||||
|
||||
d := ""
|
||||
if domain != nil {
|
||||
d = domain.String()
|
||||
}
|
||||
|
||||
s := ""
|
||||
if service != nil {
|
||||
s = service.String()
|
||||
}
|
||||
|
||||
return strings.Join([]string{pname, u, d, s}, "/")
|
||||
}
|
||||
|
||||
func keyToPositional(key string, opts *happydns.PluginOptions) (*happydns.PluginOptionsPositional, error) {
|
||||
tmp := strings.Split(key, "/")
|
||||
|
||||
if len(tmp) < 4 {
|
||||
return nil, fmt.Errorf("malformed plugin configuration key, got %q", key)
|
||||
}
|
||||
|
||||
pname := tmp[0]
|
||||
|
||||
var userid *happydns.Identifier
|
||||
if len(tmp[1]) > 0 {
|
||||
u, err := happydns.NewIdentifierFromString(tmp[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userid = &u
|
||||
}
|
||||
|
||||
var domainid *happydns.Identifier
|
||||
if len(tmp[2]) > 0 {
|
||||
d, err := happydns.NewIdentifierFromString(tmp[2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domainid = &d
|
||||
}
|
||||
|
||||
var serviceid *happydns.Identifier
|
||||
if len(tmp[3]) > 0 {
|
||||
s, err := happydns.NewIdentifierFromString(tmp[3])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
serviceid = &s
|
||||
}
|
||||
|
||||
return &happydns.PluginOptionsPositional{
|
||||
PluginName: pname,
|
||||
UserId: userid,
|
||||
DomainId: domainid,
|
||||
ServiceId: serviceid,
|
||||
Options: *opts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *KVStorage) ListPluginConfiguration(pname string) (configs []*happydns.PluginOptionsPositional, err error) {
|
||||
iter := s.db.Search("plugincfg-" + pname + "/")
|
||||
defer iter.Release()
|
||||
|
||||
for iter.Next() {
|
||||
var p happydns.PluginOptions
|
||||
|
||||
e := s.db.DecodeData(iter.Value(), &p)
|
||||
if e != nil {
|
||||
err = errors.Join(err, e)
|
||||
continue
|
||||
}
|
||||
|
||||
opts, e := keyToPositional(strings.TrimPrefix(iter.Key(), "plugincfg-"), &p)
|
||||
if e != nil {
|
||||
err = errors.Join(err, e)
|
||||
continue
|
||||
}
|
||||
|
||||
configs = append(configs, opts)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *KVStorage) GetPluginConfiguration(pname string, user *happydns.Identifier, domain *happydns.Identifier, service *happydns.Identifier) (configs []*happydns.PluginOptionsPositional, err error) {
|
||||
iter := s.db.Search("plugincfg-" + pname + "/")
|
||||
defer iter.Release()
|
||||
|
||||
for iter.Next() {
|
||||
var p happydns.PluginOptions
|
||||
|
||||
e := s.db.DecodeData(iter.Value(), &p)
|
||||
if e != nil {
|
||||
err = errors.Join(err, e)
|
||||
continue
|
||||
}
|
||||
|
||||
opts, e := keyToPositional(strings.TrimPrefix(iter.Key(), "plugincfg-"), &p)
|
||||
if e != nil {
|
||||
err = errors.Join(err, e)
|
||||
continue
|
||||
}
|
||||
|
||||
// Match logic:
|
||||
// - When parameter is nil: match ONLY configs with nil ID (requesting specific scope)
|
||||
// - When parameter is not nil: match configs with nil ID (admin-level) OR matching ID
|
||||
matchUser := (user == nil && opts.UserId == nil) ||
|
||||
(user != nil && (opts.UserId == nil || opts.UserId.Equals(*user)))
|
||||
|
||||
matchDomain := (domain == nil && opts.DomainId == nil) ||
|
||||
(domain != nil && (opts.DomainId == nil || opts.DomainId.Equals(*domain)))
|
||||
|
||||
matchService := (service == nil && opts.ServiceId == nil) ||
|
||||
(service != nil && (opts.ServiceId == nil || opts.ServiceId.Equals(*service)))
|
||||
|
||||
if matchUser && matchDomain && matchService {
|
||||
configs = append(configs, opts)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *KVStorage) UpdatePluginConfiguration(pname string, user *happydns.Identifier, domain *happydns.Identifier, service *happydns.Identifier, opts happydns.PluginOptions) error {
|
||||
return s.db.Put(fmt.Sprintf("plugincfg-%s", buildPluginKey(pname, user, domain, service)), opts)
|
||||
}
|
||||
|
||||
func (s *KVStorage) DeletePluginConfiguration(pname string, user *happydns.Identifier, domain *happydns.Identifier, service *happydns.Identifier) error {
|
||||
return s.db.Delete(fmt.Sprintf("plugincfg-%s", buildPluginKey(pname, user, domain, service)))
|
||||
}
|
||||
|
||||
func (s *KVStorage) ClearPluginConfigurations() error {
|
||||
iter := s.db.Search("plugincfg-")
|
||||
defer iter.Release()
|
||||
|
||||
for iter.Next() {
|
||||
err := s.db.Delete(iter.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
46
internal/usecase/plugin/plugin_storage.go
Normal file
46
internal/usecase/plugin/plugin_storage.go
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// This file is part of the happyDomain (R) project.
|
||||
// Copyright (c) 2020-2025 happyDomain
|
||||
// Authors: Pierre-Olivier Mercier, et al.
|
||||
//
|
||||
// This program is offered under a commercial and under the AGPL license.
|
||||
// For commercial licensing, contact us at <contact@happydomain.org>.
|
||||
//
|
||||
// For AGPL licensing:
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"git.happydns.org/happyDomain/model"
|
||||
)
|
||||
|
||||
type PluginStorage interface {
|
||||
// ListAllPluginConfigurations retrieves the list of known Providers.
|
||||
ListAllPluginConfigurations() (happydns.Iterator[happydns.PluginOptions], error)
|
||||
|
||||
// ListPluginConfiguration retrieves all providers own by the given User.
|
||||
ListPluginConfiguration(string) ([]*happydns.PluginOptionsPositional, error)
|
||||
|
||||
// GetPluginConfiguration retrieves the full Provider with the given identifier and owner.
|
||||
GetPluginConfiguration(string, *happydns.Identifier, *happydns.Identifier, *happydns.Identifier) ([]*happydns.PluginOptionsPositional, error)
|
||||
|
||||
// UpdatePluginConfiguration updates the fields of the given Provider.
|
||||
UpdatePluginConfiguration(string, *happydns.Identifier, *happydns.Identifier, *happydns.Identifier, happydns.PluginOptions) error
|
||||
|
||||
// DeletePluginConfiguration removes the given Provider from the database.
|
||||
DeletePluginConfiguration(string, *happydns.Identifier, *happydns.Identifier, *happydns.Identifier) error
|
||||
|
||||
// ClearPluginConfigurations deletes all Providers present in the database.
|
||||
ClearPluginConfigurations() error
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ package plugin
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"git.happydns.org/happyDomain/model"
|
||||
)
|
||||
|
|
@ -30,12 +31,14 @@ import (
|
|||
type testPluginUsecase struct {
|
||||
config *happydns.Options
|
||||
manager happydns.PluginManager
|
||||
store PluginStorage
|
||||
}
|
||||
|
||||
func NewTestPluginUsecase(cfg *happydns.Options, manager happydns.PluginManager) happydns.TestPluginUsecase {
|
||||
func NewTestPluginUsecase(cfg *happydns.Options, manager happydns.PluginManager, store PluginStorage) happydns.TestPluginUsecase {
|
||||
return &testPluginUsecase{
|
||||
config: cfg,
|
||||
manager: manager,
|
||||
store: store,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -48,6 +51,84 @@ func (tu *testPluginUsecase) GetTestPlugin(pname string) (happydns.TestPlugin, e
|
|||
}
|
||||
}
|
||||
|
||||
type ByOptionPosition []*happydns.PluginOptionsPositional
|
||||
|
||||
func (a ByOptionPosition) Len() int { return len(a) }
|
||||
func (a ByOptionPosition) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a ByOptionPosition) Less(i, j int) bool {
|
||||
if a[i].PluginName != a[j].PluginName {
|
||||
return a[i].PluginName < a[j].PluginName
|
||||
}
|
||||
|
||||
if res := compareIdentifiers(a[i].UserId, a[j].UserId); res != 0 {
|
||||
return res < 0
|
||||
}
|
||||
|
||||
if res := compareIdentifiers(a[i].DomainId, a[j].DomainId); res != 0 {
|
||||
return res < 0
|
||||
}
|
||||
|
||||
if res := compareIdentifiers(a[i].ServiceId, a[j].ServiceId); res != 0 {
|
||||
return res < 0
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func compareIdentifiers(a, b *happydns.Identifier) int {
|
||||
if a == nil && b == nil {
|
||||
return 0
|
||||
}
|
||||
if a == nil {
|
||||
return -1
|
||||
}
|
||||
if b == nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
if a.Equals(*b) {
|
||||
return 0
|
||||
}
|
||||
|
||||
return a.Compare(*b)
|
||||
}
|
||||
|
||||
func (tu *testPluginUsecase) GetTestPluginOptions(pname string, userid *happydns.Identifier, domainid *happydns.Identifier, serviceid *happydns.Identifier) (*happydns.PluginOptions, error) {
|
||||
configs, err := tu.store.GetPluginConfiguration(pname, userid, domainid, serviceid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sort.Sort(ByOptionPosition(configs))
|
||||
|
||||
opts := make(happydns.PluginOptions)
|
||||
|
||||
for _, c := range configs {
|
||||
for k, v := range c.Options {
|
||||
opts[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return &opts, nil
|
||||
}
|
||||
|
||||
func (tu *testPluginUsecase) ListTestPlugins() ([]happydns.TestPlugin, error) {
|
||||
return tu.manager.GetTestPlugins(), nil
|
||||
}
|
||||
|
||||
func (tu *testPluginUsecase) SetTestPluginOptions(pname string, userid *happydns.Identifier, domainid *happydns.Identifier, serviceid *happydns.Identifier, opts happydns.PluginOptions) error {
|
||||
return tu.store.UpdatePluginConfiguration(pname, userid, domainid, serviceid, opts)
|
||||
}
|
||||
|
||||
func (tu *testPluginUsecase) OverwriteSomeTestPluginOptions(pname string, userid *happydns.Identifier, domainid *happydns.Identifier, serviceid *happydns.Identifier, opts happydns.PluginOptions) error {
|
||||
current, err := tu.GetTestPluginOptions(pname, userid, domainid, serviceid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for k, v := range opts {
|
||||
(*current)[k] = v
|
||||
}
|
||||
|
||||
return tu.store.UpdatePluginConfiguration(pname, userid, domainid, serviceid, *current)
|
||||
}
|
||||
|
|
|
|||
85
internal/usecase/plugin/plugin_test_usecase_test.go
Normal file
85
internal/usecase/plugin/plugin_test_usecase_test.go
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
package plugin_test
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
uc "git.happydns.org/happyDomain/internal/usecase/plugin"
|
||||
"git.happydns.org/happyDomain/model"
|
||||
)
|
||||
|
||||
func TestSortByPluginName(t *testing.T) {
|
||||
slice := []*happydns.PluginOptionsPositional{
|
||||
{PluginName: "zeta"},
|
||||
{PluginName: "alpha"},
|
||||
{PluginName: "beta"},
|
||||
}
|
||||
|
||||
sort.Sort(uc.ByOptionPosition(slice))
|
||||
|
||||
got := []string{slice[0].PluginName, slice[1].PluginName, slice[2].PluginName}
|
||||
want := []string{"alpha", "beta", "zeta"}
|
||||
|
||||
for i := range want {
|
||||
if got[i] != want[i] {
|
||||
t.Errorf("expected %v, got %v", want, got)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNilBeforeNonNil(t *testing.T) {
|
||||
uid, _ := happydns.NewRandomIdentifier()
|
||||
slice := []*happydns.PluginOptionsPositional{
|
||||
{PluginName: "alpha", UserId: &uid},
|
||||
{PluginName: "alpha", UserId: nil},
|
||||
}
|
||||
|
||||
sort.Sort(uc.ByOptionPosition(slice))
|
||||
|
||||
if slice[0].UserId != nil {
|
||||
t.Errorf("expected nil UserId first, got %+v", slice[0].UserId)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDomainIdOrder(t *testing.T) {
|
||||
did, _ := happydns.NewRandomIdentifier()
|
||||
slice := []*happydns.PluginOptionsPositional{
|
||||
{PluginName: "alpha", UserId: nil, DomainId: &did},
|
||||
{PluginName: "alpha", UserId: nil, DomainId: nil},
|
||||
}
|
||||
|
||||
sort.Sort(uc.ByOptionPosition(slice))
|
||||
|
||||
if slice[0].DomainId != nil {
|
||||
t.Errorf("expected nil DomainId first, got %+v", slice[0].DomainId)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServiceIdOrder(t *testing.T) {
|
||||
sid, _ := happydns.NewRandomIdentifier()
|
||||
slice := []*happydns.PluginOptionsPositional{
|
||||
{PluginName: "alpha", UserId: nil, DomainId: nil, ServiceId: &sid},
|
||||
{PluginName: "alpha", UserId: nil, DomainId: nil, ServiceId: nil},
|
||||
}
|
||||
|
||||
sort.Sort(uc.ByOptionPosition(slice))
|
||||
|
||||
if slice[0].ServiceId != nil {
|
||||
t.Errorf("expected nil ServiceId first, got %+v", slice[0].ServiceId)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStableGrouping(t *testing.T) {
|
||||
uid, _ := happydns.NewRandomIdentifier()
|
||||
|
||||
slice := []*happydns.PluginOptionsPositional{
|
||||
{PluginName: "alpha", UserId: &uid},
|
||||
{PluginName: "alpha", UserId: &uid},
|
||||
}
|
||||
|
||||
sort.Sort(uc.ByOptionPosition(slice))
|
||||
if slice[0].PluginName != slice[1].PluginName {
|
||||
t.Errorf("expected grouping, got %+v vs %+v", slice[0], slice[1])
|
||||
}
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@ import (
|
|||
"encoding/base64"
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"slices"
|
||||
)
|
||||
|
||||
const IDENTIFIER_LEN = 16
|
||||
|
|
@ -55,6 +56,10 @@ func (i Identifier) Equals(other Identifier) bool {
|
|||
return bytes.Equal(i, other)
|
||||
}
|
||||
|
||||
func (i Identifier) Compare(other Identifier) int {
|
||||
return slices.Compare(i, other)
|
||||
}
|
||||
|
||||
func (i *Identifier) String() string {
|
||||
return base64.RawURLEncoding.EncodeToString(*i)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,9 +32,23 @@ type PluginResultStatus int
|
|||
|
||||
type PluginOptions map[string]any
|
||||
|
||||
type SetPluginOptionsRequest struct {
|
||||
Options PluginOptions `json:"options"`
|
||||
}
|
||||
|
||||
type PluginOptionsPositional struct {
|
||||
PluginName string
|
||||
UserId *Identifier
|
||||
DomainId *Identifier
|
||||
ServiceId *Identifier
|
||||
|
||||
Options PluginOptions
|
||||
}
|
||||
|
||||
type TestPlugin interface {
|
||||
PluginEnvName() []string
|
||||
Version() PluginVersionInfo
|
||||
AvailableOptions() PluginOptionsDocumentation
|
||||
|
||||
RunTest(options PluginOptions, meta map[string]string) (*PluginResult, error)
|
||||
}
|
||||
|
|
@ -52,6 +66,21 @@ type PluginAvailability struct {
|
|||
LimitToServices []string `json:"limitToServices,omitempty"`
|
||||
}
|
||||
|
||||
type PluginOptionsDocumentation struct {
|
||||
RunOpts []PluginOptionDocumentation `json:"runOpts,omitempty"`
|
||||
ServiceOpts []PluginOptionDocumentation `json:"serviceOpts,omitempty"`
|
||||
DomainOpts []PluginOptionDocumentation `json:"domainOpts,omitempty"`
|
||||
UserOpts []PluginOptionDocumentation `json:"userOpts,omitempty"`
|
||||
AdminOpts []PluginOptionDocumentation `json:"adminOpts,omitempty"`
|
||||
}
|
||||
|
||||
type PluginOptionDocumentation Field
|
||||
|
||||
type PluginStatus struct {
|
||||
PluginVersionInfo
|
||||
Opts PluginOptionsDocumentation `json:"options"`
|
||||
}
|
||||
|
||||
type PluginResult struct {
|
||||
Status PluginResultStatus `json:"status"`
|
||||
StatusLine string `json:"statusLine,omitempty"`
|
||||
|
|
@ -65,5 +94,8 @@ type PluginManager interface {
|
|||
|
||||
type TestPluginUsecase interface {
|
||||
GetTestPlugin(string) (TestPlugin, error)
|
||||
GetTestPluginOptions(string, *Identifier, *Identifier, *Identifier) (*PluginOptions, error)
|
||||
ListTestPlugins() ([]TestPlugin, error)
|
||||
OverwriteSomeTestPluginOptions(string, *Identifier, *Identifier, *Identifier, PluginOptions) error
|
||||
SetTestPluginOptions(string, *Identifier, *Identifier, *Identifier, PluginOptions) error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,31 @@ func (p *MatrixTester) Version() happydns.PluginVersionInfo {
|
|||
}
|
||||
}
|
||||
|
||||
func (p *MatrixTester) AvailableOptions() happydns.PluginOptionsDocumentation {
|
||||
return happydns.PluginOptionsDocumentation{
|
||||
RunOpts: []happydns.PluginOptionDocumentation{
|
||||
{
|
||||
Id: "serviceDomain",
|
||||
Type: "string",
|
||||
Label: "Matrix domain",
|
||||
Placeholder: "matrix.org",
|
||||
Default: "matrix.org",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
AdminOpts: []happydns.PluginOptionDocumentation{
|
||||
{
|
||||
Id: "federationTesterServer",
|
||||
Type: "string",
|
||||
Label: "Federation Tester Server",
|
||||
Placeholder: "https://federationtester.matrix.org/",
|
||||
Default: "https://federationtester.matrix.org/",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type FederationTesterResponse struct {
|
||||
WellKnownResult struct {
|
||||
Server string `json:"m.server"`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue