Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@
/node_modules
.DS_Store
/rethinkdb_data
/src/config.json
/src/config.json
/venv
*.gz
Binary file removed rethinkdb_dump_2019-08-14T12:49:08.tar.gz
Binary file not shown.
214 changes: 124 additions & 90 deletions src/api/albums.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import xss from 'xss'
import uuid from 'uuid/v4'
import { provider } from '../lib/ethers-utils'
import escapeRegex from 'escape-string-regexp'
import { isAddress } from 'web3-utils'

// addresses that can moderate comments :)
// const whitelist = []
Expand All @@ -17,17 +18,34 @@ export default ({ config, db, io }) => {
r.table('albums')
.get(id)
.default({})
.do((doc) => {
return doc.merge({
user: r.table('users').get(doc('userAddress'))
.without('clovers', 'curationMarket').default(null)
})
})
.do(mergeUser)
.run(db, (res) => {
callback(res)
})
}

async function makeUser(userAddress) {
const modified = await provider.getBlockNumber()
var user = userTemplate(userAddress.toLowerCase())
user.created = modified
user.modified = modified

// db update
const { changes } = await r.table('users')
.insert(user, { returnChanges: true })
.run(db)
.catch((err) => {
console.error(err)
res.sendStatus(500).end()
return
})
if (changes[0]) {
user = changes[0].new_val
}
io.emit('updateUser', user)
return user
}

let router = resource({
load,
id: 'id',
Expand Down Expand Up @@ -84,12 +102,7 @@ export default ({ config, db, io }) => {
.getAll(true, { index })
.orderBy(asc ? r.asc(sort) : r.desc(sort))
.slice(start, start + pageSize)
.map((doc) => {
return doc.merge({
user: r.table('users').get(doc('userAddress'))
.without('clovers', 'curationMarket').default(null)
})
})
.map(mergeUser)
.run(db, (err, data) => {
if (err) throw new Error(err)
return data
Expand Down Expand Up @@ -134,12 +147,8 @@ export default ({ config, db, io }) => {
const { id } = req.params

const result = await r.table('albums').get(id)
.do((doc) => {
return doc.merge({
user: r.table('users').get(doc('userAddress'))
.without('clovers', 'curationMarket').default(null)
})
})
.do(mergeUser)
.do(mergeEditors)
.default({})
.run(db)
.catch((err) => {
Expand All @@ -160,12 +169,8 @@ export default ({ config, db, io }) => {
let result = await r.table('albums')
.getAll(true, { index })
.pluck('id', 'clovers', 'name', 'userAddress')
.map((doc) => {
return doc.merge({
user: r.table('users').get(doc('userAddress'))
.without('clovers', 'curationMarket').default(null)
})
}).coerceTo('array').run(db).catch((err) => {
.map(mergeUser)
.coerceTo('array').run(db).catch((err) => {
console.error(err)
res.result(500).end()
})
Expand Down Expand Up @@ -259,38 +264,18 @@ export default ({ config, db, io }) => {
res.json({ ...album, id: generated_keys[0] }).end()
})
})


async function makeUser(userAddress) {
const modified = await provider.getBlockNumber()
var user = userTemplate(userAddress.toLowerCase())
user.created = modified
user.modified = modified

// db update
const { changes } = await r.table('users')
.insert(user, { returnChanges: true })
.run(db)
.catch((err) => {
console.error(err)
res.sendStatus(500).end()
return
})
if (changes[0]) {
user = changes[0].new_val
}
io.emit('updateUser', user)
return user
}
})

// update album
router.put('/:id', async (req, res) => {
let { albumName, clovers } = req.body
let { albumName, clovers, editors } = req.body
if (!albumName || !clovers) {
return res.status(500).end()
}

const { id } = req.params

// check user
const userAddress = req.auth && req.auth.user
if (!userAddress) {
console.error("no userAddress")
Expand All @@ -314,11 +299,15 @@ export default ({ config, db, io }) => {
return res.status(401).send('Different album with that name already exists')
}

// get album
let album = await r.table('albums').get(id).run(db)
const isOwner = user.address === album.userAddress
const isEditor = album.editors && album.editors.includes(user.address)

albumName = xss(albumName)
// check if albumName was changed
if (album.name !== albumName && album.userAddress !== user.address) {
albumName = xss(albumName)
const nameChange = album.name !== albumName
if (nameChange && !isOwner) {
// cant change name of album unless you are owner
return res.status(401).send('Only owner can change name')
}
Expand All @@ -329,80 +318,114 @@ export default ({ config, db, io }) => {
return res.status(500).send(error.message)
}

// check editors
editors = (editors || []).map(ed => ed.toLowerCase())
editors = [...new Set(editors)] // de-dupe ES6
const editorsCopy = JSON.parse(JSON.stringify(album.editors || []))
const sameEditors = editors.length === editorsCopy.length && editors.every(e => editorsCopy.includes(e))

if (!sameEditors && !isOwner) {
// can't change editors unless you own the album
return res.status(401).send('Only owner can change editors')
}

if (editors.length && !editors.every(e => isAddress(e))) {
// valid ETH addr
return res.status(401).send('Editors must be a valid ETH address.')
}

if (editors.length > 4) {
// max editors
return res.status(401).send('Max 4 editors')
}

// check if any clovers were removed...
let cloversCopy = JSON.parse(JSON.stringify(album.clovers))
clovers.forEach(c => {
let i = cloversCopy.indexOf(c)
cloversCopy.splice(i, 1)
});
if (cloversCopy.length > 0 && album.userAddress !== user.address) {
// can't remove clovers unless you own the album
return res.status(401).send('Only owner can remove clovers')

if (cloversCopy.length > 0 && !(isOwner || isEditor)) {
// can't remove clovers unless you can edit
return res.status(401).send('Only editors can remove clovers')
}

// must update something
if (album.name === albumName && album.clovers.join('') === clovers.join('')) {
if (!nameChange && album.clovers.join('') === clovers.join('') && sameEditors) {
return res.status(400).send('Must update something')
}

const emitLog = nameChange || clovers.length > album.clovers.length // name change or added clover

const blockNum = await provider.getBlockNumber().catch((err) => {
debug(err.toString())
return 0
})
album.name = albumName
album.clovers = clovers
album.modified = new Date()
// update it
r.table('albums').get(id).update({
name: album.name,
clovers: album.clovers,
modified: album.modified
name: albumName,
clovers: clovers,
modified: new Date(),
editors: editors,
}).run(db, async (err, _) => {
if (err) {
console.error('db run error')
res.status(500).end()
return
}

// get updated album
album = await r.table('albums').get(id)
.do(mergeUser)
.do(mergeEditors)
.run(db)

// update the user
await r.table('users').get(user.address).update({
albumCount: r.table('albums')
.getAll(user.address, { index: 'userAddress' })
.count()
}, { nonAtomic: true }).run(db)

// emit an event pls
const log = {
id: uuid(),
name: 'Album_Updated',
removed: false,
blockNumber: blockNum,
userAddress: null, // necessary data below
data: {
id,
userAddress: user.address,
name: albumName,
board: clovers.length > 0 && clovers[0],
createdAt: new Date()
},
userAddresses: []
}
// add a log ?
if (emitLog) {
const log = {
id: uuid(),
name: 'Album_Updated',
removed: false,
blockNumber: blockNum,
userAddress: null, // necessary data below
data: {
id,
userAddress: user.address,
name: albumName,
board: clovers.length > 0 && clovers[0],
createdAt: new Date()
},
userAddresses: []
}

r.table('logs').insert(log)
.run(db, (err) => {
if (err) {
debug('album log not saved')
debug(err)
} else {
try {
io.emit('newLog', log)
} catch (error) {
console.error(error)
r.table('logs').insert(log)
.run(db, (err) => {
if (err) {
debug('album log not saved')
debug(err)
} else {
try {
io.emit('newLog', log)
} catch (error) {
console.error(error)
}
}
}
res.status(200).json({ ...album, id }).end()
})
})
res.status(200).json({ ...album, id }).end()
})

// no log
} else {
res.status(200).json({ ...album, id }).end()
}
})
})

router.delete('/:id', async (req, res) => {
Expand Down Expand Up @@ -474,6 +497,17 @@ export function albumListener (server, db) {

}

// util to add user to doc
const mergeUser = doc => doc.merge({
user: r.table('users').get(doc('userAddress'))
.without('clovers', 'curationMarket').pluck('address', 'name').default(null)
})
// util to add editors to doc
const mergeEditors = doc => doc.merge({
editorsData: r.table('users').getAll(r.args(doc('editors').default([])))
.coerceTo('array').pluck('address', 'name')
})

async function verifyClovers(clovers, db) {
const regex = /\b(0x[0-9a-fA-F]+|[0-9]+)\b/g;
clovers.forEach(c => {
Expand Down