mgebbe@3: # twitter.js mgebbe@3: # mgebbe@3: # data object representing twitter.com mgebbe@3: # mgebbe@3: # Copyright 2013, E14N (https://e14n.com/) mgebbe@3: # all changes Copyright 2014, Intevation GmbH (https://intevation.org) mgebbe@3: # mgebbe@3: # Licensed under the Apache License, Version 2.0 (the "License"); mgebbe@3: # you may not use this file except in compliance with the License. mgebbe@3: # You may obtain a copy of the License at mgebbe@3: # mgebbe@3: # http://www.apache.org/licenses/LICENSE-2.0 mgebbe@3: # mgebbe@3: # Unless required by applicable law or agreed to in writing, software mgebbe@3: # distributed under the License is distributed on an "AS IS" BASIS, mgebbe@3: # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. mgebbe@3: # See the License for the specific language governing permissions and mgebbe@3: # limitations under the License. mgebbe@3: mgebbe@3: _ = require("underscore") mgebbe@3: async = require("async") mgebbe@3: OAuth = require("oauth").OAuth mgebbe@3: PumpIOClientApp = require("pump.io-client-app") mgebbe@3: DatabankObject = require("databank").DatabankObject mgebbe@3: RequestToken = PumpIOClientApp.RequestToken mgebbe@3: Usermap = require("./usermap") mgebbe@3: Pump = require("./pumpio") mgebbe@5: FromESN = require("./fromESN") mgebbe@3: ToESN = require("./toESN") mgebbe@5: Sync = require("./sync") mgebbe@22: util = require("util") mgebbe@28: htmlToText = require('html-to-text') mgebbe@22: twitter = require("twitter") mgebbe@3: mgebbe@3: module.exports = (config) -> mgebbe@5: bridgeid = config.bridgeid mgebbe@3: client_id = config.twclient_id mgebbe@3: client_secret = config.twclient_secret mgebbe@7: interval = config.interval mgebbe@7: if not (interval?) mgebbe@7: interval = 15 * 60 * 1000 mgebbe@3: request_token_endpoint = "https://api.twitter.com/oauth/request_token" mgebbe@3: access_token_endpoint = "https://api.twitter.com/oauth/access_token" mgebbe@3: authorization_endpoint = "https://api.twitter.com/oauth/authorize" mgebbe@3: whoami_endpoint = "https://api.twitter.com/1.1/account/verify_credentials.json" mgebbe@3: hostname = "twitter.com" mgebbe@3: mgebbe@3: Twitter = mgebbe@3: getRequestToken: (site, callback) -> mgebbe@3: oa = Twitter.getOAuth(site) mgebbe@3: async.waterfall [ mgebbe@3: (callback) -> mgebbe@3: oa.getOAuthRequestToken callback mgebbe@3: (token, secret, other, callback) -> mgebbe@3: RequestToken.create mgebbe@3: token: token mgebbe@3: secret: secret mgebbe@3: hostname: hostname mgebbe@3: , callback mgebbe@3: ], callback mgebbe@3: return mgebbe@3: mgebbe@3: authorizeURL: (rt) -> mgebbe@3: separator = undefined mgebbe@3: if _.contains(authorization_endpoint, "?") mgebbe@3: separator = "&" mgebbe@3: else mgebbe@3: separator = "?" mgebbe@3: authorization_endpoint + separator + "oauth_token=" + rt.token mgebbe@3: mgebbe@3: getAccessToken: (site, rt, verifier, callback) -> mgebbe@3: oa = Twitter.getOAuth(site) mgebbe@3: oa.getOAuthAccessToken rt.token, rt.secret, verifier, callback mgebbe@3: return mgebbe@3: mgebbe@3: whoami: (site, token, secret, callback) -> mgebbe@3: oa = Twitter.getOAuth(site) mgebbe@3: async.waterfall [(callback) -> mgebbe@3: oa.get whoami_endpoint, token, secret, callback mgebbe@3: return mgebbe@3: ], (err, doc, response) -> mgebbe@3: obj = undefined mgebbe@3: if err mgebbe@3: callback err, null mgebbe@3: else mgebbe@3: try mgebbe@3: obj = JSON.parse(doc) mgebbe@3: callback null, obj mgebbe@3: catch e mgebbe@3: callback e, null mgebbe@3: return mgebbe@3: mgebbe@3: return mgebbe@3: mgebbe@27: syncToESN: (user) -> mgebbe@3: me = user.user_pumpio mgebbe@5: id = user.user_ESN.substr(0,user.user_ESN.indexOf('@')) mgebbe@3: token = user.oauth_token mgebbe@3: secret = user.extra_token mgebbe@3: twit = new twitter( mgebbe@3: consumer_key: client_id mgebbe@3: consumer_secret: client_secret mgebbe@3: access_token_key: token mgebbe@3: access_token_secret: secret mgebbe@3: ) mgebbe@3: mgebbe@3: # GET PUBLIC PUMP POSTS AND POST THEM mgebbe@3: async.waterfall [ mgebbe@3: (callback) -> mgebbe@3: Usermap.search {id: me + '_to_' + me}, callback mgebbe@3: (user, callback) -> mgebbe@8: if (user[0]?) mgebbe@22: console.log "get feed from" + me mgebbe@8: Pump.getUserFeed(user[0],callback) mgebbe@8: else mgebbe@8: return mgebbe@3: (feed, callback) -> mgebbe@17: return if not feed? mgebbe@7: ti = new Date().getTime() - interval mgebbe@30: async.eachLimit feed.items, 1, ((post, callback) -> mgebbe@3: # do for each post mgebbe@7: ts = Date.parse(post.updated) mgebbe@7: if (ts >= ti and post.verb is "post" or post.verb is "share") and (post.object.objectType is "note" or post.object.objectType is "image") and (Pump.isPublicActivity(post)) and (typeof post.object.deleted is "undefined") mgebbe@3: ToESN.search {uid: post.object.id + "@twitter"}, (err, result) -> mgebbe@3: if result.length is 0 mgebbe@4: # post to twitter mgebbe@7: status = "" mgebbe@28: text = post.object.content mgebbe@28: text = htmlToText.fromString(text,wordwrap: 140) mgebbe@28: #text = post.object.content.replace(/<(?:.|\n)*?>/gm, '') mgebbe@28: #re = new RegExp(String.fromCharCode(160), "g") mgebbe@28: #text = text.replace(re, " ") mgebbe@7: if post.verb is "share" mgebbe@24: status = post.object.author.url + " writes: " mgebbe@3: if text.length <= 140 mgebbe@7: status += text mgebbe@3: else mgebbe@31: status += text.substr(0, 140 - (post.object.url.length + 2)) + " " + post.object.url mgebbe@3: twit.verifyCredentials((data) -> mgebbe@3: #console.log util.inspect(data) mgebbe@3: return mgebbe@3: ).updateStatus status, (data) -> mgebbe@3: async.waterfall [ mgebbe@3: (callback) -> mgebbe@3: savePost = new ToESN() mgebbe@3: savePost.uid = post.object.id + "@twitter" mgebbe@3: savePost.sourceUser = post.actor.id mgebbe@3: savePost.sourcePost = post.object.id mgebbe@3: savePost.targetUser = user.user_ESN mgebbe@3: savePost.targetPost = data.id mgebbe@3: savePost.recipientUser = 'public' mgebbe@3: savePost.updated = Date.now() mgebbe@3: savePost.save callback mgebbe@3: ], (err, result) -> mgebbe@3: #console.log util.inspect(data) mgebbe@3: return mgebbe@3: callback null, 'done' mgebbe@3: ), (err) -> mgebbe@3: callback null, 'done' mgebbe@3: ],(err, result) -> mgebbe@28: console.log "done ToESN twitter user " + me mgebbe@22: return mgebbe@22: return mgebbe@17: mgebbe@27: syncFromESN: (user) -> mgebbe@22: me = user.user_pumpio mgebbe@22: id = user.user_ESN.substr(0,user.user_ESN.indexOf('@')) mgebbe@22: token = user.oauth_token mgebbe@22: secret = user.extra_token mgebbe@22: twit = new twitter( mgebbe@22: consumer_key: client_id mgebbe@22: consumer_secret: client_secret mgebbe@22: access_token_key: token mgebbe@22: access_token_secret: secret mgebbe@22: ) mgebbe@5: ###################################### mgebbe@5: # get tweets and post them to pump.io# mgebbe@5: ###################################### mgebbe@5: twit.verifyCredentials((data) -> mgebbe@5: #console.log util.inspect(data) mgebbe@22: console.log "get twitter HomeTimeline " + me mgebbe@5: return mgebbe@28: ).getHomeTimeline {include_rts: true, count: 15 }, (data) -> mgebbe@27: console.log "got twitter HomeTimeline " + me mgebbe@27: return if not data? or data.length is 0 mgebbe@28: console.log "data isnt empty for " + me mgebbe@7: ti = (new Date().getTime() - interval) mgebbe@30: async.eachLimit data, 3, ((tweet, cb) -> mgebbe@5: async.waterfall [ mgebbe@5: (callback) -> mgebbe@30: FromESN.search {uid: tweet.id_str + "@twitter_to_" + me}, callback mgebbe@5: (result, callback) -> mgebbe@7: return if result.length isnt 0 or tweet.user.id_str is id mgebbe@30: console.log "tweet found" mgebbe@7: twitterdate = new Date(Date.parse(tweet.created_at.replace(/( +)/, " UTC$1"))) mgebbe@7: ts = Date.parse(twitterdate) mgebbe@7: if (ts >= ti) mgebbe@7: Sync.postParser tweet, null, 'twitter', callback mgebbe@22: else mgebbe@22: return mgebbe@5: (parsed, callback) -> mgebbe@27: console.log "try to post new tweet" mgebbe@5: Pump.postUser bridgeid, me, parsed, callback mgebbe@5: (pumppost, callback) -> mgebbe@27: try mgebbe@27: pumppost = JSON.parse(pumppost) mgebbe@27: catch err mgebbe@27: console.log "parse err " + err mgebbe@27: return mgebbe@5: FromESN.create mgebbe@30: postid: tweet.id_str + "@twitter" mgebbe@5: sourceUser: tweet.user.id mgebbe@30: sourcePost: 'https://twitter.com/'+tweet.user.screen_name+"/status/" + tweet.id_str mgebbe@5: pumpPost: pumppost.object.id mgebbe@5: recipientUser: me mgebbe@5: created: Date.now() mgebbe@5: , callback mgebbe@5: ], (err, result) -> mgebbe@28: console.log "post a tweet to user " + me mgebbe@30: cb mgebbe@17: ), (err) -> mgebbe@22: if (err) mgebbe@22: console.log "Error: " + err mgebbe@22: else mgebbe@28: console.log "done FromESN twitter user " + me mgebbe@3: return mgebbe@3: mgebbe@30: postLike: (user) -> mgebbe@30: i = 0 mgebbe@30: me = user.user_pumpio mgebbe@30: id = user.user_ESN.substr(0,user.user_ESN.indexOf('@')) mgebbe@30: token = user.oauth_token mgebbe@30: secret = user.extra_token mgebbe@30: twit = new twitter( mgebbe@30: consumer_key: client_id mgebbe@30: consumer_secret: client_secret mgebbe@30: access_token_key: token mgebbe@30: access_token_secret: secret mgebbe@30: ) mgebbe@30: console.log "try 2 find twitter likes for " + me mgebbe@30: async.waterfall [ mgebbe@30: (callback) -> mgebbe@30: Usermap.search {id: me + '_to_' + me}, callback mgebbe@30: (pumpuser, callback) -> mgebbe@30: Pump.getLikes(pumpuser[0], callback) mgebbe@30: (likearray, callback) -> mgebbe@30: return if not (likearray?) or likearray.length is 0 mgebbe@30: likes = JSON.parse(likearray) mgebbe@30: return if not (likes?) or likes.items.length is 0 mgebbe@30: async.each likes.items,((note, cb) -> mgebbe@30: async.waterfall [ mgebbe@30: (callback) -> mgebbe@30: FromESN.search {recipientUser: me, pumpPost: note.id}, callback mgebbe@30: (fromesn, callback) -> mgebbe@30: if (fromesn?) and fromesn.length isnt 0 and fromesn[0].sourcePost.indexOf('twitter.com') isnt -1 mgebbe@30: #console.log fromesn[0] mgebbe@30: obj = fromesn[0].postid.substr(0,fromesn[0].postid.indexOf('@')) mgebbe@30: twit.post "/favorites/create.json", mgebbe@30: id: obj mgebbe@30: , (data) -> mgebbe@30: console.log "Twitter " + obj + " liked" mgebbe@30: ], (err, result) -> mgebbe@30: ), (err) -> mgebbe@30: ], (err, result) -> mgebbe@30: return mgebbe@30: mgebbe@3: getOAuth: (site) -> mgebbe@3: new OAuth(request_token_endpoint, access_token_endpoint, client_id, client_secret, "1.0", site.url("/authorized-for-twitter"), "HMAC-SHA1", null, # nonce size; use default mgebbe@3: "User-Agent": site.userAgent() mgebbe@3: ) mgebbe@3: mgebbe@3: Twitter