Skip to content
This repository was archived by the owner on Dec 30, 2024. It is now read-only.

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
deamme committed May 22, 2018
0 parents commit 7a6ef63
Show file tree
Hide file tree
Showing 6 changed files with 871 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
yarn.lock
client_secret.json
credentials.json
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

# Giveth bot
A matrix bot that handles everything from information to point dishing for the Giveth community.

## Development
Follow [this](https://developers.google.com/sheets/api/quickstart/nodejs) guide to get `client_secret.json`.
Install cross-env globally: `npm i -g cross-env`.
Start the bot with following parameters: `cross-env BOT_USER="name" BOT_PASSWORD="password" node index`

## Production
Zeit.co NOW is being used to host the bot.
`client_secret.json` and `credentials.json` are required files.
Remove both files from `.gitignore`.
You can run `now -e BOT_USER="name" -e BOT_PASSWORD="password"` to deploy the bot.
12 changes: 12 additions & 0 deletions constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Allowed users that can dish out points
// module.exports.userList = [
// ]

// Allowed point types
module.exports.typeList = [
'gov',
'dapp',
'sc',
'comm',
'unicorn',
]
152 changes: 152 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
const fs = require('fs');
const readline = require('readline');
const {google} = require('googleapis');

// If modifying these scopes, delete credentials.json.
const SCOPES = ['https://www.googleapis.com/auth/spreadsheets'];
const TOKEN_PATH = 'credentials.json';

// Load client secrets from a local file.
fs.readFile('client_secret.json', (err, content) => {
if (err) return console.log('Error loading client secret file:', err);
// Authorize a client with credentials, then call the Google Sheets API.
authorize(JSON.parse(content), authenticated);
});

/**
* Create an OAuth2 client with the given credentials, and then execute the
* given callback function.
* @param {Object} credentials The authorization client credentials.
* @param {function} callback The callback to call with the authorized client.
*/
function authorize(credentials, callback) {
const {client_secret, client_id, redirect_uris} = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(
client_id, client_secret, redirect_uris[0]);

// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, (err, token) => {
if (err) return getNewToken(oAuth2Client, callback);
oAuth2Client.setCredentials(JSON.parse(token));
callback(oAuth2Client);
});
}

/**
* Get and store new token after prompting for user authorization, and then
* execute the given callback with the authorized OAuth2 client.
* @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for.
* @param {getEventsCallback} callback The callback for the authorized client.
*/
function getNewToken(oAuth2Client, callback) {
const authUrl = oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES,
});
console.log('Authorize this app by visiting this url:', authUrl);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question('Enter the code from that page here: ', (code) => {
rl.close();
oAuth2Client.getToken(code, (err, token) => {
if (err) return callback(err);
oAuth2Client.setCredentials(token);
// Store the token to disk for later program executions
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
if (err) console.error(err);
console.log('Token stored to', TOKEN_PATH);
});
callback(oAuth2Client);
});
});
}

const sdk = require("matrix-js-sdk");
const BigNumber = require('bignumber.js');
var dayjs = require('dayjs');

const { userList, typeList } = require("./constants");

const client = sdk.createClient("https://matrix.org");

function authenticated(auth) {
client.login(
"m.login.password",
{
user: process.env.BOT_USER,
password: process.env.BOT_PASSWORD
},
(err, data) => {
if (err) {
console.log("Error:", err);
}

console.log(`Logged in ${data.user_id} on device ${data.device_id}`);
const client = sdk.createClient({
baseUrl: "https://matrix.org",
accessToken: data.access_token,
userId: data.user_id,
deviceId: data.device_id
});

client.on("Room.timeline", (event, room, toStartOfTimeline) => {
if (event.getType() === "m.room.message" && toStartOfTimeline === false) {
client.setPresence("online");
const sender = event.getSender();
const message = event.getContent().body;
const roomId = room.roomId;
// const userAllowed = userList.filter(user => user === sender).length;
const splittedMsg = message.split(" ");

const hasHelp = splittedMsg[0] === "!help";
const hasSheet = splittedMsg[0] === "!sheet";
const hasDish = splittedMsg[0] === "!dish";
const hasNumber = parseInt(splittedMsg[1]);
const hasType = splittedMsg[2] && typeList.filter((type) => type === splittedMsg[2].toLocaleLowerCase()).length
const hasPointsToFor = splittedMsg[3] === "points" && splittedMsg[4] === "to" && splittedMsg[6] === "for"

if (hasDish && hasNumber && hasType && hasPointsToFor) {
const amount = BigNumber(splittedMsg[1]).toFormat(2);
const type = splittedMsg[2].toUpperCase();
const receiver = splittedMsg[5];
const reason = "For" + message.split("for")[1];
const date = dayjs().format("DD-MMM-YYYY");
const link = `https://riot.im/app/#/room/${roomId}/${event.getId()}`;

const sheets = google.sheets({version: 'v4', auth});
sheets.spreadsheets.values.append({
spreadsheetId: '12cblUYuYq4NwZX7JdRo0-NWnrOxlDy-XCbvF3ugzb2c',
range: 'PointsBot (DONT RENAME!)!A1:F1',
valueInputOption: 'USER_ENTERED',
requestBody: {
values: [
[receiver, sender, reason, amount, type, date, link],
]
}
}, (err, data) => {
if (err) return console.log('The API returned an error: ' + err);
client.sendTextMessage(roomId, `${sender} dished ${BigNumber(splittedMsg[1]).toFormat()} ${splittedMsg[2].toUpperCase()} points to ${splittedMsg[5]}`);
});
} else if (hasDish) {
client.sendTextMessage(roomId, "ERROR, please use the following format:\n!dish [#of points] [type of points] points to [handle] for [reason]");
} else if (hasSheet) {
client.sendTextMessage(roomId, "The RewardDAO sheet can be found here: " + "https://docs.google.com/spreadsheets/d/12cblUYuYq4NwZX7JdRo0-NWnrOxlDy-XCbvF3ugzb2c/edit?usp=sharing");
} else if (hasHelp) {
client.sendTextMessage(roomId, "Dish points using the following format:\n!dish [#of points] [type of points] points to [handle] for [reason]");
}
}
});

client.startClient(0);
}
);
}

// Zeit NOW workaround
const http = require('http')
http.createServer((req, res) => {
res.setHeader('Content-Type', 'text/plain; charset=utf-8')
res.end('Hello there!')
}).listen()
15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "giveth-bot",
"version": "1.0.0",
"main": "index.js",
"license": "GPL-3.0",
"scripts": {
"start": "node index"
},
"dependencies": {
"bignumber.js": "^7.0.1",
"dayjs": "^1.6.0",
"googleapis": "^30.0.0",
"matrix-js-sdk": "^0.10.2"
}
}

0 comments on commit 7a6ef63

Please sign in to comment.