mirror of
https://github.com/fazo96/ipfs-boards
synced 2025-03-12 21:48:39 +01:00
implemented writing comments
This commit is contained in:
parent
fb9e3db821
commit
047dad1c4c
@ -207,6 +207,48 @@ BoardsAPI.prototype.createPost = function (post, board, done) {
|
|||||||
}
|
}
|
||||||
], done)
|
], done)
|
||||||
}
|
}
|
||||||
|
BoardsAPI.prototype.createComment = function (comment, parent, done) {
|
||||||
|
try {
|
||||||
|
comment.date = parseInt((new Date()).getTime() / 1000, 10)
|
||||||
|
comment.op = this.id
|
||||||
|
comment.parent = parent
|
||||||
|
var comment_str = JSON.stringify(comment)
|
||||||
|
} catch (e) {
|
||||||
|
console.log('Error, invalid Post:', e)
|
||||||
|
return done(e)
|
||||||
|
}
|
||||||
|
if (!comment.text) return done('empty comment')
|
||||||
|
console.log('Commenting:', comment)
|
||||||
|
var dest = '/ipfs-boards-profile/comments/' + parent + '/' + comment.date + '.json'
|
||||||
|
var commenthash
|
||||||
|
asyncjs.waterfall([
|
||||||
|
// Create required directories
|
||||||
|
cb => this.ipfs.files.mkdir('/ipfs-boards-profile/comments/' + parent + '/', { p: true }, cb),
|
||||||
|
(e, cb) => {
|
||||||
|
// Remove old comment file if present
|
||||||
|
this.ipfs.files.rm(dest, { r: true }, res => cb())
|
||||||
|
},
|
||||||
|
(cb) => {
|
||||||
|
// Serialize comment and add to IPFS
|
||||||
|
this.ipfs.add(new Buffer(comment_str), cb)
|
||||||
|
},
|
||||||
|
(res, cb) => {
|
||||||
|
// Move post into mfs
|
||||||
|
console.log('added Comment to IPFS:', res.Hash)
|
||||||
|
commenthash = res.Hash
|
||||||
|
var spath = '/ipfs/' + res.Hash
|
||||||
|
this.ipfs.files.cp([spath, dest], 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, err => {
|
||||||
|
done(err, commenthash)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
], done)
|
||||||
|
}
|
||||||
|
|
||||||
BoardsAPI.prototype.delete = function (opts, done) {
|
BoardsAPI.prototype.delete = function (opts, done) {
|
||||||
var url = '/ipfs-boards-profile/'
|
var url = '/ipfs-boards-profile/'
|
||||||
|
@ -4,6 +4,62 @@ var Icon = require('icon.jsx')
|
|||||||
var Clock = require('clock.jsx')
|
var Clock = require('clock.jsx')
|
||||||
var Link = require('react-router').Link
|
var Link = require('react-router').Link
|
||||||
var UserID = require('userID.jsx')
|
var UserID = require('userID.jsx')
|
||||||
|
var { Error, Success } = require('status-components.jsx')
|
||||||
|
|
||||||
|
var CommentEditor = React.createClass({
|
||||||
|
getInitialState () {
|
||||||
|
return { }
|
||||||
|
},
|
||||||
|
componentDidMount () {
|
||||||
|
this.init(this.props)
|
||||||
|
},
|
||||||
|
componentWillReceiveProps (props) {
|
||||||
|
this.init(props)
|
||||||
|
},
|
||||||
|
init (props) {
|
||||||
|
this.setState({ api: props.api })
|
||||||
|
},
|
||||||
|
handleChange (event) {
|
||||||
|
var obj = {}
|
||||||
|
obj[event.target.id] = event.target.value
|
||||||
|
this.setState(obj)
|
||||||
|
},
|
||||||
|
save () {
|
||||||
|
var boards = this.props.api
|
||||||
|
var comment = { text: this.state.text }
|
||||||
|
this.setState({ loading: true })
|
||||||
|
boards.createComment(comment, this.props.parent, (err, hash) => {
|
||||||
|
if (err) {
|
||||||
|
this.setState({ loading: false, error: err })
|
||||||
|
} else {
|
||||||
|
this.setState({ loading: false, success: true, hash })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
render () {
|
||||||
|
if (this.state.error) {
|
||||||
|
return <Error error={this.state.error} />
|
||||||
|
} else if (this.state.loading) {
|
||||||
|
return <div className="center-block text-center find-content">
|
||||||
|
<Icon name="refresh" className="fa-3x center-block light fa-spin" />
|
||||||
|
<h4>Publishing Comment</h4>
|
||||||
|
</div>
|
||||||
|
} else if (this.state.success) {
|
||||||
|
var url = '/@' + this.props.adminID + '/' + this.props.board + '/' + (this.props.post || this.props.parent) + '/' + this.state.hash
|
||||||
|
return <Success title="Comment Published">
|
||||||
|
<Link className="button button-primary" to={url}>View</Link>
|
||||||
|
</Success>
|
||||||
|
} else {
|
||||||
|
return <div>
|
||||||
|
<textarea className="u-full-width" id="text" value={this.state.text} onChange={this.handleChange} placeholder="Speak your mind! Markdown is supported." />
|
||||||
|
<p><b>Note</b>: this version of the app doesn't check wether you are allowed to post on this board, so there are no guarantees that your post will be visible.</p>
|
||||||
|
<div className="buttons">
|
||||||
|
<button className="button button-primary" onClick={this.save}>Send</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
var Comment = React.createClass({
|
var Comment = React.createClass({
|
||||||
getInitialState () {
|
getInitialState () {
|
||||||
@ -29,7 +85,10 @@ var Comment = React.createClass({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
getComments () {
|
getComments () {
|
||||||
return <Comments className="shifted" parent={this.props.comment.hash} post={this.props.post} adminID={this.props.adminID} board={this.props.board} api={this.props.api} />
|
return <Comments className="shifted" allowReply={this.props.allowReply} parent={this.props.comment.hash} post={this.props.post} adminID={this.props.adminID} board={this.props.board} api={this.props.api} />
|
||||||
|
},
|
||||||
|
toggleReply () {
|
||||||
|
this.setState({ reply: !this.state.reply })
|
||||||
},
|
},
|
||||||
render () {
|
render () {
|
||||||
if (this.props.comment) {
|
if (this.props.comment) {
|
||||||
@ -38,9 +97,15 @@ var Comment = React.createClass({
|
|||||||
<UserID id={this.props.comment.op} api={this.props.api} />
|
<UserID id={this.props.comment.op} api={this.props.api} />
|
||||||
<Clock date={this.props.comment.date} />
|
<Clock date={this.props.comment.date} />
|
||||||
{this.getPermalink()}
|
{this.getPermalink()}
|
||||||
|
{ this.props.allowReply
|
||||||
|
? <a className="nounderline" onClick={this.toggleReply}><Icon className="not-first" name="reply" /> Reply</a>
|
||||||
|
: <a/> }
|
||||||
{this.getParentlink()}
|
{this.getParentlink()}
|
||||||
</div>
|
</div>
|
||||||
<Markdown source={this.props.comment.text} />
|
<Markdown source={this.props.comment.text} />
|
||||||
|
{ this.state.reply
|
||||||
|
? <CommentEditor parent={this.props.comment.hash} post={this.props.post} api={this.props.api} adminID={this.props.adminID} board={this.props.board} />
|
||||||
|
: <div/>}
|
||||||
<hr/>{this.getComments()}</div>
|
<hr/>{this.getComments()}</div>
|
||||||
} else {
|
} else {
|
||||||
return <div><hr/>Invalid Comment<hr/></div>
|
return <div><hr/>Invalid Comment<hr/></div>
|
||||||
@ -56,7 +121,7 @@ var Comments = React.createClass({
|
|||||||
if (this.props.api) this.init(this.props.api)
|
if (this.props.api) this.init(this.props.api)
|
||||||
},
|
},
|
||||||
componentWillReceiveProps (props) {
|
componentWillReceiveProps (props) {
|
||||||
if (props.api) this.init(props.api)
|
if (props.api !== this.props.api) this.init(props.api)
|
||||||
},
|
},
|
||||||
init (boards) {
|
init (boards) {
|
||||||
boards.getEventEmitter().on('comment for ' + this.props.parent, cmnt => {
|
boards.getEventEmitter().on('comment for ' + this.props.parent, cmnt => {
|
||||||
@ -76,7 +141,7 @@ var Comments = React.createClass({
|
|||||||
},
|
},
|
||||||
getComments () {
|
getComments () {
|
||||||
if (this.state.comments.length > 0) {
|
if (this.state.comments.length > 0) {
|
||||||
return this.state.comments.map(cmnt => (<Comment key={cmnt.hash} comment={cmnt} post={this.props.post} adminID={this.props.adminID} board={this.props.board} api={this.props.api} />))
|
return this.state.comments.map(cmnt => (<Comment allowReply={this.props.allowReply} key={cmnt.hash} comment={cmnt} post={this.props.post} adminID={this.props.adminID} board={this.props.board} api={this.props.api} />))
|
||||||
} else return <div></div>
|
} else return <div></div>
|
||||||
},
|
},
|
||||||
render () {
|
render () {
|
||||||
@ -90,4 +155,4 @@ var Comments = React.createClass({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
module.exports = { Comment, Comments }
|
module.exports = { Comment, Comments, CommentEditor }
|
||||||
|
@ -5,7 +5,7 @@ var Link = require('react-router').Link
|
|||||||
var Clock = require('clock.jsx')
|
var Clock = require('clock.jsx')
|
||||||
var UserID = require('userID.jsx')
|
var UserID = require('userID.jsx')
|
||||||
var { Error } = require('status-components.jsx')
|
var { Error } = require('status-components.jsx')
|
||||||
var Comments = require('comment.jsx').Comments
|
var { Comments, CommentEditor } = require('comment.jsx')
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
getInitialState () {
|
getInitialState () {
|
||||||
@ -54,6 +54,9 @@ module.exports = React.createClass({
|
|||||||
}
|
}
|
||||||
} else return <span/>
|
} else return <span/>
|
||||||
},
|
},
|
||||||
|
toggleReply () {
|
||||||
|
this.setState({ reply: !this.state.reply })
|
||||||
|
},
|
||||||
getContent () {
|
getContent () {
|
||||||
if (this.state.error) {
|
if (this.state.error) {
|
||||||
return <Error className="content" error={this.state.error} />
|
return <Error className="content" error={this.state.error} />
|
||||||
@ -75,6 +78,9 @@ module.exports = React.createClass({
|
|||||||
<UserID id={this.state.post.op} api={this.props.api} ></UserID>
|
<UserID id={this.state.post.op} api={this.props.api} ></UserID>
|
||||||
<Clock className="not-first" date={this.state.post.date} />
|
<Clock className="not-first" date={this.state.post.date} />
|
||||||
<Icon name="comments" className="not-first" /> <Link className="nounderline" to={this.postLink()}>View</Link>
|
<Icon name="comments" className="not-first" /> <Link className="nounderline" to={this.postLink()}>View</Link>
|
||||||
|
{ this.props.allowReply
|
||||||
|
? <a className="nounderline" onClick={this.toggleReply}><Icon className="not-first" name="reply" /> Reply</a>
|
||||||
|
: <span/>}
|
||||||
{this.editorLink()}
|
{this.editorLink()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -83,7 +89,10 @@ module.exports = React.createClass({
|
|||||||
render () {
|
render () {
|
||||||
return <div>
|
return <div>
|
||||||
<div className="post">{this.getContent()}</div>
|
<div className="post">{this.getContent()}</div>
|
||||||
<Comments parent={this.props.hash} post={this.props.hash} api={this.props.api} adminID={this.props.adminID} board={this.props.board} />
|
{ this.state.reply
|
||||||
|
? <CommentEditor parent={this.props.hash} api={this.props.api} adminID={this.props.adminID} board={this.props.board} />
|
||||||
|
: <div/>}
|
||||||
|
<Comments allowReply={this.props.allowReply} parent={this.props.hash} post={this.props.hash} api={this.props.api} adminID={this.props.adminID} board={this.props.board} />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -12,7 +12,6 @@ module.exports = function (boardsAPI) {
|
|||||||
},
|
},
|
||||||
componentDidMount: function () {
|
componentDidMount: function () {
|
||||||
boardsAPI.use(boards => {
|
boardsAPI.use(boards => {
|
||||||
boards.init()
|
|
||||||
boards.getEventEmitter().on('init', err => {
|
boards.getEventEmitter().on('init', err => {
|
||||||
if (!err && this.isMounted()) {
|
if (!err && this.isMounted()) {
|
||||||
this.init(boards)
|
this.init(boards)
|
||||||
@ -24,7 +23,9 @@ module.exports = function (boardsAPI) {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
componentWillReceiveProps: function (nextProps) {
|
componentWillReceiveProps: function (nextProps) {
|
||||||
|
if (this.props.params !== nextProps.params) {
|
||||||
boardsAPI.use(boards => this.downloadComment(boards, nextProps))
|
boardsAPI.use(boards => this.downloadComment(boards, nextProps))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
downloadComment: function (boards, props) {
|
downloadComment: function (boards, props) {
|
||||||
this.setState({ comment: false })
|
this.setState({ comment: false })
|
||||||
@ -33,14 +34,19 @@ module.exports = function (boardsAPI) {
|
|||||||
this.setState({
|
this.setState({
|
||||||
comment: { title: 'Error', text: err.Message || err.Error }
|
comment: { title: 'Error', text: err.Message || err.Error }
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
if (!comment.parent && comment.text) {
|
||||||
|
// Redirect to post page
|
||||||
|
this.props.history.push('/@' + this.props.params.userid + '/' + this.props.params.boardname + '/' + this.props.params.commenthash)
|
||||||
} else {
|
} else {
|
||||||
this.setState({ comment })
|
this.setState({ comment })
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
init: function (boards) {
|
init: function (boards) {
|
||||||
if (this.state.init) return
|
if (this.state.init) return
|
||||||
this.setState({ api: true, boards: boards })
|
this.setState({ api: true, boards, canReply: boards.isInit && !boards.limited })
|
||||||
this.downloadComment(boards, this.props)
|
this.downloadComment(boards, this.props)
|
||||||
},
|
},
|
||||||
getContext: function () {
|
getContext: function () {
|
||||||
@ -54,7 +60,7 @@ module.exports = function (boardsAPI) {
|
|||||||
},
|
},
|
||||||
showComment: function () {
|
showComment: function () {
|
||||||
if (this.state.comment) {
|
if (this.state.comment) {
|
||||||
return <Comment comment={this.state.comment} post={this.props.params.posthash} adminID={this.props.params.userid} board={this.props.params.boardname} showParent={true} api={this.state.boards} />
|
return <Comment canReply={this.state.canReply} comment={this.state.comment} post={this.props.params.posthash} adminID={this.props.params.userid} board={this.props.params.boardname} showParent={true} api={this.state.boards} />
|
||||||
} else {
|
} else {
|
||||||
return <div className="center-block text-center find-content">
|
return <div className="center-block text-center find-content">
|
||||||
<Icon name="refresh" className="fa-3x center-block light fa-spin" />
|
<Icon name="refresh" className="fa-3x center-block light fa-spin" />
|
||||||
|
@ -11,7 +11,10 @@ module.exports = function (boardsAPI) {
|
|||||||
},
|
},
|
||||||
componentDidMount: function () {
|
componentDidMount: function () {
|
||||||
boardsAPI.use(boards => {
|
boardsAPI.use(boards => {
|
||||||
this.setState({ api: boards })
|
this.setState({ api: boards, allowReply: boards.isInit && !boards.limited })
|
||||||
|
boards.getEventEmitter().on('init', (err, limited) => {
|
||||||
|
this.setState({ api: boards, allowReply: !err && !limited })
|
||||||
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getContext: function () {
|
getContext: function () {
|
||||||
@ -29,7 +32,7 @@ module.exports = function (boardsAPI) {
|
|||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
{this.getContext()}
|
{this.getContext()}
|
||||||
</div>
|
</div>
|
||||||
<Post hash={this.props.params.posthash} board={this.props.params.boardname} api={this.state.api} adminID={this.props.params.userid} />
|
<Post allowReply={true} hash={this.props.params.posthash} board={this.props.params.boardname} api={this.state.api} adminID={this.props.params.userid} />
|
||||||
</div>
|
</div>
|
||||||
} else {
|
} else {
|
||||||
return <GetIPFS api={this.state.boards} />
|
return <GetIPFS api={this.state.boards} />
|
||||||
|
@ -14,6 +14,7 @@ hr {
|
|||||||
a {
|
a {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
color: #ababab;
|
color: #ababab;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nounderline {
|
.nounderline {
|
||||||
|
Loading…
Reference in New Issue
Block a user