1
0
mirror of https://github.com/fazo96/ipfs-boards synced 2025-01-10 12:24:20 +01:00

implemented limited mode

This commit is contained in:
Enrico Fasoli 2015-12-19 17:43:55 +01:00
parent e58349f14f
commit 6bbd1377ec
9 changed files with 109 additions and 71 deletions

View File

@ -261,7 +261,10 @@ BoardsAPI.prototype.deleteComment = function (hash, parent, done) {
BoardsAPI.prototype.cat = function (path, done) { BoardsAPI.prototype.cat = function (path, done) {
if (this.limited) { if (this.limited) {
// Download via gateway // Download via gateway
if (path.indexOf('/ipfs/') !== 0) path = '/ipfs/' + path if (path.indexOf('Qm') === 0) {
path = '/ipfs/' + path
}
console.log('Downloading via Gateway: ', path)
wreck.get(path, (err, res, payload) => { wreck.get(path, (err, res, payload) => {
console.log('GET:', err, res, payload) console.log('GET:', err, res, payload)
if (payload.toString) payload = payload.toString() if (payload.toString) payload = payload.toString()
@ -291,8 +294,13 @@ BoardsAPI.prototype.backupCache = function () {
} }
// Rewrote this to use event emitters. Should also add periodic rechecking // Rewrote this to use event emitters. Should also add periodic rechecking
// TODO: maybe drop this entirely? We can cat and ls IPNS names now.
BoardsAPI.prototype.resolveIPNS = function (n, handler) { BoardsAPI.prototype.resolveIPNS = function (n, handler) {
if (handler && handler.apply) this.ee.on(n, handler) if (handler && handler.apply) this.ee.on(n, handler)
if (this.limited) {
// In limited mode, don't solve addresses
return this.ee.emit(n, '/ipns/' + n)
}
if (!this.resolvingIPNS[n]) { if (!this.resolvingIPNS[n]) {
this.resolvingIPNS[n] = true this.resolvingIPNS[n] = true
this.ipfs.name.resolve(n, (err, r) => { this.ipfs.name.resolve(n, (err, r) => {
@ -333,7 +341,7 @@ BoardsAPI.prototype.resolveIPNS = function (n, handler) {
BoardsAPI.prototype.isUserProfile = function (addr, done) { BoardsAPI.prototype.isUserProfile = function (addr, done) {
if (addr === undefined) return console.log('Asked to check if undefined is a profile') if (addr === undefined) return console.log('Asked to check if undefined is a profile')
this.ipfs.cat(addr + this.baseurl + 'ipfs-boards-version.txt', (err, r) => { this.cat(addr + this.baseurl + 'ipfs-boards-version.txt', (err, r) => {
if (err) return done(false, err) if (err) return done(false, err)
replyAsObj(r, false, (_, res) => { replyAsObj(r, false, (_, res) => {
if (!res || !res.trim) { if (!res || !res.trim) {
@ -392,7 +400,7 @@ BoardsAPI.prototype.getProfile = function (userID, done) {
done(err, null) done(err, null)
} else { } else {
// Download actual profile // Download actual profile
this.ipfs.cat(url + this.baseurl + 'profile.json', (err2, res) => { this.cat(url + this.baseurl + 'profile.json', (err2, res) => {
if (err2) { if (err2) {
this.ee.emit('error', err2) this.ee.emit('error', err2)
done(err2, null) done(err2, null)
@ -410,7 +418,7 @@ BoardsAPI.prototype.getProfile = function (userID, done) {
} }
}) })
// Get other info // Get other info
this.ipfs.ls(url + this.baseurl + 'boards/', (err2, res) => { this.ls(url + this.baseurl + 'boards/', (err2, res) => {
if (!err2) { if (!err2) {
var l = res.Objects[0].Links.map(i => { var l = res.Objects[0].Links.map(i => {
return { name: i.Name, hash: i.Hash } return { name: i.Name, hash: i.Hash }
@ -438,7 +446,7 @@ BoardsAPI.prototype.getBoardSettings = function (userID, board, done) {
this.ee.emit('error', e) this.ee.emit('error', e)
} else { } else {
var url = r + this.baseurl + 'boards/' + board + '/settings.json' var url = r + this.baseurl + 'boards/' + board + '/settings.json'
this.ipfs.cat(url, (err, resp) => { this.cat(url, (err, resp) => {
var settings var settings
try { try {
settings = JSON.parse(resp.toString()) settings = JSON.parse(resp.toString())
@ -457,7 +465,7 @@ BoardsAPI.prototype.getBoardSettings = function (userID, board, done) {
if (settings.whitelist === true) { if (settings.whitelist === true) {
// Get the whitelist // Get the whitelist
var url = r + this.baseurl + 'boards/' + board + '/whitelist' var url = r + this.baseurl + 'boards/' + board + '/whitelist'
this.ipfs.cat(url, (err, res) => { this.cat(url, (err, res) => {
if (err) { if (err) {
this.ee.emit('error', err) this.ee.emit('error', err)
// Emit an empty whitelist. // Emit an empty whitelist.
@ -479,7 +487,7 @@ BoardsAPI.prototype.getBoardSettings = function (userID, board, done) {
if (!settings.whitelist_only && !settings.approval_required && settings.blacklist === true) { if (!settings.whitelist_only && !settings.approval_required && settings.blacklist === true) {
// Get the blacklist // Get the blacklist
var u = r + this.baseurl + 'boards/' + board + '/blacklist' var u = r + this.baseurl + 'boards/' + board + '/blacklist'
this.ipfs.cat(u, (err, blacklist) => { this.cat(u, (err, blacklist) => {
if (err) { if (err) {
this.ee.emit('error', err) this.ee.emit('error', err)
} else { } else {
@ -510,7 +518,7 @@ BoardsAPI.prototype.downloadPost = function (hash, adminID, board, op, done) {
done = op done = op
op = undefined op = undefined
} }
this.ipfs.cat(hash, (err2, r) => { this.cat(hash, (err2, r) => {
if (err2) { if (err2) {
this.ee.emit('error', err2) this.ee.emit('error', err2)
console.log('Could not download post', hash, 'of', board + '@' + adminID) console.log('Could not download post', hash, 'of', board + '@' + adminID)
@ -537,7 +545,7 @@ BoardsAPI.prototype.downloadPost = function (hash, adminID, board, op, done) {
BoardsAPI.prototype.retrieveListOfApproved = function (what, addr, adminID, board) { BoardsAPI.prototype.retrieveListOfApproved = function (what, addr, adminID, board) {
var a = addr + this.baseurl + 'boards/' + board + '/approved/' + what + '/' var a = addr + this.baseurl + 'boards/' + board + '/approved/' + what + '/'
this.ipfs.ls(a, (err, res) => { this.ls(a, (err, res) => {
if (err) { if (err) {
this.ee.emit('error', err) this.ee.emit('error', err)
} else { } else {
@ -609,7 +617,7 @@ BoardsAPI.prototype.getUserPostListInBoard = function (user, board, done) {
this.ee.emit('error', err) this.ee.emit('error', err)
done(err) done(err)
} else { } else {
this.ipfs.ls(url + this.baseurl + 'posts/' + board, (e, r) => { this.ls(url + this.baseurl + 'posts/' + board, (e, r) => {
if (e) { if (e) {
this.ee.emit('error', e) this.ee.emit('error', e)
done(e) done(e)
@ -634,7 +642,7 @@ BoardsAPI.prototype.downloadComment = function (hash, adminID, board, target, do
target = undefined target = undefined
} }
console.log('target', target) console.log('target', target)
this.ipfs.cat(hash, (err2, r) => { this.cat(hash, (err2, r) => {
if (err2) { if (err2) {
this.ee.emit('error', err2) this.ee.emit('error', err2)
console.log('Could not download comment', hash, 'of', board + '@' + adminID) console.log('Could not download comment', hash, 'of', board + '@' + adminID)
@ -660,7 +668,7 @@ BoardsAPI.prototype.getCommentsFor = function (parent, board, adminID, target) {
return console.log('malformed arguments:', parent, board, adminID) return console.log('malformed arguments:', parent, board, adminID)
} }
// figure out if there's a previous version of the item // figure out if there's a previous version of the item
this.ipfs.cat(parent, (err, res) => { this.cat(parent, (err, res) => {
if (err) { if (err) {
this.ee.emit('error', err) this.ee.emit('error', err)
} else { } else {
@ -706,7 +714,7 @@ BoardsAPI.prototype.getUserCommentList = function (parent, user, done) {
this.ee.emit('error', err) this.ee.emit('error', err)
done(err) done(err)
} else { } else {
this.ipfs.ls(url + this.baseurl + 'comments/' + parent, (e, r) => { this.ls(url + this.baseurl + 'comments/' + parent, (e, r) => {
if (e) { if (e) {
this.ee.emit('error', e) this.ee.emit('error', e)
done(e) done(e)
@ -728,7 +736,7 @@ BoardsAPI.prototype.getUserCommentList = function (parent, user, done) {
BoardsAPI.prototype.isRunningFromGateway = function () { BoardsAPI.prototype.isRunningFromGateway = function () {
if (!window) return false if (!window) return false
return window.location.pathname.indexOf('/ipfs/') === 0 return window.location.pathname.indexOf('/ipfs/') === 0 || window.location.pathname.indexOf('/ipns/') === 0
} }
BoardsAPI.prototype.isNode = function () { BoardsAPI.prototype.isNode = function () {

View File

@ -53,29 +53,40 @@ var Comments = React.createClass({
return { comments: [] } return { comments: [] }
}, },
componentDidMount () { componentDidMount () {
var boards = this.props.api if (this.props.api) this.init(this.props.api)
if (boards) { },
boards.getEventEmitter().on('comment for ' + this.props.parent, cmnt => { componentWillReceiveProps (props) {
if (this.isMounted()) this.setState({ comments: this.state.comments.concat(cmnt) }) if (props.api) this.init(props.api)
}) },
if (boards.isInit && this.isMounted()) { init (boards) {
boards.getEventEmitter().on('comment for ' + this.props.parent, cmnt => {
if (this.isMounted()) this.setState({ comments: this.state.comments.concat(cmnt) })
})
boards.getEventEmitter().on('init', (err, limited) => {
if (!this.isMounted()) return
if (!err) {
boards.getCommentsFor(this.props.parent, this.props.board, this.props.adminID) boards.getCommentsFor(this.props.parent, this.props.board, this.props.adminID)
} }
boards.getEventEmitter().on('init', err => { if (limited) this.setState({ limited })
if (!err && this.isMounted()) { })
boards.getCommentsFor(this.props.parent, this.props.board, this.props.adminID) if (boards.isInit) {
} boards.getCommentsFor(this.props.parent, this.props.board, this.props.adminID)
})
} }
if (boards.limited) this.setState({ limited: true })
}, },
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 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 () {
return <div className={this.props.className + ' comments'} >{this.getComments()}</div> if (this.state.limited) {
return <div className="text-center">
<p>Comments can't be displayed in limited mode</p>
</div>
} else {
return <div className={this.props.className + ' comments'} >{this.getComments()}</div>
}
} }
}) })

View File

@ -10,12 +10,12 @@ module.exports = function (boardsAPI) {
componentDidMount () { componentDidMount () {
boardsAPI.use(boards => { boardsAPI.use(boards => {
if (boards.isInit) this.setState({ api: true, userid: boards.getMyID() }) if (boards.isInit) this.setState({ api: true, userid: boards.getMyID() })
boards.getEventEmitter().on('init', err => { boards.getEventEmitter().on('init', (err, limited) => {
if (!this.isMounted()) return if (!this.isMounted()) return
if (err) { if (err) {
this.setState({ loading: false, api: false }) this.setState({ loading: false, api: false, limited })
} else { } else {
this.setState({ api: true, userid: boards.getMyID() }) this.setState({ api: true, userid: boards.getMyID(), limited })
} }
}) })
}) })
@ -28,6 +28,8 @@ module.exports = function (boardsAPI) {
</span> </span>
} else if (this.state.loading) { } else if (this.state.loading) {
return <Icon name="refresh" className="fa-2x fa-spin light"/> return <Icon name="refresh" className="fa-2x fa-spin light"/>
} else if (this.state.limited) {
return <Link className="nounderline" to="/status"><Icon name="exclamation-triangle" className="fa-2x light"/></Link>
} else { } else {
return <Link className="nounderline" to="/status"><Icon name="ban" className="fa-2x light"/></Link> return <Link className="nounderline" to="/status"><Icon name="ban" className="fa-2x light"/></Link>
} }

View File

@ -5,6 +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
module.exports = React.createClass({ module.exports = React.createClass({
getInitialState () { getInitialState () {
@ -12,10 +13,10 @@ module.exports = React.createClass({
}, },
componentDidMount () { componentDidMount () {
if (this.props.api) { if (this.props.api) {
this.props.api.getEventEmitter().on('init', err => { this.props.api.getEventEmitter().on('init', (err, limited) => {
if (!err) this.init(this.props) if (!err || limited) this.init(this.props)
}) })
if (this.props.api.isInit) this.init(this.props) if (this.props.api.isInit || this.props.api.limited) this.init(this.props)
} }
}, },
componentWillReceiveProps (props) { componentWillReceiveProps (props) {
@ -80,6 +81,9 @@ module.exports = React.createClass({
} }
}, },
render () { render () {
return <div className="post">{this.getContent()}</div> return <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} />
</div>
} }
}) })

View File

@ -5,7 +5,7 @@ var Post = require('post.jsx')
module.exports = React.createClass({ module.exports = React.createClass({
getInitialState () { getInitialState () {
return { posts: [], api: false } return { posts: [] }
}, },
sortFn (a, b) { sortFn (a, b) {
return (b.date || 0) - (a.date || 0) return (b.date || 0) - (a.date || 0)
@ -16,9 +16,6 @@ module.exports = React.createClass({
} }
}, },
init (boards, props) { init (boards, props) {
if (this.state.init) return
props = props || this.props
this.setState({ api: true })
var onPost = (hash, date, post) => { var onPost = (hash, date, post) => {
if (!this.isMounted()) return true if (!this.isMounted()) return true
var now = (new Date()).getTime() var now = (new Date()).getTime()
@ -33,18 +30,29 @@ module.exports = React.createClass({
}*/ }*/
this.setState({ posts }) this.setState({ posts })
} }
props = props || this.props
boards.getEventEmitter().on('post in ' + props.board + (props.admin ? '@' + props.admin : ''), onPost) boards.getEventEmitter().on('post in ' + props.board + (props.admin ? '@' + props.admin : ''), onPost)
boards.getPostsInBoard(props.admin, props.board) this.setState({ api: boards, limited: boards.limited })
this.setState({ init: true }) if (boards.isInit) {
boards.getPostsInBoard(props.admin, props.board)
} else {
boards.getEventEmitter().on('init', (err, limited) => {
if (!err) {
boards.getPostsInBoard(props.admin, props.board)
} else {
this.setState({ limited })
}
})
}
}, },
componentDidMount () { componentDidMount () {
var boards = this.props.api var boards = this.props.api
if (boards) { if (boards) {
if (boards.isInit) { if (boards.isInit || boards.limited) {
this.init(boards) this.init(boards)
} else { } else {
boards.getEventEmitter().on('init', err => { boards.getEventEmitter().on('init', (err, limited) => {
if (!err && this.isMounted()) this.init(boards) if ((!err || limited) && this.isMounted()) this.init(boards)
}) })
} }
} }
@ -61,10 +69,15 @@ module.exports = React.createClass({
} }
}, },
render () { render () {
return ( if (this.state.limited) {
<div className="postList"> return <div className="text-center">
<h5 className="light"><Icon name="ban" /></h5>
<p>Posts in a board can't be shown in limited mode. Sorry!</p>
</div>
} else {
return <div className="postList">
{this.getPosts()} {this.getPosts()}
</div> </div>
) }
} }
}) })

View File

@ -16,10 +16,12 @@ module.exports = React.createClass({
props = props || this.props props = props || this.props
var boards = props.api var boards = props.api
if (boards) { if (boards) {
boards.getEventEmitter().on('init', err => { boards.getEventEmitter().on('init', (err, limited) => {
if (!err && this.isMounted()) this.getProfile(boards) if ((!err || limited) && this.isMounted()) {
this.getProfile(boards)
}
}) })
if (boards.isInit) { if (boards.isInit || boards.limited) {
this.getProfile(boards) this.getProfile(boards)
} }
} }

View File

@ -16,8 +16,8 @@ module.exports = function (boardsAPI) {
boardsAPI.use(boards => { boardsAPI.use(boards => {
if (!this.isMounted()) return if (!this.isMounted()) return
var ee = boards.getEventEmitter() var ee = boards.getEventEmitter()
ee.on('init', err => { ee.on('init', (err, limited) => {
if (!err && this.isMounted()) { if ((!err || limited) && this.isMounted()) {
this.init(boards) this.init(boards)
} }
}) })
@ -46,13 +46,17 @@ module.exports = function (boardsAPI) {
var props = newProps || this.props var props = newProps || this.props
if (!props.params.userid) return if (!props.params.userid) return
boards.getBoardSettings(props.params.userid, props.params.boardname) boards.getBoardSettings(props.params.userid, props.params.boardname)
this.setState({ loading: true, init: true, api: true, userid: boards.getMyID(), boards: boards }) this.setState({ loading: true, init: true, api: boards, userid: boards.getMyID(), limited: boards.limited })
}, },
toolbox () { toolbox () {
return <div className="iconbar text-center"> if (this.state.limited) {
<Link to={'/edit/board/' + this.props.params.boardname} ><Icon name="edit" className="fa-2x light" /></Link> return <div className="text-center">Toolbox not available in limited mode<hr/></div>
<Link to={'/edit/board/' + this.props.params.boardname + '/post'} ><Icon name="plus" className="fa-2x light" /></Link> } else {
</div> return <div className="iconbar text-center">
<Link to={'/edit/board/' + this.props.params.boardname} ><Icon name="edit" className="fa-2x light" /></Link>
<Link to={'/edit/board/' + this.props.params.boardname + '/post'} ><Icon name="plus" className="fa-2x light" /></Link>
</div>
}
}, },
render () { render () {
if (this.state.api) { if (this.state.api) {
@ -66,16 +70,16 @@ module.exports = function (boardsAPI) {
return (<div className="board"> return (<div className="board">
<h2>{this.state.name}</h2> <h2>{this.state.name}</h2>
<Markdown source={this.state.description} skipHtml={true} /> <Markdown source={this.state.description} skipHtml={true} />
{this.props.params.userid ? <h5><UserID id={this.props.params.userid} api={this.state.boards} /></h5> : <p></p>} {this.props.params.userid ? <h5><UserID id={this.props.params.userid} api={this.state.api} /></h5> : <p></p>}
<div className="whitelist"> <div className="whitelist">
{this.state.whitelist.map(i => <UserID id={i} key={i} api={this.state.boards} />)} {this.state.whitelist.map(i => <UserID id={i} key={i} api={this.state.api} />)}
</div> </div>
<hr /> <hr />
{this.toolbox()} {this.toolbox()}
<PostList board={this.props.params.boardname} admin={this.props.params.userid} api={this.state.boards} /> <PostList board={this.props.params.boardname} admin={this.props.params.userid} api={this.state.api} />
</div>) </div>)
} }
} else return <GetIPFS api={this.state.boards} /> } else return <GetIPFS api={this.state.api} />
} }
}) })
} }

View File

@ -3,7 +3,6 @@ var Link = require('react-router').Link
var UserID = require('userID.jsx') var UserID = require('userID.jsx')
var GetIPFS = require('getipfs.jsx') var GetIPFS = require('getipfs.jsx')
var Post = require('post.jsx') var Post = require('post.jsx')
var Comments = require('comment.jsx').Comments
module.exports = function (boardsAPI) { module.exports = function (boardsAPI) {
return React.createClass({ return React.createClass({
@ -31,7 +30,6 @@ module.exports = function (boardsAPI) {
{this.getContext()} {this.getContext()}
</div> </div>
<Post hash={this.props.params.posthash} board={this.props.params.boardname} api={this.state.api} /> <Post hash={this.props.params.posthash} board={this.props.params.boardname} api={this.state.api} />
<Comments parent={this.props.params.posthash} board={this.props.params.boardname} adminID={this.props.params.userid} post={this.props.params.posthash} api={this.state.boards} />
</div> </div>
} else { } else {
return <GetIPFS api={this.state.boards} /> return <GetIPFS api={this.state.boards} />

View File

@ -12,12 +12,12 @@ module.exports = function (boardsAPI) {
}, },
componentDidMount () { componentDidMount () {
boardsAPI.use(boards => { boardsAPI.use(boards => {
if (boards.isInit) { if (boards.isInit || boards.limited) {
this.init(boards) this.init(boards)
} }
var ee = boards.getEventEmitter() var ee = boards.getEventEmitter()
ee.on('init', err => { ee.on('init', (err, limited) => {
if (!err && this.isMounted()) { if ((!err || limited) && this.isMounted()) {
this.init(boards) this.init(boards)
} }
}) })
@ -30,10 +30,8 @@ module.exports = function (boardsAPI) {
downloadProfile (boards, props) { downloadProfile (boards, props) {
var ee = boards.getEventEmitter() var ee = boards.getEventEmitter()
var uid = props.params.userid var uid = props.params.userid
if (uid === 'me') uid = boards.id
ee.on('boards for ' + uid, l => { ee.on('boards for ' + uid, l => {
var u2id = props.params.userid var u2id = props.params.userid
if (u2id === 'me') u2id = boards.id
if (!this.isMounted() || u2id !== uid) return true if (!this.isMounted() || u2id !== uid) return true
this.setState({ boards: l }) this.setState({ boards: l })
}) })
@ -48,12 +46,11 @@ module.exports = function (boardsAPI) {
}, },
init (boards) { init (boards) {
if (this.state.init) return if (this.state.init) return
this.setState({ init: true, api: boards, id: boards.id }) this.setState({ init: true, api: boards, id: boards.id, limited: boards.limited })
this.downloadProfile(boards, this.props) this.downloadProfile(boards, this.props)
}, },
linkToEditor () { linkToEditor () {
var uid = this.props.params.userid var uid = this.props.params.userid
if (uid === 'me' && this.state.id) uid = this.state.id
if (uid === this.state.id) { if (uid === this.state.id) {
return <div className="your-profile"> return <div className="your-profile">
<h6>This is your profile</h6> <h6>This is your profile</h6>
@ -76,7 +73,6 @@ module.exports = function (boardsAPI) {
return <Loading title="Downloading Profile">{this.getEditButton()}</Loading> return <Loading title="Downloading Profile">{this.getEditButton()}</Loading>
} else { } else {
var uid = this.props.params.userid var uid = this.props.params.userid
if (uid === 'me') uid = this.state.id
return (<div className="profile"> return (<div className="profile">
{this.linkToEditor()} {this.linkToEditor()}
<h1>{this.state.name}</h1> <h1>{this.state.name}</h1>