# HG changeset patch # User Mathias Gebbe # Date 1402446773 -7200 # Node ID 2123f355ab684170d28c25816ca55af11bacb0e4 # Parent a94ac7c3b182dafb1bb15b7bad0e74e9b23c648d go back interval or 15 min, delete credentials, layout diff -r a94ac7c3b182 -r 2123f355ab68 public/stylesheets/style.css --- a/public/stylesheets/style.css Sat Jun 07 10:22:12 2014 +0200 +++ b/public/stylesheets/style.css Wed Jun 11 02:32:53 2014 +0200 @@ -1,20 +1,33 @@ body { background-image:url("/images/grey_wash_wall.png"); background-repeat:repeat; - padding: 50px; - font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; + text-align: left; + padding-top: 80px; + color: silver; + font: 14px "Lucida Grande", Helvetica, Arial, sans-serif!important; } -#fbstatus a { - color: #00FF00!important; +a { + color: #00FF00!important; } -#gpstatus a { - color: #00FF00!important; +h2, h3, h4, h5, h6 { + color: silver!important; } -#pumpstatus { - color: #00FF00!important; +.login { + color: black!important; + font-family: "lucida grande", tahoma, verdana, arial, sans-serif; +} + +#gp, #tw, #fb{ + margin: 10px; + display: inline-block; + border-color: grey; + border-style: dotted; + border-width: 1px; + font-size: 14px; + text-align: center; } .headline { @@ -22,36 +35,27 @@ } .main { -padding: 80px 0px; -color: #efefef; -font-size: 28px; -text-align: left; + margin-left: 80px; + color: #efefef; } .login { -color: black; -font-size: 17px; -text-align: left; + color: #efefef; } -.gp-root { - float: left; - margin-left:10px; +#gp-root, #fb-root, #tw-root{ + margin: 10px; } -.fb-root { - float: left; - margin-left:10px; -} - -.pump-root { - float: left; - margin-left:10px; +#pump-root { + color: #efefef!important; } .footer { - float: left; margin-top:10px; - color: #0F0F0F; - font-size: 14px; + margin-left:80px; } + +.footer a { + color: silver!important; +} diff -r a94ac7c3b182 -r 2123f355ab68 pumpbridge.json.example --- a/pumpbridge.json.example Sat Jun 07 10:22:12 2014 +0200 +++ b/pumpbridge.json.example Wed Jun 11 02:32:53 2014 +0200 @@ -2,11 +2,12 @@ "driver": "redis", "pparams": {"host":"localhost","database":14,"port":6379}, "secret": "takeanother", -"port": 3000, -"bounce": false, +"port": 443, +"bounce": true, +"interval": 900000, "name": "pumpbridge", "description": "connect social networks", -"urlPort": 3000, +"urlPort": 443, "hostname": "server.com", "address": "42.42.42.42", "nologger": false, diff -r a94ac7c3b182 -r 2123f355ab68 src/facebook.coffee --- a/src/facebook.coffee Sat Jun 07 10:22:12 2014 +0200 +++ b/src/facebook.coffee Wed Jun 11 02:32:53 2014 +0200 @@ -46,7 +46,7 @@ getUser(user) getStream user,callback ], (err, posts) -> - return if not (posts?) + return if not (posts?) or posts.length is 0 #console.log JSON.stringify(posts) # all posts from network (100) async.eachSeries posts, ((post, callback) -> @@ -54,7 +54,7 @@ (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 + return if result.length isnt 0 or post.from.id is id #console.log "postid: " + post.from.id + "id:" + id # if this is your own post return!!! getPublicUserInfo(post.from.id , callback) @@ -67,10 +67,14 @@ Pump.postUser bridgeid, me, parsed, callback (pumppost, callback) -> pumppost = JSON.parse(pumppost) + if (post.actions[1].link?) + postlink = post.actions[1].link + else + postlink = post.actions[0].link FromESN.create postid: post.id + "@facebook" sourceUser: post.from.id - sourcePost: post.actions[0].link + sourcePost: postlink pumpPost: pumppost.object.id recipientUser: me created: Date.now() @@ -133,9 +137,14 @@ (user, callback) -> Pump.getUserFeed(user[0],callback) (feed, callback) -> + interval = config.interval + if not (interval?) + interval = 15 * 60 * 1000 # 900 000 ms (15min) + ti = new Date().getTime() - interval 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 not (post.object.deleted?) + ts = Date.parse(post.updated) + 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?) postStream(user,post) callback null, 'done' ), (err) -> @@ -236,10 +245,14 @@ ####################################### getStream = (user,callback) -> token = user.oauth_token - + interval = config.interval + if not (interval?) + interval = 15 * 60 * 1000 # 900 000 ms (15min) + ts = Math.round(((new Date()).getTime() - interval)/1000) + FB.setAccessToken token - FB.api "me/home?limit=25&", + FB.api "me/home?limit=25&?since="+ts, fields: [ "id" "type" @@ -271,6 +284,7 @@ ####################################### postStream = (user, post) -> token = user.oauth_token + text = "" FB.setAccessToken token @@ -278,9 +292,10 @@ ToESN.search {uid: post.object.id + "@facebook"}, (err, result) -> if result.length is 0 body = post.object.content.replace(/<(?:.|\n)*?>/gm, '') + " " + post.object.url - + if post.verb is "share" + text = post.object.author.url + " wrotes:" FB.api "me/feed", "post", - message: body + message: text + body , (res) -> if not res or res.error console.log (if not res then "error occurred" else res.error) diff -r a94ac7c3b182 -r 2123f355ab68 src/google.coffee --- a/src/google.coffee Sat Jun 07 10:22:12 2014 +0200 +++ b/src/google.coffee Wed Jun 11 02:32:53 2014 +0200 @@ -21,6 +21,7 @@ config = Config.config bridgeid = config.bridgeid +interval = config.interval API_KEY = config.gpAPI_KEY CLIENTID = config.gpCLIENTID CLIENTSECRET = config.gpCLIENTSECRET @@ -32,6 +33,8 @@ return if not (user?) me = user.user_pumpio id = user.user_ESN.substr(0,user.user_ESN.indexOf('@')) + if not (interval?) + interval = 15 * 60 * 1000 # 900 000 ms (15min) async.waterfall [ (callback) -> @@ -53,7 +56,12 @@ FromESN.search {uid: post.id + "@google_to_" + me, recipientUser: me}, callback (result, callback) -> return if result.length isnt 0 - Sync.postParser post, null, 'google', callback + ti = new Date().getTime() - interval + ts = Date.parse(post.published) + if (ts >= ti) + Sync.postParser post, null, 'google', callback + else + return (parsed, callback) -> Pump.postUser bridgeid, me, parsed, callback (pumppost, callback) -> diff -r a94ac7c3b182 -r 2123f355ab68 src/routes.coffee --- a/src/routes.coffee Sat Jun 07 10:22:12 2014 +0200 +++ b/src/routes.coffee Wed Jun 11 02:32:53 2014 +0200 @@ -42,14 +42,17 @@ gpid = req.body.gpid gptoken = req.body.gptoken + gpdelete = req.body.gpdelete fbid = req.body.fbid fbtoken = req.body.fbtoken + fbdelete = req.body.fbdelete + + twdelete = req.body.twdelete # create/update userdb entrys # SET THE CONNECTION BETWEENS PUMPIO AND ESN-ACCOUNT (facebook or google) - #### PUMPIO STUFF #### if not (pumpid?) console.log 'no pumpio' @@ -62,8 +65,6 @@ #], (result) -> # Pump.postUser(result, 'mgebbe@io.intevation.de','Hallo Welt') - - #### GOOGLE STUFF #### if not (gpid?) or not (gptoken?) console.log 'no google' @@ -78,19 +79,54 @@ ], (err, result) -> # now we have a gp refresh token #console.log 'done' + if (gpdelete?) + console.log "delete gp account" + async.waterfall [ + (callback) -> + Usermap.search {user_pumpio: gpdelete}, callback + (result, callback) -> + _.each result, (um) -> + if um.user_ESN.indexOf('@google') isnt -1 + deleteUsermap(um.id,callback) + return + ], (err, result) -> + #### FACEBOOK STUFF #### if not (fbid?) or not (fbtoken?) console.log 'no facebook' else - # get long-lived token - # (token is callback function) - # get the long lived token from facebook + # get long-lived token + # (token is callback function) + # get the long lived token from facebook Facebook.getLongLivedToken fbtoken,(token) -> saveUsermap(pumpid,fbid,token,fbtoken, (err, result) -> console.log 'fbsave.') + if (fbdelete?) + console.log "delete fb account" + async.waterfall [ + (callback) -> + Usermap.search {user_pumpio: fbdelete}, callback + (result, callback) -> + _.each result, (um) -> + if um.user_ESN.indexOf('@facebook') isnt -1 + deleteUsermap(um.id,callback) + return + ], (err, result) -> + if (twdelete?) + console.log "delete tw account" + async.waterfall [ + (callback) -> + Usermap.search {user_pumpio: twdelete}, callback + (result, callback) -> + _.each result, (um) -> + if um.user_ESN.indexOf('@twitter') isnt -1 + deleteUsermap(um.id,callback) + return + ], (err, result) -> + # go back to main page #res.send JSON.stringify(req.body.pumpobj) #res.send 'bridge update for:'+ pumpid + '
--> ' + gpid + ' ' + gptoken + '
--> ' + fbid + ' ' + fbtoken @@ -152,6 +188,11 @@ ], (err, result) -> return +deleteUsermap = (id, callback) -> + bank = Usermap.bank() + bank.del Usermap.type, id, callback + return + exports.saveUsermap = saveUsermap exports.updateUserDB = updateUserDB exports.addRoutes = addRoutes diff -r a94ac7c3b182 -r 2123f355ab68 src/sync.coffee --- a/src/sync.coffee Sat Jun 07 10:22:12 2014 +0200 +++ b/src/sync.coffee Wed Jun 11 02:32:53 2014 +0200 @@ -29,7 +29,7 @@ # Facebook try Usermap.scan ((user) -> - if user.id.indexOf('facebook') isnt -1 + if user.id.indexOf('@facebook') isnt -1 console.log "start sync for facebook user" Facebook.sync(user) return @@ -42,7 +42,7 @@ # Twitter try Usermap.scan ((user) -> - if user.id.indexOf('twitter') isnt -1 + if user.id.indexOf('@twitter') isnt -1 console.log "start sync for twitter user" Twitter.sync(user) return @@ -56,7 +56,7 @@ # Google try Usermap.scan ((user) -> - if user.id.indexOf('google') isnt -1 + if user.id.indexOf('@google') isnt -1 console.log "start sync for google user" Google.sync(user) return @@ -73,7 +73,7 @@ parsed = "" #console.log "\n" + post.id + "\n" + user.id + user.displayName #PROFILE_LINK PROFILE_NAME PROFILE_PIC_LINK_80x80=$3 POST_LINK POST_TIME CONTENT - #text=' '$PROFILE_NAME' schreibt am '$POST_TIME':

'$CONTENT'' + #text=' '$PROFILE_NAME' wrotes at '$POST_TIME':

'$CONTENT'' if network is 'facebook' if (user.profilePicLink?) @@ -82,15 +82,15 @@ profilePicLink = 'http://upload.wikimedia.org/wikipedia/commons/thumb/c/c2/F_icon.svg/80px-F_icon.svg.png' if post.type is 'status' - parsed = " " + user.displayName + " schreibt via " + network + " am " + post.updated_time + ":

" + post.message + parsed = " " + user.displayName + " wrotes via " + network + " at " + post.updated_time + ":

" + post.message if post.type is 'photo' - parsed = " " + user.displayName + " schreibt via " + network + " am " + post.updated_time + ":
" + parsed = " " + user.displayName + " wrotes via " + network + " at " + post.updated_time + ":
" parsed += "
" + post.message if post.message? and post.message isnt "" parsed += "
" if post.type is 'link' or post.type is 'video' - parsed = " " + user.displayName + " schreibt via " + network + " am " + post.updated_time + ":
" + parsed = " " + user.displayName + " wrotes via " + network + " at " + post.updated_time + ":
" parsed += "
" + post.message if post.message? and post.message isnt "" parsed += "
" + post.description if post.description? parsed += "
"+ post.link + "" if post.link? @@ -99,7 +99,7 @@ callback null, parsed if network is 'google' - parsed = " " + post.actor.displayName + " schreibt via " + network + " am " + post.updated + ":

" + post.object.content + parsed = " " + post.actor.displayName + " wrotes via " + network + " at " + post.updated + ":

" + post.object.content if not post.object.attachments? _.each post.object.attachments, (attachment) -> @@ -120,7 +120,7 @@ if network is 'twitter' - parsed = " " + post.user.name + " schreibt via " + network + " am " + post.created_at + ":

" + post.text + parsed = " " + post.user.name + " wrotes via " + network + " at " + post.created_at + ":

" + post.text _.each post.entities.media, (attachment) -> parsed += "
" callback null, parsed @@ -130,9 +130,11 @@ sync = () -> - # Do this every 5 minutes + # Do this every xx minutes console.log '\n\n\n' + "starting sync deamon" - interval = 15 * 60 * 1000 + interval = config.interval + if not (interval?) + interval = 15 * 60 * 1000 # 900 000 ms (15min) setInterval syncFromESN, interval syncFromESN() diff -r a94ac7c3b182 -r 2123f355ab68 src/twitter.coffee --- a/src/twitter.coffee Sat Jun 07 10:22:12 2014 +0200 +++ b/src/twitter.coffee Wed Jun 11 02:32:53 2014 +0200 @@ -33,6 +33,9 @@ bridgeid = config.bridgeid client_id = config.twclient_id client_secret = config.twclient_secret + interval = config.interval + if not (interval?) + interval = 15 * 60 * 1000 request_token_endpoint = "https://api.twitter.com/oauth/request_token" access_token_endpoint = "https://api.twitter.com/oauth/access_token" authorization_endpoint = "https://api.twitter.com/oauth/authorize" @@ -107,18 +110,22 @@ (user, callback) -> Pump.getUserFeed(user[0],callback) (feed, callback) -> + ti = new Date().getTime() - interval 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") + ts = Date.parse(post.updated) + 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") ToESN.search {uid: post.object.id + "@twitter"}, (err, result) -> if result.length is 0 # post to twitter + status = "" text = post.object.content.replace(/<(?:.|\n)*?>/gm, '') - status = "" + if post.verb is "share" + status = post.object.author.url + " wrotes: " if text.length <= 140 - status = text + status += text else - status = text.substr(0, 140 - (post.object.url.length + 2)) + ".." + post.object.url + status += text.substr(0, 140 - (post.object.url.length + 2)) + ".." + post.object.url twit.verifyCredentials((data) -> #console.log util.inspect(data) return @@ -148,15 +155,20 @@ twit.verifyCredentials((data) -> #console.log util.inspect(data) return - ).getHomeTimeline {include_rts: false}, (data) -> + ).getHomeTimeline {include_rts: true, count: 20 }, (data) -> #console.log util.inspect(data) + ti = (new Date().getTime() - interval) _.each data, (tweet) -> async.waterfall [ (callback) -> FromESN.search {uid: tweet.id + "@twitter_to_" + me, recipientUser: me}, callback (result, callback) -> - return if result.length isnt 0 or tweet.user.id == id - Sync.postParser tweet, null, 'twitter', callback + return if result.length isnt 0 or tweet.user.id_str is id + twitterdate = new Date(Date.parse(tweet.created_at.replace(/( +)/, " UTC$1"))) + ts = Date.parse(twitterdate) + if (ts >= ti) + Sync.postParser tweet, null, 'twitter', callback + return (parsed, callback) -> Pump.postUser bridgeid, me, parsed, callback (pumppost, callback) -> @@ -176,7 +188,9 @@ return return - + + parseTwitterDate : (text) -> + getOAuth: (site) -> 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 "User-Agent": site.userAgent() diff -r a94ac7c3b182 -r 2123f355ab68 views/index.jade --- a/views/index.jade Sat Jun 07 10:22:12 2014 +0200 +++ b/views/index.jade Wed Jun 11 02:32:53 2014 +0200 @@ -137,11 +137,8 @@ $('#fbstatus').html('not logged in'); } }); - - }); - $('.fbloginbutton').on('click', function(e){ FB.login(function(response) { if (response.authResponse) { @@ -165,44 +162,51 @@ block content .main h1(class='headline') pumpbridge.
connecting social networks - #fb-root.fb-root - input(id='fbloginbutton',type='image',class='fbloginbutton',value='fbLogin',src='images/fb.svg',width='100px',height='100px') - #gp-root.gp-root - input(id='gploginbutton',type='image',class='gploginbutton',value='gpLogin',src='images/gp.svg',width='100px',height='100px') - //span.g-signin(data-scope='https://www.googleapis.com/auth/plus.login', data-clientid='460404084439-rgb5r2vh7hh8hvf2na65c7n1ofhmomek.apps.googleusercontent.com', data-redirecturi='postmessage', data-accesstype='offline', data-cookiepolicy='single_host_origin', data-callback='signInCallback', approval_prompt='force') - #tw-root.tw-root - a(href='/add-account'): input(id='twloginbutton',type='image',class='twloginbutton',value='twLogin',src='images/twitter.svg',width='100px',height='100px') - //#pump-root.pump-root - // a(href='/login') - // input(id='pumploginbutton',type='image',class='pumploginbutton',value='pumpLogin',src='images/pumpiologo.svg',width='100px',height='100px') - br - form(class='',action='/bridge',method='post') - #connect.connect - ul - li pump.io: - a(id='pumpstatus',class='pumpstatus',href=user.homepage)= user.id - br + #pump-root.pump-root + h4 + | logged in as: + a(id='pumpstatus',class='pumpstatus',href=user.homepage)=user.id + #fb.fb + #fb-root.fb-root + input(id='fbloginbutton',type='image',class='fbloginbutton',value='fbLogin',src='images/fb.svg',width='100px',height='100px') + #fb-info.fb-info + i(id='fbstatus') not logged in + br + form(class='',action='/bridge',method='post') + input(id='fbdeleted',name='fbdelete',hidden='true',value=user.id) + button(type='submit',class='btn btn-default btn-xs') + | delete credentials + #gp.gp + #gp-root.gp-root + input(id='gploginbutton',type='image',class='gploginbutton',value='gpLogin',src='images/gp.svg',width='100px',height='100px') + #gp-info.gp-info + i(id='gpstatus') not logged in + br + form(class='',action='/bridge',method='post') + input(id='gpdeleted',name='gpdelete',hidden='true',value=user.id) + button(type='submit',class='btn btn-default btn-xs') + | delete credentials + #tw.tw + #tw-root.tw-root + a(href='/add-account'): input(type='image',value='twitterlogin',src='images/twitter.svg',width='100px',height='100px') + #tw-info.tw-info + i(id='twstatus') not logged in + br + form(class='',action='/bridge',method='post') + input(id='twdeleted',name='twdelete',hidden='true',value=user.id) + button(type='submit',class='btn btn-default btn-xs') + | delete credentials + form(class='',action='/bridge',method='post') input(id='pumpid',name='pumpid',hidden='true',value=user.id) input(id='pumptoken',name='pumptoken',hidden='true', value=user.token) input(id='pumpsecret',name='pumpsecret',hidden='true', value=user.secret) input(id='pumpobj',name='pumpobj', hidden='true' value='') - li Facebook: - i(id='fbstatus')   not logged in - br input(id='fbid',name='fbid',hidden='true') input(id='fbtoken',name='fbtoken',hidden='true') - li GooglePlus: - i(id='gpstatus')   not logged in - br input(id='gpid',name='gpid',hidden='true') input(id='gptoken',name='gptoken',hidden='true',size=100) - li Twitter: - i(id='twstatus')   not logged in br - input(id='twid',name='twid',hidden='true') - input(id='twtoken',name='twtoken',hidden='true',size=100) - br - input(type='submit',class='btn btn-default',value='save tokens') + input(type='submit',class='btn btn-default',value='save credentials') .footer #logout.logout //input(id='logoutbutton',type='button',class='logoutbutton',value='Logout',disabled) @@ -211,3 +215,5 @@ br p. here our bridge will be. +
visit https://wald.intevation.org/projects/pumpbridge/ + diff -r a94ac7c3b182 -r 2123f355ab68 views/login.jade --- a/views/login.jade Sat Jun 07 10:22:12 2014 +0200 +++ b/views/login.jade Wed Jun 11 02:32:53 2014 +0200 @@ -2,7 +2,6 @@ html(lang="en") head title= pageTitle - link(rel='stylesheet', href='/stylesheets/style.css') link(rel='stylesheet', href='/stylesheets/bootstrap.min.css') link(rel='icon', href='/images/favicon.ico',type='image/x-icon') @@ -11,11 +10,8 @@ block content .main h1(class='headline') pumpbridge.
connecting social networks - form(action='/login', method='post') - - input(class='login',id='webfinger',name='webfinger',size=30,type='text',placeholder='user@pumpnetwork.com') - br - input(type='checkbox',name='rememberme',value='Remember me') - span(style='font-size:17px') save login. - br - input(type='submit',class='btn btn-primary',value='Login') + form(action='/login', method='post') + input(class='login',id='webfinger',name='webfinger',size=30,type='text',placeholder='user@pumpnetwork.com') + br + br + input(type='submit',class='btn btn-primary',value='Login')