Files
crates/server/src/api.ts
T
2022-08-08 11:22:05 +10:00

164 lines
4.8 KiB
TypeScript

import koa from 'koa';
import bodyParser from 'koa-body';
import koaRouter from '@koa/router'
import cors from '@koa/cors';
import http from 'http';
import { groupBy } from 'lodash';
import Bluebird from 'bluebird';
import type Log from 'bunyan';
import { Pg } from './pg';
import type { Listing, User, Want, Prisma } from '@prisma/client';
export default function createApi(log: Log, pg: Pg, discogs) {
const PORT = 41337;
const app = new koa();
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
log.error(err);
ctx.status = err.statusCode || err.status || 500;
ctx.body = {
message: err.message
};
}
});
const router = koaRouter();
interface ListingData extends Listing {
data: any,
want: { user: User },
};
async function getBundles() {
const bundles = await pg.bundleCandidates();
return bundles.map((b: ListingData[]) => {
const total = b.reduce((acc, l) => acc + l.data.original_price.value, 0);
const items = b.map(l => ({
id: l.data.id,
description: l.data.release.description,
price: l.data.original_price.value,
currency: l.data.original_price.curr_abbr,
condition: l.data.condition,
uri: l.data.uri,
user: l.want.user,
}));
const shipping = b[0]?.data.seller.shipping;
const bundle = {
username: b[0]?.data.seller.username,
seller: b[0]?.data.seller.id,
shipsFrom: b[0]?.data.ships_from,
total,
currency: b[0]?.data.original_price.curr_abbr,
shipping: '...',
items,
mentionsAustralia: shipping.toLowerCase().includes('australia'),
mentionsWorldwide: shipping.toLowerCase().includes('world'),
}
log.info(bundle);
return bundle;
});
}
async function populateUserListings(user: User) {
log.info(user);
const wants = await discogs.wantlist(user);
// const latest = await discogs.wantlistLatest(user);
// if (wants.length !== latest.length)
log.info({ username: user.discogs, wantCount: wants.length });
return Bluebird.mapSeries<Want, Listing[]>(wants, async want => {
const listings = await discogs.listings(want);
const populated = listings.filter(l => l);
log.info({ id: want.id, release: want.release, populated: populated.length, total: listings.length });
return populated;
});
}
function listen() {
return new Promise((resolve, reject) => {
app.on('error', err => {
reject(err);
})
app.listen(PORT, () => {
log.info('listening', { PORT });
});
});
}
app.use(cors());
app.use(bodyParser())
router.get('/bundles', async (ctx, next) => {
const bundles = await getBundles();
const search = await discogs.searchMaster('nine inch nails', 'the fragile');
log.info(search);
ctx.response.body = bundles;
})
router.get('/user/:id/offers', async function userOffersGet(ctx, next) {
const { id } = ctx.request.params;
const user = await pg.userFindId(id);
// if (!user) return ctx.response.status = 404;
const bundles = (await getBundles())
.map(b => {
b.items = b.items.filter(i => i.user.id === user.id)
return b;
})
.filter(b => b.items.length);
ctx.response.body = bundles;
});
router.post('/user', async function usersPost(ctx, next) {
const { name } = ctx.request.body;
const user = await pg.userUpsert(null, name, null);
ctx.response.body = user;
});
router.post('/user/populate', async function usersPopulate(ctx, next) {
const { userId } = ctx.request.body;
const user = await pg.userFindId(userId);
const listings = await populateUserListings(user);
ctx.response.body = listings;
});
router.post('/want', async function wantPost(ctx, next) {
const { userId, releaseId } = ctx.request.body;
const user = await pg.userFindId(userId);
const release = await discogs.release(releaseId);
const want = await pg.wantUpsert(release, user);
ctx.response.body = want;
});
router.post('/want/search', async function wantPost(ctx, next) {
const { artist, title } = ctx.request.body;
const results = await discogs.search(artist, title);
ctx.response.body = results;
});
app.use(router.routes());
return {
app,
listen,
};
}