0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-30 20:33:54 -05:00

feat(core): modify and delete PATs (#6390)

This commit is contained in:
wangsijie 2024-08-13 11:37:58 +08:00 committed by GitHub
parent 22d0a06fc6
commit fe054d5af5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 133 additions and 2 deletions

View file

@ -14,7 +14,7 @@ export class PersonalAccessTokensQueries {
returning: true,
});
public readonly update = buildUpdateWhereWithPool(this.pool)(PersonalAccessTokens, true);
private readonly update = buildUpdateWhereWithPool(this.pool)(PersonalAccessTokens, true);
constructor(public readonly pool: CommonQueryMethods) {}
@ -26,6 +26,14 @@ export class PersonalAccessTokensQueries {
`);
}
async updateName(userId: string, name: string, newName: string) {
return this.update({
where: { userId, name },
set: { name: newName },
jsonbMode: 'replace',
});
}
async getTokensByUserId(userId: string) {
return this.pool.any<PersonalAccessToken>(sql`
select ${sql.join(Object.values(fields), sql`, `)}

View file

@ -43,6 +43,53 @@
}
}
}
},
"/api/users/{userId}/personal-access-tokens/{name}": {
"delete": {
"summary": "Delete personal access token",
"description": "Delete a token for the user by name.",
"parameters": [
{
"name": "name",
"in": "path",
"description": "The name of the token."
}
],
"responses": {
"204": {
"description": "The token was deleted successfully."
}
}
},
"patch": {
"summary": "Update personal access token",
"description": "Update a token for the user by name.",
"parameters": [
{
"name": "name",
"in": "path",
"description": "The name of the token."
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"properties": {
"name": {
"description": "The token name to update. Must be unique within the user."
}
}
}
}
}
},
"responses": {
"204": {
"description": "The token was updated successfully."
}
}
}
}
}
}

View file

@ -59,4 +59,41 @@ export default function adminUserPersonalAccessTokenRoutes<T extends ManagementA
return next();
}
);
router.delete(
'/users/:userId/personal-access-tokens/:name',
koaGuard({
params: z.object({ userId: z.string(), name: z.string() }),
status: [204, 404],
}),
async (ctx, next) => {
const {
params: { userId, name },
} = ctx.guard;
await queries.personalAccessTokens.deleteByName(userId, name);
ctx.status = 204;
return next();
}
);
router.patch(
'/users/:userId/personal-access-tokens/:name',
koaGuard({
params: z.object({ userId: z.string(), name: z.string() }),
body: PersonalAccessTokens.updateGuard.pick({ name: true }).required(),
response: PersonalAccessTokens.guard,
status: [200, 400, 404],
}),
async (ctx, next) => {
const {
params: { userId, name },
body,
} = ctx.guard;
ctx.body = await queries.personalAccessTokens.updateName(userId, name, body.name);
return next();
}
);
}

View file

@ -143,3 +143,17 @@ export const createPersonalAccessToken = async ({
export const getUserPersonalAccessTokens = async (userId: string) =>
authedAdminApi.get(`users/${userId}/personal-access-tokens`).json<PersonalAccessToken[]>();
export const deletePersonalAccessToken = async (userId: string, name: string) =>
authedAdminApi.delete(`users/${userId}/personal-access-tokens/${name}`);
export const updatePersonalAccessToken = async (
userId: string,
name: string,
body: Record<string, unknown>
) =>
authedAdminApi
.patch(`users/${userId}/personal-access-tokens/${name}`, {
json: body,
})
.json<PersonalAccessToken>();

View file

@ -2,8 +2,10 @@ import { HTTPError } from 'ky';
import {
createPersonalAccessToken,
deletePersonalAccessToken,
deleteUser,
getUserPersonalAccessTokens,
updatePersonalAccessToken,
} from '#src/api/admin-user.js';
import { createUserByAdmin } from '#src/helpers/index.js';
import { devFeatureTest, randomString } from '#src/utils.js';
@ -67,7 +69,7 @@ devFeatureTest.describe('personal access tokens', () => {
await deleteUser(user.id);
});
it('should be able to create, get multiple PATs', async () => {
it('should be able to create, get, and delete multiple PATs', async () => {
const user = await createUserByAdmin();
const name1 = randomString();
const name2 = randomString();
@ -85,6 +87,29 @@ devFeatureTest.describe('personal access tokens', () => {
expect.arrayContaining([pat1, pat2])
);
await Promise.all([
deletePersonalAccessToken(user.id, name1),
deletePersonalAccessToken(user.id, name2),
]);
expect(await getUserPersonalAccessTokens(user.id)).toEqual([]);
await deleteUser(user.id);
});
it('should be able to update PAT', async () => {
const user = await createUserByAdmin();
const name = randomString();
await createPersonalAccessToken({
userId: user.id,
name,
});
const newName = randomString();
const updatedPat = await updatePersonalAccessToken(user.id, name, {
name: newName,
});
expect(updatedPat).toEqual(expect.objectContaining({ userId: user.id, name: newName }));
await deleteUser(user.id);
});
});