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
13 changes: 12 additions & 1 deletion server/src/api/votings.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ func (s *Server) updateVoting(w http.ResponseWriter, r *http.Request) {
board := ctx.Value(identifiers.BoardIdentifier).(uuid.UUID)
id := ctx.Value(identifiers.VotingIdentifier).(uuid.UUID)

var body votings.VotingCloseRequest
if err := render.Decode(r, &body); err != nil {
span.SetStatus(codes.Error, "unable to decode body")
span.RecordError(err)
common.Throw(w, r, common.BadRequestError(err))
return
}
body.ID = id
body.Board = board

notes, err := s.notes.GetAll(ctx, board)
if err != nil {
span.SetStatus(codes.Error, "failed to get notes")
Expand All @@ -110,7 +120,8 @@ func (s *Server) updateVoting(w http.ResponseWriter, r *http.Request) {
})
}

voting, err := s.votings.Close(ctx, id, board, affectedNotes)
voting, err := s.votings.Update(ctx, id, board, affectedNotes, body.Status)

if err != nil {
span.SetStatus(codes.Error, "failed to update voting")
span.RecordError(err)
Expand Down
44 changes: 41 additions & 3 deletions server/src/api/votings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,26 +94,64 @@ func (suite *VotingTestSuite) TestCloseVoting() {
s.votings = votingMock
s.notes = notesMock

req := technical_helper.NewTestRequestBuilder("PUT", "/", nil)
votingStatus := votings.Closed
req := technical_helper.NewTestRequestBuilder("PUT", "/", strings.NewReader(fmt.Sprintf(`{"status": "%s"}`, votingStatus)))
req.Req = logger.InitTestLoggerRequest(req.Request())
req.AddToContext(identifiers.BoardIdentifier, boardId).
AddToContext(identifiers.VotingIdentifier, votingId)
rr := httptest.NewRecorder()

notesMock.EXPECT().GetAll(mock.Anything, boardId).Return([]*notes.Note{}, nil)

votingMock.EXPECT().Close(mock.Anything, votingId, boardId, []votings.Note(nil)).
votingMock.EXPECT().Update(mock.Anything, votingId, boardId, []votings.Note(nil), votings.Closed).
Return(&votings.Voting{Status: votings.Closed}, tt.err)

s.updateVoting(rr, req.Request())
suite.Equal(tt.expectedCode, rr.Result().StatusCode)
votingMock.AssertExpectations(suite.T())
votingMock.AssertNumberOfCalls(suite.T(), "Close", 1)
votingMock.AssertNumberOfCalls(suite.T(), "Update", 1)
})
}

}

func (suite *VotingTestSuite) TestAbortVoting() {

testParameterBundles := *TestParameterBundles{}.
Append("all ok", http.StatusOK, nil, false, false, nil).
Append("unexpected error", http.StatusInternalServerError, errors.New("oops"), false, false, nil)

for _, tt := range testParameterBundles {
suite.Run(tt.name, func() {
s := new(Server)
votingMock := votings.NewMockVotingService(suite.T())
notesMock := notes.NewMockNotesService(suite.T())

boardId, _ := uuid.NewRandom()
votingId, _ := uuid.NewRandom()
s.votings = votingMock
s.notes = notesMock

votingStatus := votings.Aborted
req := technical_helper.NewTestRequestBuilder("PUT", "/", strings.NewReader(fmt.Sprintf(`{"status": "%s"}`, votingStatus)))
req.Req = logger.InitTestLoggerRequest(req.Request())
req.AddToContext(identifiers.BoardIdentifier, boardId).
AddToContext(identifiers.VotingIdentifier, votingId)

notesMock.EXPECT().GetAll(mock.Anything, boardId).Return([]*notes.Note{}, nil)

votingMock.EXPECT().Update(mock.Anything, votingId, boardId, []votings.Note(nil), votings.Aborted).
Return(&votings.Voting{Status: votings.Aborted}, tt.err)

rr := httptest.NewRecorder()
s.updateVoting(rr, req.Request())
suite.Equal(tt.expectedCode, rr.Result().StatusCode)
votingMock.AssertExpectations(suite.T())
votingMock.AssertNumberOfCalls(suite.T(), "Update", 1)
})
}
}

func (suite *VotingTestSuite) TestGetVoting() {
s := new(Server)
votingMock := votings.NewMockVotingService(suite.T())
Expand Down
2 changes: 1 addition & 1 deletion server/src/votings/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type VotingService interface {
GetVotes(ctx context.Context, board uuid.UUID, f VoteFilter) ([]*Vote, error)
AddVote(ctx context.Context, req VoteRequest) (*Vote, error)
RemoveVote(ctx context.Context, req VoteRequest) error
Close(ctx context.Context, id uuid.UUID, board uuid.UUID, affectedNotes []Note) (*Voting, error)
Update(ctx context.Context, id uuid.UUID, board uuid.UUID, affectedNotes []Note, votingStatus VotingStatus) (*Voting, error)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of changing the signature so that first the status is requested and then the notes?

}

type VotingApi struct {
Expand Down
45 changes: 29 additions & 16 deletions server/src/votings/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,40 @@ func (d *DB) Create(ctx context.Context, insert DatabaseVotingInsert) (DatabaseV
return voting, err
}

func (d *DB) Close(ctx context.Context, update DatabaseVotingUpdate) (DatabaseVoting, error) {
func (d *DB) Update(ctx context.Context, update DatabaseVotingUpdate) (DatabaseVoting, error) {
var voting DatabaseVoting
updateQuery := d.db.NewUpdate().

if update.Status == Closed {
updateQuery := d.db.NewUpdate().
Model(&update).
Where("id = ?", update.ID).
Where("board = ?", update.Board).
Where("status = ?", Open).
Returning("*")

updateBoard := d.db.NewUpdate().
Model((*common.DatabaseBoard)(nil)).
Set("show_voting = (SELECT id FROM \"updateQuery\")").
Where("id = ?", update.Board)

err := d.db.NewSelect().
With("updateQuery", updateQuery).
With("updateBoard", updateBoard).
With("rankUpdate", common.GetRankUpdateQueryForClosedVoting(d.db, "updateQuery")).
Model((*DatabaseVoting)(nil)).
ModelTableExpr("\"updateQuery\" AS voting").
Scan(common.ContextWithValues(ctx, "Database", d, "Result", &voting), &voting)

return voting, err
}

_, err := d.db.NewUpdate().
Model(&update).
Where("id = ?", update.ID).
Where("board = ?", update.Board).
Where("status = ?", Open).
Returning("*")

updateBoard := d.db.NewUpdate().
Model((*common.DatabaseBoard)(nil)).
Set("show_voting = (SELECT id FROM \"updateQuery\")").
Where("id = ?", update.Board)

err := d.db.NewSelect().
With("updateQuery", updateQuery).
With("updateBoard", updateBoard).
With("rankUpdate", common.GetRankUpdateQueryForClosedVoting(d.db, "updateQuery")).
Model((*DatabaseVoting)(nil)).
ModelTableExpr("\"updateQuery\" AS voting").
Scan(common.ContextWithValues(ctx, "Database", d, "Result", &voting), &voting)
Returning("*").
Exec(common.ContextWithValues(ctx, "Database", d, "Result", &voting), &voting)

return voting, err
}
Expand Down
42 changes: 41 additions & 1 deletion server/src/votings/database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (suite *DatabaseVotingTestSuite) Test_Database_Close() {
votingId := suite.baseData.Votings["Update"].ID
boardId := suite.baseData.Boards["Update"].ID

dbVoting, err := database.Close(context.Background(),
dbVoting, err := database.Update(context.Background(),
DatabaseVotingUpdate{
ID: votingId,
Board: boardId,
Expand Down Expand Up @@ -283,6 +283,46 @@ func (suite *DatabaseVotingTestSuite) Test_Database_GetVotes() {
assert.Len(t, dbVotes, 18)
}

func (suite *DatabaseVotingTestSuite) Test_Database_Cancel() {
t := suite.T()
database := NewVotingDatabase(suite.db)

votingId := suite.baseData.Votings["Update"].ID
boardId := suite.baseData.Boards["Update"].ID

dbVoting, err := database.Update(context.Background(),
DatabaseVotingUpdate{
ID: votingId,
Board: boardId,
Status: Aborted,
},
)

assert.Nil(t, err)
assert.Equal(t, votingId, dbVoting.ID)
assert.Equal(t, boardId, dbVoting.Board)
assert.Equal(t, Aborted, dbVoting.Status)
assert.Equal(t, 7, dbVoting.VoteLimit)
assert.True(t, dbVoting.AllowMultipleVotes)
assert.False(t, dbVoting.ShowVotesOfOthers)
assert.False(t, dbVoting.IsAnonymous)
assert.NotNil(t, dbVoting.CreatedAt)

// Verify notes are NOT re-ranked after cancel
noteDatabase := notes.NewNotesDatabase(suite.db)
dbNotes, notesErr := noteDatabase.GetAll(context.Background(), boardId)
assert.Nil(t, notesErr)

noteRankMap := make(map[uuid.UUID]int)
for _, n := range dbNotes {
noteRankMap[n.ID] = n.Rank
}

assert.Equal(t, 0, noteRankMap[suite.baseData.Notes["Update2"].ID])
assert.Equal(t, 0, noteRankMap[suite.baseData.Notes["Update1"].ID])
assert.Equal(t, 0, noteRankMap[suite.baseData.Notes["Update3"].ID])
}

func (suite *DatabaseVotingTestSuite) seedVotes(db *bun.DB) {
log.Println("Seeding voting database test votes")

Expand Down
5 changes: 3 additions & 2 deletions server/src/votings/dto.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ type VotingCreateRequest struct {

// VotingCloseRequest represents the request to update a voting session.
type VotingCloseRequest struct {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should rename this struct now to VotingUpdateRequest or something like this

ID uuid.UUID `json:"-"`
Board uuid.UUID `json:"-"`
ID uuid.UUID `json:"-"`
Board uuid.UUID `json:"-"`
Status VotingStatus `json:"status"`
}

// Voting is the response for all voting requests.
Expand Down
132 changes: 66 additions & 66 deletions server/src/votings/mock_VotingDatabase.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading