Commit f38b90eb authored by Eugen Rochko's avatar Eugen Rochko

Fix the Mastodon bridge, redesign it

parent 79780a17
...@@ -4,12 +4,14 @@ gem 'rails', '~> 5.0.0', '>= 5.0.0.1' ...@@ -4,12 +4,14 @@ gem 'rails', '~> 5.0.0', '>= 5.0.0.1'
gem 'pg', '~> 0.18' gem 'pg', '~> 0.18'
gem 'puma', '~> 3.0' gem 'puma', '~> 3.0'
gem 'sass-rails', '~> 5.0' gem 'sass-rails', '~> 5.0'
gem 'font-awesome-rails'
gem 'mastodon-api', require: 'mastodon' gem 'mastodon-api', require: 'mastodon'
gem 'twitter', git: 'https://github.com/sferik/twitter' gem 'twitter', git: 'https://github.com/sferik/twitter'
gem 'devise' gem 'devise'
gem 'omniauth-twitter' gem 'omniauth-twitter'
gem 'omniauth-mastodon', '>= 0.9.2' gem 'omniauth-mastodon', '>= 0.9.2'
gem 'hamlit'
group :development, :test do group :development, :test do
gem 'pry' gem 'pry'
......
GIT GIT
remote: https://github.com/sferik/twitter remote: https://github.com/sferik/twitter
revision: aa909b3b7733ca619d80f1c8cba961033d1fc7e6 revision: bc911e9106012aa0ef4d8b0b92ef05b880ed6da9
specs: specs:
twitter (5.15.0) twitter (5.15.0)
addressable (~> 2.3) addressable (~> 2.3)
...@@ -17,71 +17,78 @@ GIT ...@@ -17,71 +17,78 @@ GIT
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actioncable (5.0.0.1) actioncable (5.0.2)
actionpack (= 5.0.0.1) actionpack (= 5.0.2)
nio4r (~> 1.2) nio4r (>= 1.2, < 3.0)
websocket-driver (~> 0.6.1) websocket-driver (~> 0.6.1)
actionmailer (5.0.0.1) actionmailer (5.0.2)
actionpack (= 5.0.0.1) actionpack (= 5.0.2)
actionview (= 5.0.0.1) actionview (= 5.0.2)
activejob (= 5.0.0.1) activejob (= 5.0.2)
mail (~> 2.5, >= 2.5.4) mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
actionpack (5.0.0.1) actionpack (5.0.2)
actionview (= 5.0.0.1) actionview (= 5.0.2)
activesupport (= 5.0.0.1) activesupport (= 5.0.2)
rack (~> 2.0) rack (~> 2.0)
rack-test (~> 0.6.3) rack-test (~> 0.6.3)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.0.0.1) actionview (5.0.2)
activesupport (= 5.0.0.1) activesupport (= 5.0.2)
builder (~> 3.1) builder (~> 3.1)
erubis (~> 2.7.0) erubis (~> 2.7.0)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.0.0.1) activejob (5.0.2)
activesupport (= 5.0.0.1) activesupport (= 5.0.2)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (5.0.0.1) activemodel (5.0.2)
activesupport (= 5.0.0.1) activesupport (= 5.0.2)
activerecord (5.0.0.1) activerecord (5.0.2)
activemodel (= 5.0.0.1) activemodel (= 5.0.2)
activesupport (= 5.0.0.1) activesupport (= 5.0.2)
arel (~> 7.0) arel (~> 7.0)
activesupport (5.0.0.1) activesupport (5.0.2)
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (~> 0.7) i18n (~> 0.7)
minitest (~> 5.1) minitest (~> 5.1)
tzinfo (~> 1.1) tzinfo (~> 1.1)
addressable (2.4.0) addressable (2.5.1)
public_suffix (~> 2.0, >= 2.0.2)
arel (7.1.4) arel (7.1.4)
bcrypt (3.1.11) bcrypt (3.1.11)
buftok (0.2.0) buftok (0.2.0)
builder (3.2.2) builder (3.2.3)
coderay (1.1.1) coderay (1.1.1)
concurrent-ruby (1.0.2) concurrent-ruby (1.0.5)
devise (4.2.0) devise (4.2.1)
bcrypt (~> 3.0) bcrypt (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
railties (>= 4.1.0, < 5.1) railties (>= 4.1.0, < 5.1)
responders responders
warden (~> 1.2.3) warden (~> 1.2.3)
domain_name (0.5.20160826) domain_name (0.5.20170223)
unf (>= 0.0.5, < 1.0.0) unf (>= 0.0.5, < 1.0.0)
dotenv (2.1.1) dotenv (2.2.0)
dotenv-rails (2.1.1) dotenv-rails (2.2.0)
dotenv (= 2.1.1) dotenv (= 2.2.0)
railties (>= 4.0, < 5.1) railties (>= 3.2, < 5.1)
equalizer (0.0.11) equalizer (0.0.11)
erubis (2.7.0) erubis (2.7.0)
faraday (0.9.2) faraday (0.11.0)
multipart-post (>= 1.2, < 3) multipart-post (>= 1.2, < 3)
ffi (1.9.14) ffi (1.9.18)
font-awesome-rails (4.6.3.1)
railties (>= 3.2, < 5.1)
globalid (0.3.7) globalid (0.3.7)
activesupport (>= 4.1.0) activesupport (>= 4.1.0)
hashie (3.4.6) hamlit (2.7.2)
http (2.0.3) temple (~> 0.7.6)
thor
tilt
hashie (3.5.5)
http (2.2.1)
addressable (~> 2.3) addressable (~> 2.3)
http-cookie (~> 1.0) http-cookie (~> 1.0)
http-form_data (~> 1.0.1) http-form_data (~> 1.0.1)
...@@ -90,8 +97,7 @@ GEM ...@@ -90,8 +97,7 @@ GEM
domain_name (~> 0.5) domain_name (~> 0.5)
http-form_data (1.0.1) http-form_data (1.0.1)
http_parser.rb (0.6.0) http_parser.rb (0.6.0)
i18n (0.7.0) i18n (0.8.1)
json (1.8.3)
jwt (1.5.6) jwt (1.5.6)
listen (3.0.8) listen (3.0.8)
rb-fsevent (~> 0.9, >= 0.9.4) rb-fsevent (~> 0.9, >= 0.9.4)
...@@ -100,7 +106,7 @@ GEM ...@@ -100,7 +106,7 @@ GEM
nokogiri (>= 1.5.9) nokogiri (>= 1.5.9)
mail (2.6.4) mail (2.6.4)
mime-types (>= 1.16, < 4) mime-types (>= 1.16, < 4)
mastodon-api (1.0.0) mastodon-api (1.1.0)
addressable (~> 2.4) addressable (~> 2.4)
http (~> 2.0) http (~> 2.0)
memoizable (0.4.2) memoizable (0.4.2)
...@@ -110,24 +116,24 @@ GEM ...@@ -110,24 +116,24 @@ GEM
mime-types-data (~> 3.2015) mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521) mime-types-data (3.2016.0521)
mini_portile2 (2.1.0) mini_portile2 (2.1.0)
minitest (5.9.1) minitest (5.10.1)
multi_json (1.12.1) multi_json (1.12.1)
multi_xml (0.5.5) multi_xml (0.6.0)
multipart-post (2.0.0) multipart-post (2.0.0)
naught (1.1.0) naught (1.1.0)
nio4r (1.2.1) nio4r (2.0.0)
nokogiri (1.6.8.1) nokogiri (1.7.1)
mini_portile2 (~> 2.1.0) mini_portile2 (~> 2.1.0)
oauth (0.5.1) oauth (0.5.1)
oauth2 (1.2.0) oauth2 (1.3.1)
faraday (>= 0.8, < 0.10) faraday (>= 0.8, < 0.12)
jwt (~> 1.0) jwt (~> 1.0)
multi_json (~> 1.3) multi_json (~> 1.3)
multi_xml (~> 0.5) multi_xml (~> 0.5)
rack (>= 1.2, < 3) rack (>= 1.2, < 3)
omniauth (1.3.1) omniauth (1.6.1)
hashie (>= 1.2, < 4) hashie (>= 3.4.6, < 3.6.0)
rack (>= 1.0, < 3) rack (>= 1.6.2, < 3)
omniauth-mastodon (0.9.2) omniauth-mastodon (0.9.2)
omniauth (~> 1.0) omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1) omniauth-oauth2 (~> 1.1)
...@@ -137,34 +143,35 @@ GEM ...@@ -137,34 +143,35 @@ GEM
omniauth-oauth2 (1.4.0) omniauth-oauth2 (1.4.0)
oauth2 (~> 1.0) oauth2 (~> 1.0)
omniauth (~> 1.2) omniauth (~> 1.2)
omniauth-twitter (1.2.1) omniauth-twitter (1.4.0)
json (~> 1.3)
omniauth-oauth (~> 1.1) omniauth-oauth (~> 1.1)
rack
orm_adapter (0.5.0) orm_adapter (0.5.0)
pg (0.19.0) pg (0.20.0)
pry (0.10.4) pry (0.10.4)
coderay (~> 1.1.0) coderay (~> 1.1.0)
method_source (~> 0.8.1) method_source (~> 0.8.1)
slop (~> 3.4) slop (~> 3.4)
puma (3.6.0) public_suffix (2.0.5)
puma (3.8.2)
rack (2.0.1) rack (2.0.1)
rack-test (0.6.3) rack-test (0.6.3)
rack (>= 1.0) rack (>= 1.0)
rails (5.0.0.1) rails (5.0.2)
actioncable (= 5.0.0.1) actioncable (= 5.0.2)
actionmailer (= 5.0.0.1) actionmailer (= 5.0.2)
actionpack (= 5.0.0.1) actionpack (= 5.0.2)
actionview (= 5.0.0.1) actionview (= 5.0.2)
activejob (= 5.0.0.1) activejob (= 5.0.2)
activemodel (= 5.0.0.1) activemodel (= 5.0.2)
activerecord (= 5.0.0.1) activerecord (= 5.0.2)
activesupport (= 5.0.0.1) activesupport (= 5.0.2)
bundler (>= 1.3.0, < 2.0) bundler (>= 1.3.0, < 2.0)
railties (= 5.0.0.1) railties (= 5.0.2)
sprockets-rails (>= 2.0.0) sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.1) rails-dom-testing (2.0.2)
activesupport (>= 4.2.0, < 6.0) activesupport (>= 4.2.0, < 6.0)
nokogiri (~> 1.6.0) nokogiri (~> 1.6)
rails-html-sanitizer (1.0.3) rails-html-sanitizer (1.0.3)
loofah (~> 2.0) loofah (~> 2.0)
rails_12factor (0.0.3) rails_12factor (0.0.3)
...@@ -172,19 +179,19 @@ GEM ...@@ -172,19 +179,19 @@ GEM
rails_stdout_logging rails_stdout_logging
rails_serve_static_assets (0.0.5) rails_serve_static_assets (0.0.5)
rails_stdout_logging (0.0.5) rails_stdout_logging (0.0.5)
railties (5.0.0.1) railties (5.0.2)
actionpack (= 5.0.0.1) actionpack (= 5.0.2)
activesupport (= 5.0.0.1) activesupport (= 5.0.2)
method_source method_source
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rake (11.3.0) rake (12.0.0)
rb-fsevent (0.9.7) rb-fsevent (0.9.8)
rb-inotify (0.9.7) rb-inotify (0.9.8)
ffi (>= 0.5.0) ffi (>= 0.5.0)
responders (2.3.0) responders (2.3.0)
railties (>= 4.2.0, < 5.1) railties (>= 4.2.0, < 5.1)
sass (3.4.22) sass (3.4.23)
sass-rails (5.0.6) sass-rails (5.0.6)
railties (>= 4.0.0, < 6) railties (>= 4.0.0, < 6)
sass (~> 3.1) sass (~> 3.1)
...@@ -193,29 +200,30 @@ GEM ...@@ -193,29 +200,30 @@ GEM
tilt (>= 1.1, < 3) tilt (>= 1.1, < 3)
simple_oauth (0.3.1) simple_oauth (0.3.1)
slop (3.6.0) slop (3.6.0)
spring (2.0.0) spring (2.0.1)
activesupport (>= 4.2) activesupport (>= 4.2)
spring-watcher-listen (2.0.1) spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0) listen (>= 2.7, < 4.0)
spring (>= 1.2, < 3.0) spring (>= 1.2, < 3.0)
sprockets (3.7.0) sprockets (3.7.1)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
rack (> 1, < 3) rack (> 1, < 3)
sprockets-rails (3.2.0) sprockets-rails (3.2.0)
actionpack (>= 4.0) actionpack (>= 4.0)
activesupport (>= 4.0) activesupport (>= 4.0)
sprockets (>= 3.0.0) sprockets (>= 3.0.0)
thor (0.19.1) temple (0.7.7)
thread_safe (0.3.5) thor (0.19.4)
tilt (2.0.5) thread_safe (0.3.6)
tzinfo (1.2.2) tilt (2.0.7)
tzinfo (1.2.3)
thread_safe (~> 0.1) thread_safe (~> 0.1)
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.2) unf_ext (0.0.7.2)
warden (1.2.6) warden (1.2.7)
rack (>= 1.0) rack (>= 1.0)
websocket-driver (0.6.4) websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0) websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2) websocket-extensions (0.1.2)
...@@ -225,6 +233,8 @@ PLATFORMS ...@@ -225,6 +233,8 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
devise devise
dotenv-rails dotenv-rails
font-awesome-rails
hamlit
listen (~> 3.0.5) listen (~> 3.0.5)
mastodon-api mastodon-api
omniauth-mastodon (>= 0.9.2) omniauth-mastodon (>= 0.9.2)
......
...@@ -11,5 +11,6 @@ ...@@ -11,5 +11,6 @@
* It is generally better to create a new file per style scope. * It is generally better to create a new file per style scope.
* *
*= require_tree . *= require_tree .
*= require font-awesome
*= require_self *= require_self
*/ */
@import url(https://fonts.googleapis.com/css?family=Roboto:400,400i,700); @import url(https://fonts.googleapis.com/css?family=Roboto:400,400i,500,700);
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
body { body {
background: #fff; background: #282c37;
color: #282c37; color: #9baec8;
font-family: 'Roboto', sans-serif; font-family: 'Roboto', sans-serif;
font-size: 13px; font-size: 14px;
line-height: 18px; line-height: 21px;
font-weight: 400; font-weight: 400;
max-width: 600px; max-width: 600px;
margin: 0 auto; margin: 0 auto;
...@@ -13,16 +62,148 @@ body { ...@@ -13,16 +62,148 @@ body {
} }
a { a {
color: #2b90d9; color: lighten(#2b90d9, 4%);
&:visited { &:hover, &:focus, &:active {
color: darken(#2b90d9, 15%); color: lighten(#2b90d9, 8%);
} }
} }
hr { hr {
border: 0; border: 0;
background: none; background: none;
border-bottom: 1px solid #9baec8; border-bottom: 1px solid lighten(#282c37, 8%);
margin: 30px 0; margin: 30px 0;
} }
.toot-friend img {
display: block;
margin: 0 auto;
}
p.lead {
font-size: 16px;
font-weight: 500;
color: #fff;
margin-bottom: 20px;
}
.flash-message {
background: darken(#282c37, 8%);
color: #9baec8;
border-radius: 4px;
padding: 15px 10px;
margin-bottom: 30px;
box-shadow: 0 0 5px rgba(#000, 0.2);
text-align: center;
strong {
font-weight: 500;
}
}
.buttons {
list-style: none;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
li {
display: block;
margin: 0 5px;
}
}
.button, a.button {
background-color: darken(#2b90d9, 3%);
font-family: inherit;
display: inline-block;
position: relative;
box-sizing: border-box;
text-align: center;
border: 10px none;
color: #fff;
font-size: 14px;
font-weight: 500;
letter-spacing: 0;
text-transform: uppercase;
padding: 0 16px;
height: 36px;
cursor: pointer;
line-height: 36px;
border-radius: 4px;
text-decoration: none;
transition: all 100ms ease-in;
&:hover, &:active, &:focus {
background-color: lighten(#2b90d9, 7%);
transition: all 200ms ease-out;
}
&:disabled {
background-color: #9baec8;
cursor: default;
}
}
.footer {
text-align: center;
color: lighten(#282c37, 26%);
a {
color: inherit;
}
}
.info-area {
margin-bottom: 20px;
background: darken(#282c37, 8%);
padding: 20px 10px;
border-radius: 4px;
color: #fff;
font-size: 15px;
li {
margin-bottom: 5px;
}
strong {
font-weight: 500;
}
}
h4 {
font-size: 18px;
font-weight: 400;
margin-bottom: 20px;
color: #fff;
}
.user-map {
margin-bottom: 10px;
display: flex;
line-height: 36px;
& > div {
flex: 0 0 auto;
}
.twitter {
width: 150px;
}
.to {
width: 30px;
margin: 0 20px;
}
.mastodon {
width: 200px;
}
.follow {
flex: 1 1 auto;
text-align: right;
}
}
...@@ -4,6 +4,8 @@ class FriendsController < ApplicationController ...@@ -4,6 +4,8 @@ class FriendsController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
def index def index
@tweet_text = URI.encode("I am #{current_user.mastodon.try(:uid)} on Mastodon! Find your Twitter friends in the fediverse")
fetch_twitter_followees fetch_twitter_followees
fetch_twitter_followers fetch_twitter_followers
fetch_related_mastodons fetch_related_mastodons
...@@ -14,6 +16,8 @@ class FriendsController < ApplicationController ...@@ -14,6 +16,8 @@ class FriendsController < ApplicationController
mastodon_uid = user.authorizations.find_by(provider: :mastodon).uid mastodon_uid = user.authorizations.find_by(provider: :mastodon).uid
mastodon_client.follow_by_uri(mastodon_uid) mastodon_client.follow_by_uri(mastodon_uid)
redirect_to friends_path, notice: "Successfully followed #{mastodon_uid} from your Mastodon account" redirect_to friends_path, notice: "Successfully followed #{mastodon_uid} from your Mastodon account"
rescue Mastodon::Error::Unauthorized
redirect_to friends_path, alert: "The access token for your Mastodon account has expired or was revoked"
end end
private private
...@@ -33,7 +37,11 @@ class FriendsController < ApplicationController ...@@ -33,7 +37,11 @@ class FriendsController < ApplicationController
def fetch_related_mastodons def fetch_related_mastodons
found_ids1 = Authorization.where(provider: :twitter, uid: @twitter_friend_ids.to_a) found_ids1 = Authorization.where(provider: :twitter, uid: @twitter_friend_ids.to_a)
found_ids2 = Authorization.where(provider: :twitter, uid: @twitter_follower_ids.to_a) found_ids2 = Authorization.where(provider: :twitter, uid: @twitter_follower_ids.to_a)
@name_map = twitter_client.users((found_ids1 + found_ids2).map(&:uid).map(&:to_i)).map { |u| [u.id.to_s, u] }.to_h
@name_map = Rails.cache.fetch("#{current_user.id}/mastodons-on-twitter", expires_in: 15.minutes) do
twitter_client.users((found_ids1 + found_ids2).map(&:uid).map(&:to_i)).map { |u| [u.id.to_s, u] }.to_h
end
@friends = User.where(id: found_ids1.map(&:user_id)).includes(:authorizations) @friends = User.where(id: found_ids1.map(&:user_id)).includes(:authorizations)
@followers = User.where(id: found_ids2.map(&:user_id)).includes(:authorizations) @followers = User.where(id: found_ids2.map(&:user_id)).includes(:authorizations)
end end
......
...@@ -2,5 +2,7 @@ class HomeController < ApplicationController ...@@ -2,5 +2,7 @@ class HomeController < ApplicationController
def index def index
@twitter_count = Authorization.where(provider: :twitter).count @twitter_count = Authorization.where(provider: :twitter).count
@mastodon_count = Authorization.where(provider: :mastodon).count @mastodon_count = Authorization.where(provider: :mastodon).count
@has_twitter = user_signed_in? && !current_user.twitter.nil?
@has_mastodon = user_signed_in? && !current_user.mastodon.nil?
end end
end end
...@@ -18,6 +18,17 @@ class User < ApplicationRecord ...@@ -18,6 +18,17 @@ class User < ApplicationRecord
authorization.user = user authorization.user = user
authorization.token = auth.credentials.token authorization.token = auth.credentials.token
authorization.secret = auth.credentials.secret authorization.secret = auth.credentials.secret
if auth.provider == 'twitter'
authorization.profile_url = auth.info.urls['Twitter']
authorization.display_name = auth.info.nickname
elsif auth.provider == 'mastodon'
authorization.profile_url = auth.info.urls['Profile']
authorization.display_name = auth.info.nickname
end
binding.pry
authorization.save authorization.save
authorization.user authorization.user
end end
......
<table>
<thead>
<tr>
<th>Twitter user</th>
<th>Mastodon user</th>
<th></th>
</tr>
</thead>
<tbody>
<% collection.each do |user| %>
<tr>
<td><%= link_to "@#{@name_map[user.twitter.uid].screen_name}", "https://twitter.com/#{@name_map[user.twitter.uid].screen_name}" %></td>
<% if user.mastodon %>
<td><%= link_to user.mastodon.uid, mastodon_profile_url(user.mastodon.uid) %></td>
<td><%= link_to "Follow", follow_friend_path(user) %></td>
<% else %>
<td colspan="2">Hasn't signed in with Mastodon yet</td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
- collection.each do |user|