diff --git a/src/Collection/Collection.model.ts b/src/Collection/Collection.model.ts index 9cc7027e..ea5509d3 100644 --- a/src/Collection/Collection.model.ts +++ b/src/Collection/Collection.model.ts @@ -110,7 +110,7 @@ export class Collection extends Model { const isInRemoteIds = SQL`collections.contract_address = ANY(${remoteIds})` const sameStatusAndInTheBlockchain = SQL`(collection_curations.status = ${status} AND (${isInRemoteIds} OR (${isThirdParty})))` const conditions = [ - q ? SQL`collections.name % ${q} ` : undefined, + q ? SQL`collections.name ILIKE '%' || ${q} || '%'` : undefined, assignee ? SQL`collection_curations.assignee = ${assignee}` : undefined, address ? thirdPartyIds?.length diff --git a/src/Collection/Collection.router.spec.ts b/src/Collection/Collection.router.spec.ts index 8e131d1b..e05450f2 100644 --- a/src/Collection/Collection.router.spec.ts +++ b/src/Collection/Collection.router.spec.ts @@ -828,466 +828,222 @@ describe('Collection router', () => { }) describe('when retrieving all the collections', () => { - describe('and its not a committee member and is not sending the query params "q" and "isPublished', () => { + beforeEach(() => { + ;(isCommitteeMember as jest.Mock).mockResolvedValueOnce(true) + ;(Collection.findByContractAddresses as jest.Mock).mockResolvedValueOnce( + [] + ) + ;(collectionAPI.fetchCollections as jest.Mock).mockResolvedValueOnce([]) + thirdPartyAPIMock.fetchThirdParties.mockResolvedValueOnce([]) + }) + + describe('and sending pagination params', () => { + let page: number, limit: number let baseUrl: string + let totalCollectionsFromDb: number beforeEach(() => { - ;(isCommitteeMember as jest.Mock).mockResolvedValueOnce(false) - url = '/collections' + ;(page = 1), (limit = 3) + totalCollectionsFromDb = 1 + baseUrl = '/collections' + url = `${baseUrl}?limit=${limit}&page=${page}` + ;(Collection.findAll as jest.Mock).mockResolvedValueOnce([ + { ...dbCollection, collection_count: totalCollectionsFromDb }, + ]) }) - it('should return a 401 and a message saying that the user is not authorized', () => { + it('should respond with pagination data and should have call the findAll method with the params', () => { return server .get(buildURL(url)) .set(createAuthHeaders('get', baseUrl)) - .expect(401) + .expect(200) .then((response: any) => { expect(response.body).toEqual({ - error: 'Unauthorized', - data: { eth_address: '' }, - ok: false, + data: { + total: totalCollectionsFromDb, + pages: totalCollectionsFromDb, + page, + limit, + results: [ + { + ...resultingCollectionAttributes, + urn: `urn:decentraland:mumbai:collections-v2:${dbCollection.contract_address}`, + }, + ], + }, + + ok: true, + }) + expect(Collection.findAll).toHaveBeenCalledWith({ + assignee: undefined, + isPublished: undefined, + q: undefined, + sort: undefined, + status: undefined, + type: undefined, + limit, + offset: page - 1, // it's the offset, + thirdPartyIds: [], + remoteIds: [], }) }) }) }) - describe('and its not a committee member but the request has the params "q" for a search term and "isPublished"', () => { - let q: string - let isPublished: boolean + describe('and sending pagination params plus filtering options', () => { + let page: number, + limit: number, + baseUrl: string, + totalCollectionsFromDb: number, + q: string, + assignee: string, + status: string, + type: string, + sort: string, + isPublished: string beforeEach(() => { - ;(isCommitteeMember as jest.Mock).mockResolvedValueOnce(false) - ;(Collection.findByContractAddresses as jest.Mock).mockResolvedValueOnce( - [] - ) - ;(collectionAPI.fetchCollections as jest.Mock).mockResolvedValueOnce([]) - thirdPartyAPIMock.fetchThirdParties.mockResolvedValueOnce([]) - }) - describe('and sending pagination params', () => { - let page: number, limit: number - let baseUrl: string - let totalCollectionsFromDb: number - beforeEach(() => { - ;(page = 1), (limit = 3), (q = 'searchTerm'), (isPublished = true) - totalCollectionsFromDb = 1 - baseUrl = '/collections' - url = `${baseUrl}?limit=${limit}&page=${page}&q=${q}&is_published=${isPublished}` - ;(Collection.findAll as jest.Mock).mockResolvedValueOnce([ - { ...dbCollection, collection_count: totalCollectionsFromDb }, - ]) - }) - it('should respond with pagination data and should have call the findAll method with the params', () => { - return server - .get(buildURL(url)) - .set(createAuthHeaders('get', baseUrl)) - .expect(200) - .then((response: any) => { - expect(response.body).toEqual({ - data: { - total: totalCollectionsFromDb, - pages: totalCollectionsFromDb, - page, - limit, - results: [ - { - ...resultingCollectionAttributes, - urn: `urn:decentraland:mumbai:collections-v2:${dbCollection.contract_address}`, - }, - ], - }, - - ok: true, - }) - expect(Collection.findAll).toHaveBeenCalledWith({ - assignee: undefined, - isPublished, - q, - sort: undefined, - status: undefined, - type: undefined, - limit, - offset: page - 1, // it's the offset, - thirdPartyIds: [], - remoteIds: [], - }) - }) - }) - }) - - describe('and sending pagination params plus filtering options', () => { - let page: number, - limit: number, - baseUrl: string, - totalCollectionsFromDb: number, - q: string, - assignee: string, - status: string, - type: string, - sort: string, - isPublished: string - beforeEach(() => { - ;(page = 1), (limit = 3) - assignee = '0x1234567890123456789012345678901234567890' - status = 'published' - type = 'standard' - sort = 'NAME_DESC' - isPublished = 'true' - q = 'collection name 1' - totalCollectionsFromDb = 1 - baseUrl = '/collections' - url = `${baseUrl}?limit=${limit}&page=${page}&assignee=${assignee}&status=${status}&type=${type}&sort=${sort}&is_published=${isPublished}&q=${q}` - ;(Collection.findAll as jest.Mock).mockResolvedValueOnce([ - { ...dbCollection, collection_count: totalCollectionsFromDb }, - ]) - }) - it('should respond with pagination data and should have call the findAll method with the right params', () => { - return server - .get(buildURL(url)) - .set(createAuthHeaders('get', baseUrl)) - .expect(200) - .then((response: any) => { - expect(response.body).toEqual({ - data: { - total: totalCollectionsFromDb, - pages: totalCollectionsFromDb, - page, - limit, - results: [ - { - ...resultingCollectionAttributes, - urn: `urn:decentraland:mumbai:collections-v2:${dbCollection.contract_address}`, - }, - ], - }, - - ok: true, - }) - expect(Collection.findAll).toHaveBeenCalledWith({ - q, - assignee, - status, - type, - sort, - isPublished: true, - offset: page - 1, // it's the offset - limit, - thirdPartyIds: [], - remoteIds: [], - itemTags: undefined, - }) - }) - }) + ;(page = 1), (limit = 3) + assignee = '0x1234567890123456789012345678901234567890' + status = 'published' + type = 'standard' + sort = 'NAME_DESC' + isPublished = 'true' + q = 'collection name 1' + totalCollectionsFromDb = 1 + baseUrl = '/collections' + url = `${baseUrl}?limit=${limit}&page=${page}&assignee=${assignee}&status=${status}&type=${type}&sort=${sort}&is_published=${isPublished}&q=${q}` + ;(Collection.findAll as jest.Mock).mockResolvedValueOnce([ + { ...dbCollection, collection_count: totalCollectionsFromDb }, + ]) }) - - describe('and sending pagination params plus filtering with array tag options', () => { - let page: number, - limit: number, - baseUrl: string, - totalCollectionsFromDb: number, - q: string, - assignee: string, - status: string, - type: string, - sort: string, - isPublished: string, - itemTag: string, - itemTag2: string - beforeEach(() => { - ;(page = 1), (limit = 3) - assignee = '0x1234567890123456789012345678901234567890' - status = 'published' - type = 'standard' - sort = 'NAME_DESC' - isPublished = 'true' - q = 'collection name 1' - itemTag = 'TAG' - itemTag2 = 'TAG2' - totalCollectionsFromDb = 1 - baseUrl = '/collections' - url = `${baseUrl}?limit=${limit}&page=${page}&assignee=${assignee}&status=${status}&type=${type}&sort=${sort}&is_published=${isPublished}&q=${q}&tag=${itemTag}&tag=${itemTag2}` - ;(Collection.findAll as jest.Mock).mockResolvedValueOnce([ - { ...dbCollection, collection_count: totalCollectionsFromDb }, - ]) - }) - it('should respond with pagination data and should have call the findAll method with the right params', () => { - return server - .get(buildURL(url)) - .set(createAuthHeaders('get', baseUrl)) - .expect(200) - .then((response: any) => { - expect(response.body).toEqual({ - data: { - total: totalCollectionsFromDb, - pages: totalCollectionsFromDb, - page, - limit, - results: [ - { - ...resultingCollectionAttributes, - urn: `urn:decentraland:mumbai:collections-v2:${dbCollection.contract_address}`, - }, - ], - }, - ok: true, - }) - expect(Collection.findAll).toHaveBeenCalledWith({ - q, - assignee, - status, - type, - sort, - isPublished: true, - offset: page - 1, // it's the offset + it('should respond with pagination data and should have call the findAll method with the right params', () => { + return server + .get(buildURL(url)) + .set(createAuthHeaders('get', baseUrl)) + .expect(200) + .then((response: any) => { + expect(response.body).toEqual({ + data: { + total: totalCollectionsFromDb, + pages: totalCollectionsFromDb, + page, limit, - thirdPartyIds: [], - remoteIds: [], - itemTags: [itemTag.toLowerCase(), itemTag2.toLowerCase()], - }) - }) - }) - }) - - describe('and not sending any pagination params ', () => { - beforeEach(() => { - url = `/collections?q=${q}&is_published=${isPublished}` - ;(Collection.findAll as jest.Mock) - .mockResolvedValueOnce([dbCollection]) - .mockResolvedValueOnce([]) - }) - it('should respond with all the collections with the URN and the legacy response', () => { - return server - .get(buildURL(url)) - .set(createAuthHeaders('get', url)) - .expect(200) - .then((response: any) => { - expect(response.body).toEqual({ - data: [ + results: [ { ...resultingCollectionAttributes, urn: `urn:decentraland:mumbai:collections-v2:${dbCollection.contract_address}`, }, ], - ok: true, - }) + }, + + ok: true, }) - }) + expect(Collection.findAll).toHaveBeenCalledWith({ + q, + assignee, + status, + type, + sort, + isPublished: true, + offset: page - 1, // it's the offset + limit, + thirdPartyIds: [], + remoteIds: [], + itemTags: undefined, + }) + }) }) }) - describe('and its a request from a committee member', () => { + describe('and sending pagination params plus filtering with array tag options', () => { + let page: number, + limit: number, + baseUrl: string, + totalCollectionsFromDb: number, + q: string, + assignee: string, + status: string, + type: string, + sort: string, + isPublished: string, + itemTag: string, + itemTag2: string beforeEach(() => { - ;(isCommitteeMember as jest.Mock).mockResolvedValueOnce(true) - ;(Collection.findByContractAddresses as jest.Mock).mockResolvedValueOnce( - [] - ) - ;(collectionAPI.fetchCollections as jest.Mock).mockResolvedValueOnce([]) - thirdPartyAPIMock.fetchThirdParties.mockResolvedValueOnce([]) - }) - describe('and sending pagination params', () => { - let page: number, limit: number - let baseUrl: string - let totalCollectionsFromDb: number - beforeEach(() => { - ;(page = 1), (limit = 3) - totalCollectionsFromDb = 1 - baseUrl = '/collections' - url = `${baseUrl}?limit=${limit}&page=${page}` - ;(Collection.findAll as jest.Mock).mockResolvedValueOnce([ - { ...dbCollection, collection_count: totalCollectionsFromDb }, - ]) - }) - it('should respond with pagination data and should have call the findAll method with the params', () => { - return server - .get(buildURL(url)) - .set(createAuthHeaders('get', baseUrl)) - .expect(200) - .then((response: any) => { - expect(response.body).toEqual({ - data: { - total: totalCollectionsFromDb, - pages: totalCollectionsFromDb, - page, - limit, - results: [ - { - ...resultingCollectionAttributes, - urn: `urn:decentraland:mumbai:collections-v2:${dbCollection.contract_address}`, - }, - ], - }, - - ok: true, - }) - expect(Collection.findAll).toHaveBeenCalledWith({ - assignee: undefined, - isPublished: undefined, - q: undefined, - sort: undefined, - status: undefined, - type: undefined, - limit, - offset: page - 1, // it's the offset, - thirdPartyIds: [], - remoteIds: [], - }) - }) - }) - }) - - describe('and sending pagination params plus filtering options', () => { - let page: number, - limit: number, - baseUrl: string, - totalCollectionsFromDb: number, - q: string, - assignee: string, - status: string, - type: string, - sort: string, - isPublished: string - beforeEach(() => { - ;(page = 1), (limit = 3) - assignee = '0x1234567890123456789012345678901234567890' - status = 'published' - type = 'standard' - sort = 'NAME_DESC' - isPublished = 'true' - q = 'collection name 1' - totalCollectionsFromDb = 1 - baseUrl = '/collections' - url = `${baseUrl}?limit=${limit}&page=${page}&assignee=${assignee}&status=${status}&type=${type}&sort=${sort}&is_published=${isPublished}&q=${q}` - ;(Collection.findAll as jest.Mock).mockResolvedValueOnce([ - { ...dbCollection, collection_count: totalCollectionsFromDb }, - ]) - }) - it('should respond with pagination data and should have call the findAll method with the right params', () => { - return server - .get(buildURL(url)) - .set(createAuthHeaders('get', baseUrl)) - .expect(200) - .then((response: any) => { - expect(response.body).toEqual({ - data: { - total: totalCollectionsFromDb, - pages: totalCollectionsFromDb, - page, - limit, - results: [ - { - ...resultingCollectionAttributes, - urn: `urn:decentraland:mumbai:collections-v2:${dbCollection.contract_address}`, - }, - ], - }, - - ok: true, - }) - expect(Collection.findAll).toHaveBeenCalledWith({ - q, - assignee, - status, - type, - sort, - isPublished: true, - offset: page - 1, // it's the offset - limit, - thirdPartyIds: [], - remoteIds: [], - itemTags: undefined, - }) - }) - }) + ;(page = 1), (limit = 3) + assignee = '0x1234567890123456789012345678901234567890' + status = 'published' + type = 'standard' + sort = 'NAME_DESC' + isPublished = 'true' + q = 'collection name 1' + itemTag = 'TAG' + itemTag2 = 'TAG2' + totalCollectionsFromDb = 1 + baseUrl = '/collections' + url = `${baseUrl}?limit=${limit}&page=${page}&assignee=${assignee}&status=${status}&type=${type}&sort=${sort}&is_published=${isPublished}&q=${q}&tag=${itemTag}&tag=${itemTag2}` + ;(Collection.findAll as jest.Mock).mockResolvedValueOnce([ + { ...dbCollection, collection_count: totalCollectionsFromDb }, + ]) }) - - describe('and sending pagination params plus filtering with array tag options', () => { - let page: number, - limit: number, - baseUrl: string, - totalCollectionsFromDb: number, - q: string, - assignee: string, - status: string, - type: string, - sort: string, - isPublished: string, - itemTag: string, - itemTag2: string - beforeEach(() => { - ;(page = 1), (limit = 3) - assignee = '0x1234567890123456789012345678901234567890' - status = 'published' - type = 'standard' - sort = 'NAME_DESC' - isPublished = 'true' - q = 'collection name 1' - itemTag = 'TAG' - itemTag2 = 'TAG2' - totalCollectionsFromDb = 1 - baseUrl = '/collections' - url = `${baseUrl}?limit=${limit}&page=${page}&assignee=${assignee}&status=${status}&type=${type}&sort=${sort}&is_published=${isPublished}&q=${q}&tag=${itemTag}&tag=${itemTag2}` - ;(Collection.findAll as jest.Mock).mockResolvedValueOnce([ - { ...dbCollection, collection_count: totalCollectionsFromDb }, - ]) - }) - it('should respond with pagination data and should have call the findAll method with the right params', () => { - return server - .get(buildURL(url)) - .set(createAuthHeaders('get', baseUrl)) - .expect(200) - .then((response: any) => { - expect(response.body).toEqual({ - data: { - total: totalCollectionsFromDb, - pages: totalCollectionsFromDb, - page, - limit, - results: [ - { - ...resultingCollectionAttributes, - urn: `urn:decentraland:mumbai:collections-v2:${dbCollection.contract_address}`, - }, - ], - }, - ok: true, - }) - expect(Collection.findAll).toHaveBeenCalledWith({ - q, - assignee, - status, - type, - sort, - isPublished: true, - offset: page - 1, // it's the offset + it('should respond with pagination data and should have call the findAll method with the right params', () => { + return server + .get(buildURL(url)) + .set(createAuthHeaders('get', baseUrl)) + .expect(200) + .then((response: any) => { + expect(response.body).toEqual({ + data: { + total: totalCollectionsFromDb, + pages: totalCollectionsFromDb, + page, limit, - thirdPartyIds: [], - remoteIds: [], - itemTags: [itemTag.toLowerCase(), itemTag2.toLowerCase()], - }) - }) - }) - }) - - describe('and not sending any pagination params ', () => { - beforeEach(() => { - url = `/collections` - ;(Collection.findAll as jest.Mock) - .mockResolvedValueOnce([dbCollection]) - .mockResolvedValueOnce([]) - }) - it('should respond with all the collections with the URN and the legacy response', () => { - return server - .get(buildURL(url)) - .set(createAuthHeaders('get', url)) - .expect(200) - .then((response: any) => { - expect(response.body).toEqual({ - data: [ + results: [ { ...resultingCollectionAttributes, urn: `urn:decentraland:mumbai:collections-v2:${dbCollection.contract_address}`, }, ], - ok: true, - }) + }, + ok: true, }) - }) + expect(Collection.findAll).toHaveBeenCalledWith({ + q, + assignee, + status, + type, + sort, + isPublished: true, + offset: page - 1, // it's the offset + limit, + thirdPartyIds: [], + remoteIds: [], + itemTags: [itemTag.toLowerCase(), itemTag2.toLowerCase()], + }) + }) + }) + }) + + describe('and not sending any pagination params ', () => { + beforeEach(() => { + url = `/collections` + ;(Collection.findAll as jest.Mock) + .mockResolvedValueOnce([dbCollection]) + .mockResolvedValueOnce([]) + }) + it('should respond with all the collections with the URN and the legacy response', () => { + return server + .get(buildURL(url)) + .set(createAuthHeaders('get', url)) + .expect(200) + .then((response: any) => { + expect(response.body).toEqual({ + data: [ + { + ...resultingCollectionAttributes, + urn: `urn:decentraland:mumbai:collections-v2:${dbCollection.contract_address}`, + }, + ], + ok: true, + }) + }) }) }) }) diff --git a/src/Collection/Collection.router.ts b/src/Collection/Collection.router.ts index 4e214b59..75dce315 100644 --- a/src/Collection/Collection.router.ts +++ b/src/Collection/Collection.router.ts @@ -12,7 +12,6 @@ import { withLowercasedParams, withSchemaValidation, AuthRequest, - withPermissiveAuthentication, } from '../middleware' import { Bridge } from '../ethereum/api/Bridge' import { @@ -91,7 +90,7 @@ export class CollectionRouter extends Router { */ this.router.get( '/collections', - withPermissiveAuthentication, + withAuthentication, server.handleRequest(this.getCollections) ) @@ -233,20 +232,12 @@ export class CollectionRouter extends Router { req: AuthRequest ): Promise | FullCollection[]> => { const { page, limit } = getPaginationParams(req) - const { - assignee, - status, - sort, - q, - is_published: isPublished, - tag, - type, - } = req.query + const { assignee, status, sort, q, is_published, tag, type } = req.query const eth_address = req.auth.ethAddress const canRequestCollections = await isCommitteeMember(eth_address) // If the request is not coming from a committee member, it can only request the collections that are already published and using a search term - if (!canRequestCollections && !(q && isPublished === 'true')) { + if (!canRequestCollections) { throw new HTTPError( 'Unauthorized', { eth_address }, @@ -266,7 +257,7 @@ export class CollectionRouter extends Router { status: status as CurationStatusFilter, type: type as CollectionTypeFilter, sort: sort as CollectionSort, - isPublished: isPublished ? isPublished === 'true' : undefined, + isPublished: is_published ? is_published === 'true' : undefined, offset: page && limit ? getOffset(page, limit) : undefined, limit, remoteIds: status