Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: TPW item upsert support #376

Merged
merged 9 commits into from
Jan 6, 2022
6 changes: 2 additions & 4 deletions spec/mocks/items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import { buildTPItemURN } from '../../src/Item/utils'
import { CollectionAttributes } from '../../src/Collection'
import { collectionAttributesMock } from './collections'
import { isTPCollection } from '../../src/Collection/utils'

export type ResultItem = Omit<FullItem, 'created_at' | 'updated_at'> & {
created_at: string
Expand All @@ -23,10 +24,7 @@ export function toResultItem(
dbCollection?: CollectionAttributes
): ResultItem {
const hasURN =
itemAttributes.urn_suffix &&
dbCollection &&
dbCollection.urn_suffix &&
dbCollection.third_party_id
itemAttributes.urn_suffix && dbCollection && isTPCollection(dbCollection)

const resultItem = {
...itemAttributes,
Expand Down
8 changes: 7 additions & 1 deletion src/Item/Item.errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export class UnauthorizedToUpsertError extends Error {
}
}

export class UnauthorizedToChangeToCollection extends Error {
export class UnauthorizedToChangeToCollectionError extends Error {
constructor(
public id: string,
public eth_address: string,
Expand All @@ -67,3 +67,9 @@ export class UnauthorizedToChangeToCollection extends Error {
super("The new collection for the item isn't owned by the same owner.")
}
}

export class InvalidItemURNError extends Error {
constructor() {
super('The item URN is invalid.')
}
}
175 changes: 53 additions & 122 deletions src/Item/Item.router.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,103 +400,34 @@ describe('Item router', () => {
})

describe('and the update moves the item out of the collection', () => {
let dbItemURN: string
beforeEach(() => {
itemToUpsert = { ...itemToUpsert, collection_id: null }
dbItem = { ...dbItem, collection_id: collectionMock.id }
})

describe('and the item has an URN', () => {
let dbItemURN: string
beforeEach(() => {
itemToUpsert = { ...itemToUpsert, collection_id: null }
const itemUrnSuffix = 'an-item-urn-suffix'
dbItemURN = buildTPItemURN(
collectionMock.third_party_id!,
collectionMock.urn_suffix!,
itemUrnSuffix
)
mockItem.findOne.mockResolvedValueOnce({
...dbItem,
collection_id: collectionMock.id,
urn_suffix: itemUrnSuffix,
})
mockCollection.findOne.mockResolvedValueOnce(collectionMock)
})

describe('and is not published', () => {
let resultingItem: ResultItem

beforeEach(() => {
const updatedItem = {
...dbItem,
urn_suffix: null,
collection_id: null,
}
mockThirdPartyItemExists(dbItemURN, false)
mockItem.prototype.upsert.mockResolvedValueOnce(updatedItem)
resultingItem = toResultItem(
updatedItem,
undefined,
undefined,
collectionMock
)
})

it('should respond with a 200, update the item and return the updated item', () => {
return server
.put(buildURL(url))
.send({ item: itemToUpsert })
.set(createAuthHeaders('put', url))
.expect(200)
.then((response: any) => {
expect(response.body).toEqual({
data: resultingItem,
ok: true,
})
})
})
})

describe("and it's published", () => {
beforeEach(() => {
mockThirdPartyItemExists(dbItemURN, true)
})

it('should fail with 409 and a message saying that the item is already published', () => {
return server
.put(buildURL(url))
.send({ item: itemToUpsert })
.set(createAuthHeaders('put', url))
.expect(409)
.then((response: any) => {
expect(response.body).toEqual({
data: {
id: itemToUpsert.id,
urn: dbItemURN,
},
error:
"The third party item is already published. It can't be inserted or updated.",
ok: false,
})
})
})
const itemUrnSuffix = 'an-item-urn-suffix'
dbItemURN = buildTPItemURN(
collectionMock.third_party_id!,
collectionMock.urn_suffix!,
itemUrnSuffix
)
mockItem.findOne.mockResolvedValueOnce({
...dbItem,
collection_id: collectionMock.id,
urn_suffix: itemUrnSuffix,
})
mockCollection.findOne.mockResolvedValueOnce(collectionMock)
})

describe("and the item doesn't have an URN", () => {
describe('and is not published', () => {
let resultingItem: ResultItem

beforeEach(() => {
itemToUpsert = { ...itemToUpsert, urn: null }
mockItem.findOne.mockResolvedValueOnce({
...dbItem,
urn_suffix: null,
collection_id: collectionMock.id,
})
mockCollection.findOne.mockResolvedValueOnce(collectionMock)
const updatedItem = {
...dbItem,
urn_suffix: null,
collection_id: null,
}
mockThirdPartyItemExists(dbItemURN, false)
mockItem.prototype.upsert.mockResolvedValueOnce(updatedItem)
resultingItem = toResultItem(
updatedItem,
Expand All @@ -520,6 +451,31 @@ describe('Item router', () => {
})
})
})

describe("and it's published", () => {
beforeEach(() => {
mockThirdPartyItemExists(dbItemURN, true)
})

it('should fail with 409 and a message saying that the item is already published', () => {
return server
.put(buildURL(url))
.send({ item: itemToUpsert })
.set(createAuthHeaders('put', url))
.expect(409)
.then((response: any) => {
expect(response.body).toEqual({
data: {
id: itemToUpsert.id,
urn: dbItemURN,
},
error:
"The third party item is already published. It can't be inserted or updated.",
ok: false,
})
})
})
})
})

describe('and the update moves the item into the collection', () => {
Expand All @@ -533,7 +489,7 @@ describe('Item router', () => {
itemToUpsert = { ...itemToUpsert, collection_id: collectionMock.id }
})

describe('and the item has an urn', () => {
describe('and the new item has an urn', () => {
let itemToUspertURN: string
const itemUrnSuffix = 'an-item-urn-suffix'

Expand Down Expand Up @@ -607,34 +563,22 @@ describe('Item router', () => {
})
})

describe("and the item doesn't have an urn", () => {
let resultingItem: ResultItem
describe("and the new item doesn't have an urn", () => {
beforeEach(() => {
itemToUpsert = { ...itemToUpsert, urn: null }
const updatedItem = {
...dbItem,
urn_suffix: null,
collection_id: collectionMock.id,
}
mockItem.prototype.upsert.mockResolvedValueOnce(updatedItem)
resultingItem = toResultItem(
updatedItem,
undefined,
undefined,
collectionMock
)
})

it('should respond with a 200, update the item and return the updated item', () => {
it('should respond with a 400, signaling that the URN is not valid', () => {
return server
.put(buildURL(url))
.send({ item: itemToUpsert })
.set(createAuthHeaders('put', url))
.expect(200)
.expect(400)
.then((response: any) => {
expect(response.body).toEqual({
data: resultingItem,
ok: true,
error: 'The item URN is invalid.',
data: {},
ok: false,
})
})
})
Expand Down Expand Up @@ -845,38 +789,25 @@ describe('Item router', () => {
})

describe("and the item doesn't have an URN", () => {
let resultingItem: ResultItem

beforeEach(() => {
itemToUpsert = {
...itemToUpsert,
collection_id: collectionMock.id,
urn: null,
}
const updatedItem = {
...dbItem,
urn_suffix: null,
collection_id: collectionMock.id,
}
mockItem.prototype.upsert.mockResolvedValueOnce(updatedItem)
resultingItem = toResultItem(
updatedItem,
undefined,
undefined,
collectionMock
)
})

it('should respond with a 200, update the item and return the updated item', () => {
it('should respond with a 400, signaling that the URN is not valid', () => {
return server
.put(buildURL(url))
.send({ item: itemToUpsert })
.set(createAuthHeaders('put', url))
.expect(200)
.expect(400)
.then((response: any) => {
expect(response.body).toEqual({
data: resultingItem,
ok: true,
error: 'The item URN is invalid.',
data: {},
ok: false,
})
})
})
Expand Down
7 changes: 5 additions & 2 deletions src/Item/Item.router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ import {
CollectionForItemLockedError,
DCLItemAlreadyPublishedError,
InconsistentItemError,
InvalidItemURNError,
ItemCantBeMovedFromCollectionError,
NonExistentItemError,
ThirdPartyItemAlreadyPublishedError,
UnauthorizedToChangeToCollection,
UnauthorizedToChangeToCollectionError,
UnauthorizedToUpsertError,
} from './Item.errors'
import { NonExistentCollectionError } from '../Collection/Collection.errors'
Expand Down Expand Up @@ -355,7 +356,7 @@ export class ItemRouter extends Router {
{ id: error.id },
STATUS_CODES.unauthorized
)
} else if (error instanceof UnauthorizedToChangeToCollection) {
} else if (error instanceof UnauthorizedToChangeToCollectionError) {
throw new HTTPError(
error.message,
{
Expand Down Expand Up @@ -385,6 +386,8 @@ export class ItemRouter extends Router {
{ id, urn: error.urn },
STATUS_CODES.conflict
)
} else if (error instanceof InvalidItemURNError) {
throw new HTTPError(error.message, null, STATUS_CODES.badRequest)
}

throw error
Expand Down
Loading