acp stuff
This commit is contained in:
1 parent
deb9eb3fc2
commit
047f606e83
14 files changed
+368
-44
No files matched your search
+2
-2
@@ -51,8 +51,8 @@ describe('api', function apiTests() {
|
||||
describe('offers', function offerTests() {
|
||||
it('create offers', async function createOffersTest() {
|
||||
const { data: bundles } = await api.get('/bundles');
|
||||
const { seller } = bundles[0];
|
||||
const { data } = await api.post('/offers', { seller, shipping: 50.0, baseShipping: 15.0 });
|
||||
const listingIds = bundles[0].items.map(i => i.id);
|
||||
const { data } = await api.post('/offers', { listingIds, shipping: 50.0, baseShipping: 15.0 });
|
||||
});
|
||||
});
|
||||
});
|
||||
+37
-5
@@ -6,7 +6,7 @@ import session from 'koa-session';
|
||||
import koaRouter from '@koa/router'
|
||||
import cors from '@koa/cors';
|
||||
|
||||
import { groupBy } from 'lodash';
|
||||
import { groupBy, sortBy } from 'lodash';
|
||||
import Bluebird from 'bluebird';
|
||||
|
||||
import type Log from 'bunyan';
|
||||
@@ -104,14 +104,46 @@ export default function createApi(log: Log, pg: Pg, discogs, offers, events) {
|
||||
ctx.status = 200;
|
||||
});
|
||||
|
||||
router.get('/bundles', async (ctx, next) => {
|
||||
router.get('/acp/bundles', async function bundlesGet(ctx, next) {
|
||||
const bundles = await getBundles();
|
||||
ctx.response.body = bundles;
|
||||
})
|
||||
|
||||
router.post('/offers', async (ctx, next) => {
|
||||
const { seller, shipping, baseShipping } = ctx.request.body;
|
||||
ctx.response.body = await offers.generate(seller, shipping, baseShipping);
|
||||
router.get('/acp/offers', async function acpOffers(ctx, next) {
|
||||
const offers = await pg.offersAdmin();
|
||||
|
||||
const grouped = groupBy(offers, o => o.listing.data.seller.id);
|
||||
|
||||
const bundles = sortBy(Object.values(grouped).map(offers => {
|
||||
const shipping = offers[0]?.listing.data.seller.shipping;
|
||||
const bundle = {
|
||||
username: offers[0]?.listing.data.seller.username,
|
||||
seller: offers[0]?.listing.data.seller.id,
|
||||
shipsFrom: offers[0]?.listing.data.ships_from,
|
||||
shipping,
|
||||
offers,
|
||||
mentionsAustralia: shipping.toLowerCase().includes('australia'),
|
||||
mentionsWorldwide: shipping.toLowerCase().includes('world'),
|
||||
}
|
||||
|
||||
return bundle;
|
||||
}), bundle => -bundle.offers.length);
|
||||
|
||||
ctx.response.body = bundles;
|
||||
})
|
||||
|
||||
router.post('/offers', async function postOffers(ctx, next) {
|
||||
const { listingIds, shipping, baseShipping } = ctx.request.body;
|
||||
|
||||
ctx.assert(listingIds.length, 400, 'listingIds required');
|
||||
ctx.assert([listingIds, shipping, baseShipping].every(i => i), 400, 'listingIds, shipping, baseShipping required');
|
||||
|
||||
ctx.response.body = await offers.generate(listingIds, shipping, baseShipping);
|
||||
})
|
||||
|
||||
router.post('/offer/accept', async function postOffers(ctx, next) {
|
||||
ctx.assert(ctx.isAuthenticated(), 401, 'log in required');
|
||||
ctx.response.body = await offers.accept(ctx);
|
||||
})
|
||||
|
||||
router.get('/user/offers', async function userOffersGet(ctx, next) {
|
||||
|
||||
+20
-5
@@ -2,6 +2,7 @@ import type Log from 'bunyan';
|
||||
import type { PrismaClient, Want, User, Listing, Offer, } from '@prisma/client';
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import sortBy from 'lodash/sortBy';
|
||||
import { Context } from 'koa';
|
||||
|
||||
import { logAxiosError } from './utils';
|
||||
import { Pg } from './pg';
|
||||
@@ -14,18 +15,22 @@ export enum Status {
|
||||
}
|
||||
|
||||
export default function createOffers(log: Log, pg: Pg) {
|
||||
async function generate(seller: number, bulkShipping: number, baseShipping: number): Offer[] {
|
||||
log.info('generateOffers', { seller, bulkShipping, baseShipping });
|
||||
const listings = await pg.listingFindSeller(seller);
|
||||
async function generate(listingIds: DiscogsListing[], bulkShipping: number, baseShipping: number) {
|
||||
log.info('generateOffers', { listingIds, bulkShipping, baseShipping });
|
||||
const listings = await pg.listingByIds(listingIds);
|
||||
|
||||
log.info('creating offers for listings', { listings })
|
||||
log.info({ listings }, 'creating offers for listings')
|
||||
|
||||
const shipping = bulkShipping / listings.length;
|
||||
// how to deal with users who don't want all items in a bundle...
|
||||
|
||||
const offers = listings.map(l => ({
|
||||
userId: l.want.user.id,
|
||||
listingId: l.id,
|
||||
wantId: l.want.id,
|
||||
|
||||
// sellerId: l.seller,
|
||||
|
||||
status: Status.Pending,
|
||||
|
||||
item: l.data.price.value,
|
||||
@@ -42,11 +47,21 @@ export default function createOffers(log: Log, pg: Pg) {
|
||||
// and ensure the cheapest one goes in first
|
||||
const sorted = sortBy(offers, ['item']);
|
||||
const inserts = await pg.offersCreate(sorted);
|
||||
console.log(inserts);
|
||||
|
||||
return inserts;
|
||||
}
|
||||
|
||||
async function accept(ctx: Context) {
|
||||
const { id } = ctx.request.body;
|
||||
ctx.assert(id, 401, 'no id supplied');
|
||||
|
||||
// check the user actually has this offer
|
||||
const offer = await pg.userOfferFind(ctx.state.user, id);
|
||||
return pg.offerSetStatus(offer.id, Status.Accepted);
|
||||
}
|
||||
|
||||
return {
|
||||
generate,
|
||||
accept,
|
||||
};
|
||||
}
|
||||
+45
-4
@@ -3,6 +3,8 @@ import type Log from 'bunyan';
|
||||
import type { PrismaClient, Want, User, Listing, Offer, Prisma } from '@prisma/client';
|
||||
import * as Bluebird from 'bluebird';
|
||||
|
||||
import { Status } from './offers';
|
||||
|
||||
export interface UserCreateParams {
|
||||
email: string,
|
||||
password: string,
|
||||
@@ -14,10 +16,11 @@ export interface Pg {
|
||||
userCreate: (params: UserCreateParams) => Promise<User>,
|
||||
userWants: (user: User) => Promise<Want[]>,
|
||||
userOffers: (user: User) => Promise<Offer[]>,
|
||||
userOfferFind: (user: User, id: UUID) => Promise<Offer>,
|
||||
|
||||
listingUpsert: (listing: Listing, want: Want) => Promise<Listing>,
|
||||
listingFind: (id: DiscogsListing) => Promise<Listing>,
|
||||
listingFindSeller: (id: DiscogsSeller) => Promise<Listing[]>,
|
||||
listingByIds: (ids: DiscogsListing[]) => Promise<Listing[]>,
|
||||
listingRmUnlisted: (want: Want, ids: DiscogsListing[]) => Promise<number>,
|
||||
|
||||
wantCreate: (discogsWant: any, user: User) => Promise<Want>,
|
||||
@@ -27,6 +30,8 @@ export interface Pg {
|
||||
bundleCandidates: () => Promise<Listing[][]>,
|
||||
|
||||
offersCreate: (offers: Offer[]) => Promise<Offer[]>,
|
||||
offerSetStatus: (id: UUID, status: Status) => Promise<Offer>,
|
||||
offersAdmin: () => Promise<Offer[]>,
|
||||
}
|
||||
|
||||
export default function createPg(log: Log, prisma: PrismaClient): Pg {
|
||||
@@ -45,6 +50,21 @@ export default function createPg(log: Log, prisma: PrismaClient): Pg {
|
||||
async function userOffers(user: User) {
|
||||
return prisma.offer.findMany({
|
||||
where: { userId: user.id },
|
||||
include: {
|
||||
want: true,
|
||||
},
|
||||
orderBy: {
|
||||
status: 'desc',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function userOfferFind(user: User, id: UUID) {
|
||||
return prisma.offer.findFirstOrThrow({
|
||||
where: {
|
||||
userId: user.id,
|
||||
id,
|
||||
},
|
||||
include: {
|
||||
want: true,
|
||||
}
|
||||
@@ -145,10 +165,10 @@ export default function createPg(log: Log, prisma: PrismaClient): Pg {
|
||||
});
|
||||
}
|
||||
|
||||
async function listingFindSeller(seller: DiscogsSeller): Promise<Listing[]> {
|
||||
async function listingByIds(ids: DiscogsListing[]) {
|
||||
return prisma.listing.findMany({
|
||||
where: {
|
||||
seller,
|
||||
id: { in: ids },
|
||||
},
|
||||
include: {
|
||||
want: {
|
||||
@@ -199,12 +219,30 @@ export default function createPg(log: Log, prisma: PrismaClient): Pg {
|
||||
);
|
||||
}
|
||||
|
||||
async function offerSetStatus(id: UUID, status: Status) {
|
||||
return prisma.offer.update({
|
||||
where: { id: id },
|
||||
data: { status },
|
||||
});
|
||||
}
|
||||
|
||||
async function offersAdmin() {
|
||||
return prisma.offer.findMany({
|
||||
include: {
|
||||
listing: true,
|
||||
user: true,
|
||||
want: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
userFindId,
|
||||
userFindEmail,
|
||||
userCreate,
|
||||
userWants,
|
||||
userOffers,
|
||||
userOfferFind,
|
||||
|
||||
wantCreate,
|
||||
wantList,
|
||||
@@ -212,9 +250,12 @@ export default function createPg(log: Log, prisma: PrismaClient): Pg {
|
||||
listingUpsert,
|
||||
listingFind,
|
||||
listingRmUnlisted,
|
||||
listingFindSeller,
|
||||
listingByIds,
|
||||
|
||||
bundleCandidates,
|
||||
|
||||
offersCreate,
|
||||
offerSetStatus,
|
||||
offersAdmin,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user