Skip to content

Commit d50f6a8

Browse files
authored
Merge pull request #9798 from Turbo87/mirage-owner-invite
mirage: Fix `PUT /api/v1/crates/:name/owners` implementation
2 parents 4bcae01 + 6edac62 commit d50f6a8

File tree

7 files changed

+180
-22
lines changed

7 files changed

+180
-22
lines changed

mirage/route-handlers/crates.js

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,11 @@ export function register(server) {
227227
});
228228

229229
server.put('/api/v1/crates/:name/owners', (schema, request) => {
230+
let { user } = getSession(schema);
231+
if (!user) {
232+
return new Response(403, {}, { errors: [{ detail: 'must be logged in to perform that action' }] });
233+
}
234+
230235
let { name } = request.params;
231236
let crate = schema.crates.findBy({ name });
232237

@@ -235,17 +240,48 @@ export function register(server) {
235240
}
236241

237242
const body = JSON.parse(request.requestBody);
238-
const [ownerId] = body.owners;
239-
const user = schema.users.findBy({ login: ownerId });
240243

241-
if (!user) {
242-
return { errors: [{ detail: `could not find user with login \`${ownerId}\`` }] };
244+
let users = [];
245+
let teams = [];
246+
let msgs = [];
247+
for (let login of body.owners) {
248+
if (login.includes(':')) {
249+
let team = schema.teams.findBy({ login });
250+
if (!team) {
251+
return new Response(404, {}, { errors: [{ detail: `could not find team with login \`${login}\`` }] });
252+
}
253+
254+
teams.push(team);
255+
msgs.push(`team ${login} has been added as an owner of crate ${crate.name}`);
256+
} else {
257+
let user = schema.users.findBy({ login });
258+
if (!user) {
259+
return new Response(404, {}, { errors: [{ detail: `could not find user with login \`${login}\`` }] });
260+
}
261+
262+
users.push(user);
263+
msgs.push(`user ${login} has been invited to be an owner of crate ${crate.name}`);
264+
}
243265
}
244266

245-
return { ok: true };
267+
for (let team of teams) {
268+
schema.crateOwnerships.create({ crate, team });
269+
}
270+
271+
for (let invitee of users) {
272+
schema.crateOwnerInvitations.create({ crate, inviter: user, invitee });
273+
}
274+
275+
let msg = msgs.join(',');
276+
return { ok: true, msg };
246277
});
247278

248279
server.delete('/api/v1/crates/:name/owners', (schema, request) => {
280+
let { user } = getSession(schema);
281+
if (!user) {
282+
return new Response(403, {}, { errors: [{ detail: 'must be logged in to perform that action' }] });
283+
}
284+
249285
let { name } = request.params;
250286
let crate = schema.crates.findBy({ name });
251287

tests/adapters/crate-test.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { module, test } from 'qunit';
22

3-
import { setupMirage } from 'ember-cli-mirage/test-support';
4-
5-
import { setupTest } from 'crates-io/tests/helpers';
3+
import { setupMirage, setupTest } from 'crates-io/tests/helpers';
64

75
module('Adapter | crate', function (hooks) {
86
setupTest(hooks);

tests/helpers/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { setupApplicationTest as upstreamSetupApplicationTest } from 'ember-quni
33
import { setupSentryMock } from './sentry';
44
import setupMirage from './setup-mirage';
55

6+
export { default as setupMirage } from './setup-mirage';
67
export { setupTest, setupRenderingTest } from 'ember-qunit';
78

89
// see http://emberjs.github.io/rfcs/0637-customizable-test-setups.html
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import { module, test } from 'qunit';
2+
3+
import fetch from 'fetch';
4+
5+
import { setupTest } from '../../helpers';
6+
import setupMirage from '../../helpers/setup-mirage';
7+
8+
const ADD_USER_BODY = JSON.stringify({ owners: ['john-doe'] });
9+
10+
module('Mirage | PUT /api/v1/crates/:name/owners', function (hooks) {
11+
setupTest(hooks);
12+
setupMirage(hooks);
13+
14+
test('returns 403 if unauthenticated', async function (assert) {
15+
let response = await fetch('/api/v1/crates/foo/owners', { method: 'PUT', body: ADD_USER_BODY });
16+
assert.strictEqual(response.status, 403);
17+
assert.deepEqual(await response.json(), {
18+
errors: [{ detail: 'must be logged in to perform that action' }],
19+
});
20+
});
21+
22+
test('returns 404 for unknown crates', async function (assert) {
23+
let user = this.server.create('user');
24+
this.authenticateAs(user);
25+
26+
let response = await fetch('/api/v1/crates/foo/owners', { method: 'PUT', body: ADD_USER_BODY });
27+
assert.strictEqual(response.status, 404);
28+
assert.deepEqual(await response.json(), { errors: [{ detail: 'Not Found' }] });
29+
});
30+
31+
test('can add new owner', async function (assert) {
32+
let user = this.server.create('user');
33+
this.authenticateAs(user);
34+
35+
let crate = this.server.create('crate', { name: 'foo' });
36+
this.server.create('crate-ownership', { crate, user });
37+
38+
let user2 = this.server.create('user');
39+
40+
let body = JSON.stringify({ owners: [user2.login] });
41+
let response = await fetch('/api/v1/crates/foo/owners', { method: 'PUT', body });
42+
assert.strictEqual(response.status, 200);
43+
assert.deepEqual(await response.json(), {
44+
ok: true,
45+
msg: 'user user-2 has been invited to be an owner of crate foo',
46+
});
47+
48+
let owners = this.server.schema.crateOwnerships.where({ crateId: crate.id });
49+
assert.strictEqual(owners.length, 1);
50+
assert.strictEqual(owners.models[0].userId, user.id);
51+
52+
let invites = this.server.schema.crateOwnerInvitations.where({ crateId: crate.id });
53+
assert.strictEqual(invites.length, 1);
54+
assert.strictEqual(invites.models[0].inviterId, user.id);
55+
assert.strictEqual(invites.models[0].inviteeId, user2.id);
56+
});
57+
58+
test('can add team owner', async function (assert) {
59+
let user = this.server.create('user');
60+
this.authenticateAs(user);
61+
62+
let crate = this.server.create('crate', { name: 'foo' });
63+
this.server.create('crate-ownership', { crate, user });
64+
65+
let team = this.server.create('team');
66+
67+
let body = JSON.stringify({ owners: [team.login] });
68+
let response = await fetch('/api/v1/crates/foo/owners', { method: 'PUT', body });
69+
assert.strictEqual(response.status, 200);
70+
assert.deepEqual(await response.json(), {
71+
ok: true,
72+
msg: 'team github:rust-lang:team-1 has been added as an owner of crate foo',
73+
});
74+
75+
let owners = this.server.schema.crateOwnerships.where({ crateId: crate.id });
76+
assert.strictEqual(owners.length, 2);
77+
assert.strictEqual(owners.models[0].userId, user.id);
78+
assert.strictEqual(owners.models[0].teamId, null);
79+
assert.strictEqual(owners.models[1].userId, null);
80+
assert.strictEqual(owners.models[1].teamId, user.id);
81+
82+
let invites = this.server.schema.crateOwnerInvitations.where({ crateId: crate.id });
83+
assert.strictEqual(invites.length, 0);
84+
});
85+
86+
test('can add multiple owners', async function (assert) {
87+
let user = this.server.create('user');
88+
this.authenticateAs(user);
89+
90+
let crate = this.server.create('crate', { name: 'foo' });
91+
this.server.create('crate-ownership', { crate, user });
92+
93+
let team = this.server.create('team');
94+
let user2 = this.server.create('user');
95+
let user3 = this.server.create('user');
96+
97+
let body = JSON.stringify({ owners: [user2.login, team.login, user3.login] });
98+
let response = await fetch('/api/v1/crates/foo/owners', { method: 'PUT', body });
99+
assert.strictEqual(response.status, 200);
100+
assert.deepEqual(await response.json(), {
101+
ok: true,
102+
msg: 'user user-2 has been invited to be an owner of crate foo,team github:rust-lang:team-1 has been added as an owner of crate foo,user user-3 has been invited to be an owner of crate foo',
103+
});
104+
105+
let owners = this.server.schema.crateOwnerships.where({ crateId: crate.id });
106+
assert.strictEqual(owners.length, 2);
107+
assert.strictEqual(owners.models[0].userId, user.id);
108+
assert.strictEqual(owners.models[0].teamId, null);
109+
assert.strictEqual(owners.models[1].userId, null);
110+
assert.strictEqual(owners.models[1].teamId, user.id);
111+
112+
let invites = this.server.schema.crateOwnerInvitations.where({ crateId: crate.id });
113+
assert.strictEqual(invites.length, 2);
114+
assert.strictEqual(invites.models[0].inviterId, user.id);
115+
assert.strictEqual(invites.models[0].inviteeId, user2.id);
116+
assert.strictEqual(invites.models[1].inviterId, user.id);
117+
assert.strictEqual(invites.models[1].inviteeId, user3.id);
118+
});
119+
});

tests/models/crate-test.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ import { module, test } from 'qunit';
22

33
import AdapterError from '@ember-data/adapter/error';
44

5-
import { setupMirage } from 'ember-cli-mirage/test-support';
6-
7-
import { setupTest } from 'crates-io/tests/helpers';
5+
import { setupMirage, setupTest } from 'crates-io/tests/helpers';
86

97
module('Model | Crate', function (hooks) {
108
setupTest(hooks);
@@ -17,17 +15,23 @@ module('Model | Crate', function (hooks) {
1715
module('inviteOwner()', function () {
1816
test('happy path', async function (assert) {
1917
let user = this.server.create('user');
18+
this.authenticateAs(user);
2019

2120
let crate = this.server.create('crate');
2221
this.server.create('version', { crate });
2322

23+
let user2 = this.server.create('user');
24+
2425
let crateRecord = await this.store.findRecord('crate', crate.name);
2526

26-
let result = await crateRecord.inviteOwner(user.login);
27-
assert.deepEqual(result, { ok: true });
27+
let result = await crateRecord.inviteOwner(user2.login);
28+
assert.deepEqual(result, { ok: true, msg: 'user user-2 has been invited to be an owner of crate crate-0' });
2829
});
2930

3031
test('error handling', async function (assert) {
32+
let user = this.server.create('user');
33+
this.authenticateAs(user);
34+
3135
let crate = this.server.create('crate');
3236
this.server.create('version', { crate });
3337

@@ -43,17 +47,23 @@ module('Model | Crate', function (hooks) {
4347
module('removeOwner()', function () {
4448
test('happy path', async function (assert) {
4549
let user = this.server.create('user');
50+
this.authenticateAs(user);
4651

4752
let crate = this.server.create('crate');
4853
this.server.create('version', { crate });
4954

55+
let user2 = this.server.create('user');
56+
5057
let crateRecord = await this.store.findRecord('crate', crate.name);
5158

52-
let result = await crateRecord.removeOwner(user.login);
59+
let result = await crateRecord.removeOwner(user2.login);
5360
assert.deepEqual(result, { ok: true, msg: 'owners successfully removed' });
5461
});
5562

5663
test('error handling', async function (assert) {
64+
let user = this.server.create('user');
65+
this.authenticateAs(user);
66+
5767
let crate = this.server.create('crate');
5868
this.server.create('version', { crate });
5969

tests/models/version-test.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
1-
import { setupTest } from 'ember-qunit';
21
import { module, test } from 'qunit';
32

4-
import { setupMirage } from 'ember-cli-mirage/test-support';
5-
6-
import { setupFakeTimers } from '../helpers/fake-timers';
3+
import { setupMirage, setupTest } from 'crates-io/tests/helpers';
74

85
module('Model | Version', function (hooks) {
96
setupTest(hooks);
107
setupMirage(hooks);
11-
setupFakeTimers(hooks);
128

139
hooks.beforeEach(function () {
1410
this.store = this.owner.lookup('service:store');

tests/services/playground-test.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { module, test } from 'qunit';
22

3-
import { setupMirage } from 'ember-cli-mirage/test-support';
4-
5-
import { setupTest } from 'crates-io/tests/helpers';
3+
import { setupMirage, setupTest } from 'crates-io/tests/helpers';
64

75
module('Service | Playground', function (hooks) {
86
setupTest(hooks);

0 commit comments

Comments
 (0)