diff --git a/packages/crates-io-msw/handlers/crates.js b/packages/crates-io-msw/handlers/crates.js index 2c6d0b4dfb5..d44ef1d42a8 100644 --- a/packages/crates-io-msw/handlers/crates.js +++ b/packages/crates-io-msw/handlers/crates.js @@ -5,6 +5,7 @@ import followCrate from './crates/follow.js'; import following from './crates/following.js'; import getCrate from './crates/get.js'; import listCrates from './crates/list.js'; +import patchCrate from './crates/patch.js'; import removeOwners from './crates/remove-owners.js'; import reverseDependencies from './crates/reverse-dependencies.js'; import teamOwners from './crates/team-owners.js'; @@ -14,6 +15,7 @@ import userOwners from './crates/user-owners.js'; export default [ listCrates, getCrate, + patchCrate, deleteCrate, following, followCrate, diff --git a/packages/crates-io-msw/handlers/crates/get.test.js b/packages/crates-io-msw/handlers/crates/get.test.js index 644a614e5b8..a2350d0609d 100644 --- a/packages/crates-io-msw/handlers/crates/get.test.js +++ b/packages/crates-io-msw/handlers/crates/get.test.js @@ -41,6 +41,7 @@ test('returns a crate object for known crates', async function () { num_versions: 1, repository: null, recent_downloads: 321, + trustpub_only: false, updated_at: '2017-02-24T12:34:56Z', versions: [1], yanked: false, @@ -122,6 +123,7 @@ test('works for non-canonical names', async function () { num_versions: 1, repository: null, recent_downloads: 321, + trustpub_only: false, updated_at: '2017-02-24T12:34:56Z', versions: [1], yanked: false, diff --git a/packages/crates-io-msw/handlers/crates/list.test.js b/packages/crates-io-msw/handlers/crates/list.test.js index dcafbf659a4..8a879fb03ff 100644 --- a/packages/crates-io-msw/handlers/crates/list.test.js +++ b/packages/crates-io-msw/handlers/crates/list.test.js @@ -58,6 +58,7 @@ test('returns a paginated crates list', async function () { num_versions: 2, repository: null, recent_downloads: 321, + trustpub_only: false, updated_at: '2017-02-24T12:34:56Z', versions: null, yanked: false, diff --git a/packages/crates-io-msw/handlers/crates/patch.js b/packages/crates-io-msw/handlers/crates/patch.js new file mode 100644 index 00000000000..426abbe2023 --- /dev/null +++ b/packages/crates-io-msw/handlers/crates/patch.js @@ -0,0 +1,30 @@ +import { http, HttpResponse } from 'msw'; + +import { db } from '../../index.js'; +import { serializeCrate } from '../../serializers/crate.js'; +import { getSession } from '../../utils/session.js'; + +export default http.patch('/api/v1/crates/:name', async ({ request, params }) => { + let { user } = getSession(); + if (!user) { + return HttpResponse.json({ errors: [{ detail: 'must be logged in to perform that action' }] }, { status: 403 }); + } + + let crate = db.crate.findFirst({ where: { name: { equals: params.name } } }); + if (!crate) { + return HttpResponse.json({ errors: [{ detail: `crate \`${params.name}\` does not exist` }] }, { status: 404 }); + } + + let body = await request.json(); + + if (body.crate?.trustpub_only != null) { + crate = db.crate.update({ + where: { id: { equals: crate.id } }, + data: { + trustpubOnly: body.crate.trustpub_only, + }, + }); + } + + return HttpResponse.json({ crate: serializeCrate(crate) }); +}); diff --git a/packages/crates-io-msw/handlers/crates/patch.test.js b/packages/crates-io-msw/handlers/crates/patch.test.js new file mode 100644 index 00000000000..ee93e1ec5fb --- /dev/null +++ b/packages/crates-io-msw/handlers/crates/patch.test.js @@ -0,0 +1,52 @@ +import { assert, test } from 'vitest'; + +import { db } from '../../index.js'; + +test('returns 403 if unauthenticated', async function () { + let response = await fetch('/api/v1/crates/foo', { + method: 'PATCH', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ crate: { trustpub_only: true } }), + }); + 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 () { + let user = db.user.create(); + db.mswSession.create({ user }); + + let response = await fetch('/api/v1/crates/foo', { + method: 'PATCH', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ crate: { trustpub_only: true } }), + }); + assert.strictEqual(response.status, 404); + assert.deepEqual(await response.json(), { errors: [{ detail: 'crate `foo` does not exist' }] }); +}); + +test('updates trustpub_only flag', async function () { + let user = db.user.create(); + db.mswSession.create({ user }); + + let crate = db.crate.create({ name: 'foo', trustpubOnly: false }); + assert.strictEqual(crate.trustpubOnly, false); + + db.version.create({ crate, num: '1.0.0' }); + db.crateOwnership.create({ crate, user }); + + let response = await fetch('/api/v1/crates/foo', { + method: 'PATCH', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ crate: { trustpub_only: true } }), + }); + assert.strictEqual(response.status, 200); + + let json = await response.json(); + assert.strictEqual(json.crate.trustpub_only, true); + + let updatedCrate = db.crate.findFirst({ where: { name: { equals: 'foo' } } }); + assert.strictEqual(updatedCrate.trustpubOnly, true); +}); diff --git a/packages/crates-io-msw/handlers/summary.test.js b/packages/crates-io-msw/handlers/summary.test.js index a918470d167..243ab55f58f 100644 --- a/packages/crates-io-msw/handlers/summary.test.js +++ b/packages/crates-io-msw/handlers/summary.test.js @@ -54,6 +54,7 @@ test('returns the data for the front page', async function () { num_versions: 1, recent_downloads: 321, repository: null, + trustpub_only: false, updated_at: '2017-02-24T12:34:56Z', versions: null, yanked: false, @@ -85,6 +86,7 @@ test('returns the data for the front page', async function () { num_versions: 1, repository: null, recent_downloads: 963, + trustpub_only: false, updated_at: '2017-02-24T12:34:56Z', versions: null, yanked: false, @@ -116,6 +118,7 @@ test('returns the data for the front page', async function () { num_versions: 1, repository: null, recent_downloads: 3852, + trustpub_only: false, updated_at: '2017-02-24T12:34:56Z', versions: null, yanked: false, @@ -147,6 +150,7 @@ test('returns the data for the front page', async function () { num_versions: 1, repository: null, recent_downloads: 1605, + trustpub_only: false, updated_at: '2017-02-24T12:34:56Z', versions: null, yanked: false, diff --git a/packages/crates-io-msw/models/crate-owner-invitation.test.js b/packages/crates-io-msw/models/crate-owner-invitation.test.js index 32c10b97d52..527da2c9c24 100644 --- a/packages/crates-io-msw/models/crate-owner-invitation.test.js +++ b/packages/crates-io-msw/models/crate-owner-invitation.test.js @@ -47,6 +47,7 @@ test('happy path', ({ expect }) => { "name": "crate-1", "recent_downloads": 321, "repository": null, + "trustpubOnly": false, "updated_at": "2017-02-24T12:34:56Z", Symbol(type): "crate", Symbol(primaryKey): "id", diff --git a/packages/crates-io-msw/models/crate-ownership.test.js b/packages/crates-io-msw/models/crate-ownership.test.js index 00f6b389824..765b44f771a 100644 --- a/packages/crates-io-msw/models/crate-ownership.test.js +++ b/packages/crates-io-msw/models/crate-ownership.test.js @@ -45,6 +45,7 @@ test('can set `team`', ({ expect }) => { "name": "crate-1", "recent_downloads": 321, "repository": null, + "trustpubOnly": false, "updated_at": "2017-02-24T12:34:56Z", Symbol(type): "crate", Symbol(primaryKey): "id", @@ -88,6 +89,7 @@ test('can set `user`', ({ expect }) => { "name": "crate-1", "recent_downloads": 321, "repository": null, + "trustpubOnly": false, "updated_at": "2017-02-24T12:34:56Z", Symbol(type): "crate", Symbol(primaryKey): "id", diff --git a/packages/crates-io-msw/models/crate.js b/packages/crates-io-msw/models/crate.js index ca253732260..a9ba4ed1c6f 100644 --- a/packages/crates-io-msw/models/crate.js +++ b/packages/crates-io-msw/models/crate.js @@ -16,6 +16,7 @@ export default { updated_at: String, badges: Array, _extra_downloads: Array, + trustpubOnly: Boolean, categories: manyOf('category'), keywords: manyOf('keyword'), @@ -31,5 +32,6 @@ export default { applyDefault(attrs, 'repository', () => null); applyDefault(attrs, 'created_at', () => '2010-06-16T21:30:45Z'); applyDefault(attrs, 'updated_at', () => '2017-02-24T12:34:56Z'); + applyDefault(attrs, 'trustpubOnly', () => false); }, }; diff --git a/packages/crates-io-msw/models/crate.test.js b/packages/crates-io-msw/models/crate.test.js index 7a40dc09f3f..5c4a6b5ae0c 100644 --- a/packages/crates-io-msw/models/crate.test.js +++ b/packages/crates-io-msw/models/crate.test.js @@ -19,6 +19,7 @@ test('default are applied', ({ expect }) => { "name": "crate-1", "recent_downloads": 321, "repository": null, + "trustpubOnly": false, "updated_at": "2017-02-24T12:34:56Z", Symbol(type): "crate", Symbol(primaryKey): "id", @@ -76,6 +77,7 @@ test('attributes can be set', ({ expect }) => { "name": "crates-io", "recent_downloads": 321, "repository": null, + "trustpubOnly": false, "updated_at": "2017-02-24T12:34:56Z", Symbol(type): "crate", Symbol(primaryKey): "id", diff --git a/packages/crates-io-msw/models/dependency.test.js b/packages/crates-io-msw/models/dependency.test.js index ae9bc6adfcb..17618c187f3 100644 --- a/packages/crates-io-msw/models/dependency.test.js +++ b/packages/crates-io-msw/models/dependency.test.js @@ -36,6 +36,7 @@ test('happy path', ({ expect }) => { "name": "crate-1", "recent_downloads": 321, "repository": null, + "trustpubOnly": false, "updated_at": "2017-02-24T12:34:56Z", Symbol(type): "crate", Symbol(primaryKey): "id", @@ -62,6 +63,7 @@ test('happy path', ({ expect }) => { "name": "crate-2", "recent_downloads": 1926, "repository": null, + "trustpubOnly": false, "updated_at": "2017-02-24T12:34:56Z", Symbol(type): "crate", Symbol(primaryKey): "id", diff --git a/packages/crates-io-msw/models/trustpub/gitlab-config.test.js b/packages/crates-io-msw/models/trustpub/gitlab-config.test.js index e016c5bfde1..4517d3aae41 100644 --- a/packages/crates-io-msw/models/trustpub/gitlab-config.test.js +++ b/packages/crates-io-msw/models/trustpub/gitlab-config.test.js @@ -21,6 +21,7 @@ test('defaults are applied', ({ expect }) => { "name": "crate-1", "recent_downloads": 321, "repository": null, + "trustpubOnly": false, "updated_at": "2017-02-24T12:34:56Z", Symbol(type): "crate", Symbol(primaryKey): "id", @@ -64,6 +65,7 @@ test('fields can be set', ({ expect }) => { "name": "serde", "recent_downloads": 321, "repository": null, + "trustpubOnly": false, "updated_at": "2017-02-24T12:34:56Z", Symbol(type): "crate", Symbol(primaryKey): "id", diff --git a/packages/crates-io-msw/models/version-download.test.js b/packages/crates-io-msw/models/version-download.test.js index 405b1878682..bd148a47fae 100644 --- a/packages/crates-io-msw/models/version-download.test.js +++ b/packages/crates-io-msw/models/version-download.test.js @@ -32,6 +32,7 @@ test('happy path', ({ expect }) => { "name": "crate-1", "recent_downloads": 321, "repository": null, + "trustpubOnly": false, "updated_at": "2017-02-24T12:34:56Z", Symbol(type): "crate", Symbol(primaryKey): "id", diff --git a/packages/crates-io-msw/models/version.test.js b/packages/crates-io-msw/models/version.test.js index 9006f703c14..4d5ca9af164 100644 --- a/packages/crates-io-msw/models/version.test.js +++ b/packages/crates-io-msw/models/version.test.js @@ -27,6 +27,7 @@ test('happy path', ({ expect }) => { "name": "crate-1", "recent_downloads": 321, "repository": null, + "trustpubOnly": false, "updated_at": "2017-02-24T12:34:56Z", Symbol(type): "crate", Symbol(primaryKey): "id",