mirror of
https://github.com/LBRYFoundation/curate.git
synced 2025-08-23 17:37:25 +00:00
Compare commits
No commits in common. "master" and "0.1" have entirely different histories.
32 changed files with 1187 additions and 1752 deletions
10
.github/workflows/eslint.yml
vendored
10
.github/workflows/eslint.yml
vendored
|
@ -12,11 +12,11 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
- name: Install Node v18
|
- name: Install Node v12
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 12.x
|
||||||
- name: Install Yarn
|
- name: Install Yarn
|
||||||
run: npm install -g yarn
|
run: npm install -g yarn
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
@ -24,7 +24,7 @@ jobs:
|
||||||
- name: Run ESLint
|
- name: Run ESLint
|
||||||
run: yarn run eslint:fix
|
run: yarn run eslint:fix
|
||||||
- name: Commit changes
|
- name: Commit changes
|
||||||
uses: EndBug/add-and-commit@v9
|
uses: EndBug/add-and-commit@v4
|
||||||
with:
|
with:
|
||||||
add: src
|
add: src
|
||||||
message: "chore(lint): Auto-fix linting errors"
|
message: "chore(lint): Auto-fix linting errors"
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -3,5 +3,4 @@ config/default.js
|
||||||
config/production.js
|
config/production.js
|
||||||
config/curate.sqlite
|
config/curate.sqlite
|
||||||
package-lock.json
|
package-lock.json
|
||||||
.idea/
|
.idea/
|
||||||
yarn-error.log
|
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"deepscan.enable": true
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@ This bot allows the community of LBRY to support eachother through the [LBRY Fou
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
* Pull the repo
|
* Pull the repo
|
||||||
* Install [Node.JS LTS](https://nodejs.org/) (Currently Node v18.x)
|
* Install [Node.JS LTS](https://nodejs.org/) (Currently Node v12.x)
|
||||||
* Install [Yarn](https://yarnpkg.com/) (`npm install yarn -g`)
|
* Install [Yarn](https://yarnpkg.com/) (`npm install yarn -g`)
|
||||||
* Install [Redis](https://redis.io/) ([quickstart](https://redis.io/topics/quickstart))
|
* Install [Redis](https://redis.io/) ([quickstart](https://redis.io/topics/quickstart))
|
||||||
* Install LBRY-SDK
|
* Install LBRY-SDK
|
||||||
|
@ -19,7 +19,7 @@ This bot allows the community of LBRY to support eachother through the [LBRY Fou
|
||||||
This bot would not be possible without the following people/software:
|
This bot would not be possible without the following people/software:
|
||||||
|
|
||||||
* LBRY Inc. and the LBRY SDK
|
* LBRY Inc. and the LBRY SDK
|
||||||
* Dysnomia - NodeJS Library for Discord, fork of Eris
|
* Eris - NodeJS Library for Discord
|
||||||
* LBRY Foundation
|
* LBRY Foundation
|
||||||
* Snazzah - Creator of the Faux command base and developer of the bot
|
* Snazzah - Creator of the Faux command base and developer of the bot
|
||||||
* Coolguy3289 - Developer of the bot and command flow
|
* Coolguy3289 - Developer of the bot and command flow
|
||||||
|
|
|
@ -11,42 +11,34 @@ module.exports = {
|
||||||
debug: false,
|
debug: false,
|
||||||
// [number] The main embed color (#ffffff -> 0xffffff)
|
// [number] The main embed color (#ffffff -> 0xffffff)
|
||||||
embedColor: 0x15521c,
|
embedColor: 0x15521c,
|
||||||
// [string|Array<string>] The role ID(s) for curator roles
|
// [string] curator_role_id
|
||||||
curatorRoleID: "",
|
curatorRoleID: "",
|
||||||
// [string|Array<string>] The role ID(s) for trusted roles
|
// [string] admin_role_id
|
||||||
trustedRoleID: "",
|
|
||||||
// [string|Array<string>] The role ID(s) for admin roles
|
|
||||||
adminRoleID: "",
|
adminRoleID: "",
|
||||||
// [string] guild_id
|
// [string] guild_id
|
||||||
guildID: "",
|
guildID: "",
|
||||||
// [string] sdk_url
|
// [string] sdk_url
|
||||||
sdkURL: "",
|
sdkURL: "",
|
||||||
// [string] The ABSOLUTE path to the main wallet file to back up
|
|
||||||
walletPath: "~/.lbryum/wallets/default_wallet",
|
|
||||||
// [string] The ABSOLUTE path folder to store wallet backups after every deletion
|
|
||||||
walletBackupFolder: "~/.lbryum_backup/",
|
|
||||||
// [string] Amount to auto-fund upon account creation
|
// [string] Amount to auto-fund upon account creation
|
||||||
startingBalance: "",
|
startingBalance: "",
|
||||||
// [Object] Dysnomia client options (subset of https://abal.moe/Eris/docs/Client)
|
// [Object] Eris client options (https://abal.moe/Eris/docs/Client)
|
||||||
discordConfig: {
|
discordConfig: {
|
||||||
|
autoreconnect: true,
|
||||||
allowedMentions: {
|
allowedMentions: {
|
||||||
everyone: false,
|
everyone: false,
|
||||||
roles: false,
|
roles: false,
|
||||||
users: true
|
users: true
|
||||||
},
|
},
|
||||||
|
maxShards: "auto",
|
||||||
messageLimit: 0,
|
messageLimit: 0,
|
||||||
gateway: {
|
intents: [
|
||||||
autoreconnect: true,
|
"guilds",
|
||||||
maxShards: "auto",
|
"guildEmojis",
|
||||||
intents: [
|
"guildMessages",
|
||||||
"guilds",
|
"guildMessageReactions",
|
||||||
"guildMessages",
|
"directMessages",
|
||||||
"guildMessageReactions",
|
"directMessageReactions"
|
||||||
"directMessages",
|
]
|
||||||
"directMessageReactions",
|
|
||||||
"messageContent"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
// [Object] Redis config
|
// [Object] Redis config
|
||||||
redis: {
|
redis: {
|
||||||
|
|
23
package.json
23
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "lbry-curate",
|
"name": "lbry-curate",
|
||||||
"version": "0.1.1",
|
"version": "0.0.1",
|
||||||
"description": "Support the LBRY Community through Discord!",
|
"description": "Support the LBRY Community through Discord!",
|
||||||
"main": "src/bot.js",
|
"main": "src/bot.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -9,20 +9,21 @@
|
||||||
"eslint:fix": "eslint ./src --fix"
|
"eslint:fix": "eslint ./src --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@projectdysnomia/dysnomia": "github:projectdysnomia/dysnomia#0df1369a822dba8851c667b22d5bac34f4e849e6",
|
"abort-controller": "^3.0.0",
|
||||||
"cat-loggr": "^1.2.2",
|
"cat-loggr": "^1.1.0",
|
||||||
"config": "^3.3.9",
|
"config": "^3.3.1",
|
||||||
"eventemitter3": "^5.0.1",
|
"eris": "^0.13.3",
|
||||||
|
"eventemitter3": "^4.0.4",
|
||||||
"fuzzy": "^0.1.3",
|
"fuzzy": "^0.1.3",
|
||||||
"ioredis": "^5.3.2",
|
"moment": "^2.27.0",
|
||||||
"just-clone": "^6.2.0",
|
"node-fetch": "^2.3.0",
|
||||||
"moment": "^2.30.1",
|
"redis": "^3.0.2",
|
||||||
"require-reload": "^0.2.2",
|
"require-reload": "^0.2.2",
|
||||||
"sequelize": "^6.35.2",
|
"sequelize": "^6.3.4",
|
||||||
"sqlite3": "^5.1.7"
|
"sqlite3": "^5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^8.56.0"
|
"eslint": "^7.6.0"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
19
src/bot.js
19
src/bot.js
|
@ -1,4 +1,4 @@
|
||||||
const Dysnomia = require('@projectdysnomia/dysnomia');
|
const Eris = require('eris');
|
||||||
const Database = require('./database');
|
const Database = require('./database');
|
||||||
const EventHandler = require('./events');
|
const EventHandler = require('./events');
|
||||||
const CommandLoader = require('./commandloader');
|
const CommandLoader = require('./commandloader');
|
||||||
|
@ -8,13 +8,12 @@ const path = require('path');
|
||||||
const CatLoggr = require('cat-loggr');
|
const CatLoggr = require('cat-loggr');
|
||||||
const config = require('config');
|
const config = require('config');
|
||||||
const LBRY = require('./structures/LBRY');
|
const LBRY = require('./structures/LBRY');
|
||||||
const clone = require('just-clone');
|
|
||||||
|
|
||||||
class CurateBot extends Dysnomia.Client {
|
class CurateBot extends Eris.Client {
|
||||||
constructor({ packagePath, mainDir } = {}) {
|
constructor({ packagePath, mainDir } = {}) {
|
||||||
// Initialization
|
// Initialization
|
||||||
const pkg = require(packagePath || `${mainDir}/package.json`);
|
const pkg = require(packagePath || `${mainDir}/package.json`);
|
||||||
super(`Bot ${config.token}`, clone(config.discordConfig));
|
super(config.token, JSON.parse(JSON.stringify(config.discordConfig)));
|
||||||
this.dir = mainDir;
|
this.dir = mainDir;
|
||||||
this.pkg = pkg;
|
this.pkg = pkg;
|
||||||
this.logger = new CatLoggr({
|
this.logger = new CatLoggr({
|
||||||
|
@ -24,8 +23,10 @@ class CurateBot extends Dysnomia.Client {
|
||||||
{ name: 'error', color: CatLoggr._chalk.black.bgRed, err: true },
|
{ name: 'error', color: CatLoggr._chalk.black.bgRed, err: true },
|
||||||
{ name: 'warn', color: CatLoggr._chalk.black.bgYellow, err: true },
|
{ name: 'warn', color: CatLoggr._chalk.black.bgYellow, err: true },
|
||||||
{ name: 'init', color: CatLoggr._chalk.black.bgGreen },
|
{ name: 'init', color: CatLoggr._chalk.black.bgGreen },
|
||||||
|
{ name: 'webserv', color: CatLoggr._chalk.black.bgBlue },
|
||||||
{ name: 'info', color: CatLoggr._chalk.black.bgCyan },
|
{ name: 'info', color: CatLoggr._chalk.black.bgCyan },
|
||||||
{ name: 'assert', color: CatLoggr._chalk.cyan.bgBlack },
|
{ name: 'assert', color: CatLoggr._chalk.cyan.bgBlack },
|
||||||
|
{ name: 'poster', color: CatLoggr._chalk.yellow.bgBlack },
|
||||||
{ name: 'debug', color: CatLoggr._chalk.magenta.bgBlack, aliases: ['log', 'dir'] },
|
{ name: 'debug', color: CatLoggr._chalk.magenta.bgBlack, aliases: ['log', 'dir'] },
|
||||||
{ name: 'limiter', color: CatLoggr._chalk.gray.bgBlack },
|
{ name: 'limiter', color: CatLoggr._chalk.gray.bgBlack },
|
||||||
{ name: 'fileload', color: CatLoggr._chalk.white.bgBlack }
|
{ name: 'fileload', color: CatLoggr._chalk.white.bgBlack }
|
||||||
|
@ -102,17 +103,17 @@ class CurateBot extends Dysnomia.Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kills the bot
|
* KIlls the bot
|
||||||
*/
|
*/
|
||||||
dieGracefully() {
|
dieGracefully() {
|
||||||
return super.disconnect(false);
|
return super.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Typing
|
// Typing
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start typing in a channel
|
* Start typing in a channel
|
||||||
* @param {Dysnomia.TextableChannel} channel The channel to start typing in
|
* @param {Channel} channel The channel to start typing in
|
||||||
*/
|
*/
|
||||||
async startTyping(channel) {
|
async startTyping(channel) {
|
||||||
if (this.isTyping(channel)) return;
|
if (this.isTyping(channel)) return;
|
||||||
|
@ -124,7 +125,7 @@ class CurateBot extends Dysnomia.Client {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the bot is currently typing in a channel
|
* Whether the bot is currently typing in a channel
|
||||||
* @param {Dysnomia.TextableChannel} channel
|
* @param {Channel} channel
|
||||||
*/
|
*/
|
||||||
isTyping(channel) {
|
isTyping(channel) {
|
||||||
return this.typingIntervals.has(channel.id);
|
return this.typingIntervals.has(channel.id);
|
||||||
|
@ -132,7 +133,7 @@ class CurateBot extends Dysnomia.Client {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops typing in a channel
|
* Stops typing in a channel
|
||||||
* @param {Dysnomia.TextableChannel} channel
|
* @param {Channel} channel
|
||||||
*/
|
*/
|
||||||
stopTyping(channel) {
|
stopTyping(channel) {
|
||||||
if (!this.isTyping(channel)) return;
|
if (!this.isTyping(channel)) return;
|
||||||
|
|
|
@ -37,7 +37,6 @@ module.exports = class AbaondonAll extends Command {
|
||||||
header: 'Are you sure you want to abandon **all supports** from **all accounts**?'
|
header: 'Are you sure you want to abandon **all supports** from **all accounts**?'
|
||||||
})) return;
|
})) return;
|
||||||
await this.client.startTyping(message.channel);
|
await this.client.startTyping(message.channel);
|
||||||
await Util.LBRY.syncPairs(this.client);
|
|
||||||
const pairs = await this.client.sqlite.getAll();
|
const pairs = await this.client.sqlite.getAll();
|
||||||
let count = 0;
|
let count = 0;
|
||||||
for (let i = 0, len = pairs.length; i < len; i++) {
|
for (let i = 0, len = pairs.length; i < len; i++) {
|
||||||
|
@ -51,7 +50,7 @@ module.exports = class AbaondonAll extends Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
get metadata() { return {
|
get metadata() { return {
|
||||||
category: 'Admin',
|
category: 'Curator',
|
||||||
description: 'Abandons all supports of the bot or of a given account.',
|
description: 'Abandons all supports of the bot or of a given account.',
|
||||||
usage: '[id|@mention]'
|
usage: '[id|@mention]'
|
||||||
}; }
|
}; }
|
||||||
|
|
|
@ -13,12 +13,12 @@ module.exports = class AdminBalance extends Command {
|
||||||
const response = await this.client.lbry.walletBalance();
|
const response = await this.client.lbry.walletBalance();
|
||||||
const wallet = await response.json();
|
const wallet = await response.json();
|
||||||
if (await this.handleResponse(message, response, wallet)) return;
|
if (await this.handleResponse(message, response, wallet)) return;
|
||||||
return message.channel.createMessage({ embeds: [{
|
return message.channel.createMessage({ embed: {
|
||||||
color: config.embedColor,
|
color: config.embedColor,
|
||||||
description: `**Available:** ${wallet.result.available} LBC\n\n` +
|
description: `**Available:** ${wallet.result.available} LBC\n\n` +
|
||||||
`Reserved in Supports: ${wallet.result.reserved_subtotals.supports} LBC\n` +
|
`Reserved in Supports: ${wallet.result.reserved_subtotals.supports} LBC\n` +
|
||||||
`Total: ${wallet.result.total} LBC`
|
`Total: ${wallet.result.total} LBC`
|
||||||
}] });
|
} });
|
||||||
}
|
}
|
||||||
|
|
||||||
get metadata() { return {
|
get metadata() { return {
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
const Command = require('../../structures/Command');
|
|
||||||
const Util = require('../../util');
|
|
||||||
const GenericPager = require('../../structures/GenericPager');
|
|
||||||
|
|
||||||
module.exports = class AllSupports extends Command {
|
|
||||||
get name() { return 'allsupports'; }
|
|
||||||
|
|
||||||
get _options() { return {
|
|
||||||
aliases: ['asups', 'allsups'],
|
|
||||||
permissions: ['admin'],
|
|
||||||
minimumArgs: 0
|
|
||||||
}; }
|
|
||||||
|
|
||||||
async exec(message, { args }) {
|
|
||||||
let givenClaim;
|
|
||||||
if (args[0]) {
|
|
||||||
givenClaim = Util.resolveToClaimID(args[0]);
|
|
||||||
if (!givenClaim)
|
|
||||||
// @TODO use claim_search for invalid claim ids
|
|
||||||
return message.channel.createMessage('That Claim ID isn\'t valid.');
|
|
||||||
}
|
|
||||||
|
|
||||||
await Util.LBRY.syncPairs(this.client);
|
|
||||||
const pairs = await this.client.sqlite.getAll();
|
|
||||||
if (pairs.length <= 0)
|
|
||||||
return message.channel.createMessage('No users found in the database.');
|
|
||||||
|
|
||||||
const allSupports = [];
|
|
||||||
|
|
||||||
for (const pair of pairs) {
|
|
||||||
const supportsCount = await Util.LBRY.getSupportsCount(this.client, pair.lbryID);
|
|
||||||
if (supportsCount <= 0) continue;
|
|
||||||
const supportsResponse = await this.client.lbry.listSupports({
|
|
||||||
accountID: pair.lbryID, page_size: supportsCount, claimID: givenClaim });
|
|
||||||
const supports = (await supportsResponse.json()).result.items;
|
|
||||||
for (const support of supports)
|
|
||||||
allSupports.push({
|
|
||||||
...support,
|
|
||||||
pair
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allSupports.length <= 0)
|
|
||||||
return message.channel.createMessage('No supports found.');
|
|
||||||
|
|
||||||
const paginator = new GenericPager(this.client, message, {
|
|
||||||
items: allSupports,
|
|
||||||
header: `All supports${
|
|
||||||
givenClaim ? ` on claim \`${givenClaim}\`` : ''}`, itemTitle: 'Supports',itemsPerPage: 5,
|
|
||||||
display: item => `> ${item.name} \`${item.claim_id}\`\n> <@${item.pair.discordID}> ${item.amount} LBC\n`
|
|
||||||
});
|
|
||||||
return paginator.start(message.channel.id, message.author.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
get metadata() { return {
|
|
||||||
category: 'Admin',
|
|
||||||
description: 'List all supports from all users.',
|
|
||||||
usage: '[claimID]'
|
|
||||||
}; }
|
|
||||||
};
|
|
|
@ -21,15 +21,8 @@ module.exports = class DeleteAccount extends Command {
|
||||||
header:
|
header:
|
||||||
`Are you sure you want to delete that account? *(${supportsCount.toLocaleString()} support[s])*`
|
`Are you sure you want to delete that account? *(${supportsCount.toLocaleString()} support[s])*`
|
||||||
})) return;
|
})) return;
|
||||||
try {
|
await Util.LBRY.deleteAccount(this.client, discordID, account.accountID);
|
||||||
await Util.LBRY.deleteAccount(this.client, discordID, account.accountID);
|
return message.channel.createMessage('Deleted account.');
|
||||||
return message.channel.createMessage('Deleted account.');
|
|
||||||
} catch (e) {
|
|
||||||
return message.channel.createMessage(
|
|
||||||
'Failed to delete the account. An error most likely occured while backing up the wallet.' +
|
|
||||||
`\n\`\`\`\n${e.toString()}\`\`\``
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else
|
} else
|
||||||
return message.channel.createMessage('That user does not have an account.');
|
return message.channel.createMessage('That user does not have an account.');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
const Command = require('../../structures/Command');
|
|
||||||
const Util = require('../../util');
|
|
||||||
|
|
||||||
module.exports = class DeleteAll extends Command {
|
|
||||||
get name() { return 'deleteall'; }
|
|
||||||
|
|
||||||
get _options() { return {
|
|
||||||
aliases: ['delall'],
|
|
||||||
permissions: ['admin'],
|
|
||||||
minimumArgs: 0
|
|
||||||
}; }
|
|
||||||
|
|
||||||
async exec(message) {
|
|
||||||
await Util.LBRY.syncPairs(this.client);
|
|
||||||
const pairs = await this.client.sqlite.getAll();
|
|
||||||
|
|
||||||
if (!await this.client.messageAwaiter.confirm(message, {
|
|
||||||
header:
|
|
||||||
`Are you sure you want to delete **all** ${pairs.length} accounts?`
|
|
||||||
})) return;
|
|
||||||
|
|
||||||
for (const pair of pairs) {
|
|
||||||
try {
|
|
||||||
await Util.LBRY.deleteAccount(this.client, pair.discordID, pair.lbryID);
|
|
||||||
} catch (e) {
|
|
||||||
return message.channel.createMessage(
|
|
||||||
'Failed to delete an account. An error most likely occured while backing up the wallet.' +
|
|
||||||
`\n\`\`\`\n${e.toString()}\`\`\``
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return message.channel.createMessage('Deleted all accounts.');
|
|
||||||
}
|
|
||||||
|
|
||||||
get metadata() { return {
|
|
||||||
category: 'Admin',
|
|
||||||
description: 'Deletes all accounts in the database.'
|
|
||||||
}; }
|
|
||||||
};
|
|
|
@ -1,5 +1,4 @@
|
||||||
const Command = require('../../structures/Command');
|
const Command = require('../../structures/Command');
|
||||||
const Util = require('../../util');
|
|
||||||
|
|
||||||
module.exports = class Deposit extends Command {
|
module.exports = class Deposit extends Command {
|
||||||
get name() { return 'deposit'; }
|
get name() { return 'deposit'; }
|
||||||
|
@ -10,8 +9,7 @@ module.exports = class Deposit extends Command {
|
||||||
}; }
|
}; }
|
||||||
|
|
||||||
async exec(message) {
|
async exec(message) {
|
||||||
const account = await Util.LBRY.findSDKAccount(this.client, account => account.is_default);
|
const response = await this.client.lbry.listAddresses();
|
||||||
const response = await this.client.lbry.listAddresses({ account_id: account.id });
|
|
||||||
const address = await response.json();
|
const address = await response.json();
|
||||||
if (await this.handleResponse(message, response, address)) return;
|
if (await this.handleResponse(message, response, address)) return;
|
||||||
return message.channel.createMessage(`Address: ${address.result.items[0].address}`);
|
return message.channel.createMessage(`Address: ${address.result.items[0].address}`);
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
const Command = require('../../structures/Command');
|
|
||||||
const Util = require('../../util');
|
|
||||||
const config = require('config');
|
|
||||||
|
|
||||||
module.exports = class FundAll extends Command {
|
|
||||||
get name() { return 'fundall'; }
|
|
||||||
|
|
||||||
get _options() { return {
|
|
||||||
permissions: ['admin'],
|
|
||||||
minimumArgs: 1
|
|
||||||
}; }
|
|
||||||
|
|
||||||
async exec(message, { args }) {
|
|
||||||
const givenAmount = Util.LBRY.ensureDecimal(args[0]);
|
|
||||||
if (!givenAmount)
|
|
||||||
return message.channel.createMessage('The second argument must be a numeric amount of LBC to send!');
|
|
||||||
|
|
||||||
await Util.LBRY.syncPairs(this.client);
|
|
||||||
const pairs = await this.client.sqlite.getAll();
|
|
||||||
if (pairs.length <= 0) {
|
|
||||||
await this.client.startTyping(message.channel);
|
|
||||||
const curatorRoles = Array.isArray(config.curatorRoleID)
|
|
||||||
? config.curatorRoleID : [config.curatorRoleID];
|
|
||||||
const members = await this.client.guilds.get(config.guildID).fetchMembers();
|
|
||||||
for (const member of members) {
|
|
||||||
if (curatorRoles.map(r => member.roles.includes(r)).includes(true)) {
|
|
||||||
const account = await Util.LBRY.findOrCreateAccount(this.client, member.id);
|
|
||||||
pairs.push({ discordID: member.id, lbryID: account.accountID });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await Util.halt(5000);
|
|
||||||
this.client.stopTyping(message.channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!await this.client.messageAwaiter.confirm(message, {
|
|
||||||
header: `Are you sure you want to fund **all** accounts? *(${givenAmount} LBC)*`
|
|
||||||
})) return;
|
|
||||||
|
|
||||||
await this.client.startTyping(message.channel);
|
|
||||||
const resultLines = [];
|
|
||||||
let funded = 0,
|
|
||||||
errored = 0;
|
|
||||||
for (const pair of pairs) {
|
|
||||||
const response = await this.client.lbry.fundAccount({ to: pair.lbryID, amount: givenAmount });
|
|
||||||
await Util.halt(2000);
|
|
||||||
const transaction = await response.json();
|
|
||||||
if ('code' in transaction) {
|
|
||||||
console.info('Failed to fund account', pair.lbryID, transaction.code, transaction.message);
|
|
||||||
resultLines.push(`${pair.discordID} ! ${transaction.code} - ${transaction.message}`);
|
|
||||||
errored++;
|
|
||||||
} else {
|
|
||||||
console.info('Funded account', pair.lbryID, transaction.result.txid);
|
|
||||||
resultLines.push(`${pair.discordID} - https://explorer.lbry.com/tx/${transaction.result.txid}`);
|
|
||||||
funded++;
|
|
||||||
}
|
|
||||||
await Util.halt(2000);
|
|
||||||
}
|
|
||||||
this.client.stopTyping(message.channel);
|
|
||||||
return message.channel.createMessage(errored
|
|
||||||
? `Failed to fund ${errored} accounts! (${funded} funded)`
|
|
||||||
: `Successfully funded ${funded} account(s)!`, {
|
|
||||||
name: 'result.txt',
|
|
||||||
file: Buffer.from(resultLines.join('\n'), 'utf8')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get metadata() { return {
|
|
||||||
category: 'Admin',
|
|
||||||
description: 'Funds all users in the database a specified amount of LBC.',
|
|
||||||
usage: '<amount>'
|
|
||||||
}; }
|
|
||||||
};
|
|
|
@ -1,49 +0,0 @@
|
||||||
const Command = require('../../structures/Command');
|
|
||||||
const GenericPager = require('../../structures/GenericPager');
|
|
||||||
|
|
||||||
module.exports = class ListAll extends Command {
|
|
||||||
get name() { return 'listall'; }
|
|
||||||
get _options() { return {
|
|
||||||
permissions: ['admin'],
|
|
||||||
minimumArgs: 0
|
|
||||||
}; }
|
|
||||||
async exec(message, { args }) {
|
|
||||||
const pairs = await this.client.sqlite.getAll();
|
|
||||||
if (pairs.length <= 0)
|
|
||||||
return message.channel.createMessage('No users found in the database.');
|
|
||||||
|
|
||||||
for (const pair of pairs) {
|
|
||||||
const response = await this.client.lbry.accountBalance(pair.lbryID);
|
|
||||||
const wallet = await response.json();
|
|
||||||
if (!wallet.code) {
|
|
||||||
pair.wallet_available = wallet.result.available;
|
|
||||||
pair.wallet_reserve = wallet.result.reserved_subtotals.supports;
|
|
||||||
pair.wallet_ok = true;
|
|
||||||
} else {
|
|
||||||
console.error([
|
|
||||||
'There was an error while retrieving the balance of an account.',
|
|
||||||
'This was likely caused by an old version of the Bot\'s SQLite database file. ' +
|
|
||||||
'Run the sync command to avoid this error!'
|
|
||||||
].join('\n'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const paginator = new GenericPager(this.client, message, {
|
|
||||||
items: pairs, itemTitle: 'Users', itemsPerPage: 5,
|
|
||||||
display: pair => `> <@${pair.discordID}> - \`${pair.lbryID}\`\n` +
|
|
||||||
`> ${pair.wallet_ok
|
|
||||||
? `${pair.wallet_available} available, ${pair.wallet_reserve} staked.`
|
|
||||||
: 'Wallet Unavailable'}\n`
|
|
||||||
});
|
|
||||||
|
|
||||||
if (args[0])
|
|
||||||
paginator.toPage(args[0]);
|
|
||||||
|
|
||||||
return paginator.start(message.channel.id, message.author.id);
|
|
||||||
}
|
|
||||||
get metadata() { return {
|
|
||||||
category: 'Admin',
|
|
||||||
description: 'List all users in the database.',
|
|
||||||
usage: '[page]'
|
|
||||||
}; }
|
|
||||||
};
|
|
|
@ -1,20 +0,0 @@
|
||||||
const Command = require('../../structures/Command');
|
|
||||||
const Util = require('../../util');
|
|
||||||
|
|
||||||
module.exports = class Sync extends Command {
|
|
||||||
get name() { return 'sync'; }
|
|
||||||
|
|
||||||
get _options() { return {
|
|
||||||
permissions: ['admin']
|
|
||||||
}; }
|
|
||||||
|
|
||||||
async exec(message) {
|
|
||||||
const synced = await Util.LBRY.syncPairs(this.client);
|
|
||||||
return message.channel.createMessage(`Synced ${synced} new pairs.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
get metadata() { return {
|
|
||||||
category: 'Admin',
|
|
||||||
description: 'Sync SDK-Discord pairs.'
|
|
||||||
}; }
|
|
||||||
};
|
|
|
@ -1,7 +1,7 @@
|
||||||
const Command = require('../../structures/Command');
|
const Command = require('../../structures/Command');
|
||||||
const Util = require('../../util');
|
const Util = require('../../util');
|
||||||
|
|
||||||
module.exports = class Abandon extends Command {
|
module.exports = class Abaondon extends Command {
|
||||||
get name() { return 'abandon'; }
|
get name() { return 'abandon'; }
|
||||||
|
|
||||||
get _options() { return {
|
get _options() { return {
|
||||||
|
@ -11,8 +11,8 @@ module.exports = class Abandon extends Command {
|
||||||
}; }
|
}; }
|
||||||
|
|
||||||
async exec(message, { args }) {
|
async exec(message, { args }) {
|
||||||
const givenClaim = Util.resolveToClaimID(args[0]);
|
const givenClaim = args[0];
|
||||||
if (!givenClaim)
|
if (!/^[a-f0-9]{40}$/.test(givenClaim))
|
||||||
// @TODO use claim_search for invalid claim ids
|
// @TODO use claim_search for invalid claim ids
|
||||||
return message.channel.createMessage('That Claim ID isn\'t valid.');
|
return message.channel.createMessage('That Claim ID isn\'t valid.');
|
||||||
|
|
||||||
|
|
|
@ -10,46 +10,19 @@ module.exports = class Balance extends Command {
|
||||||
permissions: ['curatorOrAdmin']
|
permissions: ['curatorOrAdmin']
|
||||||
}; }
|
}; }
|
||||||
|
|
||||||
async exec(message, { args }) {
|
async exec(message) {
|
||||||
if (args.length) {
|
const account = await Util.LBRY.findOrCreateAccount(this.client, message.author.id);
|
||||||
if (!Util.CommandPermissions.admin(this.client, message)) {
|
const response = await this.client.lbry.accountBalance(account.accountID);
|
||||||
const admins = (Array.isArray(config.adminRoleID) ? config.adminRoleID : [config.adminRoleID])
|
const wallet = await response.json();
|
||||||
.map(id => `"${this.client.guilds.get(config.guildID).roles.get(id).name}"`);
|
if (await this.handleResponse(message, response, wallet)) return;
|
||||||
return message.channel.createMessage(
|
return message.channel.createMessage({ embed: {
|
||||||
`You need to have the ${admins.join('/')} role(s) to see others balances!`);
|
color: config.embedColor,
|
||||||
}
|
description: `You have **${wallet.result.available}** LBC available.\n\n` +
|
||||||
|
`Reserved in Supports: ${wallet.result.reserved_subtotals.supports} LBC\n` +
|
||||||
const discordID = Util.resolveToUserID(args[0]);
|
`Total: ${wallet.result.total} LBC` +
|
||||||
if (!discordID)
|
(account.newAccount ? '\n\n:warning: This account was just created. ' +
|
||||||
return message.channel.createMessage('That Discord user isn\'t valid.');
|
'Please wait a few seconds, and run the command again to get an accurate balance.' : '')
|
||||||
|
} });
|
||||||
const account = await Util.LBRY.findOrCreateAccount(this.client, discordID, false);
|
|
||||||
if (!account.accountID)
|
|
||||||
return message.channel.createMessage('That Discord user does not have an account.');
|
|
||||||
|
|
||||||
const response = await this.client.lbry.accountBalance(account.accountID);
|
|
||||||
const wallet = await response.json();
|
|
||||||
if (await this.handleResponse(message, response, wallet)) return;
|
|
||||||
return message.channel.createMessage({ embeds: [{
|
|
||||||
color: config.embedColor,
|
|
||||||
description: `<@${discordID}> has **${wallet.result.available}** LBC available.\n\n` +
|
|
||||||
`Reserved in Supports: ${wallet.result.reserved_subtotals.supports} LBC\n` +
|
|
||||||
`Total: ${wallet.result.total} LBC`
|
|
||||||
}] });
|
|
||||||
} else {
|
|
||||||
const account = await Util.LBRY.findOrCreateAccount(this.client, message.author.id);
|
|
||||||
const response = await this.client.lbry.accountBalance(account.accountID);
|
|
||||||
const wallet = await response.json();
|
|
||||||
if (await this.handleResponse(message, response, wallet)) return;
|
|
||||||
return message.channel.createMessage({ embeds: [{
|
|
||||||
color: config.embedColor,
|
|
||||||
description: `You have **${wallet.result.available}** LBC available.\n\n` +
|
|
||||||
`Reserved in Supports: ${wallet.result.reserved_subtotals.supports} LBC\n` +
|
|
||||||
`Total: ${wallet.result.total} LBC` +
|
|
||||||
(account.newAccount ? '\n\n:warning: This account was just created. ' +
|
|
||||||
'Please wait a few seconds, and run the command again to get an accurate balance.' : '')
|
|
||||||
}] });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get metadata() { return {
|
get metadata() { return {
|
||||||
|
|
|
@ -15,8 +15,8 @@ module.exports = class Support extends Command {
|
||||||
if (!givenAmount)
|
if (!givenAmount)
|
||||||
return message.channel.createMessage('The second argument must be a numeric amount of LBC to send!');
|
return message.channel.createMessage('The second argument must be a numeric amount of LBC to send!');
|
||||||
|
|
||||||
const givenClaim = Util.resolveToClaimID(args[0]);
|
const givenClaim = args[0];
|
||||||
if (!givenClaim)
|
if (!/^[a-f0-9]{40}$/.test(givenClaim))
|
||||||
// @TODO use claim_search for invalid claim ids
|
// @TODO use claim_search for invalid claim ids
|
||||||
return message.channel.createMessage('That Claim ID isn\'t valid.');
|
return message.channel.createMessage('That Claim ID isn\'t valid.');
|
||||||
|
|
||||||
|
|
|
@ -42,14 +42,12 @@ module.exports = class Supports extends Command {
|
||||||
const supportsResponse = await this.client.lbry.listSupports({
|
const supportsResponse = await this.client.lbry.listSupports({
|
||||||
accountID: account.accountID, page_size: supportsCount, claimID: givenClaim });
|
accountID: account.accountID, page_size: supportsCount, claimID: givenClaim });
|
||||||
console.debug(
|
console.debug(
|
||||||
`Displaying supports for ${
|
`Displaying supports for ${account.accountID}${givenClaim ? ` and claimID ${givenClaim}` : ''}, (${supportsCount})`);
|
||||||
account.accountID}${givenClaim ? ` and claimID ${givenClaim}` : ''}, (${supportsCount})`);
|
|
||||||
const supports = (await supportsResponse.json()).result.items;
|
const supports = (await supportsResponse.json()).result.items;
|
||||||
const paginator = new GenericPager(this.client, message, {
|
const paginator = new GenericPager(this.client, message, {
|
||||||
items: supports,
|
items: supports,
|
||||||
header: `All supports for <@${discordID || message.author.id}>${
|
header: `All supports for <@${discordID || message.author.id}>${givenClaim ? ` on claim \`${givenClaim}\`` : ''}`, itemTitle: 'Supports',
|
||||||
givenClaim ? ` on claim \`${givenClaim}\`` : ''}`, itemTitle: 'Supports',itemsPerPage: 5,
|
display: item => `*lbry://**${item.name}***#\`${item.claim_id}\` (${item.amount} LBC)`
|
||||||
display: item => `> ${item.name} \`${item.claim_id}\`\n> ${item.amount} LBC\n`
|
|
||||||
});
|
});
|
||||||
return paginator.start(message.channel.id, message.author.id);
|
return paginator.start(message.channel.id, message.author.id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ module.exports = class Help extends Command {
|
||||||
value: command.metadata.note
|
value: command.metadata.note
|
||||||
});
|
});
|
||||||
|
|
||||||
return message.channel.createMessage({ embeds: [embed] });
|
return message.channel.createMessage({ embed });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Display general help command
|
// Display general help command
|
||||||
|
@ -89,7 +89,7 @@ module.exports = class Help extends Command {
|
||||||
inline: true
|
inline: true
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return message.channel.createMessage({ embeds: [embed] });
|
return message.channel.createMessage({ embed });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
const Command = require('../../structures/Command');
|
|
||||||
const Util = require('../../util');
|
|
||||||
|
|
||||||
module.exports = class TAbandon extends Command {
|
|
||||||
get name() { return 'tabandon'; }
|
|
||||||
|
|
||||||
get _options() { return {
|
|
||||||
aliases: ['taban', 'tdrop'],
|
|
||||||
permissions: ['trustedOrAdmin'],
|
|
||||||
minimumArgs: 1
|
|
||||||
}; }
|
|
||||||
|
|
||||||
async exec(message, { args }) {
|
|
||||||
const givenClaim = Util.resolveToClaimID(args[0]);
|
|
||||||
if (!givenClaim)
|
|
||||||
// @TODO use claim_search for invalid claim ids
|
|
||||||
return message.channel.createMessage('That Claim ID isn\'t valid.');
|
|
||||||
|
|
||||||
if (!await this.client.messageAwaiter.confirm(message, {
|
|
||||||
header:
|
|
||||||
'Are you sure you want to abandon a claim from a **trusted** account?'
|
|
||||||
})) return;
|
|
||||||
|
|
||||||
const account = await Util.LBRY.findSDKAccount(this.client, account => account.is_default);
|
|
||||||
|
|
||||||
// Drop support
|
|
||||||
const response = await this.client.lbry.abandonSupport({
|
|
||||||
accountID: account.id, claimID: givenClaim });
|
|
||||||
const transaction = await response.json();
|
|
||||||
if (await this.handleResponse(message, response, transaction)) return;
|
|
||||||
const txid = transaction.result.txid;
|
|
||||||
return message.channel.createMessage(`Abandon successful! https://explorer.lbry.com/tx/${txid}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
get metadata() { return {
|
|
||||||
category: 'Trusted',
|
|
||||||
description: 'Abandons a support on a given claim from the trusted account.',
|
|
||||||
usage: '<claim>'
|
|
||||||
}; }
|
|
||||||
};
|
|
|
@ -1,30 +0,0 @@
|
||||||
const Command = require('../../structures/Command');
|
|
||||||
const Util = require('../../util');
|
|
||||||
const config = require('config');
|
|
||||||
|
|
||||||
module.exports = class TBalance extends Command {
|
|
||||||
get name() { return 'tbalance'; }
|
|
||||||
|
|
||||||
get _options() { return {
|
|
||||||
aliases: ['tbal', 'trustedbal', 'trustedbalance'],
|
|
||||||
permissions: ['trustedOrAdmin']
|
|
||||||
}; }
|
|
||||||
|
|
||||||
async exec(message) {
|
|
||||||
const account = await Util.LBRY.findSDKAccount(this.client, account => account.is_default);
|
|
||||||
const response = await this.client.lbry.accountBalance(account.id);
|
|
||||||
const wallet = await response.json();
|
|
||||||
if (await this.handleResponse(message, response, wallet)) return;
|
|
||||||
return message.channel.createMessage({ embeds: [{
|
|
||||||
color: config.embedColor,
|
|
||||||
description: `**${wallet.result.available}** LBC is available in the trusted account.\n\n` +
|
|
||||||
`Reserved in Supports: ${wallet.result.reserved_subtotals.supports} LBC\n` +
|
|
||||||
`Total: ${wallet.result.total} LBC`
|
|
||||||
}] });
|
|
||||||
}
|
|
||||||
|
|
||||||
get metadata() { return {
|
|
||||||
category: 'Trusted',
|
|
||||||
description: 'Shows the trusted wallet balance.'
|
|
||||||
}; }
|
|
||||||
};
|
|
|
@ -1,51 +0,0 @@
|
||||||
const Command = require('../../structures/Command');
|
|
||||||
const Util = require('../../util');
|
|
||||||
|
|
||||||
module.exports = class TSupport extends Command {
|
|
||||||
get name() { return 'tsupport'; }
|
|
||||||
|
|
||||||
get _options() { return {
|
|
||||||
aliases: ['tsup'],
|
|
||||||
permissions: ['trustedOrAdmin'],
|
|
||||||
minimumArgs: 2
|
|
||||||
}; }
|
|
||||||
|
|
||||||
async exec(message, { args }) {
|
|
||||||
const givenAmount = Util.LBRY.ensureDecimal(args[1]);
|
|
||||||
if (!givenAmount)
|
|
||||||
return message.channel.createMessage('The second argument must be a numeric amount of LBC to send!');
|
|
||||||
|
|
||||||
const givenClaim = Util.resolveToClaimID(args[0]);
|
|
||||||
if (!givenClaim)
|
|
||||||
// @TODO use claim_search for invalid claim ids
|
|
||||||
return message.channel.createMessage('That Claim ID isn\'t valid.');
|
|
||||||
|
|
||||||
// Get and check balance
|
|
||||||
const account = await Util.LBRY.findSDKAccount(this.client, account => account.is_default);
|
|
||||||
const walletResponse = await this.client.lbry.accountBalance(account.id);
|
|
||||||
const wallet = await walletResponse.json();
|
|
||||||
if (await this.handleResponse(message, walletResponse, wallet)) return;
|
|
||||||
const balance = wallet.result.available;
|
|
||||||
if (parseFloat(givenAmount) > parseFloat(balance))
|
|
||||||
return message.channel.createMessage('You don\'t have enough LBC to do this!');
|
|
||||||
|
|
||||||
if (!await this.client.messageAwaiter.confirm(message, {
|
|
||||||
header:
|
|
||||||
'Are you sure you want to support a claim from a **trusted** account?'
|
|
||||||
})) return;
|
|
||||||
|
|
||||||
// Create support
|
|
||||||
const response = await this.client.lbry.createSupport({
|
|
||||||
accountID: account.id, claimID: givenClaim, amount: givenAmount });
|
|
||||||
const transaction = await response.json();
|
|
||||||
if (await this.handleResponse(message, response, transaction)) return;
|
|
||||||
const txid = transaction.result.txid;
|
|
||||||
return message.channel.createMessage(`Support successful! https://explorer.lbry.com/tx/${txid}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
get metadata() { return {
|
|
||||||
category: 'Trusted',
|
|
||||||
description: 'Support a given claim from the trusted account.',
|
|
||||||
usage: '<claim> <amount>'
|
|
||||||
}; }
|
|
||||||
};
|
|
|
@ -1,42 +0,0 @@
|
||||||
const Command = require('../../structures/Command');
|
|
||||||
const GenericPager = require('../../structures/GenericPager');
|
|
||||||
const Util = require('../../util');
|
|
||||||
|
|
||||||
module.exports = class TSupports extends Command {
|
|
||||||
get name() { return 'tsupports'; }
|
|
||||||
get _options() { return {
|
|
||||||
aliases: ['tsups'],
|
|
||||||
permissions: ['trustedOrAdmin'],
|
|
||||||
minimumArgs: 0
|
|
||||||
}; }
|
|
||||||
async exec(message, { args }) {
|
|
||||||
let givenClaim;
|
|
||||||
if (args[0]) {
|
|
||||||
givenClaim = Util.resolveToClaimID(args[0]);
|
|
||||||
if (!givenClaim)
|
|
||||||
// @TODO use claim_search for invalid claim ids
|
|
||||||
return message.channel.createMessage('That Claim ID isn\'t valid.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const account = await Util.LBRY.findSDKAccount(this.client, account => account.is_default);
|
|
||||||
const supportsCount = await Util.LBRY.getSupportsCount(this.client, account.id);
|
|
||||||
if (supportsCount <= 0)
|
|
||||||
return message.channel.createMessage('No supports found.');
|
|
||||||
|
|
||||||
const supportsResponse = await this.client.lbry.listSupports({
|
|
||||||
accountID: account.id, page_size: supportsCount, claimID: givenClaim });
|
|
||||||
const supports = (await supportsResponse.json()).result.items;
|
|
||||||
const paginator = new GenericPager(this.client, message, {
|
|
||||||
items: supports,
|
|
||||||
header: `All supports for the trusted account${
|
|
||||||
givenClaim ? ` on claim \`${givenClaim}\`` : ''}`, itemTitle: 'Supports', itemsPerPage: 5,
|
|
||||||
display: item => `> ${item.name} \`${item.claim_id}\`\n> ${item.amount} LBC\n`
|
|
||||||
});
|
|
||||||
return paginator.start(message.channel.id, message.author.id);
|
|
||||||
}
|
|
||||||
get metadata() { return {
|
|
||||||
category: 'Trusted',
|
|
||||||
description: 'Shows the list of supports from the trusted account.',
|
|
||||||
usage: '[claimID]'
|
|
||||||
}; }
|
|
||||||
};
|
|
|
@ -1,4 +1,4 @@
|
||||||
const { default: Redis } = require('ioredis');
|
const redis = require('redis');
|
||||||
const { EventEmitter } = require('eventemitter3');
|
const { EventEmitter } = require('eventemitter3');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,7 +19,7 @@ module.exports = class Database extends EventEmitter {
|
||||||
connect({ host = 'localhost', port, password, prefix }) {
|
connect({ host = 'localhost', port, password, prefix }) {
|
||||||
console.info('Connecting to redis...');
|
console.info('Connecting to redis...');
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.redis = new Redis(port, host, { password, keyPrefix: prefix });
|
this.redis = redis.createClient({ host, port, password, prefix });
|
||||||
this.redis.on('error', this.onError.bind(this));
|
this.redis.on('error', this.onError.bind(this));
|
||||||
this.redis.on('warning', w => console.warn('Redis Warning', w));
|
this.redis.on('warning', w => console.warn('Redis Warning', w));
|
||||||
this.redis.on('end', () => this.onClose.bind(this));
|
this.redis.on('end', () => this.onClose.bind(this));
|
||||||
|
@ -37,32 +37,67 @@ module.exports = class Database extends EventEmitter {
|
||||||
|
|
||||||
// #region Redis functions
|
// #region Redis functions
|
||||||
hget(key, hashkey) {
|
hget(key, hashkey) {
|
||||||
return this.redis.hget(key, hashkey);
|
return new Promise((resolve, reject) => {
|
||||||
|
this.redis.HGET(key, hashkey, (err, value) => {
|
||||||
|
if (err) reject(err);
|
||||||
|
resolve(value);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
hset(key, hashkey, value) {
|
hset(key, hashkey, value) {
|
||||||
return this.redis.hset(key, hashkey, value);
|
return new Promise((resolve, reject) => {
|
||||||
|
this.redis.HSET(key, hashkey, value, (err, res) => {
|
||||||
|
if (err) reject(err);
|
||||||
|
resolve(res);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
incr(key) {
|
incr(key) {
|
||||||
return this.redis.incr(key);
|
return new Promise((resolve, reject) => {
|
||||||
|
this.redis.incr(key, (err, res) => {
|
||||||
|
if (err) reject(err);
|
||||||
|
resolve(res);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get(key) {
|
get(key) {
|
||||||
return this.redis.get(key);
|
return new Promise((resolve, reject) => {
|
||||||
|
this.redis.get(key, function(err, reply) {
|
||||||
|
if (err) reject(err);
|
||||||
|
resolve(reply);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
expire(key, ttl) {
|
expire(key, ttl) {
|
||||||
return this.redis.expire(key, ttl);
|
return new Promise((resolve, reject) => {
|
||||||
|
this.redis.expire(key, ttl, (err, value) => {
|
||||||
|
if (err) reject(err);
|
||||||
|
resolve(value);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
exists(key) {
|
exists(key) {
|
||||||
return this.redis.exists(key);
|
return new Promise((resolve, reject) => {
|
||||||
|
this.redis.exists(key, (err, value) => {
|
||||||
|
if (err) reject(err);
|
||||||
|
resolve(value === 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
set(key, value) {
|
set(key, value) {
|
||||||
return this.redis.set(key, value);
|
return new Promise((resolve, reject) => {
|
||||||
|
this.redis.set(key, value, (err, res) => {
|
||||||
|
if (err) reject(err);
|
||||||
|
resolve(res);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
|
|
|
@ -40,11 +40,11 @@ module.exports = class Events {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onReaction(message, emoji, member) {
|
onReaction(message, emoji, userID) {
|
||||||
const id = `${message.id}:${member.id}`;
|
const id = `${message.id}:${userID}`;
|
||||||
if (this.client.messageAwaiter.reactionCollectors.has(id)) {
|
if (this.client.messageAwaiter.reactionCollectors.has(id)) {
|
||||||
const collector = this.client.messageAwaiter.reactionCollectors.get(id);
|
const collector = this.client.messageAwaiter.reactionCollectors.get(id);
|
||||||
collector._onReaction(emoji, member.id);
|
collector._onReaction(emoji, userID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,9 +42,6 @@ class Command {
|
||||||
` \`${this.metadata.usage}\`` : ''}`);
|
` \`${this.metadata.usage}\`` : ''}`);
|
||||||
|
|
||||||
// Check commmand permissions
|
// Check commmand permissions
|
||||||
const curators = Array.isArray(config.curatorRoleID) ? config.curatorRoleID : [config.curatorRoleID];
|
|
||||||
const admins = Array.isArray(config.adminRoleID) ? config.adminRoleID : [config.adminRoleID];
|
|
||||||
const trusteds = Array.isArray(config.trustedRoleID) ? config.trustedRoleID : [config.trustedRoleID];
|
|
||||||
if (this.options.permissions.length)
|
if (this.options.permissions.length)
|
||||||
for (const i in this.options.permissions) {
|
for (const i in this.options.permissions) {
|
||||||
const perm = this.options.permissions[i];
|
const perm = this.options.permissions[i];
|
||||||
|
@ -56,22 +53,13 @@ class Command {
|
||||||
embed: 'I need the permission `Embed Links` to use this command!',
|
embed: 'I need the permission `Embed Links` to use this command!',
|
||||||
emoji: 'I need the permission `Use External Emojis` to use this command!',
|
emoji: 'I need the permission `Use External Emojis` to use this command!',
|
||||||
elevated: 'Only the elevated users of the bot can use this command!',
|
elevated: 'Only the elevated users of the bot can use this command!',
|
||||||
curator: `This command requires you to have the ${
|
curator: `This command requires you to have the "${
|
||||||
curators.map(id =>
|
message.guild.roles.get(config.curatorRoleID).name}" role!`,
|
||||||
`"${this.client.guilds.get(config.guildID).roles.get(id).name}"`).join('/')} role!`,
|
admin: `This command requires you to have the "${
|
||||||
admin: `This command requires you to have the ${
|
message.guild.roles.get(config.adminRoleID).name}" role!`,
|
||||||
admins.map(id =>
|
curatorOrAdmin: `This command requires you to have the "${
|
||||||
`"${this.client.guilds.get(config.guildID).roles.get(id).name}"`).join('/')} role!`,
|
message.guild.roles.get(config.curatorRoleID).name}" or "${
|
||||||
curatorOrAdmin: `This command requires you to have the ${
|
message.guild.roles.get(config.adminRoleID).name}" roles!`,
|
||||||
curators.map(id =>
|
|
||||||
`"${this.client.guilds.get(config.guildID).roles.get(id).name}"`).join('/')} or ${
|
|
||||||
admins.map(id =>
|
|
||||||
`"${this.client.guilds.get(config.guildID).roles.get(id).name}"`).join('/')} role!`,
|
|
||||||
trustedOrAdmin: `This command requires you to have the ${
|
|
||||||
trusteds.map(id =>
|
|
||||||
`"${this.client.guilds.get(config.guildID).roles.get(id).name}"`).join('/')} or ${
|
|
||||||
admins.map(id =>
|
|
||||||
`"${this.client.guilds.get(config.guildID).roles.get(id).name}"`).join('/')} role!`,
|
|
||||||
guild: 'This command must be ran in a guild!',
|
guild: 'This command must be ran in a guild!',
|
||||||
}[perm]);
|
}[perm]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ class GenericPager extends Paginator {
|
||||||
constructor(client, message, {
|
constructor(client, message, {
|
||||||
items = [], itemsPerPage = 15,
|
items = [], itemsPerPage = 15,
|
||||||
display = item => item.toString(),
|
display = item => item.toString(),
|
||||||
embedExtra = {}, itemTitle = 'Items',
|
embedExtra = {}, itemTitle = 'words.item.many',
|
||||||
header = null, footer = null
|
header = null, footer = null
|
||||||
} = {}) {
|
} = {}) {
|
||||||
super(client, message, { items, itemsPerPage });
|
super(client, message, { items, itemsPerPage });
|
||||||
|
@ -70,7 +70,7 @@ class GenericPager extends Paginator {
|
||||||
value: displayPage.join('\n')
|
value: displayPage.join('\n')
|
||||||
});
|
});
|
||||||
|
|
||||||
return { embeds: [embed] };
|
return { embed };
|
||||||
} else {
|
} else {
|
||||||
const top = `${this.itemTitle} ` +
|
const top = `${this.itemTitle} ` +
|
||||||
`(${this.items.length}, Page ${this.pageNumber}/${this.maxPages})`;
|
`(${this.items.length}, Page ${this.pageNumber}/${this.maxPages})`;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
const fetch = require('node-fetch');
|
||||||
|
const AbortController = require('abort-controller');
|
||||||
const config = require('config');
|
const config = require('config');
|
||||||
const Util = require('../util');
|
const Util = require('../util');
|
||||||
|
|
||||||
|
@ -180,13 +182,10 @@ class LBRY {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List account addresses or details.
|
* List account addresses or details of single address.
|
||||||
* @param {object} options
|
|
||||||
* @param {string} options.to How many items should be per page
|
|
||||||
* @param {string} options.amount The amount to send
|
|
||||||
*/
|
*/
|
||||||
listAddresses({ page_size = 1, account_id } = {}) {
|
listAddresses() {
|
||||||
return this._sdkRequest('address_list', { page_size, account_id });
|
return this._sdkRequest('address_list', { page_size: 1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
106
src/util.js
106
src/util.js
|
@ -1,6 +1,5 @@
|
||||||
|
const fetch = require('node-fetch');
|
||||||
const config = require('config');
|
const config = require('config');
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the utilities for the bot
|
* Represents the utilities for the bot
|
||||||
|
@ -49,7 +48,7 @@ Util.Prefix = {
|
||||||
Util.Prefix.regex(client, prefixes), '$2').replace(/\s\s+/g, ' ').trim();
|
Util.Prefix.regex(client, prefixes), '$2').replace(/\s\s+/g, ' ').trim();
|
||||||
},
|
},
|
||||||
escapeRegex(s) {
|
escapeRegex(s) {
|
||||||
return s.replace(/[-/\\^$*+?.()|[\]{}!]/g, '\\$&');
|
return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -69,40 +68,24 @@ Util.CommandPermissions = {
|
||||||
curator: (client, message) => {
|
curator: (client, message) => {
|
||||||
const member = message.guildID ? message.member :
|
const member = message.guildID ? message.member :
|
||||||
client.guilds.get(config.guildID).members.get(message.author.id);
|
client.guilds.get(config.guildID).members.get(message.author.id);
|
||||||
const roles = Array.isArray(config.curatorRoleID) ? config.curatorRoleID : [config.curatorRoleID];
|
|
||||||
if (!member) return false;
|
if (!member) return false;
|
||||||
if (Util.CommandPermissions.elevated(client, message)) return true;
|
if (Util.CommandPermissions.elevated(client, message)) return true;
|
||||||
return roles.map(r => member.roles.includes(r)).includes(true);
|
return member.roles.includes(config.curatorRoleID);
|
||||||
},
|
},
|
||||||
admin: (client, message) => {
|
admin: (client, message) => {
|
||||||
const member = message.guildID ? message.member :
|
const member = message.guildID ? message.member :
|
||||||
client.guilds.get(config.guildID).members.get(message.author.id);
|
client.guilds.get(config.guildID).members.get(message.author.id);
|
||||||
const roles = Array.isArray(config.adminRoleID) ? config.adminRoleID : [config.adminRoleID];
|
|
||||||
if (!member) return false;
|
if (!member) return false;
|
||||||
if (Util.CommandPermissions.elevated(client, message)) return true;
|
if (Util.CommandPermissions.elevated(client, message)) return true;
|
||||||
return roles.map(r => member.roles.includes(r)).includes(true);
|
return member.roles.includes(config.adminRoleID);
|
||||||
},
|
},
|
||||||
curatorOrAdmin: (client, message) => {
|
curatorOrAdmin: (client, message) => {
|
||||||
const member = message.guildID ? message.member :
|
const member = message.guildID ? message.member :
|
||||||
client.guilds.get(config.guildID).members.get(message.author.id);
|
client.guilds.get(config.guildID).members.get(message.author.id);
|
||||||
const roles = [
|
|
||||||
...(Array.isArray(config.adminRoleID) ? config.adminRoleID : [config.adminRoleID]),
|
|
||||||
...(Array.isArray(config.curatorRoleID) ? config.curatorRoleID : [config.curatorRoleID]),
|
|
||||||
];
|
|
||||||
if (!member) return false;
|
if (!member) return false;
|
||||||
if (Util.CommandPermissions.elevated(client, message)) return true;
|
if (Util.CommandPermissions.elevated(client, message)) return true;
|
||||||
return roles.map(r => member.roles.includes(r)).includes(true);
|
return member.roles.includes(config.curatorRoleID) ||
|
||||||
},
|
member.roles.includes(config.adminRoleID);
|
||||||
trustedOrAdmin: (client, message) => {
|
|
||||||
const member = message.guildID ? message.member :
|
|
||||||
client.guilds.get(config.guildID).members.get(message.author.id);
|
|
||||||
const roles = [
|
|
||||||
...(Array.isArray(config.adminRoleID) ? config.adminRoleID : [config.adminRoleID]),
|
|
||||||
...(Array.isArray(config.trustedRoleID) ? config.trustedRoleID : [config.trustedRoleID]),
|
|
||||||
];
|
|
||||||
if (!member) return false;
|
|
||||||
if (Util.CommandPermissions.elevated(client, message)) return true;
|
|
||||||
return roles.map(r => member.roles.includes(r)).includes(true);
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -162,20 +145,6 @@ Util.resolveToUserID = (arg) => {
|
||||||
else return null;
|
else return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve argument to a claim ID
|
|
||||||
* @memberof Util.
|
|
||||||
* @param {string} arg
|
|
||||||
* @returns {?string}
|
|
||||||
*/
|
|
||||||
Util.resolveToClaimID = (arg) => {
|
|
||||||
if (/^[a-f0-9]{40}$/.test(arg))
|
|
||||||
return arg;
|
|
||||||
else if (/^lbry:\/\/@?[\w-]+#([a-f0-9]{40})$/.test(arg))
|
|
||||||
return arg.replace(/^lbry:\/\/@?[\w-]+#([a-f0-9]{40})$/, '$1');
|
|
||||||
else return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a promise that resolves after some time
|
* Make a promise that resolves after some time
|
||||||
* @memberof Util.
|
* @memberof Util.
|
||||||
|
@ -232,26 +201,6 @@ Util.Hastebin = {
|
||||||
* @memberof Util.
|
* @memberof Util.
|
||||||
*/
|
*/
|
||||||
Util.LBRY = {
|
Util.LBRY = {
|
||||||
async syncPairs(client) {
|
|
||||||
const response = await client.lbry.listAccounts({ page_size: await Util.LBRY.getAccountCount(client) });
|
|
||||||
const accounts = await response.json();
|
|
||||||
|
|
||||||
let syncedAccounts = 0;
|
|
||||||
for (const account of accounts.result.items) {
|
|
||||||
if (/\d{17,19}/.test(account.name)) {
|
|
||||||
if (await client.sqlite.get(account.name)) continue;
|
|
||||||
await client.sqlite.pair(account.name, account.id);
|
|
||||||
syncedAccounts++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return syncedAccounts;
|
|
||||||
},
|
|
||||||
async findSDKAccount(client, fn) {
|
|
||||||
const response = await client.lbry.listAccounts({ page_size: await Util.LBRY.getAccountCount(client) });
|
|
||||||
const accounts = await response.json();
|
|
||||||
return accounts.result.items.find(fn);
|
|
||||||
},
|
|
||||||
async findOrCreateAccount(client, discordID, create = true) {
|
async findOrCreateAccount(client, discordID, create = true) {
|
||||||
// Check SQLite
|
// Check SQLite
|
||||||
const pair = await client.sqlite.get(discordID);
|
const pair = await client.sqlite.get(discordID);
|
||||||
|
@ -259,7 +208,9 @@ Util.LBRY = {
|
||||||
return { accountID: pair.lbryID };
|
return { accountID: pair.lbryID };
|
||||||
|
|
||||||
// Check accounts via SDK
|
// Check accounts via SDK
|
||||||
const foundAccount = await Util.LBRY.findSDKAccount(client, account => account.name === discordID);
|
const response = await client.lbry.listAccounts({ page_size: await Util.LBRY.getAccountCount(client) });
|
||||||
|
const accounts = await response.json();
|
||||||
|
const foundAccount = accounts.result.items.find(account => account.name === discordID);
|
||||||
if (foundAccount) {
|
if (foundAccount) {
|
||||||
await client.sqlite.pair(discordID, foundAccount.id);
|
await client.sqlite.pair(discordID, foundAccount.id);
|
||||||
return { accountID: foundAccount.id };
|
return { accountID: foundAccount.id };
|
||||||
|
@ -299,27 +250,14 @@ Util.LBRY = {
|
||||||
return Number.isInteger(num) ? `${num}.0` : num.toString();
|
return Number.isInteger(num) ? `${num}.0` : num.toString();
|
||||||
},
|
},
|
||||||
async deleteAccount(client, discordID, lbryID) {
|
async deleteAccount(client, discordID, lbryID) {
|
||||||
// Backup the wallet before doing any delete function
|
|
||||||
try {
|
|
||||||
Util.LBRY.backupWallet();
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error occurred while backing up wallet file!');
|
|
||||||
console.error(err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Abandon supports
|
// Abandon supports
|
||||||
await Util.LBRY.abandonAllClaims(client, lbryID);
|
await Util.LBRY.abandonAllClaims(client, lbryID);
|
||||||
|
|
||||||
// Take out funds from account
|
// Take out funds from account
|
||||||
const balanceResponse = await client.lbry.accountBalance(lbryID);
|
const balanceResponse = await client.lbry.accountBalance(lbryID);
|
||||||
let amount = (await balanceResponse.json()).result.total;
|
const amount = (await balanceResponse.json()).result.total;
|
||||||
while (amount >= 2) {
|
if (parseFloat(amount) > 0)
|
||||||
await client.lbry.fundAccount({ from: lbryID, everything: true, amount });
|
await client.lbry.fundAccount({ from: lbryID, everything: true, amount });
|
||||||
const finalBalance = await client.lbry.accountBalance(lbryID);
|
|
||||||
amount = (await finalBalance.json()).result.total;
|
|
||||||
await Util.halt(3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove account from SDK & SQLite
|
// Remove account from SDK & SQLite
|
||||||
await client.lbry.removeAccount(lbryID);
|
await client.lbry.removeAccount(lbryID);
|
||||||
|
@ -336,27 +274,7 @@ Util.LBRY = {
|
||||||
for (let i = 0, len = supports.length; i < len; i++) {
|
for (let i = 0, len = supports.length; i < len; i++) {
|
||||||
const support = supports[i];
|
const support = supports[i];
|
||||||
await client.lbry.abandonSupport({ claimID: support.claim_id, accountID: lbryID });
|
await client.lbry.abandonSupport({ claimID: support.claim_id, accountID: lbryID });
|
||||||
await Util.halt(3000);
|
|
||||||
}
|
}
|
||||||
return { count: supports.length };
|
return { count: supports.length };
|
||||||
},
|
|
||||||
backupWallet() {
|
|
||||||
const wallet = fs.readFileSync(config.walletPath);
|
|
||||||
const d = new Date();
|
|
||||||
const date = [
|
|
||||||
d.getUTCFullYear(),
|
|
||||||
d.getUTCMonth().toString().padStart(2, '0'),
|
|
||||||
d.getUTCDay().toString().padStart(2, '0'),
|
|
||||||
].join('-');
|
|
||||||
const time = [
|
|
||||||
d.getUTCHours().toString().padStart(2, '0'),
|
|
||||||
d.getUTCMinutes().toString().padStart(2, '0'),
|
|
||||||
d.getUTCSeconds().toString().padStart(2, '0'),
|
|
||||||
d.getUTCMilliseconds().toString()
|
|
||||||
].join('-');
|
|
||||||
const backupName = 'default_wallet.' + date + '_' + time + '.bak';
|
|
||||||
const backupPath = path.join(config.walletBackupFolder, backupName);
|
|
||||||
fs.writeFileSync(backupPath, wallet);
|
|
||||||
console.log(`Backed up wallet file: ${backupPath}`);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
Loading…
Add table
Reference in a new issue