Skip to content
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

Use MongoDB to get overseer info #9

Merged
merged 6 commits into from
Oct 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Steem Bot To Enable And Grow Ulogs.org Communities & Ulog-subtags.

Current Version: v0.0.1
Current Version: v1.0.0

License: MIT

Expand Down
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"name": "ulog-communities",
"version": "0.0.1",
"version": "1.0.0",
"engines": {
"node": ">=7.10.1",
"npm": "=5.3.0"
"npm": ">=5.3.0"
},
"main": "dist/index.js",
"license": "MIT",
Expand All @@ -15,6 +15,8 @@
"dsteem": "^0.8.7",
"event-stream": "^3.3.4",
"jest": "^22.4.3",
"mongodb": "^3.1.8",
"mongoose": "^5.3.7",
"nodemon": "^1.17.1",
"steem": "^0.7.1",
"striptags": "^3.1.1"
Expand All @@ -35,6 +37,8 @@
"@types/dotenv-safe": "^5.0.0",
"@types/es6-promise": "^3.3.0",
"@types/jest": "^22.2.3",
"@types/mongodb": "^3.1.13",
"@types/mongoose": "^5.2.20",
"@types/node": "^9.6.6",
"typescript": "^2.8.3"
}
Expand Down
312 changes: 173 additions & 139 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import * as es from 'event-stream'
import * as util from 'util'
import * as striptags from 'striptags'

const mongoose = require('mongoose')
require('./models/Overseer');
const Overseer = mongoose.model('Overseer');

// file
import { arrayContains, die, getVoteWeight } from './functions'
import { OVERSEERS, FAIL_COMMENT, SUCCESS_COMMENT } from './config'
Expand Down Expand Up @@ -40,8 +44,10 @@ let ADD_ULOG_TEST_ACCOUNTS: boolean
= (process.env.ADD_ULOG_TEST_ACCOUNTS === "true")
// @ts-ignore
let DEFAULT_VOTE_WEIGHT: number = parseInt(process.env.DEFAULT_VOTE_WEIGHT)
// @ts-ignore
let DATABASE: string = process.env.DATABASE
if (BOT === '' || ACCOUNT_KEY === '' || BOT_COMMAND === '' || MAIN_TAG === ''
|| ULOGS_APP === '' || DEFAULT_VOTE_WEIGHT === 0) die('Check .env file')
|| ULOGS_APP === '' || DEFAULT_VOTE_WEIGHT === 0 || DATABASE === '') die('Check .env file')

// Steem Init

Expand All @@ -53,145 +59,173 @@ console.log('Operation started')
console.log('Is simulation?', SIMULATE_ONLY)
console.log('Bot command:', BOT_COMMAND)

getCertifiedUloggers(client).then(res => {
let certifiedUloggers: string[] = []
res.forEach((obj: any) => certifiedUloggers.push(obj.following))
if(ADD_ULOG_TEST_ACCOUNTS) {
console.log('adding uloggers for testing')
certifiedUloggers.push('eastmael', 'east.autovote')
}

// Stream Steem Blockchain
stream.on('data', async operation => {
// Look for comment type of transaction
if (operation.op[0] == 'comment') {
let txData = operation.op[1]

// check if reply (return if post)
if (txData.parent_author === '') return

// get post data
let summoner: string = txData.author
let permlink: string = txData.permlink
let post = await getPostData(summoner, permlink).catch(() =>
console.error("Couldn't fetch post data with SteemJS")
)

let splitBody = striptags(post.body.toLowerCase().replace("<br/>", " ")).split(" ")
if (summoner === "eastmael") console.log('split body arry', splitBody)
// check if summoned by specific command
if (splitBody.indexOf(BOT_COMMAND.toLowerCase()) < 0) return

// #################### CHECKS #######################
// 2) check if certified ulogger
let isCertifiedUlogger = arrayContains(summoner, certifiedUloggers)

// 2b) check summon is a direct reply under the post
let isReplyToPost = (post.root_author === post.parent_author
&& post.root_permlink === post.parent_permlink)
console.log('is reply directly under post:', isReplyToPost)

// get root post (to get all tags)
let rootPost = await getPostData(post.root_author, post.root_permlink)
.catch(() =>
console.error("Couldn't fetch ROOT post data with SteemJS")
)

// 3) posted using 'ulogs' app
let app: string = ''
try {
app = JSON.parse(rootPost.json_metadata).app
} catch (e) {
console.error('Invalid app')
return
}
console.log('posted using ulogs: ', app.indexOf(ULOGS_APP) >= 0)
let isUlogApp = app.indexOf(ULOGS_APP) >= 0

// 4) First tag is 'ulogs'
let rootTags: string[]
try {
rootTags = JSON.parse(rootPost.json_metadata).tags
} catch (e) {
console.error('Invalid root tags')
return
}
console.log('first tag is main tag: ', rootTags[0] === MAIN_TAG)
let isFirstTagUlog = (rootTags[0] === MAIN_TAG)

// 5) Summoner is overseer of sub-tag
// TODO: Change to map
let overseerInfo = OVERSEERS[summoner]
let subtags = overseerInfo.tags
// 7a) Is an overseer?
console.log('summoner is an overseer? ', subtags);
let isOverseer = (subtags && subtags.length > 0)

// 7b) Is an overseer of sub-tag?
console.log('summoner is an overseer of sub-tag? ',
arrayContains(rootTags[1], subtags));
let isSubtagOverseer = (isOverseer && arrayContains(rootTags[1], subtags))

// 8) is valid param weight
let isValidWeight = (isNaN(parseInt(splitBody[1])) === false)
console.log('is integer vote weight: ', isValidWeight)

// 9) is already upvoted
let isAlreadyVoted = rootPost.active_votes.some((r:any) => {
return BOT === r.voter
})
console.log('is already voted: ', isAlreadyVoted)

// 10) is past curation window
let isPastCurationWindow = true
console.log('is past curation window: ', isPastCurationWindow)

let isSuccess = isCertifiedUlogger && isUlogApp && isFirstTagUlog && isOverseer
&& isSubtagOverseer && isReplyToPost && isValidWeight && !isAlreadyVoted && isPastCurationWindow
let commentTemplate: string = ''
if (isSuccess) {
commentTemplate = SUCCESS_COMMENT(summoner, BOT)
} else {
commentTemplate = FAIL_COMMENT(
summoner,
BOT,
rootTags[1],
{
isCertifiedUlogger,
isUlogApp,
isFirstTagUlog,
isSubtagOverseer,
isReplyToPost,
isValidWeight,
isAlreadyVoted,
isPastCurationWindow,
}
)
// Initialize mongoose then connect
mongoose.connect(process.env.DATABASE, { useNewUrlParser: true })
mongoose.Promise = global.Promise
mongoose.connection
.on('connected', () => {
console.log('Mongoose connection open...');

getCertifiedUloggers(client).then(res => {
let certifiedUloggers: string[] = []
res.forEach((obj: any) => certifiedUloggers.push(obj.following))
if(ADD_ULOG_TEST_ACCOUNTS) {
console.log('adding uloggers for testing')
certifiedUloggers.push('eastmael', 'east.autovote')
}

if (SIMULATE_ONLY) {
console.log('simulation only...')
console.log(commentTemplate)
} else {
console.log('sending comment...')
// Send Comment
comment(client, summoner, permlink, key, BOT, commentTemplate)
.then(() => {

if(isSuccess) {
let voteweight = getVoteWeight(parseInt(splitBody[1]), overseerInfo.maxweight)
console.log('voting with weight...', voteweight)
// Vote post
vote(client, BOT, post.root_author, post.root_permlink,
voteweight, key).catch(() =>
console.error("Couldn't vote on the violated post")
// Stream Steem Blockchain
stream.on('data', async operation => {
// Look for comment type of transaction
if (operation.op[0] == 'comment') {
let txData = operation.op[1]

// check if reply (return if post)
if (txData.parent_author === '') return

// get post data
let summoner: string = txData.author
let permlink: string = txData.permlink
let post = await getPostData(summoner, permlink).catch(() =>
console.error("Couldn't fetch post data with SteemJS")
)

let splitBody = striptags(post.body.toLowerCase().replace("<br/>", " ")).split(" ")
if (summoner === "eastmael") console.log('split body arry', splitBody)
// check if summoned by specific command
if (splitBody.indexOf(BOT_COMMAND.toLowerCase()) < 0) return

// #################### CHECKS #######################
// 2) check if certified ulogger
let isCertifiedUlogger = arrayContains(summoner, certifiedUloggers)

// 2b) check summon is a direct reply under the post
let isReplyToPost = (post.root_author === post.parent_author
&& post.root_permlink === post.parent_permlink)
console.log('is reply directly under post:', isReplyToPost)

// get root post (to get all tags)
let rootPost = await getPostData(post.root_author, post.root_permlink)
.catch(() =>
console.error("Couldn't fetch ROOT post data with SteemJS")
)

// 3) posted using 'ulogs' app
let app: string = ''
try {
app = JSON.parse(rootPost.json_metadata).app
} catch (e) {
console.error('Invalid app')
return
}
}).catch(() => {
console.error("Couldn't comment on the violated post")
})
}
}
return
})
})
console.log('posted using ulogs: ', app.indexOf(ULOGS_APP) >= 0)
let isUlogApp = app.indexOf(ULOGS_APP) >= 0

// 4) First tag is 'ulogs'
let rootTags: string[]
try {
rootTags = JSON.parse(rootPost.json_metadata).tags
} catch (e) {
console.error('Invalid root tags')
return
}
console.log('first tag is main tag: ', rootTags[0] === MAIN_TAG)
let isFirstTagUlog = (rootTags[0] === MAIN_TAG)

// Query overseer info
Overseer.find()
.then((result: any) => {

let overseersMap: {[key:string]: any} = {}
result.forEach((overseer: any) => {
overseersMap[overseer.name] = { tags: overseer.tags, maxweight: overseer.maxweight }
})
console.log('overseers map size:', Object.keys(overseersMap).length)

// 5) Summoner is overseer of sub-tag
let overseerInfo = overseersMap[summoner]
console.log('overseer info:', overseerInfo)

let subtags = overseerInfo.tags
// 7a) Is an overseer?
console.log('summoner is an overseer? ', subtags);
let isOverseer = (subtags && subtags.length > 0)

// 7b) Is an overseer of sub-tag?
console.log('summoner is an overseer of sub-tag? ',
arrayContains(rootTags[1], subtags));
let isSubtagOverseer = (isOverseer && arrayContains(rootTags[1], subtags))

// 8) is valid param weight
let isValidWeight = (isNaN(parseInt(splitBody[1])) === false)
console.log('is integer vote weight: ', isValidWeight)

// 9) is already upvoted
let isAlreadyVoted = rootPost.active_votes.some((r:any) => {
return BOT === r.voter
})
console.log('is already voted: ', isAlreadyVoted)

// 10) is past curation window
let isPastCurationWindow = true
console.log('is past curation window: ', isPastCurationWindow)

let isSuccess = isCertifiedUlogger && isUlogApp && isFirstTagUlog && isOverseer
&& isSubtagOverseer && isReplyToPost && isValidWeight && !isAlreadyVoted && isPastCurationWindow
let commentTemplate: string = ''
if (isSuccess) {
commentTemplate = SUCCESS_COMMENT(summoner, BOT)
} else {
commentTemplate = FAIL_COMMENT(
summoner,
BOT,
rootTags[1],
{
isCertifiedUlogger,
isUlogApp,
isFirstTagUlog,
isSubtagOverseer,
isReplyToPost,
isValidWeight,
isAlreadyVoted,
isPastCurationWindow,
}
)
}

if (SIMULATE_ONLY) {
console.log('simulation only...')
console.log(commentTemplate)
} else {
console.log('sending comment...')
// Send Comment
comment(client, summoner, permlink, key, BOT, commentTemplate)
.then(() => {

if(isSuccess) {
let voteweight = getVoteWeight(parseInt(splitBody[1]), overseerInfo.maxweight)
console.log('voting with weight...', voteweight)
// Vote post
vote(client, BOT, post.root_author, post.root_permlink,
voteweight, key).catch(() =>
console.error("Couldn't vote on the violated post")
)
}
}).catch(() => {
console.error("Couldn't comment on the violated post")
})
}
})
.catch(() => { console.log('Something went wrong in fetching overseers.') }) // end: Overseer.find()
} // end: if (operation.op[0] == 'comment') {}
return

}) // end: stream.on()

}) // end: getCertifiedUloggers()

}) // end: mongo.connection on:connected
.on('error', (err: any) => {
console.log(`Connection error: ${err.message}`);
}) // end: mongo.connection on:error

15 changes: 15 additions & 0 deletions src/models/Overseer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Document, Schema, Model, model} from "mongoose"

export interface IOverseerModel extends Document {
name?: string
tags?: string[]
maxweight?: number
}

export var OverseerSchema: Schema = new Schema({
name: String,
tags: [],
maxweight: Number,
})

export const Overseer: Model<IOverseerModel> = model<IOverseerModel>("Overseer", OverseerSchema)