diff --git a/lib/boards-api.js b/lib/boards-api.js index b1693a1..5c7637f 100644 --- a/lib/boards-api.js +++ b/lib/boards-api.js @@ -11,6 +11,7 @@ var EventEmitter = require('wolfy87-eventemitter') var asyncjs = require('async') function asObj(str,done){ + if(str.toString) str = str.toString() if(typeof str === 'string'){ var obj try { @@ -43,8 +44,9 @@ function replyAsObj(res,isJson,done){ done(null,data) } }) - } else { - console.log('got string:',res) + } else if(res.split || res.toString){ + console.log('got string or buffer:',res) + if(res.toString) res = res.toString() // Is a string if(isJson){ asObj(res,done) @@ -88,7 +90,7 @@ BoardsAPI.prototype.resolveIPNS = function(n,handler){ var cached = this.users[n] if(cached){ this.ee.emit(n,cached) - console.log(n,'was cached',cached) + //console.log(n,'was cached',cached) } else { console.log(n,'not cached') } @@ -178,7 +180,6 @@ BoardsAPI.prototype.searchUsers = function(){ } BoardsAPI.prototype.getProfile = function(userID,done){ - console.log('profile requested for',userID) this.resolveIPNS(userID,(url,err) => { if(err){ this.ee.emit('error',err) @@ -282,41 +283,55 @@ BoardsAPI.prototype.downloadPost = function(hash,adminID,board,op,done){ return this.ee } -BoardsAPI.prototype.getPostsInBoard = function(adminID,board){ - this.getBoardSettings(adminID,board) +BoardsAPI.prototype.retrieveListOfApproved = function(what,addr,adminID,board){ + var a = addr+this.baseurl+'boards/'+board+'/approved/'+what+'/' + this.ipfs.ls(a,(err,res) => { + if(err){ + this.ee.emit('error',err) + } else { + // Send approved posts list + var ret = res.Objects[0].Links.map(item => { + return { date: item.Name, hash: item.Hash } + }) + this.emit('approved '+what+' for '+board+'@'+adminID,ret) + } + }) +} + +BoardsAPI.prototype.getAllowedContentProducers = function(adminID,board,options){ + if(!options) return this.ee.on('settings for'+board+'@'+adminID,function(settings,addr){ - // Download posts based on settings + // Get stuff based on settings if(settings.approval_required == true){ // Get approved posts list - var a = addr+this.baseurl+'boards/'+board+'/approved/posts/' - this.ipfs.ls(a,(err,res) => { - if(err){ - this.ee.emit('error',err) - } else { - // Send approved posts list - var ret = res.Objects[0].Links.map(item => { - return { date: item.Name, hash: item.Hash } - }) - this.emit('approved posts for '+board+'@'+adminID,ret) - // Automatically download approved posts - ret.forEach(item => this.downloadPost(item.hash,adminID,board)) - } - }) + if(options.posts) this.retrieveListOfApproved('posts',addr,adminID,board) + // Get approved comments list + if(options.comments) this.retrieveListOfApproved('comments',addr,adminID,board) if(settings.whitelist == true){ - // TODO: Download all posts from whitelisted users + // TODO: emit all whitelisted users } } else if(settings.whitelist_only == true){ - // TODO: download all posts from whitelisted users + // TODO: emit all whitelisted users } else if(settings.blacklist == true){ - // TODO: get the blacklist, then start downloading posts from everyone not in the blacklist + // TODO: emit all users not in the blacklist } }) + this.getBoardSettings(adminID,board) + return this.ee +} + +BoardsAPI.prototype.getPostsInBoard = function(adminID,board){ + this.ee.on('approved posts for '+board+'@'+adminID,ret => { + // Automatically download approved posts + ret.forEach(item => this.downloadPost(item.hash,adminID,board)) + }) // Get the admin's posts this.getUserPostListInBoard(adminID,board,(err,res) => { if(err){ console.log(err) } else res.forEach(item => this.downloadPost(item.hash,adminID,board,adminID)) }) + this.getAllowedContentProducers(adminID,board,{ posts: true }) return this.ee } @@ -343,9 +358,57 @@ BoardsAPI.prototype.getUserPostListInBoard = function(user,board,done){ return this.ee } +BoardsAPI.prototype.downloadComment = function(hash,adminID,board,done){ + this.ipfs.cat(hash,(err2,r) => { + if(err2){ + this.ee.emit('error',err2) + console.log('Could not download comment',hash,'of',board+'@'+adminID) + if(done && done.apply) done(err2) + } else { + // TODO: add JSON parsing error handling + var cmnt = JSON.parse(r.toString()) + cmnt.hash = hash + this.ee.emit(hash,cmnt,adminID,board) + this.ee.emit('comment for '+cmnt.parent,cmnt) + if(done && done.apply) done(null,cmnt) + } + }) + return this.ee +} + BoardsAPI.prototype.getCommentsFor = function(parent,board,adminID){ - // Create an EventEmitter, start looking and emit an event for every new comment - // Consider the rules of @adminID#board + this.ee.on('approved comments for '+board+'@'+adminID,ret => { + ret.forEach(item => this.downloadComment(item.hash,adminID,board)) + }) + // get the admin's comments + this.getUserCommentList(parent,adminID,(err,res) => { + if(err){ + console.log(err) + } else res.forEach(item => this.downloadComment(item.hash,adminID,board)) + }) + this.getAllowedContentProducers(adminID,board,{ comments: true }) +} + +BoardsAPI.prototype.getUserCommentList = function(parent,user,done){ + this.resolveIPNS(user,(url,err) => { + if(err){ + this.ee.emit('error',err) + done(err) + } else this.ipfs.ls(url+this.baseurl+'comments/'+parent,(e,r) => { + if(e){ + this.ee.emit('error',e) + done(e) + } else if(r && !r.split){ + console.log('Found',r.Objects[0].Links.length,'comments for',parent,'at',user) + var l = r.Objects[0].Links.map(i => { + return { date: i.Name, hash: i.Hash } + }) + done(null,l) + } + }) + return true // remove myself from listeners + }) + return this.ee } // API for publishing content and managing to be done later... diff --git a/webapp/components/comment.jsx b/webapp/components/comment.jsx new file mode 100644 index 0000000..bc6767a --- /dev/null +++ b/webapp/components/comment.jsx @@ -0,0 +1,39 @@ +var React = require('react') +var Markdown = require('markdown.jsx') +var Icon = require('icon.jsx') + +module.exports = function(boardsAPI){ + var UserID = require('userID.jsx')(boardsAPI) + return React.createClass({ + getInitialState: function(){ + return { moment: false } + }, + componentDidMount: function(){ + require.ensure(['moment'],_ => { + if(this.isMounted()) this.setState({ moment: require('moment') }) + }) + }, + getDate: function(){ + if(this.props.comment.date){ + if(this.state.moment) + return this.state.moment.unix(this.props.comment.date).fromNow() + else return '...' + } else { + return 'Unknown Date' + } + }, + render: function(){ + if(this.props.comment){ + return