Skip to content

Commit

Permalink
feat: add validation for the amount the tags being added (#738)
Browse files Browse the repository at this point in the history
* feat: add validation for the amount the tags being added

* test: remove commented code

* chore: remove old import not used anymore

* test: add mock serviec method

* test: remove extra arrow fn not needed
  • Loading branch information
juanmahidalgo committed Apr 5, 2024
1 parent f36c2c2 commit 85b5c8a
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 6 deletions.
10 changes: 10 additions & 0 deletions src/Item/Item.errors.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { MAX_TAGS_LENGTH } from './Item.model'

export enum ItemAction {
DELETE = 'deleted',
INSERT = 'inserted',
Expand Down Expand Up @@ -42,6 +44,14 @@ export class URNAlreadyInUseError extends Error {
}
}

export class MaximunAmountOfTagsReachedError extends Error {
constructor(public id: string) {
super(
`You hace exceeded the maximun amount of tags allowed (${MAX_TAGS_LENGTH}).`
)
}
}

export class DCLItemAlreadyPublishedError extends Error {
constructor(
public id: string,
Expand Down
2 changes: 2 additions & 0 deletions src/Item/Item.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { ItemCuration } from '../Curation/ItemCuration'
import { DEFAULT_LIMIT } from '../Pagination/utils'
import { DBItemApprovalData, ItemAttributes } from './Item.types'

export const MAX_TAGS_LENGTH = 20

type ItemWithTotalCount = ItemAttributes & { total_count: number }

type ItemQueryOptions = {
Expand Down
128 changes: 124 additions & 4 deletions src/Item/Item.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@ import {
itemFragmentMock,
} from '../../spec/mocks/items'
import { wearableMock } from '../../spec/mocks/peer'
import { mockOwnableCanUpsert } from '../../spec/utils'
import { Collection } from '../Collection/Collection.model'
import { CollectionService } from '../Collection/Collection.service'
import { Bridge } from '../ethereum/api/Bridge'
import { collectionAPI } from '../ethereum/api/collection'
import { peerAPI } from '../ethereum/api/peer'
import {
ItemCantBeMovedFromCollectionError,
MaximunAmountOfTagsReachedError,
ThirdPartyItemInsertByURNError,
} from './Item.errors'
import { Item } from './Item.model'
import { Item, MAX_TAGS_LENGTH } from './Item.model'
import { ItemService } from './Item.service'
import { ItemAttributes } from './Item.types'
import { VIDEO_PATH } from './utils'
Expand Down Expand Up @@ -80,7 +83,7 @@ describe('Item Service', () => {
})

it('should throw the ItemCantBeMovedFromCollectionError error', () => {
return expect(() =>
return expect(
service.upsertItem(
Bridge.toFullItem(dbTPItem, dbTPCollectionMock),
'0xnewCreator'
Expand All @@ -102,7 +105,7 @@ describe('Item Service', () => {
})

it('should throw the ItemCantBeMovedFromCollectionError error', () => {
return expect(() =>
return expect(
service.upsertItem(Bridge.toFullItem(dbItem), '0xnewCreator')
).rejects.toThrowError(ItemCantBeMovedFromCollectionError)
})
Expand All @@ -115,14 +118,131 @@ describe('Item Service', () => {
})

it('should throw the ThirdPartyItemInsertByURNError error', () => {
return expect(() =>
return expect(
service.upsertItem(
Bridge.toFullItem(dbTPItem, dbTPCollectionMock),
'0xnewCreator'
)
).rejects.toThrowError(ThirdPartyItemInsertByURNError)
})
})

describe('and the item being upserted contains tags', () => {
beforeEach(() => {
CollectionService.prototype.getDBCollection = jest.fn()
})
describe('and it is an insert operation', () => {
beforeEach(() => {
;(Item.findByURNSuffix as jest.Mock).mockResolvedValueOnce(undefined)
})
describe('and it is inserting less than the maximun amount of tags', () => {
beforeEach(() => {
dbItem = {
...dbItemMock,
eth_address: '0xAddress',
data: {
...dbItemMock.data,
tags: Array(MAX_TAGS_LENGTH - 1).fill('tag'),
},
}
dbCollectionMock.eth_address = dbItem.eth_address
mockOwnableCanUpsert(Item, dbItem.id, dbItem.eth_address, true)
mockOwnableCanUpsert(
Collection,
dbCollectionMock.id,
dbItem.eth_address,
true
)
;(CollectionService.prototype
.getDBCollection as jest.Mock).mockResolvedValueOnce(
dbCollectionMock
)
;(Item.upsert as jest.Mock).mockResolvedValueOnce(dbItem)
CollectionService.prototype.isDCLPublished = jest.fn()
})
it('should not throw any errors and return the inserted item', () => {
const result = service.upsertItem(
Bridge.toFullItem(dbItem, dbTPCollectionMock),
dbItem.eth_address
)
return expect(result).resolves.toEqual(
Bridge.toFullItem(dbItem, dbCollectionMock)
)
})
})

describe('and it is inserting more than the maximun amount of tags', () => {
beforeEach(() => {
dbItem = {
...dbItemMock,
data: {
...dbItemMock.data,
tags: Array(MAX_TAGS_LENGTH + 1).fill('tag'),
},
}
})
it('should throw the MaximunAmountOfTagsReachedError error', () => {
return expect(
service.upsertItem(
Bridge.toFullItem(dbItem, dbTPCollectionMock),
dbItem.eth_address
)
).rejects.toThrowError(MaximunAmountOfTagsReachedError)
})
})
})

describe('and it is an update operation', () => {
beforeEach(() => {
;(Item.findByURNSuffix as jest.Mock).mockResolvedValueOnce(dbItem)
})
describe('and the item already has the maximun amount of tags', () => {
it('should throw the MaximunAmountOfTagsReachedError error', () => {
return expect(
service.upsertItem(
Bridge.toFullItem(dbItem, dbTPCollectionMock),
dbItem.eth_address
)
).rejects.toThrowError(MaximunAmountOfTagsReachedError)
})
})

describe('and the item has less than the maximun amount of tags', () => {
beforeEach(() => {
dbItem = {
...dbItemMock,
eth_address: '0xAddress',
data: {
...dbItemMock.data,
tags: Array(MAX_TAGS_LENGTH - 1).fill('tag'),
},
}
dbCollectionMock.eth_address = dbItem.eth_address
mockOwnableCanUpsert(Item, dbItem.id, dbItem.eth_address, true)
mockOwnableCanUpsert(
Collection,
dbCollectionMock.id,
dbItem.eth_address,
true
)
;(CollectionService.prototype
.getDBCollection as jest.Mock).mockResolvedValueOnce(
dbCollectionMock
)
;(Item.upsert as jest.Mock).mockResolvedValueOnce(dbItem)
})
it('should not throw any error and return the inserted item', () => {
const result = service.upsertItem(
Bridge.toFullItem(dbItem, dbTPCollectionMock),
dbItem.eth_address
)
return expect(result).resolves.toEqual(
Bridge.toFullItem(dbItem, dbCollectionMock)
)
})
})
})
})
})

describe('getItemByContractAddressAndTokenId', () => {
Expand Down
21 changes: 19 additions & 2 deletions src/Item/Item.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ import {
InvalidItemURNError,
URNAlreadyInUseError,
ThirdPartyItemInsertByURNError,
MaximunAmountOfTagsReachedError,
} from './Item.errors'
import { Item } from './Item.model'
import { Item, MAX_TAGS_LENGTH } from './Item.model'
import {
FullItem,
ItemAttributes,
Expand All @@ -62,6 +63,7 @@ export class ItemService {
item: FullItem,
eth_address: string
): Promise<FullItem> {
console.log('here1')
const decodedItemURN =
!item.id && item.urn ? decodeThirdPartyItemURN(item.urn) : null

Expand All @@ -72,12 +74,25 @@ export class ItemService {
decodedItemURN.item_urn_suffix
)
: await Item.findOne<ItemAttributes>(item.id)
console.log('here2')
if (item.data.tags.length > MAX_TAGS_LENGTH) {
const isAlreadyExceeded =
!!dbItem && dbItem.data.tags.length > MAX_TAGS_LENGTH
const isAddingMoreTags =
!!dbItem && item.data.tags.length > dbItem.data.tags.length
if (!dbItem || (isAlreadyExceeded && isAddingMoreTags)) {
throw new MaximunAmountOfTagsReachedError(item.id)
}
}
console.log('here3')

// Inserting by URN is not allowed
if (!item.id && item.urn && !dbItem) {
throw new ThirdPartyItemInsertByURNError(item.urn)
}

console.log('here4')

const isMovingItemFromACollectionToAnother =
dbItem && this.isMovingItemFromACollectionToAnother(item, dbItem)
const isMovingOrphanItemIntoACollection =
Expand Down Expand Up @@ -115,6 +130,7 @@ export class ItemService {
// Set the item dates
item = { ...item, ...buildModelDates(dbItem?.created_at) }

console.log('here5')
// An item is a third party item if it's current collection or the collection
// that is going to be inserted into is a third party collection.
if (dbItemCollection && isTPCollection(dbItemCollection)) {
Expand Down Expand Up @@ -494,6 +510,7 @@ export class ItemService {
const isMovingItemBetweenCollections =
dbItem && this.isMovingItemFromACollectionToAnother(item, dbItem)

console.log('here6')
const [
isDbItemCollectionPublished,
isItemCollectionPublished,
Expand All @@ -506,6 +523,7 @@ export class ItemService {
itemCollection.contract_address &&
this.collectionService.isDCLPublished(itemCollection.contract_address),
])
console.log('here7')

const isDbItemCollectionOwner =
dbCollection && this.isCollectionOwner(eth_address, dbCollection)
Expand All @@ -515,7 +533,6 @@ export class ItemService {
// Check if we have permissions to move or edit an orphaned item
if (!dbItem?.collection_id) {
const canUpsert = await new Ownable(Item).canUpsert(item.id, eth_address)

if (!canUpsert) {
throw new UnauthorizedToUpsertError(item.id, eth_address)
}
Expand Down

0 comments on commit 85b5c8a

Please sign in to comment.