Skip to content

Commit

Permalink
✨ Add APIs for deleting Twitter/Telegram Connection
Browse files Browse the repository at this point in the history
  • Loading branch information
0x46616c6b committed Oct 14, 2022
1 parent fc26200 commit 15b3e92
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 46 deletions.
2 changes: 2 additions & 0 deletions internal/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ func API(config config.Config, storage storage.TickerStorage) *gin.Engine {
admin.POST(`/tickers`, user.NeedAdmin(), handler.PostTicker)
admin.PUT(`/tickers/:tickerID`, ticker.PrefetchTicker(storage), handler.PutTicker)
admin.PUT(`/tickers/:tickerID/twitter`, ticker.PrefetchTicker(storage), handler.PutTickerTwitter)
admin.DELETE(`/tickers/:tickerID/twitter`, ticker.PrefetchTicker(storage), handler.DeleteTickerTwitter)
admin.PUT(`/tickers/:tickerID/telegram`, ticker.PrefetchTicker(storage), handler.PutTickerTelegram)
admin.DELETE(`/tickers/:tickerID/telegram`, ticker.PrefetchTicker(storage), handler.DeleteTickerTelegram)
admin.DELETE(`/tickers/:tickerID`, user.NeedAdmin(), ticker.PrefetchTicker(storage), handler.DeleteTicker)
admin.PUT(`/tickers/:tickerID/reset`, ticker.PrefetchTicker(storage), ticker.PrefetchTicker(storage), handler.ResetTicker)
admin.GET(`/tickers/:tickerID/users`, ticker.PrefetchTicker(storage), handler.GetTickerUsers)
Expand Down
73 changes: 48 additions & 25 deletions internal/api/tickers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"net/http"
"strconv"

"github.com/dghubble/go-twitter/twitter"
"github.com/gin-gonic/gin"
"github.com/systemli/ticker/internal/api/helper"
"github.com/systemli/ticker/internal/api/response"
Expand Down Expand Up @@ -131,41 +130,47 @@ func (h *handler) PutTickerTwitter(c *gin.Context) {
return
}

var body struct {
Active bool `json:"active,omitempty"`
Disconnect bool `json:"disconnect"`
Token string `json:"token,omitempty"`
Secret string `json:"secret,omitempty"`
}
var body storage.Twitter

err = c.Bind(&body)
if err != nil {
c.JSON(http.StatusBadRequest, response.ErrorResponse(response.CodeDefault, response.FormError))
return
}

if body.Disconnect {
ticker.Twitter.Token = ""
ticker.Twitter.Secret = ""
ticker.Twitter.Active = false
ticker.Twitter.User = twitter.User{}
ticker.Twitter.Active = body.Active
if body.Token != "" {
ticker.Twitter.Token = body.Token
}
if body.Secret != "" {
ticker.Twitter.Secret = body.Secret
}

tu, err := bridge.TwitterUser(ticker, h.config)
if err != nil {
log.WithError(err).Error("cant fetch user information from twitter")
} else {
if body.Token != "" {
ticker.Twitter.Token = body.Token
}
if body.Secret != "" {
ticker.Twitter.Secret = body.Secret
}
ticker.Twitter.Active = body.Active
ticker.Twitter.User = *tu
}

tu, err := bridge.TwitterUser(ticker, h.config)
if err != nil {
log.WithError(err).Error("cant fetch user information from twitter")
} else {
ticker.Twitter.User = *tu
}
err = h.storage.SaveTicker(&ticker)
if err != nil {
c.JSON(http.StatusBadRequest, response.ErrorResponse(response.CodeDefault, response.StorageError))
return
}

c.JSON(http.StatusOK, response.SuccessResponse(map[string]interface{}{"ticker": response.TickerResponse(ticker, h.config)}))
}

func (h *handler) DeleteTickerTwitter(c *gin.Context) {
ticker, err := helper.Ticker(c)
if err != nil {
c.JSON(http.StatusNotFound, response.ErrorResponse(response.CodeDefault, response.TickerNotFound))
return
}

ticker.Twitter.Reset()

err = h.storage.SaveTicker(&ticker)
if err != nil {
c.JSON(http.StatusBadRequest, response.ErrorResponse(response.CodeDefault, response.StorageError))
Expand Down Expand Up @@ -200,6 +205,24 @@ func (h *handler) PutTickerTelegram(c *gin.Context) {
c.JSON(http.StatusOK, response.SuccessResponse(map[string]interface{}{"ticker": response.TickerResponse(ticker, h.config)}))
}

func (h *handler) DeleteTickerTelegram(c *gin.Context) {
ticker, err := helper.Ticker(c)
if err != nil {
c.JSON(http.StatusNotFound, response.ErrorResponse(response.CodeDefault, response.TickerNotFound))
return
}

ticker.Telegram.Reset()

err = h.storage.SaveTicker(&ticker)
if err != nil {
c.JSON(http.StatusBadRequest, response.ErrorResponse(response.CodeDefault, response.StorageError))
return
}

c.JSON(http.StatusOK, response.SuccessResponse(map[string]interface{}{"ticker": response.TickerResponse(ticker, h.config)}))
}

func (h *handler) DeleteTicker(c *gin.Context) {
ticker, err := helper.Ticker(c)
if err != nil {
Expand Down
97 changes: 85 additions & 12 deletions internal/api/tickers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,11 +348,11 @@ func TestPutTickerTwitterFormError(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestPutTickerTwitterDisconnect(t *testing.T) {
func TestPutTickerTwitterConnect(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("ticker", storage.Ticker{})
body := `{"disconnect":true}`
body := `{"active":true,"token":"token","secret":"secret"}`
c.Request = httptest.NewRequest(http.MethodPut, "/v1/admin/tickers/1/twitter", strings.NewReader(body))
c.Request.Header.Add("Content-Type", "application/json")
s := &storage.MockTickerStorage{}
Expand All @@ -363,46 +363,73 @@ func TestPutTickerTwitterDisconnect(t *testing.T) {
}

h.PutTickerTwitter(c)

assert.Equal(t, http.StatusOK, w.Code)
}

func TestPutTickerTwitterConnect(t *testing.T) {
func TestPutTickerTwitterStorageError(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("ticker", storage.Ticker{})
body := `{"active":true,"token":"token","secret":"secret"}`
body := `{"active":false}`
c.Request = httptest.NewRequest(http.MethodPut, "/v1/admin/tickers/1/twitter", strings.NewReader(body))
c.Request.Header.Add("Content-Type", "application/json")
s := &storage.MockTickerStorage{}
s.On("SaveTicker", mock.Anything).Return(nil)
s.On("SaveTicker", mock.Anything).Return(errors.New("storage error"))
h := handler{
storage: s,
config: config.NewConfig(),
}

h.PutTickerTwitter(c)

assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestPutTickerTwitterStorageError(t *testing.T) {
func TestDeleteTickerTwitterTickerNotFound(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
s := &storage.MockTickerStorage{}
h := handler{
storage: s,
config: config.NewConfig(),
}

h.DeleteTickerTwitter(c)

assert.Equal(t, http.StatusNotFound, w.Code)
}

func TesDeleteTickerTwitterStorageError(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("ticker", storage.Ticker{})
body := `{"disconnect":true}`
c.Request = httptest.NewRequest(http.MethodPut, "/v1/admin/tickers/1/twitter", strings.NewReader(body))
c.Request.Header.Add("Content-Type", "application/json")
s := &storage.MockTickerStorage{}
s.On("SaveTicker", mock.Anything).Return(errors.New("storage error"))
h := handler{
storage: s,
config: config.NewConfig(),
}

h.PutTickerTwitter(c)
h.DeleteTickerTwitter(c)

assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TesDeleteTickerTwitter(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("ticker", storage.Ticker{})
s := &storage.MockTickerStorage{}
s.On("SaveTicker", mock.Anything).Return(nil)
h := handler{
storage: s,
config: config.NewConfig(),
}

h.DeleteTickerTwitter(c)

assert.Equal(t, http.StatusOK, w.Code)
}

func TestPutTickerTelegramTickerNotFound(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
Expand Down Expand Up @@ -472,6 +499,52 @@ func TestPutTickerTelegram(t *testing.T) {
assert.Equal(t, http.StatusOK, w.Code)
}

func TestDeleteTickerTelegramTickerNotFound(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
s := &storage.MockTickerStorage{}
h := handler{
storage: s,
config: config.NewConfig(),
}

h.DeleteTickerTelegram(c)

assert.Equal(t, http.StatusNotFound, w.Code)
}

func TesDeleteTickerTelegramStorageError(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("ticker", storage.Ticker{})
s := &storage.MockTickerStorage{}
s.On("SaveTicker", mock.Anything).Return(errors.New("storage error"))
h := handler{
storage: s,
config: config.NewConfig(),
}

h.DeleteTickerTelegram(c)

assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TesDeleteTickerTelegram(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("ticker", storage.Ticker{})
s := &storage.MockTickerStorage{}
s.On("SaveTicker", mock.Anything).Return(nil)
h := handler{
storage: s,
config: config.NewConfig(),
}

h.DeleteTickerTelegram(c)

assert.Equal(t, http.StatusOK, w.Code)
}

func TestDeleteTickerTickerNotFound(t *testing.T) {
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
Expand Down
27 changes: 18 additions & 9 deletions internal/storage/ticker.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,10 @@ func (t *Ticker) Reset() {
t.Active = false
t.Description = ""
t.Information = Information{}
t.Twitter.Secret = ""
t.Twitter.Token = ""
t.Twitter.Active = false
t.Twitter.User = twitter.User{}
t.Telegram.Active = false
t.Telegram.ChannelName = ""
t.Location = Location{}

t.Twitter.Reset()
t.Telegram.Reset()
}

type Information struct {
Expand All @@ -48,12 +45,19 @@ type Information struct {
}

type Twitter struct {
Active bool
Token string
Secret string
Active bool `json:"active"`
Token string `json:"token"`
Secret string `json:"secret"`
User twitter.User
}

func (tw *Twitter) Reset() {
tw.Active = false
tw.Token = ""
tw.Secret = ""
tw.User = twitter.User{}
}

func (tw *Twitter) Connected() bool {
return tw.Token != "" && tw.Secret != ""
}
Expand All @@ -63,6 +67,11 @@ type Telegram struct {
ChannelName string `json:"channel_name"`
}

func (tg *Telegram) Reset() {
tg.Active = false
tg.ChannelName = ""
}

type Location struct {
Lat float64
Lon float64
Expand Down

0 comments on commit 15b3e92

Please sign in to comment.