Skip to content

Commit 8bb6d32

Browse files
committed
Added: DeleteCurrentApiToken use case
1 parent 38c36d2 commit 8bb6d32

File tree

8 files changed

+114
-1
lines changed

8 files changed

+114
-1
lines changed

src/core/infra/repositories/ApiRepository.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ export abstract class ApiRepository {
3535
return await this.doRequest('put', apiEndpoint, data, queryParams)
3636
}
3737

38+
public async doDelete(apiEndpoint: string, queryParams: object = {}): Promise<AxiosResponse> {
39+
return await axios
40+
.delete(buildRequestUrl(apiEndpoint), buildRequestConfig(true, queryParams))
41+
.then((response) => response)
42+
.catch((error) => {
43+
throw new WriteError(this.buildErrorMessage(error))
44+
})
45+
}
46+
3847
protected buildApiEndpoint(
3948
resourceName: string,
4049
operation: string,

src/users/domain/repositories/IUsersRepository.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ export interface IUsersRepository {
55
getCurrentAuthenticatedUser(): Promise<AuthenticatedUser>
66
recreateApiToken(): Promise<ApiTokenInfo>
77
getCurrentApiToken(): Promise<ApiTokenInfo>
8+
deleteCurrentApiToken(): Promise<void>
89
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { UseCase } from '../../../core/domain/useCases/UseCase'
2+
import { IUsersRepository } from '../repositories/IUsersRepository'
3+
4+
export class DeleteCurrentApiToken implements UseCase<void> {
5+
private usersRepository: IUsersRepository
6+
7+
constructor(usersRepository: IUsersRepository) {
8+
this.usersRepository = usersRepository
9+
}
10+
11+
/**
12+
* Deletes the API token of the current authenticated user in ApiConfig.
13+
*
14+
* @returns {Promise<void>}
15+
*/
16+
async execute(): Promise<void> {
17+
return await this.usersRepository.deleteCurrentApiToken()
18+
}
19+
}

src/users/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ import { UsersRepository } from './infra/repositories/UsersRepository'
22
import { GetCurrentAuthenticatedUser } from './domain/useCases/GetCurrentAuthenticatedUser'
33
import { RecreateApiToken } from './domain/useCases/RecreateApiToken'
44
import { GetCurrentApiToken } from './domain/useCases/GetCurrentApiToken'
5+
import { DeleteCurrentApiToken } from './domain/useCases/DeleteCurrentApiToken'
56

67
const usersRepository = new UsersRepository()
78

89
const getCurrentAuthenticatedUser = new GetCurrentAuthenticatedUser(usersRepository)
910
const recreateApiToken = new RecreateApiToken(usersRepository)
1011
const getCurrentApiToken = new GetCurrentApiToken(usersRepository)
12+
const deleteCurrentApiToken = new DeleteCurrentApiToken(usersRepository)
1113

12-
export { getCurrentAuthenticatedUser, recreateApiToken, getCurrentApiToken }
14+
export { getCurrentAuthenticatedUser, recreateApiToken, getCurrentApiToken, deleteCurrentApiToken }
1315
export { AuthenticatedUser } from './domain/models/AuthenticatedUser'
16+
export { ApiTokenInfo } from './domain/models/ApiTokenInfo'

src/users/infra/repositories/UsersRepository.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ export class UsersRepository extends ApiRepository implements IUsersRepository {
3535
})
3636
}
3737

38+
public async deleteCurrentApiToken(): Promise<void> {
39+
return this.doDelete(`/${this.usersResourceName}/token`)
40+
.then(() => undefined)
41+
.catch((error) => {
42+
throw error
43+
})
44+
}
45+
3846
private getAuthenticatedUserFromResponse(response: AxiosResponse): AuthenticatedUser {
3947
const responseData = response.data.data
4048
return {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { ApiConfig, WriteError, deleteCurrentApiToken } from '../../../src'
2+
import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig'
3+
import { TestConstants } from '../../testHelpers/TestConstants'
4+
import { createApiTokenViaApi } from '../../testHelpers/users/apiTokenHelper'
5+
6+
describe('execute', () => {
7+
beforeAll(async () => {
8+
ApiConfig.init(
9+
TestConstants.TEST_API_URL,
10+
DataverseApiAuthMechanism.API_KEY,
11+
process.env.TEST_API_KEY
12+
)
13+
})
14+
15+
afterAll(async () => {
16+
ApiConfig.init(
17+
TestConstants.TEST_API_URL,
18+
DataverseApiAuthMechanism.API_KEY,
19+
process.env.TEST_API_KEY
20+
)
21+
})
22+
23+
test('should successfully recreate the API token', async () => {
24+
const testApiToken = await createApiTokenViaApi('deleteCurrentApiTokenFTUser')
25+
ApiConfig.init(TestConstants.TEST_API_URL, DataverseApiAuthMechanism.API_KEY, testApiToken)
26+
await deleteCurrentApiToken.execute()
27+
// Since the token has been deleted, the next call using it should return a WriteError
28+
await expect(
29+
deleteCurrentApiToken.execute()
30+
).rejects.toBeInstanceOf(WriteError)
31+
})
32+
})

test/integration/users/UsersRepository.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,22 @@ describe('UsersRepository', () => {
7575
await expect(sut.getCurrentApiToken()).rejects.toThrow(errorExpected)
7676
})
7777
})
78+
79+
describe('deleteCurrentApiToken', () => {
80+
test('should return API token info when valid authentication is provided', async () => {
81+
const testApiToken = await createApiTokenViaApi('deleteCurrentApiTokenITUser')
82+
ApiConfig.init(TestConstants.TEST_API_URL, DataverseApiAuthMechanism.API_KEY, testApiToken)
83+
await sut.deleteCurrentApiToken()
84+
// Since the token has been deleted, the next call using it should return 401
85+
const errorExpected: WriteError = new WriteError('[401] Bad API key')
86+
await expect(sut.deleteCurrentApiToken()).rejects.toThrow(errorExpected)
87+
})
88+
89+
test('should return error when authentication is not valid', async () => {
90+
ApiConfig.init(TestConstants.TEST_API_URL, DataverseApiAuthMechanism.API_KEY, 'invalidApiKey')
91+
92+
const errorExpected: WriteError = new WriteError('[401] Bad API key')
93+
await expect(sut.deleteCurrentApiToken()).rejects.toThrow(errorExpected)
94+
})
95+
})
7896
})
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { IUsersRepository } from '../../../src/users/domain/repositories/IUsersRepository'
2+
import { WriteError } from '../../../src'
3+
import { DeleteCurrentApiToken } from '../../../src/users/domain/useCases/DeleteCurrentApiToken'
4+
5+
describe('execute', () => {
6+
test('should return undefined on repository success', async () => {
7+
const usersRepositoryStub: IUsersRepository = {} as IUsersRepository
8+
usersRepositoryStub.deleteCurrentApiToken = jest.fn().mockResolvedValue(undefined)
9+
const sut = new DeleteCurrentApiToken(usersRepositoryStub)
10+
11+
const actual = await sut.execute()
12+
13+
expect(actual).toBeUndefined()
14+
})
15+
16+
test('should return error result on repository error', async () => {
17+
const usersRepositoryStub: IUsersRepository = {} as IUsersRepository
18+
usersRepositoryStub.deleteCurrentApiToken = jest.fn().mockRejectedValue(new WriteError())
19+
const sut = new DeleteCurrentApiToken(usersRepositoryStub)
20+
21+
await expect(sut.execute()).rejects.toThrow(WriteError)
22+
})
23+
})

0 commit comments

Comments
 (0)