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'
gem 'pg', '~> 0.18'
gem 'puma', '~> 3.0'
gem 'sass-rails', '~> 5.0'
gem 'font-awesome-rails'
gem 'mastodon-api', require: 'mastodon'
gem 'twitter', git: 'https://github.com/sferik/twitter'
gem 'devise'
gem 'omniauth-twitter'
gem 'omniauth-mastodon', '>= 0.9.2'
gem 'hamlit'
group :development, :test do
gem 'pry'
......
GIT
remote: https://github.com/sferik/twitter
revision: aa909b3b7733ca619d80f1c8cba961033d1fc7e6
revision: bc911e9106012aa0ef4d8b0b92ef05b880ed6da9
specs:
twitter (5.15.0)
addressable (~> 2.3)
......@@ -17,71 +17,78 @@ GIT
GEM
remote: https://rubygems.org/
specs:
actioncable (5.0.0.1)
actionpack (= 5.0.0.1)
nio4r (~> 1.2)
actioncable (5.0.2)
actionpack (= 5.0.2)
nio4r (>= 1.2, < 3.0)
websocket-driver (~> 0.6.1)
actionmailer (5.0.0.1)
actionpack (= 5.0.0.1)
actionview (= 5.0.0.1)
activejob (= 5.0.0.1)
actionmailer (5.0.2)
actionpack (= 5.0.2)
actionview (= 5.0.2)
activejob (= 5.0.2)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (5.0.0.1)
actionview (= 5.0.0.1)
activesupport (= 5.0.0.1)
actionpack (5.0.2)
actionview (= 5.0.2)
activesupport (= 5.0.2)
rack (~> 2.0)
rack-test (~> 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.0.0.1)
activesupport (= 5.0.0.1)
actionview (5.0.2)
activesupport (= 5.0.2)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
activejob (5.0.0.1)
activesupport (= 5.0.0.1)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.0.2)
activesupport (= 5.0.2)
globalid (>= 0.3.6)
activemodel (5.0.0.1)
activesupport (= 5.0.0.1)
activerecord (5.0.0.1)
activemodel (= 5.0.0.1)
activesupport (= 5.0.0.1)
activemodel (5.0.2)
activesupport (= 5.0.2)
activerecord (5.0.2)
activemodel (= 5.0.2)
activesupport (= 5.0.2)
arel (~> 7.0)
activesupport (5.0.0.1)
activesupport (5.0.2)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (~> 0.7)
minitest (~> 5.1)
tzinfo (~> 1.1)
addressable (2.4.0)
addressable (2.5.1)
public_suffix (~> 2.0, >= 2.0.2)
arel (7.1.4)
bcrypt (3.1.11)
buftok (0.2.0)
builder (3.2.2)
builder (3.2.3)
coderay (1.1.1)
concurrent-ruby (1.0.2)
devise (4.2.0)
concurrent-ruby (1.0.5)
devise (4.2.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0, < 5.1)
responders
warden (~> 1.2.3)
domain_name (0.5.20160826)
domain_name (0.5.20170223)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.1.1)
dotenv-rails (2.1.1)
dotenv (= 2.1.1)
railties (>= 4.0, < 5.1)
dotenv (2.2.0)
dotenv-rails (2.2.0)
dotenv (= 2.2.0)
railties (>= 3.2, < 5.1)
equalizer (0.0.11)
erubis (2.7.0)
faraday (0.9.2)
faraday (0.11.0)
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)
activesupport (>= 4.1.0)
hashie (3.4.6)
http (2.0.3)
hamlit (2.7.2)
temple (~> 0.7.6)
thor
tilt
hashie (3.5.5)
http (2.2.1)
addressable (~> 2.3)
http-cookie (~> 1.0)
http-form_data (~> 1.0.1)
......@@ -90,8 +97,7 @@ GEM
domain_name (~> 0.5)
http-form_data (1.0.1)
http_parser.rb (0.6.0)
i18n (0.7.0)
json (1.8.3)
i18n (0.8.1)
jwt (1.5.6)
listen (3.0.8)
rb-fsevent (~> 0.9, >= 0.9.4)
......@@ -100,7 +106,7 @@ GEM
nokogiri (>= 1.5.9)
mail (2.6.4)
mime-types (>= 1.16, < 4)
mastodon-api (1.0.0)
mastodon-api (1.1.0)
addressable (~> 2.4)
http (~> 2.0)
memoizable (0.4.2)
......@@ -110,24 +116,24 @@ GEM
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
mini_portile2 (2.1.0)
minitest (5.9.1)
minitest (5.10.1)
multi_json (1.12.1)
multi_xml (0.5.5)
multi_xml (0.6.0)
multipart-post (2.0.0)
naught (1.1.0)
nio4r (1.2.1)
nokogiri (1.6.8.1)
nio4r (2.0.0)
nokogiri (1.7.1)
mini_portile2 (~> 2.1.0)
oauth (0.5.1)
oauth2 (1.2.0)
faraday (>= 0.8, < 0.10)
oauth2 (1.3.1)
faraday (>= 0.8, < 0.12)
jwt (~> 1.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
omniauth (1.3.1)
hashie (>= 1.2, < 4)
rack (>= 1.0, < 3)
omniauth (1.6.1)
hashie (>= 3.4.6, < 3.6.0)
rack (>= 1.6.2, < 3)
omniauth-mastodon (0.9.2)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1)
......@@ -137,34 +143,35 @@ GEM
omniauth-oauth2 (1.4.0)
oauth2 (~> 1.0)
omniauth (~> 1.2)
omniauth-twitter (1.2.1)
json (~> 1.3)
omniauth-twitter (1.4.0)
omniauth-oauth (~> 1.1)
rack
orm_adapter (0.5.0)
pg (0.19.0)
pg (0.20.0)
pry (0.10.4)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
puma (3.6.0)
public_suffix (2.0.5)
puma (3.8.2)
rack (2.0.1)
rack-test (0.6.3)
rack (>= 1.0)
rails (5.0.0.1)
actioncable (= 5.0.0.1)
actionmailer (= 5.0.0.1)
actionpack (= 5.0.0.1)
actionview (= 5.0.0.1)
activejob (= 5.0.0.1)
activemodel (= 5.0.0.1)
activerecord (= 5.0.0.1)
activesupport (= 5.0.0.1)
rails (5.0.2)
actioncable (= 5.0.2)
actionmailer (= 5.0.2)
actionpack (= 5.0.2)
actionview (= 5.0.2)
activejob (= 5.0.2)
activemodel (= 5.0.2)
activerecord (= 5.0.2)
activesupport (= 5.0.2)
bundler (>= 1.3.0, < 2.0)
railties (= 5.0.0.1)
railties (= 5.0.2)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.1)
rails-dom-testing (2.0.2)
activesupport (>= 4.2.0, < 6.0)
nokogiri (~> 1.6.0)
nokogiri (~> 1.6)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
rails_12factor (0.0.3)
......@@ -172,19 +179,19 @@ GEM
rails_stdout_logging
rails_serve_static_assets (0.0.5)
rails_stdout_logging (0.0.5)
railties (5.0.0.1)
actionpack (= 5.0.0.1)
activesupport (= 5.0.0.1)
railties (5.0.2)
actionpack (= 5.0.2)
activesupport (= 5.0.2)
method_source
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (11.3.0)
rb-fsevent (0.9.7)
rb-inotify (0.9.7)
rake (12.0.0)
rb-fsevent (0.9.8)
rb-inotify (0.9.8)
ffi (>= 0.5.0)
responders (2.3.0)
railties (>= 4.2.0, < 5.1)
sass (3.4.22)
sass (3.4.23)
sass-rails (5.0.6)
railties (>= 4.0.0, < 6)
sass (~> 3.1)
......@@ -193,29 +200,30 @@ GEM
tilt (>= 1.1, < 3)
simple_oauth (0.3.1)
slop (3.6.0)
spring (2.0.0)
spring (2.0.1)
activesupport (>= 4.2)
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
spring (>= 1.2, < 3.0)
sprockets (3.7.0)
sprockets (3.7.1)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.0)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
thor (0.19.1)
thread_safe (0.3.5)
tilt (2.0.5)
tzinfo (1.2.2)
temple (0.7.7)
thor (0.19.4)
thread_safe (0.3.6)
tilt (2.0.7)
tzinfo (1.2.3)
thread_safe (~> 0.1)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.2)
warden (1.2.6)
warden (1.2.7)
rack (>= 1.0)
websocket-driver (0.6.4)
websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)
......@@ -225,6 +233,8 @@ PLATFORMS
DEPENDENCIES
devise
dotenv-rails
font-awesome-rails
hamlit
listen (~> 3.0.5)
mastodon-api
omniauth-mastodon (>= 0.9.2)
......
......@@ -11,5 +11,6 @@
* It is generally better to create a new file per style scope.
*
*= require_tree .
*= require font-awesome
*= 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 {
background: #fff;
color: #282c37;
background: #282c37;
color: #9baec8;
font-family: 'Roboto', sans-serif;
font-size: 13px;
line-height: 18px;
font-size: 14px;
line-height: 21px;
font-weight: 400;
max-width: 600px;
margin: 0 auto;
......@@ -13,16 +62,148 @@ body {
}
a {
color: #2b90d9;
color: lighten(#2b90d9, 4%);
&:visited {
color: darken(#2b90d9, 15%);
&:hover, &:focus, &:active {
color: lighten(#2b90d9, 8%);
}
}
hr {
border: 0;
background: none;
border-bottom: 1px solid #9baec8;
border-bottom: 1px solid lighten(#282c37, 8%);
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
before_action :authenticate_user!
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_followers
fetch_related_mastodons
......@@ -14,6 +16,8 @@ class FriendsController < ApplicationController
mastodon_uid = user.authorizations.find_by(provider: :mastodon).uid
mastodon_client.follow_by_uri(mastodon_uid)
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
private
......@@ -33,7 +37,11 @@ class FriendsController < ApplicationController
def fetch_related_mastodons
found_ids1 = Authorization.where(provider: :twitter, uid: @twitter_friend_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)
@followers = User.where(id: found_ids2.map(&:user_id)).includes(:authorizations)
end
......
......@@ -2,5 +2,7 @@ class HomeController < ApplicationController
def index
@twitter_count = Authorization.where(provider: :twitter).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
......@@ -18,6 +18,17 @@ class User < ApplicationRecord
authorization.user = user
authorization.token = auth.credentials.token
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.user
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|
.user-map
.twitter= link_to "@#{@name_map[user.twitter.uid].screen_name}", "https://twitter.com/#{@name_map[user.twitter.uid].screen_name}"
.to= fa_icon('chevron-right')
- if user.mastodon
.mastodon= link_to user.mastodon.uid, mastodon_profile_url(user.mastodon.uid)
.follow= link_to "Follow", follow_friend_path(user), class: 'button'
- else
.mastodon Unknown, yet
<p>Your friends are not showing up in the table? Tell them to create a Mastodon account and then sign in on this website using both Twitter and Mastodon.</p>
<p>
<a class="twitter-share-button" href="https://twitter.com/intent/tweet?text=<%= URI.encode('Find your friends on #Mastodon') %>&url=<%= root_url %>" data-size="large">Tweet</a>
</p>
<h4>Friends</h4>
<%= render 'table', collection: @friends %>
<h4>Followers</h4>
<%= render 'table', collection: @followers %>
<script>window.twttr = (function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0],
t = window.twttr || {};
if (d.getElementById(id)) return t;
js = d.createElement(s);
js.id = id;
js.src = "https://platform.twitter.com/widgets.js";
fjs.parentNode.insertBefore(js, fjs);
t._e = [];
t.ready = function(f) {
t._e.push(f);
};
return t;
}(document, "script", "twitter-wjs"));</script>
%p.lead
Your friends are not showing up in the table? Tell them to create a Mastodon account on any instance and then sign in on this website using both Twitter and Mastodon.
%p
%a.twitter-share-button{"data-size" => "large", :href => "https://twitter.com/intent/tweet?text=#{@tweet_text}"} Tweet
%hr/
%h4 Friends
= render 'table', collection: @friends
%hr/
%h4 Followers
= render 'table', collection: @followers
:javascript
window.twttr = (function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0],
t = window.twttr || {};
if (d.getElementById(id)) return t;
js = d.createElement(s);
js.id = id;
js.src = "https://platform.twitter.com/widgets.js";
fjs.parentNode.insertBefore(js, fjs);
t._e = [];
t.ready = function(f) {
t._e.push(f);
};
return t;
}(document, "script", "twitter-wjs"));
<p><em>This website is a tool for finding your Twitter friends in the federated Mastodon network. As long as your friends have signed on here with both accounts, you can find them.</em></p>
<ul>
<li><a href="https://github.com/Gargron/mastodon" target="_blank">What is Mastodon?</a></li>
<li><a href="https://github.com/Gargron/mastodon/wiki/List-of-Mastodon-instances" target="_blank">List of available Mastodon instances where you can make an account</a></li>
</ul>
<hr />
<ul>
<li><%= link_to "Sign in with Twitter", user_twitter_omniauth_authorize_path %></li>
<li><%= link_to "Sign in with Mastodon", user_mastodon_omniauth_authorize_path %></li>
</ul>
<% if user_signed_in? %>
<p>You are signed in:</p>
<table>
<tbody>
<tr>
<th>Twitter</th>
<td><%= current_user.twitter.try(:uid) || 'Please sign in' %></td>
</tr>
<tr>
<th>Mastodon</th>
<td><%= current_user.mastodon.try(:uid) || 'Please sign in' %></td>
</tr>
</tbody>
</table>
<ul>
<li><%= link_to "Find friends on Mastodon", friends_path %></li>
</ul>
<% else %>
<p>You are not signed in</p>
<% end %>
<p>So far, <strong><%= @twitter_count %></strong> users signed in with Twitter, and <strong><%= @mastodon_count %></strong> with Mastodon. Are your friends or followers among them?</p>