Skip to content

Commit

Permalink
Merge pull request #7 from GoodDollar/add--orbis-and-upgrade-strapi
Browse files Browse the repository at this point in the history
Add  orbis and upgrade strapi
  • Loading branch information
sirpy authored Oct 5, 2023
2 parents 83b928e + 491eb95 commit 6b6c332
Show file tree
Hide file tree
Showing 13 changed files with 13,765 additions and 15,318 deletions.
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"bracketSameLine": false,
"arrowParens": "avoid"
}
15,072 changes: 0 additions & 15,072 deletions package-lock.json

This file was deleted.

12 changes: 7 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,18 @@
"dependencies": {
"@ceramicnetwork/http-client": "^2.0.4",
"@ceramicnetwork/stream-tile": "^2.1.3",
"@strapi/plugin-i18n": "4.1.11",
"@strapi/plugin-users-permissions": "4.1.11",
"@strapi/provider-upload-aws-s3": "^4.1.11",
"@strapi/strapi": "4.1.11",
"@orbisclub/orbis-sdk": "^0.4.87",
"@strapi/plugin-i18n": "4.11.4",
"@strapi/plugin-users-permissions": "4.11.4",
"@strapi/provider-upload-aws-s3": "^4.11.4",
"@strapi/strapi": "4.11.4",
"async-lock": "^1.3.1",
"axios": "^0.27.2",
"dids": "^3.1.0",
"form-data": "^4.0.0",
"key-did-provider-ed25519": "^2.0.0",
"key-did-resolver": "^2.0.4",
"localstorage-memory": "^1.0.3",
"multiformats": "^9.7.1",
"pg": "^8.7.3",
"sqlite3": "5.0.8",
Expand All @@ -58,4 +60,4 @@
"npm": ">=6.0.0"
},
"license": "MIT"
}
}
20 changes: 13 additions & 7 deletions src/plugins/ceramic-feed/cli/commands/client-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,37 @@ const env = require('@strapi/utils/lib/env-helper')
const getPluginsConfig = require('../../../../../config/plugins')

const { string } = require('../../server/utils')
const { Post } = require('../../server/services/ceramic/CeramicClient')
const { Post } = require('../../server/services/ceramic/CeramicOrbisClient')
const bootstrapCeramicNetwork = require('../../server/bootstrap/ceramic-network')

;(async () => {
try {
const envTmpl = string.mustache(
`REACT_APP_CERAMIC_NODE_URL={ceramicNodeURL}\n` +
`REACT_APP_CERAMIC_INDEX={postsIndex}\n` +
`REACT_APP_CERAMIC_LIVE_INDEX={postsLiveIndex}`
`REACT_APP_CERAMIC_INDEX={postsIndex}\n` +
`REACT_APP_CERAMIC_LIVE_INDEX={postsLiveIndex}`
)

dotenv.config()

const config = getPluginsConfig({ env })
const { ceramicNodeURL, ceramicDIDSeed } = get(config, 'ceramic-feed.config')
const { ceramicNodeURL, ceramicDIDSeed } = get(
config,
'ceramic-feed.config'
)

await bootstrapCeramicNetwork(ceramicNodeURL, ceramicDIDSeed)

const { id: postsIndex } = await Post.getIndex()
const { id: postsLiveIndex } = await Post.getLiveIndex()
const settings = mapValues({ postsIndex, postsLiveIndex, ceramicNodeURL }, String)
const settings = mapValues(
{ postsIndex, postsLiveIndex, ceramicNodeURL },
String
)
const reactEnv = envTmpl(settings)

logger.info('Add the following lines to React App .env file:');
logger.info(`\n\n${colors.cyan(reactEnv)}\n`);
logger.info('Add the following lines to React App .env file:')
logger.info(`\n\n${colors.cyan(reactEnv)}\n`)
} catch (exception) {
logger.error(exception)
}
Expand Down
1 change: 1 addition & 0 deletions src/plugins/ceramic-feed/server/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module.exports = {
default: ({ env }) => ({
ceramicNodeURL: env('CERAMIC_NODE_URL', 'https://ceramic-clay.3boxlabs.com'),
web3storageGateway: env('WEB3STORAGE_GATEWAY', 'https://ipfsgateway.goodworker.workers.dev'),
orbisContext: env('ORBIS_FEED_CONTEXT', 'kjzl6cwe1jw147bfd2hn7f3j2sdsq6708xnb3a217iz1m18a35v25kgxna3s0os'),
}),
validator(config) {
const mandatoryOptions = ['ceramicNodeURL', 'ceramicDIDSeed', 'web3storageGateway']
Expand Down
172 changes: 106 additions & 66 deletions src/plugins/ceramic-feed/server/content-types/ceramic-post/lifecycles.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
const { assign, pick, map, mapValues, mapKeys, filter, isEmpty, isPlainObject, bindAll } = require('lodash')

const { ApplicationError } = require('@strapi/utils').errors;
const {
assign,
pick,
map,
mapValues,
mapKeys,
filter,
isEmpty,
isPlainObject,
bindAll
} = require('lodash')
const { ApplicationError } = require('@strapi/utils').errors
const { metadata, array } = require('../../utils')

const { withArray } = require('../../utils/async')
const { schema, relations } = require('./datagram');
const { schema, relations } = require('./datagram')

const { resolveMediaFieldsPaths, makePopulate } = metadata
const POSTS = 'plugin::ceramic-feed.ceramic-post'

const LifecycleHooks = new class {
// boolean fields that should be converted to tags
const PUBLISH_TAGS = ['publishWallet', 'publishDapp']
const PUBLISH_TAGS_TITLES = {
publishWallet: 'Publish on goodwallet',
publishDapp: 'Publish on gooddapp'
}

const LifecycleHooks = new (class {
get ceramic() {
const { strapi } = this

Expand Down Expand Up @@ -39,86 +55,79 @@ const LifecycleHooks = new class {
bindAll(this, '_callCeramic')
}

async onPublish(event) {
const { _callCeramic } = this
const entity = await this._loadEntity(event)

const { cid, publishedAt } = entity
const published = publishedAt instanceof Date ? publishedAt.toISOString() : publishedAt
async onPublish(entity) {
const { _callCeramic, entityService } = this

const { cid, orbisId, publishedAt, updatedAt } = entity
const published =
publishedAt instanceof Date ? publishedAt.toISOString() : publishedAt
const updated =
updatedAt instanceof Date ? updatedAt.toISOString() : updatedAt
// on publish we have to pre-fill
// or update 'published' date field
const payload = await this._readPayload(entity)
.then(data => ({ ...data, published }))
const payload = await this._readPayload(entity).then(data => ({
...data,
published,
updated
}))

console.log('onPublish payload:', payload)
// if Ceramic ID was set - update doc (with latest data)
// and publish (by writing 'updated' event to the changelog)
if (cid) {
await _callCeramic(async ceramic => {
await ceramic.updateAndPublish(cid, payload)
await ceramic.updateAndPublish(cid, orbisId, payload)
})

if (!orbisId) {
console.log('no orbis id...')
const data = await _callCeramic(async ceramic =>
ceramic.syncOrbis(payload)
)
entityService.update(POSTS, entity.id, { data })
}
return
}

// if no Ceramic ID in document - create document
// and write 'added' event to the changelog
const document = await _callCeramic(async ceramic => ceramic.createAndPublish(payload))
const { data } = event.params

// prefill data with Ceramic ID newly generated
data.cid = String(document.id)
const data = await _callCeramic(async ceramic =>
ceramic.createAndPublish(payload)
)
entityService.update(POSTS, entity.id, { data })
}

async onUpdate(event) {
const { _callCeramic } = this
const { data } = event.params

// if 'publishedAt' present in update PAYLOAD - publish or unpublish
// button was pressed, there's no other cases where this field
// could be presented in payload
if ('publishedAt' in data) {
// if publishedAt is set - publishing document
if (data.publishedAt) {
return this.onPublish(event)
}
async onAfterUpdate(event) {
const entity = event.result
const { publishedAt } = entity

// if publishedAt is null - unpublishing it
return this.onUnpublish(event)
//case 1. being or already published - update or create the record on ceramic
if (publishedAt) {
return this.onPublish(entity)
}

const entity = await this._loadEntity(event)
const { publishedAt, cid } = entity

// if 'publishedAt' present in DOCUMENT (but absent in UPDATE PAYLOAD) that means
// the published document was updated and nees to be also updated in Ceramic
// before update we're checking is Ceramic ID is set
if (publishedAt && cid) {
const payload = await this._readPayload(entity)

await _callCeramic(async ceramic => {
await ceramic.updateAndPublish(cid, payload)
})
}

// if no 'publishedAt' present in DOCUMENT then means the DRAFT was updated we're skipping
// updating of the drafts in Ceramic. they will be updated on the next re-publish
//case 2. being or already unpublished
return this.onUnpublish(entity)
}

async onUnpublish(event) {
const { params } = event
const { params = {} } = event
const { where, data } = params
const { _callCeramic, posts } = this
let ids

if (('data' in params) && ('cid' in data)) {
ids = [data.cid]
// case for single unpublish
if ('cid' in event) {
ids = [[event.cid, event.orbisId]]
// case for single delete
} else if ('data' in params && 'cid' in data) {
ids = [[data.cid, data.orbisId]]
} else {
//case for delete many
// getting ceramic IDs querying posts table
// by id/ids got from event's where conditions
ids = await posts
.findMany({ select: ['cid'], where })
.then(records => map(records, 'cid'))
.findMany({ select: ['cid', 'orbisId'], where })
.then(records => map(records, _ => [_.cid, _.orbisId]))
}

ids = filter(ids)
Expand All @@ -129,7 +138,7 @@ const LifecycleHooks = new class {

await _callCeramic(async ceramic => {
// unpublishing document by ceramic ID
await withArray(ids, async id => ceramic.unpublish(id))
await withArray(ids, async id => ceramic.unpublish(id[0], id[1]))
})
}

Expand All @@ -142,7 +151,7 @@ const LifecycleHooks = new class {
return { fields, mediaFields }
}

return { ...schemaMeta, fields: array.remove(fields, 'cid') }
return { ...schemaMeta, fields: array.remove(fields, 'cid', 'orbisId') }
}

/**
Expand All @@ -154,7 +163,22 @@ const LifecycleHooks = new class {
const { relatedFieldName } = metadata
const entitySchema = schemaName ? schemas[schemaName] : schema
const { fields, mediaFields, relationFields } = entitySchema
const payload = pick(entity, fields)

const payload = pick(
entity,
array.remove(fields, ...PUBLISH_TAGS) //converting to tags
)

//handle tags for orbis
payload.tags = []
PUBLISH_TAGS.forEach(t => {
if (entity[t]) {
payload.tags.push({
slug: t,
title: PUBLISH_TAGS_TITLES[t]
})
}
})

await withArray(mediaFields, async field => {
payload[field] = await this._loadAsset(payload, field)
Expand All @@ -165,11 +189,13 @@ const LifecycleHooks = new class {
if (!schemaName) {
await withArray(relationFields, async field => {
const relatedEntity = await this._loadRelation(entity, field)

if (relatedEntity) {
const entityPayload = await this._readPayload(relatedEntity, field)

assign(payload, mapKeys(entityPayload, (_, key) => relatedFieldName(field, key)))
assign(
payload,
mapKeys(entityPayload, (_, key) => relatedFieldName(field, key))
)
}

delete payload[field]
Expand Down Expand Up @@ -214,7 +240,7 @@ const LifecycleHooks = new class {
return media
}

return assets.findOne({ select: ['url'], where: { id: media }})
return assets.findOne({ select: ['url'], where: { id: media } })
}

/** @private */
Expand All @@ -236,16 +262,30 @@ const LifecycleHooks = new class {
try {
return await callback(this.ceramic)
} catch (e) {
throw new ApplicationError('Ceramic Network sync failed. Please try again later...')
console.log('Error:', e)
throw new ApplicationError(
'Ceramic Network sync failed. Please try again later...'
)
}
}
}(strapi, schema, relations)
})(strapi, schema, relations)

module.exports = {
async beforeUpdate(event) {
return LifecycleHooks.onUpdate(event)
async afterUpdate(event) {
console.log('afterUpdate', event)
const {
params: { data }
} = event
// skipping if this is us just updating ceramic/orbis ids after update
const skip =
//updatedAt, orbisId, cid
Object.keys(data).length <= 3 && (data.cid || data.orbisId)
if (skip) {
console.log('skipping ids update...')
return
}
LifecycleHooks.onAfterUpdate(event)
},

// we still need to listen for delete events
// because physical removal should also unpublish
// documents from Ceramic Network
Expand Down
Loading

0 comments on commit 6b6c332

Please sign in to comment.