From 9b92803bcd57a02d5896e08e463269e3d0fd8361 Mon Sep 17 00:00:00 2001 From: Rustin170506 <29879298+Rustin170506@users.noreply.github.com> Date: Sun, 27 Oct 2024 16:35:45 +0800 Subject: [PATCH 1/6] mirage: Implement `PATCH /crates/:name/:version` route handler Signed-off-by: Rustin170506 <29879298+Rustin170506@users.noreply.github.com> --- mirage/route-handlers/crates.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/mirage/route-handlers/crates.js b/mirage/route-handlers/crates.js index fcbe824e23f..66d617bd745 100644 --- a/mirage/route-handlers/crates.js +++ b/mirage/route-handlers/crates.js @@ -264,6 +264,28 @@ export function register(server) { return { ok: true, msg: 'owners successfully removed' }; }); + server.patch('/api/v1/crates/:name/:version', (schema, request) => { + const { name, version: versionNum } = request.params; + const crate = schema.crates.findBy({ name }); + if (!crate) { + return notFound(); + } + + const version = schema.versions.findBy({ crateId: crate.id, num: versionNum }); + if (!version) { + return notFound(); + } + + const body = JSON.parse(request.requestBody); + version.yanked = body.version.yanked; + version.yank_message = body.version.yank_message; + version.save(); + + return { + version, + }; + }); + server.delete('/api/v1/crates/:name/:version/yank', (schema, request) => { let { user } = getSession(schema); if (!user) { From bff0dda0816c63a5b36611d972d1790467c06c78 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 29 Oct 2024 12:17:29 +0100 Subject: [PATCH 2/6] mirage: Use `version` serializer for `PATCH` route handler --- mirage/route-handlers/crates.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mirage/route-handlers/crates.js b/mirage/route-handlers/crates.js index 66d617bd745..da0c19033eb 100644 --- a/mirage/route-handlers/crates.js +++ b/mirage/route-handlers/crates.js @@ -264,7 +264,7 @@ export function register(server) { return { ok: true, msg: 'owners successfully removed' }; }); - server.patch('/api/v1/crates/:name/:version', (schema, request) => { + server.patch('/api/v1/crates/:name/:version', function (schema, request) { const { name, version: versionNum } = request.params; const crate = schema.crates.findBy({ name }); if (!crate) { @@ -281,9 +281,7 @@ export function register(server) { version.yank_message = body.version.yank_message; version.save(); - return { - version, - }; + return this.serialize(version); }); server.delete('/api/v1/crates/:name/:version/yank', (schema, request) => { From 24fa7d7685cb5a935cb47066e6551922786676dd Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 29 Oct 2024 12:18:32 +0100 Subject: [PATCH 3/6] mirage: Add authentication check to `PATCH` version route handler --- mirage/route-handlers/crates.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mirage/route-handlers/crates.js b/mirage/route-handlers/crates.js index da0c19033eb..84ac2e2f966 100644 --- a/mirage/route-handlers/crates.js +++ b/mirage/route-handlers/crates.js @@ -265,6 +265,11 @@ export function register(server) { }); server.patch('/api/v1/crates/:name/:version', function (schema, request) { + let { user } = getSession(schema); + if (!user) { + return new Response(403, {}, { errors: [{ detail: 'must be logged in to perform that action' }] }); + } + const { name, version: versionNum } = request.params; const crate = schema.crates.findBy({ name }); if (!crate) { From 6e68cbba2022b4a2fcd7fb2833db2cf5832593be Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 29 Oct 2024 12:20:12 +0100 Subject: [PATCH 4/6] mirage: Add tests for `PATCH` version route handler --- tests/mirage/crates/versions/patch-test.js | 85 ++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 tests/mirage/crates/versions/patch-test.js diff --git a/tests/mirage/crates/versions/patch-test.js b/tests/mirage/crates/versions/patch-test.js new file mode 100644 index 00000000000..6b196dbba49 --- /dev/null +++ b/tests/mirage/crates/versions/patch-test.js @@ -0,0 +1,85 @@ +import { module, test } from 'qunit'; + +import fetch from 'fetch'; + +import { setupTest } from '../../../helpers'; +import setupMirage from '../../../helpers/setup-mirage'; + +const YANK_BODY = JSON.stringify({ + version: { + yanked: true, + yank_message: 'some reason', + }, +}); + +module('Mirage | PATCH /api/v1/crates/:crate/:version', function (hooks) { + setupTest(hooks); + setupMirage(hooks); + + test('returns 403 if unauthenticated', async function (assert) { + let response = await fetch('/api/v1/crates/foo/1.0.0', { method: 'PATCH', body: YANK_BODY }); + assert.strictEqual(response.status, 403); + assert.deepEqual(await response.json(), { + errors: [{ detail: 'must be logged in to perform that action' }], + }); + }); + + test('returns 404 for unknown crates', async function (assert) { + let user = this.server.create('user'); + this.authenticateAs(user); + + let response = await fetch('/api/v1/crates/foo/1.0.0', { method: 'PATCH', body: YANK_BODY }); + assert.strictEqual(response.status, 404); + assert.deepEqual(await response.json(), { errors: [{ detail: 'Not Found' }] }); + }); + + test('returns 404 for unknown versions', async function (assert) { + this.server.create('crate', { name: 'foo' }); + + let user = this.server.create('user'); + this.authenticateAs(user); + + let response = await fetch('/api/v1/crates/foo/1.0.0', { method: 'PATCH', body: YANK_BODY }); + assert.strictEqual(response.status, 404); + assert.deepEqual(await response.json(), { errors: [{ detail: 'Not Found' }] }); + }); + + test('yanks the version', async function (assert) { + let crate = this.server.create('crate', { name: 'foo' }); + let version = this.server.create('version', { crate, num: '1.0.0', yanked: false }); + assert.false(version.yanked); + assert.strictEqual(version.yank_message, null); + + let user = this.server.create('user'); + this.authenticateAs(user); + + let response = await fetch('/api/v1/crates/foo/1.0.0', { method: 'PATCH', body: YANK_BODY }); + assert.strictEqual(response.status, 200); + assert.deepEqual(await response.json(), { + version: { + crate: 'foo', + crate_size: 0, + created_at: '2010-06-16T21:30:45Z', + dl_path: '/api/v1/crates/foo/1.0.0/download', + downloads: 0, + id: '1', + license: 'MIT/Apache-2.0', + links: { + dependencies: '/api/v1/crates/foo/1.0.0/dependencies', + version_downloads: '/api/v1/crates/foo/1.0.0/downloads', + }, + num: '1.0.0', + published_by: null, + readme_path: '/api/v1/crates/foo/1.0.0/readme', + rust_version: null, + updated_at: '2017-02-24T12:34:56Z', + yank_message: 'some reason', + yanked: true, + }, + }); + + user.reload(); + assert.true(version.yanked); + assert.strictEqual(version.yank_message, 'some reason'); + }); +}); From 387d1da72ebbdba47af7356cacfb3121a89c020d Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 29 Oct 2024 12:19:57 +0100 Subject: [PATCH 5/6] mirage: Use `version.update()` to simplify `PATCH` version route handler --- mirage/route-handlers/crates.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mirage/route-handlers/crates.js b/mirage/route-handlers/crates.js index 84ac2e2f966..7ba043bd1f9 100644 --- a/mirage/route-handlers/crates.js +++ b/mirage/route-handlers/crates.js @@ -282,9 +282,10 @@ export function register(server) { } const body = JSON.parse(request.requestBody); - version.yanked = body.version.yanked; - version.yank_message = body.version.yank_message; - version.save(); + version.update({ + yanked: body.version.yanked, + yank_message: body.version.yank_message, + }); return this.serialize(version); }); From 22e1e75359bab1432007d0b92c616494ea739123 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 29 Oct 2024 12:28:04 +0100 Subject: [PATCH 6/6] mirage: Reset `version.yank_message` when unyanking --- mirage/route-handlers/crates.js | 4 +-- tests/mirage/crates/versions/patch-test.js | 35 +++++++++++++++++++ .../crates/versions/yank/unyank-test.js | 4 ++- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/mirage/route-handlers/crates.js b/mirage/route-handlers/crates.js index 7ba043bd1f9..eea1d76b856 100644 --- a/mirage/route-handlers/crates.js +++ b/mirage/route-handlers/crates.js @@ -284,7 +284,7 @@ export function register(server) { const body = JSON.parse(request.requestBody); version.update({ yanked: body.version.yanked, - yank_message: body.version.yank_message, + yank_message: body.version.yanked ? body.version.yank_message || null : null, }); return this.serialize(version); @@ -329,7 +329,7 @@ export function register(server) { return notFound(); } - version.update({ yanked: false }); + version.update({ yanked: false, yank_message: null }); return { ok: true }; }); diff --git a/tests/mirage/crates/versions/patch-test.js b/tests/mirage/crates/versions/patch-test.js index 6b196dbba49..e55db8ba625 100644 --- a/tests/mirage/crates/versions/patch-test.js +++ b/tests/mirage/crates/versions/patch-test.js @@ -12,6 +12,12 @@ const YANK_BODY = JSON.stringify({ }, }); +const UNYANK_BODY = JSON.stringify({ + version: { + yanked: false, + }, +}); + module('Mirage | PATCH /api/v1/crates/:crate/:version', function (hooks) { setupTest(hooks); setupMirage(hooks); @@ -81,5 +87,34 @@ module('Mirage | PATCH /api/v1/crates/:crate/:version', function (hooks) { user.reload(); assert.true(version.yanked); assert.strictEqual(version.yank_message, 'some reason'); + + response = await fetch('/api/v1/crates/foo/1.0.0', { method: 'PATCH', body: UNYANK_BODY }); + assert.strictEqual(response.status, 200); + assert.deepEqual(await response.json(), { + version: { + crate: 'foo', + crate_size: 0, + created_at: '2010-06-16T21:30:45Z', + dl_path: '/api/v1/crates/foo/1.0.0/download', + downloads: 0, + id: '1', + license: 'MIT/Apache-2.0', + links: { + dependencies: '/api/v1/crates/foo/1.0.0/dependencies', + version_downloads: '/api/v1/crates/foo/1.0.0/downloads', + }, + num: '1.0.0', + published_by: null, + readme_path: '/api/v1/crates/foo/1.0.0/readme', + rust_version: null, + updated_at: '2017-02-24T12:34:56Z', + yank_message: null, + yanked: false, + }, + }); + + user.reload(); + assert.false(version.yanked); + assert.strictEqual(version.yank_message, null); }); }); diff --git a/tests/mirage/crates/versions/yank/unyank-test.js b/tests/mirage/crates/versions/yank/unyank-test.js index bf5607e9191..5db7a5f504b 100644 --- a/tests/mirage/crates/versions/yank/unyank-test.js +++ b/tests/mirage/crates/versions/yank/unyank-test.js @@ -39,8 +39,9 @@ module('Mirage | PUT /api/v1/crates/:crateId/unyank', function (hooks) { test('unyanks the version', async function (assert) { let crate = this.server.create('crate', { name: 'foo' }); - let version = this.server.create('version', { crate, num: '1.0.0', yanked: true }); + let version = this.server.create('version', { crate, num: '1.0.0', yanked: true, yank_message: 'some reason' }); assert.true(version.yanked); + assert.strictEqual(version.yank_message, 'some reason'); let user = this.server.create('user'); this.authenticateAs(user); @@ -51,5 +52,6 @@ module('Mirage | PUT /api/v1/crates/:crateId/unyank', function (hooks) { user.reload(); assert.false(version.yanked); + assert.strictEqual(version.yank_message, null); }); });