-
-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add moderation class, new cmd /moderation, and fix cmd output #50
Changes from all commits
9040636
b310474
e24c444
bd90d25
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,6 +43,14 @@ module.exports = { | |
}) | ||
} | ||
}, | ||
share: { | ||
help: () => 'print a cabal key with you as admin. useful for sending to friends', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Discussion point: do we want /share to share with you as admin, or with you + whoever is in your admin/mod-keys? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @noffle good discussion point! my reasoning was as follows: what i reckoned was that it would get so absurdly long as to be useless if we shared all the admin + modkeys, which is why i opted for sharing oneself as an admin; reasoning that would have a similar effect (at least that was what i was thinking at the time; given that the passed-in admin/modkeys don't actually issue admin/mods as statements then they won't be transitively be available) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hey! I wasn't sure where to continue this convo :) As I understand it, most people have one admin key. So a /share that used your admin keys should also just include one key, right? It feels like it might get confusing if inviting another user gives them a different moderation view than yours. |
||
call: (cabal, res, arg) => { | ||
const adminkey = `cabal://${cabal.key}?admin=${cabal.user.key}` | ||
res.info(adminkey, { data: { adminkey }}) | ||
res.end() | ||
} | ||
}, | ||
ids: { | ||
help: () => 'toggle showing ids at the end of nicks. useful for moderation', | ||
call: (cabal, res, arg) => { | ||
|
@@ -215,6 +223,36 @@ module.exports = { | |
}) | ||
} | ||
}, | ||
moderation: { | ||
help: () => 'display moderation help and commands', | ||
call: (cabal, res, arg) => { | ||
const baseCmds = ["hide", "mod", "admin"] | ||
const extraCmds = ["inspect", "ids"] | ||
const debugCmds = ["flag", "flags"] | ||
res.info("moderation commands") | ||
res.info("\nbasic actions. the basic actions will be published to your log") | ||
res.info("USAGE /<cmd> NICK{.PUBKEY} {REASON...}") | ||
baseCmds.forEach((base) => { | ||
res.info(`/${base}: ${module.exports[base].help()}`) | ||
const reverse = `un${base}` | ||
res.info(`/${reverse}: ${module.exports[reverse].help()}`) | ||
}) | ||
res.info("\nlisting applied moderation actions. local actions (i.e. not published)") | ||
baseCmds.forEach((base) => { | ||
const list = `${base}s` | ||
res.info(`/${list}: ${module.exports[list].help()}`) | ||
}) | ||
res.info("\nadditional commands. local actions") | ||
extraCmds.forEach((cmd) => { | ||
res.info(`/${cmd}: ${module.exports[cmd].help()}`) | ||
}) | ||
res.info("\ndebug commands") | ||
debugCmds.forEach((cmd) => { | ||
res.info(`/${cmd}: ${module.exports[cmd].help()}`) | ||
}) | ||
res.end() | ||
} | ||
}, | ||
hide: { | ||
help: () => 'hide a user from a channel or the whole cabal', | ||
call: (cabal, res, arg) => { | ||
|
@@ -481,50 +519,42 @@ function flagCmd (cmd, cabal, res, arg) { | |
return res.end() | ||
} | ||
id = keys[0] | ||
var fname = /^un/.test(cmd) ? 'removeFlags' : 'addFlags' | ||
var type = /^un/.test(cmd) ? 'remove' : 'add' | ||
var flag = cmd.replace(/^un/,'') | ||
cabal.core.moderation[fname]({ | ||
id, | ||
channel, | ||
flags: [flag], | ||
reason: args.slice(1).join(' ') | ||
}, (err) => { | ||
if (err) { res.error(err) } | ||
else { | ||
var reason = args.slice(1).join(' ') | ||
cabal.moderation._flagCmd(flag, type, channel, id, reason).then(() => { | ||
res.info(`${/^un/.test(cmd) ? 'removed' : 'added'} flag ${flag} for ${id}`) | ||
res.end() | ||
} | ||
}) | ||
}).catch((err) => { res.error(err) }) | ||
} | ||
|
||
function listCmd (cmd, cabal, res, arg) { | ||
var args = arg ? arg.split(/\s+/) : [] | ||
var channel = '@' | ||
pump( | ||
cabal.core.moderation.listByFlag({ flag: cmd, channel }), | ||
to.obj(write, end) | ||
) | ||
function write (row, enc, next) { | ||
if (/^[0-9a-f]{64}@\d+$/.test(row.key)) { | ||
cabal.core.getMessage(row.key, function (err, doc) { | ||
if (err) return res.error(err) | ||
res.info(Object.assign({}, row, { | ||
text: `${cmd}: ${getPeerName(cabal, row.id)}: ` | ||
|
||
cabal.moderation._listCmd(cmd, channel).then((keys) => { | ||
if (keys.length === 0) { | ||
res.info(`you don't have any ${cmd}s`) | ||
res.end() | ||
return | ||
} | ||
keys.forEach((key) => { | ||
if (/^[0-9a-f]{64}@\d+$/.test(key)) { | ||
cabal.core.getMessage(key, function (err, doc) { | ||
if (err) return res.error(err) | ||
res.info(Object.assign({}, { | ||
text: `${cmd}: ${getPeerName(cabal, key)}: ` | ||
+ (doc.timestamp ? strftime(' [%F %T] ', new Date(doc.timestamp)) : '') | ||
+ (doc.content && doc.content.reason || '') | ||
})) | ||
}) | ||
} else { | ||
res.info(Object.assign({}, { | ||
text: `${cmd}: ${getPeerName(cabal, key)}` | ||
})) | ||
}) | ||
} else { | ||
res.info(Object.assign({}, row, { | ||
text: `${cmd}: ${getPeerName(cabal, row.id)}` | ||
})) | ||
} | ||
next() | ||
} | ||
function end (next) { | ||
res.end() | ||
next() | ||
} | ||
} | ||
}) | ||
}) | ||
} | ||
|
||
function ucfirst (s) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
const pump = require('pump') | ||
const to = require('to2') | ||
|
||
class Moderation { | ||
constructor (core) { | ||
this.core = core | ||
} | ||
|
||
getAdmins (channel) { | ||
return this._listCmd('admin', channel) | ||
} | ||
|
||
getMods (channel) { | ||
return this._listCmd('mod', channel) | ||
} | ||
|
||
getHides (channel) { | ||
return this._listCmd('hide', channel) | ||
} | ||
|
||
getBlocks (channel) { | ||
return this._listCmd('block', channel) | ||
} | ||
|
||
hide (id, opts) { | ||
opts = opts || {} | ||
return this.setFlag('hide', 'add', opts.channel, id, opts.reason) | ||
} | ||
|
||
unhide (id, opts) { | ||
opts = opts || {} | ||
return this.setFlag('hide', 'remove', opts.channel, id, opts.reason) | ||
} | ||
|
||
block (id, opts) { | ||
opts = opts || {} | ||
return this.setFlag('block', 'add', opts.channel, id, opts.reason) | ||
} | ||
|
||
unblock (id, opts) { | ||
opts = opts || {} | ||
return this.setFlag('block', 'remove', opts.channel, id, opts.reason) | ||
} | ||
|
||
addAdmin (id, opts) { | ||
opts = opts || {} | ||
return this.setFlag('admin', 'add', id, opts.channel, opts.reason) | ||
} | ||
|
||
removeAdmin (id, opts) { | ||
opts = opts || {} | ||
return this.setFlag('admin', 'remove', opts.channel, id, opts.reason) | ||
} | ||
|
||
addMod (id, opts) { | ||
opts = opts || {} | ||
return this.setFlag('mod', 'add', opts.channel, id, opts.reason) | ||
} | ||
|
||
removeMod (id, opts) { | ||
opts = opts || {} | ||
return this.setFlag('mod', 'remove', opts.channel, id, opts.reason) | ||
} | ||
|
||
setFlag (flag, type, channel='@', id, reason='') { | ||
// a list of [[id, reason]] was passed in | ||
if (typeof id[Symbol.iterator] === 'function') { | ||
const promises = id.map((entry) => { return this._flagCmd(flag, type, channel, entry[0], entry[1]) }) | ||
return Promise.all(promises) | ||
} | ||
return this._flagCmd(flag, type, id, channel, reason) | ||
} | ||
|
||
_flagCmd (flag, type, channel='@', id, reason='') { | ||
const fname = (type === 'add' ? 'addFlags' : 'removeFlags') | ||
return new Promise((resolve, reject) => { | ||
this.core.moderation[fname]({ | ||
id, | ||
channel, | ||
flags: [flag], | ||
reason | ||
}, (err) => { | ||
if (err) { return reject(err) } | ||
else { resolve() } | ||
}) | ||
}) | ||
} | ||
|
||
_listCmd (cmd, channel='@') { | ||
const keys = [] | ||
return new Promise((resolve, reject) => { | ||
const write = (row, enc, next) => { | ||
keys.push(row.id) | ||
next() | ||
} | ||
const end = (next) => { | ||
next() | ||
resolve(keys) | ||
} | ||
pump( | ||
this.core.moderation.listByFlag({ flag: cmd, channel }), | ||
to.obj(write, end) | ||
) | ||
}) | ||
} | ||
} | ||
|
||
module.exports = Moderation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leftover debug output?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hehe oops :^)