@ -7,80 +7,83 @@ const client = new Discord.Client({
} ) ;
} ) ;
import fetch from "node-fetch" ;
import fetch from "node-fetch" ;
import * as fs from "fs" ;
import * as fs from "fs" ;
import * as path from "path" ;
import axios from "axios" ;
import axios from "axios" ;
import userScore from "./mongooseModels/mongooseUserScoreModel.js" ;
import userScore from "./mongooseModels/mongooseUserScoreModel.js" ;
import { } from 'dotenv/config.js' ;
import { } from "dotenv/config.js" ;
import mongoose from "mongoose" ;
import mongoose from "mongoose" ;
const helpMessage =
const helpMessage =
"`do be helping`: display this help message\n`do be roundgen`: send a pdf round to the channel\n`do be roundgen dm`: dm a pdf round to you\n`do be scoring`: start a scoring session\n > `do be scoring (a/b)(4/10)`: add points to Team A or Team B\n > `do be scoring stop`: end scoring session and post final points\n > `do be servers`: send the number of servers this bot is a part of\n > `do be iss`: show the current location of the International Space Station\n`do be training`: send a quick practice problem (you **must** react to your answer, or the bot will yell at you)\n > subject options: astro, phys, chem, math, bio, ess, energy\n`do be top`: list cross-server top 10 players\nSource Code: https://github.com/ADawesomeguy/AwesomeSciBo (don't forget to star!)" ;
"`do be helping`: display this help message\n`do be roundgen`: send a pdf round to the channel\n`do be roundgen dm`: dm a pdf round to you\n`do be scoring`: start a scoring session\n > `do be scoring (a/b)(4/10)`: add points to Team A or Team B\n > `do be scoring stop`: end scoring session and post final points\n > `do be servers`: send the number of servers this bot is a part of\n > `do be iss`: show the current location of the International Space Station\n`do be training`: send a quick practice problem (you **must** react to your answer, or the bot will yell at you)\n > subject options: astro, phys, chem, math, bio, ess, energy\n`do be top`: list cross-server top 10 players\nSource Code: https://github.com/ADawesomeguy/AwesomeSciBo (don't forget to star!)" ;
client . once ( "ready" , ( ) => {
client . once ( "ready" , ( ) => {
mongoose . connect ( process . env . MONGO_URI , { useUnifiedTopology : true , useNewUrlParser : true } ) . then ( ( ) => {
mongoose
. connect ( process . env . MONGO_URI , {
useUnifiedTopology : true ,
useNewUrlParser : true ,
} )
. then ( ( ) => {
console . log ( client . user . username ) ;
console . log ( client . user . username ) ;
client . user . setActivity (
client . user . setActivity (
'for "do be helping" | Add me to your own server: adat.link/awscibo' ,
'for "do be helping" | Add me to your own server: adat.link/awscibo' ,
{ type : "WATCHING" }
{ type : "WATCHING" }
)
) ;
} ) . catch ( err => console . log ( err ) )
} )
. catch ( ( err ) => console . log ( err ) ) ;
} ) ;
} ) ;
client . on ( "guildCreate" , ( guild ) => {
client . on ( "guildCreate" , ( guild ) => {
guild . channels . cache
guild . channels . cache
. find ( ( channel ) => channel . name === "general" && channel . type === "text" )
. find (
( channel ) =>
channel . name === process . env . WELCOME_CHANNEL && channel . type === "text"
)
. send ( "'Sup, I'm the AwesomeSciBo bot!" )
. send ( "'Sup, I'm the AwesomeSciBo bot!" )
. catch ( console . error ) ;
. catch ( console . error ) ;
} ) ;
} ) ;
client . on ( "message" , async ( message ) => {
function getSubjectUrl ( subject ) {
if ( message . author . bot ) {
return ` https://moose.lcsrc.org/subjects/ ${ subject } .json ` ;
return ;
}
}
async function updateScore ( isCorrect , score , authorId ) {
if ( ! isCorrect ) {
return ` Nice try! Your score is still ${ score } . ` ;
} else {
score += 4 ;
if ( score == 4 ) {
const newUserScore = new userScore ( {
authorID : authorId ,
score : score ,
} ) ;
newUserScore . save ( ( err ) =>
err
? console . log ( "Error creating new user for scoring" )
: console . log ( "Sucessfully created user to score." )
) ;
} else {
const doc = await userScore . findOne ( {
authorID : authorId ,
} ) ;
doc . score = doc . score + 4 ;
doc . save ( ) ;
console . log ( "Succesfully updated score." ) ;
}
return ` Great job! Your score is now ${ score } . ` ;
const formattedMessage = message . content . toLowerCase ( ) . replace ( /\s+/g , "" ) ;
if ( formattedMessage . startsWith ( "dobe" ) ) {
switch ( formattedMessage ) {
case "dobehelping" :
sendHelpMessage ( ) ;
break ;
case "doberoundgen" :
generateRound ( false ) ;
break ;
case "doberoundgendm" :
generateRound ( true ) ;
break ;
case "dobescoring" :
startScoring ( ) ;
break ;
case "dobetop" :
showLeaderboard ( ) ;
break ;
case "dobehappy" :
dontWorryBeHappy ( ) ;
break ;
case "dobeservers" :
showServerNumber ( ) ;
break ;
case "dobeiss" :
showIssLocation ( ) ;
break ;
default :
otherCommands ( ) ;
}
}
}
}
async function otherCommands ( ) {
async function otherCommands ( message ) {
if (
if (
message . content . toLowerCase ( ) . startsWith ( "do be announcing" ) &&
message . content . toLowerCase ( ) . startsWith ( "do be announcing" ) &&
message . author . id === process . argv [ 3 ]
( message . author . id === process . env . ABHEEK_USER_ID ||
message . author . id === process . env . TEJAS_USER_ID )
) {
) {
const announcement = message . content . substring ( 17 ) ;
const announcement = message . content . substring ( 17 ) ;
client . guilds . cache . forEach ( ( guild ) => {
client . guilds . cache . forEach ( ( guild ) => {
const channel = guild . channels . cache . find (
const channel = guild . channels . cache . find (
( channelGeneral ) => channelGeneral . name === "general"
( channelGeneral ) =>
channelGeneral . name === process . env . ANNOUNCING_CHANNEL
) ;
) ;
if ( channel ) {
if ( channel ) {
if ( channel . type === "text" ) {
if ( channel . type === "text" ) {
@ -89,62 +92,127 @@ client.on("message", async (message) => {
}
}
} ) ;
} ) ;
} else if ( message . content . toLowerCase ( ) . startsWith ( "do be training" ) ) {
} else if ( message . content . toLowerCase ( ) . startsWith ( "do be training" ) ) {
// BEGIN CHANGES
const authorId = message . author . id ;
let score ;
userScore
. findOne ( { authorID : authorId } )
. lean ( )
. then ( ( obj , err ) => {
if ( ! obj ) {
score = 0 ;
} else if ( obj ) {
score = obj . score ;
} else {
console . log ( err ) ;
}
} ) ;
if ( message . content === "do be training" ) {
if ( message . content === "do be training" ) {
axios . get ( "https://scibowldb.com/api/questions/random" ) . then ( data => {
axios . get ( "https://scibowldb.com/api/questions/random" ) . then ( ( res ) => {
const data = res . data ;
const messageAuthorFilter = ( m ) => m . author . id === message . author . id ;
const messageAuthorFilter = ( m ) => m . author . id === message . author . id ;
message
message . reply ( data . question . tossup_question ) . then ( ( ) => {
. reply ( data . data . question . tossup_question )
message . channel
. then ( ( ) => {
. awaitMessages ( messageAuthorFilter , {
message . channel . awaitMessages ( messageAuthorFilter , {
max : 1 ,
max : 1 ,
time : 30000 ,
time : 30000 ,
errors : [ "time" ] ,
errors : [ "time" ] ,
} ) ;
} )
} )
. then ( resMessage => {
. then ( ( answerMsg ) => {
const responseAuthorID = resMessage . first ( ) . author . id ;
answerMsg = answerMsg . first ( ) ;
let predicted = null ;
if ( data . question . tossup_format === "Multiple Choice" ) {
if (
answerMsg . content . charAt ( 0 ) . toLowerCase ( ) ===
data . question . tossup_answer . charAt ( 0 ) . toLowerCase ( )
) {
predicted = "correct" ;
} else {
predicted = "incorrect" ;
}
} else {
if (
answerMsg . content . toLowerCase ( ) ===
data . question . tossup_answer . toLowerCase ( )
) {
predicted = "correct" ;
} else {
predicted = "incorrect" ;
}
}
answerMsg . channel . send (
` Correct answer: ** ${ data . question . tossup_answer } **. Predicted: ** ${ predicted } **. Please react to your answer! `
) ;
answerMsg . react ( "✅" ) ;
answerMsg . react ( "❌" ) ;
const filter = ( reaction , user ) => {
return (
[ "❌" , "✅" ] . includes ( reaction . emoji . name ) &&
user . id === answerMsg . author . id
) ;
} ;
answerMsg
. awaitReactions ( filter , {
max : 1 ,
time : 600000 ,
errors : [ "time" ] ,
} )
. then ( ( userReaction ) => {
const reaction = userReaction . first ( ) ;
if ( reaction . emoji . name === "❌" ) {
updateScore ( false , score , authorId ) . then ( ( msgToReply ) =>
answerMsg . reply ( msgToReply )
) ;
} else {
updateScore ( true , score , authorId ) . then ( ( msgToReply ) =>
answerMsg . reply ( msgToReply )
) ;
}
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} else {
} else {
const subject = message . content . substring ( 15 ) ;
const subject = message . content . substring ( 15 ) ;
let subjectURL ;
let subjectURL ;
switch ( subject ) {
switch ( subject ) {
case "astro" :
case "astro" :
case "astronomy" :
case "astronomy" :
subjectURL = ` https://moose.lcsrc.org/subjects/astronomy.json ` ;
subjectURL = getSubjectUrl ( "astronomy" ) ;
break ;
break ;
case "bio" :
case "bio" :
case "biology" :
case "biology" :
subjectURL = ` https://moose.lcsrc.org/subjects/biology.json ` ;
subjectURL = getSubjectUrl ( "biology" ) ;
break ;
break ;
case "ess" :
case "ess" :
case "earth science" :
case "earth science" :
case "es" :
case "es" :
subjectURL = ` https://moose.lcsrc.org/subjects/ess.json ` ;
subjectURL = getSubjectUrl ( "ess" ) ;
break ;
break ;
case "chem" :
case "chem" :
case "chemistry" :
case "chemistry" :
subjectURL = ` https://moose.lcsrc.org/subjects/chemistry.json ` ;
subjectURL = getSubjectUrl ( "astronomy" ) ;
break ;
break ;
case "phys" :
case "phys" :
case "physics" :
case "physics" :
subjectURL = ` https://moose.lcsrc.org/subjects/physics.json ` ;
subjectURL = getSubjectUrl ( "physics" ) ;
break ;
break ;
case "math" :
case "math" :
subjectURL = ` https://moose.lcsrc.org/subjects/math.json ` ;
subjectURL = getSubjectUrl ( "math" ) ;
break ;
break ;
case "energy" :
case "energy" :
subjectURL = ` https://moose.lcsrc.org/subjects/energy.json ` ;
subjectURL = getSubjectUrl ( "energy" ) ;
break ;
break ;
default :
default :
message . channel . send ( "Not a valid subject!" ) ;
message . channel . send ( "Not a valid subject!" ) ;
return ;
return ;
}
}
const authorId = message . author . id ;
fetch ( subjectURL )
axios
. then ( ( response ) => response . json ( ) )
. get ( subjectURL )
. then ( ( data ) => {
. then ( ( res ) => {
const data = res . data ;
const questionNum = Math . floor ( Math . random ( ) * data . length ) ;
const questionNum = Math . floor ( Math . random ( ) * data . length ) ;
const messageFilter = ( m ) => m . author . id === authorId ;
const messageFilter = ( m ) => m . author . id === authorId ;
message . reply ( data [ questionNum ] . tossup_question ) . then ( ( ) => {
message . reply ( data [ questionNum ] . tossup_question ) . then ( ( ) => {
@ -156,8 +224,6 @@ client.on("message", async (message) => {
} )
} )
. then ( ( answerMsg ) => {
. then ( ( answerMsg ) => {
answerMsg = answerMsg . first ( ) ;
answerMsg = answerMsg . first ( ) ;
const userDocScore = userScore . findOne ( { authorID : authorId } ) . select ( "score" ) ;
let score = userDocScore || 0 ;
let predicted = null ;
let predicted = null ;
if ( data [ questionNum ] . tossup_format === "Multiple Choice" ) {
if ( data [ questionNum ] . tossup_format === "Multiple Choice" ) {
@ -198,33 +264,14 @@ client.on("message", async (message) => {
} )
} )
. then ( async ( userReaction ) => {
. then ( async ( userReaction ) => {
const reaction = userReaction . first ( ) ;
const reaction = userReaction . first ( ) ;
if ( reaction . emoji . name === "❌" ) {
if ( reaction . emoji . name == "❌" ) {
answerMsg . reply ( ` nice try! Your score is now ${ score . toString ( ) } ` ) ;
updateScore ( false , score , authorId ) . then ( ( msgToReply ) =>
} else {
answerMsg . reply ( msgToReply )
score += 4 ;
if ( score == 4 ) {
const newUserScore = new userScore ( {
authorID : authorId ,
score : score ,
} ) ;
newUserScore . save ( ( err ) =>
err
? console . log (
"Error creating new user for scoring"
)
: console . log (
"Sucessfully created user to score."
)
) ;
) ;
} else {
} else {
const doc = await userScore . findOne ( {
updateScore ( true , score , authorId ) . then ( ( msgToReply ) =>
authorID : authorId ,
answerMsg . reply ( msgToReply )
} ) ;
) ;
doc . score = doc . score + 4 ;
doc . save ( ) ;
}
answerMsg . reply ( ` nice job! Your score is now ${ score . toString ( ) } ` ) ;
}
}
} )
} )
. catch ( ( collected ) => { } ) ;
. catch ( ( collected ) => { } ) ;
@ -237,22 +284,19 @@ client.on("message", async (message) => {
. catch ( console . error ) ;
. catch ( console . error ) ;
}
}
} else {
} else {
if ( formattedMessage . startsWith ( "dobescoring" || "dobetraining" ) ) {
return ;
}
message . channel . send (
message . channel . send (
"That didn't quite make sense! Please use `do be helping` to see the available commands."
"That didn't quite make sense! Please use `do be helping` to see the available commands."
) ;
) ;
}
}
}
}
async function sendHelpMessage ( ) {
async function sendHelpMessage ( message ) {
message . channel . send (
message . channel . send (
new Discord . MessageEmbed ( ) . setTitle ( "Help" ) . setDescription ( helpMessage )
new Discord . MessageEmbed ( ) . setTitle ( "Help" ) . setDescription ( helpMessage )
) ;
) ;
}
}
async function generateRound ( isDM ) {
async function generateRound ( message , isDM ) {
fs . writeFile ( "index.html" , "<h1>Here's your round!</h1>" , ( error ) => {
fs . writeFile ( "index.html" , "<h1>Here's your round!</h1>" , ( error ) => {
if ( error ) {
if ( error ) {
console . log ( error ) ;
console . log ( error ) ;
@ -338,10 +382,10 @@ client.on("message", async (message) => {
}
}
}
}
async function startScoring ( ) {
async function startScoring ( message ) {
let scoreA = 0 ;
let scoreA = 0 ;
let scoreB = 0 ;
let scoreB = 0 ;
const scoreboard = await message . channel
await message . channel
. send ( ` Here's the score: \n Team A: ${ scoreA } \n Team B: ${ scoreB } ` )
. send ( ` Here's the score: \n Team A: ${ scoreA } \n Team B: ${ scoreB } ` )
. then ( ( scoreboard ) => {
. then ( ( scoreboard ) => {
const filter = ( m ) => m . content . includes ( "do be" ) ;
const filter = ( m ) => m . content . includes ( "do be" ) ;
@ -384,7 +428,8 @@ client.on("message", async (message) => {
} ) ;
} ) ;
} ) ;
} ) ;
}
}
async function dontWorryBeHappy ( ) {
async function dontWorryBeHappy ( message ) {
message . channel . send (
message . channel . send (
new Discord . MessageEmbed ( )
new Discord . MessageEmbed ( )
. setTitle ( ` Don't Worry Be Happy! ` )
. setTitle ( ` Don't Worry Be Happy! ` )
@ -393,11 +438,11 @@ client.on("message", async (message) => {
) ;
) ;
}
}
async function showServerNumber ( ) {
async function showServerNumber ( message ) {
message . channel . send ( client . guilds . cache . size ) ;
message . channel . send ( client . guilds . cache . size ) ;
}
}
async function showIssLocation ( ) {
async function showIssLocation ( message ) {
await fetch ( "http://api.open-notify.org/iss-now.json" )
await fetch ( "http://api.open-notify.org/iss-now.json" )
. then ( ( request ) => request . json ( ) )
. then ( ( request ) => request . json ( ) )
. then ( ( data ) => {
. then ( ( data ) => {
@ -412,30 +457,25 @@ client.on("message", async (message) => {
} ) ;
} ) ;
}
}
async function showLeaderboard ( ) {
async function showLeaderboard ( message ) {
let messageContent = "" ;
let messageContent = "" ;
let scores = [ ] ;
u serS core
. find ( { } )
const directoryPath = path . join ( "userScore" ) ;
. sort ( { score : - 1 } )
fs . readdir ( directoryPath , function ( err , files ) {
. exec ( ( err , obj ) => {
if ( err ) {
if ( err ) {
return console . log ( "Unable to scan directory: " + err ) ;
console . log ( err ) ;
return message . reply (
"Uh oh! :( There was an internal error. Please try again."
) ;
}
}
files . forEach ( function ( file ) {
if ( obj . length < 2 ) {
scores . push (
return message . reply (
` ${ fs . readFileSync ( "userScore/" + file , "utf8" ) } |<@ ${ file } > `
` There are only ${ obj . length } users, we need at least 10! `
) ;
) ;
} ) ;
const scoresFormatted = scores . sort ( function ( a , b ) {
return b . split ( "|" ) [ 0 ] - a . split ( "|" ) [ 0 ] ;
} ) ;
if ( scores . length < 10 ) {
message . channel . send ( "Not enough scores yet!" ) ;
return ;
}
}
for ( let i = 0 ; i < 10 ; i ++ ) {
for ( let i = 0 ; i < 2 ; i ++ ) {
const currentScore = scoresFormatted [ i ] . split ( "|" ) ;
messageContent += ` ${ i + 1 } : <@ ${ obj [ i ] . authorID } >: ${ obj [ i ] . score } \n ` ;
messageContent += ` ${ currentScore [ 1 ] } : ${ currentScore [ 0 ] } \n \n ` ;
}
}
message . channel . send (
message . channel . send (
new Discord . MessageEmbed ( )
new Discord . MessageEmbed ( )
@ -443,9 +483,49 @@ client.on("message", async (message) => {
. setDescription ( messageContent )
. setDescription ( messageContent )
) ;
) ;
} ) ;
} ) ;
console . log ( messageContent ) ;
}
client . on ( "message" , async ( message ) => {
if ( message . author . bot ) {
return ;
}
const formattedMessage = message . content . toLowerCase ( ) . replace ( /\s+/g , "" ) ;
if ( formattedMessage . startsWith ( "dobe" ) ) {
switch ( formattedMessage ) {
case "dobehelping" :
sendHelpMessage ( message ) ;
break ;
case "doberoundgen" :
generateRound ( message , false ) ;
break ;
case "doberoundgendm" :
generateRound ( message , true ) ;
break ;
case "dobescoring" :
startScoring ( message ) ;
break ;
case "dobetop" :
showLeaderboard ( message ) ;
break ;
case "dobehappy" :
dontWorryBeHappy ( message ) ;
break ;
case "dobeservers" :
showServerNumber ( message ) ;
break ;
case "dobeiss" :
showIssLocation ( message ) ;
break ;
default :
otherCommands ( message ) ;
}
}
}
} ) ;
} ) ;
client
client
. login ( process . env . TOKEN )
. login ( process . env . TOKEN )
. then ( ( ) => console . log ( "Running!" ) )
. catch ( ( error ) => console . log ( error ) ) ;
. catch ( ( error ) => console . log ( error ) ) ;