Skip to content

Commit 8318172

Browse files
committed
msw: Implement PUT /api/v1/me/tokens request handler
1 parent 635dbf7 commit 8318172

File tree

4 files changed

+142
-0
lines changed

4 files changed

+142
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import createToken from './api-tokens/create.js';
2+
3+
export default [createToken];
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { http, HttpResponse } from 'msw';
2+
3+
import { db } from '../../index.js';
4+
import { serializeApiToken } from '../../serializers/api-token.js';
5+
import { getSession } from '../../utils/session.js';
6+
7+
export default http.put('/api/v1/me/tokens', async ({ request }) => {
8+
let { user } = getSession();
9+
if (!user) {
10+
return HttpResponse.json({ errors: [{ detail: 'must be logged in to perform that action' }] }, { status: 403 });
11+
}
12+
13+
let json = await request.json();
14+
15+
let token = db.apiToken.create({
16+
user,
17+
name: json.api_token.name,
18+
crateScopes: json.api_token.crate_scopes ?? null,
19+
endpointScopes: json.api_token.endpoint_scopes ?? null,
20+
expiredAt: json.api_token.expired_at ?? null,
21+
createdAt: new Date().toISOString(),
22+
});
23+
24+
return HttpResponse.json({
25+
api_token: serializeApiToken(token, { includeToken: true }),
26+
});
27+
});
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { afterEach, assert, beforeEach, test, vi } from 'vitest';
2+
3+
import { db } from '../../index.js';
4+
5+
beforeEach(() => {
6+
vi.useFakeTimers();
7+
vi.setSystemTime(new Date('2017-11-20T11:23:45Z'));
8+
});
9+
10+
afterEach(() => {
11+
vi.restoreAllMocks();
12+
});
13+
14+
test('creates a new API token', async function () {
15+
let user = db.user.create();
16+
db.mswSession.create({ user });
17+
18+
let body = JSON.stringify({ api_token: { name: 'foooo' } });
19+
let response = await fetch('/api/v1/me/tokens', { method: 'PUT', body });
20+
assert.strictEqual(response.status, 200);
21+
22+
let token = db.apiToken.findMany({})[0];
23+
assert.ok(token);
24+
25+
assert.deepEqual(await response.json(), {
26+
api_token: {
27+
id: 1,
28+
crate_scopes: null,
29+
created_at: '2017-11-20T11:23:45.000Z',
30+
endpoint_scopes: null,
31+
expired_at: null,
32+
last_used_at: null,
33+
name: 'foooo',
34+
revoked: false,
35+
token: token.token,
36+
},
37+
});
38+
});
39+
40+
test('creates a new API token with scopes', async function () {
41+
let user = db.user.create();
42+
db.mswSession.create({ user });
43+
44+
let body = JSON.stringify({
45+
api_token: {
46+
name: 'foooo',
47+
crate_scopes: ['serde', 'serde-*'],
48+
endpoint_scopes: ['publish-update'],
49+
},
50+
});
51+
let response = await fetch('/api/v1/me/tokens', { method: 'PUT', body });
52+
assert.strictEqual(response.status, 200);
53+
54+
let token = db.apiToken.findMany({})[0];
55+
assert.ok(token);
56+
57+
assert.deepEqual(await response.json(), {
58+
api_token: {
59+
id: 1,
60+
crate_scopes: ['serde', 'serde-*'],
61+
created_at: '2017-11-20T11:23:45.000Z',
62+
endpoint_scopes: ['publish-update'],
63+
expired_at: null,
64+
last_used_at: null,
65+
name: 'foooo',
66+
revoked: false,
67+
token: token.token,
68+
},
69+
});
70+
});
71+
72+
test('creates a new API token with expiry date', async function () {
73+
let user = db.user.create();
74+
db.mswSession.create({ user });
75+
76+
let body = JSON.stringify({
77+
api_token: {
78+
name: 'foooo',
79+
expired_at: '2023-12-24T12:34:56Z',
80+
},
81+
});
82+
let response = await fetch('/api/v1/me/tokens', { method: 'PUT', body });
83+
assert.strictEqual(response.status, 200);
84+
85+
let token = db.apiToken.findMany({})[0];
86+
assert.ok(token);
87+
88+
assert.deepEqual(await response.json(), {
89+
api_token: {
90+
id: 1,
91+
crate_scopes: null,
92+
created_at: '2017-11-20T11:23:45.000Z',
93+
endpoint_scopes: null,
94+
expired_at: '2023-12-24T12:34:56.000Z',
95+
last_used_at: null,
96+
name: 'foooo',
97+
revoked: false,
98+
token: token.token,
99+
},
100+
});
101+
});
102+
103+
test('returns an error if unauthenticated', async function () {
104+
let body = JSON.stringify({ api_token: {} });
105+
let response = await fetch('/api/v1/me/tokens', { method: 'PUT', body });
106+
assert.strictEqual(response.status, 403);
107+
assert.deepEqual(await response.json(), {
108+
errors: [{ detail: 'must be logged in to perform that action' }],
109+
});
110+
});

packages/crates-io-msw/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import apiTokenHandlers from './handlers/api-tokens.js';
12
import categoryHandlers from './handlers/categories.js';
23
import docsRsHandlers from './handlers/docs-rs.js';
34
import inviteHandlers from './handlers/invites.js';
@@ -21,6 +22,7 @@ import version from './models/version.js';
2122
import { factory } from './utils/factory.js';
2223

2324
export const handlers = [
25+
...apiTokenHandlers,
2426
...categoryHandlers,
2527
...docsRsHandlers,
2628
...inviteHandlers,

0 commit comments

Comments
 (0)