Skip to content

Commit d700721

Browse files
jeanp413easyCZmustard-mh
authored andcommitted
[public-api] delete personal access token
Co-authored-by: Milan Pavlik <[email protected]> Co-authored-by: mustard <[email protected]>
1 parent 580e20f commit d700721

File tree

4 files changed

+98
-10
lines changed

4 files changed

+98
-10
lines changed

components/gitpod-db/go/personal_access_token.go

+28
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,34 @@ func UpdatePersonalAccessTokenHash(ctx context.Context, conn *gorm.DB, tokenID u
119119
return GetPersonalAccessTokenForUser(ctx, conn, tokenID, userID)
120120
}
121121

122+
func DeletePersonalAccessTokenForUser(ctx context.Context, conn *gorm.DB, tokenID uuid.UUID, userID uuid.UUID) (int64, error) {
123+
if tokenID == uuid.Nil {
124+
return 0, fmt.Errorf("Invalid or empty tokenID")
125+
}
126+
127+
if userID == uuid.Nil {
128+
return 0, fmt.Errorf("Invalid or empty userID")
129+
}
130+
131+
db := conn.WithContext(ctx)
132+
133+
db = db.
134+
Table((&PersonalAccessToken{}).TableName()).
135+
Where("id = ?", tokenID).
136+
Where("userId = ?", userID).
137+
Where("deleted = ?", 0).
138+
Update("deleted", 1)
139+
if db.Error != nil {
140+
return 0, fmt.Errorf("failed to delete token (ID: %s): %v", tokenID.String(), db.Error)
141+
}
142+
143+
if db.RowsAffected == 0 {
144+
return 0, fmt.Errorf("token (ID: %s) for user (ID: %s) does not exist: %w", tokenID, userID, ErrorNotFound)
145+
}
146+
147+
return db.RowsAffected, nil
148+
}
149+
122150
func ListPersonalAccessTokensForUser(ctx context.Context, conn *gorm.DB, userID uuid.UUID, pagination Pagination) (*PaginatedResult[PersonalAccessToken], error) {
123151
if userID == uuid.Nil {
124152
return nil, fmt.Errorf("user ID is a required argument to list personal access tokens for user, got nil")

components/gitpod-db/go/personal_access_token_test.go

+40
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,46 @@ func TestPersonalAccessToken_UpdateHash(t *testing.T) {
119119
})
120120
}
121121

122+
func TestPersonalAccessToken_Delete(t *testing.T) {
123+
conn := dbtest.ConnectForTests(t)
124+
125+
firstUserId := uuid.New()
126+
secondUserId := uuid.New()
127+
128+
token := dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{UserID: firstUserId})
129+
token2 := dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{UserID: secondUserId})
130+
131+
tokenEntries := []db.PersonalAccessToken{token, token2}
132+
133+
dbtest.CreatePersonalAccessTokenRecords(t, conn, tokenEntries...)
134+
135+
t.Run("not matching user", func(t *testing.T) {
136+
count, err := db.DeletePersonalAccessTokenForUser(context.Background(), conn, token.ID, token2.UserID)
137+
require.Error(t, err, db.ErrorNotFound)
138+
require.Equal(t, int64(0), count)
139+
})
140+
141+
t.Run("not matching token", func(t *testing.T) {
142+
count, err := db.DeletePersonalAccessTokenForUser(context.Background(), conn, token2.ID, token.UserID)
143+
require.Error(t, err, db.ErrorNotFound)
144+
require.Equal(t, int64(0), count)
145+
})
146+
147+
t.Run("both token and user don't exist in the DB", func(t *testing.T) {
148+
count, err := db.DeletePersonalAccessTokenForUser(context.Background(), conn, uuid.New(), uuid.New())
149+
require.Error(t, err, db.ErrorNotFound)
150+
require.Equal(t, int64(0), count)
151+
})
152+
153+
t.Run("valid", func(t *testing.T) {
154+
count, err := db.DeletePersonalAccessTokenForUser(context.Background(), conn, token.ID, token.UserID)
155+
require.NoError(t, err)
156+
require.Equal(t, int64(1), count)
157+
_, err = db.GetPersonalAccessTokenForUser(context.Background(), conn, token.ID, token.UserID)
158+
require.Error(t, err, db.ErrorNotFound)
159+
})
160+
}
161+
122162
func TestListPersonalAccessTokensForUser(t *testing.T) {
123163
ctx := context.Background()
124164
conn := dbtest.ConnectForTests(t)

components/public-api-server/pkg/apiv1/tokens.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -227,13 +227,18 @@ func (s *TokensService) DeletePersonalAccessToken(ctx context.Context, req *conn
227227
return nil, err
228228
}
229229

230-
_, _, err = s.getUser(ctx, conn)
230+
_, userID, err := s.getUser(ctx, conn)
231231
if err != nil {
232232
return nil, err
233233
}
234234

235-
log.Infof("Handling DeletePersonalAccessToken request for Token ID '%s'", tokenID.String())
236-
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("gitpod.experimental.v1.TokensService.DeletePersonalAccessToken is not implemented"))
235+
_, err = db.DeletePersonalAccessTokenForUser(ctx, s.dbConn, tokenID, userID)
236+
if err != nil {
237+
log.WithError(err).Errorf("failed to delete personal access token (ID: %s) for user %s", tokenID.String(), userID.String())
238+
return nil, connect.NewError(connect.CodeInternal, errors.New("Failed to delete personal access token."))
239+
}
240+
241+
return connect.NewResponse(&v1.DeletePersonalAccessTokenResponse{}), nil
237242
}
238243

239244
func (s *TokensService) getUser(ctx context.Context, conn protocol.APIInterface) (*protocol.User, uuid.UUID, error) {

components/public-api-server/pkg/apiv1/tokens_test.go

+22-7
Original file line numberDiff line numberDiff line change
@@ -513,16 +513,31 @@ func TestTokensService_DeletePersonalAccessToken(t *testing.T) {
513513
require.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err))
514514
})
515515

516-
t.Run("unimplemented when feature flag enabled", func(t *testing.T) {
517-
serverMock, _, client := setupTokensService(t, withTokenFeatureEnabled)
516+
t.Run("delete token", func(t *testing.T) {
517+
serverMock, dbConn, client := setupTokensService(t, withTokenFeatureEnabled)
518518

519-
serverMock.EXPECT().GetLoggedInUser(gomock.Any()).Return(user, nil)
519+
tokens := dbtest.CreatePersonalAccessTokenRecords(t, dbConn,
520+
dbtest.NewPersonalAccessToken(t, db.PersonalAccessToken{
521+
UserID: uuid.MustParse(user.ID),
522+
}),
523+
)
520524

521-
_, err := client.DeletePersonalAccessToken(context.Background(), connect.NewRequest(&v1.DeletePersonalAccessTokenRequest{
522-
Id: uuid.New().String(),
525+
serverMock.EXPECT().GetLoggedInUser(gomock.Any()).Return(user, nil).Times(3)
526+
527+
_, err := client.GetPersonalAccessToken(context.Background(), connect.NewRequest(&v1.GetPersonalAccessTokenRequest{
528+
Id: tokens[0].ID.String(),
523529
}))
530+
require.NoError(t, err)
524531

525-
require.Equal(t, connect.CodeUnimplemented, connect.CodeOf(err))
532+
_, err = client.DeletePersonalAccessToken(context.Background(), connect.NewRequest(&v1.DeletePersonalAccessTokenRequest{
533+
Id: tokens[0].ID.String(),
534+
}))
535+
require.NoError(t, err)
536+
537+
_, err = client.GetPersonalAccessToken(context.Background(), connect.NewRequest(&v1.GetPersonalAccessTokenRequest{
538+
Id: tokens[0].ID.String(),
539+
}))
540+
require.Error(t, err, fmt.Errorf("Token with ID %s does not exist: not found", tokens[0].ID.String()))
526541
})
527542
}
528543

@@ -578,7 +593,7 @@ func TestTokensService_Workflow(t *testing.T) {
578593
_, err = client.DeletePersonalAccessToken(ctx, connect.NewRequest(&v1.DeletePersonalAccessTokenRequest{
579594
Id: secondTokenResponse.Msg.GetToken().GetId(),
580595
}))
581-
require.Error(t, err, "currently unimplemented")
596+
require.NoError(t, err)
582597
}
583598

584599
func setupTokensService(t *testing.T, expClient experiments.Client) (*protocol.MockAPIInterface, *gorm.DB, v1connect.TokensServiceClient) {

0 commit comments

Comments
 (0)