Skip to content

Commit

Permalink
feat: add logic to fetch banned names before returning them
Browse files Browse the repository at this point in the history
  • Loading branch information
juanmahidalgo committed Sep 4, 2023
1 parent 94d2214 commit f830df3
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 3 deletions.
1 change: 1 addition & 0 deletions .env.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ SIGNATURES_SERVER_URL=
MARKETPLACE_CHAIN_ID=1
COLLECTIONS_CHAIN_ID=137
MIN_SALE_VALUE_IN_WEI=
DCL_LISTS_SERVER=https://dcl-lists.decentraland.org
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ async function initComponents(): Promise<AppComponents> {
// nfts
const marketplaceNFTs = createNFTComponent({
subgraph: marketplaceSubgraph,
listsServer: await config.requireString('DCL_LISTS_SERVER'),
fragmentName: 'marketplaceFragment',
getFragment: getMarketplaceFragment,
fromFragment: fromMarketplaceNFTFragment,
Expand Down
22 changes: 20 additions & 2 deletions src/ports/nfts/component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { NFTFilters, NFTSortBy } from '@dcl/schemas'
import nodeFetch from 'node-fetch'
import { NFTCategory, NFTFilters, NFTSortBy } from '@dcl/schemas'
import { ISubgraphComponent } from '@well-known-components/thegraph-component'
import { INFTsComponent, NFTResult } from './types'
import {
Expand All @@ -10,6 +11,7 @@ import {

export function createNFTComponent<T extends { id: string }>(options: {
subgraph: ISubgraphComponent
listsServer?: string
fragmentName: string
getFragment: () => string
fromFragment(fragment: T, caller?: string): NFTResult
Expand All @@ -27,6 +29,7 @@ export function createNFTComponent<T extends { id: string }>(options: {
getExtraVariables,
fromFragment,
getShouldFetch,
listsServer,
} = options

function getFragmentFetcher(filters: NFTFilters & { caller?: string }) {
Expand All @@ -37,7 +40,8 @@ export function createNFTComponent<T extends { id: string }>(options: {
getFragment,
getExtraVariables,
getExtraWhere,
isCount
isCount,
filters.category === NFTCategory.ENS ? await getBannedNames() : []
)
const variables = getQueryVariables(filters, getSortByProp)
const { nfts: fragments } = await subgraph.query<{
Expand All @@ -47,6 +51,20 @@ export function createNFTComponent<T extends { id: string }>(options: {
}
}

async function getBannedNames() {
try {
const bannedNames = await nodeFetch(`${listsServer}/banned-names`, {
method: 'POST',
})

const data: { data: string[] } = await bannedNames.json()
return data.data
} catch (error) {
// if there was an error fetching the lists server, return an empty array
return []
}
}

async function fetch(
options: NFTFilters & { caller?: string }
): Promise<NFTResult[]> {
Expand Down
20 changes: 20 additions & 0 deletions src/ports/nfts/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@ import { EmotePlayMode, GenderFilterOption, NFTCategory } from '@dcl/schemas'
import { getFetchQuery } from './utils'

describe('#getFetchQuery', () => {
let bannedNames = ['aBannedName']
describe('when the array of banned list is passed', () => {
fit('should add the name_not_in filter to the query', () => {
expect(
getFetchQuery(
{},
'',
() => '',
undefined,
undefined,
false,
bannedNames
)
).toEqual(
expect.stringContaining(
`name_not_in: [${bannedNames.map((name) => `"${name}"`).join(', ')}]`
)
)
})
})
describe('when emotePlayMode is defined', () => {
describe('and it only has one property', () => {
it('should add loop as true to the query for LOOP mode', () => {
Expand Down
9 changes: 8 additions & 1 deletion src/ports/nfts/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,18 @@ export function getFetchQuery(
getNFTFragment: () => string,
getExtraVariables?: (options: NFTFilters) => string[],
getExtraWhere?: (options: NFTFilters) => string[],
isCount = false
isCount = false,
bannedNames: string[] = []
) {
const where: string[] = []
let wrapWhere = false

if (bannedNames.length) {
where.push(
`name_not_in: [${bannedNames.map((name) => `"${name}"`).join(', ')}]`
)
}

if (filters.owner) {
where.push('owner: $owner')
}
Expand Down
82 changes: 82 additions & 0 deletions src/tests/ports/nfts.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as nodeFetch from 'node-fetch'
import {
BodyShape,
EmoteCategory,
Expand Down Expand Up @@ -27,6 +28,8 @@ import { INFTsComponent } from '../../ports/nfts/types'
import { FragmentItemType } from '../../ports/items/types'
import { getFetchQuery, getQueryVariables } from '../../ports/nfts/utils'

jest.mock('node-fetch')

let marketplaceSubgraphMock: ISubgraphComponent
let collectionSubgraphMock: ISubgraphComponent
let queryMock: jest.Mock
Expand Down Expand Up @@ -229,3 +232,82 @@ describe('when fetching emotes', () => {
})
})
})

describe('when fetching nfts', () => {
let nftFragments: CollectionsFragment[]
let filters: NFTFilters = {
category: NFTCategory.EMOTE,
}

beforeEach(() => {
const contractAddress = `0x0`
nftFragments = Array.from({ length: 2 }, (_, i) => ({
id: `${contractAddress}-${i}`,
itemType: FragmentItemType.EMOTE_V1,
image: `https://peer.decentraland.zone/lambdas/collections/contents/urn:decentraland:mumbai:collections-v2:${contractAddress}:${i}/thumbnail`,
contractAddress,
tokenId: i.toString(),
owner: { address: '0x0' },
metadata: {
wearable: null,
emote: {
name: 'emote',
description: '',
category: EmoteCategory.DANCE,
rarity: Rarity.COMMON,
bodyShapes: [BodyShape.MALE, BodyShape.FEMALE],
loop: false,
},
},
createdAt: Date.now().toString(),
updatedAt: Date.now().toString(),
soldAt: '',
searchOrderPrice: null,
searchOrderCreatedAt: null,
itemBlockchainId: i.toString(),
issuedId: i.toString(),
activeOrder: null,
openRentalId: null,
urn: `urn:decentraland:mumbai:collections-v2:${contractAddress}:${i}`,
}))
})

describe('and fetching ENS', () => {
let bannedNames: string[]
beforeEach(() => {
bannedNames = ['bannedName1', 'bannedName1']
const mockedResponse = {
json: async () => ({
data: bannedNames,
}),
}

;(nodeFetch as unknown as jest.Mock).mockResolvedValue(mockedResponse)

filters = {
...filters,
category: NFTCategory.ENS,
}
queryMock.mockResolvedValue({ nfts: nftFragments })
})

it('should fetch the banned names and filter the query based on them', async () => {
const fetchQuery = getFetchQuery(
filters,
collectionsFragment,
getCollectionsFragment,
getCollectionsExtraVariables,
getCollectionsExtraWhere,
false,
bannedNames
)
const variableQuery = getQueryVariables(filters, getCollectionsOrderBy)
const result = await collectionsNFTsMock.fetch(filters)
expect(result).toEqual(
nftFragments.map((f) => fromCollectionsFragment(f))
)
expect(nodeFetch).toHaveBeenCalled()
return expect(queryMock).toBeCalledWith(fetchQuery, variableQuery)
})
})
})

0 comments on commit f830df3

Please sign in to comment.