177 lines
5.2 KiB
TypeScript
177 lines
5.2 KiB
TypeScript
import http from 'http';
|
|
|
|
import koa from 'koa';
|
|
import bodyParser from 'koa-body';
|
|
import session from 'koa-session';
|
|
import koaRouter from '@koa/router'
|
|
import cors from '@koa/cors';
|
|
|
|
import { groupBy } from 'lodash';
|
|
import Bluebird from 'bluebird';
|
|
|
|
import type Log from 'bunyan';
|
|
import type { Listing, User, Want, Prisma } from '@prisma/client';
|
|
|
|
import { Pg } from './pg';
|
|
import routerAuth from './routers/router.auth';
|
|
|
|
export default function createApi(log: Log, pg: Pg, discogs) {
|
|
const PORT = 41337;
|
|
const SECRET = 'ohja4Eif9eidah3aj5ta2haa4iemooth';
|
|
|
|
const app = new koa();
|
|
const server = http.createServer(app.callback());
|
|
|
|
// 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'),
|
|
}
|
|
|
|
return bundle;
|
|
});
|
|
}
|
|
|
|
|
|
async function populateUserListings(user: User) {
|
|
const wants = await discogs.wantlist(user);
|
|
|
|
// const latest = await discogs.wantlistLatest(user);
|
|
// if (wants.length !== latest.length)
|
|
|
|
log.debug({ 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.debug({ 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);
|
|
})
|
|
|
|
server.listen(PORT, () => {
|
|
log.info('listening', { PORT });
|
|
});
|
|
});
|
|
}
|
|
|
|
app.use(cors({ origin: false, credentials: true }));
|
|
app.use(bodyParser())
|
|
|
|
app.keys = [SECRET];
|
|
app.use(session(app));
|
|
|
|
const { authRouter, passport } = routerAuth(log, pg);
|
|
app.use(passport.initialize());
|
|
app.use(passport.session())
|
|
app.use(authRouter.routes());
|
|
|
|
router.get('/health', async function health(ctx) {
|
|
ctx.status = 200;
|
|
});
|
|
|
|
async function requireAuth(ctx, next) {
|
|
log.warn(ctx.isAuthenticated());
|
|
await next();
|
|
}
|
|
|
|
router.get('/bundles', requireAuth, async (ctx, next) => {
|
|
const bundles = await getBundles();
|
|
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/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,
|
|
server,
|
|
listen,
|
|
};
|
|
}
|