Skip to content

Commit

Permalink
Auto merge of #4145 - Turbo87:mirage-invites, r=locks
Browse files Browse the repository at this point in the history
mirage: Implement `GET /api/private/crate_owner_invitations` route handler

This will be needed to address #4083
  • Loading branch information
bors committed Nov 8, 2021
2 parents a658181 + fc175da commit 7c3ee6c
Show file tree
Hide file tree
Showing 3 changed files with 280 additions and 0 deletions.
2 changes: 2 additions & 0 deletions mirage/config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as Categories from './route-handlers/categories';
import * as Crates from './route-handlers/crates';
import * as DocsRS from './route-handlers/docs-rs';
import * as Invites from './route-handlers/invites';
import * as Keywords from './route-handlers/keywords';
import * as Me from './route-handlers/me';
import * as Session from './route-handlers/session';
Expand All @@ -12,6 +13,7 @@ export default function () {
Categories.register(this);
Crates.register(this);
DocsRS.register(this);
Invites.register(this);
Keywords.register(this);
Me.register(this);
Session.register(this);
Expand Down
49 changes: 49 additions & 0 deletions mirage/route-handlers/invites.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Response } from 'ember-cli-mirage';

import { getSession } from '../utils/session';
import { notFound } from './-utils';

export function register(server) {
server.get('/api/private/crate_owner_invitations', function (schema, request) {
let { user } = getSession(schema);
if (!user) {
return new Response(403, {}, { errors: [{ detail: 'must be logged in to perform that action' }] });
}

let invites;
if (request.queryParams['crate_name']) {
let crate = schema.crates.findBy({ name: request.queryParams['crate_name'] });
if (!crate) return notFound();

invites = schema.crateOwnerInvitations.where({ crateId: crate.id });
} else if (request.queryParams['invitee_id']) {
let inviteeId = request.queryParams['invitee_id'];
if (inviteeId !== user.id) {
return new Response(403, {}, { errors: [{ detail: 'must be logged in to perform that action' }] });
}

invites = schema.crateOwnerInvitations.where({ inviteeId });
} else {
return new Response(400, {}, { errors: [{ detail: 'missing or invalid filter' }] });
}

let perPage = 10;
let start = request.queryParams['__start__'] ?? 0;
let end = start + perPage;

let nextPage = null;
if (invites.length > end) {
let url = new URL(request.url, 'https://crates.io');
url.searchParams.set('__start__', end);
nextPage = url.search;
}

invites = invites.slice(start, end);

let response = this.serialize(invites);
response.users ??= [];
response.meta = { next_page: nextPage };

return response;
});
}
229 changes: 229 additions & 0 deletions tests/mirage/private/crate-owner-invitations/get-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
import { module, test } from 'qunit';

import fetch from 'fetch';

import { setupTest } from '../../../helpers';
import setupMirage from '../../../helpers/setup-mirage';

module('Mirage | GET /api/private/crate_owner_invitations', function (hooks) {
setupTest(hooks);
setupMirage(hooks);

test('happy path (invitee_id)', async function (assert) {
let nanomsg = this.server.create('crate', { name: 'nanomsg' });
this.server.create('version', { crate: nanomsg });

let ember = this.server.create('crate', { name: 'ember-rs' });
this.server.create('version', { crate: ember });

let user = this.server.create('user');
this.server.create('mirage-session', { user });

let inviter = this.server.create('user', { name: 'janed' });
this.server.create('crate-owner-invitation', {
crate: nanomsg,
createdAt: '2016-12-24T12:34:56Z',
invitee: user,
inviter,
});

let inviter2 = this.server.create('user', { name: 'wycats' });
this.server.create('crate-owner-invitation', {
crate: ember,
createdAt: '2020-12-31T12:34:56Z',
invitee: user,
inviter: inviter2,
});

let response = await fetch(`/api/private/crate_owner_invitations?invitee_id=${user.id}`);
assert.equal(response.status, 200);
assert.deepEqual(await response.json(), {
crate_owner_invitations: [
{
crate_id: Number(nanomsg.id),
crate_name: 'nanomsg',
created_at: '2016-12-24T12:34:56Z',
invited_by_username: 'janed',
invitee_id: Number(user.id),
inviter_id: Number(inviter.id),
},
{
crate_id: Number(ember.id),
crate_name: 'ember-rs',
created_at: '2020-12-31T12:34:56Z',
invited_by_username: 'wycats',
invitee_id: Number(user.id),
inviter_id: Number(inviter2.id),
},
],
users: [
{
avatar: user.avatar,
id: Number(user.id),
login: user.login,
name: user.name,
url: user.url,
},
{
avatar: 'https://avatars1.githubusercontent.com/u/14631425?v=4',
id: Number(inviter.id),
login: 'janed',
name: 'janed',
url: 'https://github.com/janed',
},
{
avatar: 'https://avatars1.githubusercontent.com/u/14631425?v=4',
id: Number(inviter2.id),
login: 'wycats',
name: 'wycats',
url: 'https://github.com/wycats',
},
],
meta: {
next_page: null,
},
});
});

test('happy path with empty response (invitee_id)', async function (assert) {
let user = this.server.create('user');
this.server.create('mirage-session', { user });

let response = await fetch(`/api/private/crate_owner_invitations?invitee_id=${user.id}`);
assert.equal(response.status, 200);
assert.deepEqual(await response.json(), {
crate_owner_invitations: [],
users: [],
meta: {
next_page: null,
},
});
});

test('happy path with pagination (invitee_id)', async function (assert) {
let inviter = this.server.create('user');

let user = this.server.create('user');
this.server.create('mirage-session', { user });

for (let i = 0; i < 15; i++) {
let crate = this.server.create('crate');
this.server.create('version', { crate });
this.server.create('crate-owner-invitation', { crate, invitee: user, inviter });
}

let response = await fetch(`/api/private/crate_owner_invitations?invitee_id=${user.id}`);
assert.equal(response.status, 200);
let responseJSON = await response.json();
assert.strictEqual(responseJSON['crate_owner_invitations'].length, 10);
assert.ok(responseJSON.meta['next_page']);

response = await fetch(`/api/private/crate_owner_invitations${responseJSON.meta['next_page']}`);
assert.equal(response.status, 200);
responseJSON = await response.json();
assert.strictEqual(responseJSON['crate_owner_invitations'].length, 5);
assert.strictEqual(responseJSON.meta['next_page'], null);
});

test('happy path (crate_name)', async function (assert) {
let nanomsg = this.server.create('crate', { name: 'nanomsg' });
this.server.create('version', { crate: nanomsg });

let ember = this.server.create('crate', { name: 'ember-rs' });
this.server.create('version', { crate: ember });

let user = this.server.create('user');
this.server.create('mirage-session', { user });

let inviter = this.server.create('user', { name: 'janed' });
this.server.create('crate-owner-invitation', {
crate: nanomsg,
createdAt: '2016-12-24T12:34:56Z',
invitee: user,
inviter,
});

let inviter2 = this.server.create('user', { name: 'wycats' });
this.server.create('crate-owner-invitation', {
crate: ember,
createdAt: '2020-12-31T12:34:56Z',
invitee: user,
inviter: inviter2,
});

let response = await fetch(`/api/private/crate_owner_invitations?crate_name=ember-rs`);
assert.equal(response.status, 200);
assert.deepEqual(await response.json(), {
crate_owner_invitations: [
{
crate_id: Number(ember.id),
crate_name: 'ember-rs',
created_at: '2020-12-31T12:34:56Z',
invited_by_username: 'wycats',
invitee_id: Number(user.id),
inviter_id: Number(inviter2.id),
},
],
users: [
{
avatar: user.avatar,
id: Number(user.id),
login: user.login,
name: user.name,
url: user.url,
},
{
avatar: 'https://avatars1.githubusercontent.com/u/14631425?v=4',
id: Number(inviter2.id),
login: 'wycats',
name: 'wycats',
url: 'https://github.com/wycats',
},
],
meta: {
next_page: null,
},
});
});

test('returns 403 if unauthenticated', async function (assert) {
let response = await fetch(`/api/private/crate_owner_invitations?invitee_id=42`);
assert.equal(response.status, 403);
assert.deepEqual(await response.json(), {
errors: [{ detail: 'must be logged in to perform that action' }],
});
});

test('returns 400 if query params are missing', async function (assert) {
let user = this.server.create('user');
this.server.create('mirage-session', { user });

let response = await fetch(`/api/private/crate_owner_invitations`);
assert.equal(response.status, 400);
assert.deepEqual(await response.json(), {
errors: [{ detail: 'missing or invalid filter' }],
});
});

test("returns 404 if crate can't be found", async function (assert) {
let user = this.server.create('user');
this.server.create('mirage-session', { user });

let response = await fetch(`/api/private/crate_owner_invitations?crate_name=foo`);
assert.equal(response.status, 404);
assert.deepEqual(await response.json(), {
errors: [{ detail: 'Not Found' }],
});
});

test('returns 403 if requesting for other user', async function (assert) {
let user = this.server.create('user');
this.server.create('mirage-session', { user });

let response = await fetch(`/api/private/crate_owner_invitations?invitee_id=${user.id + 1}`);
assert.equal(response.status, 403);
assert.deepEqual(await response.json(), {
errors: [{ detail: 'must be logged in to perform that action' }],
});
});
});

0 comments on commit 7c3ee6c

Please sign in to comment.