diff --git a/xtrn/twitter/readme.txt b/xtrn/twitter/readme.txt new file mode 100644 index 0000000000000000000000000000000000000000..46550cc35d419509007b1e06a98c3f3270a1b286 --- /dev/null +++ b/xtrn/twitter/readme.txt @@ -0,0 +1,124 @@ +Twitter utilities for Synchronet BBS 3.16c+ +echicken -at- bbs.electronicchicken.com, January 2017 + +Contents: + + 1) Introduction + 2) Create a Twitter application + 3) Add your Twitter configuration to modopts.ini + 4) Send a test tweet + 5) Do things + 6) Support + +1) Introduction + + This project is in its early stages. Its purpose is to provide a set of + utilities that will enable your BBS to interact with the Twitter REST API. + Additionally, a library (twitter.js) is provided which you can use to + develop your own custom integrations. + + At the moment the only included utility is 'tweet.js', which can be used to + send a tweet. You can run this via jsexec, or by using the 'bbs.exec()' or + 'system.exec()' javascript methods, or by configuring it as an external + program which is triggered by a certain event. + + The 'twitter.js' library contains methods for posting tweets, searching for + tweets, or reading a list of tweets by a particular user. If you have + questions about how to write scripts that use this library, or want to + request additional features, let me know. (See the Support section below.) + + Be sure that you have updated the following two files before attempting to + use this: + + exec/load/http.js + exec/load/oauth.js + + You can find these files on the Synchronet CVS repository, cvs.synchro.net. + +2) Create a Twitter application + + If you don't already have a Twitter account, sign up for one: + + https://twitter.com/signup + + (Any tweets created by your BBS will be sent from this account.) + + Next, create a new application: + + https://apps.twitter.com/app/new + + Under the application's 'Keys and Access Tokens' tab, click on the 'Create + my access token' button at the bottom. + +3) Add your Twitter configuration to modopts.ini + + Add a new section to your 'ctrl/modopts.ini' file that looks like this: + + [twitter] + consumer_key = xxx + consumer_secret = xxx + access_token = xxx + access_token_secret = xxx + + Replace the 'xxx' values with the corresponding details from your Twitter + application's 'Keys and Access Tokens' page. + +4) Send a test tweet + + From a command prompt, change to the 'exec' directory of your Synchronet + installation and try the following: + + Linux: + + ./jsexec ../xtrn/twitter/tweet.js This is a test tweet + + Windows: + + jsexec ..\xtrn\twitter\tweet.js This is a test tweet + + On the web, check to see that your tweet was published. If so, you're ready + to proceed. + +5) Do things + + You can send a tweet from within any Synchronet javascript module by adding + a line similar to this: + + bbs.exec('?../xtrn/twitter/tweet.js This is a test tweet'); + + For example, you could announce on Twitter whenever somebody logs on to your + BBS by placing the following line at the bottom of your 'logon.js' file: + + bbs.exec('?../xtrn/twitter/tweet.js ' + user.alias + ' logged on.'); + + Twitter may refuse to accept a tweet if it's identical to another one you've + sent recently, so it may help to add some unique info to it: + + bbs.exec( + '?../xtrn/twitter/tweet.js ' + user.alias + ' logged on.' + + ' (Call #' + system.stats.total_logons + ')' + ); + + If modifying 'logon.js' or any other stock javascript module, remember to + copy the original file to your 'mods' directory and make your changes to + the copy. If a script exists in 'mods', it will be used instead of the copy + in the 'exec' directory. + +6) Support + + DOVE-Net + + Post a message to 'echicken' in the 'Synchronet Sysops' sub-board. + Unless I'm dead or on vacation, I'll probably get back to you within a + day or so. + + electronic chicken bbs + + Post a message in the 'Support' sub-board of the 'Local' message group + on my BBS, bbs.electronicchicken.com + + IRC : #synchronet on irc.synchro.net + + I'm not always in front of a computer, so you won't always receive an + immediate response if you contact me on IRC. That said, if you stay + online and idle, I'll probably see your message and respond eventually. diff --git a/xtrn/twitter/tweet.js b/xtrn/twitter/tweet.js new file mode 100644 index 0000000000000000000000000000000000000000..96d3d021d2b611a9b212dbb7a01dc79be9f6ad8a --- /dev/null +++ b/xtrn/twitter/tweet.js @@ -0,0 +1,14 @@ +load('sbbsdefs.js'); +load(js.exec_dir + 'twitter.js'); +var options = load({}, 'modopts.js', 'twitter'); + +if (argv.length < 1) exit(); + +try { + (new Twitter( + options.consumer_key, options.consumer_secret, + options.access_token, options.access_token_secret + )).tweet({ status : argv.join(' ') }); +} catch (err) { + log(LOG_ERR, err); +} \ No newline at end of file diff --git a/xtrn/twitter/twitter.js b/xtrn/twitter/twitter.js new file mode 100644 index 0000000000000000000000000000000000000000..4308e61e07c51f09af16d36a4c6752143b95731f --- /dev/null +++ b/xtrn/twitter/twitter.js @@ -0,0 +1,85 @@ +load('oauth.js'); + +var Twitter = function (key, secret, token, token_secret) { + + var self = this; + + this.api_url = 'https://api.twitter.com/1.1'; + this.key = key; + this.secret = secret; + this.token = token; + this.token_secret = token_secret; + + var endpoints = { + search : { + tweets : { + method : 'search', + required : { q : '' }, + http_method : 'get' + } + }, + statuses : { + update : { + method : 'tweet', + required : { status : '' }, + http_method : 'post' + }, + user_timeline : { + method : 'get_user_timeline', + required : { screen_name : '' }, + http_method : 'get' + } + } + }; + + /* Send a signed OAuth1 POST request to this.api_url + 'path'. + POST data will be constructed from key/value pairs in 'obj'. */ + this.post = function (path, obj) { + return JSON.parse( + (new OAuth1_Client()).post( + this.api_url + path, obj, + this.key, this.secret, this.token, this.token_secret + ) + ); + } + + /* Send a signed OAuth1 GET request to this.api_url + 'path'. + Query parameters will be constructed from key/value pairs in 'obj'. */ + this.get = function (path, obj) { + return JSON.parse( + (new OAuth1_Client()).get( + this.api_url + path + '?' + param_stringify(obj, false, '&'), + this.key, this.secret, this.token, this.token_secret + ) + ); + } + + // Populate methods from described REST API endpoints + function methodist(obj, path) { + for (var property in obj) { + if (typeof obj[property].method === 'undefined') { + methodist(obj[property], path + property + '/'); + } else { + (function (obj, property, path) { + self[obj[property].method] = function (data) { + if (typeof data === 'undefined') var data = {}; + if (typeof obj[property].required === 'object') { + for (var r in obj[property].required) { + if (typeof data[r] !== + typeof obj[property].required[r] + ) { + throw obj[property].method + ': missing ' + r; + } + } + } + return self[obj[property].http_method]( + path + property + '.json', data + ); + } + })(obj, property, path); + } + } + } + methodist(endpoints, '/'); + +} \ No newline at end of file