From 35b61312b9b173b98da29b66becb0fd0f5dca8fd Mon Sep 17 00:00:00 2001 From: hydrabolt Date: Sun, 23 Aug 2015 16:55:23 +0100 Subject: [PATCH] Deleted examples, beginning to write in EC6. Examples and Hydrabot will soon live in a separate repo which is better suited to learning - this is so the main package isn't bloated. --- .settings/settings.json | 3 + .settings/tasks.json | 220 ++++++++ examples/avatar.js | 37 -- examples/formatting.js | 24 - examples/pingpong.js | 32 -- examples/presence.js | 26 - examples/query.js | 61 --- examples/status.js | 24 - hydrabot/.gitignore | 2 - hydrabot/README.md | 19 - hydrabot/authority.js | 37 -- hydrabot/commands.js | 516 ------------------- hydrabot/hydrabot.js | 132 ----- index.js | 1087 --------------------------------------- jsconfig.json | 6 + lib/Client.js | 63 +++ lib/PMChannel.js | 6 +- lib/TokenManager.js | 83 ++- lib/asd.js | 63 +++ lib/channel.js | 15 +- lib/endpoints.js | 24 +- lib/index.js | 23 + lib/internal.js | 386 ++++++-------- lib/invite.js | 14 +- lib/list.js | 294 +++++++---- lib/message.js | 40 +- lib/server.js | 116 ++--- lib/user.js | 32 +- src/Client.js | 69 +++ src/Endpoints.js | 11 + src/PMChannel.js | 6 + src/TokenManager.js | 68 +++ src/channel.js | 28 + src/index.js | 21 + src/internal.js | 277 ++++++++++ src/invite.js | 21 + src/list.js | 248 +++++++++ src/message.js | 39 ++ src/server.js | 106 ++++ src/user.js | 37 ++ 40 files changed, 1830 insertions(+), 2486 deletions(-) create mode 100644 .settings/settings.json create mode 100644 .settings/tasks.json delete mode 100644 examples/avatar.js delete mode 100644 examples/formatting.js delete mode 100644 examples/pingpong.js delete mode 100644 examples/presence.js delete mode 100644 examples/query.js delete mode 100644 examples/status.js delete mode 100644 hydrabot/.gitignore delete mode 100644 hydrabot/README.md delete mode 100644 hydrabot/authority.js delete mode 100644 hydrabot/commands.js delete mode 100644 hydrabot/hydrabot.js delete mode 100644 index.js create mode 100644 jsconfig.json create mode 100644 lib/Client.js create mode 100644 lib/asd.js create mode 100644 lib/index.js create mode 100644 src/Client.js create mode 100644 src/Endpoints.js create mode 100644 src/PMChannel.js create mode 100644 src/TokenManager.js create mode 100644 src/channel.js create mode 100644 src/index.js create mode 100644 src/internal.js create mode 100644 src/invite.js create mode 100644 src/list.js create mode 100644 src/message.js create mode 100644 src/server.js create mode 100644 src/user.js diff --git a/.settings/settings.json b/.settings/settings.json new file mode 100644 index 000000000..20af2f68a --- /dev/null +++ b/.settings/settings.json @@ -0,0 +1,3 @@ +// Place your settings in this file to overwrite default and user settings. +{ +} \ No newline at end of file diff --git a/.settings/tasks.json b/.settings/tasks.json new file mode 100644 index 000000000..95c321163 --- /dev/null +++ b/.settings/tasks.json @@ -0,0 +1,220 @@ +// Available variables which can be used inside of strings. +// ${workspaceRoot}: the root folder of the team +// ${file}: the current opened file +// ${fileBasename}: the current opened file's basename +// ${fileDirname}: the current opened file's dirname +// ${fileExtname}: the current opened file's extension +// ${cwd}: the current working directory of the spawned process + +// A task runner that calls the Typescript compiler (tsc) and +// Compiles a HelloWorld.ts program +{ + "version": "0.1.0", + "command" : "babel", + "isShellCommand": true, + "tasks": [ + { + "taskName": "watch", + "suppressTaskName": true, + "isBuildCommand": true, + "isWatching": true, + "args": [ + "src", "--out-dir", "lib", "-w" + ] + } + ] +} + +// A task runner that calls the Typescript compiler (tsc) and +// compiles based on a tsconfig.json file that is present in +// the root of the folder open in VSCode +/* +{ + "version": "0.1.0", + + // The command is tsc. Assumes that tsc has been installed using npm install -g typescript + "command": "tsc", + + // The command is a shell script + "isShellCommand": true, + + // Show the output window only if unrecognized errors occur. + "showOutput": "silent", + + // Tell the tsc compiler to use the tsconfig.json from the open folder. + "args": ["-p", "."], + + // use the standard tsc problem matcher to find compile problems + // in the output. + "problemMatcher": "$tsc" +} +*/ + +// A task runner configuration for gulp. Gulp provides a less task +// which compiles less to css. +/* +{ + "version": "0.1.0", + "command": "gulp", + "isShellCommand": true, + "tasks": [ + { + "taskName": "less", + // Make this the default build command. + "isBuildCommand": true, + // Show the output window only if unrecognized errors occur. + "showOutput": "silent", + // Use the standard less compilation problem matcher. + "problemMatcher": "$lessCompile" + } + ] +} +*/ + +// Uncomment the following section to use gulp in a watching mode that compiles a +// less file. The gulp task prints "[hh:mm:ss] Starting 'clean-styles'" to the console +// when existing css files get deleted and "[hh:mm:ss] Finished 'styles'" when the +// overall less compilation has finished. When the clean pattern is detect internal less +// problems are cleaned. When the finshed pattern is detected in the output less +// problems are published. +/* +{ + "version": "0.1.0", + "command": "gulp", + "isShellCommand": true, + "tasks": [ + { + "taskName": "watch-less", + // Make this the default build command. + "isBuildCommand": true, + // Show the output window only if unrecognized errors occur. + "showOutput": "silent", + // Task is running in watching mode. + "isWatching": true, + "problemMatcher": { + // Use the standard less compilation problem matcher as the base. + "base": "$lessCompile", + // A regular expression signalling that a watched task begins executing (usually triggered through file watching). + "watchedTaskBeginsRegExp": "^\\[\\d+:\\d+:\\d+\\] Starting 'clean-styles'\\.\\.\\.$", + // A regular expression signalling that a watched tasks ends executing. + "watchedTaskEndsRegExp": "^\\[\\d+:\\d+:\\d+\\] Finished 'styles' after \\d+" + } + } + ] +} +*/ + +// Uncomment the following section to use jake to build a workspace +// cloned from https://github.com/Microsoft/TypeScript.git +/* +{ + "version": "0.1.0", + // Task runner is jake + "command": "jake", + // Need to be executed in shell / cmd + "isShellCommand": true, + "showOutput": "silent", + "tasks": [ + { + // TS build command is local. + "taskName": "local", + // Make this the default build command. + "isBuildCommand": true, + // Show the output window only if unrecognized errors occur. + "showOutput": "silent", + // Use the redefined Typescript output problem matcher. + "problemMatcher": [ + "$tsc" + ] + } + ] +} +*/ + +// Uncomment the section below to use msbuild and generate problems +// for csc, cpp, tsc and vb. The configuration assumes that msbuild +// is available on the path and a solution file exists in the +// workspace folder root. +/* +{ + "version": "0.1.0", + "command": "msbuild", + "args": [ + // Ask msbuild to generate full paths for file names. + "/property:GenerateFullPaths=true" + ], + "taskSelector": "/t:", + "showOutput": "silent", + "tasks": [ + { + "taskName": "build", + // Show the output window only if unrecognized errors occur. + "showOutput": "silent", + // Use the standard MS compiler pattern to detect errors, warnings + // and infos in the output. + "problemMatcher": "$msCompile" + } + ] +} +*/ + +// Uncomment the following section to use msbuild which compiles Typescript +// and less files. +/* +{ + "version": "0.1.0", + "command": "msbuild", + "args": [ + // Ask msbuild to generate full paths for file names. + "/property:GenerateFullPaths=true" + ], + "taskSelector": "/t:", + "showOutput": "silent", + "tasks": [ + { + "taskName": "build", + // Show the output window only if unrecognized errors occur. + "showOutput": "silent", + // Use the standard MS compiler pattern to detect errors, warnings + // and infos in the output. + "problemMatcher": [ + "$msCompile", + "$lessCompile" + ] + } + ] +} +*/ +// A task runner example that defines a problemMatcher inline instead of using +// a predfined one. +/* +{ + "version": "0.1.0", + "command": "tsc", + "isShellCommand": true, + "args": ["HelloWorld.ts"], + "showOutput": "silent", + "problemMatcher": { + // The problem is owned by the typescript language service. Ensure that the problems + // are merged with problems produced by Visual Studio's language service. + "owner": "typescript", + // The file name for reported problems is relative to the current working directory. + "fileLocation": ["relative", "${cwd}"], + // The actual pattern to match problems in the output. + "pattern": { + // The regular expression. Matches HelloWorld.ts(2,10): error TS2339: Property 'logg' does not exist on type 'Console'. + "regexp": "^([^\\s].*)\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(error|warning|info)\\s+(TS\\d+)\\s*:\\s*(.*)$", + // The match group that denotes the file containing the problem. + "file": 1, + // The match group that denotes the problem location. + "location": 2, + // The match group that denotes the problem's severity. Can be omitted. + "severity": 3, + // The match group that denotes the problem code. Can be omitted. + "code": 4, + // The match group that denotes the problem's message. + "message": 5 + } + } +} +*/ \ No newline at end of file diff --git a/examples/avatar.js b/examples/avatar.js deleted file mode 100644 index 32ad48a8f..000000000 --- a/examples/avatar.js +++ /dev/null @@ -1,37 +0,0 @@ -/* - * A bot that shows how to mention users in messages and how to - * access user avatars. - */ - -var Discord = require( "../" ); -var myBot = new Discord.Client(); - -myBot.login( "hello@example.com", "password1" ); - -// The "ready" event is triggered after the bot successfully connected to -// Discord and is ready to send messages. -myBot.on( "ready", function() { - console.log( "Bot connected successfully." ); -} ); - -myBot.on( "message", function( message ) { - // React to all messages with the content "$avatar" - if ( message.content === "$avatar" ) { - // Obtain the user who requested the avatar. - var user = message.author; - - // Check whether the user actually has an avatar. - if ( user.avatar ) { - // Construct the avatar URL from the user ID and the avatar ID. - var url = "https://discordapp.com/api/users/" + user.id + "/avatars/" + user.avatar + ".jpg"; - - // A user can be mentioned in a message by inserting the string obtained - // by user.mention() into the message. - // Note that simply writing "@user" will NOT work. - this.sendMessage( message.channel, message.author.mention() + ", here's your avatar: " + url ); - } else { - // Nothing should be done if the user has not set an avatar. - this.sendMessage( message.channel, message.author.mention() + ", you don't have an avatar!" ); - } - } -} ); diff --git a/examples/formatting.js b/examples/formatting.js deleted file mode 100644 index 02756eaaa..000000000 --- a/examples/formatting.js +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Discord uses a subset of Markdown for formatting, so adding formatting to - * messages is as simple as inserting the formatting codes into the message. - */ - -var Discord = require( "../" ); -var myBot = new Discord.Client(); - -myBot.login( "hello@example.com", "password1" ); - -// The "ready" event is triggered after the bot successfully connected to -// Discord and is ready to send messages. -myBot.on( "ready", function() { - console.log( "Bot connected successfully." ); -} ); - -myBot.on( "message", function( message ) { - // React to all messages with the content "$formatting". - if ( message.content === "$formatting" ) { - // Show off formatting by sending a simple message with formatting codes. - this.sendMessage( message.channel, "**bold** ****semibold**** *italic* " + - "_**bold and italic**_ __underline__ ~~strikethrough~~" ); - } -} ); diff --git a/examples/pingpong.js b/examples/pingpong.js deleted file mode 100644 index 51a2664e3..000000000 --- a/examples/pingpong.js +++ /dev/null @@ -1,32 +0,0 @@ -/* - * A basic bot that shows how to connect to a Discord account, - * how to listen to messages and how to send messages. - * - * This bot responds to every "ping" message with a "pong". - */ - -var Discord = require( "../" ); - -// Create the bot -var myBot = new Discord.Client(); - -// Login with an example email and password -myBot.login( "hello@example.com", "password1" ); - -// The "ready" event is triggered after the bot successfully connected to -// Discord and is ready to send messages. -myBot.on( "ready", function() { - console.log( "Bot connected successfully." ); -} ); - -// Add a listener to the "message" event, which triggers upon receiving -// any message -myBot.on( "message", function( message ) { - // message.content accesses the content of the message as a string. - // If it is equal to "ping", then the bot should respond with "pong". - if ( message.content === "ping" ) { - // Send a message ("pong") to the channel the message was sent in, - // which is accessed by message.channel. - this.sendMessage( message, "pong" ); - } -} ); diff --git a/examples/presence.js b/examples/presence.js deleted file mode 100644 index 9014feea2..000000000 --- a/examples/presence.js +++ /dev/null @@ -1,26 +0,0 @@ -/* - * A bot that shows how to listen to presence update events, such as a user - * joining or leaving. - */ - -var Discord = require( "../" ); -var myBot = new Discord.Client(); - -myBot.login( "hello@example.com", "password1" ); - -// The "ready" event is triggered after the bot successfully connected to -// Discord and is ready to send messages. -myBot.on( "ready", function() { - console.log( "Bot connected successfully." ); -} ); - -// The "presence" event is triggered when a user joins a server, leaves it or -// goes away. -// The status parameter can be "online", "offline" or "idle", respectively. -myBot.on( "presence", function( user, status, server ) { - // Send a message on the default channel of the server, as presence updates - // are not restricted to one channel. - var message = user.mention() + " is " + status + " in " + server.name + "!"; - console.log(message); - this.sendMessage( server.getDefaultChannel(), message ); -} ); diff --git a/examples/query.js b/examples/query.js deleted file mode 100644 index 9341e7e98..000000000 --- a/examples/query.js +++ /dev/null @@ -1,61 +0,0 @@ -/* - * A bot that shows how to access and search the logs of a specific channel. - * Specifically, it returns the last message from a given user in the last - * 100 messages. - */ - -var Discord = require( "discord.js" ); -var myBot = new Discord.Client(); - -myBot.login( "hello@example.com", "password1" ); - -myBot.on( "message", function( message ) { - // React to all messages starting with "$query". - if ( message.content.startsWith( "$query" ) ) { - // Obtain the channel for which logs should be accessed. - var channel = message.channel; - - // Find all the arguments to the command. - var arguments = message.content.split( " " ); - - // Get the first argument specifically, as it contains the username - // to be queried for. - var username = arguments.slice( 1 ).join( " " ); - - // Exit the event handler unless the user exists. - if ( !username ) { - myBot.sendMessage( channel, "That user doesn't exist!" ); - return; - } - - // The getChannelLogs() function takes the channel that should be accessed, - // the amount of messages to query and a callback as its arguments. - myBot.getChannelLogs( channel, 100, function( error, messageList ) { - // filter() takes three arguments, the key to be filtered for (in this - // case the username, so "username"), the value to look for, and whether - // only the first finding should be returned (true) or a list of all - // findings (false). - - // Check to see if there is an error, if there isn't this will be null, - // which equates to false in a conditional. - if ( error ) { - // There was an error, so stop proceeding as if there is an error - // retrieving logs, no logs are returned. We should tell the - // users that there was an error retrieving logs and return. - myBot.sendMessage( channel, "There was an error retrieving logs!" ); - return; - } - - var message = messageList.filter( "username", username, true ); - - // Only continue if the message has been found - if ( message ) { - myBot.sendMessage( channel, "The last message from user " + username + - " is: \"" + message.content + "\"." ). - } else { - myBot.sendMessage( "That user has not sent a message " + - "for the last 100 messages!" ) - } - } ); - } -} ); diff --git a/examples/status.js b/examples/status.js deleted file mode 100644 index 9ee2b9a6a..000000000 --- a/examples/status.js +++ /dev/null @@ -1,24 +0,0 @@ -/* - * A bot that doesn't interact with Discord, but instead shows how to listen - * to the "ready" and "disconnected" events, that are triggered when the bot - * starts up or shuts down, respectively. - */ - -var Discord = require( "../" ); -var myBot = new Discord.Client(); - -myBot.login( "hello@example.com", "password1" ); - -// The "ready" event is triggered after the bot successfully connected to -// Discord and is ready to send messages. -myBot.on( "ready", function() { - console.log( "Bot connected successfully." ); -} ); - -// The "disconnected" event is triggered after the connection to Discord -// ended. -// It is also triggered when the connection attempt fails, for example due -// to a wrong password. -myBot.on( "disconnected", function(e) { - console.log( "Bot disconnected from Discord -", e.reason ); -} ); diff --git a/hydrabot/.gitignore b/hydrabot/.gitignore deleted file mode 100644 index 070bc70aa..000000000 --- a/hydrabot/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -config.json -authority.json diff --git a/hydrabot/README.md b/hydrabot/README.md deleted file mode 100644 index 90aeffc4b..000000000 --- a/hydrabot/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# hydrabot -Hydrabot is an open-source bot made with the intents of demonstrating the capabilities of [discord.js](https://github.com/hydrabolt/discord.js/). - -### Set up -The easiest setup would be to clone the discord.js repo, and then open a terminal/cmd in this directory and run `node hydrabot.js`. - -If you don't want to clone the repo but instead just use this folder, you need to edit `hydrabot.js` to use `require("discord.js")` as opposed to `require("../")`. Cloned directories will always be using the latest **discord.js**. - -### Setting up credentials - -Create `config.json` to use your Discord email and password, and then run `node hydrabot.js`. - -What config.json should look like: -```js -{ - "email" : "your email", - "password" : "your password" -} -``` diff --git a/hydrabot/authority.js b/hydrabot/authority.js deleted file mode 100644 index 1f7c1c4af..000000000 --- a/hydrabot/authority.js +++ /dev/null @@ -1,37 +0,0 @@ -var fs = require( "fs" ); - -var authCache = {}; - -exports.init = function() { - try { - var fd = fs.openSync( "./authority.json", "wx" ); - exports.writeCache(); - } catch ( e ) { - if ( e.errno !== -4075 ){ - throw e; - }else{ - authCache = JSON.parse(fs.readFileSync("./authority.json", "utf8")); - } - } -} - -exports.getLevel = function(user){ - - if(authCache[user.id]) - return authCache[user.id]; - else - return 0; - -} - -exports.setLevel = function(user, level){ - authCache[user.id] = level; - exports.writeCache(); -} - -exports.writeCache = function() { - fs.writeFile( './authority.json', JSON.stringify(authCache), function( err ) { - if ( err ) - console.log("Error saving Authority Caches - " + err.code); - } ); -} diff --git a/hydrabot/commands.js b/hydrabot/commands.js deleted file mode 100644 index b499d9dce..000000000 --- a/hydrabot/commands.js +++ /dev/null @@ -1,516 +0,0 @@ -var Authority = require( "./authority.js" ); -var BotClass = require( "./hydrabot.js" ); -var Discord = BotClass.Discord; - -Commands = []; - -Commands[ "info" ] = { - oplevel: 0, - fn: function( bot, params, message ) { - - var verbose = hasFlag( params, "verbose" ) || hasFlag( params, "v" ); - var user = getUser( message, params ); - - bot.reply( message, [ - "here's some info on " + user.mention() + ":", - "In channel **#" + message.channel.name + "**" + ( verbose ? " - ID *" + message.channel.id + "*" : "" ), ( message.isPM() ? - "You're in a private conversation with me!" + ( verbose ? " The ID is " + message.channel.id : "" ) : "In the server **" + message.channel.server.name + "**" + ( verbose ? " - ID *" + message.channel.server.id + "*" : "" ) - ), - "User ID is *" + user.id + "*", - "Authority/OP Level to me is **" + Authority.getLevel( user ) + "**" - ], function( err ) { - if ( err ) - console.log( err ); - } ); - - } -} - -Commands[ "loading" ] = { - oplevel: 0, - fn: function( bot, params, message ) { - - var progress = 0; - var currentMessage; - var bars = 20; - - function getM() { - var before = progress; - var after = bars - progress; - var ret = ""; - for ( x = 0; x < before; x++ ) { - ret += "-"; - } - ret += "**#**"; - for ( y = 0; y < after; y++ ) { - ret += "-"; - } - return ret; - } - - function doProg() { - if ( progress === ( bars + 1 ) ) { - progress = 0; - } - - if ( currentMessage ) { - bot.updateMessage( currentMessage, getM(), function( err, msg ) { - if ( !err ) - currentMessage = msg; - } ); - progress++; - } - - } - - bot.sendMessage( message.channel, getM(), function( err, message ) { - currentMessage = message; - setInterval( doProg, 200 ); - } ); - - } -} - -Commands[ "flashy" ] = { - oplevel: 0, - fn: function( bot, params, message ) { - - var phase = 0; - var msg; - - var textToSay = getKey( params, "m", "FLASH" ); - var speed = parseInt( getKey( params, "s", "500" ) ); - - function change() { - if ( msg ) { - - var highlighting = ( ( phase % 2 ) === 0 ? "**" : "" ); - phase++; - bot.updateMessage( msg, highlighting + textToSay + highlighting, function( err, message ) { - if ( !err ) { - msg = message; - } - } ); - } - } - - bot.sendMessage( message.channel, textToSay, function( err, message ) { - msg = message; - setInterval( change, speed ); - } ); - - } -} - -Commands[ "echo" ] = { - oplevel: 0, - fn: function( bot, params, message ) { - - bot.sendMessage( message, params.join( " " ), function( err, msg ) { - if ( err ) { - bot.sendMessage( message, "Unable to echo!" ); - console.log( err ); - } - } ); - - } -} - -Commands[ "auth" ] = { - oplevel: 0, - fn: function( bot, params, message ) { - - var level = getKey( params, "level", "0" ); - var method = hasFlag( params, "set" ) ? "set" : "get"; - var user = getUser( message, params ); - - if ( method === "set" ) { - if ( authLevel( message.author ) <= level ) { - bot.reply( message, "that authority level is too high for you to set!" ); - } else if ( user.equals( message.author ) ) { - bot.reply( message, "you can't alter your own authority level!" ); - } else if ( authLevel( user ) >= authLevel( message.author ) ) { - bot.reply( message, "that user has a higher or equal OP level to you!" ); - } else if ( level < 0 ) { - bot.reply( message, "that level's a bit too low :P" ); - } else { - setAuthLevel( user, level ); - bot.reply( message, "I set the authority of " + user.mention() + " to **" + level + "**" ); - } - } else { - bot.reply( message, user.equals( message.author ) ? "Your authority level is **" + authLevel( user ) + "**" : "The authority level of " + user.mention() + " is **" + authLevel( user ) + "**" ); - } - - } -} - -Commands[ "clear" ] = { - oplevel: 0, - fn: function( bot, params, message ) { - - if ( !message.isPM() ) { - if ( authLevel( message.author ) < 1 ) { - bot.reply( message, BotClass.AUTH_ERROR ); - return; - } - } - - var initMessage = false, - cleared = false; - - bot.getChannelLogs( message.channel, 250, function( err, logs ) { - - if ( err ) { - bot.sendMessage( "Couldn't grab logs to delete messages." ); - } else { - - var deletedCount = 0, - failedCount = 0, - todo = logs.length(); - for ( msg of logs.contents ) { - if ( msg.author.equals( bot.user ) ) { - bot.deleteMessage( msg, function( err ) { - todo--; - if ( err ) - failedCount++; - else - deletedCount++; - - if ( todo === 0 ) { - bot.reply( - message, - "Done! " + deletedCount + " message(s) were deleted, with " + failedCount + " error(s).", - false, { - selfDestruct: 5000 - } - ); - cleared = true; - deleteInitMessage(); - } - } ); - } else { - todo--; - } - } - - } - - } ); - - bot.reply( message, "clearing up my messages...", function( err, msg ) { - if ( !err ) { - initMessage = msg; - if ( cleared ) - deleteInitMessage(); - } - } ); - - function deleteInitMessage() { - if ( initMessage ) { - bot.deleteMessage( initMessage ); - } - } - - } -} - -Commands[ "leave" ] = { - oplevel: 3, - fn: function( bot, params, message ) { - - var silent = hasFlag( params, "s" ) || hasFlag( params, "silent" ); - - if ( message.isPM() ) { - bot.reply( message, "Umm... I can't leave PMs... How awkward..." ); - } else { - - if ( !silent ) - bot.reply( message, "Ok ;( I'm leaving!" ); - - bot.leaveServer( message.channel.server, function( err ) { - if ( err ) { - bot.reply( message, "There was an error leaving... how awkward." ); - } - } ); - } - } -} - -Commands[ "avatar" ] = { - oplevel: 0, - fn: function( bot, params, message ) { - - var user = getUser( message, params, bot ); - - if ( !user.avatar ) { - bot.sendMessage( message.channel, user.mention() + " does not have an avatar!" ); - } else { - bot.reply( message, user.getAvatarURL() ); - } - } -} - -Commands[ "setusername" ] = { - oplevel: 3, - fn: function( bot, params, message ) { - - var name = getKey( params, "name", "Boris Johnson" ); - - bot.setUsername( name, function( err ) { - if ( err ) - bot.reply( message, err ); - } ) - - } -} - -Commands[ "cat" ] = { - oplevel: 0, - fn: function( bot, params, message ) { - - var http = require( "http" ); - var request = require( 'request' ); - - bot.sendFile( message, request("http://thecatapi.com/api/images/get?type=jpg"), "cat.jpg", function( err ) { - if(err) - bot.reply( message, err ); - } ); - - } -} - -Commands[ "icon" ] = { - oplevel: 0, - fn: function( bot, params, message ) { - - if ( message.isPM() ) { - bot.reply( message, "PMs don't have avatars!" ); - return; - } - - if ( !message.channel.server.icon ) { - bot.reply( message, "this server does not have an icon!" ); - return; - } - - bot.reply( message, message.channel.server.getIconURL() ); - - } -} - -Commands[ "avataritup" ] = { - oplevel: 2, - fn: function( bot, params, message ) { - - console.log( message.channel ); - bot.sendMessage( message, message.channel.server.members.getValues( "avatar" ).join( "\n" ) ); - - } -} - -Commands[ "feedback" ] = { - - oplevel: 0, - fn: function( bot, params, message ) { - - var amount = getKey( params, "amount" ) || getKey( params, "n" ) || 1000; - - bot.getChannelLogs( message.channel, amount, function( err, logs ) { - - console.log( logs ); - - if ( err ) { - bot.reply( message, "an error occurred when grabbing the logs.", false, { - selfDestruct: 3000 - } ); - } else { - - var found = []; - for ( msg of logs.contents ) { - - if ( ~msg.content.indexOf( "[request" ) || ~msg.content.indexOf( "[feature" || ~msg.content.indexOf( "[suggestion" ) ) ) { - if ( msg.content.length > 10 ) { - found.push( msg ); - } - } - - } - - bot.sendMessage( message.author, "Ok, here's a rundown of all feature requests so far:", function( err, ms ) { - - if ( !err ) - gothroughit(); - - } ); - - bot.reply( message, "I found " + found.length + " result(s) that matched this. I'll send it to you in a PM.", false, { - selfDestruct: 3000 - } ); - - function gothroughit() { - for ( msg of found ) { - - bot.sendMessage( message.author, "**" + msg.author.username + "** said:\n " + msg.content ); - - } - } - } - } ); - - } - -} - -Commands[ "acceptinvite" ] = { - oplevel: 0, - fn: function( bot, params, message ) { - - var inv = getKey( params, "i" ); - - bot.joinServer( inv, function( err, server ) { - if ( err ) { - bot.reply( message, "I couldn't join that server :(" ); - } else { - bot.reply( message, "I joined **" + server.name + "**, a server with " + server.channels.length() + " channels and " + server.members.length() + " members." ); - } - } ); - - } -} - -Commands[ "filtertest" ] = { - oplevel: 0, - fn: function( bot, params, message ) { - console.log( message.channel.server.members.filter( "username", "HYDRABOLT" ) ); - console.log( message.channel.server.members.filter( "username", "HYDRABOLT", false, true ) ); - } -} - -Commands[ "test" ] = { - oplevel: 0, - fn: function( bot, params, message ) { - - console.log( message.channel.server.channels.filter( "name", "a", true ) ); - - } -} - -Commands[ "remind" ] = { - oplevel: 0, - fn: function( bot, params, message ) { - - var time = parseInt( getKey( params, "t" ) || getKey( params, "time" ) ) * 1000 || 21000; - var msg = getKey( params, "m" ) || getKey( params, "msg" ) || getKey( params, "message" ); - - bot.reply( message, "I'll remind you to *" + msg + "* in *" + time / 1000 + "* seconds.", false, true, { - selfDestruct: time - } ); - - setTimeout( send, time ); - - function send() { - bot.sendMessage( message.author, time + " seconds are up! **" + msg + "**." ); - } - - } -} - -Commands[ "annoy" ] = { - oplevel: 0, - fn: function( bot, params, message ) { - - var user = getUser( message, params ); - - bot.sendMessage( user, "Ha I'm annoying you on " + message.author.mention() + "'s request!" ); - - } -} - -Commands[ "activity" ] = { - oplevel: 0, - fn: function( bot, params, message ) { - - var amount = getKey( params, "amount" ) || getKey( params, "n" ) || 250; - var limit = getKey( params, "limit" ) || getKey( params, "l" ) || 10; - - bot.getChannelLogs( message.channel, amount, function( err, logs ) { - - if ( err ) { - bot.reply( message, "error gettings logs." ); - } else { - - var activity = {}, - count = 0; - for ( msg of logs.contents ) { - - count = logs.length(); - - if ( !activity[ msg.author.id ] ) - activity[ msg.author.id ] = 0; - activity[ msg.author.id ]++; - } - - var report = "here's a list of activity over the last " + count + " messages :\n\n"; - - var usernames = {}; - for ( id in activity ) { - usernames[ id ] = bot.getUser( id ).username; - } - - for ( id in activity ) { - report += usernames[ id ] + " | " + activity[ id ] + " | **" + Math.round( ( activity[ id ] / count ) * 100 ) + "%**.\n"; - } - - bot.reply( message, report, false, false ); - } - - } ); - - } -} - -exports.Commands = Commands; - -function hasFlag( array, flag ) { - return ~array.indexOf( flag ); -} - -function getKey( array, key, def ) { - - for ( element of array ) { - var chunks = element.split( "=" ); - if ( chunks.length > 1 ) { - if ( chunks[ 0 ] == key ) { - return chunks[ 1 ]; - } - } - } - - return def; - -} - -function authLevel( user ) { - return Authority.getLevel( user ); -} - -function setAuthLevel( user, level ) { - Authority.setLevel( user, level ); -} - -function getUser( message, params, bot ) { - var usr = false; - if ( !message.isPM() ) { - var wantedUser = getKey( params, "user", false ) || getKey( params, "u", false ); - if ( wantedUser ) { - if ( bot ) { - console.log( bot.getUsers().length() ); - return bot.getUsers().filter( "username", wantedUser, true ); - } - usr = message.channel.server.members.filter( Discord.isUserID( wantedUser ) ? "id" : "username", wantedUser, true ); - } - } - if ( !usr ) - usr = message.author; - return usr; -} diff --git a/hydrabot/hydrabot.js b/hydrabot/hydrabot.js deleted file mode 100644 index 4f010266d..000000000 --- a/hydrabot/hydrabot.js +++ /dev/null @@ -1,132 +0,0 @@ -// If you did not clone discord.js, change the require parameter to `discord.js` -// and then run `npm install --save discord.js` in the same directory as this -// file. The bot should then run. -var Discord = require( "../" ); -exports.Discord = Discord; - -// Load the config file. If you have not already, make one that follows the -// structure : { "email" : "discordEmail", "password" : "discordPassword" } -var BotConfig = require( "./config.json" ); - -// Load the commands file -var Commands = require( "./commands.js" ).Commands; - -// Load the Authority handler -var Authority = require( "./authority.js" ); - -// Initialise it -Authority.init(); - -// Create a new Discord Client -var hydrabot = new Discord.Client(); - -// An array of single character prefixes the bot will respond to -var commandPrefixes = [ "$", "£", "`" ]; - -// Log the client in using the auth details in config.json - -hydrabot.on("debug", function(m){ - console.log("debug", m); -}) - -console.time("hydrabotbenchmark"); -hydrabot.login( BotConfig.email, BotConfig.password ); -var time = Date.now(); - -// When the bot is ready to go, output to the console -hydrabot.on( "ready", function() { - console.timeEnd("hydrabotbenchmark"); -} ); - -hydrabot.on("userupdate", function(ol, ne){ - - var serversInvolved = hydrabot.getServers().deepFilter(["members", "id"], ol.id); - - for(server of serversInvolved.contents){ - hydrabot.sendMessage(server.getDefaultChannel(), "Just sayin', "+ol.username+" changed their name to "+ne.username+". I know. Disgraceful.", function(err){ - console.log(err); - }, { - selfDestruct: 5000 - }); - } - -}); - -// When the bot gets disconnected, exit. -hydrabot.on( "disconnected", function( obj ) { - // Say we couldn't connect and then exit - console.log( "Disconnected - " + obj.reason ); - process.exit( 0 ); -} ); - -hydrabot.on("messageDelete", function(message){ - console.log(message); -}) - -hydrabot.on("messageUpdate", function(former, edit){ - /* - if(former){ - - if(former.author.equals(this.user) || former.content === edit.content){ - return; - } - - var seconds = Math.round((Date.now() - former.time) / 1000); - - var channel = former.channel; - hydrabot.sendMessage(channel, "**"+former.author.username + "** (edit from message "+seconds+" seconds ago):\n " + former.content); - - } - */ -}) - -hydrabot.on( "message", function( message ) { - - // if the message doesn't begin with a valid command prefix exit - - if ( commandPrefixes.indexOf( message.content.charAt( 0 ) ) == -1 ) - return; - - var command = "", - params = []; //set the message details - - // remove the prefix from the start of the message - message.content = message.content.substr( 1 ); - - // split the message by slashes. This will yield something - // like: ["command", "a", "b", "c"]. - var chunks = message.content.split( "/" ); - - for ( key in chunks ) { //loop through the chunks and trim them - chunks[ key ] = chunks[ key ].trim(); - } - - command = chunks[ 0 ]; //the first param will be the command - params = chunks.slice( 1 ); - - // it's less messy if we outsource to another function - handleMessage( command, params, message ); - -} ); - -function handleMessage( command, params, message ) { - - if ( Commands[ command ] ) { - - if ( Authority.getLevel( message.author ) >= Commands[ command ].oplevel ) { - //user has authority to do this - Commands[ command ].fn( hydrabot, params, message ); - - } else { - //user doesn't have authority - hydrabot.reply( message, exports.AUTH_ERROR ); - } - - } else { - hydrabot.reply( message, exports.NOT_FOUND ); - } - -} - -exports.AUTH_ERROR = "you don't have authority to do this!"; -exports.NOT_FOUND = "that command was not found!"; diff --git a/index.js b/index.js deleted file mode 100644 index d8b9a1560..000000000 --- a/index.js +++ /dev/null @@ -1,1087 +0,0 @@ -var request = require("superagent"); -var Endpoints = require("./lib/endpoints.js"); -var Server = require("./lib/server.js").Server; -var Message = require("./lib/message.js").Message; -var User = require("./lib/user.js").User; -var Channel = require("./lib/channel.js").Channel; -var List = require("./lib/list.js").List; -var Invite = require("./lib/invite.js").Invite; -var PMChannel = require("./lib/PMChannel.js").PMChannel; -var WebSocket = require('ws'); -var Internal = require("./lib/internal.js").Internal; -var TokenManager = require("./lib/TokenManager.js").TokenManager; - -var serverCreateRequests = [], - globalLoginTime = Date.now(); - -function tp(time) { - return Date.now() - time; -} - -/** - * The wrapper module for the Discord Client, also provides some helpful objects. - * - * @module Discord - */ -exports; - -exports.Endpoints = Endpoints; -exports.Server = Server; -exports.Message = Message; -exports.User = User; -exports.Channel = Channel; -exports.List = List; -exports.Invite = Invite; -exports.PMChannel = PMChannel; - -/** - * The Discord Client used to interface with the Discord API. Instantiate this to start writing code - * with discord.js - * @class Client - * @constructor - * @param {Object} [options] An object containing configurable options. - * @param {Number} [options.maxmessage=5000] The maximum amount of messages to be stored per channel. - */ - -exports.Client = function (shouldUseTokenManager) { - - /** - * Contains the options of the client - * @attribute options - * @type {Object} - */ - if (shouldUseTokenManager) - this.tokenManager = new TokenManager("./", "tokencache.json"); - /** - * Contains the token used to authorise HTTP requests and WebSocket connection. Received when login was successful. - * @attribute token - * @readonly - * @type {String} - */ - this.token = ""; - /** - * Indicates whether the client is logged in or not. Does not indicate whether the client is ready. - * @attribute loggedIn - * @readonly - * @type {Boolean} - */ - this.loggedIn = false; - /** - * The WebSocket used when receiving message and other event updates. - * @type {WebSocket} - * @attribute websocket - * @readonly - */ - this.websocket = null; - /** - * An Object containing the functions tied to events. These should be set using Client.on(); - * @type {Object} - * @attribute events - */ - this.events = {}; - /** - * The User of the Client class, set when the initial startup is complete. - * @attribute user - * @type {User} - * @readonly - */ - this.user = null; - /** - * Indicates whether the Client is ready and has cached all servers it as aware of. - * @type {Boolean} - * @attribute ready - * @readonly - */ - this.ready = false; - /** - * A List containing all the Servers the Client has access to. - * @attribute serverList - * @type {List} - * @readonly - */ - this.serverList = new List("id"); - /** - * A List containing all the PMChannels the Client has access to. - * @attribute PMList - * @type {List} - * @readonly - */ - this.PMList = new List("id"); - -} - -/** - * Returns a list of all servers that the Discord Client has access to. - * - * @method getServers - * @return {List} ServerList - */ -exports.Client.prototype.getServers = function () { - return this.serverList; -} - -/** - * Returns a list of all servers that the Discord Client has access to. - * @method getChannels - * @return {List} Channelist - */ -exports.Client.prototype.getChannels = function () { - return this.serverList.concatSublists("channels", "id"); -} - -/** - * Returns a Server matching the given id, or false if not found. Will return false if the server is not cached or not available. - * @method getServer - * @param {String/Number} id The ID of the Server - * @return {Server} The Server matching the ID - */ -exports.Client.prototype.getServer = function (id) { - return this.getServers().filter("id", id, true); -} - -/** - * Returns a Channel matching the given id, or false if not found. Will return false if the Channel is not cached or not available. - * @method getChannel - * @param {String/Number} id The ID of the Channel - * @return {Server} The Channel matching the ID - */ -exports.Client.prototype.getChannel = function (id) { - return this.getChannels().filter("id", id, true); -} - -/** - * Returns a Channel matching the given name, or false if not found. Will return false if the Channel is not cached or not available. - * @method getChannelByName - * @param {String/Number} name The Name of the Channel - * @return {Server} The Channel matching the Name - */ -exports.Client.prototype.getChannelByName = function (name) { - return this.getChannels().filter("name", name, true); -} - -/** - * Triggers an .on() event. - * @param {String} event The event to be triggered - * @param {Array} args The arguments to be passed onto the method - * @return {Boolean} whether the event was triggered successfully. - * @method triggerEvent - * @private - */ -exports.Client.prototype.triggerEvent = function (event, args) { - - if (!this.ready && event !== "raw" && event !== "disconnected" && event !== "debug") { //if we're not even loaded yet, don't try doing anything because it always ends badly! - return false; - } - - if (this.events[event]) { - this.events[event].apply(this, args); - return true; - } else { - return false; - } - -} - -/** - * Binds a function to an event - * @param {String} name The event name which the function should be bound to. - * @param {Function} fn The function that should be bound to the event. - * @method on - */ -exports.Client.prototype.on = function (name, fn) { - this.events[name] = fn; -} - -/** - * Unbinds a function from an event - * @param {String} name The event name which should be cleared - * @method off - */ -exports.Client.prototype.off = function (name) { - this.events[name] = function () { }; -} - -exports.Client.prototype.cacheServer = function (id, cb, members) { - var self = this; - var serverInput = {}; - - if (typeof id === 'string' || id instanceof String) { - //actually an ID - - if (this.serverList.filter("id", id).length > 0) { - return; - } - - Internal.XHR.getServer(self.token, id, function (err, data) { - if (!err) { - makeServer(data); - } - }) - - } else { - // got objects because SPEEEDDDD - - if (this.serverList.filter("id", id.id).length > 0) { - return; - } - serverInput = id; - id = id.id; - makeServer(serverInput); - - } - - function channelsFromHTTP() { - Internal.XHR.getChannel(self.token, id, function (err) { - if (!err) - cacheChannels(res.body); - }) - } - - var server; - - function makeServer(dat) { - server = new Server(dat.region, dat.owner_id, dat.name, id, serverInput.members || dat.members, dat.icon, dat.afk_timeout, dat.afk_channel_id); - if (dat.channels) - cacheChannels(dat.channels); - else - channelsFromHTTP(); - } - - function cacheChannels(dat) { - - var channelList = dat; - for (var channel of channelList) { - server.channels.add(new Channel(channel, server)); - } - self.serverList.add(server); - - cb(server); - } - -} - -/** - * Logs the Client in with the specified credentials and begins initialising it. - * @async - * @method login - * @param {String} email The Discord email. - * @param {String} password The Discord password. - * @param {Function} [callback] Called when received reply from authentication server. - * @param {Object} callback.error Set to null if there was no error logging in, otherwise is an Object that - * can be evaluated as true. - * @param {String} callback.error.reason The reason why there was an error - * @param {Object} callback.error.error The raw XHR error. - * @param {String} callback.token The token received when logging in - */ -exports.Client.prototype.login = function (email, password, callback, noCache) { - - globalLoginTime = Date.now(); - - this.debug("login called at " + globalLoginTime); - - var self = this; - callback = callback || function () { }; - - if (noCache == undefined || noCache == null) { - noCache = false; - } - - self.connectWebsocket(); - - if (this.tokenManager) { - if (this.tokenManager.exists(email) && !noCache) { - - var token = this.tokenManager.getToken(email, password); - if (!token.match(/[^\w.-]+/g)) { - done(this.tokenManager.getToken(email, password)); - self.debug("loaded token from caches in " + tp(globalLoginTime)); - return; - } else { - self.debug("error getting token from caches, using default auth"); - } - } - } - var time = Date.now(); - Internal.XHR.login(email, password, function (err, token) { - if (err) { - self.triggerEvent("disconnected", [{ - reason: "failed to log in", - error: err - }]); - self.websocket.close(); - self.debug("failed to login in " + tp(globalLoginTime)); - } else { - if (!noCache) { - self.tokenManager.addToken(email, token, password); - } - self.debug("loaded token from auth servers in " + tp(globalLoginTime)); - done(token); - } - - }); - - function done(token) { - self.email = email; - self.password = password; - self.debug("using token " + token); - self.token = token; - self.websocket.sendData(); - self.loggedIn = true; - callback(null, token); - } -} - -/** - * Replies to a message with a given message - * @param {Message/User/Channel/Server/String} destination Where the message should be sent. Channel IDs can also be used here. - * @param {String/Message/Array} toSend If a message, the message's content will be sent. If an array, a message will be sent of - * the array seperated by a newline. If a String, the string will be sent. - * @param {Function} callback Called when a response from the API has been received, the message has either been sent or not. - * @param {Object} callback.error If there was an error, this would be an XHR Error object. Otherwise, it will be null. - * @param {Message} callback.message If there were no errors, this will be the sent message in Message form. - * @param {Object} options see sendMessage(options) - * @method reply - */ -exports.Client.prototype.reply = function (destination, toSend, callback, options) { - - if (toSend instanceof Array) { - toSend = toSend.join("\n"); - } - - toSend = destination.author.mention() + ", " + toSend; - - this.sendMessage(destination, toSend, callback, options); - -} - -exports.Client.prototype.connectWebsocket = function (cb) { - - var self = this; - - var sentInitData = false; - - this.websocket = new WebSocket(Endpoints.WEBSOCKET_HUB); - this.websocket.onclose = function (e) { - self.triggerEvent("disconnected", [{ - reason: "websocket disconnected", - error: e - }]); - }; - this.websocket.onmessage = function (e) { - - self.triggerEvent("raw", [e]); - - var dat = JSON.parse(e.data); - var webself = this; - - switch (dat.op) { - - case 0: - if (dat.t === "READY") { - - self.debug("got ready packet"); - - var data = dat.d; - - self.user = new User(data.user); - - var _servers = data.guilds, - servers = []; - - var cached = 0, - toCache = _servers.length; - - for (x in data.private_channels) { - self.PMList.add(new PMChannel(data.private_channels[x].recipient, data.private_channels[x].id)); - } - - for (x in _servers) { - _server = _servers[x]; - - self.cacheServer(_server, function (server) { - cached++; - if (cached === toCache) { - self.ready = true; - self.triggerEvent("ready"); - self.debug("ready triggered"); - } - }); - } - - setInterval(function () { - webself.keepAlive.apply(webself); - }, data.heartbeat_interval); - - } else if (dat.t === "MESSAGE_CREATE") { - var data = dat.d; - - var channel = self.getChannel(data.channel_id); - var message = new Message(data, channel); - self.triggerEvent("message", [message]); - if (channel.messages) - channel.messages.add(message); - - } else if (dat.t === "MESSAGE_DELETE") { - var data = dat.d; - - var channel = self.getChannel(data.channel_id); - - if (!channel.messages) - return; - - var _msg = channel.messages.filter("id", data.id, true); - - if (_msg) { - self.triggerEvent("messageDelete", [_msg]); - channel.messages.removeElement(_msg); - } - - } else if (dat.t === "MESSAGE_UPDATE") { - - var data = dat.d; - if (!self.ready) - return; - - var formerMessage = false; - - var channel = self.getChannel(data.channel_id); - - if (channel) { - - formerMessage = channel.messages.filter("id", data.id, true); - var newMessage; - - data.author = data.author || formerMessage.author; - data.timestamp = data.time || formerMessage.time; - data.content = data.content || formerMessage.content; - data.channel = data.channel || formerMessage.channel; - data.id = data.id || formerMessage.id; - data.mentions = data.mentions || formerMessage.mentions; - data.mention_everyone = data.mention_everyone || formerMessage.everyoneMentioned; - data.embeds = data.embeds || formerMessage.embeds; - - try { - newMessage = new Message(data, channel); - } catch (e) { - self.debug("dropped a message update packet"); - return; - } - - self.triggerEvent("messageUpdate", [formerMessage, newMessage]); - - if (formerMessage) - channel.messages.updateElement(formerMessage, newMessage); - else - channel.messages.add(newMessage); - - } - - } else if (dat.t === "PRESENCE_UPDATE") { - - var data = dat.d; - var getUser = self.getUser(data.user.id); - if (getUser) { - //user already exists - var usr = new User(data.user); - if (usr.equalsStrict(getUser)) { - //no changes, actually a presence. - } else { - if (self.updateUserReferences(data.user.id, getUser, new User(data.user))) { - self.triggerEvent("userupdate", [getUser, usr]); - } - } - } - self.triggerEvent("presence", [new User(data.user), data.status, self.serverList.filter("id", data.guild_id, true)]); - - } else if (dat.t === "GUILD_DELETE") { - - var deletedServer = self.serverList.filter("id", dat.d.id, true); - - if (deletedServer) { - self.triggerEvent("serverDelete", [deletedServer]); - } - - } else if (dat.t === "CHANNEL_DELETE") { - - var delServer = self.serverList.filter("id", dat.d.guild_id, true); - - if (delServer) { - var channel = delServer.channels.filter("id", dat.d.id, true); - - if (channel) { - self.triggerEvent("channelDelete", [channel]); - } - } - - } else if (dat.t === "GUILD_CREATE") { - - if (!self.serverList.filter("id", dat.d.id, true)) { - self.cacheServer(dat.d, function (server) { - if (serverCreateRequests[server.id]) { - serverCreateRequests[server.id](null, server); - serverCreateRequests[server.id] = null; - } else { - self.triggerEvent("serverJoin", [server]); - } - }); - } - - } else if (dat.t === "CHANNEL_CREATE") { - - var srv = self.serverList.filter("id", dat.d.guild_id, true); - - if (srv) { - - if (!srv.channels.filter("id", dat.d.d, true)) { - - var chann = new Channel(dat.d, srv); - - srv.channels.add(new Channel(dat.d, srv)); - self.triggerEvent("channelCreate", [chann]); - - } - - } - - } else if (dat.t === "USER_UPDATE") { - - if (dat.d.id === self.user.id) { - var newUsr = new User(dat.d); - self.triggerEvent("userupdate", [self.user, newUsr]); - self.user = newUsr; - } - - } else if (dat.t === "GUILD_MEMBER_ADD") { - - var srv = self.getServer(dat.d.guild_id); - if (srv) { - var usr = new User(dat.d.user); - srv.members.add(usr); - self.triggerEvent("serverMemberAdd", [usr]); - } - - } else if (dat.t === "GUILD_MEMBER_REMOVE") { - - var srv = self.getServer(dat.d.guild_id); - if (srv) { - var usr = new User(dat.d.user); - srv.members.removeElement(usr); - self.triggerEvent("serverMemberRemove", [usr]); - } - - } - break; - - } - - }; - this.websocket.sendPacket = function (p) { - this.send(JSON.stringify(p)); - } - this.websocket.keepAlive = function () { - - if (this.readyState !== 1) - return false; - - this.sendPacket({ - op: 1, - d: Date.now() - }); - - } - this.websocket.onopen = function () { - - self.debug("websocket conn open"); - this.sendData("onopen"); - - } - this.websocket.sendData = function (why) { - if (this.readyState == 1 && !sentInitData && self.token) { - sentInitData = true; - var connDat = { - op: 2, - d: { - token: self.token, - v: 2 - } - }; - - connDat.d.properties = Internal.WebSocket.properties; - this.sendPacket(connDat); - } - } -} - -exports.Client.prototype.debug = function (msg) { - this.triggerEvent("debug", ["[SL " + tp(globalLoginTime) + "] " + msg]); -} - -/** - * Logs the current Client out of Discord and closes any connections. - * @param {Function} callback Called after a response is obtained. - * @param {Object} callback.error Null unless there was an error, in which case is an XHR error. - * @method logout - */ -exports.Client.prototype.logout = function (callback) { - - callback = callback || function () { }; - - var self = this; - - Internal.XHR.logout(self.token, function (err) { - if (err) { - callback(err); - } - self.loggedIn = false; - self.websocket.close(); - }); - -} - -/** - * Creates a server with the specified name and region and returns it - * @param {String} name The name of the server - * @param {String} region The region of the server - * @param {Function} callback Called when the request is made. - * @param {Object} callback.error An XHR error or null if there were no errors. - * @param {Server} callback.server A Server object representing the created server. - * @method createServer - * @async - */ -exports.Client.prototype.createServer = function (name, region, cb) { - - var self = this; - - Internal.XHR.createServer(self.token, name, region, function (err, data) { - - if (err) { - cb(err); - } else { - - self.cacheServer(data, function (server) { - cb(null, server); - }); - - } - - }); - -} - -/** - * Makes the Client leave the Server - * @param {Server} server A server object. The server you want to leave. - * @param {Function} callback Called when the leave request is made. - * @param {Object} callback.error An XHR error or null if there were no errors. - * @param {Server} callback.server A Server object representing the deleted server. - * @method leaveServer - * @async - */ -exports.Client.prototype.leaveServer = function (server, callback) { - - var self = this; - - // callback is not necessary for this function - callback = callback || function () { }; - - Internal.XHR.leaveServer(self.token, server.id, function (err) { - - if (err) { - callback(err); - } else { - self.serverList.removeElement(server); - callback(null, server); - } - - }); - -} - -/** - * Creates an Invite to the specified channel/server with the specified options - * @param {Channel/Server} channel The channel/server the invite is to be made to. - * @param {Object} [options] The options for the invite - * @param {Number} [options.max_age=0] When the invite will expire in seconds - * @param {Number} [options.max_uses=0] How many uses the invite has - * @param {Boolean} [options.temporary=false] Whether the invite is temporary - * @param {Boolean} [options.xkcdpass=false] Whether the invite's code should be composed of words. - * @param {Function} callback Called when the invite request has been made - * @param {Object} callback.error An XHR Error or null if there were no errors. - * @param {Invite} callback.invite An invite object representing the created invite. - * @method createInvite - */ -exports.Client.prototype.createInvite = function (channel, options, callback) { - - var self = this; - var options = options || {}; - - // callback is not necessary for this function - callback = callback || function () { }; - - if (channel instanceof Server) { - channel = channel.getDefaultChannel(); - } - - options.max_age = options.max_age || 0; - options.max_uses = options.max_uses || 0; - options.temporary = options.temporary || false; - options.xkcdpass = options.xkcd || false; - - Internal.XHR.createInvite(self.token, channel.id, options, function (err, data) { - - if (err) { - callback(err); - } else { - callback(null, new Invite(data)); - } - - }); - -} - -exports.Client.prototype.startPM = function (user, callback) { - - var self = this; - - callback = callback || function () { }; - - Internal.XHR.startPM(self.token, self.user.id, user.id, function (err, data) { - - if (err) { - callback(err); - } else { - var channel = new PMChannel(data.recipient, data.id); - self.PMList.add(channel); - callback(null, channel); - } - - }); - -} - -/** - * Sends a message to the specified destination. - * @param {Server/Channel/PMChannel/Message/User/String} destination Where the message should be sent. If this is a String, the String should be a channel ID. - * @param {String/Array/Message} toSend The message to send. If an array, the array will be seperated into new lines and then sent. - * @param {Function} callback Called when the message has been sent. - * @param {Object} error An XHR Error or null if there were no errors. - * @param {Message} message A message object representing the sent object. - * @param {Object} [options] An object containing options for the message. - * @param {Array/Boolean/String} [options.mentions=true] If an Array, it should be an array of User IDs. If a boolean, false will - * notify no-one, and true will figure out who should be mentioned based on the message. If a String, should be a User - * ID. - * @param {Number} [options.selfDestruct=false] If specified, should be the amount of milliseconds at which the message should - * delete itself after being sent. - * @method sendMessage - */ - -exports.Client.prototype.sendFile = function (destination, toSend, fileName, callback, options) { - - this.sendMessage(destination, toSend, callback, options, fileName); - -} - -exports.Client.prototype.sendMessage = function (destination, toSend, callback, options, fileName) { - - options = options || {}; - callback = callback || function () { }; - - var channel_id, message, mentions, self = this; - - channel_id = resolveChannel(destination, self); - if (!fileName) { - message = resolveMessage(toSend); - mentions = resolveMentions(message, options.mention); - } - - if (channel_id) { - send(); - } else { - //a channel is being sorted - } - - function send() { - - if (fileName) { - Internal.XHR.sendFile(self.token, channel_id, toSend, fileName, function (err) { - - callback(err); - - }); - return; - } - - Internal.XHR.sendMessage(self.token, channel_id, { - content: message, - mentions: mentions - }, function (err, data) { - if (err) { - callback(err); - } else { - var msg = new Message(data, self.getChannel(data.channel_id)); - if (options.selfDestruct) { - setTimeout(function () { - self.deleteMessage(msg); - }, options.selfDestruct); - } - callback(null, msg); - } - }); - } - - function setChannId(id) { - channel_id = id; - } - - function resolveChannel(destination, self) { - var channel_id = false; - if (destination instanceof Server) { - channel_id = destination.getDefaultChannel().id; - } else if (destination instanceof Channel) { - channel_id = destination.id; - } else if (destination instanceof PMChannel) { - channel_id = destination.id; - } else if (destination instanceof Message) { - channel_id = destination.channel.id; - } else if (destination instanceof User) { - var destId = self.PMList.deepFilter(["user", "id"], destination.id, true); - - if (destId) { - channel_id = destId.id; - } else { - //start a PM and then get that use that - self.startPM(destination, function (err, channel) { - if (err) { - callback(err); - } else { - self.PMList.add(new PMChannel(channel.user, channel.id)); - setChannId(channel.id); - send(); - } - }); - return false; - } - } else { - channel_id = destination; - } - return channel_id; - } - - function resolveMessage(toSend) { - var message; - if (typeof toSend === "string" || toSend instanceof String) - message = toSend; - else if (toSend instanceof Array) - message = toSend.join("\n"); - else if (toSend instanceof Message) - message = toSend.content; - else - message = toSend; - return message.substring(0, 2000); - } - - function resolveMentions(message, mentionsOpt) { - var mentions = []; - if (mentionsOpt === false) { } else if (mentionsOpt || mentionsOpt === "auto" || mentionsOpt == null || mentionsOpt == undefined) { - for (mention of (message.match(/<@[^>]*>/g) || [])) { - mentions.push(mention.substring(2, mention.length - 1)); - } - } else if (mentionsOpt instanceof Array) { - for (mention of mentionsOpt) { - if (mention instanceof User) { - mentions.push(mention.id); - } else { - mentions.push(mention); - } - } - } - return mentions; - } -} - -/** - * Deletes the specified message if the bot has authority - * @param {Message} message The message to delete - * @param {Function} callback Called after the message deletion request is sent. - * @param {Object} callback.error If there was an error, this would be an XHR Error object. Otherwise, it will be null. - * @param {Message} callback.message A message object representing the deleted object. - * @method deleteMessage - */ -exports.Client.prototype.deleteMessage = function (message, callback) { - callback = callback || function () { }; - - var self = this; - - Internal.XHR.deleteMessage(self.token, message.channel.id, message.id, callback); -} - -exports.Client.prototype.updateMessage = function (oldMessage, newContent, callback, options) { - - var self = this; - var channel = oldMessage.channel; - options = options || {}; - - Internal.XHR.updateMessage(self.token, channel.id, oldMessage.id, { - content: newContent, - mentions: [] - }, function (err, data) { - if (err) { - callback(err); - return; - } - var msg = new Message(data, self.getChannel(data.channel_id)); - if (options.selfDestruct) { - setTimeout(function () { - self.deleteMessage(msg); - }, options.selfDestruct); - } - callback(null, msg); - }); - -} - -exports.Client.prototype.setUsername = function (username, callback) { - - var self = this; - - Internal.XHR.setUsername(self.token, self.user.avatar, self.email, null, self.password, username, function (err) { - - callback(err); - - }); - -} - -exports.Client.prototype.getChannelLogs = function (channel, amount, callback) { - var self = this; - - Internal.XHR.getChannelLogs(self.token, channel.id, (amount || 50), function (err, data) { - - if (err) { - callback(err); - return; - } - - var logs = new List("id"); - for (message of data) { - logs.add(new Message(message, channel)); - } - callback(null, logs); - - }); -} - -exports.Client.prototype.createChannel = function (server, name, type, callback) { - - var self = this; - - Internal.XHR.createChannel(self.token, server.id, name, type, function (err, data) { - - if (err) { - callback(err); - } else { - var chann = new Channel(data, server); - server.channels.add(chann); - callback(null, chann); - } - - }); -} - -exports.Client.prototype.deleteChannel = function (channel, callback) { - var self = this; - - Internal.XHR.deleteChannel(self.token, channel.id, function (err) { - - channel.server.channels.removeElement(channel); - self.triggerEvent("channelDelete", [channel]); - callback(null); - - }); -} - -exports.Client.prototype.deleteServer = function (server, callback) { - - var self = this; - - Internal.XHR.deleteServer(self.token, server.id, function (err) { - - self.serverList.removeElement(server); - self.triggerEvent("serverDelete", [server]); - callback(null); - - }); - -} - -exports.Client.prototype.joinServer = function (invite, callback) { - - var self = this; - - var code = (invite instanceof Invite ? invite.code : invite); - - Internal.XHR.acceptInvite(self.token, code, function (err, inviteData) { - - if (err) { - callback(err); - } else { - serverCreateRequests[inviteData.guild.id] = callback; - } - - }); - -} - -exports.Client.prototype.getServers = function () { - return this.serverList; -} - -exports.Client.prototype.getChannels = function () { - return this.serverList.concatSublists("channels", "id"); -} - -exports.Client.prototype.getUsers = function () { - return this.getServers().concatSublists("members", "id"); -} - -exports.Client.prototype.getServer = function (id) { - return this.getServers().filter("id", id, true); -} - -exports.Client.prototype.getChannel = function (id) { - var normalChan = this.getChannels().filter("id", id, true); - return normalChan || this.PMList.filter("id", id, true); -} - -exports.Client.prototype.getChannelByName = function (name) { - return this.getChannels().filter("name", name, true); -} - -exports.Client.prototype.getUser = function (id) { - return this.getUsers().filter("id", id, true); -} - -exports.isUserID = function (id) { - return ((id + "").length === 17 && !isNaN(id)); -} - -exports.Client.prototype.updateUserReferences = function (id, oldUser, user) { - - if (oldUser.equalsStrict(user)) { - return false; - } - - for (server of this.serverList.contents) { - - server.members.updateElement(oldUser, user); - - } - - this.debug("Updated references to " + oldUser.username + " to " + this.getUser(id).username); - return true; - -} - -exports.Client.prototype.addPM = function (pm) { - this.PMList.add(pm); -} diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 000000000..0438b79f6 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "target": "ES6", + "module": "commonjs" + } +} \ No newline at end of file diff --git a/lib/Client.js b/lib/Client.js new file mode 100644 index 000000000..c74b5e209 --- /dev/null +++ b/lib/Client.js @@ -0,0 +1,63 @@ +"use strict"; + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var request = require("superagent"); + +var defaultOptions = { + cache_tokens: false +}; + +var Client = (function () { + function Client() { + var options = arguments.length <= 0 || arguments[0] === undefined ? defaultOptions : arguments[0]; + var token = arguments.length <= 1 || arguments[1] === undefined ? undefined : arguments[1]; + + _classCallCheck(this, Client); + + /* + When created, if a token is specified the Client will + try connecting with it. If the token is incorrect, no + further efforts will be made to connect. + */ + this.options = options; + this.token = token; + this.state = 0; + this.websocket = null; + this.events = new Map(); + this.user = null; + /* + State values: + 0 - idle + 1 - logging in + 2 - logged in + 3 - ready + 4 - disconnected + */ + } + + _createClass(Client, [{ + key: "login", + + //def login + value: function login() { + var email = arguments.length <= 0 || arguments[0] === undefined ? "foo@bar.com" : arguments[0]; + var password = arguments.length <= 1 || arguments[1] === undefined ? "pass1234s" : arguments[1]; + + if (this.state === 0 || this.state === 4) { + + this.state = 1; + request.post(); + } + } + }, { + key: "ready", + get: function get() { + return this.state === 3; + } + }]); + + return Client; +})(); \ No newline at end of file diff --git a/lib/PMChannel.js b/lib/PMChannel.js index 1bfe3c155..31911a4d3 100644 --- a/lib/PMChannel.js +++ b/lib/PMChannel.js @@ -1,6 +1,8 @@ +"use strict"; + var User = require("./user.js").User; -exports.PMChannel = function(user, id){ +exports.PMChannel = function (user, id) { this.user = new User(user); this.id = id; -} +}; \ No newline at end of file diff --git a/lib/TokenManager.js b/lib/TokenManager.js index ceeed9ded..22732a462 100644 --- a/lib/TokenManager.js +++ b/lib/TokenManager.js @@ -1,68 +1,67 @@ -var fs = require( "fs" ); -var crypto = require( "crypto" ); -var md5 = require( "md5" ); +"use strict"; + +var fs = require("fs"); +var crypto = require("crypto"); +var md5 = require("md5"); var tokens = {}; -exports.TokenManager = function( folder, file ) { +exports.TokenManager = function (folder, file) { this.path = folder + file; var self = this; try { - var fd = fs.openSync( self.path, "wx" ); + var fd = fs.openSync(self.path, "wx"); self.writeTokens(); - } catch ( e ) { + } catch (e) { self.readTokens(); } +}; -} - -exports.TokenManager.prototype.addToken = function( id, token, pass ) { - tokens[ md5( id ) ] = encrypt( token, pass ); +exports.TokenManager.prototype.addToken = function (id, token, pass) { + tokens[md5(id)] = encrypt(token, pass); this.writeTokens(); -} +}; -exports.TokenManager.prototype.readTokens = function() { - tokens = JSON.parse( fs.readFileSync( this.path, "utf8" ) ); - for ( tkn in tokens ) { - tokens[ tkn ] = decrypt( tokens[ tkn ], tkn ); +exports.TokenManager.prototype.readTokens = function () { + tokens = JSON.parse(fs.readFileSync(this.path, "utf8")); + for (tkn in tokens) { + tokens[tkn] = decrypt(tokens[tkn], tkn); } -} +}; -exports.TokenManager.prototype.writeTokens = function() { +exports.TokenManager.prototype.writeTokens = function () { var tkn = {}; - for ( token in tokens ) { - tkn[ token ] = encrypt( tokens[ token ], token ); + for (token in tokens) { + tkn[token] = encrypt(tokens[token], token); } - fs.writeFile( this.path, JSON.stringify( tkn ), function( err ) { + fs.writeFile(this.path, JSON.stringify(tkn), function (err) {}); +}; - } ); -} +exports.TokenManager.prototype.exists = function (id) { + return tokens[md5(id)]; +}; -exports.TokenManager.prototype.exists = function( id ) { - return tokens[ md5( id ) ]; -} +exports.TokenManager.prototype.getToken = function (id, pass) { + try { + return decrypt(tokens[md5(id)], pass); + } catch (e) { + return false; + } +}; -exports.TokenManager.prototype.getToken = function( id, pass ) { - try{ - return decrypt( tokens[ md5( id ) ], pass ); - }catch(e){ - return false; - } -} - -function encrypt( string, password ) { - var cipher = crypto.createCipher( "aes-256-ctr", password ) - var crypted = cipher.update( string, 'utf8', 'hex' ) - crypted += cipher.final( 'hex' ); +function encrypt(string, password) { + var cipher = crypto.createCipher("aes-256-ctr", password); + var crypted = cipher.update(string, 'utf8', 'hex'); + crypted += cipher.final('hex'); return crypted; } -function decrypt( string, password ) { - var decipher = crypto.createDecipher( "aes-256-ctr", password ) - var dec = decipher.update( string, 'hex', 'utf8' ) - dec += decipher.final( 'utf8' ); +function decrypt(string, password) { + var decipher = crypto.createDecipher("aes-256-ctr", password); + var dec = decipher.update(string, 'hex', 'utf8'); + dec += decipher.final('utf8'); return dec; -} +} \ No newline at end of file diff --git a/lib/asd.js b/lib/asd.js new file mode 100644 index 000000000..c74b5e209 --- /dev/null +++ b/lib/asd.js @@ -0,0 +1,63 @@ +"use strict"; + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var request = require("superagent"); + +var defaultOptions = { + cache_tokens: false +}; + +var Client = (function () { + function Client() { + var options = arguments.length <= 0 || arguments[0] === undefined ? defaultOptions : arguments[0]; + var token = arguments.length <= 1 || arguments[1] === undefined ? undefined : arguments[1]; + + _classCallCheck(this, Client); + + /* + When created, if a token is specified the Client will + try connecting with it. If the token is incorrect, no + further efforts will be made to connect. + */ + this.options = options; + this.token = token; + this.state = 0; + this.websocket = null; + this.events = new Map(); + this.user = null; + /* + State values: + 0 - idle + 1 - logging in + 2 - logged in + 3 - ready + 4 - disconnected + */ + } + + _createClass(Client, [{ + key: "login", + + //def login + value: function login() { + var email = arguments.length <= 0 || arguments[0] === undefined ? "foo@bar.com" : arguments[0]; + var password = arguments.length <= 1 || arguments[1] === undefined ? "pass1234s" : arguments[1]; + + if (this.state === 0 || this.state === 4) { + + this.state = 1; + request.post(); + } + } + }, { + key: "ready", + get: function get() { + return this.state === 3; + } + }]); + + return Client; +})(); \ No newline at end of file diff --git a/lib/channel.js b/lib/channel.js index 16a8e4a51..a6c4f5280 100644 --- a/lib/channel.js +++ b/lib/channel.js @@ -1,8 +1,11 @@ +"use strict"; + var List = require("./list.js").List; -exports.Channel = function(name, server, type, id, isPrivate){ +exports.Channel = function (name, server, type, id, isPrivate) { - if(!type){ //there's no second argument + if (!type) { + //there's no second argument var channel = name; name = channel.name; server = server; @@ -17,12 +20,12 @@ exports.Channel = function(name, server, type, id, isPrivate){ this.id = id; this.isPrivate = isPrivate; this.messages = new List("id", 5000); -} +}; -exports.Channel.equals = function(otherChannel){ - if(otherChannel.id === this.id){ +exports.Channel.equals = function (otherChannel) { + if (otherChannel.id === this.id) { return true; } else { return false; } -} +}; \ No newline at end of file diff --git a/lib/endpoints.js b/lib/endpoints.js index 46ca08090..fe87bf57f 100644 --- a/lib/endpoints.js +++ b/lib/endpoints.js @@ -1,15 +1,13 @@ -var base = "https://discordapp.com/"; -var apibase = base + "api"; +"use strict"; -exports.API = apibase; +exports.BASE_DOMAIN = "discordapp.com"; +exports.BASE = "https://" + exports.BASE_DOMAIN; +exports.WEBSOCKET_HUB = "wss://" + exports.BASE_DOMAIN + "/hub"; -exports.WEBSOCKET_HUB = "wss://discordapp.com/hub" - -exports.USERS = apibase + "/users"; - -exports.LOGIN = apibase + "/auth/login"; -exports.LOGOUT = apibase + "/auth/logout"; - -exports.SERVERS = apibase + "/guilds"; - -exports.CHANNELS = apibase + "/channels"; +exports.API = exports.BASE + "/api"; +exports.AUTH = exports.API + "/auth"; +exports.LOGIN = exports.AUTH + "/login"; +exports.LOGIN = exports.AUTH + "/logout"; +exports.USERS = exports.API + "/users"; +exports.SERVERS = exports.API + "/guilds"; +exports.CHANNELS = exports.API + "/channels"; \ No newline at end of file diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 000000000..4c50da911 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,23 @@ +"use strict"; + +var request = require("superagent"); +var Endpoints = require("./lib/endpoints.js"); +var Server = require("./lib/server.js").Server; +var Message = require("./lib/message.js").Message; +var User = require("./lib/user.js").User; +var Channel = require("./lib/channel.js").Channel; +var List = require("./lib/list.js").List; +var Invite = require("./lib/invite.js").Invite; +var PMChannel = require("./lib/PMChannel.js").PMChannel; +var WebSocket = require('ws'); +var Internal = require("./lib/internal.js").Internal; +var TokenManager = require("./lib/TokenManager.js").TokenManager; + +exports.Endpoints = Endpoints; +exports.Server = Server; +exports.Message = Message; +exports.User = User; +exports.Channel = Channel; +exports.List = List; +exports.Invite = Invite; +exports.PMChannel = PMChannel; \ No newline at end of file diff --git a/lib/internal.js b/lib/internal.js index 42d0dc689..3acf5940b 100644 --- a/lib/internal.js +++ b/lib/internal.js @@ -1,5 +1,7 @@ -var request = require( "superagent" ); -var Endpoints = require( "./endpoints.js" ); +"use strict"; + +var request = require("superagent"); +var Endpoints = require("./endpoints.js"); var Internal = {}; @@ -14,264 +16,188 @@ Internal.WebSocket.properties = { "$referring_domain": "" }; -Internal.XHR.login = function( email, password, callback ) { +Internal.XHR.login = function (email, password, callback) { - request - .post( Endpoints.LOGIN ) - .send( { - email: email, - password: password - } ) - .end( function( err, res ) { - if ( err ) { - callback( err ); - } else { - callback( null, res.body.token ); - } - } ); + request.post(Endpoints.LOGIN).send({ + email: email, + password: password + }).end(function (err, res) { + if (err) { + callback(err); + } else { + callback(null, res.body.token); + } + }); +}; -} +Internal.XHR.logout = function (token, callback) { -Internal.XHR.logout = function( token, callback ) { + request.post(Endpoints.LOGOUT).end(function (err, res) { - request - .post( Endpoints.LOGOUT ) - .end( function( err, res ) { + err ? callback(err) : callback(null); + }); +}; - err ? callback( err ) : callback( null ); +Internal.XHR.createServer = function (token, name, region, callback) { - } ); + request.post(Endpoints.SERVERS).set("authorization", token).send({ + name: name, + region: region + }).end(function (err, res) { + if (err) { + callback(err); + } else { + callback(null, res.body); + } + }); +}; -} +Internal.XHR.leaveServer = function (token, serverId, callback) { -Internal.XHR.createServer = function( token, name, region, callback ) { + request.del(Endpoints.SERVERS + "/" + serverId).set("authorization", token).end(function (err, res) { - request - .post( Endpoints.SERVERS ) - .set( "authorization", token ) - .send( { - name: name, - region: region - } ) - .end( function( err, res ) { - if ( err ) { - callback( err ); - } else { - callback( null, res.body ); - } - } ); -} + err ? callback(err) : callback(null); + }); +}; -Internal.XHR.leaveServer = function( token, serverId, callback ) { +Internal.XHR.createInvite = function (token, channelId, options, callback) { + request.post(Endpoints.CHANNELS + "/" + channelId + "/invites").set("authorization", token).send(options).end(function (err, res) { + if (err) { + callback(err); + } else { + callback(null, res.body); + } + }); +}; - request - .del( Endpoints.SERVERS + "/" + serverId ) - .set( "authorization", token ) - .end( function( err, res ) { +Internal.XHR.startPM = function (token, selfID, userID, callback) { - err ? callback( err ) : callback( null ); + request.post(Endpoints.USERS + "/" + selfID + "/channels").set("authorization", token).send({ + recipient_id: userID + }).end(function (err, res) { + if (err) { + callback(err); + } else { + callback(null, res.body); + } + }); +}; - } ); +Internal.XHR.sendMessage = function (token, channelID, messageParameters, callback) { + request.post(Endpoints.CHANNELS + "/" + channelID + "/messages").set("authorization", token).send(messageParameters).end(function (err, res) { -} + if (err) { + callback(err); + } else { + callback(null, res.body); + } + }); +}; -Internal.XHR.createInvite = function( token, channelId, options, callback ) { - request - .post( Endpoints.CHANNELS + "/" + channelId + "/invites" ) - .set( "authorization", token ) - .send( options ) - .end( function( err, res ) { - if ( err ) { - callback( err ); - } else { - callback( null, res.body ); - } - } ) -} +Internal.XHR.sendFile = function (token, channelID, file, fileName, callback) { + request.post(Endpoints.CHANNELS + "/" + channelID + "/messages").set("authorization", token).attach("file", file, fileName).end(function (err, res) { -Internal.XHR.startPM = function( token, selfID, userID, callback ) { + if (err) { + callback(err); + } else { + callback(null, res.body); + } + }); +}; - request - .post( Endpoints.USERS + "/" + selfID + "/channels" ) - .set( "authorization", token ) - .send( { - recipient_id: userID - } ) - .end( function( err, res ) { - if ( err ) { - callback( err ); - } else { - callback( null, res.body ); - } - } ); +Internal.XHR.deleteMessage = function (token, channelID, messageID, callback) { + request.del(Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID).set("authorization", token).end(function (err) { + err ? callback(err) : callback(null); + }); +}; -} +Internal.XHR.updateMessage = function (token, channelID, messageID, messageParameters, callback) { -Internal.XHR.sendMessage = function( token, channelID, messageParameters, callback ) { - request - .post( Endpoints.CHANNELS + "/" + channelID + "/messages" ) - .set( "authorization", token ) - .send( messageParameters ) - .end( function( err, res ) { + request.patch(Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID).set("authorization", token).send(messageParameters).end(function (err, res) { + if (err) { + callback(err); + } else { + callback(null, res.body); + } + }); +}; - if ( err ) { - callback( err ); - } else { - callback( null, res.body ); - } +Internal.XHR.getChannelLogs = function (token, channelID, amount, callback) { + request.get(Endpoints.CHANNELS + "/" + channelID + "/messages?limit=" + amount).set("authorization", token).end(function (err, res) { - } ); + if (err) { + callback(err); + } else { + callback(null, res.body); + } + }); +}; -} +Internal.XHR.createChannel = function (token, serverID, name, type, callback) { + request.post(Endpoints.SERVERS + "/" + serverID + "/channels").set("authorization", token).send({ + name: name, + type: type + }).end(function (err, res) { + if (err) { + callback(err); + } else { + callback(null, res.body); + } + }); +}; -Internal.XHR.sendFile = function( token, channelID, file, fileName, callback ) { - request - .post( Endpoints.CHANNELS + "/" + channelID + "/messages" ) - .set( "authorization", token ) - .attach("file", file, fileName) - .end( function( err, res ) { +Internal.XHR.deleteChannel = function (token, channelID, callback) { - if ( err ) { - callback( err ); - } else { - callback( null, res.body ); - } + request.del(Endpoints.CHANNELS + "/" + channelID).set("authorization", token).end(function (err) { + err ? callback(err) : callback(null); + }); +}; +Internal.XHR.deleteServer = function (token, serverID, callback) { + request.del(Endpoints.SERVERS + "/" + serverID).set("authorization", token).end(function (err) { + err ? callback(err) : callback(null); + }); +}; - } ); -} +Internal.XHR.getChannels = function (token, serverID, callback) { + request.get(Endpoints.SERVERS + "/" + serverID + "/channels").set("authorization", token).end(function (err) { + err ? callback(err) : callback(null); + }); +}; -Internal.XHR.deleteMessage = function( token, channelID, messageID, callback ) { - request - .del( Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID ) - .set( "authorization", token ) - .end( function( err ) { - err ? callback( err ) : callback( null ); - } ); -} +Internal.XHR.getServer = function (token, serverID, callback) { -Internal.XHR.updateMessage = function( token, channelID, messageID, messageParameters, callback ) { + request.get(Endpoints.SERVERS + "/" + serverID).set("authorization", token).end(function (err, res) { - request - .patch( Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID ) - .set( "authorization", token ) - .send( messageParameters ) - .end( function( err, res ) { - if ( err ) { - callback( err ); - } else { - callback( null, res.body ); - } - } ); -} + if (err) { + callback(err); + } else { + callback(null, res.body); + } + }); +}; -Internal.XHR.getChannelLogs = function( token, channelID, amount, callback ) { - request - .get( Endpoints.CHANNELS + "/" + channelID + "/messages?limit=" + amount ) - .set( "authorization", token ) - .end( function( err, res ) { +Internal.XHR.acceptInvite = function (token, inviteID, callback) { - if ( err ) { - callback( err ); - } else { - callback( null, res.body ); - } + request.post(Endpoints.API + "/invite/" + inviteID).set("authorization", token).end(function (err, res) { + if (err) { + callback(err); + } else { + callback(null, res.body); + } + }); +}; - } ); -} +Internal.XHR.setUsername = function (token, avatar, email, newPassword, password, username, callback) { -Internal.XHR.createChannel = function( token, serverID, name, type, callback ) { - request - .post( Endpoints.SERVERS + "/" + serverID + "/channels" ) - .set( "authorization", token ) - .send( { - name: name, - type: type - } ) - .end( function( err, res ) { - if ( err ) { - callback( err ); - } else { - callback( null, res.body ); - } - } ); -} + request.patch(Endpoints.API + "/users/@me").set("authorization", token).send({ + avatar: avatar, + email: email, + new_password: newPassword, + password: password, + username: username + }).end(function (err) { + callback(err); + }); +}; -Internal.XHR.deleteChannel = function( token, channelID, callback ) { - - request - .del( Endpoints.CHANNELS + "/" + channelID ) - .set( "authorization", token ) - .end( function( err ) { - err ? callback( err ) : callback( null ); - } ); - -} -Internal.XHR.deleteServer = function( token, serverID, callback ) { - request - .del( Endpoints.SERVERS + "/" + serverID ) - .set( "authorization", token ) - .end( function( err ) { - err ? callback( err ) : callback( null ); - } ); -} - -Internal.XHR.getChannels = function( token, serverID, callback ) { - request - .get( Endpoints.SERVERS + "/" + serverID + "/channels" ) - .set( "authorization", token ) - .end( function( err ) { - err ? callback( err ) : callback( null ); - } ); -} - -Internal.XHR.getServer = function( token, serverID, callback ) { - - request - .get( Endpoints.SERVERS + "/" + serverID ) - .set( "authorization", token ) - .end( function( err, res ) { - - if ( err ) { - callback( err ); - } else { - callback( null, res.body ); - } - - } ); - -} - -Internal.XHR.acceptInvite = function( token, inviteID, callback ) { - - request - .post( Endpoints.API + "/invite/" + inviteID ) - .set( "authorization", token ) - .end( function( err, res ) { - if ( err ) { - callback( err ); - } else { - callback( null, res.body ) - } - } ); - -} - -Internal.XHR.setUsername = function( token, avatar, email, newPassword, password, username, callback ) { - - request - .patch( Endpoints.API + "/users/@me" ) - .set( "authorization", token ) - .send( { - avatar: avatar, - email: email, - new_password: newPassword, - password: password, - username: username - } ) - .end( function( err ) { - callback( err ); - } ); - -} - -exports.Internal = Internal; +exports.Internal = Internal; \ No newline at end of file diff --git a/lib/invite.js b/lib/invite.js index f2e10077a..359ac512b 100644 --- a/lib/invite.js +++ b/lib/invite.js @@ -1,6 +1,8 @@ +"use strict"; + var User = require("./user.js").User; -exports.Invite = function(json){ +exports.Invite = function (json) { this.max_age = json.max_age; this.code = json.code; @@ -13,9 +15,9 @@ exports.Invite = function(json){ this.inviter = new User(json.inviter); this.xkcdpass = json.xkcdpass; this.channel = json.channel; -} +}; -exports.Invite.prototype.generateInviteURL = function(xkcd){ - var code = (xkcd ? this.xkcdpass : this.code); - return "https://discord.gg/"+code; -} +exports.Invite.prototype.generateInviteURL = function (xkcd) { + var code = xkcd ? this.xkcdpass : this.code; + return "https://discord.gg/" + code; +}; \ No newline at end of file diff --git a/lib/list.js b/lib/list.js index 5ad268523..df07cad86 100644 --- a/lib/list.js +++ b/lib/list.js @@ -4,27 +4,29 @@ * when created. Generally "ID" * @class List */ -exports.List = function( discriminator, cap ) { +"use strict"; + +exports.List = function (discriminator, cap) { /** - * What to use to distringuish duplicates - * @attribute discriminator - * @type {String} - */ + * What to use to distringuish duplicates + * @attribute discriminator + * @type {String} + */ this.discriminator = discriminator; /** - * The maximum amount of elements allowed in the list. - * @default Infinity - * @attribute cap - * @type {Number} - */ + * The maximum amount of elements allowed in the list. + * @default Infinity + * @attribute cap + * @type {Number} + */ this.cap = cap || Number.MAX_SAFE_INTEGER; /** - * The Array version of the List. - * @type {Array} - * @attribute contents - */ + * The Array version of the List. + * @type {Array} + * @attribute contents + */ this.contents = []; -} +}; /** * Adds an element to the list if it isn't already there. @@ -34,40 +36,59 @@ exports.List = function( discriminator, cap ) { * List.add( obj ); * List.add( [ obj, obj, obj ] ); */ -exports.List.prototype.add = function( child ) { +exports.List.prototype.add = function (child) { var self = this; - if ( child.constructor === Array ) { + if (child.constructor === Array) { children = child; - for ( child of children ) { - addChild( child ); - } + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + try { + for (var _iterator = children[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + child = _step.value; + + addChild(child); + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator["return"]) { + _iterator["return"](); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } } else { - addChild( child ); + addChild(child); } - function addChild( child ) { + function addChild(child) { - if ( self.length() > self.cap ) { - self.splice( 0, 1 ); + if (self.length() > self.cap) { + self.splice(0, 1); } - if ( self.filter( self.discriminator, child[ self.discriminator ] ).length() === 0 ) - self.contents.push( child ); + if (self.filter(self.discriminator, child[self.discriminator]).length() === 0) self.contents.push(child); } -} +}; /** * Returns the length of the List * @method length * @return {Number} */ -exports.List.prototype.length = function() { +exports.List.prototype.length = function () { return this.contents.length; -} +}; /** * Gets the index of an element in the List or defaults to false @@ -75,30 +96,28 @@ exports.List.prototype.length = function() { * @return {Number/Boolean} The index if the object is in the list, or false. * @method getIndex */ -exports.List.prototype.getIndex = function( object ) { +exports.List.prototype.getIndex = function (object) { var index = false; - for ( elementIndex in this.contents ) { - var element = this.contents[ elementIndex ]; - if ( element[ this.discriminator ] == object[ this.discriminator ] ) { + for (elementIndex in this.contents) { + var element = this.contents[elementIndex]; + if (element[this.discriminator] == object[this.discriminator]) { return elementIndex; } - } return index; - -} +}; /** * Removes an element at the specified index * @param {Number} index * @method removeIndex */ -exports.List.prototype.removeIndex = function( index ) { - this.contents.splice( index, 1 ); -} +exports.List.prototype.removeIndex = function (index) { + this.contents.splice(index, 1); +}; /** * Removes an element from the list @@ -106,18 +125,18 @@ exports.List.prototype.removeIndex = function( index ) { * @method removeElement * @return {Boolean} whether the operation was successful or not. */ -exports.List.prototype.removeElement = function( child ) { +exports.List.prototype.removeElement = function (child) { - for ( _element in this.contents ) { - var element = this.contents[ _element ]; - if ( child[ this.discriminator ] == element[ this.discriminator ] ) { - this.removeIndex( _element, 1 ); + for (_element in this.contents) { + var element = this.contents[_element]; + if (child[this.discriminator] == element[this.discriminator]) { + this.removeIndex(_element, 1); return true; } } return false; -} +}; /** * Replaces an element in the list with a specified element @@ -126,123 +145,206 @@ exports.List.prototype.removeElement = function( child ) { * @param {Object} newElement New Element * @return {Boolean} whether the operation was successful or not. */ -exports.List.prototype.updateElement = function( child, newChild ) { +exports.List.prototype.updateElement = function (child, newChild) { - for ( _element in this.contents ) { - var element = this.contents[ _element ]; - if ( child[ this.discriminator ] == element[ this.discriminator ] ) { - this.contents[ _element ] = newChild; + for (_element in this.contents) { + var element = this.contents[_element]; + if (child[this.discriminator] == element[this.discriminator]) { + this.contents[_element] = newChild; return true; } } return false; +}; -} - -exports.List.prototype.concatSublists = function( whereList, discriminator ) { +exports.List.prototype.concatSublists = function (whereList, discriminator) { //this is meant to look at the contents, and assuming the contents are all lists, concatenate their values. - var concatList = new exports.List( discriminator ); + var concatList = new exports.List(discriminator); - for ( item of this.contents ) { - var itemList = item[ whereList ]; - concatList.add( itemList.contents ); + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = this.contents[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + item = _step2.value; + + var itemList = item[whereList]; + concatList.add(itemList.contents); + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2["return"]) { + _iterator2["return"](); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } } return concatList; -} +}; -exports.List.prototype.filter = function( key, value, onlyOne, caseInsen ) { +exports.List.prototype.filter = function (key, value, onlyOne, caseInsen) { var results = []; - value = change( value ); + value = change(value); - for ( index in this.contents ) { - var child = this.contents[ index ]; - if ( change( child[ key ] ) == value ) { - if ( onlyOne ) { + for (index in this.contents) { + var child = this.contents[index]; + if (change(child[key]) == value) { + if (onlyOne) { return child; } else { - results.push( child ); + results.push(child); } } } - function change( val ) { - if ( caseInsen ) { + function change(val) { + if (caseInsen) { val = val.toUpperCase(); } return val; } - if ( onlyOne ) { + if (onlyOne) { return false; } - var retList = new exports.List( this.discriminator ); + var retList = new exports.List(this.discriminator); retList.contents = results; return retList; -} +}; -exports.List.prototype.getValues = function( key ){ +exports.List.prototype.getValues = function (key) { var valList = []; - for( child of this.contents){ - valList.push( child[key] ); + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = this.contents[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + child = _step3.value; + + valList.push(child[key]); + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3["return"]) { + _iterator3["return"](); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } } + return valList; +}; -} - -exports.List.prototype.deepFilter = function( keys, value, onlyOne, caseInsen ) { +exports.List.prototype.deepFilter = function (keys, value, onlyOne, caseInsen) { var results = []; - value = change( value ); + value = change(value); - for ( index in this.contents ) { - var child = this.contents[ index ]; + for (index in this.contents) { + var child = this.contents[index]; var buffer = child; - for ( key of keys ) { - if(buffer instanceof exports.List){ - buffer = buffer.contents; - } - if(buffer instanceof Array){ - for(elem of buffer){ - if( change(elem[key]) == value ){ - buffer = elem; + var _iteratorNormalCompletion4 = true; + var _didIteratorError4 = false; + var _iteratorError4 = undefined; + + try { + for (var _iterator4 = keys[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { + key = _step4.value; + + if (buffer instanceof exports.List) { + buffer = buffer.contents; + } + if (buffer instanceof Array) { + var _iteratorNormalCompletion5 = true; + var _didIteratorError5 = false; + var _iteratorError5 = undefined; + + try { + for (var _iterator5 = buffer[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { + elem = _step5.value; + + if (change(elem[key]) == value) { + buffer = elem; + } + } + } catch (err) { + _didIteratorError5 = true; + _iteratorError5 = err; + } finally { + try { + if (!_iteratorNormalCompletion5 && _iterator5["return"]) { + _iterator5["return"](); + } + } finally { + if (_didIteratorError5) { + throw _iteratorError5; + } + } } } + buffer = buffer[key]; + } + } catch (err) { + _didIteratorError4 = true; + _iteratorError4 = err; + } finally { + try { + if (!_iteratorNormalCompletion4 && _iterator4["return"]) { + _iterator4["return"](); + } + } finally { + if (_didIteratorError4) { + throw _iteratorError4; + } } - buffer = buffer[ key ]; } - if ( change( buffer ) == value ) { - if ( onlyOne ) { + if (change(buffer) == value) { + if (onlyOne) { return child; } else { - results.push( child ); + results.push(child); } } } - function change( val ) { - if ( caseInsen ) { + function change(val) { + if (caseInsen) { val = val.toUpperCase(); } return val; } - if ( onlyOne ) { + if (onlyOne) { return false; } - var retList = new exports.List( this.discriminator ); + var retList = new exports.List(this.discriminator); retList.contents = results; return retList; -} +}; \ No newline at end of file diff --git a/lib/message.js b/lib/message.js index 121bbf5dd..af9ce1f4b 100644 --- a/lib/message.js +++ b/lib/message.js @@ -1,10 +1,12 @@ -var User = require( "./user.js" ).User; -var List = require( "./list.js" ).List; -var PMChannel = require( "./PMChannel.js" ).PMChannel; +"use strict"; -exports.Message = function( time, author, content, channel, id, mentions, everyoneMentioned, embeds ) { +var User = require("./user.js").User; +var List = require("./list.js").List; +var PMChannel = require("./PMChannel.js").PMChannel; - if ( !content ) { +exports.Message = function (time, author, content, channel, id, mentions, everyoneMentioned, embeds) { + + if (!content) { message = time; channel = author; time = message.timestamp; @@ -16,24 +18,24 @@ exports.Message = function( time, author, content, channel, id, mentions, everyo embeds = message.embeds; } - this.time = Date.parse( time ); - this.author = new User( author ); - this.content = content.replace( /\s+/g, ' ' ).trim(); //content.replace(/<[^>]*>/g, "").replace(/\s+/g, ' ').trim(); + this.time = Date.parse(time); + this.author = new User(author); + this.content = content.replace(/\s+/g, ' ').trim(); //content.replace(/<[^>]*>/g, "").replace(/\s+/g, ' ').trim(); this.channel = channel; this.id = id; - this.mentions = new List( "id" ); + this.mentions = new List("id"); this.everyoneMentioned = everyoneMentioned; this.embeds = embeds; - for ( x in mentions ) { - var _mention = mentions[ x ]; - this.mentions.add( new User( _mention ) ); + for (x in mentions) { + var _mention = mentions[x]; + this.mentions.add(new User(_mention)); } -} +}; -exports.Message.prototype.isPM = function() { - return ( this.channel instanceof PMChannel ); -} +exports.Message.prototype.isPM = function () { + return this.channel instanceof PMChannel; +}; -exports.Message.prototype.isMentioned = function( user ) { - return ( this.mentions.filter( "id", user.id ).length > 0 ); -} +exports.Message.prototype.isMentioned = function (user) { + return this.mentions.filter("id", user.id).length > 0; +}; \ No newline at end of file diff --git a/lib/server.js b/lib/server.js index a5cfaab6a..57ca54c21 100644 --- a/lib/server.js +++ b/lib/server.js @@ -1,106 +1,104 @@ -var User = require( "./user.js" ).User; -var List = require( "./list.js" ).List; +"use strict"; + +var User = require("./user.js").User; +var List = require("./list.js").List; /** * A wrapper for Server information, contains channels and users too. Developers should not instantiate the class, instead they should * manipulate Server objects given to them. * @class Server * @param {String} region The region of the server */ -exports.Server = function( region, ownerID, name, id, members, icon, afkTimeout, afkChannelId ) { +exports.Server = function (region, ownerID, name, id, members, icon, afkTimeout, afkChannelId) { /** - * The region of the Server - * @type {String} - * @attribute region - */ + * The region of the Server + * @type {String} + * @attribute region + */ this.region = region; /** - * The ID of the owner of the Server (not a User!) - * @type {String} - * @attribute ownerID - */ + * The ID of the owner of the Server (not a User!) + * @type {String} + * @attribute ownerID + */ this.ownerID = ownerID; /** - * The name of the Server - * @type {String} - * @attribute name - */ + * The name of the Server + * @type {String} + * @attribute name + */ this.name = name; /** - * The ID of the Server - * @type {String} - * @attribute id - */ + * The ID of the Server + * @type {String} + * @attribute id + */ this.id = id; /** - * List containing members of the Server - * @param {List} - * @attribute members - */ - this.members = new List( "id" ); + * List containing members of the Server + * @param {List} + * @attribute members + */ + this.members = new List("id"); /** - * List containing channelss of the Server - * @param {List} - * @attribute channels - */ - this.channels = new List( "id" ); + * List containing channelss of the Server + * @param {List} + * @attribute channels + */ + this.channels = new List("id"); /** - * ID of the Icon of the Server - * @param {String} - * @attribute icon - */ + * ID of the Icon of the Server + * @param {String} + * @attribute icon + */ this.icon = icon; /** - * The amount of seconds that should pass before the user is - * @type {Number} - * @attribute afkTimeout - */ + * The amount of seconds that should pass before the user is + * @type {Number} + * @attribute afkTimeout + */ this.afkTimeout = afkTimeout; /** - * The ID of the AFK Channel, evaluates to false if doesn't exist. - * @type {String} - * @attribute afkChannelId - */ + * The ID of the AFK Channel, evaluates to false if doesn't exist. + * @type {String} + * @attribute afkChannelId + */ this.afkChannelId = afkChannelId; - for ( x in members ) { - var member = members[ x ].user; - this.members.add( new User( member ) ); + for (x in members) { + var member = members[x].user; + this.members.add(new User(member)); } -} +}; /** * Returns a valid URL pointing towards the server's icon if it has one. * @method getIconURL * @return {String/Boolean} If there is an icon, a URL is returned. If not, false is returned. */ -exports.Server.prototype.getIconURL = function(){ - if(!this.icon) - return false; - return "https://discordapp.com/api/guilds/"+this.id+"/icons/"+this.icon+".jpg"; -} +exports.Server.prototype.getIconURL = function () { + if (!this.icon) return false; + return "https://discordapp.com/api/guilds/" + this.id + "/icons/" + this.icon + ".jpg"; +}; /** * Returns the AFK Channel if a server has one * @method getAFKChannel * @return {Channel/Boolean} If there is an AFK Channel, a Channel is returned. If not, false is returned. */ -exports.Server.prototype.getAFKChannel = function(){ +exports.Server.prototype.getAFKChannel = function () { - if(!this.afkChannelId) - return false; + if (!this.afkChannelId) return false; return this.channels.filter("id", this.afkChannelId, true); - -} +}; /** * Returns the #general channel of the server. * @method getDefaultChannel * @return {Channel} Returns the #general channel of the Server. */ -exports.Server.prototype.getDefaultChannel = function() { +exports.Server.prototype.getDefaultChannel = function () { - return this.channels.filter( "name", "general", true ); - -} + return this.channels.filter("name", "general", true); +}; \ No newline at end of file diff --git a/lib/user.js b/lib/user.js index 2bf3cc51b..44bb6ce7d 100644 --- a/lib/user.js +++ b/lib/user.js @@ -1,6 +1,9 @@ -exports.User = function( username, id, discriminator, avatar ) { +"use strict"; - if ( !id ) { //there's no second argument +exports.User = function (username, id, discriminator, avatar) { + + if (!id) { + //there's no second argument var user = username; username = user.username; id = user.id; @@ -12,26 +15,23 @@ exports.User = function( username, id, discriminator, avatar ) { this.discriminator = discriminator; this.id = id; this.avatar = avatar; -} +}; -exports.User.prototype.getAvatarURL = function() { - if ( !this.avatar ) - return false; +exports.User.prototype.getAvatarURL = function () { + if (!this.avatar) return false; return "https://discordapp.com/api/users/" + this.id + "/avatars/" + this.avatar + ".jpg"; -} +}; -exports.User.prototype.mention = function() { +exports.User.prototype.mention = function () { return "<@" + this.id + ">"; -} +}; -exports.User.prototype.equals = function( otherUser ) { +exports.User.prototype.equals = function (otherUser) { return otherUser.id === this.id; +}; -} +exports.User.prototype.equalsStrict = function (otherUser) { -exports.User.prototype.equalsStrict = function( otherUser ) { - - return ( this.username === otherUser.username && this.discriminator === otherUser.discriminator && this.id === otherUser.id && this.avatar === otherUser.avatar ); - -} + return this.username === otherUser.username && this.discriminator === otherUser.discriminator && this.id === otherUser.id && this.avatar === otherUser.avatar; +}; \ No newline at end of file diff --git a/src/Client.js b/src/Client.js new file mode 100644 index 000000000..5aa87b72d --- /dev/null +++ b/src/Client.js @@ -0,0 +1,69 @@ +//discord.js modules +var Endpoints = require("./Endpoints.js"); + +//node modules +var request = require("superagent"); + +var defaultOptions = { + cache_tokens: false +} + +class Client { + + constructor(options = defaultOptions, token = undefined) { + /* + When created, if a token is specified the Client will + try connecting with it. If the token is incorrect, no + further efforts will be made to connect. + */ + this.options = options; + this.token = token; + this.state = 0; + this.websocket = null; + this.events = new Map(); + this.user = null; + /* + State values: + 0 - idle + 1 - logging in + 2 - logged in + 3 - ready + 4 - disconnected + */ + } + + get ready() { + return this.state === 3; + } + + //def login + login(email = "foo@bar.com", password = "pass1234s", callback = function(){}) { + + var self = this; + + if (this.state === 0 || this.state === 4) { + + this.state = 1; //set the state to logging in + + request + .post(Endpoints.LOGIN) + .send({ + email : email, + password : password + }).end(function(err, res){ + + if(err){ + self.state = 4; //set state to disconnected + callback(err); + }else{ + self.state = 2; //set state to logged in (not yet ready) + self.token = res.body.token; + } + + }); + + } + + } + +} \ No newline at end of file diff --git a/src/Endpoints.js b/src/Endpoints.js new file mode 100644 index 000000000..00d8667ae --- /dev/null +++ b/src/Endpoints.js @@ -0,0 +1,11 @@ +exports.BASE_DOMAIN = "discordapp.com"; +exports.BASE = `https://${exports.BASE_DOMAIN}`; +exports.WEBSOCKET_HUB = `wss://${exports.BASE_DOMAIN}/hub`; + +exports.API = `${exports.BASE}/api`; +exports.AUTH = `${exports.API}/auth`; +exports.LOGIN = `${exports.AUTH}/login`; +exports.LOGIN = `${exports.AUTH}/logout`; +exports.USERS = `${exports.API}/users`; +exports.SERVERS = `${exports.API}/guilds`; +exports.CHANNELS = `${exports.API}/channels`; \ No newline at end of file diff --git a/src/PMChannel.js b/src/PMChannel.js new file mode 100644 index 000000000..1bfe3c155 --- /dev/null +++ b/src/PMChannel.js @@ -0,0 +1,6 @@ +var User = require("./user.js").User; + +exports.PMChannel = function(user, id){ + this.user = new User(user); + this.id = id; +} diff --git a/src/TokenManager.js b/src/TokenManager.js new file mode 100644 index 000000000..ceeed9ded --- /dev/null +++ b/src/TokenManager.js @@ -0,0 +1,68 @@ +var fs = require( "fs" ); +var crypto = require( "crypto" ); +var md5 = require( "md5" ); + +var tokens = {}; + +exports.TokenManager = function( folder, file ) { + + this.path = folder + file; + + var self = this; + + try { + var fd = fs.openSync( self.path, "wx" ); + self.writeTokens(); + } catch ( e ) { + self.readTokens(); + } + +} + +exports.TokenManager.prototype.addToken = function( id, token, pass ) { + tokens[ md5( id ) ] = encrypt( token, pass ); + this.writeTokens(); +} + +exports.TokenManager.prototype.readTokens = function() { + tokens = JSON.parse( fs.readFileSync( this.path, "utf8" ) ); + for ( tkn in tokens ) { + tokens[ tkn ] = decrypt( tokens[ tkn ], tkn ); + } +} + +exports.TokenManager.prototype.writeTokens = function() { + var tkn = {}; + for ( token in tokens ) { + tkn[ token ] = encrypt( tokens[ token ], token ); + } + fs.writeFile( this.path, JSON.stringify( tkn ), function( err ) { + + } ); +} + +exports.TokenManager.prototype.exists = function( id ) { + return tokens[ md5( id ) ]; +} + +exports.TokenManager.prototype.getToken = function( id, pass ) { + try{ + return decrypt( tokens[ md5( id ) ], pass ); + }catch(e){ + return false; + } +} + +function encrypt( string, password ) { + var cipher = crypto.createCipher( "aes-256-ctr", password ) + var crypted = cipher.update( string, 'utf8', 'hex' ) + crypted += cipher.final( 'hex' ); + return crypted; +} + +function decrypt( string, password ) { + var decipher = crypto.createDecipher( "aes-256-ctr", password ) + var dec = decipher.update( string, 'hex', 'utf8' ) + dec += decipher.final( 'utf8' ); + return dec; +} diff --git a/src/channel.js b/src/channel.js new file mode 100644 index 000000000..16a8e4a51 --- /dev/null +++ b/src/channel.js @@ -0,0 +1,28 @@ +var List = require("./list.js").List; + +exports.Channel = function(name, server, type, id, isPrivate){ + + if(!type){ //there's no second argument + var channel = name; + name = channel.name; + server = server; + type = channel.type; + id = channel.id; + isPrivate = channel.is_private; + } + + this.name = name; + this.server = server; + this.type = type; + this.id = id; + this.isPrivate = isPrivate; + this.messages = new List("id", 5000); +} + +exports.Channel.equals = function(otherChannel){ + if(otherChannel.id === this.id){ + return true; + } else { + return false; + } +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 000000000..ba14989f3 --- /dev/null +++ b/src/index.js @@ -0,0 +1,21 @@ +var request = require("superagent"); +var Endpoints = require("./lib/endpoints.js"); +var Server = require("./lib/server.js").Server; +var Message = require("./lib/message.js").Message; +var User = require("./lib/user.js").User; +var Channel = require("./lib/channel.js").Channel; +var List = require("./lib/list.js").List; +var Invite = require("./lib/invite.js").Invite; +var PMChannel = require("./lib/PMChannel.js").PMChannel; +var WebSocket = require('ws'); +var Internal = require("./lib/internal.js").Internal; +var TokenManager = require("./lib/TokenManager.js").TokenManager; + +exports.Endpoints = Endpoints; +exports.Server = Server; +exports.Message = Message; +exports.User = User; +exports.Channel = Channel; +exports.List = List; +exports.Invite = Invite; +exports.PMChannel = PMChannel; \ No newline at end of file diff --git a/src/internal.js b/src/internal.js new file mode 100644 index 000000000..42d0dc689 --- /dev/null +++ b/src/internal.js @@ -0,0 +1,277 @@ +var request = require( "superagent" ); +var Endpoints = require( "./endpoints.js" ); + +var Internal = {}; + +Internal.XHR = {}; +Internal.WebSocket = {}; + +Internal.WebSocket.properties = { + "$os": "discord.js", + "$browser": "discord.js", + "$device": "discord.js", + "$referrer": "", + "$referring_domain": "" +}; + +Internal.XHR.login = function( email, password, callback ) { + + request + .post( Endpoints.LOGIN ) + .send( { + email: email, + password: password + } ) + .end( function( err, res ) { + if ( err ) { + callback( err ); + } else { + callback( null, res.body.token ); + } + } ); + +} + +Internal.XHR.logout = function( token, callback ) { + + request + .post( Endpoints.LOGOUT ) + .end( function( err, res ) { + + err ? callback( err ) : callback( null ); + + } ); + +} + +Internal.XHR.createServer = function( token, name, region, callback ) { + + request + .post( Endpoints.SERVERS ) + .set( "authorization", token ) + .send( { + name: name, + region: region + } ) + .end( function( err, res ) { + if ( err ) { + callback( err ); + } else { + callback( null, res.body ); + } + } ); +} + +Internal.XHR.leaveServer = function( token, serverId, callback ) { + + request + .del( Endpoints.SERVERS + "/" + serverId ) + .set( "authorization", token ) + .end( function( err, res ) { + + err ? callback( err ) : callback( null ); + + } ); + +} + +Internal.XHR.createInvite = function( token, channelId, options, callback ) { + request + .post( Endpoints.CHANNELS + "/" + channelId + "/invites" ) + .set( "authorization", token ) + .send( options ) + .end( function( err, res ) { + if ( err ) { + callback( err ); + } else { + callback( null, res.body ); + } + } ) +} + +Internal.XHR.startPM = function( token, selfID, userID, callback ) { + + request + .post( Endpoints.USERS + "/" + selfID + "/channels" ) + .set( "authorization", token ) + .send( { + recipient_id: userID + } ) + .end( function( err, res ) { + if ( err ) { + callback( err ); + } else { + callback( null, res.body ); + } + } ); + +} + +Internal.XHR.sendMessage = function( token, channelID, messageParameters, callback ) { + request + .post( Endpoints.CHANNELS + "/" + channelID + "/messages" ) + .set( "authorization", token ) + .send( messageParameters ) + .end( function( err, res ) { + + if ( err ) { + callback( err ); + } else { + callback( null, res.body ); + } + + } ); + +} + +Internal.XHR.sendFile = function( token, channelID, file, fileName, callback ) { + request + .post( Endpoints.CHANNELS + "/" + channelID + "/messages" ) + .set( "authorization", token ) + .attach("file", file, fileName) + .end( function( err, res ) { + + if ( err ) { + callback( err ); + } else { + callback( null, res.body ); + } + + } ); +} + +Internal.XHR.deleteMessage = function( token, channelID, messageID, callback ) { + request + .del( Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID ) + .set( "authorization", token ) + .end( function( err ) { + err ? callback( err ) : callback( null ); + } ); +} + +Internal.XHR.updateMessage = function( token, channelID, messageID, messageParameters, callback ) { + + request + .patch( Endpoints.CHANNELS + "/" + channelID + "/messages/" + messageID ) + .set( "authorization", token ) + .send( messageParameters ) + .end( function( err, res ) { + if ( err ) { + callback( err ); + } else { + callback( null, res.body ); + } + } ); +} + +Internal.XHR.getChannelLogs = function( token, channelID, amount, callback ) { + request + .get( Endpoints.CHANNELS + "/" + channelID + "/messages?limit=" + amount ) + .set( "authorization", token ) + .end( function( err, res ) { + + if ( err ) { + callback( err ); + } else { + callback( null, res.body ); + } + + } ); +} + +Internal.XHR.createChannel = function( token, serverID, name, type, callback ) { + request + .post( Endpoints.SERVERS + "/" + serverID + "/channels" ) + .set( "authorization", token ) + .send( { + name: name, + type: type + } ) + .end( function( err, res ) { + if ( err ) { + callback( err ); + } else { + callback( null, res.body ); + } + } ); +} + +Internal.XHR.deleteChannel = function( token, channelID, callback ) { + + request + .del( Endpoints.CHANNELS + "/" + channelID ) + .set( "authorization", token ) + .end( function( err ) { + err ? callback( err ) : callback( null ); + } ); + +} +Internal.XHR.deleteServer = function( token, serverID, callback ) { + request + .del( Endpoints.SERVERS + "/" + serverID ) + .set( "authorization", token ) + .end( function( err ) { + err ? callback( err ) : callback( null ); + } ); +} + +Internal.XHR.getChannels = function( token, serverID, callback ) { + request + .get( Endpoints.SERVERS + "/" + serverID + "/channels" ) + .set( "authorization", token ) + .end( function( err ) { + err ? callback( err ) : callback( null ); + } ); +} + +Internal.XHR.getServer = function( token, serverID, callback ) { + + request + .get( Endpoints.SERVERS + "/" + serverID ) + .set( "authorization", token ) + .end( function( err, res ) { + + if ( err ) { + callback( err ); + } else { + callback( null, res.body ); + } + + } ); + +} + +Internal.XHR.acceptInvite = function( token, inviteID, callback ) { + + request + .post( Endpoints.API + "/invite/" + inviteID ) + .set( "authorization", token ) + .end( function( err, res ) { + if ( err ) { + callback( err ); + } else { + callback( null, res.body ) + } + } ); + +} + +Internal.XHR.setUsername = function( token, avatar, email, newPassword, password, username, callback ) { + + request + .patch( Endpoints.API + "/users/@me" ) + .set( "authorization", token ) + .send( { + avatar: avatar, + email: email, + new_password: newPassword, + password: password, + username: username + } ) + .end( function( err ) { + callback( err ); + } ); + +} + +exports.Internal = Internal; diff --git a/src/invite.js b/src/invite.js new file mode 100644 index 000000000..f2e10077a --- /dev/null +++ b/src/invite.js @@ -0,0 +1,21 @@ +var User = require("./user.js").User; + +exports.Invite = function(json){ + + this.max_age = json.max_age; + this.code = json.code; + this.server = json.guild; + this.revoked = json.revoked; + this.created_at = Date.parse(json.created_at); + this.temporary = json.temporary; + this.uses = json.uses; + this.max_uses = json.uses; + this.inviter = new User(json.inviter); + this.xkcdpass = json.xkcdpass; + this.channel = json.channel; +} + +exports.Invite.prototype.generateInviteURL = function(xkcd){ + var code = (xkcd ? this.xkcdpass : this.code); + return "https://discord.gg/"+code; +} diff --git a/src/list.js b/src/list.js new file mode 100644 index 000000000..5ad268523 --- /dev/null +++ b/src/list.js @@ -0,0 +1,248 @@ +/** + * Similar to a Java set. Contains no duplicate elements and includes filter + * functions. Discriminates between elements based on a discriminator passed + * when created. Generally "ID" + * @class List + */ +exports.List = function( discriminator, cap ) { + /** + * What to use to distringuish duplicates + * @attribute discriminator + * @type {String} + */ + this.discriminator = discriminator; + /** + * The maximum amount of elements allowed in the list. + * @default Infinity + * @attribute cap + * @type {Number} + */ + this.cap = cap || Number.MAX_SAFE_INTEGER; + /** + * The Array version of the List. + * @type {Array} + * @attribute contents + */ + this.contents = []; +} + +/** + * Adds an element to the list if it isn't already there. + * @method add + * @param {Object/Array} element The element(s) to add + * @example + * List.add( obj ); + * List.add( [ obj, obj, obj ] ); + */ +exports.List.prototype.add = function( child ) { + + var self = this; + + if ( child.constructor === Array ) { + + children = child; + for ( child of children ) { + addChild( child ); + } + + } else { + addChild( child ); + } + + function addChild( child ) { + + if ( self.length() > self.cap ) { + self.splice( 0, 1 ); + } + + if ( self.filter( self.discriminator, child[ self.discriminator ] ).length() === 0 ) + self.contents.push( child ); + } +} + +/** + * Returns the length of the List + * @method length + * @return {Number} + */ +exports.List.prototype.length = function() { + return this.contents.length; +} + +/** + * Gets the index of an element in the List or defaults to false + * @param {Object} object The element we want to get the index of + * @return {Number/Boolean} The index if the object is in the list, or false. + * @method getIndex + */ +exports.List.prototype.getIndex = function( object ) { + + var index = false; + + for ( elementIndex in this.contents ) { + var element = this.contents[ elementIndex ]; + if ( element[ this.discriminator ] == object[ this.discriminator ] ) { + return elementIndex; + } + + } + + return index; + +} + +/** + * Removes an element at the specified index + * @param {Number} index + * @method removeIndex + */ +exports.List.prototype.removeIndex = function( index ) { + this.contents.splice( index, 1 ); +} + +/** + * Removes an element from the list + * @param {Object} element + * @method removeElement + * @return {Boolean} whether the operation was successful or not. + */ +exports.List.prototype.removeElement = function( child ) { + + for ( _element in this.contents ) { + var element = this.contents[ _element ]; + if ( child[ this.discriminator ] == element[ this.discriminator ] ) { + this.removeIndex( _element, 1 ); + return true; + } + } + + return false; +} + +/** + * Replaces an element in the list with a specified element + * @method updateElement + * @param {Object} element Element to update. + * @param {Object} newElement New Element + * @return {Boolean} whether the operation was successful or not. + */ +exports.List.prototype.updateElement = function( child, newChild ) { + + for ( _element in this.contents ) { + var element = this.contents[ _element ]; + if ( child[ this.discriminator ] == element[ this.discriminator ] ) { + this.contents[ _element ] = newChild; + return true; + } + } + + return false; + +} + +exports.List.prototype.concatSublists = function( whereList, discriminator ) { + //this is meant to look at the contents, and assuming the contents are all lists, concatenate their values. + + var concatList = new exports.List( discriminator ); + + for ( item of this.contents ) { + var itemList = item[ whereList ]; + concatList.add( itemList.contents ); + } + + return concatList; +} + +exports.List.prototype.filter = function( key, value, onlyOne, caseInsen ) { + + var results = []; + + value = change( value ); + + for ( index in this.contents ) { + var child = this.contents[ index ]; + if ( change( child[ key ] ) == value ) { + if ( onlyOne ) { + return child; + } else { + results.push( child ); + } + } + } + + function change( val ) { + if ( caseInsen ) { + val = val.toUpperCase(); + } + return val; + } + + if ( onlyOne ) { + return false; + } + + var retList = new exports.List( this.discriminator ); + retList.contents = results; + + return retList; +} + +exports.List.prototype.getValues = function( key ){ + + var valList = []; + for( child of this.contents){ + valList.push( child[key] ); + } + return valList; + +} + +exports.List.prototype.deepFilter = function( keys, value, onlyOne, caseInsen ) { + + var results = []; + + value = change( value ); + + for ( index in this.contents ) { + var child = this.contents[ index ]; + var buffer = child; + + for ( key of keys ) { + if(buffer instanceof exports.List){ + buffer = buffer.contents; + } + if(buffer instanceof Array){ + for(elem of buffer){ + if( change(elem[key]) == value ){ + buffer = elem; + } + } + } + buffer = buffer[ key ]; + } + + if ( change( buffer ) == value ) { + if ( onlyOne ) { + return child; + } else { + results.push( child ); + } + } + } + + function change( val ) { + if ( caseInsen ) { + val = val.toUpperCase(); + } + return val; + } + + if ( onlyOne ) { + return false; + } + + var retList = new exports.List( this.discriminator ); + retList.contents = results; + + return retList; +} diff --git a/src/message.js b/src/message.js new file mode 100644 index 000000000..121bbf5dd --- /dev/null +++ b/src/message.js @@ -0,0 +1,39 @@ +var User = require( "./user.js" ).User; +var List = require( "./list.js" ).List; +var PMChannel = require( "./PMChannel.js" ).PMChannel; + +exports.Message = function( time, author, content, channel, id, mentions, everyoneMentioned, embeds ) { + + if ( !content ) { + message = time; + channel = author; + time = message.timestamp; + author = message.author; + content = message.content; + id = message.id; + mentions = message.mentions; + everyoneMentioned = message.mention_everyone; + embeds = message.embeds; + } + + this.time = Date.parse( time ); + this.author = new User( author ); + this.content = content.replace( /\s+/g, ' ' ).trim(); //content.replace(/<[^>]*>/g, "").replace(/\s+/g, ' ').trim(); + this.channel = channel; + this.id = id; + this.mentions = new List( "id" ); + this.everyoneMentioned = everyoneMentioned; + this.embeds = embeds; + for ( x in mentions ) { + var _mention = mentions[ x ]; + this.mentions.add( new User( _mention ) ); + } +} + +exports.Message.prototype.isPM = function() { + return ( this.channel instanceof PMChannel ); +} + +exports.Message.prototype.isMentioned = function( user ) { + return ( this.mentions.filter( "id", user.id ).length > 0 ); +} diff --git a/src/server.js b/src/server.js new file mode 100644 index 000000000..a5cfaab6a --- /dev/null +++ b/src/server.js @@ -0,0 +1,106 @@ +var User = require( "./user.js" ).User; +var List = require( "./list.js" ).List; +/** + * A wrapper for Server information, contains channels and users too. Developers should not instantiate the class, instead they should + * manipulate Server objects given to them. + * @class Server + * @param {String} region The region of the server + */ +exports.Server = function( region, ownerID, name, id, members, icon, afkTimeout, afkChannelId ) { + + /** + * The region of the Server + * @type {String} + * @attribute region + */ + this.region = region; + /** + * The ID of the owner of the Server (not a User!) + * @type {String} + * @attribute ownerID + */ + this.ownerID = ownerID; + /** + * The name of the Server + * @type {String} + * @attribute name + */ + this.name = name; + /** + * The ID of the Server + * @type {String} + * @attribute id + */ + this.id = id; + /** + * List containing members of the Server + * @param {List} + * @attribute members + */ + this.members = new List( "id" ); + /** + * List containing channelss of the Server + * @param {List} + * @attribute channels + */ + this.channels = new List( "id" ); + /** + * ID of the Icon of the Server + * @param {String} + * @attribute icon + */ + this.icon = icon; + /** + * The amount of seconds that should pass before the user is + * @type {Number} + * @attribute afkTimeout + */ + this.afkTimeout = afkTimeout; + /** + * The ID of the AFK Channel, evaluates to false if doesn't exist. + * @type {String} + * @attribute afkChannelId + */ + this.afkChannelId = afkChannelId; + + for ( x in members ) { + var member = members[ x ].user; + this.members.add( new User( member ) ); + } +} + +/** + * Returns a valid URL pointing towards the server's icon if it has one. + * @method getIconURL + * @return {String/Boolean} If there is an icon, a URL is returned. If not, false is returned. + */ +exports.Server.prototype.getIconURL = function(){ + if(!this.icon) + return false; + return "https://discordapp.com/api/guilds/"+this.id+"/icons/"+this.icon+".jpg"; +} + +/** + * Returns the AFK Channel if a server has one + * @method getAFKChannel + * @return {Channel/Boolean} If there is an AFK Channel, a Channel is returned. If not, false is returned. + */ +exports.Server.prototype.getAFKChannel = function(){ + + if(!this.afkChannelId) + return false; + + return this.channels.filter("id", this.afkChannelId, true); + +} + +/** + * Returns the #general channel of the server. + * @method getDefaultChannel + * @return {Channel} Returns the #general channel of the Server. + */ +exports.Server.prototype.getDefaultChannel = function() { + + return this.channels.filter( "name", "general", true ); + +} diff --git a/src/user.js b/src/user.js new file mode 100644 index 000000000..2bf3cc51b --- /dev/null +++ b/src/user.js @@ -0,0 +1,37 @@ +exports.User = function( username, id, discriminator, avatar ) { + + if ( !id ) { //there's no second argument + var user = username; + username = user.username; + id = user.id; + discriminator = user.discriminator; + avatar = user.avatar; + } + + this.username = username; + this.discriminator = discriminator; + this.id = id; + this.avatar = avatar; +} + +exports.User.prototype.getAvatarURL = function() { + if ( !this.avatar ) + return false; + return "https://discordapp.com/api/users/" + this.id + "/avatars/" + this.avatar + ".jpg"; +} + +exports.User.prototype.mention = function() { + return "<@" + this.id + ">"; +} + +exports.User.prototype.equals = function( otherUser ) { + + return otherUser.id === this.id; + +} + +exports.User.prototype.equalsStrict = function( otherUser ) { + + return ( this.username === otherUser.username && this.discriminator === otherUser.discriminator && this.id === otherUser.id && this.avatar === otherUser.avatar ); + +}