view src/facebook.coffee @ 3:98a070c98982

add Twitter support
author Mathias Gebbe <mgebbe@intevation.de>
date Thu, 05 Jun 2014 18:02:25 +0200
parents b73191efc65b
children f352c74a6a5b
line wrap: on
line source
# Copyright (C) 2014 by Intevation GmbH
# Author: Mathias Gebbe <mgebbe@intevation.de>
#
# This file is Free Software under the Apache License, Version 2.0;
# and comes with NO WARRANTY!
# See the documentation coming with pumpbridge for details.

https = require("https")
async = require("async")
_ = require("underscore")
Routes = require("./routes")
FB = require('fb')
EdgeControl = require("./edgecontrol")
Edge = require("./edge")
CommentToESN = require("./commenttoesn")
ToESN = require("./toESN")
FromESN = require("./fromESN")
Pump = require("./pumpio")
User = require("./user")
Sync = require("./sync")
Usermap = require("./usermap")
Config = require("./config")

config = Config.config

bridgeid = config.bridgeid
secret = config.fbSECRET
appid = config.fbAPPID

#######################################
###### facebook sync              #####
#######################################

sync = (user) ->
  me = user.user_pumpio
  id = user.user_ESN.substr(0,user.user_ESN.indexOf('@'))
  pubuser = ""
  post = ""

  # GET NEW POSTS
  ####
  async.waterfall [
    (callback) ->
      getFriends(user)
      getPages(user)
      getUser(user)
      getStream user,callback
  ], (err, posts) ->
    return if not (posts?)
    #console.log JSON.stringify(posts) # all posts from network (100)
    async.eachSeries posts, ((post, callback) ->

      async.waterfall [
        (callback) ->
          FromESN.search {uid: post.id + "@facebook_to_" + me, recipientUser: me}, callback
        (result, callback) ->
          return if result.length isnt 0 or post.from.id == id
          #console.log "postid: " + post.from.id + "id:" + id
          # if this is your own post return!!!
          getPublicUserInfo(post.from.id , callback)
        (pubuser, callback) ->
          pubuser = pubuser
          User.search {id: pubuser.id + "@facebook"}, callback
        (dbuser, callback) ->
          Sync.postParser post, dbuser[0], 'facebook', callback
        (parsed, callback) ->
          Pump.postUser bridgeid, me, parsed, callback
        (pumppost, callback) ->
          pumppost = JSON.parse(pumppost)
          FromESN.create
            postid: post.id + "@facebook"
            sourceUser: post.from.id
            sourcePost: post.actions[0].link
            pumpPost: pumppost.object.id
            recipientUser: me
            created: Date.now()
          , callback
     ], (err, result) ->
          #console.log result
          #console.log 'done.'
      callback null, 'done'
    ), (err) ->
      if err
        console.log 'one post fail to process'
      else
        console.log 'all posts processed'
      return
  ####
  # TO DO: GET NEW COMMENTS
  # for each fromESN check the comments
  # if comment author = me
  # post comment
  # if comment author != me
  # post comment with 'user schreibt'
  async.waterfall [
    (callback) ->
      FromESN.search {recipientUser: me}, callback
    (allESN, callback) ->
      async.each allESN, ((fromesn, callback) ->
        async.waterfall [
          (cb) ->
            cb (true) if fromesn.sourcePost.indexOf('www.facebook.com') is -1
            Usermap.search {id: me + '_to_' + me}, cb
          (pumpuser, cb) ->
            Pump.getNote(pumpuser[0], fromesn.pumpPost, cb)
          (note, cb) ->
            if note.liked is not undefined and note.liked is true
              obj = fromesn.postid.substr(0,fromesn.postid.indexOf('@'))
              postLike(user,obj)
            if (note.replies?)
              reply = JSON.stringify(note.replies)
              rep = JSON.parse(reply)
              if rep.totalItems >= 1
                async.each rep.items, ((r, callback) ->
                  if r.author.id is "acct:" + me
                    obj = fromesn.postid.substr(0,fromesn.postid.indexOf('@'))
                    postComment(user, obj, r.id , r.content)
                  callback null, 'done'
                ), (err) ->
            cb null, 'done'
        ], (err, result) ->
         #done
      ), (err) ->
        callback null, 'done'
  ], (err, result) ->
    #done


  # GET PUBLIC PUMP POSTS AND POST THEM
  async.waterfall [
    (callback) ->
      Usermap.search {id: me + '_to_' + me}, callback
    (user, callback) ->
      Pump.getUserFeed(user[0],callback)
    (feed, callback) ->
      async.eachSeries feed.items, ((post, callback) ->
        # do for each post
        if (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")
          postStream(user,post)
        callback null, 'done'
      ), (err) ->
        callback null, 'done'
  ],(err, result) ->
        #console.log 'done.'

  return


#######################################
###### get user facebook          #####
#######################################
getUser = (user) ->
  data = ""
  id = user.user_ESN.substr(0,user.user_ESN.indexOf('@'))
  token = user.oauth_token
  fields = 'fields=id,name,picture,link'
  options =
   host: 'graph.facebook.com'
   port: 443
   path: '/' + id + '?access_token=' + token + '&' + fields

  https.get(options, (res) ->
    #console.log "Got response: " + res.statusCode

    res.on "data", (chunk) ->
      data += chunk
      return

    res.on "end", () ->
      user = JSON.parse(data)
      ### with app id ###
      Routes.updateUserDB(user.id+'@facebook',user.name,user.name,user.link,user.picture.data.url) unless typeof user is "undefined"
      ### with link ###
      Routes.updateUserDB(user.link,user.name,user.name,user.link,user.picture.data.url) unless typeof user is "undefined"
      return

  ).on "error", (e) ->
    console.log "Got error: " + e.message

  return

##############################################
###### get facebook friends /remove all ######
##############################################
getFriends = (user) ->
  me = user.user_pumpio
  id = user.user_ESN.substr(0,user.user_ESN.indexOf('@'))
  token = user.oauth_token

  EdgeControl.removeEdges(me,'@facebook')
  EdgeControl.removeEdges(me,'www.facebook.com')

  FB.setAccessToken token
  FB.api "fql",
    q: "SELECT uid2 FROM friend WHERE uid1 = me()"
  , (res) ->
    if not res or res.error
      console.log (if not res then "error occurred" else res.error)
      return

    _.each res.data, (user) ->
      getUserById(me,user.uid2,token) unless typeof user.id is "undefined"
      return

    return

  return

##############################################
###### get facebook likes               ######
##############################################
getPages = (user) ->
  me = user.user_pumpio
  token = user.oauth_token

  FB.setAccessToken token

  FB.api "me/likes?limit=1000&",
    fields: [
      "id"
    ]
  , (res) ->
    if not res or res.error
      console.log (if not res then "error occurred" else res.error)

    _.each res.data, (page) ->
      getUserById(me,page.id,token) unless typeof user.id is "undefined"
      return


  return


#######################################
###### get facebook stream       ######
#######################################
getStream = (user,callback) ->
  token = user.oauth_token

  FB.setAccessToken token

  FB.api "me/home?limit=25&",
    fields: [
      "id"
      "type"
      "from"
      "privacy"
      "message"
      "picture"
      "link"
      "status_type"
      "caption"
      "created_time"
      "updated_time"
      "picture"
      "actions"
    ]
  , (res) ->
    if not res or res.error
      console.log (if not res then "error occurred" else res.error)
      callback null, null

    newposts = new Array()
    _.each res.data, (post) ->
      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')

    callback null, newposts.reverse()

#######################################
###### post facebook stream      ######
#######################################
postStream = (user, post) ->
  token = user.oauth_token

  FB.setAccessToken token

  return if typeof post.object.content  is "undefined" or post.object.content is ""
  ToESN.search {uid: post.object.id + "@twitter"}, (err, result) ->
    if result.length is 0
      body = post.object.content.replace(/<(?:.|\n)*?>/gm, '') + " " + post.object.url

      FB.api "me/feed", "post",
        message: body
      , (res) ->
        if not res or res.error
          console.log (if not res then "error occurred" else res.error)
          return

        async.waterfall [
          (callback) ->
            savePost = new ToESN()
            savePost.uid = post.object.id + "@twitter"
            savePost.sourceUser = post.actor.id
            savePost.sourcePost = post.object.id
            savePost.targetUser = user.user_ESN
            savePost.targetPost = res.id
            savePost.recipientUser = 'public'
            savePost.updated = Date.now()
            savePost.save callback
        ], (err, result) ->

        return

  return

##################################################
###### post comment to facebook stream      ######
##################################################
postComment = (user, object_id, pumpid, text) ->

# check if the comment is allready posted (search bla return)

  CommentToESN.search { uid: pumpid + "_to_" + "https://facebook.com/" + object_id}, (err, result) ->
    if result.length is 0
      token = user.oauth_token
      text = text.replace /<(?:.|\n)*?>/g, ""

      FB.setAccessToken token

      FB.api "" + object_id + "/comments", "POST",
        message: text
      , (res) ->
        if not res or res.error
          console.log (if not res then "error occurred" else res.error)
          return

      CommentToESN.create
        ESNPost: "https://facebook.com/" + object_id
        pumpComment: pumpid
        created: Date.now()
      , (err, result) ->
        console.log 'comment saved'

  return

##################################################
###### like post on facebook stream         ######
##################################################
postLike = (user, object_id) ->
  token = user.oauth_token
  FB.setAccessToken token

  FB.api "" + object_id + "/likes", "POST"
  , (res) ->
    if not res or res.error
      console.log (if not res then "error occurred" else res.error)
      return

    console.log 'liked'
    return

  return


######################################################################
###### get user facebook by id and add him to UserDB and EDGES   #####
######################################################################
getUserById = (me,id,token) ->
  data = ""
  token = token
  fields = 'fields=id,name,picture,link'
  options =
   host: 'graph.facebook.com'
   port: 443
   path: '/' + id + '?access_token=' + token + '&' + fields

  https.get(options, (res) ->
    #console.log "Got response: " + res.statusCode

    res.on "data", (chunk) ->
      data += chunk
      return

    res.on "end", () ->
      user = JSON.parse(data) unless data isnt "undefined"

      #### with app user id ###
      Routes.updateUserDB(user.id+'@facebook',user.name,user.name,user.link,user.picture.data.url) unless typeof user is "undefined"
      EdgeControl.addEdge(me,user.id+'@facebook') unless typeof user is "undefined"

      #### with profile url ###
      Routes.updateUserDB(user.link,user.name,user.name,user.link,user.picture.data.url) unless typeof user is "undefined"
      EdgeControl.addEdge(me,user.link) unless typeof user is "undefined"


      return

  ).on "error", (e) ->
    console.log "Got error: " + e.message

  return


######################################################################
###### get user facebook by id and add him to UserDB and EDGES   #####
######################################################################
getPublicUserInfo = (id, callback) ->

  FB.api ""+id,
   (res) ->
     if not res or res.error
       console.log (if not res then "error occurred" else res.error)
     callback null,res

  return

######################################################################
###### get facebook long lived token                             #####
######################################################################
getLongLivedToken = (token, callback) ->
  data = ""
  options =
   host: 'graph.facebook.com'
   port: 443
   path: '/oauth/access_token?' + 'grant_type=fb_exchange_token&client_id='+ appid + '&client_secret=' + secret + '&fb_exchange_token=' + token + ''

  https.get(options, (res) ->
    res.on "data", (chunk) ->
      data += chunk
      return

    res.on "end", () ->
      # returns --> "access_token=CAAK9efmXh2IBAAm9abitB98TvF6HHF5ducYDkV5PBrooG6MVNoP9eOy06yvyL0hMKQVzh1xvJPM8XMAYe8L0ZARzZCdolahSymrZCDXN2ZAfr0aIFbWocr8K5DMLu64ZD&expires=5183792"
      ltoken = JSON.stringify(data)
      callback ltoken.substring(ltoken.indexOf('=')+1,ltoken.indexOf('&'))
      return

  ).on "error", (e) ->
    console.log "Got error: " + e.message

  return

exports.getUser = getUser
exports.getPages = getPages
exports.getStream = getStream
exports.getFriends = getFriends
exports.postStream = postStream
exports.getLongLivedToken = getLongLivedToken
exports.getPublicUserInfo = getPublicUserInfo
exports.getUserById = getUserById
exports.sync = sync
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)