Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ func (a *OIDCAPI) registerUser(username, oidcID string, hasAdminGroup bool) (*mo
return nil, http.StatusInternalServerError, fmt.Errorf("failed to create user: %w", err)
}
log.Info().Str("oidc_id", oidcID).Str("username", user.Name).Bool("admin", user.Admin).Msg("OIDC auto registration")
if err := a.UserChangeNotifier.fireUserAdded(user.ID); err != nil {
if err := a.UserChangeNotifier.fireUserAdded(a.DB, user.ID); err != nil {
log.Error().Err(err).Uint("user_id", user.ID).Msg("Could not notify user change")
}
return user, 0, nil
Expand Down
3 changes: 2 additions & 1 deletion api/oidc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/gin-gonic/gin"
"github.com/gotify/server/v3/auth"
"github.com/gotify/server/v3/database"
"github.com/gotify/server/v3/decaymap"
"github.com/gotify/server/v3/mode"
"github.com/gotify/server/v3/model"
Expand Down Expand Up @@ -49,7 +50,7 @@ func (s *OIDCSuite) BeforeTest(suiteName, testName string) {
s.db = testdb.NewDB(s.T())
s.notified = false
notifier := new(UserChangeNotifier)
notifier.OnUserAdded(func(uint) error {
notifier.OnUserAdded(func(tx *database.GormDatabase, uid uint) error {
s.notified = true
return nil
})
Expand Down
12 changes: 6 additions & 6 deletions api/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (c *PluginAPI) GetPlugins(ctx *gin.Context) {
Website: info.Website,
License: info.License,
Enabled: conf.Enabled,
Capabilities: inst.Supports().Strings(),
Capabilities: inst.Instance().Supports().Strings(),
})
}
}
Expand Down Expand Up @@ -255,7 +255,7 @@ func (c *PluginAPI) GetDisplay(ctx *gin.Context) {
ctx.AbortWithError(404, errors.New("plugin instance not found"))
return
}
ctx.JSON(200, instance.GetDisplay(location.Get(ctx)))
ctx.JSON(200, instance.Instance().GetDisplay(location.Get(ctx)))
})
}

Expand Down Expand Up @@ -317,7 +317,7 @@ func (c *PluginAPI) GetConfig(ctx *gin.Context) {
return
}

if aborted := supportOrAbort(ctx, instance, compat.Configurer); aborted {
if aborted := supportOrAbort(ctx, instance.Instance(), compat.Configurer); aborted {
return
}

Expand Down Expand Up @@ -381,11 +381,11 @@ func (c *PluginAPI) UpdateConfig(ctx *gin.Context) {
return
}

if aborted := supportOrAbort(ctx, instance, compat.Configurer); aborted {
if aborted := supportOrAbort(ctx, instance.Instance(), compat.Configurer); aborted {
return
}

newConf := instance.DefaultConfig()
newConf := instance.Instance().DefaultConfig()
newconfBytes, err := io.ReadAll(ctx.Request.Body)
if err != nil {
ctx.AbortWithError(500, err)
Expand All @@ -395,7 +395,7 @@ func (c *PluginAPI) UpdateConfig(ctx *gin.Context) {
ctx.AbortWithError(400, err)
return
}
if err := instance.ValidateAndSetConfig(newConf); err != nil {
if err := instance.Instance().ValidateAndSetConfig(newConf); err != nil {
ctx.AbortWithError(400, err)
return
}
Expand Down
71 changes: 53 additions & 18 deletions api/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"net/http/httptest"
"sync"
"testing"

"github.com/gin-gonic/gin"
Expand All @@ -29,6 +30,7 @@ type PluginSuite struct {
suite.Suite
db *testdb.Database
a *PluginAPI
u *UserAPI
ctx *gin.Context
recorder *httptest.ResponseRecorder
manager *plugin.Manager
Expand All @@ -39,19 +41,23 @@ func (s *PluginSuite) BeforeTest(suiteName, testName string) {
mode.Set(mode.TestDev)
s.db = testdb.NewDB(s.T())
s.resetRecorder()
manager, err := plugin.NewManager(s.db, "", nil, s)
manager, err := plugin.NewManager(s.db.GormDatabase, "", nil, s)
assert.Nil(s.T(), err)
s.manager = manager
withURL(s.ctx, "http", "example.com")
s.a = &PluginAPI{DB: s.db, Manager: manager, Notifier: s}
s.u = &UserAPI{DB: s.db.GormDatabase, UserChangeNotifier: &UserChangeNotifier{}}

mockPluginCompat := new(mock.Plugin)
assert.Nil(s.T(), s.manager.LoadPlugin(mockPluginCompat))

s.db.User(1)
assert.Nil(s.T(), s.manager.InitializeForUserID(1))
s.db.User(2)
assert.Nil(s.T(), s.manager.InitializeForUserID(2))
s.db.NewUserWithNameAdmin(1, "user1", true)
wg := &sync.WaitGroup{}
assert.Nil(s.T(), s.manager.InitializeForUserID(s.db.GormDatabase, 1, wg))
wg.Wait()
s.db.NewUserWithNameAdmin(2, "user2", true)
assert.Nil(s.T(), s.manager.InitializeForUserID(s.db.GormDatabase, 2, wg))
wg.Wait()

s.db.CreatePluginConf(&model.PluginConf{
UserID: 1,
Expand Down Expand Up @@ -97,6 +103,31 @@ func (s *PluginSuite) Test_GetPlugins() {
assert.False(s.T(), pluginConfs[0].Enabled, "Plugins should be disabled by default")
}

func (s *PluginSuite) Test_DeleteUser() {
test.WithUser(s.ctx, 1)

s.ctx.Request = httptest.NewRequest("POST", "/plugin/1/enable", nil)
s.ctx.Params = gin.Params{{Key: "id", Value: "1"}}
s.a.EnablePlugin(s.ctx)

assert.Equal(s.T(), 200, s.recorder.Code)

if pluginConf, err := s.db.GetPluginConfByUserAndPath(1, mock.ModulePath); assert.NoError(s.T(), err) {
assert.True(s.T(), pluginConf.Enabled)
}
s.resetRecorder()

s.ctx.Request = httptest.NewRequest("DELETE", "/user/1", nil)
s.ctx.Params = gin.Params{{Key: "id", Value: "1"}}
s.u.DeleteUserByID(s.ctx)

assert.Equal(s.T(), 200, s.recorder.Code)

user, err := s.db.GetUserByID(1)
assert.NoError(s.T(), err)
assert.Nil(s.T(), user)
}

func (s *PluginSuite) Test_EnableDisablePlugin() {
{
test.WithUser(s.ctx, 1)
Expand Down Expand Up @@ -161,7 +192,9 @@ func (s *PluginSuite) Test_EnableDisablePlugin() {

func (s *PluginSuite) Test_EnableDisablePlugin_EnableReturnsError_expect500() {
s.db.User(16)
assert.Nil(s.T(), s.manager.InitializeForUserID(16))
wg := &sync.WaitGroup{}
assert.Nil(s.T(), s.manager.InitializeForUserID(s.db.GormDatabase, 16, wg))
wg.Wait()
mock.ReturnErrorOnEnableForUser(16, errors.New("test error"))
conf, err := s.db.GetPluginConfByUserAndPath(16, mock.ModulePath)
assert.NoError(s.T(), err)
Expand All @@ -183,7 +216,9 @@ func (s *PluginSuite) Test_EnableDisablePlugin_EnableReturnsError_expect500() {

func (s *PluginSuite) Test_EnableDisablePlugin_DisableReturnsError_expect500() {
s.db.User(17)
assert.Nil(s.T(), s.manager.InitializeForUserID(17))
wg := &sync.WaitGroup{}
assert.Nil(s.T(), s.manager.InitializeForUserID(s.db.GormDatabase, 17, wg))
wg.Wait()
mock.ReturnErrorOnDisableForUser(17, errors.New("test error"))
conf, err := s.db.GetPluginConfByUserAndPath(17, mock.ModulePath)
assert.NoError(s.T(), err)
Expand Down Expand Up @@ -291,7 +326,7 @@ func (s *PluginSuite) Test_GetDisplay() {
assert.NoError(s.T(), err)
inst, err := s.manager.Instance(conf.ID)
assert.Nil(s.T(), err)
mockInst := inst.(*mock.PluginInstance)
mockInst := inst.Instance().(*mock.PluginInstance)

mockInst.DisplayString = "test string"

Expand All @@ -312,7 +347,7 @@ func (s *PluginSuite) Test_GetDisplay_NotImplemented_expectEmptyString() {
assert.NoError(s.T(), err)
inst, err := s.manager.Instance(conf.ID)
assert.Nil(s.T(), err)
mockInst := inst.(*mock.PluginInstance)
mockInst := inst.Instance().(*mock.PluginInstance)

mockInst.SetCapability(compat.Displayer, false)
defer mockInst.SetCapability(compat.Displayer, true)
Expand All @@ -334,7 +369,7 @@ func (s *PluginSuite) Test_GetDisplay_incorrectUser_expectNotFound() {
assert.NoError(s.T(), err)
inst, err := s.manager.Instance(conf.ID)
assert.Nil(s.T(), err)
mockInst := inst.(*mock.PluginInstance)
mockInst := inst.Instance().(*mock.PluginInstance)

mockInst.DisplayString = "test string"

Expand Down Expand Up @@ -380,7 +415,7 @@ func (s *PluginSuite) Test_GetConfig() {
assert.NoError(s.T(), err)
inst, err := s.manager.Instance(conf.ID)
assert.Nil(s.T(), err)
mockInst := inst.(*mock.PluginInstance)
mockInst := inst.Instance().(*mock.PluginInstance)

assert.Equal(s.T(), mockInst.DefaultConfig(), mockInst.Config, "Initial config should be default config")
{
Expand All @@ -402,7 +437,7 @@ func (s *PluginSuite) Test_GetConfg_notImplemeted_expect400() {
assert.NoError(s.T(), err)
inst, err := s.manager.Instance(conf.ID)
assert.Nil(s.T(), err)
mockInst := inst.(*mock.PluginInstance)
mockInst := inst.Instance().(*mock.PluginInstance)

mockInst.SetCapability(compat.Configurer, false)
defer mockInst.SetCapability(compat.Configurer, true)
Expand Down Expand Up @@ -464,7 +499,7 @@ func (s *PluginSuite) Test_UpdateConfig() {
assert.NoError(s.T(), err)
inst, err := s.manager.Instance(conf.ID)
assert.Nil(s.T(), err)
mockInst := inst.(*mock.PluginInstance)
mockInst := inst.Instance().(*mock.PluginInstance)

newConfig := &mock.PluginConfig{
TestKey: "test__new__config",
Expand Down Expand Up @@ -499,7 +534,7 @@ func (s *PluginSuite) Test_UpdateConfig_invalidConfig_expect400() {
assert.NoError(s.T(), err)
inst, err := s.manager.Instance(conf.ID)
assert.Nil(s.T(), err)
mockInst := inst.(*mock.PluginInstance)
mockInst := inst.Instance().(*mock.PluginInstance)
origConfig := mockInst.Config

newConfig := &mock.PluginConfig{
Expand Down Expand Up @@ -536,7 +571,7 @@ func (s *PluginSuite) Test_UpdateConfig_malformedYAML_expect400() {
assert.NoError(s.T(), err)
inst, err := s.manager.Instance(conf.ID)
assert.Nil(s.T(), err)
mockInst := inst.(*mock.PluginInstance)
mockInst := inst.Instance().(*mock.PluginInstance)
origConfig := mockInst.Config

newConfigYAML := []byte(`--- "rg e""`)
Expand Down Expand Up @@ -568,7 +603,7 @@ func (s *PluginSuite) Test_UpdateConfig_ioError_expect500() {
assert.NoError(s.T(), err)
inst, err := s.manager.Instance(conf.ID)
assert.Nil(s.T(), err)
mockInst := inst.(*mock.PluginInstance)
mockInst := inst.Instance().(*mock.PluginInstance)
origConfig := mockInst.Config

{
Expand Down Expand Up @@ -598,7 +633,7 @@ func (s *PluginSuite) Test_UpdateConfig_notImplemented_expect400() {
assert.NoError(s.T(), err)
inst, err := s.manager.Instance(conf.ID)
assert.Nil(s.T(), err)
mockInst := inst.(*mock.PluginInstance)
mockInst := inst.Instance().(*mock.PluginInstance)

newConfig := &mock.PluginConfig{
TestKey: "test__new__config",
Expand Down Expand Up @@ -626,7 +661,7 @@ func (s *PluginSuite) Test_UpdateConfig_incorrectUser_expectNotFound() {
assert.NoError(s.T(), err)
inst, err := s.manager.Instance(conf.ID)
assert.Nil(s.T(), err)
mockInst := inst.(*mock.PluginInstance)
mockInst := inst.Instance().(*mock.PluginInstance)
origConfig := mockInst.Config

newConfig := &mock.PluginConfig{
Expand Down
3 changes: 2 additions & 1 deletion api/stream/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/gorilla/websocket"
"github.com/gotify/server/v3/auth"
"github.com/gotify/server/v3/config"
"github.com/gotify/server/v3/database"
"github.com/gotify/server/v3/model"
)

Expand Down Expand Up @@ -51,7 +52,7 @@ func (a *API) CollectConnectedClientTokens() []string {
}

// NotifyDeletedUser closes existing connections for the given user.
func (a *API) NotifyDeletedUser(userID uint) error {
func (a *API) NotifyDeletedUser(tx *database.GormDatabase, userID uint) error {
a.lock.Lock()
defer a.lock.Unlock()
if clients, ok := a.clients[userID]; ok {
Expand Down
2 changes: 1 addition & 1 deletion api/stream/stream_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ func TestDeleteUser(t *testing.T) {
expectNoMessage(userTwo...)
expectNoMessage(userThree...)

api.NotifyDeletedUser(1)
api.NotifyDeletedUser(nil, 1)

api.Notify(1, &model.MessageExternal{ID: 2, Message: "there"})
expectNoMessage(userOne...)
Expand Down
Loading
Loading