Skip to content
This repository has been archived by the owner on Mar 11, 2021. It is now read-only.

Enable the delete workitem endpoint #2305

Merged
merged 32 commits into from
Oct 23, 2018
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
f93db24
[1] Enable the delete workitem endpoint
DhritiShikhar Sep 28, 2018
3fda771
rename function
DhritiShikhar Sep 28, 2018
aa39af2
Removes MethodNotAllowed HTTP response
DhritiShikhar Sep 28, 2018
ed9d652
Removes a test which is not longer valid
DhritiShikhar Sep 28, 2018
9f8c107
Adds tests for delete workitem
DhritiShikhar Oct 8, 2018
cfaed6b
Adds tests, returns proper error
DhritiShikhar Oct 10, 2018
f9be9b0
Merge remote-tracking branch 'upstream/master' into delete-workitem-1
DhritiShikhar Oct 10, 2018
1b07bad
removes unused identity
DhritiShikhar Oct 10, 2018
37e2d35
Adds test to check work item link deletion
DhritiShikhar Oct 10, 2018
1aaa631
adds comments in tests
DhritiShikhar Oct 10, 2018
115d334
Merge remote-tracking branch 'upstream/master' into delete-workitem-1
DhritiShikhar Oct 10, 2018
77b6e4e
removes unnecessary code
DhritiShikhar Oct 10, 2018
f7fd115
* Removes topology from test case
DhritiShikhar Oct 11, 2018
bb06677
Merge remote-tracking branch 'upstream/master' into delete-workitem-1
DhritiShikhar Oct 11, 2018
49d5479
Uses uuid for creator and editor in isWorkitemCreatorOrSpaceOwner
DhritiShikhar Oct 22, 2018
eb19194
Merge remote-tracking branch 'upstream/master' into delete-workitem-1
DhritiShikhar Oct 22, 2018
0c8fe6e
change isWorkitemCreatorOrSpaceOwner method to return only error
DhritiShikhar Oct 22, 2018
5990f13
Error handling
DhritiShikhar Oct 22, 2018
50c9e17
Adds repository level test for delete workitem
DhritiShikhar Oct 22, 2018
d37cced
Adds test for deleteLinks
DhritiShikhar Oct 22, 2018
e8a08a5
Corrects error returned
DhritiShikhar Oct 23, 2018
31ef3d4
Merge remote-tracking branch 'upstream/master' into delete-workitem-1
DhritiShikhar Oct 23, 2018
68517a6
Updates comment
DhritiShikhar Oct 23, 2018
b996cf6
update error response
DhritiShikhar Oct 23, 2018
6bc6b87
Uncomments an delete workitem test
DhritiShikhar Oct 23, 2018
3d6aabb
Adds assertion to test cases
DhritiShikhar Oct 23, 2018
15ac6ab
Merge remote-tracking branch 'upstream/master' into delete-workitem-1
DhritiShikhar Oct 23, 2018
f9d6c10
removes unnecessary comment
DhritiShikhar Oct 23, 2018
b2f76c6
Merge branch 'master' into del-wi-1
DhritiShikhar Oct 23, 2018
41bc004
checks for result of type conversion
DhritiShikhar Oct 23, 2018
16a708e
Changes name of function
DhritiShikhar Oct 23, 2018
e131257
Merge remote-tracking branch 'origin/del-wi-1' into delete-workitem-1
DhritiShikhar Oct 23, 2018
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
33 changes: 20 additions & 13 deletions controller/workitem.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,8 @@ func NewNotifyingWorkitemController(service *goa.Service, db application.DB, not
config: config}
}

// authorizeWorkitemTypeEditor returns true if the modifier is allowed to change
// workitem type else it returns false.
// Only space owner and workitem creator are allowed to change workitem type
func (c *WorkitemController) authorizeWorkitemTypeEditor(ctx context.Context, spaceID uuid.UUID, creatorID string, editorID string) (bool, error) {
// isWorkitemCreatorOrSpaceOwner returns true if the modifier is space owner or workitem creator
jarifibrahim marked this conversation as resolved.
Show resolved Hide resolved
func (c *WorkitemController) isWorkitemCreatorOrSpaceOwner(ctx context.Context, spaceID uuid.UUID, creatorID string, editorID string) (bool, error) {
jarifibrahim marked this conversation as resolved.
Show resolved Hide resolved
// check if workitem editor is same as workitem creator
if editorID == creatorID {
return true, nil
Expand All @@ -87,7 +85,7 @@ func (c *WorkitemController) authorizeWorkitemTypeEditor(ctx context.Context, sp
if space != nil && editorID == space.OwnerID.String() {
return true, nil
}
return false, errors.NewUnauthorizedError("user is not allowed to change workitem type")
return false, errors.NewForbiddenError("user is not a workitem creator or space owner")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why did you change this error type?

Copy link
Member

Choose a reason for hiding this comment

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

This should be a ForbiddenError. The workitem could not be deleted because the user doesn't have necessary permissions.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I know what it means but I really don't see a difference between: the action is forbidden and you're not authorized.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@kwk @jarifibrahim let's discuss this in weekly today? I have some thoughts around it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Based on the discussion in the weekly sync, we decided to use NewForbiddenError specific for this case.

}

// Returns true if the user is the work item creator or space collaborator
Expand Down Expand Up @@ -134,7 +132,7 @@ func (c *WorkitemController) Update(ctx *app.UpdateWorkitemContext) error {
if ctx.Payload.Data.Relationships != nil && ctx.Payload.Data.Relationships.BaseType != nil &&
ctx.Payload.Data.Relationships.BaseType.Data != nil && ctx.Payload.Data.Relationships.BaseType.Data.ID != wi.Type {

authorized, err := c.authorizeWorkitemTypeEditor(ctx, wi.SpaceID, creator.(string), currentUserIdentityID.String())
authorized, err := c.isWorkitemCreatorOrSpaceOwner(ctx, wi.SpaceID, creator.(string), currentUserIdentityID.String())
if err != nil {
return jsonapi.JSONErrorResponse(ctx, err)
}
Expand Down Expand Up @@ -236,14 +234,11 @@ func (c *WorkitemController) Show(ctx *app.ShowWorkitemContext) error {

// Delete does DELETE workitem
func (c *WorkitemController) Delete(ctx *app.DeleteWorkitemContext) error {
// Temporarly disabled, See https://github.com/fabric8-services/fabric8-wit/issues/1036
if true {
return ctx.MethodNotAllowed()
}
currentUserIdentityID, err := login.ContextIdentity(ctx)
if err != nil {
return jsonapi.JSONErrorResponse(ctx, errors.NewUnauthorizedError(err.Error()))
}

var wi *workitem.WorkItem
err = application.Transactional(c.db, func(appl application.Application) error {
wi, err = appl.WorkItems().LoadByID(ctx, ctx.WiID)
Expand All @@ -255,13 +250,25 @@ func (c *WorkitemController) Delete(ctx *app.DeleteWorkitemContext) error {
if err != nil {
return jsonapi.JSONErrorResponse(ctx, err)
jarifibrahim marked this conversation as resolved.
Show resolved Hide resolved
}
authorized, err := authz.Authorize(ctx, wi.SpaceID.String())

// This checks if user is space admin or workitem creator or not
jarifibrahim marked this conversation as resolved.
Show resolved Hide resolved
creator := wi.Fields[workitem.SystemCreator]
if creator == nil {
return jsonapi.JSONErrorResponse(ctx, errors.NewInternalError(ctx, errs.New("work item doesn't have creator")))
}
authorized, err := c.isWorkitemCreatorOrSpaceOwner(ctx, wi.SpaceID, creator.(string), currentUserIdentityID.String())
if err != nil {
return jsonapi.JSONErrorResponse(ctx, errors.NewUnauthorizedError(err.Error()))
forbidden, err := errors.IsForbiddenError(err)
jarifibrahim marked this conversation as resolved.
Show resolved Hide resolved
if forbidden {
return jsonapi.JSONErrorResponse(ctx, errors.NewForbiddenError("user is not authorized to delete the workitem"))

}
return err
}
if !authorized {
jarifibrahim marked this conversation as resolved.
Show resolved Hide resolved
return jsonapi.JSONErrorResponse(ctx, errors.NewForbiddenError("user is not authorized to access the space"))
return jsonapi.JSONErrorResponse(ctx, errors.NewForbiddenError("user is not authorized to delete the workitem"))
}

err = application.Transactional(c.db, func(appl application.Application) error {
if err := appl.WorkItems().Delete(ctx, ctx.WiID, *currentUserIdentityID); err != nil {
return errs.Wrapf(err, "error deleting work item %s", ctx.WiID)
Expand Down
33 changes: 22 additions & 11 deletions controller/workitem_blackbox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2304,17 +2304,6 @@ func (s *WorkItem2Suite) TestWI2FailShowMissing() {
test.ShowWorkitemNotFound(s.T(), s.svc.Context, s.svc, s.workitemCtrl, uuid.NewV4(), nil, nil)
}

func (s *WorkItem2Suite) TestWI2FailOnDelete() {
c := minimumRequiredCreatePayload()
c.Data.Attributes[workitem.SystemTitle] = "Title"
c.Data.Attributes[workitem.SystemState] = workitem.SystemStateNew
c.Data.Relationships.BaseType = newRelationBaseType(workitem.SystemBug)

_, createdWI := test.CreateWorkitemsCreated(s.T(), s.svc.Context, s.svc, s.workitemsCtrl, *c.Data.Relationships.Space.Data.ID, &c)
test.ShowWorkitemOK(s.T(), s.svc.Context, s.svc, s.workitemCtrl, *createdWI.Data.ID, nil, nil)
test.DeleteWorkitemMethodNotAllowed(s.T(), s.svc.Context, s.svc, s.workitemCtrl, *createdWI.Data.ID)
}

func (s *WorkItem2Suite) TestWI2CreateWithArea() {
fxt := tf.NewTestFixture(s.T(), s.DB,
tf.CreateWorkItemEnvironment(),
Expand Down Expand Up @@ -3392,3 +3381,25 @@ func (s *WorkItem2Suite) TestCreateAndUpdateWorkItemForEveryWIT() {
})
}
}

func (s *WorkItem2Suite) TestDeleteWorkitem() {
s.T().Run("ok", func(t *testing.T) {
fxt := tf.NewTestFixture(s.T(), s.DB, tf.WorkItems(1))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please use t instead of s.T() in sub-tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@kwk addressed it as a part of this PR - 37e2d35

s.svc = testsupport.ServiceAsUser("TestUpdateWI2-Service", *fxt.Identities[0])
test.DeleteWorkitemOK(s.T(), s.svc.Context, s.svc, s.workitemCtrl, fxt.WorkItems[0].ID)
})
s.T().Run("unauthorized", func(t *testing.T) {
fxt := tf.NewTestFixture(s.T(), s.DB, tf.WorkItems(1), tf.Identities(2))
Copy link
Collaborator

Choose a reason for hiding this comment

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

The second identity seems unused.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed unused identity here 1b07bad

Copy link
Collaborator

Choose a reason for hiding this comment

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

tf.WorkItems(1), tf.Identities(1) is the same a tf.WorkItems(1) because a work item requires an identity on its own.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@kwk yes. Thanks for pointing that out. removed it here -> 77b6e4e

svcNotAuthorized := goa.New("TestDeleteWI2-Service")
workitemCtrlNotAuthorized := NewWorkitemController(svcNotAuthorized, s.GormDB, s.Configuration)
test.DeleteWorkitemUnauthorized(s.T(), svcNotAuthorized.Context, svcNotAuthorized, workitemCtrlNotAuthorized, fxt.WorkItems[0].ID)
})
s.T().Run("forbidden", func(t *testing.T) {
fxt := tf.NewTestFixture(s.T(), s.DB, tf.WorkItems(1), tf.Identities(2))
s.svc = testsupport.ServiceAsUser("TestUpdateWI2-Service", *fxt.Identities[1])
test.DeleteWorkitemForbidden(s.T(), s.svc.Context, s.svc, s.workitemCtrl, fxt.WorkItems[0].ID)
})
s.T().Run("workitem not found", func(t *testing.T) {
test.DeleteWorkitemNotFound(s.T(), s.svc.Context, s.svc, s.workitemCtrl, uuid.NewV4())
})
}
2 changes: 0 additions & 2 deletions design/workitems.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,7 @@ var _ = a.Resource("workitem", func() {
a.Params(func() {
a.Param("wiID", d.UUID, "ID of the work item to delete")
})
a.Response(d.MethodNotAllowed)
a.Response(d.OK)
a.Response(d.BadRequest, JSONAPIErrors)
a.Response(d.InternalServerError, JSONAPIErrors)
a.Response(d.NotFound, JSONAPIErrors)
a.Response(d.Unauthorized, JSONAPIErrors)
Expand Down