diff --git a/lib/boards-api.js b/lib/boards-api.js index 0a80e52..92ae8f4 100644 --- a/lib/boards-api.js +++ b/lib/boards-api.js @@ -84,15 +84,57 @@ function BoardsAPI (ipfs) { } } -BoardsAPI.prototype.createProfile = function (profile) { - console.log('creating profile') - this.ipfs.add(new Buffer(JSON.stringify(profile)), (err, res) => { - console.log('added profile to IPFS:', err, res.Hash) - var profilepath = '/ipfs/' + res.Hash - this.ipfs.files.mv([profilepath, '/ipns/local/profile.json'], (err, res) => { - console.log('mv', err, res) - }) - }) +BoardsAPI.prototype.createProfile = function (profile, done) { + console.log('Generating profile:', profile) + try { + var profile_str = JSON.stringify(profile) + } catch (e) { + console.log('Error, invalid profile:', e) + return done(e) + } + asyncjs.waterfall([ + // Create required directories + cb => this.ipfs.files.mkdir('/ipfs-boards-profile/boards', { p: true }, cb), + (e, cb) => this.ipfs.files.mkdir('/ipfs-boards-profile/comments', { p: true }, cb), + (e, cb) => this.ipfs.files.mkdir('/ipfs-boards-profile/posts', { p: true }, cb), + (e, cb) => { + // Remove old profile files if present + console.log('Removing file...') + var path = '/ipfs-boards-profile/ipfs-boards-version.txt' + this.ipfs.files.rm(path, { r: true }, res => { + console.log('Removing file...') + var path = '/ipfs-boards-profile/profile.json' + this.ipfs.files.rm(path, { r: true }, res => cb()) + }) + }, + cb => { + // Add profile version file + var path = '/ipfs-boards-profile/ipfs-boards-version.txt' + var version_hash = '/ipfs/' + this.version_hash + this.ipfs.files.cp([version_hash, path], cb) + }, + (e, cb) => { + // Serialize profile and add to IPFS + this.ipfs.add(new Buffer(profile_str), cb) + }, + (res, cb) => { + // Move profile into mfs + console.log('added profile to IPFS:', res.Hash) + var profilepath = '/ipfs/' + res.Hash + this.ipfs.files.cp([profilepath, '/ipfs-boards-profile/profile.json'], cb) + }, + (e, cb) => this.ipfs.files.stat('/', cb), + (res, cb) => { + var profile_hash = res.Hash + console.log('Publishing profile...') + this.ipfs.name.publish(profile_hash, cb) + // TODO: cb is probably never called here! Figure out why! + }, + (e, cb) => { + console.log('Done') + cb() + } + ], done) } BoardsAPI.prototype.backupCache = function () { @@ -112,6 +154,7 @@ BoardsAPI.prototype.resolveIPNS = function (n, handler) { if (err) { // Communicate error this.ee.emit('error', err) + if (handler && handler.apply) handler(undefined, err) } else { var url = r.Path if (url === undefined) { @@ -527,7 +570,7 @@ BoardsAPI.prototype.init = function (done) { this.id = res.ID this.resolveIPNS(res.ID) console.log('Version is', this.version) - this.ipfs.add(new Buffer('ipfs:boards:version:' + this.version), {n: true}, (err2, r) => { + this.ipfs.add(new Buffer(this.version), (err2, r) => { if (err2) { this.ee.emit('error', err2) console.log('Error while calculating version hash:', err2) @@ -544,7 +587,7 @@ BoardsAPI.prototype.init = function (done) { console.log('Error while getting ipfs version:', err) if (done && done.apply) done(err) } else { - this.ipfs_version = res.Version + this.ipfs_version = res.Version.split('-')[0] console.log('IPFS Version is', res.Version) if (semver.satisfies(this.ipfs_version, '~0.4.0')) { console.log('IPFS version is supported') diff --git a/webapp/app.jsx b/webapp/app.jsx index fa821e9..4ad0185 100644 --- a/webapp/app.jsx +++ b/webapp/app.jsx @@ -25,6 +25,7 @@ var Profile = require('profile.jsx')(boards) var Board = require('board.jsx')(boards) var PostPage = require('postpage.jsx')(boards) var CommentPage = require('commentpage.jsx')(boards) +var ProfileEditor = require('profile-editor.jsx')(boards) // Define Main Components @@ -91,6 +92,7 @@ ReactDOM.render( + diff --git a/webapp/pages/getipfs.jsx b/webapp/pages/getipfs.jsx index 5cdd1c6..757a767 100644 --- a/webapp/pages/getipfs.jsx +++ b/webapp/pages/getipfs.jsx @@ -57,7 +57,7 @@ module.exports = React.createClass({

Sorry, but at the moment an external application is needed to try the Prototype


Error Message
-

{this.state.error.Message || this.state.error || 'connection to go-ipfs failed'}

+

{this.state.error || 'connection to go-ipfs failed'}


You don't have an IPFS node running at {opt.addr}:{opt.port} or it is not reachable. The IPFS Boards prototype requires a full IPFS node. Please start one by following the diff --git a/webapp/pages/profile-editor.jsx b/webapp/pages/profile-editor.jsx new file mode 100644 index 0000000..0d7a08c --- /dev/null +++ b/webapp/pages/profile-editor.jsx @@ -0,0 +1,94 @@ +var React = require('react') +var GetIPFS = require('getipfs.jsx') +var Icon = require('icon.jsx') + +module.exports = function (boardsAPI) { + return React.createClass({ + getInitialState () { + return { loading: true } + }, + componentDidMount () { + boardsAPI.use(boards => { + boards.init() + boards.getEventEmitter().on('init', err => { + if (!err && this.isMounted()) { + this.init(boards) + } + }) + if (this.isMounted() && boards.isInit) { + this.init(boards) + } + }) + }, + getProfile (boards) { + boards.getProfile(boards.getMyID(), (err, p) => { + if (!this.isMounted()) return + else if (err) this.setState({ loading: false }) + else if (this.state.loading) { + // State isn't set to p directly to avoid XSS. + // There is no knowing what's gonna be in a profile + // Should also convert to string and check length etc. + this.setState({ p: p.name, description: p.description, loading: false }) + } + }) + }, + init (boards) { + if (this.state.init) return + this.setState({ api: boards }) + this.getProfile(boards) + }, + handleChange (event) { + if (event.target.id === 'name') { + this.setState({ name: event.target.value }) + } else { + this.setState({ description: event.target.value }) + } + }, + skip () { + this.setState({ loading: false }) + }, + save () { + var boards = this.state.api + var profile = { + name: this.state.name, + description: this.state.description + } + boards.createProfile(profile, err => { + console.log('CREATE:', err) + }) + }, + render () { + if (this.state.api) { + if (this.state.loading) { + return

+
+ +

Fetching your current profile...

+ +
+
+ } else { + return ( +
+

Edit Profile

+

This App uses IPFS to store your profile. When you are offline, + other users or servers that viewed your profile will serve it to + others.

+
+ + +
+
+ +