Skip to content

Commit

Permalink
fix: refactor shop import to handle imports from different gameserver…
Browse files Browse the repository at this point in the history
…s better
  • Loading branch information
niekcandaele committed Dec 17, 2024
1 parent 4f3e6be commit 4fcc0ec
Show file tree
Hide file tree
Showing 16 changed files with 283 additions and 187 deletions.
17 changes: 16 additions & 1 deletion packages/app-api/src/controllers/Shop/Listing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
ShopListingUpdateDTO,
ShopListingCreateDTO,
ShopImportOptions,
ShopListingItemMetaOutputDTO,
ShopListingItemMetaInputDTO,
} from '../../service/Shop/dto.js';
import multer from 'multer';

Expand Down Expand Up @@ -156,7 +158,20 @@ export class ShopListingController {
const rawImportData = JSON.parse(req.body.import);
const rawOptions = JSON.parse(req.body.options);

const importData: ShopListingCreateDTO[] = rawImportData.map((item: any) => new ShopListingCreateDTO(item));
const importData: ShopListingCreateDTO[] = rawImportData.map(
(listing: any) =>
new ShopListingCreateDTO({
...listing,
items: listing.items.map(
(item: ShopListingItemMetaOutputDTO) =>
new ShopListingItemMetaInputDTO({
amount: item.amount,
quality: item.quality,
code: item.item.code,
}),
),
}),
);
const options = new ShopImportOptions(rawOptions);

await Promise.all(importData.map((item) => item.validate()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,16 @@ const shopSetup = async function (this: IntegrationTest<IShopSetup>): Promise<IS
value: 'test coin',
});

const items = (await this.client.item.itemControllerSearch({ sortBy: 'name' })).data.data;
const items = (
await this.client.item.itemControllerSearch({
sortBy: 'name',
filters: { gameserverId: [setupData.gameServer1.id] },
})
).data.data;

const listingRes = await this.client.shopListing.shopListingControllerCreate({
gameServerId: setupData.gameServer1.id,
items: [{ itemId: items[0].id, amount: 1 }],
items: [{ code: items[0].code, amount: 1 }],
price: 100,
name: 'Test item',
});
Expand Down Expand Up @@ -60,7 +65,7 @@ const tests = [
const items = (await this.client.item.itemControllerSearch({ filters: { name: ['Stone'] } })).data.data;
const res = await this.client.shopListing.shopListingControllerCreate({
gameServerId: this.setupData.gameServer1.id,
items: [{ itemId: items[0].id, amount: 1 }],
items: [{ code: items[0].code, amount: 1 }],
price: 150,
name: 'Test item',
});
Expand All @@ -80,7 +85,7 @@ const tests = [
test: async function () {
const res = await this.client.shopListing.shopListingControllerUpdate(this.setupData.listing.id, {
price: 200,
items: [{ itemId: this.setupData.items[1].id, amount: 5 }],
items: [{ code: this.setupData.items[1].code, amount: 5 }],
gameServerId: this.setupData.gameServer1.id,
name: 'Updated item',
});
Expand Down Expand Up @@ -132,7 +137,7 @@ const tests = [
test: async function () {
return this.client.shopListing.shopListingControllerCreate({
gameServerId: this.setupData.gameServer1.id,
items: [{ itemId: this.setupData.items[0].id, amount: 1 }],
items: [{ code: this.setupData.items[1].code, amount: 1 }],
price: -100,
name: 'Test item',
});
Expand All @@ -148,7 +153,7 @@ const tests = [
test: async function () {
return this.client.shopListing.shopListingControllerCreate({
gameServerId: this.setupData.gameServer1.id,
items: [{ itemId: this.setupData.items[0].id, amount: 1 }],
items: [{ code: this.setupData.items[1].code, amount: 1 }],
price: 0,
name: 'Test item',
});
Expand Down Expand Up @@ -180,7 +185,7 @@ const tests = [
Array.from({ length: listingsToMake }).map(async (_, i) => {
return this.client.shopListing.shopListingControllerCreate({
gameServerId: this.setupData.gameServer1.id,
items: [{ itemId: items[0].id, amount: 1 }],
items: [{ code: items[0].code, amount: 1 }],
price: 100 + i,
name: `Test item ${i}`,
});
Expand Down Expand Up @@ -222,6 +227,8 @@ const tests = [
expect(shop2Listings).to.have.length(shop1Listings.length);
// Check createdAt and compare to before to ensure these are new listings
expect(shop2ListingsBefore.every((l) => shop2Listings.some((l2) => l2.createdAt < l.createdAt))).to.be.true;
// Ensure there are items in the listing
expect(shop2Listings.every((l) => l.items.length > 0)).to.be.true;
},
}),
new IntegrationTest<IShopSetup>({
Expand All @@ -237,7 +244,7 @@ const tests = [
Array.from({ length: listingsToMake }).map(async (_, i) => {
return this.client.shopListing.shopListingControllerCreate({
gameServerId: this.setupData.gameServer1.id,
items: [{ itemId: items[0].id, amount: 1 }],
items: [{ code: items[0].code, amount: 1 }],
price: 100 + i,
name: `Test item ${i}`,
});
Expand Down Expand Up @@ -277,6 +284,8 @@ const tests = [
})
).data.data;
expect(shop2Listings).to.have.length(shop1Listings.length + shop2ListingsBefore.length);
// Ensure there are items in the listing
expect(shop2Listings.every((l) => l.items.length > 0)).to.be.true;
},
}),
new IntegrationTest<IShopSetup>({
Expand All @@ -292,7 +301,7 @@ const tests = [
Array.from({ length: listingsToMake }).map(async (_, i) => {
return this.client.shopListing.shopListingControllerCreate({
gameServerId: this.setupData.gameServer1.id,
items: [{ itemId: items[0].id, amount: 1 }],
items: [{ code: items[0].code, amount: 1 }],
price: 100 + i,
name: `Test item ${i}`,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,14 @@ const shopSetup = async function (this: IntegrationTest<IShopSetup>): Promise<IS

const listing100Res = await this.client.shopListing.shopListingControllerCreate({
gameServerId: setupData.gameServer1.id,
items: [{ itemId: items[0].id, amount: 1 }],
items: [{ code: items[0].code, amount: 1 }],
price: 100,
name: 'Test item',
});

const listing33Res = await this.client.shopListing.shopListingControllerCreate({
gameServerId: setupData.gameServer1.id,
items: [{ itemId: items[1].id, amount: 1 }],
items: [{ code: items[1].code, amount: 1 }],
price: 33,
name: 'Test item 2',
});
Expand Down Expand Up @@ -728,7 +728,7 @@ const tests = [
const listingGameserver1 = (
await this.client.shopListing.shopListingControllerCreate({
gameServerId: this.setupData.gameServer1.id,
items: [{ itemId: this.setupData.items[0].id, amount: 1 }],
items: [{ code: this.setupData.items[0].code, amount: 1 }],
price: 1,
name: 'Test item 1',
})
Expand All @@ -737,7 +737,7 @@ const tests = [
const listingGameserver2 = (
await this.client.shopListing.shopListingControllerCreate({
gameServerId: this.setupData.gameServer2.id,
items: [{ itemId: this.setupData.items[0].id, amount: 1 }],
items: [{ code: this.setupData.items[0].code, amount: 1 }],
price: 1,
name: 'Test item 2',
})
Expand Down Expand Up @@ -780,7 +780,7 @@ const tests = [
const listingGameserver1 = (
await this.client.shopListing.shopListingControllerCreate({
gameServerId: this.setupData.gameServer1.id,
items: [{ itemId: this.setupData.items[0].id, amount: 1 }],
items: [{ code: this.setupData.items[0].code, amount: 1 }],
price: 1,
name: 'Test item 1',
})
Expand All @@ -789,7 +789,7 @@ const tests = [
const listingGameserver2 = (
await this.client.shopListing.shopListingControllerCreate({
gameServerId: this.setupData.gameServer2.id,
items: [{ itemId: this.setupData.items[0].id, amount: 1 }],
items: [{ code: this.setupData.items[0].code, amount: 1 }],
price: 1,
name: 'Test item 2',
})
Expand Down Expand Up @@ -831,7 +831,7 @@ const tests = [
const listingGameserver1 = (
await this.client.shopListing.shopListingControllerCreate({
gameServerId: this.setupData.gameServer1.id,
items: [{ itemId: this.setupData.items[0].id, amount: 1 }],
items: [{ code: this.setupData.items[0].code, amount: 1 }],
price: 1,
name: 'Test item 1',
})
Expand All @@ -840,7 +840,7 @@ const tests = [
const listingGameserver2 = (
await this.client.shopListing.shopListingControllerCreate({
gameServerId: this.setupData.gameServer2.id,
items: [{ itemId: this.setupData.items[0].id, amount: 1 }],
items: [{ code: this.setupData.items[0].code, amount: 1 }],
price: 1,
name: 'Test item 2',
})
Expand Down
12 changes: 12 additions & 0 deletions packages/app-api/src/db/items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ export class ItemRepo extends ITakaroRepo<ItemsModel, ItemsOutputDTO, ItemCreate
query: model.query().modify('domainScoped', this.domainId),
};
}

async translateItemCodesToIds(gameserverId: string, codes: string[]): Promise<ItemsOutputDTO[]> {
const { query } = await this.getModel();
const data = await query.whereIn('code', codes).andWhere('gameserverId', gameserverId);

if (!data) {
throw new errors.NotFoundError();
}

return Promise.all(data.map((item) => new ItemsOutputDTO(item)));
}

async find(filters: ITakaroQuery<ItemsOutputDTO>) {
const { query } = await this.getModel();

Expand Down
44 changes: 31 additions & 13 deletions packages/app-api/src/db/shopListing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ITakaroQuery, QueryBuilder, TakaroModel } from '@takaro/db';
import { Model } from 'objection';
import { errors, traceableClass } from '@takaro/util';
import { GameServerModel } from './gameserver.js';
import { ItemsModel } from './items.js';
import { ItemRepo, ItemsModel } from './items.js';
import { RoleModel } from './role.js';
import { ITakaroRepo } from './base.js';
import { ShopListingOutputDTO, ShopListingUpdateDTO, ShopListingCreateDTO } from '../service/Shop/dto.js';
Expand Down Expand Up @@ -158,12 +158,21 @@ export class ShopListingRepo extends ITakaroRepo<

if (!item.items || !item.items.length) throw new errors.BadRequestError('At least one item is required');

const itemMetas = item.items.map((i) => ({
listingId: listing.id,
itemId: i.itemId,
amount: i.amount,
quality: i.quality,
}));
const itemRepo = new ItemRepo(this.domainId);
const items = await itemRepo.translateItemCodesToIds(
item.gameServerId,
item.items.map((i) => i.code).filter((code): code is string => code !== undefined),
);
const itemMetas = item.items
.map((i) => ({
listingId: listing.id,
itemId: items.find((item) => item.code === i.code)?.id || i.itemId,
amount: i.amount,
quality: i.quality,
}))
.filter((i) => i.itemId);

if (!itemMetas.length) throw new errors.BadRequestError('No valid items found');

await Promise.all(
itemMetas.map(async (i) => {
Expand Down Expand Up @@ -205,12 +214,21 @@ export class ShopListingRepo extends ITakaroRepo<
const res = await query.updateAndFetchById(id, data.toJSON()).returning('*');

if (data.items) {
const itemMetas = data.items.map((i) => ({
listingId: id,
itemId: i.itemId,
amount: i.amount,
quality: i.quality,
}));
const itemRepo = new ItemRepo(this.domainId);
const items = await itemRepo.translateItemCodesToIds(
data.gameServerId,
data.items.map((i) => i.code).filter((code): code is string => code !== undefined),
);
const itemMetas = data.items
.map((i) => {
return {
listingId: id,
itemId: items.find((item) => item.code === i.code)?.id || i.itemId,
amount: i.amount,
quality: i.quality,
};
})
.filter((i) => i.itemId);

await ItemOnShopListingModel.bindKnex(knex).query().delete().where('listingId', id);

Expand Down
8 changes: 6 additions & 2 deletions packages/app-api/src/service/Shop/dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { TakaroModelDTO, TakaroDTO } from '@takaro/util';
import { Type } from 'class-transformer';
import { ItemsOutputDTO } from '../ItemsService.js';

class ShopListingItemMetaOutputDTO extends TakaroModelDTO<ShopListingItemMetaOutputDTO> {
export class ShopListingItemMetaOutputDTO extends TakaroModelDTO<ShopListingItemMetaOutputDTO> {
@IsNumber()
amount: number;
@IsString()
Expand All @@ -30,8 +30,12 @@ export class ShopListingItemMetaInputDTO extends TakaroDTO<ShopListingItemMetaIn
@IsString()
@IsOptional()
quality?: string;
@IsString()
@IsOptional()
code?: string;
@IsUUID('4')
itemId: string;
@IsOptional()
itemId?: string;
}

export class ShopListingOutputDTO extends TakaroModelDTO<ShopListingOutputDTO> {
Expand Down
34 changes: 28 additions & 6 deletions packages/app-api/src/service/Shop/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
ShopOrderStatus,
ShopOrderCreateInternalDTO,
ShopImportOptions,
ShopListingItemMetaInputDTO,
} from './dto.js';
import { UserService } from '../User/index.js';
import { checkPermissions } from '../AuthService.js';
Expand All @@ -29,6 +30,7 @@ import {
TakaroEventShopOrderStatusChanged,
} from '@takaro/modules';
import { IMessageOptsDTO, IPlayerReferenceDTO } from '@takaro/gameserver';
import { ItemsService } from '../ItemsService.js';

@traceableClass('service:shopListing')
export class ShopListingService extends TakaroService<
Expand Down Expand Up @@ -93,8 +95,28 @@ export class ShopListingService extends TakaroService<
return listing;
}

async create(item: ShopListingCreateDTO): Promise<ShopListingOutputDTO> {
const created = await this.repo.create(item);
async create(listing: ShopListingCreateDTO): Promise<ShopListingOutputDTO> {
const itemCodes = listing.items.map((item) => item.code).filter(Boolean);
const itemsService = new ItemsService(this.domainId);
const items = await itemsService.find({ filters: { code: itemCodes } });
listing.items = listing.items.map((item) => {
const code = items.results.find((i) => i.code === item.code);
if (!code) {
if (!item.itemId)
throw new errors.BadRequestError(`Item with code ${item.code} not found and no itemId provided`);
return new ShopListingItemMetaInputDTO({
amount: item.amount,
quality: item.quality,
itemId: item.itemId,
});
}
return new ShopListingItemMetaInputDTO({
amount: item.amount,
quality: item.quality,
code: item.code,
});
});
const created = await this.repo.create(listing);

await this.eventService.create(
new EventCreateDTO({
Expand Down Expand Up @@ -344,10 +366,10 @@ export class ShopListingService extends TakaroService<
}

const promises = await Promise.allSettled(
data.map((item) => {
item.draft = options.draft;
item.gameServerId = options.gameServerId;
return this.create(item);
data.map((listing) => {
listing.draft = options.draft;
listing.gameServerId = options.gameServerId;
return this.create(listing);
}),
);

Expand Down
Loading

0 comments on commit 4fcc0ec

Please sign in to comment.