mgebbe@0: # Copyright (C) 2014 by Intevation GmbH mgebbe@0: # Author: Mathias Gebbe mgebbe@0: # mgebbe@3: # This file is Free Software under the Apache License, Version 2.0; mgebbe@3: # and comes with NO WARRANTY! mgebbe@3: # See the documentation coming with pumpbridge for details. mgebbe@0: mgebbe@0: https = require("https") mgebbe@0: async = require("async") mgebbe@0: _ = require("underscore") mgebbe@0: Routes = require("./routes") mgebbe@0: FB = require('fb') mgebbe@0: EdgeControl = require("./edgecontrol") mgebbe@0: Edge = require("./edge") mgebbe@0: CommentToESN = require("./commenttoesn") mgebbe@0: ToESN = require("./toESN") mgebbe@0: FromESN = require("./fromESN") mgebbe@0: Pump = require("./pumpio") mgebbe@0: User = require("./user") mgebbe@0: Sync = require("./sync") mgebbe@0: Usermap = require("./usermap") mgebbe@0: Config = require("./config") mgebbe@0: mgebbe@0: config = Config.config mgebbe@0: mgebbe@0: bridgeid = config.bridgeid mgebbe@0: secret = config.fbSECRET mgebbe@0: appid = config.fbAPPID mgebbe@0: mgebbe@0: ####################################### mgebbe@0: ###### facebook sync ##### mgebbe@0: ####################################### mgebbe@0: mgebbe@0: sync = (user) -> mgebbe@0: me = user.user_pumpio mgebbe@0: id = user.user_ESN.substr(0,user.user_ESN.indexOf('@')) mgebbe@0: pubuser = "" mgebbe@0: post = "" mgebbe@0: mgebbe@0: # GET NEW POSTS mgebbe@0: #### mgebbe@0: async.waterfall [ mgebbe@0: (callback) -> mgebbe@0: getFriends(user) mgebbe@0: getPages(user) mgebbe@0: getUser(user) mgebbe@0: getStream user,callback mgebbe@0: ], (err, posts) -> mgebbe@17: return if not posts? or posts.length is 0 mgebbe@0: #console.log JSON.stringify(posts) # all posts from network (100) mgebbe@22: async.eachLimit posts, 10, ((post, callback) -> mgebbe@0: async.waterfall [ mgebbe@0: (callback) -> mgebbe@22: FromESN.search {uid: post.id + "@facebook_to_" + me}, callback mgebbe@0: (result, callback) -> mgebbe@7: return if result.length isnt 0 or post.from.id is id mgebbe@0: #console.log "postid: " + post.from.id + "id:" + id mgebbe@0: # if this is your own post return!!! mgebbe@0: getPublicUserInfo(post.from.id , callback) mgebbe@0: (pubuser, callback) -> mgebbe@0: pubuser = pubuser mgebbe@0: User.search {id: pubuser.id + "@facebook"}, callback mgebbe@0: (dbuser, callback) -> mgebbe@8: if (dbuser[0]?) mgebbe@8: Sync.postParser post, dbuser[0], 'facebook', callback mgebbe@8: else mgebbe@8: return mgebbe@0: (parsed, callback) -> mgebbe@0: Pump.postUser bridgeid, me, parsed, callback mgebbe@0: (pumppost, callback) -> mgebbe@17: return if not pumppost? or not post.actions[0]? mgebbe@0: pumppost = JSON.parse(pumppost) mgebbe@17: postlink = post.actions[0].link mgebbe@0: FromESN.create mgebbe@0: postid: post.id + "@facebook" mgebbe@0: sourceUser: post.from.id mgebbe@7: sourcePost: postlink mgebbe@0: pumpPost: pumppost.object.id mgebbe@0: recipientUser: me mgebbe@0: created: Date.now() mgebbe@0: , callback mgebbe@0: ], (err, result) -> mgebbe@0: callback null, 'done' mgebbe@0: ), (err) -> mgebbe@0: if err mgebbe@0: console.log 'one post fail to process' mgebbe@0: else mgebbe@0: console.log 'all posts processed' mgebbe@0: return mgebbe@22: mgebbe@0: #### mgebbe@0: # TO DO: GET NEW COMMENTS mgebbe@0: # for each fromESN check the comments mgebbe@0: # if comment author = me mgebbe@0: # post comment mgebbe@0: # if comment author != me mgebbe@0: # post comment with 'user schreibt' mgebbe@0: async.waterfall [ mgebbe@0: (callback) -> mgebbe@0: FromESN.search {recipientUser: me}, callback mgebbe@0: (allESN, callback) -> mgebbe@22: async.eachLimit allESN, 10, ((fromesn, callback) -> mgebbe@0: async.waterfall [ mgebbe@0: (cb) -> mgebbe@8: if fromesn.sourcePost.indexOf('www.facebook.com') is -1 mgebbe@8: return mgebbe@0: Usermap.search {id: me + '_to_' + me}, cb mgebbe@0: (pumpuser, cb) -> mgebbe@0: Pump.getNote(pumpuser[0], fromesn.pumpPost, cb) mgebbe@0: (note, cb) -> mgebbe@8: return if not (note?) mgebbe@4: if note.liked is true mgebbe@0: obj = fromesn.postid.substr(0,fromesn.postid.indexOf('@')) mgebbe@0: postLike(user,obj) mgebbe@0: if (note.replies?) mgebbe@0: reply = JSON.stringify(note.replies) mgebbe@0: rep = JSON.parse(reply) mgebbe@0: if rep.totalItems >= 1 mgebbe@0: async.each rep.items, ((r, callback) -> mgebbe@0: if r.author.id is "acct:" + me mgebbe@0: obj = fromesn.postid.substr(0,fromesn.postid.indexOf('@')) mgebbe@0: postComment(user, obj, r.id , r.content) mgebbe@0: callback null, 'done' mgebbe@0: ), (err) -> mgebbe@0: cb null, 'done' mgebbe@0: ], (err, result) -> mgebbe@0: #done mgebbe@0: ), (err) -> mgebbe@0: callback null, 'done' mgebbe@0: ], (err, result) -> mgebbe@0: #done mgebbe@0: mgebbe@0: # GET PUBLIC PUMP POSTS AND POST THEM mgebbe@0: async.waterfall [ mgebbe@0: (callback) -> mgebbe@0: Usermap.search {id: me + '_to_' + me}, callback mgebbe@0: (user, callback) -> mgebbe@0: Pump.getUserFeed(user[0],callback) mgebbe@0: (feed, callback) -> mgebbe@7: interval = config.interval mgebbe@7: if not (interval?) mgebbe@7: interval = 15 * 60 * 1000 # 900 000 ms (15min) mgebbe@7: ti = new Date().getTime() - interval mgebbe@0: async.eachSeries feed.items, ((post, callback) -> mgebbe@0: # 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 not (post.object.deleted?) mgebbe@0: postStream(user,post) mgebbe@0: callback null, 'done' mgebbe@0: ), (err) -> mgebbe@0: callback null, 'done' mgebbe@0: ],(err, result) -> mgebbe@0: #console.log 'done.' mgebbe@0: mgebbe@0: return mgebbe@0: mgebbe@0: mgebbe@0: ####################################### mgebbe@0: ###### get user facebook ##### mgebbe@0: ####################################### mgebbe@0: getUser = (user) -> mgebbe@0: data = "" mgebbe@0: id = user.user_ESN.substr(0,user.user_ESN.indexOf('@')) mgebbe@0: token = user.oauth_token mgebbe@0: fields = 'fields=id,name,picture,link' mgebbe@0: options = mgebbe@0: host: 'graph.facebook.com' mgebbe@0: port: 443 mgebbe@0: path: '/' + id + '?access_token=' + token + '&' + fields mgebbe@0: mgebbe@0: https.get(options, (res) -> mgebbe@0: #console.log "Got response: " + res.statusCode mgebbe@0: mgebbe@0: res.on "data", (chunk) -> mgebbe@0: data += chunk mgebbe@0: return mgebbe@0: mgebbe@0: res.on "end", () -> mgebbe@12: if (data?) mgebbe@12: try mgebbe@12: user = JSON.parse(data) mgebbe@12: ### with app id ### mgebbe@12: Routes.updateUserDB(user.id+'@facebook',user.name,user.name,user.link,user.picture.data.url) if user? mgebbe@12: ### with link ### mgebbe@12: Routes.updateUserDB(user.link,user.name,user.name,user.link,user.picture.data.url) if user? mgebbe@12: catch err mgebbe@12: console.log "User Error" mgebbe@0: return mgebbe@0: mgebbe@0: ).on "error", (e) -> mgebbe@0: console.log "Got error: " + e.message mgebbe@0: mgebbe@0: return mgebbe@0: mgebbe@0: ############################################## mgebbe@12: ###### get facebook likes ###### mgebbe@0: ############################################## mgebbe@0: getFriends = (user) -> mgebbe@0: me = user.user_pumpio mgebbe@12: token = user.oauth_token mgebbe@12: mgebbe@12: FB.setAccessToken token mgebbe@12: mgebbe@12: FB.api "me/friends?limit=5000", mgebbe@12: fields: [ mgebbe@12: "id" mgebbe@12: ] mgebbe@12: , (res) -> mgebbe@12: if not res or res.error mgebbe@12: console.log (if not res then "error occurred" else res.error) mgebbe@12: mgebbe@17: async.each res.data, ((person, cb) -> mgebbe@12: getUserById(me,person.id,token) mgebbe@17: cb() mgebbe@12: return mgebbe@17: ), (err) -> mgebbe@17: return mgebbe@12: return mgebbe@12: mgebbe@12: ####################################### mgebbe@12: ###### get user facebook3 ##### mgebbe@12: ####################################### mgebbe@12: getFriends3 = (user) -> mgebbe@12: data = "" mgebbe@12: id = user.user_ESN.substr(0,user.user_ESN.indexOf('@')) mgebbe@12: token = user.oauth_token mgebbe@12: options = mgebbe@12: host: 'graph.facebook.com' mgebbe@12: port: 443 mgebbe@12: path: 'me/friends?limit=5000&access_token=' + token + '&client_id='+ appid + '&client_secret=' + secret mgebbe@12: mgebbe@12: https.get(options, (res) -> mgebbe@12: console.log "Got response: " + res.statusCode mgebbe@12: mgebbe@12: res.on "data", (chunk) -> mgebbe@12: data += chunk mgebbe@12: return mgebbe@12: mgebbe@12: res.on "end", () -> mgebbe@12: console.log data mgebbe@12: return mgebbe@12: mgebbe@12: ).on "error", (e) -> mgebbe@12: console.log "Got error: " + e.message mgebbe@12: mgebbe@12: return mgebbe@12: mgebbe@12: ############################################## mgebbe@12: ###### get facebook friends2 ###### mgebbe@12: ############################################## mgebbe@12: getFriends2 = (user) -> mgebbe@12: me = user.user_pumpio mgebbe@11: id = user.user_ESN.substr(0,user.user_ESN.indexOf('@')) mgebbe@0: token = user.oauth_token mgebbe@0: mgebbe@0: EdgeControl.removeEdges(me,'@facebook') mgebbe@0: EdgeControl.removeEdges(me,'www.facebook.com') mgebbe@0: mgebbe@0: FB.setAccessToken token mgebbe@11: FB.api "fql", mgebbe@11: q: "SELECT uid2 FROM friend WHERE uid1 = me()" mgebbe@0: , (res) -> mgebbe@11: console.log res mgebbe@0: if not res or res.error mgebbe@0: console.log (if not res then "error occurred" else res.error) mgebbe@11: return mgebbe@0: mgebbe@17: async.each res.data, ((user, cb) -> mgebbe@12: getUserById(me,user.uid2,token) mgebbe@17: cb() mgebbe@0: return mgebbe@17: ), (err) -> mgebbe@17: return mgebbe@11: return mgebbe@11: mgebbe@10: return mgebbe@10: mgebbe@10: mgebbe@10: ############################################## mgebbe@10: ###### get facebook likes ###### mgebbe@10: ############################################## mgebbe@10: getPages = (user) -> mgebbe@10: me = user.user_pumpio mgebbe@10: token = user.oauth_token mgebbe@10: mgebbe@10: FB.setAccessToken token mgebbe@10: mgebbe@10: FB.api "me/likes?limit=5000", mgebbe@10: fields: [ mgebbe@10: "id" mgebbe@10: ] mgebbe@10: , (res) -> mgebbe@10: if not res or res.error mgebbe@10: console.log (if not res then "error occurred" else res.error) mgebbe@10: mgebbe@17: async.each res.data, ((page,cb) -> mgebbe@11: getUserById(me,page.id,token) mgebbe@17: cb() mgebbe@10: return mgebbe@17: ), (err) -> mgebbe@17: return mgebbe@0: return mgebbe@0: mgebbe@0: mgebbe@0: ####################################### mgebbe@0: ###### get facebook stream ###### mgebbe@0: ####################################### mgebbe@0: getStream = (user,callback) -> mgebbe@0: token = user.oauth_token mgebbe@7: interval = config.interval mgebbe@7: if not (interval?) mgebbe@7: interval = 15 * 60 * 1000 # 900 000 ms (15min) mgebbe@7: ts = Math.round(((new Date()).getTime() - interval)/1000) mgebbe@12: mgebbe@0: FB.setAccessToken token mgebbe@0: mgebbe@17: FB.api "me/home?limit=10&?since="+ts, mgebbe@0: fields: [ mgebbe@0: "id" mgebbe@0: "type" mgebbe@0: "from" mgebbe@0: "privacy" mgebbe@0: "message" mgebbe@0: "picture" mgebbe@0: "link" mgebbe@0: "status_type" mgebbe@0: "caption" mgebbe@0: "created_time" mgebbe@0: "updated_time" mgebbe@0: "picture" mgebbe@0: "actions" mgebbe@0: ] mgebbe@0: , (res) -> mgebbe@0: if not res or res.error mgebbe@0: console.log (if not res then "error occurred" else res.error) mgebbe@0: callback null, null mgebbe@0: mgebbe@0: newposts = new Array() mgebbe@17: async.each res.data, ((post,cb) -> mgebbe@0: newposts.push(post) if (post.type is 'status' or post.type is 'photo' or post.type is 'link' or post.type is 'video') and (post.status_type is 'mobile_status_update' or post.status_type is 'added_photos' or post.status_type is 'shared_story') mgebbe@17: cb() mgebbe@17: return mgebbe@17: ), (err) -> mgebbe@17: callback null, newposts.reverse() mgebbe@17: return mgebbe@17: return mgebbe@0: mgebbe@0: ####################################### mgebbe@0: ###### post facebook stream ###### mgebbe@0: ####################################### mgebbe@0: postStream = (user, post) -> mgebbe@0: token = user.oauth_token mgebbe@7: text = "" mgebbe@0: mgebbe@0: FB.setAccessToken token mgebbe@0: mgebbe@4: return if not post.object.content? or post.object.content is "" mgebbe@4: ToESN.search {uid: post.object.id + "@facebook"}, (err, result) -> mgebbe@0: if result.length is 0 mgebbe@0: body = post.object.content.replace(/<(?:.|\n)*?>/gm, '') + " " + post.object.url mgebbe@7: if post.verb is "share" mgebbe@24: text = post.object.author.url + " writes:" mgebbe@0: FB.api "me/feed", "post", mgebbe@7: message: text + body mgebbe@0: , (res) -> mgebbe@0: if not res or res.error mgebbe@0: console.log (if not res then "error occurred" else res.error) mgebbe@0: return mgebbe@0: mgebbe@0: async.waterfall [ mgebbe@0: (callback) -> mgebbe@0: savePost = new ToESN() mgebbe@4: savePost.uid = post.object.id + "@facebook" mgebbe@0: savePost.sourceUser = post.actor.id mgebbe@0: savePost.sourcePost = post.object.id mgebbe@0: savePost.targetUser = user.user_ESN mgebbe@0: savePost.targetPost = res.id mgebbe@0: savePost.recipientUser = 'public' mgebbe@0: savePost.updated = Date.now() mgebbe@0: savePost.save callback mgebbe@0: ], (err, result) -> mgebbe@0: mgebbe@0: return mgebbe@0: mgebbe@0: return mgebbe@0: mgebbe@0: ################################################## mgebbe@0: ###### post comment to facebook stream ###### mgebbe@0: ################################################## mgebbe@0: postComment = (user, object_id, pumpid, text) -> mgebbe@0: mgebbe@0: # check if the comment is allready posted (search bla return) mgebbe@0: mgebbe@0: CommentToESN.search { uid: pumpid + "_to_" + "https://facebook.com/" + object_id}, (err, result) -> mgebbe@0: if result.length is 0 mgebbe@0: token = user.oauth_token mgebbe@0: text = text.replace /<(?:.|\n)*?>/g, "" mgebbe@0: mgebbe@0: FB.setAccessToken token mgebbe@0: mgebbe@0: FB.api "" + object_id + "/comments", "POST", mgebbe@0: message: text mgebbe@0: , (res) -> mgebbe@0: if not res or res.error mgebbe@0: console.log (if not res then "error occurred" else res.error) mgebbe@0: return mgebbe@0: mgebbe@0: CommentToESN.create mgebbe@0: ESNPost: "https://facebook.com/" + object_id mgebbe@0: pumpComment: pumpid mgebbe@0: created: Date.now() mgebbe@0: , (err, result) -> mgebbe@0: console.log 'comment saved' mgebbe@0: mgebbe@0: return mgebbe@0: mgebbe@0: ################################################## mgebbe@0: ###### like post on facebook stream ###### mgebbe@0: ################################################## mgebbe@0: postLike = (user, object_id) -> mgebbe@0: token = user.oauth_token mgebbe@0: FB.setAccessToken token mgebbe@0: mgebbe@0: FB.api "" + object_id + "/likes", "POST" mgebbe@0: , (res) -> mgebbe@0: if not res or res.error mgebbe@0: console.log (if not res then "error occurred" else res.error) mgebbe@0: return mgebbe@0: mgebbe@0: console.log 'liked' mgebbe@0: return mgebbe@0: mgebbe@0: return mgebbe@0: mgebbe@0: mgebbe@0: ###################################################################### mgebbe@0: ###### get user facebook by id and add him to UserDB and EDGES ##### mgebbe@0: ###################################################################### mgebbe@0: getUserById = (me,id,token) -> mgebbe@0: data = "" mgebbe@0: token = token mgebbe@0: fields = 'fields=id,name,picture,link' mgebbe@0: options = mgebbe@0: host: 'graph.facebook.com' mgebbe@0: port: 443 mgebbe@10: path: '/' + id + '?access_token=' + token + '&client_secret=' + secret + '&' + fields mgebbe@0: mgebbe@0: https.get(options, (res) -> mgebbe@0: #console.log "Got response: " + res.statusCode mgebbe@0: mgebbe@0: res.on "data", (chunk) -> mgebbe@0: data += chunk mgebbe@0: return mgebbe@0: mgebbe@0: res.on "end", () -> mgebbe@4: user = JSON.parse(data) if data? mgebbe@0: mgebbe@0: #### with app user id ### mgebbe@4: if user? mgebbe@4: Routes.updateUserDB(user.id+'@facebook',user.name,user.name,user.link,user.picture.data.url) mgebbe@4: EdgeControl.addEdge(me,user.id+'@facebook') mgebbe@4: #### with profile url ### mgebbe@4: Routes.updateUserDB(user.link,user.name,user.name,user.link,user.picture.data.url) mgebbe@4: EdgeControl.addEdge(me,user.link) mgebbe@0: mgebbe@0: return mgebbe@0: mgebbe@0: ).on "error", (e) -> mgebbe@0: console.log "Got error: " + e.message mgebbe@0: mgebbe@0: return mgebbe@0: mgebbe@0: mgebbe@0: ###################################################################### mgebbe@0: ###### get user facebook by id and add him to UserDB and EDGES ##### mgebbe@0: ###################################################################### mgebbe@0: getPublicUserInfo = (id, callback) -> mgebbe@0: FB.api ""+id, mgebbe@0: (res) -> mgebbe@0: if not res or res.error mgebbe@0: console.log (if not res then "error occurred" else res.error) mgebbe@0: callback null,res mgebbe@0: mgebbe@0: return mgebbe@0: mgebbe@0: ###################################################################### mgebbe@0: ###### get facebook long lived token ##### mgebbe@0: ###################################################################### mgebbe@0: getLongLivedToken = (token, callback) -> mgebbe@0: data = "" mgebbe@0: options = mgebbe@0: host: 'graph.facebook.com' mgebbe@0: port: 443 mgebbe@0: path: '/oauth/access_token?' + 'grant_type=fb_exchange_token&client_id='+ appid + '&client_secret=' + secret + '&fb_exchange_token=' + token + '' mgebbe@0: mgebbe@0: https.get(options, (res) -> mgebbe@0: res.on "data", (chunk) -> mgebbe@0: data += chunk mgebbe@0: return mgebbe@0: mgebbe@0: res.on "end", () -> mgebbe@0: # returns --> "access_token=CAAK9efmXh2IBAAm9abitB98TvF6HHF5ducYDkV5PBrooG6MVNoP9eOy06yvyL0hMKQVzh1xvJPM8XMAYe8L0ZARzZCdolahSymrZCDXN2ZAfr0aIFbWocr8K5DMLu64ZD&expires=5183792" mgebbe@0: ltoken = JSON.stringify(data) mgebbe@0: callback ltoken.substring(ltoken.indexOf('=')+1,ltoken.indexOf('&')) mgebbe@0: return mgebbe@0: mgebbe@0: ).on "error", (e) -> mgebbe@0: console.log "Got error: " + e.message mgebbe@0: mgebbe@0: return mgebbe@0: mgebbe@0: exports.getUser = getUser mgebbe@0: exports.getPages = getPages mgebbe@0: exports.getStream = getStream mgebbe@0: exports.getFriends = getFriends mgebbe@0: exports.postStream = postStream mgebbe@0: exports.getLongLivedToken = getLongLivedToken mgebbe@0: exports.getPublicUserInfo = getPublicUserInfo mgebbe@0: exports.getUserById = getUserById mgebbe@0: exports.sync = sync