@jaybirdgroup/data-hub-connector-twitter
Version:
Connector to interact with Twitter API in scope of Data Hub.
261 lines (205 loc) • 7.31 kB
JavaScript
/**
* Twitter bot re-posts latest post from random competitor Facebook page.
*
* @module twitter-bot
*/
;
const Twit = require('twit');
const TwitterApi = require('node-twitter-api');
const _merge = require('lodash/merge');
const fs = require('fs');
const request = require('request').defaults({ encoding: null });
const path = require('path');
/**
* Class representing a Twitter bot re-posts latest post from random competitor Facebook page
*/
class Twitter {
/**
* Init class and apply defaults.
* @param {Object} config - Bot configurations and Twitter keys.
*/
constructor(config) {
// default params
this.defaults = {
consumerKey: '',
consumerSecret: '',
accessToken: '',
accessTokenSecret: '',
appOnlyAuth: false
};
// TODO: check for missing parameters
this.config = _merge({}, this.defaults, config);
this.twitter = new Twit({
consumer_key: this.config.consumerKey,
consumer_secret: this.config.consumerSecret,
access_token: this.config.accessToken,
access_token_secret: this.config.accessTokenSecret,
app_only_auth: this.config.appOnlyAuth,
timeout_ms: 60 * 1000 // optional HTTP request timeout to apply to all requests.
});
}
/**
* Method to be called after post is published or error occurred.
* @callback publishPostCallback
* @param {Array} errs - Array with JS Errors objects or empty.
* @param {Array} publishedPosts - Array with results or empty.
*/
/**
* Publish post to one or several destination Facebook pages
* @param {Object} publishData - Post data to be sent
* @param {string} publishData.url - Post url
* @param {?string} publishData.title - Title of the store
* @param {?string} publishData.content - Message
* @param {publishPostCallback} next - [Callback function]{@link module:twitter-bot~publishPostCallback}.
*/
publishPost (publishData, next) {
// publishData example:
// {
// url: normalizedPost.videoSource,
// title: normalizedPost.title,
// content: normalizedPost.message
// }
const localname = `tempmedia-${Date.now()}`;
const PATH = path.join(
__dirname,
`${localname}`
);
// get the media from remote storage
request.get(publishData.url, (error, response, body) => {
if (error) {
return next(error);
}
// save media to disk temporarily, we
// delete the media after uploading it
fs.writeFile(PATH, body, (error) => {
if (error) {
return next(error);
}
// step ONE
this.twitter.postMediaChunked({ file_path: PATH }, (error, data, response) => {
if (error) {
return next(error);
}
const mediaIdStr = data.media_id_string;
const meta_params = { media_id: mediaIdStr };
// step TWO
this.twitter.post('media/metadata/create', meta_params, (error, data, response) => {
if (error) {
return next(error);
}
const params = { status: publishData.content, media_ids: [mediaIdStr] };
// step THREE
this.twitter.post('statuses/update', params, (error, tweet, response) => {
fs.unlinkSync(PATH); // Deletes media from /tmp folder
return next(error, tweet);
}); // end '/statuses/update'
}); // end '/media/metadata/create'
}); // end T.postMedisChunked
}); //end fs.writeFile
}); // end request.get
}
/**
* Check for a Twitter error.
* @param {Object} res - A response from a Twitter API.
* @returns {?Error} - An Error object or null.
*/
_error (res) {
if (!res || res.error) {
let errorMessage = 'unknown error occurred';
if (res.error && typeof res.error === 'string') {
errorMessage = res.error;
}
else if (res.error) {
errorMessage = JSON.stringify(res.error);
}
return new Error(errorMessage);
}
return null;
}
/**
* Method to be called after get login url or error occurred.
* @callback getLoginUrlCallback
* @param {?Error} err - An Error object or null.
* @param {Object} loginInfo - An object with login information
* @param {string} loginInfo.loginUrl - A login url
* @param {string} loginInfo.requestToken - A request token
* @param {string} loginInfo.requestTokenSecret - A request token secret
*/
/**
* Get url for login
* @param {string} returnUrl - A return url to be redirected to after twitter login
* @param {string} accessType - A permission
* @param {getLoginUrlCallback} next - [Callback function]{@link module:twitter-bot~getLoginUrlCallback}.
* @return {Promise}
*/
getLoginUrl(returnUrl, accessType, next) {
const twitterApi = new TwitterApi({
consumerKey: this.config.consumerKey,
consumerSecret: this.config.consumerSecret,
callback: returnUrl,
x_auth_access_type: accessType
});
return new Promise((resolve, reject) => {
twitterApi.getRequestToken((err, requestToken, requestTokenSecret) => {
if (err) {
if (next) {
next(err);
}
return reject(err);
}
const loginUrl = twitterApi.getAuthUrl(requestToken);
const results = {
loginUrl,
requestToken,
requestTokenSecret
};
if (next) {
next(null, results);
}
resolve(results);
});
});
}
/**
* Method to be called after get access token or error occurred.
* @callback getAccessTokenCallback
* @param {?Error} err - An Error object or null.
* @param {Object} accessTokenInfo - An object with access token information
* @param {string} accessTokenInfo.accessToken - An access token
* @param {string} accessTokenInfo.accessTokenSecret - An access token secret
*/
/**
* Get access token to make api calls
* @param {string} oauthVerifier - Oauth verifier received after login on twitter side
* @param {string} requestToken - A request token
* @param {string} requestTokenSecret - A request token secret
* @param {getAccessTokenCallback} next - [Callback function]{@link module:twitter-bot~getAccessTokenCallback}.
* @return {Promise}
*/
getAccessToken(oauthVerifier, requestToken, requestTokenSecret, next) {
const twitterApi = new TwitterApi({
consumerKey: this.config.consumerKey,
consumerSecret: this.config.consumerSecret
});
return new Promise((resolve, reject) => {
twitterApi.getAccessToken(requestToken, requestTokenSecret, oauthVerifier, (err, accessToken, accessTokenSecret) => {
if (err) {
if (next) {
next(err);
}
return reject(err);
}
const results = {
accessToken,
accessTokenSecret
};
if (next) {
next(null, results);
}
resolve(results);
});
});
}
}
// export class to have the extend ability
module.exports = Twitter;