Skip to content

Commit

Permalink
feat(api): add create tags api route (#991)
Browse files Browse the repository at this point in the history
  • Loading branch information
almostinf authored Feb 19, 2024
1 parent 7cdeac6 commit ffd2c00
Show file tree
Hide file tree
Showing 13 changed files with 477 additions and 33 deletions.
9 changes: 9 additions & 0 deletions api/controller/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ func getTagNamesSorted(database moira.Database) ([]string, error) {
return tagsNames, nil
}

// CreateTags create tags with tag names
func CreateTags(database moira.Database, tags *dto.TagsData) *api.ErrorResponse {
if err := database.CreateTags(tags.TagNames); err != nil {
return api.ErrorInternalServer(err)
}

return nil
}

// RemoveTag deletes tag by name
func RemoveTag(database moira.Database, tagName string) (*dto.MessageResponse, *api.ErrorResponse) {
triggerIDs, err := database.GetTagTriggerIDs(tagName)
Expand Down
35 changes: 35 additions & 0 deletions api/controller/tag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,41 @@ func TestGetAllTags(t *testing.T) {
})
}

func TestCreateTags(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
database := mock_moira_alert.NewMockDatabase(mockCtrl)

emptyTags := &dto.TagsData{
TagNames: make([]string, 0),
}
tags := &dto.TagsData{
TagNames: []string{"test1", "test2"},
}

Convey("Success with empty tags", t, func() {
database.EXPECT().CreateTags(emptyTags.TagNames).Return(nil).Times(1)

err := CreateTags(database, emptyTags)
So(err, ShouldBeNil)
})

Convey("Success with many tags", t, func() {
database.EXPECT().CreateTags(tags.TagNames).Return(nil).Times(1)

err := CreateTags(database, tags)
So(err, ShouldBeNil)
})

Convey("Error from database", t, func() {
expectedErr := fmt.Errorf("some error")
database.EXPECT().CreateTags(tags.TagNames).Return(expectedErr).Times(1)

err := CreateTags(database, tags)
So(err, ShouldResemble, api.ErrorInternalServer(expectedErr))
})
}

func TestDeleteTag(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
Expand Down
7 changes: 7 additions & 0 deletions api/dto/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,17 @@ type TagsData struct {
TagNames []string `json:"list" example:"cpu"`
}

// Render is a function that implements chi Renderer interface for TagsData
func (*TagsData) Render(w http.ResponseWriter, r *http.Request) error {
return nil
}

// Bind is a method that implements Binder interface from chi and checks that validity of data in request
func (tags *TagsData) Bind(request *http.Request) error {
tags.TagNames = normalizeTags(tags.TagNames)
return nil
}

type MessageResponse struct {
Message string `json:"message" example:"tag deleted"`
}
Expand Down
45 changes: 23 additions & 22 deletions api/handler/contact_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const (
LoginKey = "login"
defaultContact = "testContact"
defaultLogin = "testLogin"
defaultTeamID = "testTeamID"
)

func TestGetAllContacts(t *testing.T) {
Expand All @@ -43,7 +44,7 @@ func TestGetAllContacts(t *testing.T) {
ID: defaultContact,
Type: "mail",
Value: "[email protected]",
User: "moira",
User: defaultLogin,
Team: "",
},
}, nil).Times(1)
Expand All @@ -55,7 +56,7 @@ func TestGetAllContacts(t *testing.T) {
ID: defaultContact,
Type: "mail",
Value: "[email protected]",
User: "moira",
User: defaultLogin,
Team: "",
},
},
Expand Down Expand Up @@ -120,7 +121,7 @@ func TestGetContactById(t *testing.T) {
ID: contactID,
Type: "mail",
Value: "[email protected]",
User: "test",
User: defaultLogin,
Team: "",
}, nil).Times(1)
database = mockDb
Expand All @@ -129,7 +130,7 @@ func TestGetContactById(t *testing.T) {
ID: contactID,
Type: "mail",
Value: "[email protected]",
User: "test",
User: defaultLogin,
TeamID: "",
}

Expand Down Expand Up @@ -336,7 +337,7 @@ func TestCreateNewContact(t *testing.T) {
})

Convey("Trying to create a contact when both userLogin and teamID specified", func() {
newContactDto.TeamID = "test"
newContactDto.TeamID = defaultTeamID
defer func() {
newContactDto.TeamID = ""
}()
Expand Down Expand Up @@ -383,7 +384,7 @@ func TestUpdateContact(t *testing.T) {
ID: contactID,
Type: "mail",
Value: "[email protected]",
User: "test",
User: defaultLogin,
TeamID: "",
}

Expand Down Expand Up @@ -502,7 +503,7 @@ func TestRemoveContact(t *testing.T) {
})

Convey("Successful deletion of a contact without team id and subscriptions", func() {
mockDb.EXPECT().GetUserSubscriptionIDs("test").Return([]string{}, nil).Times(1)
mockDb.EXPECT().GetUserSubscriptionIDs(defaultLogin).Return([]string{}, nil).Times(1)
mockDb.EXPECT().GetSubscriptions([]string{}).Return([]*moira.SubscriptionData{}, nil).Times(1)
mockDb.EXPECT().RemoveContact(contactID).Return(nil).Times(1)
database = mockDb
Expand All @@ -512,7 +513,7 @@ func TestRemoveContact(t *testing.T) {
ID: contactID,
Type: "mail",
Value: "[email protected]",
User: "test",
User: defaultLogin,
}))
testRequest.Header.Add("content-type", "application/json")

Expand All @@ -529,7 +530,7 @@ func TestRemoveContact(t *testing.T) {
})

Convey("Successful deletion of a contact without user id and subscriptions", func() {
mockDb.EXPECT().GetTeamSubscriptionIDs("test").Return([]string{}, nil).Times(1)
mockDb.EXPECT().GetTeamSubscriptionIDs(defaultTeamID).Return([]string{}, nil).Times(1)
mockDb.EXPECT().GetSubscriptions([]string{}).Return([]*moira.SubscriptionData{}, nil).Times(1)
mockDb.EXPECT().RemoveContact(contactID).Return(nil).Times(1)
database = mockDb
Expand All @@ -539,7 +540,7 @@ func TestRemoveContact(t *testing.T) {
ID: contactID,
Type: "mail",
Value: "[email protected]",
Team: "test",
Team: defaultTeamID,
}))
testRequest.Header.Add("content-type", "application/json")

Expand All @@ -556,8 +557,8 @@ func TestRemoveContact(t *testing.T) {
})

Convey("Successful deletion of a contact without subscriptions", func() {
mockDb.EXPECT().GetUserSubscriptionIDs("test").Return([]string{}, nil).Times(1)
mockDb.EXPECT().GetTeamSubscriptionIDs("test").Return([]string{}, nil).Times(1)
mockDb.EXPECT().GetUserSubscriptionIDs(defaultLogin).Return([]string{}, nil).Times(1)
mockDb.EXPECT().GetTeamSubscriptionIDs(defaultTeamID).Return([]string{}, nil).Times(1)
mockDb.EXPECT().GetSubscriptions([]string{}).Return([]*moira.SubscriptionData{}, nil).Times(1)
mockDb.EXPECT().RemoveContact(contactID).Return(nil).Times(1)
database = mockDb
Expand All @@ -567,8 +568,8 @@ func TestRemoveContact(t *testing.T) {
ID: contactID,
Type: "mail",
Value: "[email protected]",
User: "test",
Team: "test",
User: defaultLogin,
Team: defaultTeamID,
}))
testRequest.Header.Add("content-type", "application/json")

Expand All @@ -590,7 +591,7 @@ func TestRemoveContact(t *testing.T) {
ErrorText: "this contact is being used in following subscriptions: (tags: test)",
}

mockDb.EXPECT().GetUserSubscriptionIDs("test").Return([]string{"test"}, nil).Times(1)
mockDb.EXPECT().GetUserSubscriptionIDs(defaultLogin).Return([]string{"test"}, nil).Times(1)
mockDb.EXPECT().GetSubscriptions([]string{"test"}).Return([]*moira.SubscriptionData{
{
Contacts: []string{"testContact"},
Expand All @@ -604,7 +605,7 @@ func TestRemoveContact(t *testing.T) {
ID: contactID,
Type: "mail",
Value: "[email protected]",
User: "test",
User: defaultLogin,
}))
testRequest.Header.Add("content-type", "application/json")

Expand All @@ -629,7 +630,7 @@ func TestRemoveContact(t *testing.T) {
ErrorText: "this contact is being used in following subscriptions: (tags: test)",
}

mockDb.EXPECT().GetTeamSubscriptionIDs("test").Return([]string{"test"}, nil).Times(1)
mockDb.EXPECT().GetTeamSubscriptionIDs(defaultTeamID).Return([]string{"test"}, nil).Times(1)
mockDb.EXPECT().GetSubscriptions([]string{"test"}).Return([]*moira.SubscriptionData{
{
Contacts: []string{"testContact"},
Expand All @@ -643,7 +644,7 @@ func TestRemoveContact(t *testing.T) {
ID: contactID,
Type: "mail",
Value: "[email protected]",
Team: "test",
Team: defaultTeamID,
}))
testRequest.Header.Add("content-type", "application/json")

Expand All @@ -668,8 +669,8 @@ func TestRemoveContact(t *testing.T) {
ErrorText: "this contact is being used in following subscriptions: (tags: test1), (tags: test2)",
}

mockDb.EXPECT().GetUserSubscriptionIDs("test1").Return([]string{"test1"}, nil).Times(1)
mockDb.EXPECT().GetTeamSubscriptionIDs("test2").Return([]string{"test2"}, nil).Times(1)
mockDb.EXPECT().GetUserSubscriptionIDs(defaultLogin).Return([]string{"test1"}, nil).Times(1)
mockDb.EXPECT().GetTeamSubscriptionIDs(defaultTeamID).Return([]string{"test2"}, nil).Times(1)
mockDb.EXPECT().GetSubscriptions([]string{"test1", "test2"}).Return([]*moira.SubscriptionData{
{
Contacts: []string{"testContact"},
Expand All @@ -687,8 +688,8 @@ func TestRemoveContact(t *testing.T) {
ID: contactID,
Type: "mail",
Value: "[email protected]",
Team: "test2",
User: "test1",
Team: defaultTeamID,
User: defaultLogin,
}))
testRequest.Header.Add("content-type", "application/json")

Expand Down
27 changes: 27 additions & 0 deletions api/handler/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import (
"github.com/go-chi/render"
"github.com/moira-alert/moira/api"
"github.com/moira-alert/moira/api/controller"
"github.com/moira-alert/moira/api/dto"
"github.com/moira-alert/moira/api/middleware"
)

func tag(router chi.Router) {
router.Post("/", createTags)
router.Get("/", getAllTags)
router.Get("/stats", getAllTagsAndSubscriptions)
router.Route("/{tag}", func(router chi.Router) {
Expand Down Expand Up @@ -42,6 +44,31 @@ func getAllTags(writer http.ResponseWriter, request *http.Request) {
}
}

// nolint: gofmt,goimports
//
// @summary Create new tags
// @id create-tags
// @tags tag
// @accept json
// @produce json
// @param tags body dto.TagsData true "Tags data"
// @success 200 "Create tags successfully"
// @failure 400 {object} api.ErrorInvalidRequestExample "Bad request from client"
// @failure 422 {object} api.ErrorRenderExample "Render error"
// @failure 500 {object} api.ErrorInternalServerExample "Internal server error"
// @router /tag [post]
func createTags(writer http.ResponseWriter, request *http.Request) {
tags := dto.TagsData{}
if err := render.Bind(request, &tags); err != nil {
render.Render(writer, request, api.ErrorInvalidRequest(err)) //nolint:errcheck
return
}

if err := controller.CreateTags(database, &tags); err != nil {
render.Render(writer, request, err) //nolint
}
}

// nolint: gofmt,goimports
//
// @summary Get all tags and their subscriptions
Expand Down
Loading

0 comments on commit ffd2c00

Please sign in to comment.