# HG changeset patch # User Mathias Gebbe # Date 1401984145 -7200 # Node ID 98a070c9898218fba0e4c780998f5e55767c7b15 # Parent e942a968cb52de130fa3079eae2dbf95916a7165 add Twitter support diff -r e942a968cb52 -r 98a070c98982 package.json --- a/package.json Thu Jun 05 11:09:18 2014 +0200 +++ b/package.json Thu Jun 05 18:02:25 2014 +0200 @@ -9,6 +9,7 @@ "databank-redis": "0.19.x", "jade": "1.3.x", "fb": "0.7.x", + "twitter": "0.2.9", "oauth": "0.9.x", "async": "0.2.x", "node-uuid": "1.4.x", diff -r e942a968cb52 -r 98a070c98982 public/images/default.png Binary file public/images/default.png has changed diff -r e942a968cb52 -r 98a070c98982 public/images/stardust.png Binary file public/images/stardust.png has changed diff -r e942a968cb52 -r 98a070c98982 public/images/twitter.svg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/public/images/twitter.svg Thu Jun 05 18:02:25 2014 +0200 @@ -0,0 +1,18 @@ + + + + + + + + + + + + diff -r e942a968cb52 -r 98a070c98982 public/images/water-pump.jpg Binary file public/images/water-pump.jpg has changed diff -r e942a968cb52 -r 98a070c98982 src/app.coffee --- a/src/app.coffee Thu Jun 05 11:09:18 2014 +0200 +++ b/src/app.coffee Thu Jun 05 18:02:25 2014 +0200 @@ -1,10 +1,9 @@ # Copyright (C) 2014 by Intevation GmbH # Author: Mathias Gebbe # -# This file is Free Software under the Apache License, Version 2.0 -# (the "License"); and comes with ABSOLUTELY NO WARRANTY! -# You may not use this file except in compliance with the License. -# See LICENSE for details. +# 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. async = require 'async' databank = require 'databank' @@ -21,8 +20,6 @@ # sets up the config app = new PumpIOClientApp(config) - # Attach shadows to the user - routes.addRoutes app # Start the app diff -r e942a968cb52 -r 98a070c98982 src/commenttoesn.coffee --- a/src/commenttoesn.coffee Thu Jun 05 11:09:18 2014 +0200 +++ b/src/commenttoesn.coffee Thu Jun 05 18:02:25 2014 +0200 @@ -1,10 +1,9 @@ # Copyright (C) 2014 by Intevation GmbH # Author: Mathias Gebbe # -# This file is Free Software under the Apache License, Version 2.0 -# (the "License"); and comes with ABSOLUTELY NO WARRANTY! -# You may not use this file except in compliance with the License. -# See LICENSE for details. +# 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. _ = require("underscore") async = require("async") diff -r e942a968cb52 -r 98a070c98982 src/config.coffee --- a/src/config.coffee Thu Jun 05 11:09:18 2014 +0200 +++ b/src/config.coffee Thu Jun 05 18:02:25 2014 +0200 @@ -1,10 +1,9 @@ # Copyright (C) 2014 by Intevation GmbH # Author: Mathias Gebbe # -# This file is Free Software under the Apache License, Version 2.0 -# (the "License"); and comes with ABSOLUTELY NO WARRANTY! -# You may not use this file except in compliance with the License. -# See LICENSE for details. +# 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. fs = require 'fs' path = require 'path' diff -r e942a968cb52 -r 98a070c98982 src/edgecontrol.coffee --- a/src/edgecontrol.coffee Thu Jun 05 11:09:18 2014 +0200 +++ b/src/edgecontrol.coffee Thu Jun 05 18:02:25 2014 +0200 @@ -1,10 +1,9 @@ # Copyright (C) 2014 by Intevation GmbH # Author: Mathias Gebbe # -# This file is Free Software under the Apache License, Version 2.0 -# (the "License"); and comes with ABSOLUTELY NO WARRANTY! -# You may not use this file except in compliance with the License. -# See LICENSE for details. +# 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. async = require("async") _ = require("underscore") diff -r e942a968cb52 -r 98a070c98982 src/facebook.coffee --- a/src/facebook.coffee Thu Jun 05 11:09:18 2014 +0200 +++ b/src/facebook.coffee Thu Jun 05 18:02:25 2014 +0200 @@ -1,10 +1,9 @@ # Copyright (C) 2014 by Intevation GmbH # Author: Mathias Gebbe # -# This file is Free Software under the Apache License, Version 2.0 -# (the "License"); and comes with ABSOLUTELY NO WARRANTY! -# You may not use this file except in compliance with the License. -# See LICENSE for details. +# 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") @@ -276,7 +275,7 @@ FB.setAccessToken token return if typeof post.object.content is "undefined" or post.object.content is "" - ToESN.search {uid: post.object.id }, (err, result) -> + ToESN.search {uid: post.object.id + "@twitter"}, (err, result) -> if result.length is 0 body = post.object.content.replace(/<(?:.|\n)*?>/gm, '') + " " + post.object.url @@ -290,7 +289,7 @@ async.waterfall [ (callback) -> savePost = new ToESN() - savePost.uid = post.object.id + savePost.uid = post.object.id + "@twitter" savePost.sourceUser = post.actor.id savePost.sourcePost = post.object.id savePost.targetUser = user.user_ESN diff -r e942a968cb52 -r 98a070c98982 src/fromESN.coffee --- a/src/fromESN.coffee Thu Jun 05 11:09:18 2014 +0200 +++ b/src/fromESN.coffee Thu Jun 05 18:02:25 2014 +0200 @@ -1,10 +1,9 @@ # Copyright (C) 2014 by Intevation GmbH # Author: Mathias Gebbe # -# This file is Free Software under the Apache License, Version 2.0 -# (the "License"); and comes with ABSOLUTELY NO WARRANTY! -# You may not use this file except in compliance with the License. -# See LICENSE for details. +# 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. _ = require("underscore") async = require("async") diff -r e942a968cb52 -r 98a070c98982 src/google.coffee --- a/src/google.coffee Thu Jun 05 11:09:18 2014 +0200 +++ b/src/google.coffee Thu Jun 05 18:02:25 2014 +0200 @@ -1,10 +1,9 @@ # Copyright (C) 2014 by Intevation GmbH # Author: Mathias Gebbe # -# This file is Free Software under the Apache License, Version 2.0 -# (the "License"); and comes with ABSOLUTELY NO WARRANTY! -# You may not use this file except in compliance with the License. -# See LICENSE for details. +# 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") @@ -195,9 +194,9 @@ getRefreshToken = (user, callback) -> if user.oauth_token.indexOf(';') isnt -1 token = user.oauth_token.substr(0,user.oauth_token.indexOf(';')) + code = user.oauth_token.substr(user.oauth_token.indexOf(';')+1 ,user.oauth_token.length) else token = user.oauth_token - code = user.oauth_token.substr(user.oauth_token.indexOf(';')+1 ,user.oauth_token.lenght) data = "" post_data = querystring.stringify( "code": code diff -r e942a968cb52 -r 98a070c98982 src/pumpio.coffee --- a/src/pumpio.coffee Thu Jun 05 11:09:18 2014 +0200 +++ b/src/pumpio.coffee Thu Jun 05 18:02:25 2014 +0200 @@ -1,10 +1,9 @@ # Copyright (C) 2014 by Intevation GmbH # Author: Mathias Gebbe # -# This file is Free Software under the Apache License, Version 2.0 -# (the "License"); and comes with ABSOLUTELY NO WARRANTY! -# You may not use this file except in compliance with the License. -# See LICENSE for details. +# 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") diff -r e942a968cb52 -r 98a070c98982 src/routes.coffee --- a/src/routes.coffee Thu Jun 05 11:09:18 2014 +0200 +++ b/src/routes.coffee Thu Jun 05 18:02:25 2014 +0200 @@ -1,10 +1,9 @@ # Copyright (C) 2014 by Intevation GmbH # Author: Mathias Gebbe # -# This file is Free Software under the Apache License, Version 2.0 -# (the "License"); and comes with ABSOLUTELY NO WARRANTY! -# You may not use this file except in compliance with the License. -# See LICENSE for details. +# 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. async = require("async") _ = require("underscore") @@ -20,6 +19,7 @@ Usermap = require("./usermap") Google = require("./google") Facebook = require("./facebook") +Twitterroutes = require("./twitterroutes") Pump = require("./pumpio") User = require("./user") Edge = require("./edge") @@ -51,7 +51,7 @@ #### PUMPIO STUFF #### - if pumpid is "" or typeof pumpid is "undefined" + if not (pumpid?) console.log 'no pumpio' else saveUsermap(pumpid,pumpid,pumptoken+';'+pumpsecret,pumpsecret, (err, result) -> @@ -65,7 +65,7 @@ #### GOOGLE STUFF #### - if gpid is "" or typeof gpid is "undefined" or gptoken is "" or typeof gptoken is "undefined" + if not (gpid?) or not (gptoken?) console.log 'no google' else async.waterfall [ @@ -74,13 +74,13 @@ (user, callback) -> Google.getRefreshToken(user,callback) (token, callback) -> - saveUsermap(pumpid,gpid,token.access_token+";"+gptoken.substr(gptoken.indexOf(';')+1 ,gptoken.lenght),token.refresh_token,callback) + saveUsermap(pumpid,gpid,token.access_token + ";" + gptoken.substr(gptoken.indexOf(';')+1,gptoken.length),token.refresh_token,callback) ], (err, result) -> # now we have a gp refresh token #console.log 'done' #### FACEBOOK STUFF #### - if fbid is "" or typeof fbid is "undefined" or fbtoken is "" or typeof fbtoken is "undefined" + if not (fbid?) or not (fbtoken?) console.log 'no facebook' else # get long-lived token @@ -102,6 +102,7 @@ # Routes app.get "/bridge", userAuth, userRequired, getBridge app.post "/bridge", userAuth, userRequired, saveBridge + Twitterroutes.addRoutes(app) return diff -r e942a968cb52 -r 98a070c98982 src/sync.coffee --- a/src/sync.coffee Thu Jun 05 11:09:18 2014 +0200 +++ b/src/sync.coffee Thu Jun 05 18:02:25 2014 +0200 @@ -1,16 +1,18 @@ # Copyright (C) 2014 by Intevation GmbH # Author: Mathias Gebbe # -# This file is Free Software under the Apache License, Version 2.0 -# (the "License"); and comes with ABSOLUTELY NO WARRANTY! -# You may not use this file except in compliance with the License. -# See LICENSE for details. +# 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. _ = require("underscore") async = require("async") Facebook = require("./facebook") Usermap = require("./usermap") Google = require("./google") +Config = require ("./config") +config = Config.config +Twitter = require("./twitter")(config) syncFromESN = () -> console.log 'syncFromESN' @@ -37,6 +39,20 @@ console.log 'Error!' return + # Twitter + try + Usermap.scan ((user) -> + if user.id.indexOf('twitter') isnt -1 + console.log "start sync for twitter user" + Twitter.sync(user) + return + ), (err) -> + return + catch err + console.log 'Error!' + return + + # Google try Usermap.scan ((user) -> diff -r e942a968cb52 -r 98a070c98982 src/toESN.coffee --- a/src/toESN.coffee Thu Jun 05 11:09:18 2014 +0200 +++ b/src/toESN.coffee Thu Jun 05 18:02:25 2014 +0200 @@ -1,10 +1,9 @@ # Copyright (C) 2014 by Intevation GmbH # Author: Mathias Gebbe # -# This file is Free Software under the Apache License, Version 2.0 -# (the "License"); and comes with ABSOLUTELY NO WARRANTY! -# You may not use this file except in compliance with the License. -# See LICENSE for details. +# 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. _ = require("underscore") async = require("async") diff -r e942a968cb52 -r 98a070c98982 src/twitter.coffee --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/twitter.coffee Thu Jun 05 18:02:25 2014 +0200 @@ -0,0 +1,157 @@ +# twitter.js +# +# data object representing twitter.com +# +# Copyright 2013, E14N (https://e14n.com/) +# all changes Copyright 2014, Intevation GmbH (https://intevation.org) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +_ = require("underscore") +async = require("async") +OAuth = require("oauth").OAuth +PumpIOClientApp = require("pump.io-client-app") +DatabankObject = require("databank").DatabankObject +RequestToken = PumpIOClientApp.RequestToken +Usermap = require("./usermap") +Pump = require("./pumpio") +ToESN = require("./toESN") + + +module.exports = (config) -> + client_id = config.twclient_id + client_secret = config.twclient_secret + 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" + whoami_endpoint = "https://api.twitter.com/1.1/account/verify_credentials.json" + hostname = "twitter.com" + + Twitter = + getRequestToken: (site, callback) -> + oa = Twitter.getOAuth(site) + async.waterfall [ + (callback) -> + oa.getOAuthRequestToken callback + (token, secret, other, callback) -> + RequestToken.create + token: token + secret: secret + hostname: hostname + , callback + ], callback + return + + authorizeURL: (rt) -> + separator = undefined + if _.contains(authorization_endpoint, "?") + separator = "&" + else + separator = "?" + authorization_endpoint + separator + "oauth_token=" + rt.token + + getAccessToken: (site, rt, verifier, callback) -> + oa = Twitter.getOAuth(site) + oa.getOAuthAccessToken rt.token, rt.secret, verifier, callback + return + + whoami: (site, token, secret, callback) -> + oa = Twitter.getOAuth(site) + async.waterfall [(callback) -> + oa.get whoami_endpoint, token, secret, callback + return + ], (err, doc, response) -> + obj = undefined + if err + callback err, null + else + try + obj = JSON.parse(doc) + callback null, obj + catch e + callback e, null + return + + return + + sync: (user) -> + me = user.user_pumpio + id = user.user_ESN.substr(0,user.user_ESN.indexOf('@')) + token = user.oauth_token + secret = user.extra_token + util = require("util") + twitter = require("twitter") + twit = new twitter( + consumer_key: client_id + consumer_secret: client_secret + access_token_key: token + access_token_secret: secret + ) + + #twit.verifyCredentials((data) -> + # console.log util.inspect(data) + # return + #).updateStatus "Test tweet from pumpbridge using " + twitter.VERSION, (data) -> + # console.log util.inspect(data) + # return + + # 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") + ToESN.search {uid: post.object.id + "@twitter"}, (err, result) -> + if result.length is 0 + text = post.object.content.replace(/<(?:.|\n)*?>/gm, '') + status = "" + if text.length <= 140 + status = text + else + status = text.substr(0, 140 - (post.object.url.length + 2)) + ".." + post.object.url + twit.verifyCredentials((data) -> + #console.log util.inspect(data) + return + ).updateStatus status, (data) -> + 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 = data.id + savePost.recipientUser = 'public' + savePost.updated = Date.now() + savePost.save callback + ], (err, result) -> + #console.log util.inspect(data) + return + callback null, 'done' + ), (err) -> + callback null, 'done' + ],(err, result) -> + #console.log 'done.' + + return + + 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() + ) + + Twitter diff -r e942a968cb52 -r 98a070c98982 src/twitterroutes.coffee --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/twitterroutes.coffee Thu Jun 05 18:02:25 2014 +0200 @@ -0,0 +1,99 @@ +# Most of the routes in the application +# +# Copyright 2013, E14N (https://e14n.com/) +# all changes Copyright 2014, Intevation GmbH (https://intevation.org) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +async = require("async") +_ = require("underscore") +PumpIOClientApp = require("pump.io-client-app") +RequestToken = PumpIOClientApp.RequestToken +userAuth = PumpIOClientApp.userAuth +userOptional = PumpIOClientApp.userOptional +userRequired = PumpIOClientApp.userRequired +noUser = PumpIOClientApp.noUser +Routes = require("./routes") +Config = require("./config") +config = Config.config + +addRoutes = (app) -> + + Twitter = require("./twitter")(config) + + addAccount = (req, res, next) -> + Twitter.getRequestToken req.site, (err, rt) -> + if err + next err + else + res.redirect Twitter.authorizeURL(rt) + return + + return + + authorizedForTwitter = (req, res, next) -> + hostname = "twitter.com" + token = req.query.oauth_token + verifier = req.query.oauth_verifier + problem = req.query.oauth_problem + user = req.user + rt = undefined + fuser = undefined + access_token = undefined + token_secret = undefined + id = undefined + object = undefined + newUser = false + unless token + next new Error("No token returned.") + return + async.waterfall [ + (callback) -> + RequestToken.get RequestToken.key(hostname, token), callback + (results, callback) -> + rt = results + Twitter.getAccessToken req.site, rt, verifier, callback + (token, secret, extra, callback) -> + access_token = token + token_secret = secret + async.parallel [ + (callback) -> + rt.del callback + (callback) -> + Twitter.whoami req.site, access_token, token_secret, callback + ], callback + (results, callback) -> + object = results[1] + object = JSON.stringify(object) + object = JSON.parse(object) + res.clearCookie('twitteruser') + res.clearCookie('twitterid') + res.cookie('twitterid',object.id, { maxAge: 900000, httpOnly: false }) + res.cookie('twitteruser',object.screen_name, { maxAge: 900000, httpOnly: false }) + Routes.saveUsermap(user.id ,object.id + "@twitter" ,access_token, token_secret, callback) + ], (err) -> + if err + next err + else + res.redirect "/" + return + + return + + # Routes + console.log "Initializing Twitter routes" + app.get "/add-account", userAuth, userRequired, addAccount + app.get "/authorized-for-twitter", userAuth, userRequired, authorizedForTwitter + return + +exports.addRoutes = addRoutes diff -r e942a968cb52 -r 98a070c98982 src/user.coffee --- a/src/user.coffee Thu Jun 05 11:09:18 2014 +0200 +++ b/src/user.coffee Thu Jun 05 18:02:25 2014 +0200 @@ -1,10 +1,9 @@ # Copyright (C) 2014 by Intevation GmbH # Author: Mathias Gebbe # -# This file is Free Software under the Apache License, Version 2.0 -# (the "License"); and comes with ABSOLUTELY NO WARRANTY! -# You may not use this file except in compliance with the License. -# See LICENSE for details. +# 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. _ = require("underscore") async = require("async") diff -r e942a968cb52 -r 98a070c98982 src/usermap.coffee --- a/src/usermap.coffee Thu Jun 05 11:09:18 2014 +0200 +++ b/src/usermap.coffee Thu Jun 05 18:02:25 2014 +0200 @@ -1,10 +1,9 @@ # Copyright (C) 2014 by Intevation GmbH # Author: Mathias Gebbe # -# This file is Free Software under the Apache License, Version 2.0 -# (the "License"); and comes with ABSOLUTELY NO WARRANTY! -# You may not use this file except in compliance with the License. -# See LICENSE for details. +# 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. _ = require("underscore") async = require("async") diff -r e942a968cb52 -r 98a070c98982 views/index.jade --- a/views/index.jade Thu Jun 05 11:09:18 2014 +0200 +++ b/views/index.jade Thu Jun 05 18:02:25 2014 +0200 @@ -18,10 +18,12 @@ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s); })(); - + // load googleplus api sign in script(type='text/javascript'). + + (function() { var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true; @@ -64,7 +66,7 @@ //alert(JSON.stringify(resp)); $('#gpstatus').html(' ' + resp.displayName + ''); var token = gapi.auth.getToken(); - //alert(JSON.stringify(token)); + //alert(JSON.stringify(resp.id)); $('#gpid').val(resp.id+'@google'); $('#gptoken').val(token.access_token + ';' + token.code); }); @@ -81,10 +83,25 @@ } } + script. + // twitter stuff + function getCookie(cname) { + var name = cname + "="; + var ca = document.cookie.split(';'); + for(var i=0; i ' + getCookie('twitteruser') + ''); $.ajaxSetup({ cache: true @@ -152,6 +169,8 @@ #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') @@ -160,15 +179,20 @@ #connect.connect ul li Facebook: - i(id='fbstatus') not logged in + 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 + 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) li pump.io: a(id='pumpstatus',class='pumpstatus',href=user.homepage)= user.id br diff -r e942a968cb52 -r 98a070c98982 views/login.jade --- a/views/login.jade Thu Jun 05 11:09:18 2014 +0200 +++ b/views/login.jade Thu Jun 05 18:02:25 2014 +0200 @@ -7,9 +7,6 @@ link(rel='stylesheet', href='/stylesheets/bootstrap.min.css') link(rel='icon', href='/images/favicon.ico',type='image/x-icon') - // load jquery - script(src='https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js') - body block content .main