Skip to content

Commit

Permalink
Merge pull request #98 from packagelabs/collection-http-media
Browse files Browse the repository at this point in the history
Update NFTCollectionDisplayView to support HTTP media
  • Loading branch information
psiemens authored Sep 21, 2022
2 parents bee6ce3 + 52dc3f5 commit 1dd94cc
Show file tree
Hide file tree
Showing 6 changed files with 364 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
pub fun resolveNFTCollectionDisplay(): MetadataViews.NFTCollectionDisplay {
let media = MetadataViews.Media(
{{#if view.options.media.ipfs }}
file: MetadataViews.IPFSFile(
cid: "{{ view.options.media.ipfsCid }}",
path: nil
cid: "{{ view.options.media.ipfs.cid }}",
path: {{#if view.options.media.ipfs.path }}"{{ view.options.media.ipfs.path }}"{{ else }}nil{{/if}}
),
{{ else }}
file: MetadataViews.HTTPFile(url: "{{ view.options.media.url }}"),
{{/if}}
mediaType: "{{ view.options.media.type }}"
)

Expand Down
112 changes: 112 additions & 0 deletions docs/nodejs.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ mint and distribute NFTs on Flow from a Node.js application.
- [Edition-based claim sales](#edition-based-claim-sales)
- [Reveal on claim](#reveal-on-claim)
- [Allowlists](#allowlists)
- [Add to an allowlist](#add-to-an-allowlist)
- [Create a sale with an allowlist](#create-a-sale-with-an-allowlist)
- [Metadata views](#metadata-views)
- [Add views to a schema](#add-views-to-a-schema)
- [Built-in views](#built-in-views)
- [NFT Collection Display View](#nft-collection-display-view)
- [Collection media](#collection-media)
- [IPFS Media](#ipfs-media)
- [HTTP Media](#http-media)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

Expand Down Expand Up @@ -91,6 +100,9 @@ This is the minimum set of fields required to
implement the [Display](https://github.com/onflow/flow-nft#list-of-common-views)
metadata view.

For a full list of supported metadata views,
see the [metadata views](#metadata-views) section.

```js
const defaultSchema = metadata.createSchema({
fields: {
Expand Down Expand Up @@ -1069,3 +1081,103 @@ await client.send(sale.start({
allowlist: 'early-access-users'
}));
```

# Metadata views

Metadata views allow NFTs to return their metadata in a standardized way
to consumers such as wallets, indexers and marketplaces.
They were proposed in [FLIP-0636](https://github.com/onflow/flow/blob/master/flips/20210916-nft-metadata.md)
and implemented in the [Flow NFT standard repository](https://github.com/onflow/flow-nft#nft-metadata).

Freshmint allows you to specify views as part of your metadata schema.
It will then generate the necessary Cadence code to attach the views to your contract.

## Add views to a schema

```js
import { metadata } from 'freshmint';

const defaultSchema = metadata.createSchema({
fields: {
name: metadata.String(),
description: metadata.String(),
thumbnail: metadata.IPFSImage()
},
// The views property returns a list of views
// to be attached to the contract.
views: (fields) => [
metadata.DisplayView({
name: fields.name,
description: fields.description,
thumbnail: fields.thumbnail
})
]
});
```

## Built-in views

Freshmint has built-in support for the following metadata views.

### NFT Collection Display View

The `NFTCollectionDisplay` view returns a basic representation of the collection
that an NFT belongs to.

```js
import { metadata } from 'freshmint';

const view = metadata.NFTCollectionDisplayView({
name: 'My NFT Collection',
description: 'This is my new NFT collection.',
url: 'http://my-nft-collection.com',
media: {
ipfs: 'bafkreicrfbblmaduqg2kmeqbymdifawex7rxqq2743mitmeia4zdybmmre',
type: 'image/jpeg'
}
})
```

#### Collection media

The media object can either be an IPFS CID or an HTTP URL.

##### IPFS Media

```js
// Example: IPFS media file

const view = metadata.NFTCollectionDisplayView({
// ...
media: {
ipfs: 'bafkreicrfbblmaduqg2kmeqbymdifawex7rxqq2743mitmeia4zdybmmre',
type: 'image/jpeg'
}
})

// Alternatively, you can specify an IPFS CID and path as an object.
const view = metadata.NFTCollectionDisplayView({
// ...
media: {
ipfs: {
cid: 'bafkreicrfbblmaduqg2kmeqbymdifawex7rxqq2743mitmeia4zdybmmre',
path: 'banner.jpeg'
}
type: 'image/jpeg'
}
})
```

##### HTTP Media

```js
// Example: HTTP media file

const view = metadata.NFTCollectionDisplayView({
// ...
media: {
url: 'http://my-nft-collection.com/banner.jpeg',
type: 'image/jpeg'
}
})
```
64 changes: 64 additions & 0 deletions src/lib/metadata/__snapshots__/views.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`NFTCollectionDisplayView generates a Cadence snippet with an HTTP media file 1`] = `
"pub fun resolveNFTCollectionDisplay(): MetadataViews.NFTCollectionDisplay {
let media = MetadataViews.Media(
file: MetadataViews.HTTPFile(url: \\"http://foo.com/nft.jpeg\\"),
mediaType: \\"image/jpeg\\"
)
return MetadataViews.NFTCollectionDisplay(
name: \\"Foo NFT Collection\\",
description: \\"This is the Foo NFT collection.\\",
externalURL: MetadataViews.ExternalURL(\\"http://foo.com\\"),
squareImage: media,
bannerImage: media,
socials: {}
)
}
"
`;

exports[`NFTCollectionDisplayView generates a Cadence snippet with an IPFS media file with a path 1`] = `
"pub fun resolveNFTCollectionDisplay(): MetadataViews.NFTCollectionDisplay {
let media = MetadataViews.Media(
file: MetadataViews.IPFSFile(
cid: \\"bafkreicrfbblmaduqg2kmeqbymdifawex7rxqq2743mitmeia4zdybmmre\\",
path: \\"foo.jpeg\\"
),
mediaType: \\"image/jpeg\\"
)
return MetadataViews.NFTCollectionDisplay(
name: \\"Foo NFT Collection\\",
description: \\"This is the Foo NFT collection.\\",
externalURL: MetadataViews.ExternalURL(\\"http://foo.com\\"),
squareImage: media,
bannerImage: media,
socials: {}
)
}
"
`;

exports[`NFTCollectionDisplayView generates a Cadence snippet with an IPFS media file with no path 1`] = `
"pub fun resolveNFTCollectionDisplay(): MetadataViews.NFTCollectionDisplay {
let media = MetadataViews.Media(
file: MetadataViews.IPFSFile(
cid: \\"bafkreicrfbblmaduqg2kmeqbymdifawex7rxqq2743mitmeia4zdybmmre\\",
path: nil
),
mediaType: \\"image/jpeg\\"
)
return MetadataViews.NFTCollectionDisplay(
name: \\"Foo NFT Collection\\",
description: \\"This is the Foo NFT collection.\\",
externalURL: MetadataViews.ExternalURL(\\"http://foo.com\\"),
squareImage: media,
bannerImage: media,
socials: {}
)
}
"
`;
110 changes: 110 additions & 0 deletions src/lib/metadata/views.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import TemplateGenerator from '../generators/TemplateGenerator';
import * as metadata from './index';

const name = 'Foo NFT Collection';
const description = 'This is the Foo NFT collection.';
const url = 'http://foo.com';
const ipfsMedia = 'bafkreicrfbblmaduqg2kmeqbymdifawex7rxqq2743mitmeia4zdybmmre';
const httpMedia = 'http://foo.com/nft.jpeg';
const mediaType = 'image/jpeg';

function generateView(view: metadata.View): string {
return TemplateGenerator.generate(view.type.cadenceTemplatePath, { view });
}

describe('NFTCollectionDisplayView', () => {
it('rejects combined IPFS and HTTP media input', () => {
expect(() => {
metadata.NFTCollectionDisplayView({
name,
description,
url,
media: {
ipfs: {
cid: ipfsMedia,
},
url: httpMedia,
type: mediaType,
},
});
}).toThrow();
});

const ipfsView = metadata.NFTCollectionDisplayView({
name,
description,
url,
media: {
ipfs: {
cid: ipfsMedia,
},
type: mediaType,
},
});

const ipfsWithPathView = metadata.NFTCollectionDisplayView({
name,
description,
url,
media: {
ipfs: {
cid: ipfsMedia,
path: 'foo.jpeg',
},
type: mediaType,
},
});

const compactIpfsView = metadata.NFTCollectionDisplayView({
name,
description,
url,
media: {
ipfs: ipfsMedia,
type: mediaType,
},
});

const legacyIpfsView = metadata.NFTCollectionDisplayView({
name,
description,
url,
media: {
ipfsCid: ipfsMedia,
type: mediaType,
},
});

it('generates a Cadence snippet with an IPFS media file with no path', () => {
expect(generateView(ipfsView)).toMatchSnapshot();
});

it('generates a Cadence snippet with an IPFS media file with a path', () => {
expect(generateView(ipfsWithPathView)).toMatchSnapshot();
});

it('generates a Cadence snippet with an IPFS media file passed as a CID string only', () => {
expect(compactIpfsView).toEqual(ipfsView);
expect(generateView(compactIpfsView)).toEqual(generateView(ipfsView));
});

it('generates a Cadence snippet with an IPFS media file using legacy input', () => {
// Legacy view should be equivalent to non-legacy view
expect(legacyIpfsView).toEqual(ipfsView);
expect(generateView(legacyIpfsView)).toEqual(generateView(ipfsView));
});

it('generates a Cadence snippet with an HTTP media file', () => {
const view = metadata.NFTCollectionDisplayView({
name,
description,
url,
media: {
url: httpMedia,
type: mediaType,
},
});

expect(generateView(view)).toMatchSnapshot();
});
});
Loading

0 comments on commit 1dd94cc

Please sign in to comment.