From 2728ee25be9fd94108bc52fe65e11057978b270d Mon Sep 17 00:00:00 2001 From: louis Date: Mon, 20 Jan 2025 16:29:32 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20Ticker=20Reset?= =?UTF-8?q?=20and=20Delete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/api/tickers.go | 47 ++------ internal/api/tickers_test.go | 44 ++----- internal/storage/mock_Storage.go | 128 ++++++++++++++++++-- internal/storage/sql_storage.go | 85 +++++++++++-- internal/storage/sql_storage_test.go | 173 +++++++++++++++++++++++++-- internal/storage/storage.go | 12 +- internal/storage/ticker.go | 38 ------ internal/storage/ticker_test.go | 26 ---- 8 files changed, 379 insertions(+), 174 deletions(-) diff --git a/internal/api/tickers.go b/internal/api/tickers.go index 0b44d349..0f960359 100644 --- a/internal/api/tickers.go +++ b/internal/api/tickers.go @@ -165,9 +165,7 @@ func (h *handler) DeleteTickerTelegram(c *gin.Context) { return } - ticker.Telegram.Reset() - - err = h.storage.SaveTicker(&ticker) + err = h.storage.DeleteTelegram(&ticker) if err != nil { c.JSON(http.StatusBadRequest, response.ErrorResponse(response.CodeDefault, response.StorageError)) return @@ -233,9 +231,7 @@ func (h *handler) DeleteTickerMastodon(c *gin.Context) { return } - ticker.Mastodon.Reset() - - err = h.storage.SaveTicker(&ticker) + err = h.storage.DeleteMastodon(&ticker) if err != nil { c.JSON(http.StatusBadRequest, response.ErrorResponse(response.CodeDefault, response.StorageError)) return @@ -286,9 +282,7 @@ func (h *handler) DeleteTickerBluesky(c *gin.Context) { return } - ticker.Bluesky.Reset() - - err = h.storage.SaveTicker(&ticker) + err = h.storage.DeleteBluesky(&ticker) if err != nil { c.JSON(http.StatusBadRequest, response.ErrorResponse(response.CodeDefault, response.StorageError)) return @@ -352,9 +346,7 @@ func (h *handler) DeleteTickerSignalGroup(c *gin.Context) { return } - ticker.SignalGroup.Reset() - - err = h.storage.SaveTicker(&ticker) + err = h.storage.DeleteSignalGroup(&ticker) if err != nil { c.JSON(http.StatusBadRequest, response.ErrorResponse(response.CodeDefault, response.StorageError)) return @@ -398,17 +390,9 @@ func (h *handler) DeleteTicker(c *gin.Context) { return } - err = h.storage.DeleteMessages(ticker) - if err != nil { - log.WithError(err).Error("failed to delete message for ticker") - } - err = h.storage.DeleteUploadsByTicker(ticker) + err = h.storage.DeleteTicker(&ticker) if err != nil { - log.WithError(err).Error("failed to delete uploads for ticker") - } - err = h.storage.DeleteTicker(ticker) - if err != nil { - c.JSON(http.StatusNotFound, response.ErrorResponse(response.CodeNotFound, response.StorageError)) + c.JSON(http.StatusInternalServerError, response.ErrorResponse(response.CodeDefault, response.StorageError)) return } @@ -452,24 +436,7 @@ func (h *handler) ResetTicker(c *gin.Context) { return } - err = h.storage.DeleteMessages(ticker) - if err != nil { - log.WithError(err).WithField("ticker", ticker.ID).Error("error while deleting messages") - } - err = h.storage.DeleteUploadsByTicker(ticker) - if err != nil { - log.WithError(err).WithField("ticker", ticker.ID).Error("error while deleting remaining uploads") - } - - ticker.Reset() - - err = h.storage.SaveTicker(&ticker) - if err != nil { - c.JSON(http.StatusInternalServerError, response.ErrorResponse(response.CodeDefault, response.StorageError)) - return - } - - err = h.storage.DeleteTickerUsers(&ticker) + err = h.storage.ResetTicker(&ticker) if err != nil { c.JSON(http.StatusInternalServerError, response.ErrorResponse(response.CodeDefault, response.StorageError)) return diff --git a/internal/api/tickers_test.go b/internal/api/tickers_test.go index 8ee49133..88006506 100644 --- a/internal/api/tickers_test.go +++ b/internal/api/tickers_test.go @@ -327,7 +327,7 @@ func (s *TickerTestSuite) TestDeleteTickerTelegram() { s.Run("when storage returns error", func() { s.ctx.Set("ticker", storage.Ticker{}) - s.store.On("SaveTicker", mock.Anything).Return(errors.New("storage error")).Once() + s.store.On("DeleteTelegram", mock.Anything).Return(errors.New("storage error")).Once() h := s.handler() h.DeleteTickerTelegram(s.ctx) @@ -337,7 +337,7 @@ func (s *TickerTestSuite) TestDeleteTickerTelegram() { s.Run("when storage returns ticker", func() { s.ctx.Set("ticker", storage.Ticker{}) - s.store.On("SaveTicker", mock.Anything).Return(nil).Once() + s.store.On("DeleteTelegram", mock.Anything).Return(nil).Once() h := s.handler() h.DeleteTickerTelegram(s.ctx) @@ -428,7 +428,7 @@ func (s *TickerTestSuite) TestDeleteTickerMastodon() { s.Run("when storage returns error", func() { s.ctx.Set("ticker", storage.Ticker{}) - s.store.On("SaveTicker", mock.Anything).Return(errors.New("storage error")).Once() + s.store.On("DeleteMastodon", mock.Anything).Return(errors.New("storage error")).Once() h := s.handler() h.DeleteTickerMastodon(s.ctx) @@ -438,7 +438,7 @@ func (s *TickerTestSuite) TestDeleteTickerMastodon() { s.Run("when storage returns ticker", func() { s.ctx.Set("ticker", storage.Ticker{}) - s.store.On("SaveTicker", mock.Anything).Return(nil).Once() + s.store.On("DeleteMastodon", mock.Anything).Return(nil).Once() h := s.handler() h.DeleteTickerMastodon(s.ctx) @@ -555,7 +555,7 @@ func (s *TickerTestSuite) TestDeleteTickerBluesky() { s.Run("when storage returns error", func() { s.ctx.Set("ticker", storage.Ticker{}) - s.store.On("SaveTicker", mock.Anything).Return(errors.New("storage error")).Once() + s.store.On("DeleteBluesky", mock.Anything).Return(errors.New("storage error")).Once() h := s.handler() h.DeleteTickerBluesky(s.ctx) @@ -565,7 +565,7 @@ func (s *TickerTestSuite) TestDeleteTickerBluesky() { s.Run("when storage returns ticker", func() { s.ctx.Set("ticker", storage.Ticker{}) - s.store.On("SaveTicker", mock.Anything).Return(nil).Once() + s.store.On("DeleteBluesky", mock.Anything).Return(nil).Once() h := s.handler() h.DeleteTickerBluesky(s.ctx) @@ -982,7 +982,7 @@ func (s *TickerTestSuite) TestDeleteTickerSignalGroup() { }) s.ctx.Request = httptest.NewRequest(http.MethodDelete, "/v1/admin/tickers/1/signal_group", nil) s.ctx.Request.Header.Add("Content-Type", "application/json") - s.store.On("SaveTicker", mock.Anything).Return(errors.New("storage error")).Once() + s.store.On("DeleteSignalGroup", mock.Anything).Return(errors.New("storage error")).Once() h := s.handler() h.DeleteTickerSignalGroup(s.ctx) @@ -1061,7 +1061,7 @@ func (s *TickerTestSuite) TestDeleteTickerSignalGroup() { }) s.ctx.Request = httptest.NewRequest(http.MethodDelete, "/v1/admin/tickers/1/signal_group", nil) s.ctx.Request.Header.Add("Content-Type", "application/json") - s.store.On("SaveTicker", mock.Anything).Return(nil).Once() + s.store.On("DeleteSignalGroup", mock.Anything).Return(nil).Once() h := s.handler() h.DeleteTickerSignalGroup(s.ctx) @@ -1156,21 +1156,17 @@ func (s *TickerTestSuite) TestDeleteTicker() { s.Run("when storage returns error", func() { s.ctx.Set("ticker", storage.Ticker{}) - s.store.On("DeleteMessages", mock.Anything).Return(errors.New("storage error")) - s.store.On("DeleteUploadsByTicker", mock.Anything).Return(errors.New("storage error")) s.store.On("DeleteTicker", mock.Anything).Return(errors.New("storage error")) h := s.handler() h.DeleteTicker(s.ctx) - s.Equal(http.StatusNotFound, s.w.Code) + s.Equal(http.StatusInternalServerError, s.w.Code) s.store.AssertExpectations(s.T()) }) s.Run("happy path", func() { s.cache.Set("response:localhost:/v1/init", true, time.Minute) s.ctx.Set("ticker", storage.Ticker{Domain: "localhost"}) - s.store.On("DeleteMessages", mock.Anything).Return(nil) - s.store.On("DeleteUploadsByTicker", mock.Anything).Return(nil) s.store.On("DeleteTicker", mock.Anything).Return(nil) h := s.handler() h.DeleteTicker(s.ctx) @@ -1246,22 +1242,7 @@ func (s *TickerTestSuite) TestResetTicker() { s.Run("when storage returns error", func() { s.ctx.Set("ticker", storage.Ticker{}) - s.store.On("DeleteMessages", mock.Anything).Return(errors.New("storage error")).Once() - s.store.On("DeleteUploadsByTicker", mock.Anything).Return(errors.New("storage error")).Once() - s.store.On("SaveTicker", mock.Anything).Return(errors.New("storage error")).Once() - h := s.handler() - h.ResetTicker(s.ctx) - - s.Equal(http.StatusInternalServerError, s.w.Code) - s.store.AssertExpectations(s.T()) - }) - - s.Run("when deleting users fails", func() { - s.ctx.Set("ticker", storage.Ticker{}) - s.store.On("DeleteMessages", mock.Anything).Return(nil).Once() - s.store.On("DeleteUploadsByTicker", mock.Anything).Return(nil).Once() - s.store.On("SaveTicker", mock.Anything).Return(nil).Once() - s.store.On("DeleteTickerUsers", mock.Anything).Return(errors.New("storage error")).Once() + s.store.On("ResetTicker", mock.Anything).Return(errors.New("storage error")).Once() h := s.handler() h.ResetTicker(s.ctx) @@ -1272,10 +1253,7 @@ func (s *TickerTestSuite) TestResetTicker() { s.Run("happy path", func() { s.cache.Set("response:localhost:/v1/init", true, time.Minute) s.ctx.Set("ticker", storage.Ticker{Domain: "localhost"}) - s.store.On("DeleteMessages", mock.Anything).Return(nil).Once() - s.store.On("DeleteUploadsByTicker", mock.Anything).Return(nil).Once() - s.store.On("SaveTicker", mock.Anything).Return(nil).Once() - s.store.On("DeleteTickerUsers", mock.Anything).Return(nil).Once() + s.store.On("ResetTicker", mock.Anything).Return(nil).Once() h := s.handler() h.ResetTicker(s.ctx) diff --git a/internal/storage/mock_Storage.go b/internal/storage/mock_Storage.go index fe6f0c9c..cfa9417f 100644 --- a/internal/storage/mock_Storage.go +++ b/internal/storage/mock_Storage.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.43.0. DO NOT EDIT. +// Code generated by mockery v2.50.4. DO NOT EDIT. package storage @@ -31,6 +31,60 @@ func (_m *MockStorage) AddTickerUser(ticker *Ticker, user *User) error { return r0 } +// DeleteBluesky provides a mock function with given fields: ticker +func (_m *MockStorage) DeleteBluesky(ticker *Ticker) error { + ret := _m.Called(ticker) + + if len(ret) == 0 { + panic("no return value specified for DeleteBluesky") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*Ticker) error); ok { + r0 = rf(ticker) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteIntegrations provides a mock function with given fields: ticker +func (_m *MockStorage) DeleteIntegrations(ticker *Ticker) error { + ret := _m.Called(ticker) + + if len(ret) == 0 { + panic("no return value specified for DeleteIntegrations") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*Ticker) error); ok { + r0 = rf(ticker) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteMastodon provides a mock function with given fields: ticker +func (_m *MockStorage) DeleteMastodon(ticker *Ticker) error { + ret := _m.Called(ticker) + + if len(ret) == 0 { + panic("no return value specified for DeleteMastodon") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*Ticker) error); ok { + r0 = rf(ticker) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // DeleteMessage provides a mock function with given fields: message func (_m *MockStorage) DeleteMessage(message Message) error { ret := _m.Called(message) @@ -50,7 +104,7 @@ func (_m *MockStorage) DeleteMessage(message Message) error { } // DeleteMessages provides a mock function with given fields: ticker -func (_m *MockStorage) DeleteMessages(ticker Ticker) error { +func (_m *MockStorage) DeleteMessages(ticker *Ticker) error { ret := _m.Called(ticker) if len(ret) == 0 { @@ -58,7 +112,43 @@ func (_m *MockStorage) DeleteMessages(ticker Ticker) error { } var r0 error - if rf, ok := ret.Get(0).(func(Ticker) error); ok { + if rf, ok := ret.Get(0).(func(*Ticker) error); ok { + r0 = rf(ticker) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteSignalGroup provides a mock function with given fields: ticker +func (_m *MockStorage) DeleteSignalGroup(ticker *Ticker) error { + ret := _m.Called(ticker) + + if len(ret) == 0 { + panic("no return value specified for DeleteSignalGroup") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*Ticker) error); ok { + r0 = rf(ticker) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteTelegram provides a mock function with given fields: ticker +func (_m *MockStorage) DeleteTelegram(ticker *Ticker) error { + ret := _m.Called(ticker) + + if len(ret) == 0 { + panic("no return value specified for DeleteTelegram") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*Ticker) error); ok { r0 = rf(ticker) } else { r0 = ret.Error(0) @@ -68,7 +158,7 @@ func (_m *MockStorage) DeleteMessages(ticker Ticker) error { } // DeleteTicker provides a mock function with given fields: ticker -func (_m *MockStorage) DeleteTicker(ticker Ticker) error { +func (_m *MockStorage) DeleteTicker(ticker *Ticker) error { ret := _m.Called(ticker) if len(ret) == 0 { @@ -76,7 +166,7 @@ func (_m *MockStorage) DeleteTicker(ticker Ticker) error { } var r0 error - if rf, ok := ret.Get(0).(func(Ticker) error); ok { + if rf, ok := ret.Get(0).(func(*Ticker) error); ok { r0 = rf(ticker) } else { r0 = ret.Error(0) @@ -145,7 +235,7 @@ func (_m *MockStorage) DeleteUploads(uploads []Upload) { } // DeleteUploadsByTicker provides a mock function with given fields: ticker -func (_m *MockStorage) DeleteUploadsByTicker(ticker Ticker) error { +func (_m *MockStorage) DeleteUploadsByTicker(ticker *Ticker) error { ret := _m.Called(ticker) if len(ret) == 0 { @@ -153,7 +243,7 @@ func (_m *MockStorage) DeleteUploadsByTicker(ticker Ticker) error { } var r0 error - if rf, ok := ret.Get(0).(func(Ticker) error); ok { + if rf, ok := ret.Get(0).(func(*Ticker) error); ok { r0 = rf(ticker) } else { r0 = ret.Error(0) @@ -707,7 +797,7 @@ func (_m *MockStorage) FindUsersByTicker(ticker Ticker, opts ...func(*gorm.DB) * return r0, r1 } -// GetInactiveSettings provides a mock function with given fields: +// GetInactiveSettings provides a mock function with no fields func (_m *MockStorage) GetInactiveSettings() InactiveSettings { ret := _m.Called() @@ -725,7 +815,7 @@ func (_m *MockStorage) GetInactiveSettings() InactiveSettings { return r0 } -// GetRefreshIntervalSettings provides a mock function with given fields: +// GetRefreshIntervalSettings provides a mock function with no fields func (_m *MockStorage) GetRefreshIntervalSettings() RefreshIntervalSettings { ret := _m.Called() @@ -743,6 +833,24 @@ func (_m *MockStorage) GetRefreshIntervalSettings() RefreshIntervalSettings { return r0 } +// ResetTicker provides a mock function with given fields: ticker +func (_m *MockStorage) ResetTicker(ticker *Ticker) error { + ret := _m.Called(ticker) + + if len(ret) == 0 { + panic("no return value specified for ResetTicker") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*Ticker) error); ok { + r0 = rf(ticker) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // SaveInactiveSettings provides a mock function with given fields: inactiveSettings func (_m *MockStorage) SaveInactiveSettings(inactiveSettings InactiveSettings) error { ret := _m.Called(inactiveSettings) @@ -851,7 +959,7 @@ func (_m *MockStorage) SaveUser(user *User) error { return r0 } -// UploadPath provides a mock function with given fields: +// UploadPath provides a mock function with no fields func (_m *MockStorage) UploadPath() string { ret := _m.Called() diff --git a/internal/storage/sql_storage.go b/internal/storage/sql_storage.go index 40861b35..3349f0d9 100644 --- a/internal/storage/sql_storage.go +++ b/internal/storage/sql_storage.go @@ -190,36 +190,95 @@ func (s *SqlStorage) SaveTicker(ticker *Ticker) error { } // DeleteTicker deletes a ticker and all associated data. -func (s *SqlStorage) DeleteTicker(ticker Ticker) error { - if err := s.DeleteTickerUsers(&ticker); err != nil { +func (s *SqlStorage) DeleteTicker(ticker *Ticker) error { + if err := s.deleteTickerAssociations(ticker); err != nil { + return err + } + + return s.DB.Delete(&ticker).Error +} + +func (s *SqlStorage) ResetTicker(ticker *Ticker) error { + if err := s.deleteTickerAssociations(ticker); err != nil { + return err + } + + ticker.Active = false + ticker.Title = "Ticker" + ticker.Description = "" + ticker.Information = TickerInformation{} + ticker.Location = TickerLocation{} + ticker.Users = make([]User, 0) + + return s.DB.Save(&ticker).Error +} + +func (s *SqlStorage) deleteTickerAssociations(ticker *Ticker) error { + if err := s.DeleteTickerUsers(ticker); err != nil { log.WithError(err).WithField("ticker_id", ticker.ID).Error("failed to delete ticker users") + return err } if err := s.DeleteUploadsByTicker(ticker); err != nil { log.WithError(err).WithField("ticker_id", ticker.ID).Error("failed to delete ticker uploads") + return err } if err := s.DeleteMessages(ticker); err != nil { log.WithError(err).WithField("ticker_id", ticker.ID).Error("failed to delete ticker messages") + return err } - if err := s.DB.Delete(TickerMastodon{}, "ticker_id = ?", ticker.ID).Error; err != nil { - log.WithError(err).WithField("ticker_id", ticker.ID).Error("failed to delete mastodon settings") + if err := s.DeleteIntegrations(ticker); err != nil { + log.WithError(err).WithField("ticker_id", ticker.ID).Error("failed to delete ticker integrations") + return err } - if err := s.DB.Delete(TickerTelegram{}, "ticker_id = ?", ticker.ID).Error; err != nil { - log.WithError(err).WithField("ticker_id", ticker.ID).Error("failed to delete telegram settings") + return nil +} + +func (s *SqlStorage) DeleteIntegrations(ticker *Ticker) error { + if err := s.DeleteMastodon(ticker); err != nil { + return err } - if err := s.DB.Delete(TickerBluesky{}, "ticker_id = ?", ticker.ID).Error; err != nil { - log.WithError(err).WithField("ticker_id", ticker.ID).Error("failed to delete bluesky settings") + if err := s.DeleteTelegram(ticker); err != nil { + return err } - if err := s.DB.Delete(TickerSignalGroup{}, "ticker_id = ?", ticker.ID).Error; err != nil { - log.WithError(err).WithField("ticker_id", ticker.ID).Error("failed to delete signal group settings") + if err := s.DeleteBluesky(ticker); err != nil { + return err } - return s.DB.Delete(&ticker).Error + if err := s.DeleteSignalGroup(ticker); err != nil { + return err + } + + return nil +} + +func (s *SqlStorage) DeleteMastodon(ticker *Ticker) error { + ticker.Mastodon = TickerMastodon{} + + return s.DB.Delete(TickerMastodon{}, "ticker_id = ?", ticker.ID).Error +} + +func (s *SqlStorage) DeleteTelegram(ticker *Ticker) error { + ticker.Telegram = TickerTelegram{} + + return s.DB.Delete(TickerTelegram{}, "ticker_id = ?", ticker.ID).Error +} + +func (s *SqlStorage) DeleteBluesky(ticker *Ticker) error { + ticker.Bluesky = TickerBluesky{} + + return s.DB.Delete(TickerBluesky{}, "ticker_id = ?", ticker.ID).Error +} + +func (s *SqlStorage) DeleteSignalGroup(ticker *Ticker) error { + ticker.SignalGroup = TickerSignalGroup{} + + return s.DB.Delete(TickerSignalGroup{}, "ticker_id = ?", ticker.ID).Error } func (s *SqlStorage) FindUploadByUUID(uuid string) (Upload, error) { @@ -267,7 +326,7 @@ func (s *SqlStorage) DeleteUploads(uploads []Upload) { } } -func (s *SqlStorage) DeleteUploadsByTicker(ticker Ticker) error { +func (s *SqlStorage) DeleteUploadsByTicker(ticker *Ticker) error { uploads := make([]Upload, 0) s.DB.Model(&Upload{}).Where("ticker_id = ?", ticker.ID).Find(&uploads) @@ -332,7 +391,7 @@ func (s *SqlStorage) DeleteMessage(message Message) error { return s.DB.Delete(&message).Error } -func (s *SqlStorage) DeleteMessages(ticker Ticker) error { +func (s *SqlStorage) DeleteMessages(ticker *Ticker) error { var msgIds []int err := s.DB.Model(&Message{}).Where("ticker_id = ?", ticker.ID).Pluck("id", &msgIds).Error if err != nil { diff --git a/internal/storage/sql_storage_test.go b/internal/storage/sql_storage_test.go index 177b0160..44784ec0 100644 --- a/internal/storage/sql_storage_test.go +++ b/internal/storage/sql_storage_test.go @@ -696,16 +696,167 @@ func (s *SqlStorageTestSuite) TestSaveTicker() { }) } +func (s *SqlStorageTestSuite) TestDeleteIntegrations() { + s.Run("when ticker is resetting integrations", func() { + var telegramCount, mastodonCount, blueskyCount, signalGroupCount int64 + + ticker := Ticker{} + ticker.Telegram = TickerTelegram{Active: true, ChannelName: "channel"} + ticker.Mastodon = TickerMastodon{Active: true, Server: "server", Token: "token", AccessToken: "access_token"} + ticker.Bluesky = TickerBluesky{Active: true, AppKey: "app_key"} + ticker.SignalGroup = TickerSignalGroup{Active: true, GroupID: "group_id", GroupInviteLink: "group_invite_link"} + + err := s.store.SaveTicker(&ticker) + s.NoError(err) + + s.store.DB.Model(&TickerTelegram{}).Where("ticker_id = ?", ticker.ID).Count(&telegramCount) + s.store.DB.Model(&TickerMastodon{}).Where("ticker_id = ?", ticker.ID).Count(&mastodonCount) + s.store.DB.Model(&TickerBluesky{}).Where("ticker_id = ?", ticker.ID).Count(&blueskyCount) + s.store.DB.Model(&TickerSignalGroup{}).Where("ticker_id = ?", ticker.ID).Count(&signalGroupCount) + + s.Equal(int64(1), telegramCount) + s.Equal(int64(1), mastodonCount) + s.Equal(int64(1), blueskyCount) + s.Equal(int64(1), signalGroupCount) + + s.True(ticker.Telegram.Active) + s.Equal("channel", ticker.Telegram.ChannelName) + s.True(ticker.Mastodon.Active) + s.Equal("server", ticker.Mastodon.Server) + s.Equal("token", ticker.Mastodon.Token) + s.Equal("access_token", ticker.Mastodon.AccessToken) + s.True(ticker.Bluesky.Active) + s.Equal("app_key", ticker.Bluesky.AppKey) + s.True(ticker.SignalGroup.Active) + s.Equal("group_id", ticker.SignalGroup.GroupID) + s.Equal("group_invite_link", ticker.SignalGroup.GroupInviteLink) + + err = s.store.DeleteIntegrations(&ticker) + s.NoError(err) + + s.False(ticker.Telegram.Active) + s.Empty(ticker.Telegram.ChannelName) + s.False(ticker.Mastodon.Active) + s.Empty(ticker.Mastodon.Server) + s.Empty(ticker.Mastodon.Token) + s.Empty(ticker.Mastodon.AccessToken) + s.False(ticker.Bluesky.Active) + s.Empty(ticker.Bluesky.AppKey) + s.False(ticker.SignalGroup.Active) + s.Empty(ticker.SignalGroup.GroupID) + s.Empty(ticker.SignalGroup.GroupInviteLink) + + s.store.DB.Model(&TickerTelegram{}).Where("ticker_id = ?", ticker.ID).Count(&telegramCount) + s.store.DB.Model(&TickerMastodon{}).Where("ticker_id = ?", ticker.ID).Count(&mastodonCount) + s.store.DB.Model(&TickerBluesky{}).Where("ticker_id = ?", ticker.ID).Count(&blueskyCount) + s.store.DB.Model(&TickerSignalGroup{}).Where("ticker_id = ?", ticker.ID).Count(&signalGroupCount) + s.Equal(int64(0), telegramCount) + s.Equal(int64(0), mastodonCount) + s.Equal(int64(0), blueskyCount) + s.Equal(int64(0), signalGroupCount) + }) +} + +func (s *SqlStorageTestSuite) TestResetTicker() { + ticker := &Ticker{ + Title: "title", + Domain: "example.org", + Active: true, + Description: "description", + Information: TickerInformation{ + Author: "author", + Email: "email", + Twitter: "twitter", + Facebook: "facebook", + Telegram: "telegram", + Mastodon: "mastodon", + Bluesky: "bluesky", + }, + Location: TickerLocation{ + Lat: 1, + Lon: 1, + }, + } + + err := s.store.SaveTicker(ticker) + s.NoError(err) + s.NotZero(ticker.ID) + + s.Run("basic reset", func() { + err = s.store.ResetTicker(ticker) + + s.NoError(err) + s.Equal("Ticker", ticker.Title) + s.Equal("example.org", ticker.Domain) + s.False(ticker.Active) + s.Empty(ticker.Description) + s.Empty(ticker.Information.Author) + s.Empty(ticker.Information.Email) + s.Empty(ticker.Information.Twitter) + s.Empty(ticker.Information.Facebook) + s.Empty(ticker.Information.Telegram) + s.Empty(ticker.Information.Mastodon) + s.Empty(ticker.Information.Bluesky) + s.Zero(ticker.Location.Lat) + s.Zero(ticker.Location.Lon) + }) + + s.Run("with integrations", func() { + var telegramCount, mastodonCount, blueskyCount, signalGroupCount int64 + ticker.Telegram = TickerTelegram{Active: true, ChannelName: "channel"} + ticker.Mastodon = TickerMastodon{Active: true, Server: "server", Token: "token", AccessToken: "access_token"} + ticker.Bluesky = TickerBluesky{Active: true, AppKey: "app_key"} + ticker.SignalGroup = TickerSignalGroup{Active: true, GroupID: "group_id", GroupInviteLink: "group_invite_link"} + + err = s.store.SaveTicker(ticker) + s.NoError(err) + + s.store.DB.Model(&TickerTelegram{}).Where("ticker_id = ?", ticker.ID).Count(&telegramCount) + s.store.DB.Model(&TickerMastodon{}).Where("ticker_id = ?", ticker.ID).Count(&mastodonCount) + s.store.DB.Model(&TickerBluesky{}).Where("ticker_id = ?", ticker.ID).Count(&blueskyCount) + s.store.DB.Model(&TickerSignalGroup{}).Where("ticker_id = ?", ticker.ID).Count(&signalGroupCount) + + s.Equal(int64(1), telegramCount) + s.Equal(int64(1), mastodonCount) + s.Equal(int64(1), blueskyCount) + s.Equal(int64(1), signalGroupCount) + + err = s.store.ResetTicker(ticker) + s.NoError(err) + s.False(ticker.Telegram.Active) + s.False(ticker.Mastodon.Active) + s.False(ticker.Bluesky.Active) + s.False(ticker.SignalGroup.Active) + s.Empty(ticker.Telegram.ChannelName) + s.Empty(ticker.Mastodon.Server) + s.Empty(ticker.Mastodon.Token) + s.Empty(ticker.Mastodon.AccessToken) + s.Empty(ticker.Bluesky.AppKey) + s.Empty(ticker.SignalGroup.GroupID) + s.Empty(ticker.SignalGroup.GroupInviteLink) + + s.store.DB.Model(&TickerTelegram{}).Where("ticker_id = ?", ticker.ID).Count(&telegramCount) + s.store.DB.Model(&TickerMastodon{}).Where("ticker_id = ?", ticker.ID).Count(&mastodonCount) + s.store.DB.Model(&TickerBluesky{}).Where("ticker_id = ?", ticker.ID).Count(&blueskyCount) + s.store.DB.Model(&TickerSignalGroup{}).Where("ticker_id = ?", ticker.ID).Count(&signalGroupCount) + + s.Equal(int64(0), telegramCount) + s.Equal(int64(0), mastodonCount) + s.Equal(int64(0), blueskyCount) + s.Equal(int64(0), signalGroupCount) + }) +} + func (s *SqlStorageTestSuite) TestDeleteTicker() { s.Run("when ticker does not exist", func() { - ticker := Ticker{ID: 1} + ticker := &Ticker{ID: 1} err := s.store.DeleteTicker(ticker) s.NoError(err) }) s.Run("when ticker exists", func() { - ticker := Ticker{ID: 1} - err := s.db.Create(&ticker).Error + ticker := &Ticker{ID: 1} + err := s.db.Create(ticker).Error s.NoError(err) err = s.store.DeleteTicker(ticker) @@ -724,7 +875,7 @@ func (s *SqlStorageTestSuite) TestDeleteTicker() { err = s.db.Create(&user).Error s.NoError(err) - ticker := Ticker{ID: 1, Users: []User{user}} + ticker := &Ticker{ID: 1, Users: []User{user}} err = s.db.Create(&ticker).Error s.NoError(err) @@ -743,7 +894,7 @@ func (s *SqlStorageTestSuite) TestDeleteTicker() { }) s.Run("when ticker exists with uploads", func() { - ticker := Ticker{ID: 1} + ticker := &Ticker{ID: 1} err := s.db.Create(&ticker).Error s.NoError(err) @@ -766,7 +917,7 @@ func (s *SqlStorageTestSuite) TestDeleteTicker() { }) s.Run("when ticker exists with messages", func() { - ticker := Ticker{ID: 1} + ticker := &Ticker{ID: 1} err := s.db.Create(&ticker).Error s.NoError(err) @@ -789,7 +940,7 @@ func (s *SqlStorageTestSuite) TestDeleteTicker() { }) s.Run("when ticker exists with integrations", func() { - ticker := Ticker{ID: 1} + ticker := &Ticker{ID: 1} err := s.db.Create(&ticker).Error s.NoError(err) @@ -952,13 +1103,13 @@ func (s *SqlStorageTestSuite) TestDeleteUploads() { func (s *SqlStorageTestSuite) TestDeleteUploadsByTicker() { s.Run("when uploads do not exist", func() { - ticker := Ticker{ID: 1} + ticker := &Ticker{ID: 1} err := s.store.DeleteUploadsByTicker(ticker) s.NoError(err) }) s.Run("when uploads exist", func() { - ticker := Ticker{ID: 1} + ticker := &Ticker{ID: 1} err := s.db.Create(&ticker).Error s.NoError(err) @@ -1172,7 +1323,7 @@ func (s *SqlStorageTestSuite) TestDeleteMessage() { } func (s *SqlStorageTestSuite) TestDeleteMessages() { - ticker := Ticker{ID: 1} + ticker := &Ticker{ID: 1} err := s.db.Create(&ticker).Error s.NoError(err) @@ -1181,7 +1332,7 @@ func (s *SqlStorageTestSuite) TestDeleteMessages() { s.NoError(err) s.Run("when messages do not exist", func() { - err := s.store.DeleteMessages(Ticker{ID: 2}) + err := s.store.DeleteMessages(&Ticker{ID: 2}) s.NoError(err) }) diff --git a/internal/storage/storage.go b/internal/storage/storage.go index cf97e217..52431e71 100644 --- a/internal/storage/storage.go +++ b/internal/storage/storage.go @@ -25,19 +25,25 @@ type Storage interface { FindTickerByDomain(domain string, opts ...func(*gorm.DB) *gorm.DB) (Ticker, error) FindTickerByID(id int, opts ...func(*gorm.DB) *gorm.DB) (Ticker, error) SaveTicker(ticker *Ticker) error - DeleteTicker(ticker Ticker) error + DeleteTicker(ticker *Ticker) error + ResetTicker(ticker *Ticker) error + DeleteIntegrations(ticker *Ticker) error + DeleteMastodon(ticker *Ticker) error + DeleteTelegram(ticker *Ticker) error + DeleteBluesky(ticker *Ticker) error + DeleteSignalGroup(ticker *Ticker) error SaveUpload(upload *Upload) error FindUploadByUUID(uuid string) (Upload, error) FindUploadsByIDs(ids []int) ([]Upload, error) DeleteUpload(upload Upload) error DeleteUploads(uploads []Upload) - DeleteUploadsByTicker(ticker Ticker) error + DeleteUploadsByTicker(ticker *Ticker) error FindMessage(tickerID, messageID int, opts ...func(*gorm.DB) *gorm.DB) (Message, error) FindMessagesByTicker(ticker Ticker, opts ...func(*gorm.DB) *gorm.DB) ([]Message, error) FindMessagesByTickerAndPagination(ticker Ticker, pagination pagination.Pagination, opts ...func(*gorm.DB) *gorm.DB) ([]Message, error) SaveMessage(message *Message) error DeleteMessage(message Message) error - DeleteMessages(ticker Ticker) error + DeleteMessages(ticker *Ticker) error GetInactiveSettings() InactiveSettings GetRefreshIntervalSettings() RefreshIntervalSettings SaveInactiveSettings(inactiveSettings InactiveSettings) error diff --git a/internal/storage/ticker.go b/internal/storage/ticker.go index 1ef849fe..d5d73878 100644 --- a/internal/storage/ticker.go +++ b/internal/storage/ticker.go @@ -27,18 +27,6 @@ func NewTicker() Ticker { return Ticker{} } -func (t *Ticker) Reset() { - t.Active = false - t.Description = "" - t.Information = TickerInformation{} - t.Location = TickerLocation{} - - t.Telegram.Reset() - t.Mastodon.Reset() - t.Bluesky.Reset() - t.SignalGroup.Reset() -} - func (t *Ticker) AsMap() map[string]interface{} { return map[string]interface{}{ "id": t.ID, @@ -81,11 +69,6 @@ type TickerTelegram struct { ChannelName string } -func (tg *TickerTelegram) Reset() { - tg.Active = false - tg.ChannelName = "" -} - func (tg *TickerTelegram) Connected() bool { return tg.ChannelName != "" } @@ -113,15 +96,6 @@ func (m *TickerMastodon) Connected() bool { return m.Token != "" && m.Secret != "" && m.AccessToken != "" } -func (m *TickerMastodon) Reset() { - m.Active = false - m.Server = "" - m.Token = "" - m.Secret = "" - m.AccessToken = "" - m.User = MastodonUser{} -} - type TickerBluesky struct { ID int `gorm:"primaryKey"` CreatedAt time.Time @@ -138,12 +112,6 @@ func (b *TickerBluesky) Connected() bool { return b.Handle != "" && b.AppKey != "" } -func (b *TickerBluesky) Reset() { - b.Active = false - b.Handle = "" - b.AppKey = "" -} - type TickerSignalGroup struct { ID int `gorm:"primaryKey"` CreatedAt time.Time @@ -158,12 +126,6 @@ func (s *TickerSignalGroup) Connected() bool { return s.GroupID != "" } -func (s *TickerSignalGroup) Reset() { - s.Active = false - s.GroupID = "" - s.GroupInviteLink = "" -} - type TickerLocation struct { Lat float64 Lon float64 diff --git a/internal/storage/ticker_test.go b/internal/storage/ticker_test.go index 5f0117ed..3bf8dec6 100644 --- a/internal/storage/ticker_test.go +++ b/internal/storage/ticker_test.go @@ -38,32 +38,6 @@ func TestTickerSignalGroupConnect(t *testing.T) { assert.True(t, ticker.SignalGroup.Connected()) } -func TestTickerReset(t *testing.T) { - ticker.Active = true - ticker.Description = "Description" - ticker.Information.Author = "Author" - ticker.Information.Email = "Email" - ticker.Information.Twitter = "Twitter" - ticker.Telegram.Active = true - ticker.Telegram.ChannelName = "ChannelName" - ticker.SignalGroup.Active = true - ticker.SignalGroup.GroupID = "GroupID" - ticker.Location.Lat = 1 - ticker.Location.Lon = 2 - - ticker.Reset() - - assert.False(t, ticker.Active) - assert.False(t, ticker.Telegram.Active) - assert.Empty(t, ticker.Description) - assert.Empty(t, ticker.Information.Author) - assert.Empty(t, ticker.Information.Email) - assert.Empty(t, ticker.Information.Twitter) - assert.Empty(t, ticker.Telegram.ChannelName) - assert.Empty(t, ticker.SignalGroup.GroupID) - assert.Empty(t, ticker.Location) -} - func TestNewTickerFilter(t *testing.T) { filter := NewTickerFilter(nil) assert.Nil(t, filter.Active)