From 3269632ecb35686d60c4a130b0341fd65b325d24 Mon Sep 17 00:00:00 2001 From: DIYgod Date: Thu, 26 May 2022 04:41:07 +0100 Subject: [PATCH] feat(notes): support for getting mutiple crossbell notes --- docs/guide/notes/Crossbell-Note.md | 7 +- docs/guide/notes/README.md | 4 +- package.json | 2 +- src/assets/index.ts | 13 +-- src/notes/crossbell-note.ts | 136 ++++++++++++++++++++--------- src/notes/index.ts | 3 +- src/utils.ts | 9 ++ yarn.lock | 10 +-- 8 files changed, 125 insertions(+), 59 deletions(-) diff --git a/docs/guide/notes/Crossbell-Note.md b/docs/guide/notes/Crossbell-Note.md index 88555e6..6139051 100644 --- a/docs/guide/notes/Crossbell-Note.md +++ b/docs/guide/notes/Crossbell-Note.md @@ -17,15 +17,20 @@ You can initialize with `ipfsGateway` to potentially get a faster response or hi ```ts const notes: Notes = await unidata.notes.get(options: { source: 'Crossbell Note'; - identity: string; + identity?: string; platform?: string; limit?: number; cursor?: string; + filter?: { + url?: string; + } }); ``` +- `identity` is optional, returns data based on filter only when not provided. - Use Ethereum address as the `identity` and `'Ethereum'` as the `platform` to get notes from all profiles belonging to this address. - Use Crossbell handle as the `identity` and `'Crossbell'` as the `platform` to get notes from a specific profile. +- Use `filter.url` to get notes linking to the url. ### Set diff --git a/docs/guide/notes/README.md b/docs/guide/notes/README.md index d229831..008636a 100644 --- a/docs/guide/notes/README.md +++ b/docs/guide/notes/README.md @@ -13,10 +13,11 @@ You can initialize with `ipfsGateway` to potentially get a faster response or hi ```ts const notes: Notes = await unidata.notes.get(options: { source: string; - identity: string; + identity?: string; platform?: string; limit?: number; cursor?: any; + filters?: any; }); ``` @@ -24,6 +25,7 @@ const notes: Notes = await unidata.notes.get(options: { - `platform`: Platfrom of the identity. Ethereum, Solana, Flow, Crossbell, etc. Default to `Ethereum`. - `limit`: The number of assets to return. Since providers use different pagination schemes, there is no guarantee that the quantities are always accurate. - `cursor`: The pagination cursor returned from the previous page's results. Since providers use different pagination schemes, the type is uncertain. +- `filters`: Varies depending on the source. ### Set diff --git a/package.json b/package.json index b833988..b5bb3f9 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "dependencies": { "@urql/core": "2.5.0", "axios": "0.27.2", - "crossbell.js": "0.5.12", + "crossbell.js": "0.5.13", "ethers": "5.6.8", "graphql": "16.5.0", "lodash": "4.17.21", diff --git a/src/assets/index.ts b/src/assets/index.ts index f759999..6ffa37d 100644 --- a/src/assets/index.ts +++ b/src/assets/index.ts @@ -1,7 +1,6 @@ import Main from '../index'; import Base from './base'; import { mergeWith, keyBy, values, uniqWith, isEqual } from 'lodash'; -import mime from 'mime'; import EthereumNFTMoralis from './ethereum-nft-moralis'; import EthereumNFTOpenSea from './ethereum-nft-opensea'; import EthereumNFTPOAP from './ethereum-nft-poap'; @@ -95,14 +94,6 @@ class Assets { } } - private generateMimeType(address: string) { - address = this.main.utils.replaceIPFS(address); - const mimeType = mime.getType(address); - if (mimeType) { - return mimeType; - } - } - async get(options: AssetsOptions) { options = Object.assign( { @@ -168,7 +159,7 @@ class Assets { item.address = this.main.utils.replaceIPFS(item.address); } if (item.address && !item.mime_type) { - item.mime_type = this.generateMimeType(item.address); + item.mime_type = this.main.utils.getMimeType(item.address); } }); } @@ -178,7 +169,7 @@ class Assets { item.address = this.main.utils.replaceIPFS(item.address); } if (item.address && !item.mime_type) { - item.mime_type = this.generateMimeType(item.address); + item.mime_type = this.main.utils.getMimeType(item.address); } }); } diff --git a/src/notes/crossbell-note.ts b/src/notes/crossbell-note.ts index ca360a2..b77dbac 100644 --- a/src/notes/crossbell-note.ts +++ b/src/notes/crossbell-note.ts @@ -3,11 +3,11 @@ import Base from './base'; import { NotesOptions, NoteSetOptions, NoteInput } from './index'; import { Indexer, Contract, Network } from 'crossbell.js'; import { Web3Storage } from 'web3.storage'; +import { BigNumber } from 'ethers'; class CrossbellNote extends Base { indexer: Indexer; contract: Contract; - contractSet: Contract; constructor(main: Main) { super(main); @@ -15,11 +15,17 @@ class CrossbellNote extends Base { Network.setIpfsGateway(this.main.options.ipfsGateway!); } + async init() { + await Network.switchToCrossbellMainnet(this.main.options.ethereumProvider); + this.contract = new Contract(this.main.options.ethereumProvider); + await this.contract.connect(); + } + async get(options: NotesOptions) { if (!this.contract) { - this.contract = new Contract(); - await this.contract.connect(); + await this.init(); } + options = Object.assign( { platform: 'Ethereum', @@ -27,47 +33,96 @@ class CrossbellNote extends Base { options, ); - let profileId = await this.main.utils.getCrossbellProfileId({ - identity: options.identity, - platform: options.platform!, - }); - if (profileId === '0') { - return { - total: 0, - list: [], - }; + // @ts-ignore + const initialContract = this.contract.contract; + + let events: any; + if (options.identity) { + let profileId = await this.main.utils.getCrossbellProfileId({ + identity: options.identity, + platform: options.platform!, + }); + if (profileId === '0') { + return { + total: 0, + list: [], + }; + } + const filter = initialContract.filters.PostNote(BigNumber.from(profileId)); + events = await initialContract.queryFilter(filter); + } else if (options.filter?.url) { + const filter = initialContract.filters.PostNote( + null, + null, + this.contract.getLinkKeyForAnyUri(options.filter?.url), + ); + events = await initialContract.queryFilter(filter); } - const result = (await this.contract.getNote(profileId, '1')).data; + const list = await Promise.all( + events.reverse().map(async (event: any) => { + const profileId = event.args.profileId.toString(); + const nodeId = event.args.noteId.toString(); + const note = (await this.contract.getNote(profileId, nodeId, 'AnyUri')).data; - const now = new Date().toISOString(); + // @ts-ignore + const date = new Date((await initialContract.provider.getBlock(event.blockNumber)).timestamp * 1000); - const item: Note = Object.assign({}, result.metadata, { - id: result.noteId, + const item: Note = Object.assign({}, note.metadata as Partial, { + id: `${profileId}-${nodeId}`, - date_created: now, - date_updated: now, + date_created: date, + date_updated: date, - authors: [options.identity], + related_urls: [ + ...(note.linkItem?.uri && [note.linkItem?.uri]), + `https://scan.crossbell.io/tx/${event.transactionHash}`, + ], - source: 'Crossbell Note', - metadata: { - network: 'Crossbell', - proof: result.noteId, - }, - }); + authors: [options.identity], - // Crossbell specification compatibility - if (item.summary) { - item.summary = { - content: (item).summary, - mime_type: 'text/markdown', - }; - } + source: 'Crossbell Note', + metadata: { + network: 'Crossbell', + proof: event.transactionHash, + + block_number: event.blockNumber, + }, + }); + + // Crossbell specification compatibility + if (item.summary) { + item.summary = { + content: (item).summary, + mime_type: 'text/markdown', + }; + } + if ((item).content) { + item.summary = { + content: (item).content, + mime_type: 'text/markdown', + }; + delete (item).content; + } + + if (item.attachments) { + item.attachments.forEach((attachment) => { + if (attachment.address) { + attachment.address = this.main.utils.replaceIPFS(attachment.address); + } + if (attachment.address && !attachment.mime_type) { + attachment.mime_type = this.main.utils.getMimeType(attachment.address); + } + }); + } + + return item; + }), + ); return { - total: 1, - list: [item], + total: list.length, + list: list, }; } @@ -80,9 +135,8 @@ class CrossbellNote extends Base { options, ); - if (!this.contractSet) { - this.contractSet = new Contract(this.main.options.ethereumProvider); - await this.contractSet.connect(); + if (!this.contract) { + await this.init(); } let profileId = await this.main.utils.getCrossbellProfileId({ @@ -103,6 +157,10 @@ class CrossbellNote extends Base { }); // Crossbell specification compatibility + if (input.body) { + (input).content = input.body.content; + delete input.body; + } if (input.summary) { (input).summary = input.summary.content; } @@ -117,7 +175,7 @@ class CrossbellNote extends Base { wrapWithDirectory: false, }); - const data = await this.contractSet.postNote(profileId, `ipfs://${cid}`); + const data = await this.contract.postNote(profileId, `ipfs://${cid}`); return { code: 0, @@ -132,7 +190,7 @@ class CrossbellNote extends Base { message: 'Missing id', }; } else { - await this.contractSet.deleteNote(profileId, input.id); + await this.contract.deleteNote(profileId, input.id); return { code: 0, diff --git a/src/notes/index.ts b/src/notes/index.ts index d862a26..39bbcb5 100644 --- a/src/notes/index.ts +++ b/src/notes/index.ts @@ -7,10 +7,11 @@ import CrossbellNote from './crossbell-note'; export type NotesOptions = { source: string; - identity: string; + identity?: string; platform?: string; limit?: number; cursor?: any; + filter?: any; }; export type NoteSetOptions = { diff --git a/src/utils.ts b/src/utils.ts index 4e3b570..ec89f7b 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,6 @@ import Main from './index'; import { Indexer, Contract, Network } from 'crossbell.js'; +import mime from 'mime'; class Utils { main: Main; @@ -79,6 +80,14 @@ class Utils { delete father.obj[father.key]; } } + + getMimeType(address: string) { + address = this.main.utils.replaceIPFS(address); + const mimeType = mime.getType(address); + if (mimeType) { + return mimeType; + } + } } export default Utils; diff --git a/yarn.lock b/yarn.lock index 39c0942..045155a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2316,14 +2316,14 @@ __metadata: languageName: node linkType: hard -"crossbell.js@npm:0.5.12": - version: 0.5.12 - resolution: "crossbell.js@npm:0.5.12" +"crossbell.js@npm:0.5.13": + version: 0.5.13 + resolution: "crossbell.js@npm:0.5.13" dependencies: ethers: ^5.6.3 ts-mixer: ^6.0.1 undici: ^5.2.0 - checksum: db66811a4362c12a7a4d7f04f8bdde6ff7e72ce0b21fa77d4efb517a7a3fb104e61bb85f6d2a7519e165e48251c81141b22ed13436d84b2ca522a2de270d4434 + checksum: 706d109eca1542efdb4c3836a9209292fdcedbae15687c7b3411de1f724d921a21bfbe03a271490a274f38ac4e5f57c25012359429e47587f990fecb1e0767d6 languageName: node linkType: hard @@ -6149,7 +6149,7 @@ __metadata: "@vuepress/plugin-docsearch": 2.0.0-beta.45 "@vuepress/plugin-register-components": 2.0.0-beta.45 axios: 0.27.2 - crossbell.js: 0.5.12 + crossbell.js: 0.5.13 element-plus: 2.2.2 ethers: 5.6.8 graphql: 16.5.0