Skip to content

Commit

Permalink
feat: Add endpoint to retrieve available slots for a TP collection
Browse files Browse the repository at this point in the history
  • Loading branch information
juanmahidalgo committed Feb 9, 2022
1 parent 933aa0e commit 95c841f
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 0 deletions.
15 changes: 15 additions & 0 deletions src/Curation/ItemCuration/ItemCuration.model.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Model, raw, SQL } from 'decentraland-server'
import { Collection } from '../../Collection'
import { Item } from '../../Item'
import { CurationType } from '../Curation.types'
import { ItemCurationAttributes } from './ItemCuration.types'
Expand All @@ -14,4 +15,18 @@ export class ItemCuration extends Model<ItemCurationAttributes> {
FROM ${raw(this.tableName)} ic
INNER JOIN ${raw(Item.tableName)} i ON i.id = ic.item_id AND i.collection_id = ${collectionId}`)
}

static async getItemCurationCountByThirdPartyId(thirdPartyId: string) {
return this.query(
SQL`SELECT COUNT(DISTINCT ${raw(ItemCuration.tableName)}.id) as Count
FROM ${raw(ItemCuration.tableName)}
JOIN ${raw(Item.tableName)} ON ${raw(Item.tableName)}.id=${raw(
ItemCuration.tableName
)}.item_id
JOIN ${raw(Collection.tableName)} ON ${raw(
Collection.tableName
)}.id=${raw(Item.tableName)}.collection_id
WHERE ${raw(Collection.tableName)}.third_party_id=${thirdPartyId}`
)
}
}
36 changes: 36 additions & 0 deletions src/ThirdParty/ThirdParty.router.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import supertest from 'supertest'
import { createAuthHeaders, buildURL } from '../../spec/utils'
import { ItemCuration } from '../Curation/ItemCuration'
import {
ThirdPartyFragment,
ThirdPartyMetadataType,
Expand All @@ -12,6 +13,7 @@ import { toThirdParty } from './utils'
const server = supertest(app.getApp())

jest.mock('../ethereum/api/thirdParty')
jest.mock('../Curation/ItemCuration')

describe('ThirdParty router', () => {
let fragments: ThirdPartyFragment[]
Expand Down Expand Up @@ -93,4 +95,38 @@ describe('ThirdParty router', () => {
})
})
})

describe('when retreiving the available slots for a third party', () => {
let url: string
const maxSlots = 10
const itemsInCuration = 6

beforeEach(() => {
;(thirdPartyAPI.fetchMaxItemsByThirdParty as jest.Mock).mockResolvedValueOnce(
maxSlots
)
;(thirdPartyAPI.isManager as jest.Mock).mockResolvedValueOnce(true)
;(ItemCuration.getItemCurationCountByThirdPartyId as jest.Mock).mockResolvedValueOnce(
[{ count: itemsInCuration }]
)
url = '/thirdParties/aThirdPartyId/slots'
})

afterEach(() => {
jest.restoreAllMocks()
})

it('should respond with the correct count', () => {
return server
.get(buildURL(url))
.set(createAuthHeaders('get', url))
.expect(200)
.then((response: any) => {
expect(response.body).toEqual({
data: maxSlots - itemsInCuration,
ok: true,
})
})
})
})
})
27 changes: 27 additions & 0 deletions src/ThirdParty/ThirdParty.router.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { server } from 'decentraland-server'

import { Router } from '../common/Router'
import { HTTPError, STATUS_CODES } from '../common/HTTPError'
import { AuthRequest, withAuthentication } from '../middleware/authentication'
import { thirdPartyAPI } from '../ethereum/api/thirdParty'
import { ItemCuration } from '../Curation/ItemCuration'
import { ThirdParty } from './ThirdParty.types'
import { toThirdParty } from './utils'

Expand All @@ -16,6 +18,14 @@ export class ThirdPartyRouter extends Router {
withAuthentication,
server.handleRequest(this.getThirdParties)
)
/**
* Get third party available slots
*/
this.router.get(
'/thirdParties/:id/slots',
withAuthentication,
server.handleRequest(this.getThirdPartyAvailableSlots)
)
}

async getThirdParties(req: AuthRequest): Promise<ThirdParty[]> {
Expand All @@ -28,4 +38,21 @@ export class ThirdPartyRouter extends Router {
const fragments = await thirdPartyAPI.fetchThirdPartiesByManager(manager)
return fragments.map(toThirdParty)
}

async getThirdPartyAvailableSlots(req: AuthRequest): Promise<number> {
const thirdPartyId = server.extractFromReq(req, 'id')
const eth_address = req.auth.ethAddress
if (!(await thirdPartyAPI.isManager(thirdPartyId, eth_address))) {
throw new HTTPError(
'Unauthorized access. Account is not manager of the collection',
{ eth_address },
STATUS_CODES.unauthorized
)
}
const maxItems = await thirdPartyAPI.fetchMaxItemsByThirdParty(thirdPartyId)
const itemCurationsCount = await ItemCuration.getItemCurationCountByThirdPartyId(
thirdPartyId
)
return maxItems - itemCurationsCount[0].count
}
}
20 changes: 20 additions & 0 deletions src/ethereum/api/thirdParty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ const getItemsByThirdPartyIdsQuery = () => gql`
${thirdPartyItemFragment()}
`

const getThirdPartyMaxItems = () => gql`
query getThirdPartyAvailableSlots($thirdPartyId: String!) {
thirdParties(where: { id: $thirdPartyId }) {
maxItems
}
}
`

const getItemsByCollectionQuery = () => gql`
query getItemsByCollection(${PAGINATION_VARIABLES}, $thirdPartiesId: String!, $collectionId: String!) {
items(${PAGINATION_ARGUMENTS}, where: { thirdParty: $thirdPartiesId, searchCollectionId: $collectionId }) {
Expand Down Expand Up @@ -171,6 +179,18 @@ export class ThirdPartyAPI extends BaseGraphAPI {
})
}

fetchMaxItemsByThirdParty = async (thirdPartyId: string): Promise<number> => {
const {
data: { thirdParties },
} = await this.query<{
thirdParties: { maxItems: string }[]
}>({
query: getThirdPartyMaxItems(),
variables: { thirdPartyId },
})
return +thirdParties[0].maxItems
}

fetchItems = async (): Promise<ThirdPartyItemFragment[]> => {
return this.paginate(['items'], {
query: getItemsQuery(),
Expand Down

0 comments on commit 95c841f

Please sign in to comment.